diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 6e31bb9..d048109 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -43,6 +43,10 @@
android:name=".activity.contact.list.ContactListActivity"
android:launchMode="singleTask"
android:screenOrientation="portrait" />
+
{
+ private static final String TAG = "AppListActivity";
+
+ private MMKV mMMKV = MMKV.mmkvWithID(CommonConfig.MMKV_ID, MMKV.MULTI_PROCESS_MODE);
+
+ private MoreAppAdapter mMoreAppAdapter;
+
+
+ @Override
+ public boolean setNightMode() {
+ return true;
+ }
+
+ @Override
+ public boolean setfitWindow() {
+ return true;
+ }
+
+ @Override
+ protected int getLayoutId() {
+ return R.layout.activity_app_list;
+ }
+
+ @Override
+ protected void initDataBinding() {
+ mViewModel.setContext(this);
+ mViewModel.setVDBinding(mViewDataBinding);
+ mViewModel.setLifecycle(getLifecycleSubject());
+ mViewDataBinding.setClick(new BtnClick());
+ }
+
+ @Override
+ protected void initView() {
+ mMoreAppAdapter = new MoreAppAdapter(LoaderManager.getInstance(this));
+ mViewDataBinding.recyclerView.setLayoutManager(new GridLayoutManager(this, 3));
+ mViewDataBinding.recyclerView.setAdapter(mMoreAppAdapter);
+
+ }
+
+ @Override
+ protected void initData() {
+ mViewModel.mDesktopSortAppData.observe(this, new Observer>() {
+ @Override
+ public void onChanged(List desktopSortApps) {
+ mMoreAppAdapter.setDesktopSortApps(desktopSortApps);
+ }
+ });
+
+// mViewModel.getLauncherAppList();
+ mViewModel.getDbAppList();
+ }
+
+
+ public class BtnClick {
+
+ }
+}
diff --git a/app/src/main/java/com/ttstd/dialer/activity/app/AppListViewModel.java b/app/src/main/java/com/ttstd/dialer/activity/app/AppListViewModel.java
new file mode 100644
index 0000000..dfd27ac
--- /dev/null
+++ b/app/src/main/java/com/ttstd/dialer/activity/app/AppListViewModel.java
@@ -0,0 +1,153 @@
+package com.ttstd.dialer.activity.app;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.ResolveInfo;
+import android.util.Log;
+
+import androidx.lifecycle.MutableLiveData;
+
+import com.trello.rxlifecycle4.RxLifecycle;
+import com.trello.rxlifecycle4.android.ActivityEvent;
+import com.ttstd.dialer.base.mvvm.BaseViewModel;
+import com.ttstd.dialer.db.app.AppRepository;
+import com.ttstd.dialer.db.app.DesktopSortApp;
+import com.ttstd.dialer.databinding.ActivityAppListBinding;
+import com.ttstd.dialer.utils.ApkUtils;
+
+import java.text.Collator;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Locale;
+import java.util.concurrent.Callable;
+import java.util.stream.Collectors;
+
+import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
+import io.reactivex.rxjava3.annotations.NonNull;
+import io.reactivex.rxjava3.core.Observable;
+import io.reactivex.rxjava3.core.Observer;
+import io.reactivex.rxjava3.disposables.Disposable;
+import io.reactivex.rxjava3.functions.Function;
+import io.reactivex.rxjava3.schedulers.Schedulers;
+
+public class AppListViewModel extends BaseViewModel {
+ private static final String TAG = "AppListViewModel";
+
+ private AppRepository mAppRepository;
+
+ @Override
+ public void setContext(Context context) {
+ super.setContext(context);
+ mAppRepository = new AppRepository(context);
+ }
+
+ public MutableLiveData> mDesktopSortAppData = new MutableLiveData<>();
+
+ public void getDbAppList(){
+ Observable.fromCallable(new Callable>() {
+ @Override
+ public List call() throws Exception {
+ return mAppRepository.getAllContacts();
+ }
+ }) .compose(RxLifecycle.bindUntilEvent(getLifecycle(), ActivityEvent.DESTROY))
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(new Observer>() {
+ @Override
+ public void onSubscribe(@NonNull Disposable d) {
+ Log.e("getDbAppList", "onSubscribe: " );
+ }
+
+ @Override
+ public void onNext(@NonNull List desktopSortApps) {
+ Log.e("getDbAppList", "onNext: "+desktopSortApps );
+ mDesktopSortAppData.setValue(desktopSortApps);
+ }
+
+ @Override
+ public void onError(@NonNull Throwable e) {
+ Log.e("getDbAppList", "onError: " +e.getMessage());
+ }
+
+ @Override
+ public void onComplete() {
+ Log.e("getDbAppList", "onComplete: " );
+ }
+ });
+
+
+ }
+
+ public void getLauncherAppList() {
+ Observable.fromCallable(new Callable>() {
+ @Override
+ public List call() throws Exception {
+ return ApkUtils.getAllLauncherResolveInfo(getSafeContext());
+ }
+ })
+ .compose(RxLifecycle.bindUntilEvent(getLifecycle(), ActivityEvent.DESTROY))
+ .subscribeOn(Schedulers.io())
+ .map(new Function, List>() {
+ @Override
+ public List apply(List resolveInfos) throws Throwable {
+ List componentNames = resolveInfos.stream().map(new java.util.function.Function() {
+ @Override
+ public ComponentName apply(ResolveInfo resolveInfo) {
+ String packageName = resolveInfo.activityInfo.packageName;
+ String className = resolveInfo.activityInfo.name;
+ ComponentName componentName = new ComponentName(packageName, className);
+ return componentName;
+ }
+ }).collect(Collectors.toList());
+ return componentNames;
+ }
+ })
+ .compose(RxLifecycle.bindUntilEvent(getLifecycle(), ActivityEvent.DESTROY))
+ .subscribeOn(Schedulers.io())
+ .map(new Function, List>() {
+ @Override
+ public List apply(List componentNames) throws Throwable {
+ List desktopSortApps = componentNames.stream().map(new java.util.function.Function() {
+ @Override
+ public DesktopSortApp apply(ComponentName componentName) {
+ DesktopSortApp desktopSortApp = new DesktopSortApp(getSafeContext(), componentName);
+ return desktopSortApp;
+ }
+ }).sorted(new Comparator() {
+ @Override
+ public int compare(DesktopSortApp o1, DesktopSortApp o2) {
+ return Collator.getInstance(Locale.CHINESE).compare(o1.getLabel(), o2.getLabel());
+ }
+ }).collect(Collectors.toList());
+ return desktopSortApps;
+ }
+ })
+ .compose(RxLifecycle.bindUntilEvent(getLifecycle(), ActivityEvent.DESTROY))
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(new Observer>() {
+ @Override
+ public void onSubscribe(@NonNull Disposable d) {
+
+ }
+
+ @Override
+ public void onNext(@NonNull List desktopSortApps) {
+ Log.e(TAG, "getLauncherAppList" + "onNext: " + desktopSortApps);
+ mDesktopSortAppData.setValue(desktopSortApps);
+ }
+
+ @Override
+ public void onError(@NonNull Throwable e) {
+
+ }
+
+ @Override
+ public void onComplete() {
+
+ }
+ });
+
+ }
+
+}
diff --git a/app/src/main/java/com/ttstd/dialer/activity/main/MainActivity.java b/app/src/main/java/com/ttstd/dialer/activity/main/MainActivity.java
index 16bcece..3bac6dd 100644
--- a/app/src/main/java/com/ttstd/dialer/activity/main/MainActivity.java
+++ b/app/src/main/java/com/ttstd/dialer/activity/main/MainActivity.java
@@ -102,7 +102,7 @@ public class MainActivity extends BaseMvvmActivity {
+ private static final String TAG = "MainViewModel";
+
+ private AppRepository mAppRepository;
+
+ @Override
+ public void setContext(Context context) {
+ super.setContext(context);
+ mAppRepository = new AppRepository(context);
+ }
+
+ public void updateAppList() {
+ Observable.fromCallable(new Callable>() {
+ @Override
+ public List call() throws Exception {
+ return ApkUtils.getAllLauncherResolveInfo(getSafeContext());
+ }
+ })
+ .compose(RxLifecycle.bindUntilEvent(getLifecycle(), ActivityEvent.DESTROY))
+ .subscribeOn(Schedulers.io())
+ .map(new Function, List>() {
+ @Override
+ public List apply(List resolveInfos) throws Throwable {
+ List componentNames = resolveInfos.stream().map(new java.util.function.Function() {
+ @Override
+ public ComponentName apply(ResolveInfo resolveInfo) {
+ String packageName = resolveInfo.activityInfo.packageName;
+ String className = resolveInfo.activityInfo.name;
+ ComponentName componentName = new ComponentName(packageName, className);
+ return componentName;
+ }
+ }).collect(Collectors.toList());
+ return componentNames;
+ }
+ })
+ .compose(RxLifecycle.bindUntilEvent(getLifecycle(), ActivityEvent.DESTROY))
+ .subscribeOn(Schedulers.io())
+ .map(new Function, List>() {
+ @Override
+ public List apply(List componentNames) throws Throwable {
+ List desktopSortApps = componentNames.stream().map(new java.util.function.Function() {
+ @Override
+ public DesktopSortApp apply(ComponentName componentName) {
+ DesktopSortApp desktopSortApp = new DesktopSortApp(getSafeContext(), componentName);
+ return desktopSortApp;
+ }
+ }).sorted(new Comparator() {
+ @Override
+ public int compare(DesktopSortApp o1, DesktopSortApp o2) {
+ return Collator.getInstance(Locale.CHINESE).compare(o1.getLabel(), o2.getLabel());
+ }
+ }).collect(Collectors.toList());
+ return desktopSortApps;
+ }
+ })
+ .compose(RxLifecycle.bindUntilEvent(getLifecycle(), ActivityEvent.DESTROY))
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(new Observer>() {
+ @Override
+ public void onSubscribe(@NonNull Disposable d) {
+
+ }
+
+ @Override
+ public void onNext(@NonNull List desktopSortApps) {
+ Log.e(TAG, "getLauncherAppList" + "onNext: " + desktopSortApps);
+ }
+
+ @Override
+ public void onError(@NonNull Throwable e) {
+
+ }
+
+ @Override
+ public void onComplete() {
+
+ }
+ });
+ }
}
diff --git a/app/src/main/java/com/ttstd/dialer/adapter/MoreAppAdapter.java b/app/src/main/java/com/ttstd/dialer/adapter/MoreAppAdapter.java
new file mode 100644
index 0000000..b864704
--- /dev/null
+++ b/app/src/main/java/com/ttstd/dialer/adapter/MoreAppAdapter.java
@@ -0,0 +1,122 @@
+package com.ttstd.dialer.adapter;
+
+import android.content.ComponentName;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.constraintlayout.widget.ConstraintLayout;
+import androidx.fragment.app.FragmentActivity;
+import androidx.loader.app.LoaderManager;
+import androidx.loader.content.Loader;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.tencent.mmkv.MMKV;
+import com.ttstd.dialer.R;
+import com.ttstd.dialer.db.app.DesktopSortApp;
+import com.ttstd.dialer.config.CommonConfig;
+import com.ttstd.dialer.utils.ApkUtils;
+import com.ttstd.iconloader.IconCacheManager;
+import com.ttstd.iconloader.IconLoader;
+
+import org.jetbrains.annotations.NotNull;
+
+import java.util.List;
+
+public class MoreAppAdapter extends RecyclerView.Adapter implements LoaderManager.LoaderCallbacks {
+ private static final String TAG = "MoreAppAdapter";
+
+ private MMKV mMMKV = MMKV.mmkvWithID(CommonConfig.MMKV_ID, MMKV.MULTI_PROCESS_MODE);
+
+ private FragmentActivity mContext;
+ private LoaderManager mLoaderManager;
+ private IconCacheManager mIconCacheManager = IconCacheManager.getInstance();
+
+ public MoreAppAdapter(LoaderManager loaderManager) {
+ mLoaderManager = loaderManager;
+ }
+
+ public void setSelectApps(List selectApps) {
+
+ }
+
+ private List mDesktopSortApps;
+
+ public void setDesktopSortApps(List desktopSortApps) {
+ mDesktopSortApps = desktopSortApps;
+ notifyDataSetChanged();
+ }
+
+ @NonNull
+ @NotNull
+ @Override
+ public AppHolder onCreateViewHolder(@NonNull @NotNull ViewGroup parent, int viewType) {
+ mContext = (FragmentActivity) parent.getContext();
+ return new AppHolder(LayoutInflater.from(mContext).inflate(R.layout.item_app, parent, false));
+ }
+
+ @Override
+ public void onBindViewHolder(@NonNull @NotNull AppHolder holder, int position) {
+ DesktopSortApp desktopSortApp = mDesktopSortApps.get(position);
+ Drawable drawable = mIconCacheManager.getIcon(desktopSortApp.getComponentName().flattenToShortString());
+ if (drawable != null) {
+ holder.iv_icon.setImageDrawable(drawable);
+ } else {
+ mLoaderManager.restartLoader(position, null, this).forceLoad();
+ }
+ holder.tv_app_name.setText(desktopSortApp.getLabel());
+ holder.root.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ ApkUtils.openApp(mContext, desktopSortApp.getComponentName());
+ }
+ });
+ }
+
+ @Override
+ public int getItemCount() {
+ return mDesktopSortApps == null ? 0 : mDesktopSortApps.size();
+ }
+
+ @NonNull
+ @NotNull
+ @Override
+ public Loader onCreateLoader(int id, @Nullable @org.jetbrains.annotations.Nullable Bundle args) {
+ DesktopSortApp appInfo = mDesktopSortApps.get(id);
+ ComponentName componentName = appInfo.getComponentName(); // 从数据项中获取 ComponentName
+ return new IconLoader(mContext, componentName, mIconCacheManager);
+ }
+
+ @Override
+ public void onLoadFinished(@NonNull @NotNull Loader loader, Drawable data) {
+ int position = loader.getId();
+ notifyItemChanged(position);
+ }
+
+ @Override
+ public void onLoaderReset(@NonNull @NotNull Loader loader) {
+ Log.e(TAG, "onLoaderReset: ");
+ }
+
+ public class AppHolder extends RecyclerView.ViewHolder {
+
+ ConstraintLayout root;
+ ImageView iv_icon;
+ TextView tv_app_name;
+
+ public AppHolder(@NonNull @NotNull View itemView) {
+ super(itemView);
+ root = itemView.findViewById(R.id.root);
+ iv_icon = itemView.findViewById(R.id.iv_icon);
+ tv_app_name = itemView.findViewById(R.id.tv_app_name);
+ }
+ }
+
+}
diff --git a/app/src/main/java/com/ttstd/dialer/base/BaseApplication.java b/app/src/main/java/com/ttstd/dialer/base/BaseApplication.java
index 97a2ff4..91c5be7 100644
--- a/app/src/main/java/com/ttstd/dialer/base/BaseApplication.java
+++ b/app/src/main/java/com/ttstd/dialer/base/BaseApplication.java
@@ -16,7 +16,9 @@ import com.tencent.bugly.crashreport.CrashReport;
import com.tencent.mmkv.MMKV;
import com.ttstd.dialer.BuildConfig;
import com.ttstd.dialer.config.CommonConfig;
+import com.ttstd.dialer.manager.AppManager;
import com.ttstd.dialer.utils.SystemUtils;
+import com.ttstd.iconloader.IconCacheManager;
public class BaseApplication extends Application {
@@ -67,6 +69,9 @@ public class BaseApplication extends Application {
CrashReport.initCrashReport(getApplicationContext(), "845e3ed68c", false);
CrashReport.setDeviceId(this, Build.MODEL);
xcrash.XCrash.init(this);
+
+ AppManager.init(this);
+ IconCacheManager.init(this);
}
}
diff --git a/app/src/main/java/com/ttstd/dialer/db/app/AppDao.java b/app/src/main/java/com/ttstd/dialer/db/app/AppDao.java
new file mode 100644
index 0000000..049ff76
--- /dev/null
+++ b/app/src/main/java/com/ttstd/dialer/db/app/AppDao.java
@@ -0,0 +1,57 @@
+package com.ttstd.dialer.db.app;
+
+import androidx.room.Dao;
+import androidx.room.Delete;
+import androidx.room.Insert;
+import androidx.room.Query;
+import androidx.room.Update;
+
+import java.util.List;
+
+@Dao
+public interface AppDao {
+ // 基本查询:获取总行数
+ @Query("SELECT COUNT(*) FROM app_list")
+ Integer getTotalCount();
+
+ // 查询:根据特定列的非空值计数
+ @Query("SELECT COUNT(id) FROM app_list")
+ Integer getCountById();
+
+ @Query("SELECT * FROM app_list WHERE package_name = :packageName AND class_name = :className")
+ DesktopSortApp getAppInfo(String packageName, String className);
+
+ @Query("SELECT id FROM app_list WHERE package_name = :packageName AND class_name = :className")
+ Integer getIdByPackageAndClass(String packageName, String className);
+
+ // 检查数据是否存在(返回布尔值)
+ @Query("SELECT COUNT(*) FROM app_list WHERE package_name = :pkgName AND class_name = :clsName")
+ Integer checkAppInfoExists(String pkgName, String clsName);
+
+ @Insert
+ long insert(DesktopSortApp desktopSortApp);
+
+ @Insert
+ long[] insert(List contacts);
+
+ @Update
+ Integer update(DesktopSortApp desktopSortApp);
+
+ @Delete
+ Integer delete(DesktopSortApp desktopSortApp);
+
+ @Query("DELETE FROM app_list WHERE id = :id")
+ Integer deleteById(Integer id);
+
+ @Query("DELETE FROM app_list")
+ Integer deleteAll();
+
+ @Query("SELECT * FROM app_list ORDER BY position ASC")
+ List getAllApp();
+
+ @Query("SELECT * FROM app_list WHERE id = :id")
+ DesktopSortApp getAppById(Integer id);
+
+ @Query("SELECT * FROM app_list WHERE label LIKE :searchQuery OR package_name LIKE :searchQuery")
+ List searchApp(String searchQuery);
+}
diff --git a/app/src/main/java/com/ttstd/dialer/db/contact/AppDatabase.java b/app/src/main/java/com/ttstd/dialer/db/app/AppDatabase.java
similarity index 79%
rename from app/src/main/java/com/ttstd/dialer/db/contact/AppDatabase.java
rename to app/src/main/java/com/ttstd/dialer/db/app/AppDatabase.java
index 9b152d6..19e1251 100644
--- a/app/src/main/java/com/ttstd/dialer/db/contact/AppDatabase.java
+++ b/app/src/main/java/com/ttstd/dialer/db/app/AppDatabase.java
@@ -1,4 +1,4 @@
-package com.ttstd.dialer.db.contact;
+package com.ttstd.dialer.db.app;
import android.content.Context;
@@ -8,9 +8,9 @@ import androidx.room.RoomDatabase;
import java.io.File;
-@Database(entities = {Contact.class}, version = 1, exportSchema = false)
+@Database(entities = {DesktopSortApp.class}, version = 2, exportSchema = false)
public abstract class AppDatabase extends RoomDatabase {
- public abstract ContactDao contactDao();
+ public abstract AppDao appDao();
private static volatile AppDatabase INSTANCE;
@@ -20,7 +20,7 @@ public abstract class AppDatabase extends RoomDatabase {
synchronized (AppDatabase.class) {
if (INSTANCE == null) {
INSTANCE = Room.databaseBuilder(context.getApplicationContext(),
- AppDatabase.class, context.getExternalFilesDir("db") + File.separator + "contact_database")
+ AppDatabase.class, context.getExternalFilesDir("db") + File.separator + "app" + File.separator + "app_db")
// .allowMainThreadQueries() // 为了简化示例,允许主线程查询
.build();
}
diff --git a/app/src/main/java/com/ttstd/dialer/db/app/AppRepository.java b/app/src/main/java/com/ttstd/dialer/db/app/AppRepository.java
new file mode 100644
index 0000000..699d22f
--- /dev/null
+++ b/app/src/main/java/com/ttstd/dialer/db/app/AppRepository.java
@@ -0,0 +1,78 @@
+package com.ttstd.dialer.db.app;
+
+import android.content.Context;
+
+import java.util.List;
+
+public class AppRepository {
+ AppDao mAppDao;
+
+ public AppRepository(Context context) {
+ AppDatabase db = AppDatabase.getDatabase(context);
+ mAppDao = db.appDao();
+ }
+
+ public int getTotalCount() {
+ return mAppDao.getTotalCount();
+ }
+
+ public int getCountById() {
+ return mAppDao.getCountById();
+ }
+
+ public DesktopSortApp getAppInfo(String packageName, String className) {
+ return mAppDao.getAppInfo(packageName, className);
+ }
+
+ public int getIdByPackageAndClass(String packageName, String className) {
+ return mAppDao.getIdByPackageAndClass(packageName, className);
+ }
+
+ public int checkAppInfoExists(String packageName, String className) {
+ return mAppDao.checkAppInfoExists(packageName, className);
+ }
+
+ // 获取所有APP
+ public List getAllContacts() {
+ return mAppDao.getAllApp();
+ }
+
+ // 根据ID获取APP
+ public DesktopSortApp getContactById(int id) {
+ return mAppDao.getAppById(id);
+ }
+
+ // 搜索APP
+ public List searchContacts(String query) {
+ return mAppDao.searchApp("%" + query + "%");
+ }
+
+ // 添加APP
+ public long insert(DesktopSortApp contact) {
+ return mAppDao.insert(contact);
+ }
+
+ public long[] insert(List contacts) {
+ return mAppDao.insert(contacts);
+ }
+
+ // 更新APP
+ public int update(DesktopSortApp contact) {
+ return mAppDao.update(contact);
+ }
+
+ // 删除APP
+ public int delete(DesktopSortApp contact) {
+ return mAppDao.delete(contact);
+ }
+
+ // 根据ID删除APP
+ public int deleteById(int id) {
+ return mAppDao.deleteById(id);
+ }
+
+ // 删除所有APP
+ public int deleteAll() {
+ return mAppDao.deleteAll();
+ }
+}
diff --git a/app/src/main/java/com/ttstd/dialer/db/app/ComponentNameConverter.java b/app/src/main/java/com/ttstd/dialer/db/app/ComponentNameConverter.java
new file mode 100644
index 0000000..58536ba
--- /dev/null
+++ b/app/src/main/java/com/ttstd/dialer/db/app/ComponentNameConverter.java
@@ -0,0 +1,27 @@
+package com.ttstd.dialer.db.app;
+
+import android.content.ComponentName;
+import androidx.room.TypeConverter;
+
+public class ComponentNameConverter {
+
+ @TypeConverter
+ public static String fromComponentName(ComponentName componentName) {
+ // 如果 componentName 为 null,则返回 null
+ if (componentName == null) {
+ return null;
+ }
+ // 将 ComponentName 转换为其字符串形式(例如:"com.example.app/.MyService")
+ return componentName.flattenToString();
+ }
+
+ @TypeConverter
+ public static ComponentName toComponentName(String componentNameString) {
+ // 如果字符串为 null 或空,则返回 null
+ if (componentNameString == null || componentNameString.isEmpty()) {
+ return null;
+ }
+ // 从字符串形式解包为 ComponentName 对象
+ return ComponentName.unflattenFromString(componentNameString);
+ }
+}
diff --git a/app/src/main/java/com/ttstd/dialer/db/app/DesktopSortApp.java b/app/src/main/java/com/ttstd/dialer/db/app/DesktopSortApp.java
new file mode 100644
index 0000000..0dd1967
--- /dev/null
+++ b/app/src/main/java/com/ttstd/dialer/db/app/DesktopSortApp.java
@@ -0,0 +1,118 @@
+package com.ttstd.dialer.db.app;
+
+import android.content.ComponentName;
+import android.content.Context;
+
+import androidx.annotation.Nullable;
+import androidx.room.ColumnInfo;
+import androidx.room.Entity;
+import androidx.room.Index;
+import androidx.room.PrimaryKey;
+import androidx.room.TypeConverters;
+
+import com.ttstd.dialer.utils.ApkUtils;
+
+import java.io.Serializable;
+import java.util.Objects;
+
+@Entity(tableName = "app_list", indices = {@Index(value = "component_name", unique = true)})
+@TypeConverters({ComponentNameConverter.class})
+public class DesktopSortApp implements Serializable {
+ private static final long serialVersionUID = 9113517079637096245L;
+
+ @PrimaryKey(autoGenerate = true)
+ private int id;
+ @ColumnInfo(name = "component_name")
+ private ComponentName componentName;
+ @ColumnInfo(name = "label")
+ private String mLabel;
+ @ColumnInfo(name = "package_name")
+ private String mPackageName;
+ @ColumnInfo(name = "class_name")
+ private String mClassName;
+ @ColumnInfo(name = "position")
+ private int mPosition;
+
+ public DesktopSortApp() {
+ }
+
+ public DesktopSortApp(Context context, ComponentName componentName) {
+ this.componentName = componentName;
+ mPackageName = componentName.getPackageName();
+ mClassName = componentName.getClassName();
+ mPosition = 0;
+ mLabel = ApkUtils.getAppName(context, componentName);
+ }
+
+ public DesktopSortApp(Context context, ComponentName componentName, int pos) {
+ this.componentName = componentName;
+ mPackageName = componentName.getPackageName();
+ mClassName = componentName.getClassName();
+ mPosition = pos;
+ mLabel = ApkUtils.getAppName(context, componentName);
+ }
+
+ public int getId() {
+ return id;
+ }
+
+ public void setId(int id) {
+ this.id = id;
+ }
+
+ public ComponentName getComponentName() {
+ return componentName;
+ }
+
+ public void setComponentName(ComponentName componentName) {
+ this.componentName = componentName;
+ }
+
+ public String getLabel() {
+ return mLabel;
+ }
+
+ public void setLabel(String label) {
+ this.mLabel = label;
+ }
+
+ public String getPackageName() {
+ return mPackageName;
+ }
+
+ public void setPackageName(String packageName) {
+ this.mPackageName = packageName;
+ }
+
+ public String getClassName() {
+ return mClassName;
+ }
+
+ public void setClassName(String className) {
+ this.mClassName = className;
+ }
+
+ public int getPosition() {
+ return mPosition;
+ }
+
+ public void setPosition(int position) {
+ this.mPosition = position;
+ }
+
+ @Override
+ public boolean equals(@Nullable @org.jetbrains.annotations.Nullable Object obj) {
+ if (obj instanceof DesktopSortApp) {
+ return Objects.equals(componentName, ((DesktopSortApp) obj).componentName);
+ } else if (obj instanceof ComponentName) {
+ return Objects.equals(componentName, obj);
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ return componentName.hashCode();
+ }
+}
diff --git a/app/src/main/java/com/ttstd/dialer/db/contact/ContactDatabase.java b/app/src/main/java/com/ttstd/dialer/db/contact/ContactDatabase.java
new file mode 100644
index 0000000..1eb148d
--- /dev/null
+++ b/app/src/main/java/com/ttstd/dialer/db/contact/ContactDatabase.java
@@ -0,0 +1,31 @@
+package com.ttstd.dialer.db.contact;
+
+import android.content.Context;
+
+import androidx.room.Database;
+import androidx.room.Room;
+import androidx.room.RoomDatabase;
+
+import java.io.File;
+
+@Database(entities = {Contact.class}, version = 1, exportSchema = false)
+public abstract class ContactDatabase extends RoomDatabase {
+ public abstract ContactDao contactDao();
+
+ private static volatile ContactDatabase INSTANCE;
+
+ // 单例模式获取数据库实例
+ public static ContactDatabase getDatabase(final Context context) {
+ if (INSTANCE == null) {
+ synchronized (ContactDatabase.class) {
+ if (INSTANCE == null) {
+ INSTANCE = Room.databaseBuilder(context.getApplicationContext(),
+ ContactDatabase.class, context.getExternalFilesDir("db") + File.separator + "contact" + File.separator + "contact_database")
+// .allowMainThreadQueries() // 为了简化示例,允许主线程查询
+ .build();
+ }
+ }
+ }
+ return INSTANCE;
+ }
+}
diff --git a/app/src/main/java/com/ttstd/dialer/db/contact/ContactRepository.java b/app/src/main/java/com/ttstd/dialer/db/contact/ContactRepository.java
index 6bade65..97e8ff3 100644
--- a/app/src/main/java/com/ttstd/dialer/db/contact/ContactRepository.java
+++ b/app/src/main/java/com/ttstd/dialer/db/contact/ContactRepository.java
@@ -9,7 +9,7 @@ public class ContactRepository {
// 构造函数,获取数据库访问对象
public ContactRepository(Context context) {
- AppDatabase db = AppDatabase.getDatabase(context);
+ ContactDatabase db = ContactDatabase.getDatabase(context);
mContactDao = db.contactDao();
}
diff --git a/app/src/main/java/com/ttstd/dialer/fragment/home/HomeFragment.java b/app/src/main/java/com/ttstd/dialer/fragment/home/HomeFragment.java
index ac56cfa..8ad2888 100644
--- a/app/src/main/java/com/ttstd/dialer/fragment/home/HomeFragment.java
+++ b/app/src/main/java/com/ttstd/dialer/fragment/home/HomeFragment.java
@@ -16,6 +16,7 @@ import androidx.fragment.app.Fragment;
import com.hjq.toast.Toaster;
import com.ttstd.dialer.R;
+import com.ttstd.dialer.activity.app.AppListActivity;
import com.ttstd.dialer.activity.contact.list.ContactListActivity;
import com.ttstd.dialer.base.mvvm.fragment.BaseMvvmFragment;
import com.ttstd.dialer.databinding.FragmentHomeBinding;
@@ -186,12 +187,7 @@ public class HomeFragment extends BaseMvvmFragment
+ *
+ * @author: 小嵩
+ * @date: 2017/3/16 16:22
+
+ */
+
+public class GetJsonDataUtil {
+
+
+ public String getJson(Context context, String fileName) {
+
+ StringBuilder stringBuilder = new StringBuilder();
+ try {
+ AssetManager assetManager = context.getAssets();
+ BufferedReader bf = new BufferedReader(new InputStreamReader(
+ assetManager.open(fileName)));
+ String line;
+ while ((line = bf.readLine()) != null) {
+ stringBuilder.append(line);
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return stringBuilder.toString();
+ }
+}
+
diff --git a/app/src/main/java/com/ttstd/dialer/gson/GsonUtils.java b/app/src/main/java/com/ttstd/dialer/gson/GsonUtils.java
new file mode 100644
index 0000000..fd7f6b6
--- /dev/null
+++ b/app/src/main/java/com/ttstd/dialer/gson/GsonUtils.java
@@ -0,0 +1,153 @@
+package com.ttstd.dialer.gson;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+import com.google.gson.reflect.TypeToken;
+
+import java.lang.reflect.Type;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+
+public class GsonUtils {
+ //https://blog.csdn.net/zte1055889498/article/details/122400299
+
+ public static JsonObject getJsonObject(String jsonString) {
+ JsonObject jsonObject = JsonParser.parseString(jsonString).getAsJsonObject();
+ return jsonObject;
+ }
+
+ private static final Gson gson;
+ private static final Gson exposeGson;
+
+ static {
+ GsonBuilder builder = new GsonBuilder();
+ builder.registerTypeAdapterFactory(new NullStringToEmptyAdapterFactory());
+ builder.registerTypeAdapter(Integer.class, new IntegerDefault0Adapter());
+ builder.registerTypeAdapter(int.class, new IntegerDefault0Adapter());
+ builder.disableHtmlEscaping();
+ builder.enableComplexMapKeySerialization();
+ // builder.excludeFieldsWithoutExposeAnnotation();
+ builder.setDateFormat("yyyy-MM-dd HH:mm:ss");
+ gson = builder.create();
+ exposeGson = new GsonBuilder()
+ .excludeFieldsWithoutExposeAnnotation()
+ .create();
+ }
+
+ public static Type makeJavaType(Type rawType, Type... typeArguments) {
+ return TypeToken.getParameterized(rawType, typeArguments).getType();
+ }
+
+ public static String toString(Object value) {
+ if (Objects.isNull(value)) {
+ return null;
+ }
+ if (value instanceof String) {
+ return (String) value;
+ }
+ return toJSONString(value);
+ }
+
+ public static String toJSONString(Object value) {
+ return gson.toJson(value);
+ }
+
+ public static String toExposeJSONString(Object value) {
+ return gson.toJson(value);
+ }
+
+
+ public static String toPrettyString(Object value) {
+ return gson.newBuilder().setPrettyPrinting().create().toJson(value);
+ }
+
+ public static JsonElement fromJavaObject(Object value) {
+ JsonElement result = null;
+ if (Objects.nonNull(value) && (value instanceof String)) {
+ result = parseObject((String) value);
+ } else {
+ result = gson.toJsonTree(value);
+ }
+ return result;
+ }
+
+ public static JsonElement parseObject(String content) {
+ return JsonParser.parseString(content);
+ }
+
+ public static JsonElement getJsonElement(JsonObject node, String name) {
+ return node.get(name);
+ }
+
+ public static JsonElement getJsonElement(JsonArray node, int index) {
+ return node.get(index);
+ }
+
+ public static T toJavaObject(JsonElement node, Class clazz) {
+ return gson.fromJson(node, clazz);
+ }
+
+ public static T toJavaObject(JsonElement node, Type type) {
+ return gson.fromJson(node, type);
+ }
+
+ public static T toJavaObject(JsonElement node, TypeToken> typeToken) {
+ return toJavaObject(node, typeToken.getType());
+ }
+
+ public static List toJavaList(JsonElement node, Class clazz) {
+ return toJavaObject(node, makeJavaType(List.class, clazz));
+ }
+
+ public static List