This commit is contained in:
wangcongtao
2020-01-09 14:59:46 +08:00
parent 742b72d9e4
commit c48af40b32
29 changed files with 858 additions and 121 deletions

View File

@@ -34,6 +34,8 @@ public class AppsFragment extends MvpFragment< AppsView, AppsPresenter > impleme
private View mExit;
private IMogoFragmentManager mMogoFragmentManager;
private View mLoadingView;
@Override
protected int getLayoutId() {
return R.layout.module_apps_fragment_apps;
@@ -62,6 +64,8 @@ public class AppsFragment extends MvpFragment< AppsView, AppsPresenter > impleme
// }
// } );
// mBottomSheetBehavior.setState( BottomSheetBehavior.STATE_COLLAPSED );
mLoadingView = findViewById( R.id.module_apps_id_loading );
mLoadingView.setVisibility( View.VISIBLE );
}
@NonNull
@@ -78,6 +82,7 @@ public class AppsFragment extends MvpFragment< AppsView, AppsPresenter > impleme
@Override
public void renderApps( Map< Integer, List< AppInfo > > appInfos ) {
mLoadingView.setVisibility( View.GONE );
if ( mAppsPagerAdapter == null ) {
mAppsPagerAdapter = new AppsPagerAdapter( appInfos );
mAppsPager.setAdapter( mAppsPagerAdapter );
@@ -88,5 +93,6 @@ public class AppsFragment extends MvpFragment< AppsView, AppsPresenter > impleme
} else {
mAppsPagerAdapter.setPagedApps( appInfos );
}
mLoadingView.setVisibility( View.GONE );
}
}

View File

@@ -1,26 +1,16 @@
package com.mogo.module.apps;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.graphics.drawable.Drawable;
import androidx.annotation.NonNull;
import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.Observer;
import com.mogo.commons.mvp.Presenter;
import com.mogo.module.apps.model.AppInfo;
import com.mogo.module.apps.model.AppsModel;
import com.mogo.utils.ThreadPoolService;
import com.mogo.utils.TipToast;
import com.mogo.utils.UiThreadHandler;
import com.mogo.utils.logger.Logger;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author congtaowang
@@ -32,13 +22,8 @@ public class AppsPresenter extends Presenter< AppsView > {
private static final String TAG = "AppsPresenter";
private AppFilter mAppFilter;
public AppsPresenter( AppsView view ) {
super( view );
RefreshAppsListLiveData.getInstance().observeForever( s -> {
renderAppsList();
} );
}
@Override
@@ -49,45 +34,17 @@ public class AppsPresenter extends Presenter< AppsView > {
private void renderAppsList() {
ThreadPoolService.execute( () -> {
final Map< Integer, List< AppInfo > > appInfoList = loadAppsList();
UiThreadHandler.post( () -> {
if ( mView != null ) {
mView.renderApps( appInfoList );
}
AppsModel.getInstance( getContext() ).load( appInfoList -> {
UiThreadHandler.post( () -> {
if ( mView != null ) {
mView.renderApps( appInfoList );
}
} );
} );
} );
}
private Map< Integer, List< AppInfo > > loadAppsList() {
Logger.i( TAG, "load apps list." );
if ( mAppFilter == null ) {
mAppFilter = new AppFilterImpl( getContext() );
}
final Map< Integer, List< AppInfo > > pagedApps = new HashMap<>();
final PackageManager packageManager = getContext().getPackageManager();
List< PackageInfo > packages = packageManager.getInstalledPackages( 0 );
int counter = 0;
for ( int i = 0; i < packages.size(); ++i ) {
PackageInfo packageInfo = packages.get( i );
if ( mAppFilter.filter( packageInfo ) ) {
continue;
}
int page = counter++ / AppsConst.TOTAL_SIZE_EACH_PAGE;
if ( !pagedApps.containsKey( page ) ) {
pagedApps.put( page, new ArrayList<>() );
}
String appName = packageInfo.applicationInfo.loadLabel( packageManager ).toString();
String packageName = packageInfo.packageName;
String versionName = packageInfo.versionName;
int versionCode = packageInfo.versionCode;
Drawable appIcon = packageInfo.applicationInfo.loadIcon( packageManager );
AppInfo appInfo = new AppInfo( appName, packageName, versionName, versionCode, appIcon );
pagedApps.get( page ).add( appInfo );
}
return pagedApps;
}
public void launch( AppInfo appInfo ) {
if ( appInfo == null ) {
return;

View File

@@ -1,32 +0,0 @@
package com.mogo.module.apps;
import androidx.lifecycle.MutableLiveData;
/**
* @author congtaowang
* @since 2019-12-30
* <p>
* 刷新app列表
*/
public class RefreshAppsListLiveData extends MutableLiveData< String > {
private static volatile RefreshAppsListLiveData sInstance;
private RefreshAppsListLiveData() {
}
public static RefreshAppsListLiveData getInstance() {
if ( sInstance == null ) {
synchronized ( RefreshAppsListLiveData.class ) {
if ( sInstance == null ) {
sInstance = new RefreshAppsListLiveData();
}
}
}
return sInstance;
}
public synchronized void release() {
sInstance = null;
}
}

View File

@@ -0,0 +1,15 @@
package com.mogo.module.apps.model;
import java.util.List;
import java.util.Map;
/**
* @author congtaowang
* @since 2020-01-09
* <p>
* 描述
*/
public interface AppLoadCallback {
void onLoaded( Map< Integer, List< AppInfo > > appInfos );
}

View File

@@ -0,0 +1,185 @@
package com.mogo.module.apps.model;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.graphics.drawable.Drawable;
import android.text.TextUtils;
import com.mogo.module.apps.AppFilter;
import com.mogo.module.apps.AppFilterImpl;
import com.mogo.module.apps.AppsConst;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* @author congtaowang
* @since 2020-01-09
* <p>
* 加载并保存 app 列表
*/
public class AppsModel {
private static volatile AppsModel sInstance;
private final Context mContext;
private AppFilter mAppFilter;
private Map< Integer, List< AppInfo > > mPagedApps = new HashMap<>();
private AppsModel( Context context ) {
mContext = context;
mAppFilter = new AppFilterImpl( context );
}
public static AppsModel getInstance( Context context ) {
if ( sInstance == null ) {
synchronized ( AppsModel.class ) {
if ( sInstance == null ) {
sInstance = new AppsModel( context );
}
}
}
return sInstance;
}
private AtomicBoolean mIsLoaded = new AtomicBoolean( false );
public synchronized void release() {
sInstance = null;
}
public void load( AppLoadCallback callback ) {
if ( !mPagedApps.isEmpty() ) {
if ( callback != null ) {
callback.onLoaded( mPagedApps );
}
return;
}
final PackageManager packageManager = mContext.getPackageManager();
List< PackageInfo > packages = packageManager.getInstalledPackages( 0 );
int counter = 0;
for ( int i = 0; i < packages.size(); ++i ) {
PackageInfo packageInfo = packages.get( i );
if ( mAppFilter.filter( packageInfo ) ) {
continue;
}
int page = counter++ / AppsConst.TOTAL_SIZE_EACH_PAGE;
if ( !mPagedApps.containsKey( page ) ) {
mPagedApps.put( page, new ArrayList<>() );
}
String appName = packageInfo.applicationInfo.loadLabel( packageManager ).toString();
String packageName = packageInfo.packageName;
String versionName = packageInfo.versionName;
int versionCode = packageInfo.versionCode;
Drawable appIcon = packageInfo.applicationInfo.loadIcon( packageManager );
AppInfo appInfo = new AppInfo( appName, packageName, versionName, versionCode, appIcon );
mPagedApps.get( page ).add( appInfo );
}
if ( callback != null ) {
callback.onLoaded( mPagedApps );
}
mIsLoaded.set( true );
}
public void appAdded( String packageName ) {
if ( !mIsLoaded.get() ) {
return;
}
if ( TextUtils.isEmpty( packageName ) ) {
return;
}
if ( mPagedApps.isEmpty() ) {
return;
}
try {
final PackageManager packageManager = mContext.getPackageManager();
PackageInfo packageInfo = packageManager.getPackageInfo( packageName, 0 );
if ( !mAppFilter.filter( packageInfo ) ) {
String appName = packageInfo.applicationInfo.loadLabel( packageManager ).toString();
String versionName = packageInfo.versionName;
int versionCode = packageInfo.versionCode;
Drawable appIcon = packageInfo.applicationInfo.loadIcon( packageManager );
AppInfo appInfo = new AppInfo( appName, packageName, versionName, versionCode, appIcon );
int pageIndex = getPageIndex( packageName, true );
if ( !mPagedApps.containsKey( pageIndex ) ) {
mPagedApps.put( pageIndex, new ArrayList<>() );
}
mPagedApps.get( pageIndex ).add( appInfo );
}
} catch ( PackageManager.NameNotFoundException e ) {
e.printStackTrace();
}
}
private int getPageIndex( String packageName, boolean add ) {
int totalPages = mPagedApps.size();
if ( add ) {
if ( totalPages == 0 ) {
return 0;
} else {
if ( mPagedApps.get( totalPages - 1 ).size() == AppsConst.TOTAL_SIZE_EACH_PAGE ) {
return totalPages + 1;
} else {
return totalPages;
}
}
} else {
if ( totalPages == 0 ) {
return -1;
}
int pageIndex = -1;
for ( int i = 0; i < totalPages; i++ ) {
for ( AppInfo appInfo : mPagedApps.get( i ) ) {
if ( TextUtils.equals( appInfo.getPackageName(), packageName ) ) {
pageIndex = i;
}
}
}
return pageIndex;
}
}
public void appRemoved( String packageName ) {
if ( !mIsLoaded.get() ) {
return;
}
if ( TextUtils.isEmpty( packageName ) ) {
return;
}
try {
final PackageManager packageManager = mContext.getPackageManager();
PackageInfo packageInfo = packageManager.getPackageInfo( packageName, 0 );
if ( !mAppFilter.filter( packageInfo ) ) {
int pageIndex = getPageIndex( packageName, false );
if ( pageIndex == -1 ) {
return;
}
int totalPages = mPagedApps.size();
List< AppInfo > dynamicAppsList = new ArrayList<>();
for ( int i = pageIndex; i < totalPages; i++ ) {
dynamicAppsList.addAll( mPagedApps.remove( i ) );
}
int counter = 0;
for ( int i = 0; i < dynamicAppsList.size(); i++ ) {
AppInfo appInfo = dynamicAppsList.get( i );
if ( TextUtils.equals( appInfo.getPackageName(), packageName ) ) {
continue;
}
int page = counter++ / AppsConst.TOTAL_SIZE_EACH_PAGE + pageIndex;
if ( !mPagedApps.containsKey( page ) ) {
mPagedApps.put( page, new ArrayList<>() );
}
mPagedApps.get( page ).add( appInfo );
}
}
} catch ( PackageManager.NameNotFoundException e ) {
e.printStackTrace();
}
}
}

View File

@@ -4,9 +4,8 @@ package com.mogo.module.apps.receiver;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import com.mogo.module.apps.RefreshAppsListLiveData;
import com.mogo.module.apps.model.AppsModel;
public class AppInstallReceiver extends BroadcastReceiver {
@@ -14,31 +13,23 @@ public class AppInstallReceiver extends BroadcastReceiver {
public void onReceive( Context context, Intent intent ) {
if ( intent.getAction().equals( Intent.ACTION_PACKAGE_ADDED ) ) {
String packageName = intent.getData().getSchemeSpecificPart();
notifyRefreshAppsList( packageName );
AppsModel.getInstance( context ).appAdded( packageName );
}
if ( intent.getAction().equals( Intent.ACTION_PACKAGE_REMOVED ) ) {
String packageName = intent.getData().getSchemeSpecificPart();
notifyRefreshAppsList( packageName );
AppsModel.getInstance( context ).appRemoved( packageName );
}
if ( intent.getAction().equals( Intent.ACTION_PACKAGE_REPLACED ) ) {
String packageName = intent.getData().getSchemeSpecificPart();
notifyRefreshAppsList( packageName );
}
if ( intent.getAction().equals( Intent.ACTION_PACKAGE_CHANGED ) ) {
String packageName = intent.getData().getSchemeSpecificPart();
notifyRefreshAppsList( packageName );
}
if ( intent.getAction().equals( Intent.ACTION_PACKAGE_RESTARTED ) ) {
String packageName = intent.getData().getSchemeSpecificPart();
notifyRefreshAppsList( packageName );
}
if ( intent.getAction().equals( Intent.ACTION_PACKAGE_DATA_CLEARED ) ) {
String packageName = intent.getData().getSchemeSpecificPart();
notifyRefreshAppsList( packageName );
}
}
private void notifyRefreshAppsList( String packageName ) {
RefreshAppsListLiveData.getInstance().postValue( packageName );
}
}