diff --git a/app/src/main/java/com/ttstd/dialer/activity/app/AppListActivity.java b/app/src/main/java/com/ttstd/dialer/activity/app/AppListActivity.java index 6a61487..e65d559 100644 --- a/app/src/main/java/com/ttstd/dialer/activity/app/AppListActivity.java +++ b/app/src/main/java/com/ttstd/dialer/activity/app/AppListActivity.java @@ -8,9 +8,9 @@ import com.tencent.mmkv.MMKV; import com.ttstd.dialer.R; import com.ttstd.dialer.adapter.MoreAppAdapter; import com.ttstd.dialer.base.mvvm.BaseMvvmActivity; -import com.ttstd.dialer.db.app.DesktopSortApp; import com.ttstd.dialer.config.CommonConfig; import com.ttstd.dialer.databinding.ActivityAppListBinding; +import com.ttstd.dialer.db.app.AppInfo; import java.util.List; @@ -48,6 +48,13 @@ public class AppListActivity extends BaseMvvmActivity>() { + mViewModel.mDesktopSortAppData.observe(this, new Observer>() { @Override - public void onChanged(List desktopSortApps) { - mMoreAppAdapter.setDesktopSortApps(desktopSortApps); + public void onChanged(List appInfos) { + mMoreAppAdapter.setAppInfos(appInfos); } }); -// mViewModel.getLauncherAppList(); mViewModel.getDbAppList(); + + mViewModel.mAppUpdateData.observe(this, new Observer() { + @Override + public void onChanged(Integer integer) { + if (integer > 0) { + + } + mViewModel.getDbAppList(); + } + }); } 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 index 9b591d5..35c7e94 100644 --- a/app/src/main/java/com/ttstd/dialer/activity/app/AppListViewModel.java +++ b/app/src/main/java/com/ttstd/dialer/activity/app/AppListViewModel.java @@ -11,8 +11,8 @@ import com.trello.rxlifecycle4.RxLifecycle; import com.trello.rxlifecycle4.android.ActivityEvent; import com.ttstd.dialer.base.mvvm.BaseViewModel; import com.ttstd.dialer.databinding.ActivityAppListBinding; +import com.ttstd.dialer.db.app.AppInfo; import com.ttstd.dialer.db.app.AppRepository; -import com.ttstd.dialer.db.app.DesktopSortApp; import com.ttstd.dialer.utils.ApkUtils; import java.text.Collator; @@ -41,27 +41,27 @@ public class AppListViewModel extends BaseViewModel> mDesktopSortAppData = new MutableLiveData<>(); + public MutableLiveData> mDesktopSortAppData = new MutableLiveData<>(); public void getDbAppList() { - Observable.fromCallable(new Callable>() { + Observable.fromCallable(new Callable>() { @Override - public List call() throws Exception { - return mAppRepository.getAllApp(); + public List call() throws Exception { + return mAppRepository.getInsideApp(); } }).compose(RxLifecycle.bindUntilEvent(getLifecycle(), ActivityEvent.DESTROY)) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) - .subscribe(new Observer>() { + .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); + public void onNext(@NonNull List appInfos) { + Log.e("getDbAppList", "onNext: " + appInfos); + mDesktopSortAppData.setValue(appInfos); } @Override @@ -74,80 +74,41 @@ public class AppListViewModel extends BaseViewModel>() { + public MutableLiveData mAppUpdateData = new MutableLiveData<>(); + + public void updateAppInfo(AppInfo appInfo){ + Observable.fromCallable(new Callable() { @Override - public List call() throws Exception { - return ApkUtils.getAllLauncherResolveInfo(getSafeContext()); + public Integer call() throws Exception { + return mAppRepository.update(appInfo); } - }) - .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)) + }).compose(RxLifecycle.bindUntilEvent(getLifecycle(), ActivityEvent.DESTROY)) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) - .subscribe(new Observer>() { + .subscribe(new Observer() { @Override public void onSubscribe(@NonNull Disposable d) { - + Log.e("updateAppInfo", "onSubscribe: "); } @Override - public void onNext(@NonNull List desktopSortApps) { - Log.e(TAG, "getLauncherAppList" + "onNext: " + desktopSortApps); - mDesktopSortAppData.setValue(desktopSortApps); + public void onNext(@NonNull Integer row) { + Log.e("updateAppInfo", "onNext: " + row); + mAppUpdateData.setValue(row); } @Override public void onError(@NonNull Throwable e) { - + Log.e("updateAppInfo", "onError: " + e.getMessage()); } @Override public void onComplete() { - + Log.e("updateAppInfo", "onComplete: "); } }); - } } diff --git a/app/src/main/java/com/ttstd/dialer/activity/contact/add/ContactAddViewModel.java b/app/src/main/java/com/ttstd/dialer/activity/contact/add/ContactAddViewModel.java index 2bbda6b..23875eb 100644 --- a/app/src/main/java/com/ttstd/dialer/activity/contact/add/ContactAddViewModel.java +++ b/app/src/main/java/com/ttstd/dialer/activity/contact/add/ContactAddViewModel.java @@ -9,7 +9,7 @@ import com.trello.rxlifecycle4.RxLifecycle; import com.trello.rxlifecycle4.android.ActivityEvent; import com.ttstd.dialer.base.mvvm.BaseViewModel; import com.ttstd.dialer.databinding.ActivityContactAddBinding; -import com.ttstd.dialer.db.contact.Contact; +import com.ttstd.dialer.db.contact.ContactInfo; import com.ttstd.dialer.db.contact.ContactRepository; import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers; @@ -38,9 +38,9 @@ public class ContactAddViewModel extends BaseViewModel emitter) throws Throwable { int count = mRepository.getTotalCount() + 1; - Contact contact = new Contact(name, phone, count); - Log.e(TAG, "saveContact: " + contact); - emitter.onNext(mRepository.insert(contact)); + ContactInfo contactInfo = new ContactInfo(name, phone, count); + Log.e(TAG, "saveContact: " + contactInfo); + emitter.onNext(mRepository.insert(contactInfo)); emitter.onComplete(); } }).compose(RxLifecycle.bindUntilEvent(getLifecycle(), ActivityEvent.DESTROY)) diff --git a/app/src/main/java/com/ttstd/dialer/activity/contact/list/ContactListActivity.java b/app/src/main/java/com/ttstd/dialer/activity/contact/list/ContactListActivity.java index 3be639a..185901a 100644 --- a/app/src/main/java/com/ttstd/dialer/activity/contact/list/ContactListActivity.java +++ b/app/src/main/java/com/ttstd/dialer/activity/contact/list/ContactListActivity.java @@ -1,14 +1,11 @@ package com.ttstd.dialer.activity.contact.list; -import android.Manifest; import android.content.Intent; import android.content.pm.PackageManager; -import android.net.Uri; import android.util.Log; import android.view.View; import androidx.annotation.NonNull; -import androidx.core.app.ActivityCompat; import androidx.lifecycle.Observer; import androidx.recyclerview.widget.ItemTouchHelper; import androidx.recyclerview.widget.LinearLayoutManager; @@ -18,7 +15,7 @@ import com.ttstd.dialer.activity.contact.add.ContactAddActivity; import com.ttstd.dialer.adapter.ContactInfoAdapter; import com.ttstd.dialer.base.mvvm.BaseMvvmActivity; import com.ttstd.dialer.databinding.ActivityContactListBinding; -import com.ttstd.dialer.db.contact.Contact; +import com.ttstd.dialer.db.contact.ContactInfo; import com.ttstd.dialer.fragment.dialog.call.CallFragment; import com.ttstd.dialer.view.ItemTouchHelperCallback; @@ -31,7 +28,7 @@ public class ContactListActivity extends BaseMvvmActivity mContacts; + private List mContactInfos; @Override public boolean setNightMode() { @@ -63,14 +60,14 @@ public class ContactListActivity extends BaseMvvmActivity>() { + mViewModel.mContactListData.observe(this, new Observer>() { @Override - public void onChanged(List contacts) { - Log.e(TAG, "mContactListData: " + contacts); - mContacts = contacts; - mContactInfoAdapter.setContacts(mContacts); + public void onChanged(List contactInfos) { + Log.e(TAG, "mContactListData: " + contactInfos); + mContactInfos = contactInfos; + mContactInfoAdapter.setContactInfos(mContactInfos); } }); } diff --git a/app/src/main/java/com/ttstd/dialer/activity/contact/list/ContactListViewModel.java b/app/src/main/java/com/ttstd/dialer/activity/contact/list/ContactListViewModel.java index f821973..ece0a01 100644 --- a/app/src/main/java/com/ttstd/dialer/activity/contact/list/ContactListViewModel.java +++ b/app/src/main/java/com/ttstd/dialer/activity/contact/list/ContactListViewModel.java @@ -9,7 +9,7 @@ import com.trello.rxlifecycle4.RxLifecycle; import com.trello.rxlifecycle4.android.ActivityEvent; import com.ttstd.dialer.base.mvvm.BaseViewModel; import com.ttstd.dialer.databinding.ActivityContactListBinding; -import com.ttstd.dialer.db.contact.Contact; +import com.ttstd.dialer.db.contact.ContactInfo; import com.ttstd.dialer.db.contact.ContactRepository; import java.util.List; @@ -33,29 +33,29 @@ public class ContactListViewModel extends BaseViewModel> mContactListData = new MutableLiveData<>(); + public MutableLiveData> mContactListData = new MutableLiveData<>(); public void getAllContacts() { - Observable.create(new ObservableOnSubscribe>() { + Observable.create(new ObservableOnSubscribe>() { @Override - public void subscribe(@NonNull ObservableEmitter> emitter) throws Throwable { - List contacts = mRepository.getAllContacts(); - emitter.onNext(contacts); + public void subscribe(@NonNull ObservableEmitter> emitter) throws Throwable { + List contactInfos = mRepository.getAllContacts(); + emitter.onNext(contactInfos); emitter.onComplete(); } }).compose(RxLifecycle.bindUntilEvent(getLifecycle(), ActivityEvent.DESTROY)) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) - .subscribe(new Observer>() { + .subscribe(new Observer>() { @Override public void onSubscribe(@NonNull Disposable d) { Log.e("getAllContacts", "onSubscribe: "); } @Override - public void onNext(@NonNull List contacts) { + public void onNext(@NonNull List contactInfos) { Log.e("getAllContacts", "onNext: "); - mContactListData.setValue(contacts); + mContactListData.setValue(contactInfos); // List sorted = contacts.stream().sorted(new Comparator() { // @Override @@ -78,12 +78,12 @@ public class ContactListViewModel extends BaseViewModel() { @Override public void subscribe(@NonNull ObservableEmitter emitter) throws Throwable { - int id = mRepository.update(contact); + int id = mRepository.update(contactInfo); emitter.onNext(id); emitter.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..e594a4c 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 @@ -4,14 +4,19 @@ import android.util.Log; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentManager; +import androidx.lifecycle.Observer; +import androidx.loader.app.LoaderManager; import com.tencent.mmkv.MMKV; import com.ttstd.dialer.R; import com.ttstd.dialer.base.mvvm.BaseMvvmActivity; import com.ttstd.dialer.config.CommonConfig; import com.ttstd.dialer.databinding.ActivityMainBinding; +import com.ttstd.dialer.db.app.AppInfo; +import com.ttstd.dialer.fragment.app.AppFragment; import com.ttstd.dialer.fragment.contact.ContactFragment; import com.ttstd.dialer.fragment.home.HomeFragment; +import com.ttstd.dialer.view.ApkPagerAdapter; import com.ttstd.dialer.view.BaseFragmentPagerAdapter; import com.ttstd.dialer.view.ScaleCircleNavigator; @@ -25,7 +30,8 @@ public class MainActivity extends BaseMvvmActivity mFragments = new ArrayList<>(); private HomeFragment mHomeFragment; @@ -34,8 +40,12 @@ public class MainActivity extends BaseMvvmActivity mAppInfos; + @Override public boolean setNightMode() { @@ -62,18 +72,21 @@ public class MainActivity extends BaseMvvmActivity> mDesktopSortAppData = new MutableLiveData<>(); + + public void getOutsideApp() { + Observable.fromCallable(new Callable>() { + @Override + public List call() throws Exception { + return mAppRepository.getOutsideApp(); + } + }).compose(RxLifecycle.bindUntilEvent(getLifecycle(), ActivityEvent.DESTROY)) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(new Observer>() { + @Override + public void onSubscribe(@NonNull Disposable d) { + Log.e("getOutsideApp", "onSubscribe: "); + } + + @Override + public void onNext(@NonNull List appInfos) { + Log.e("getOutsideApp", "onNext: " + appInfos); + mDesktopSortAppData.setValue(appInfos); + } + + @Override + public void onError(@NonNull Throwable e) { + Log.e("getOutsideApp", "onError: " + e.getMessage()); + } + + @Override + public void onComplete() { + Log.e("getOutsideApp", "onComplete: "); + } + }); + } } diff --git a/app/src/main/java/com/ttstd/dialer/adapter/AppAdapter.java b/app/src/main/java/com/ttstd/dialer/adapter/AppAdapter.java new file mode 100644 index 0000000..5799114 --- /dev/null +++ b/app/src/main/java/com/ttstd/dialer/adapter/AppAdapter.java @@ -0,0 +1,152 @@ +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.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.shehuan.niv.NiceImageView; +import com.tencent.mmkv.MMKV; +import com.ttstd.dialer.R; +import com.ttstd.dialer.config.CommonConfig; +import com.ttstd.dialer.db.app.AppInfo; +import com.ttstd.dialer.fragment.dialog.shortcut.ShortcutDialogFagment; +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 AppAdapter extends RecyclerView.Adapter implements LoaderManager.LoaderCallbacks { + private static final String TAG = "AppAdapter"; + + private MMKV mMMKV = MMKV.mmkvWithID(CommonConfig.MMKV_ID, MMKV.MULTI_PROCESS_MODE); + + private FragmentActivity mContext; + private LoaderManager mLoaderManager; + private IconCacheManager mIconCacheManager = IconCacheManager.getInstance(); + + public AppAdapter(LoaderManager loaderManager) { + mLoaderManager = loaderManager; + } + + private List mAppInfos; + + public void setAppInfos(List appInfos) { + mAppInfos = appInfos; + notifyDataSetChanged(); + } + + public interface ShortcutCallback { + void setAppInside(AppInfo appInfo); + } + + private ShortcutCallback mShortcutCallback; + + public void setShortcutCallback(ShortcutCallback shortcutCallback) { + mShortcutCallback = shortcutCallback; + } + + @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) { + AppInfo appInfo = mAppInfos.get(position); + Drawable drawable = mIconCacheManager.getIcon(appInfo.getComponentName().flattenToShortString()); + if (drawable != null) { + holder.iv_icon.setImageDrawable(drawable); + } else { + mLoaderManager.restartLoader(position, null, this).forceLoad(); + } + holder.tv_app_name.setText(appInfo.getLabel()); + holder.root.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + ApkUtils.openApp(mContext, appInfo.getComponentName()); + } + }); + holder.root.setOnLongClickListener(new View.OnLongClickListener() { + @Override + public boolean onLongClick(View v) { + ShortcutDialogFagment shortcutDialogFagment = new ShortcutDialogFagment(appInfo); + shortcutDialogFagment.setTitil("温馨提示"); + shortcutDialogFagment.setTips("是否将应用放入更多应用"); + shortcutDialogFagment.setOnClickListener(new ShortcutDialogFagment.OnClickListener() { + @Override + public void onPositiveClick() { + if (mShortcutCallback != null) + mShortcutCallback.setAppInside(appInfo); + shortcutDialogFagment.dismiss(); + } + + @Override + public void onNegativeClick() { + shortcutDialogFagment.dismiss(); + } + }); + shortcutDialogFagment.show(mContext.getSupportFragmentManager(), "ShortcutDialogFagment"); + return false; + } + }); + } + + @Override + public int getItemCount() { + return mAppInfos == null ? 0 : mAppInfos.size(); + } + + @NonNull + @NotNull + @Override + public Loader onCreateLoader(int id, @Nullable @org.jetbrains.annotations.Nullable Bundle args) { + AppInfo appInfo = mAppInfos.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; + NiceImageView 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/adapter/ContactInfoAdapter.java b/app/src/main/java/com/ttstd/dialer/adapter/ContactInfoAdapter.java index 432b220..73d5861 100644 --- a/app/src/main/java/com/ttstd/dialer/adapter/ContactInfoAdapter.java +++ b/app/src/main/java/com/ttstd/dialer/adapter/ContactInfoAdapter.java @@ -1,9 +1,5 @@ package com.ttstd.dialer.adapter; -import android.Manifest; -import android.content.Intent; -import android.content.pm.PackageManager; -import android.net.Uri; import android.util.Log; import android.view.LayoutInflater; import android.view.View; @@ -12,13 +8,12 @@ import android.widget.TextView; import androidx.annotation.NonNull; import androidx.constraintlayout.widget.ConstraintLayout; -import androidx.core.app.ActivityCompat; import androidx.fragment.app.FragmentActivity; import androidx.recyclerview.widget.RecyclerView; import com.shehuan.niv.NiceImageView; import com.ttstd.dialer.R; -import com.ttstd.dialer.db.contact.Contact; +import com.ttstd.dialer.db.contact.ContactInfo; import java.util.Collections; import java.util.List; @@ -28,10 +23,10 @@ public class ContactInfoAdapter extends RecyclerView.Adapter mContacts; + private List mContactInfos; - public void setContacts(List contacts) { - mContacts = contacts; + public void setContactInfos(List contactInfos) { + mContactInfos = contactInfos; notifyDataSetChanged(); } @@ -48,7 +43,7 @@ public class ContactInfoAdapter extends RecyclerView.Adapter toPosition; i--) { - Collections.swap(mContacts, i, i - 1); + Collections.swap(mContactInfos, i, i - 1); } } notifyItemMoved(fromPosition, toPosition); diff --git a/app/src/main/java/com/ttstd/dialer/adapter/HomeContactAdapter.java b/app/src/main/java/com/ttstd/dialer/adapter/HomeContactAdapter.java index eceb511..fe5f961 100644 --- a/app/src/main/java/com/ttstd/dialer/adapter/HomeContactAdapter.java +++ b/app/src/main/java/com/ttstd/dialer/adapter/HomeContactAdapter.java @@ -13,7 +13,7 @@ import androidx.recyclerview.widget.RecyclerView; import com.shehuan.niv.NiceImageView; import com.ttstd.dialer.R; -import com.ttstd.dialer.db.contact.Contact; +import com.ttstd.dialer.db.contact.ContactInfo; import java.util.Collections; import java.util.List; @@ -23,10 +23,10 @@ public class HomeContactAdapter extends RecyclerView.Adapter mContacts; + private List mContactInfos; - public void setContacts(List contacts) { - mContacts = contacts; + public void setContactInfos(List contactInfos) { + mContactInfos = contactInfos; notifyDataSetChanged(); } @@ -43,7 +43,7 @@ public class HomeContactAdapter extends RecyclerView.Adapter toPosition; i--) { - Collections.swap(mContacts, i, i - 1); + Collections.swap(mContactInfos, i, i - 1); } } notifyItemMoved(fromPosition, toPosition); diff --git a/app/src/main/java/com/ttstd/dialer/adapter/MoreAppAdapter.java b/app/src/main/java/com/ttstd/dialer/adapter/MoreAppAdapter.java index b864704..462bedc 100644 --- a/app/src/main/java/com/ttstd/dialer/adapter/MoreAppAdapter.java +++ b/app/src/main/java/com/ttstd/dialer/adapter/MoreAppAdapter.java @@ -7,7 +7,6 @@ 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; @@ -18,10 +17,12 @@ import androidx.loader.app.LoaderManager; import androidx.loader.content.Loader; import androidx.recyclerview.widget.RecyclerView; +import com.shehuan.niv.NiceImageView; 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.db.app.AppInfo; +import com.ttstd.dialer.fragment.dialog.shortcut.ShortcutDialogFagment; import com.ttstd.dialer.utils.ApkUtils; import com.ttstd.iconloader.IconCacheManager; import com.ttstd.iconloader.IconLoader; @@ -43,53 +44,87 @@ public class MoreAppAdapter extends RecyclerView.Adapter selectApps) { + public void setSelectApps(List selectApps) { } - private List mDesktopSortApps; + private List mAppInfos; - public void setDesktopSortApps(List desktopSortApps) { - mDesktopSortApps = desktopSortApps; + public void setAppInfos(List appInfos) { + mAppInfos = appInfos; notifyDataSetChanged(); } + public interface ShortcutCallback { + void setAppOutside(AppInfo appInfo); + } + + private ShortcutCallback mShortcutCallback; + + public void setShortcutCallback(ShortcutCallback shortcutCallback) { + mShortcutCallback = shortcutCallback; + } + @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)); + return new AppHolder(LayoutInflater.from(mContext).inflate(R.layout.item_more_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()); + AppInfo appInfo = mAppInfos.get(position); + Drawable drawable = mIconCacheManager.getIcon(appInfo.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.tv_app_name.setText(appInfo.getLabel()); holder.root.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - ApkUtils.openApp(mContext, desktopSortApp.getComponentName()); + ApkUtils.openApp(mContext, appInfo.getComponentName()); + } + }); + holder.root.setOnLongClickListener(new View.OnLongClickListener() { + @Override + public boolean onLongClick(View v) { + ShortcutDialogFagment shortcutDialogFagment = new ShortcutDialogFagment(appInfo); + shortcutDialogFagment.setTitil("温馨提示"); + shortcutDialogFagment.setTips("是否将应用放在桌面显示"); + + shortcutDialogFagment.setOnClickListener(new ShortcutDialogFagment.OnClickListener() { + @Override + public void onPositiveClick() { + if (mShortcutCallback != null) + mShortcutCallback.setAppOutside(appInfo); + shortcutDialogFagment.dismiss(); + } + + @Override + public void onNegativeClick() { + shortcutDialogFagment.dismiss(); + } + }); + shortcutDialogFagment.show(mContext.getSupportFragmentManager(), "ShortcutDialogFagment"); + return false; } }); } @Override public int getItemCount() { - return mDesktopSortApps == null ? 0 : mDesktopSortApps.size(); + return mAppInfos == null ? 0 : mAppInfos.size(); } @NonNull @NotNull @Override public Loader onCreateLoader(int id, @Nullable @org.jetbrains.annotations.Nullable Bundle args) { - DesktopSortApp appInfo = mDesktopSortApps.get(id); + AppInfo appInfo = mAppInfos.get(id); ComponentName componentName = appInfo.getComponentName(); // 从数据项中获取 ComponentName return new IconLoader(mContext, componentName, mIconCacheManager); } @@ -108,7 +143,7 @@ public class MoreAppAdapter extends RecyclerView.Adapter desktopSortApps); + long[] insert(List appInfos); @Update - Integer update(DesktopSortApp desktopSortApp); + Integer update(AppInfo appInfo); @Delete - Integer delete(DesktopSortApp desktopSortApp); + Integer delete(AppInfo appInfo); @Query("DELETE FROM app_list WHERE id = :id") Integer deleteById(Integer id); @@ -47,11 +47,17 @@ public interface AppDao { Integer deleteAll(); @Query("SELECT * FROM app_list ORDER BY position ASC") - List getAllApp(); + List getAllApp(); + + @Query("SELECT * FROM app_list WHERE outside = 1 ORDER BY position ASC") + List getOutsideApp(); + + @Query("SELECT * FROM app_list WHERE outside = 0 ORDER BY position ASC") + List getInsideApp(); @Query("SELECT * FROM app_list WHERE id = :id") - DesktopSortApp getAppById(Integer id); + AppInfo getAppById(Integer id); @Query("SELECT * FROM app_list WHERE label LIKE :searchQuery OR package_name LIKE :searchQuery") - List searchApp(String searchQuery); + List searchApp(String searchQuery); } diff --git a/app/src/main/java/com/ttstd/dialer/db/app/AppDatabase.java b/app/src/main/java/com/ttstd/dialer/db/app/AppDatabase.java index 19e1251..c5ebdc4 100644 --- a/app/src/main/java/com/ttstd/dialer/db/app/AppDatabase.java +++ b/app/src/main/java/com/ttstd/dialer/db/app/AppDatabase.java @@ -8,7 +8,7 @@ import androidx.room.RoomDatabase; import java.io.File; -@Database(entities = {DesktopSortApp.class}, version = 2, exportSchema = false) +@Database(entities = {AppInfo.class}, version = 1, exportSchema = false) public abstract class AppDatabase extends RoomDatabase { public abstract AppDao appDao(); diff --git a/app/src/main/java/com/ttstd/dialer/db/app/DesktopSortApp.java b/app/src/main/java/com/ttstd/dialer/db/app/AppInfo.java similarity index 50% rename from app/src/main/java/com/ttstd/dialer/db/app/DesktopSortApp.java rename to app/src/main/java/com/ttstd/dialer/db/app/AppInfo.java index 0dd1967..23fb455 100644 --- a/app/src/main/java/com/ttstd/dialer/db/app/DesktopSortApp.java +++ b/app/src/main/java/com/ttstd/dialer/db/app/AppInfo.java @@ -2,7 +2,10 @@ package com.ttstd.dialer.db.app; import android.content.ComponentName; import android.content.Context; +import android.os.Parcel; +import android.os.Parcelable; +import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.room.ColumnInfo; import androidx.room.Entity; @@ -10,6 +13,8 @@ import androidx.room.Index; import androidx.room.PrimaryKey; import androidx.room.TypeConverters; +import com.google.gson.Gson; +import com.google.gson.JsonParser; import com.ttstd.dialer.utils.ApkUtils; import java.io.Serializable; @@ -17,7 +22,7 @@ import java.util.Objects; @Entity(tableName = "app_list", indices = {@Index(value = "component_name", unique = true)}) @TypeConverters({ComponentNameConverter.class}) -public class DesktopSortApp implements Serializable { +public class AppInfo implements Serializable , Parcelable { private static final long serialVersionUID = 9113517079637096245L; @PrimaryKey(autoGenerate = true) @@ -32,26 +37,53 @@ public class DesktopSortApp implements Serializable { private String mClassName; @ColumnInfo(name = "position") private int mPosition; + @ColumnInfo(name = "outside") + private int outside; + + public AppInfo() { - public DesktopSortApp() { } - public DesktopSortApp(Context context, ComponentName componentName) { + public AppInfo(Context context, ComponentName componentName) { this.componentName = componentName; - mPackageName = componentName.getPackageName(); - mClassName = componentName.getClassName(); - mPosition = 0; - mLabel = ApkUtils.getAppName(context, componentName); + this.mLabel = ApkUtils.getAppName(context, componentName); + this.mPackageName = componentName.getPackageName(); + this.mClassName = componentName.getClassName(); + this.mPosition = 0; + this.outside = 0; } - public DesktopSortApp(Context context, ComponentName componentName, int pos) { + public AppInfo(Context context, ComponentName componentName, int pos) { this.componentName = componentName; - mPackageName = componentName.getPackageName(); - mClassName = componentName.getClassName(); - mPosition = pos; - mLabel = ApkUtils.getAppName(context, componentName); + this.mLabel = ApkUtils.getAppName(context, componentName); + this.mPackageName = componentName.getPackageName(); + this.mClassName = componentName.getClassName(); + this.mPosition = pos; + this.outside = 0; } + protected AppInfo(Parcel in) { + id = in.readInt(); + componentName = in.readParcelable(ComponentName.class.getClassLoader()); + mLabel = in.readString(); + mPackageName = in.readString(); + mClassName = in.readString(); + mPosition = in.readInt(); + outside = in.readInt(); + } + + public static final Creator CREATOR = new Creator() { + @Override + public AppInfo createFromParcel(Parcel in) { + return new AppInfo(in); + } + + @Override + public AppInfo[] newArray(int size) { + return new AppInfo[size]; + } + }; + public int getId() { return id; } @@ -100,10 +132,18 @@ public class DesktopSortApp implements Serializable { this.mPosition = position; } + public int getOutside() { + return outside; + } + + public void setOutside(int outside) { + this.outside = outside; + } + @Override public boolean equals(@Nullable @org.jetbrains.annotations.Nullable Object obj) { - if (obj instanceof DesktopSortApp) { - return Objects.equals(componentName, ((DesktopSortApp) obj).componentName); + if (obj instanceof AppInfo) { + return Objects.equals(componentName, ((AppInfo) obj).componentName); } else if (obj instanceof ComponentName) { return Objects.equals(componentName, obj); } else { @@ -115,4 +155,27 @@ public class DesktopSortApp implements Serializable { public int hashCode() { return componentName.hashCode(); } + + + @NonNull + @Override + public String toString() { + return JsonParser.parseString(new Gson().toJson(this)).getAsJsonObject().toString(); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(id); + dest.writeParcelable(componentName, flags); + dest.writeString(mLabel); + dest.writeString(mPackageName); + dest.writeString(mClassName); + dest.writeInt(mPosition); + dest.writeInt(outside); + } } 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 index 517ab89..71d52cf 100644 --- a/app/src/main/java/com/ttstd/dialer/db/app/AppRepository.java +++ b/app/src/main/java/com/ttstd/dialer/db/app/AppRepository.java @@ -20,7 +20,7 @@ public class AppRepository { return mAppDao.getCountById(); } - public DesktopSortApp getAppInfo(String packageName, String className) { + public AppInfo getAppInfo(String packageName, String className) { return mAppDao.getAppInfo(packageName, className); } @@ -33,37 +33,47 @@ public class AppRepository { } // 获取所有APP - public List getAllApp() { + public List getAllApp() { return mAppDao.getAllApp(); } + // 获取在外面显示的APP + public List getOutsideApp() { + return mAppDao.getOutsideApp(); + } + + // 获取在里面显示的APP + public List getInsideApp() { + return mAppDao.getInsideApp(); + } + // 根据ID获取APP - public DesktopSortApp getAppById(int id) { + public AppInfo getAppById(int id) { return mAppDao.getAppById(id); } // 搜索APP - public List searchApp(String query) { + public List searchApp(String query) { return mAppDao.searchApp("%" + query + "%"); } // 添加APP - public long insert(DesktopSortApp desktopSortApp) { - return mAppDao.insert(desktopSortApp); + public long insert(AppInfo appInfo) { + return mAppDao.insert(appInfo); } - public long[] insert(List desktopSortApps) { - return mAppDao.insert(desktopSortApps); + public long[] insert(List appInfos) { + return mAppDao.insert(appInfos); } // 更新APP - public int update(DesktopSortApp desktopSortApp) { - return mAppDao.update(desktopSortApp); + public int update(AppInfo appInfo) { + return mAppDao.update(appInfo); } // 删除APP - public int delete(DesktopSortApp desktopSortApp) { - return mAppDao.delete(desktopSortApp); + public int delete(AppInfo appInfo) { + return mAppDao.delete(appInfo); } // 根据ID删除APP diff --git a/app/src/main/java/com/ttstd/dialer/db/contact/ContactDao.java b/app/src/main/java/com/ttstd/dialer/db/contact/ContactDao.java index c678080..07ffcb6 100644 --- a/app/src/main/java/com/ttstd/dialer/db/contact/ContactDao.java +++ b/app/src/main/java/com/ttstd/dialer/db/contact/ContactDao.java @@ -19,13 +19,13 @@ public interface ContactDao { int getCountById(); @Insert - long insert(Contact contact); + long insert(ContactInfo contactInfo); @Update - int update(Contact contact); + int update(ContactInfo contactInfo); @Delete - int delete(Contact contact); + int delete(ContactInfo contactInfo); @Query("DELETE FROM contacts WHERE id = :id") int deleteById(int id); @@ -34,12 +34,12 @@ public interface ContactDao { int deleteAll(); @Query("SELECT * FROM contacts ORDER BY position ASC") - List getAllContacts(); + List getAllContacts(); @Query("SELECT * FROM contacts WHERE id = :id") - Contact getContactById(int id); + ContactInfo getContactById(int id); @Query("SELECT * FROM contacts WHERE name LIKE :searchQuery OR phoneNumber LIKE :searchQuery") - List searchContacts(String searchQuery); + List searchContacts(String searchQuery); } 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 index 1eb148d..3240407 100644 --- a/app/src/main/java/com/ttstd/dialer/db/contact/ContactDatabase.java +++ b/app/src/main/java/com/ttstd/dialer/db/contact/ContactDatabase.java @@ -8,7 +8,7 @@ import androidx.room.RoomDatabase; import java.io.File; -@Database(entities = {Contact.class}, version = 1, exportSchema = false) +@Database(entities = {ContactInfo.class}, version = 1, exportSchema = false) public abstract class ContactDatabase extends RoomDatabase { public abstract ContactDao contactDao(); diff --git a/app/src/main/java/com/ttstd/dialer/db/contact/Contact.java b/app/src/main/java/com/ttstd/dialer/db/contact/ContactInfo.java similarity index 85% rename from app/src/main/java/com/ttstd/dialer/db/contact/Contact.java rename to app/src/main/java/com/ttstd/dialer/db/contact/ContactInfo.java index e00db90..8771e56 100644 --- a/app/src/main/java/com/ttstd/dialer/db/contact/Contact.java +++ b/app/src/main/java/com/ttstd/dialer/db/contact/ContactInfo.java @@ -12,7 +12,7 @@ import java.io.Serializable; import java.util.Objects; @Entity(tableName = "contacts") -public class Contact implements Serializable { +public class ContactInfo implements Serializable { @PrimaryKey(autoGenerate = true) private int id; @@ -22,7 +22,7 @@ public class Contact implements Serializable { private String wxid; private int position; - public Contact(String name, String phoneNumber, int position) { + public ContactInfo(String name, String phoneNumber, int position) { this.name = name; this.phoneNumber = phoneNumber; this.position = position; @@ -78,9 +78,9 @@ public class Contact implements Serializable { @Override public boolean equals(@Nullable Object obj) { - if (obj instanceof Contact) { - return Objects.equals(((Contact) obj).phoneNumber, phoneNumber) - || ((Contact) obj).id == id; + if (obj instanceof ContactInfo) { + return Objects.equals(((ContactInfo) obj).phoneNumber, phoneNumber) + || ((ContactInfo) obj).id == id; } return false; } 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 97e8ff3..69ded99 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 @@ -22,33 +22,33 @@ public class ContactRepository { } // 获取所有联系人 - public List getAllContacts() { + public List getAllContacts() { return mContactDao.getAllContacts(); } // 根据ID获取联系人 - public Contact getContactById(int id) { + public ContactInfo getContactById(int id) { return mContactDao.getContactById(id); } // 搜索联系人 - public List searchContacts(String query) { + public List searchContacts(String query) { return mContactDao.searchContacts("%" + query + "%"); } // 添加联系人 - public long insert(Contact contact) { - return mContactDao.insert(contact); + public long insert(ContactInfo contactInfo) { + return mContactDao.insert(contactInfo); } // 更新联系人 - public int update(Contact contact) { - return mContactDao.update(contact); + public int update(ContactInfo contactInfo) { + return mContactDao.update(contactInfo); } // 删除联系人 - public int delete(Contact contact) { - return mContactDao.delete(contact); + public int delete(ContactInfo contactInfo) { + return mContactDao.delete(contactInfo); } // 根据ID删除联系人 diff --git a/app/src/main/java/com/ttstd/dialer/db/contact/ContactViewModel.java b/app/src/main/java/com/ttstd/dialer/db/contact/ContactViewModel.java index 62f0def..12af605 100644 --- a/app/src/main/java/com/ttstd/dialer/db/contact/ContactViewModel.java +++ b/app/src/main/java/com/ttstd/dialer/db/contact/ContactViewModel.java @@ -14,28 +14,28 @@ public class ContactViewModel extends AndroidViewModel { mRepository = new ContactRepository(application); } - public List getAllContacts() { + public List getAllContacts() { return mRepository.getAllContacts(); } - public Contact getContactById(int id) { + public ContactInfo getContactById(int id) { return mRepository.getContactById(id); } - public List searchContacts(String query) { + public List searchContacts(String query) { return mRepository.searchContacts(query); } - public void insert(Contact contact) { - mRepository.insert(contact); + public void insert(ContactInfo contactInfo) { + mRepository.insert(contactInfo); } - public void update(Contact contact) { - mRepository.update(contact); + public void update(ContactInfo contactInfo) { + mRepository.update(contactInfo); } - public void delete(Contact contact) { - mRepository.delete(contact); + public void delete(ContactInfo contactInfo) { + mRepository.delete(contactInfo); } public void deleteById(int id) { diff --git a/app/src/main/java/com/ttstd/dialer/fragment/app/AppFragment.java b/app/src/main/java/com/ttstd/dialer/fragment/app/AppFragment.java index 9e4e846..17676f9 100644 --- a/app/src/main/java/com/ttstd/dialer/fragment/app/AppFragment.java +++ b/app/src/main/java/com/ttstd/dialer/fragment/app/AppFragment.java @@ -2,14 +2,56 @@ package com.ttstd.dialer.fragment.app; import android.app.Activity; import android.os.Bundle; +import android.util.Log; + +import androidx.lifecycle.Observer; +import androidx.loader.app.LoaderManager; +import androidx.recyclerview.widget.GridLayoutManager; import com.ttstd.dialer.R; +import com.ttstd.dialer.adapter.AppAdapter; import com.ttstd.dialer.base.mvvm.fragment.BaseMvvmFragment; import com.ttstd.dialer.databinding.FragmentAppBinding; +import com.ttstd.dialer.db.app.AppInfo; +import com.ttstd.dialer.view.EqualHeightDecoration; + +import java.io.Serializable; +import java.util.List; public class AppFragment extends BaseMvvmFragment { + private static final String TAG = "AppFragment"; + + private static final String ARG_APP_LIST = "app_list"; + private Activity mContext; + private AppAdapter mAppAdapter; + private List mAppInfos; + +// public static AppFragment newInstance(List apkList) { +// AppFragment appFragment = new AppFragment(); +// Log.e(TAG, "newInstance: " + appFragment); +// Bundle args = new Bundle(); +// args.putSerializable(ARG_APP_LIST, (Serializable) apkList); +// appFragment.setArguments(args); +// return appFragment; +// } + + + public AppFragment(List appInfos) { + mAppInfos = appInfos; + } + + public interface UpdateCallback { + void onUpdate(); + } + + private UpdateCallback mUpdateCallback; + + public void setUpdateCallback(UpdateCallback updateCallback) { + mUpdateCallback = updateCallback; + } + @Override protected int getLayoutId() { return R.layout.fragment_app; @@ -26,20 +68,68 @@ public class AppFragment extends BaseMvvmFragment() { + @Override + public void onChanged(Integer integer) { + if (integer > 0) { + } + if (mUpdateCallback != null) { + mUpdateCallback.onUpdate(); + } + } + }); +// if (getArguments() != null) { +// mAppInfos = (List) getArguments().getSerializable(ARG_APP_LIST); +// } + if (mAppInfos != null) { + Log.e(TAG, "initData: mAppInfos size = " + mAppInfos.size()); + mAppAdapter.setAppInfos(mAppInfos); + } } @Override public void fetchData() { + Log.e(TAG, "fetchData: "); } - public class BtnClick{ + @Override + public void onResume() { + super.onResume(); + Log.e(TAG, "onResume: "); + if (mAppInfos != null) { + mAppAdapter.setAppInfos(mAppInfos); + } + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + Log.e(TAG, "onDestroyView: "); + mViewModel.resetLiveData(); + } + + public class BtnClick { } } diff --git a/app/src/main/java/com/ttstd/dialer/fragment/app/AppViewModel.java b/app/src/main/java/com/ttstd/dialer/fragment/app/AppViewModel.java index c481580..7af01ee 100644 --- a/app/src/main/java/com/ttstd/dialer/fragment/app/AppViewModel.java +++ b/app/src/main/java/com/ttstd/dialer/fragment/app/AppViewModel.java @@ -1,10 +1,74 @@ package com.ttstd.dialer.fragment.app; +import android.content.Context; +import android.util.Log; + +import androidx.lifecycle.MutableLiveData; + +import com.trello.rxlifecycle4.RxLifecycle; +import com.trello.rxlifecycle4.android.ActivityEvent; import com.trello.rxlifecycle4.android.FragmentEvent; import com.ttstd.dialer.base.mvvm.BaseViewModel; import com.ttstd.dialer.databinding.FragmentAppBinding; +import com.ttstd.dialer.db.app.AppInfo; +import com.ttstd.dialer.db.app.AppRepository; + +import java.util.concurrent.Callable; + +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.schedulers.Schedulers; public class AppViewModel extends BaseViewModel { + private static final String TAG = "AppViewModel"; + private AppRepository mAppRepository; + @Override + public void setContext(Context context) { + super.setContext(context); + mAppRepository = new AppRepository(context); + } + + public MutableLiveData mAppUpdateData = new MutableLiveData<>(); + + public void resetLiveData() { + mAppUpdateData = new MutableLiveData<>(); + } + + public void updateAppInfo(AppInfo appInfo) { + Observable.fromCallable(new Callable() { + @Override + public Integer call() throws Exception { + return mAppRepository.update(appInfo); + } + }).compose(RxLifecycle.bindUntilEvent(getLifecycle(), FragmentEvent.DESTROY)) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(new Observer() { + @Override + public void onSubscribe(@NonNull Disposable d) { + Log.e("updateAppInfo", "onSubscribe: "); + } + + @Override + public void onNext(@NonNull Integer row) { + Log.e("updateAppInfo", "onNext: " + row); + mAppUpdateData.setValue(row); + } + + @Override + public void onError(@NonNull Throwable e) { + Log.e("updateAppInfo", "onError: " + e.getMessage()); + } + + @Override + public void onComplete() { + Log.e("updateAppInfo", "onComplete: "); + } + }); + } } diff --git a/app/src/main/java/com/ttstd/dialer/fragment/contact/ContactFragment.java b/app/src/main/java/com/ttstd/dialer/fragment/contact/ContactFragment.java index 68b65f6..2fbb7d4 100644 --- a/app/src/main/java/com/ttstd/dialer/fragment/contact/ContactFragment.java +++ b/app/src/main/java/com/ttstd/dialer/fragment/contact/ContactFragment.java @@ -1,14 +1,9 @@ package com.ttstd.dialer.fragment.contact; -import android.Manifest; import android.app.Activity; -import android.content.Intent; -import android.content.pm.PackageManager; -import android.net.Uri; import android.os.Bundle; import android.util.Log; -import androidx.core.app.ActivityCompat; import androidx.lifecycle.Observer; import androidx.recyclerview.widget.GridLayoutManager; @@ -16,9 +11,8 @@ import com.ttstd.dialer.R; import com.ttstd.dialer.adapter.HomeContactAdapter; import com.ttstd.dialer.base.mvvm.fragment.BaseMvvmFragment; import com.ttstd.dialer.databinding.FragmentContactBinding; -import com.ttstd.dialer.db.contact.Contact; +import com.ttstd.dialer.db.contact.ContactInfo; import com.ttstd.dialer.fragment.dialog.call.CallFragment; -import com.ttstd.dialer.fragment.dialog.permission.PermissionDialogFragment; import com.ttstd.dialer.view.EqualHeightDecoration; import java.util.List; @@ -28,7 +22,7 @@ public class ContactFragment extends BaseMvvmFragment mContacts; + private List mContactInfos; private static final int REQUEST_CODE_CALL = 7897; @@ -52,8 +46,8 @@ public class ContactFragment extends BaseMvvmFragment>() { + mViewModel.mContactListData.observe(this, new Observer>() { @Override - public void onChanged(List contacts) { - Log.e(TAG, "mContactListData: " + contacts); - mContacts = contacts; - mHomeContactAdapter.setContacts(mContacts); + public void onChanged(List contactInfos) { + Log.e(TAG, "mContactListData: " + contactInfos); + mContactInfos = contactInfos; + mHomeContactAdapter.setContactInfos(mContactInfos); } }); } diff --git a/app/src/main/java/com/ttstd/dialer/fragment/contact/ContactViewModel.java b/app/src/main/java/com/ttstd/dialer/fragment/contact/ContactViewModel.java index 32c458c..97b6def 100644 --- a/app/src/main/java/com/ttstd/dialer/fragment/contact/ContactViewModel.java +++ b/app/src/main/java/com/ttstd/dialer/fragment/contact/ContactViewModel.java @@ -6,11 +6,10 @@ import android.util.Log; import androidx.lifecycle.MutableLiveData; import com.trello.rxlifecycle4.RxLifecycle; -import com.trello.rxlifecycle4.android.ActivityEvent; import com.trello.rxlifecycle4.android.FragmentEvent; import com.ttstd.dialer.base.mvvm.BaseViewModel; import com.ttstd.dialer.databinding.FragmentContactBinding; -import com.ttstd.dialer.db.contact.Contact; +import com.ttstd.dialer.db.contact.ContactInfo; import com.ttstd.dialer.db.contact.ContactRepository; import java.util.List; @@ -33,29 +32,29 @@ public class ContactViewModel extends BaseViewModel> mContactListData = new MutableLiveData<>(); + public MutableLiveData> mContactListData = new MutableLiveData<>(); public void getAllContacts() { - Observable.create(new ObservableOnSubscribe>() { + Observable.create(new ObservableOnSubscribe>() { @Override - public void subscribe(@NonNull ObservableEmitter> emitter) throws Throwable { - List contacts = mRepository.getAllContacts(); - emitter.onNext(contacts); + public void subscribe(@NonNull ObservableEmitter> emitter) throws Throwable { + List contactInfos = mRepository.getAllContacts(); + emitter.onNext(contactInfos); emitter.onComplete(); } }).compose(RxLifecycle.bindUntilEvent(getLifecycle(), FragmentEvent.DESTROY)) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) - .subscribe(new Observer>() { + .subscribe(new Observer>() { @Override public void onSubscribe(@NonNull Disposable d) { Log.e("getAllContacts", "onSubscribe: "); } @Override - public void onNext(@NonNull List contacts) { + public void onNext(@NonNull List contactInfos) { Log.e("getAllContacts", "onNext: "); - mContactListData.setValue(contacts); + mContactListData.setValue(contactInfos); // List sorted = contacts.stream().sorted(new Comparator() { // @Override diff --git a/app/src/main/java/com/ttstd/dialer/fragment/dialog/call/CallFragment.java b/app/src/main/java/com/ttstd/dialer/fragment/dialog/call/CallFragment.java index d774780..49dc513 100644 --- a/app/src/main/java/com/ttstd/dialer/fragment/dialog/call/CallFragment.java +++ b/app/src/main/java/com/ttstd/dialer/fragment/dialog/call/CallFragment.java @@ -21,10 +21,9 @@ import androidx.fragment.app.FragmentManager; import androidx.fragment.app.FragmentTransaction; import com.ttstd.dialer.R; -import com.ttstd.dialer.activity.contact.list.ContactListActivity; import com.ttstd.dialer.base.mvvm.fragment.BaseMvvmDialogFragment; import com.ttstd.dialer.databinding.FragmentCallBinding; -import com.ttstd.dialer.db.contact.Contact; +import com.ttstd.dialer.db.contact.ContactInfo; public class CallFragment extends BaseMvvmDialogFragment { private static final String TAG = "CallFragment"; @@ -32,10 +31,10 @@ public class CallFragment extends BaseMvvmDialogFragment { + private static final String TAG = "ShortcutDialogFagment"; + + private Activity mContext; + private PackageManager mPackageManager; + + private AppInfo mAppInfo; + private String mTitil; + private String mTips; + private String mNegativeText; + private String mPositiveText; + + public ShortcutDialogFagment(AppInfo appInfo) { + mAppInfo = appInfo; + } + + public void setTitil(String titil) { + mTitil = titil; + } + + public void setTips(String tips) { + mTips = tips; + } + + public void setNegativeText(String negativeText) { + mNegativeText = negativeText; + } + + public void setPositiveText(String positiveText) { + mPositiveText = positiveText; + } + + public interface OnClickListener { + void onPositiveClick(); + + void onNegativeClick(); + } + + private OnClickListener mOnClickListener; + + public void setOnClickListener(OnClickListener onClickListener) { + mOnClickListener = onClickListener; + } + + @Override + protected int getLayoutId() { + return R.layout.fragment_dialog_shortcut; + } + + @Override + protected void initDataBinding() { + mContext = getActivity(); + mPackageManager = mContext.getPackageManager(); + mViewModel.setContext(mContext); + mViewModel.setVDBinding(mViewDataBinding); + mViewModel.setLifecycle(getLifecycleSubject()); + mViewDataBinding.setClick(new BtnClick()); + } + + @Override + protected void initView(Bundle bundle) { + + } + + @Override + protected void initData(Bundle savedInstanceState) { + if (TextUtils.isEmpty(mTitil)) { + mViewDataBinding.tvTitle.setText("提示"); + } else { + mViewDataBinding.tvTitle.setText(mTitil); + } + + if (TextUtils.isEmpty(mTips)) { + mViewDataBinding.tvMessage.setText(""); + mViewDataBinding.tvMessage.setVisibility(View.GONE); + } else { + mViewDataBinding.tvMessage.setText(mTips); + mViewDataBinding.tvMessage.setVisibility(View.VISIBLE); + } + + if (TextUtils.isEmpty(mNegativeText)){ + mViewDataBinding.tvNegative.setText("取消"); + }else { + mViewDataBinding.tvNegative.setText(mNegativeText); + } + + if (TextUtils.isEmpty(mPositiveText)){ + mViewDataBinding.tvPositive.setText("确定"); + }else { + mViewDataBinding.tvPositive.setText(mPositiveText); + } + + if (mAppInfo != null) { + try { + ActivityInfo info = mPackageManager.getActivityInfo(mAppInfo.getComponentName(), 0); + mViewDataBinding.tvAppName.setText(info.loadLabel(mPackageManager)); + Drawable rawIcon = info.loadIcon(mPackageManager); + mViewDataBinding.ivIcon.setImageDrawable(rawIcon); + } catch (PackageManager.NameNotFoundException e) { + e.printStackTrace(); + } + } + } + + @Override + public void onStart() { + super.onStart(); + if (getDialog() != null) { + Window window = getDialog().getWindow(); + if (window == null) return; + WindowManager.LayoutParams params = window.getAttributes(); + params.width = WindowManager.LayoutParams.MATCH_PARENT; + params.height = WindowManager.LayoutParams.WRAP_CONTENT; + params.gravity = Gravity.CENTER; + window.setAttributes(params); + window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT)); + getDialog().setCancelable(true); + getDialog().setCanceledOnTouchOutside(true); + } + } + + @Override + public void show(FragmentManager manager, String tag) { + DialogFragment fragment = (DialogFragment) manager.findFragmentByTag(tag); + if (fragment != null && fragment.isAdded() + && fragment.getDialog() != null && fragment.getDialog().isShowing()) { + return; + } + + try { + FragmentTransaction ft = manager.beginTransaction(); + ft.add(this, tag); + ft.commitAllowingStateLoss(); + } catch (Exception e) { + Log.e(TAG, "show: " + e.getMessage()); + } + } + + @Override + public void fetchData() { + + } + + public class BtnClick { + public void onPositive(View view) { + if (mOnClickListener != null) { + mOnClickListener.onPositiveClick(); + } + } + + public void onNegative(View view) { + if (mOnClickListener != null) { + mOnClickListener.onNegativeClick(); + } + } + + } +} diff --git a/app/src/main/java/com/ttstd/dialer/fragment/dialog/shortcut/ShortcutViewModel.java b/app/src/main/java/com/ttstd/dialer/fragment/dialog/shortcut/ShortcutViewModel.java new file mode 100644 index 0000000..814a496 --- /dev/null +++ b/app/src/main/java/com/ttstd/dialer/fragment/dialog/shortcut/ShortcutViewModel.java @@ -0,0 +1,9 @@ +package com.ttstd.dialer.fragment.dialog.shortcut; + +import com.trello.rxlifecycle4.android.FragmentEvent; +import com.ttstd.dialer.base.mvvm.BaseViewModel; +import com.ttstd.dialer.databinding.FragmentDialogShortcutBinding; + +public class ShortcutViewModel extends BaseViewModel { + +} diff --git a/app/src/main/java/com/ttstd/dialer/manager/AppManager.java b/app/src/main/java/com/ttstd/dialer/manager/AppManager.java index 56accbe..43ed6d3 100644 --- a/app/src/main/java/com/ttstd/dialer/manager/AppManager.java +++ b/app/src/main/java/com/ttstd/dialer/manager/AppManager.java @@ -9,8 +9,8 @@ import android.util.Log; import com.tencent.mmkv.MMKV; import com.ttstd.dialer.config.CommonConfig; +import com.ttstd.dialer.db.app.AppInfo; import com.ttstd.dialer.db.app.AppRepository; -import com.ttstd.dialer.db.app.DesktopSortApp; import com.ttstd.dialer.gson.GsonUtils; import com.ttstd.dialer.utils.ApkUtils; @@ -27,6 +27,7 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.CopyOnWriteArraySet; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import java.util.function.IntConsumer; import java.util.stream.Collectors; import java.util.stream.IntStream; @@ -73,6 +74,8 @@ public class AppManager { this.add("com.android.settings"); this.add("com.android.dialer"); this.add("com.android.camera2"); + this.add("com.android.messaging"); + this.add("com.android.contacts"); this.add("com.tencent.mm"); this.add("com.jiangjia.gif"); this.add("com.ss.android.ugc.aweme"); @@ -142,9 +145,9 @@ public class AppManager { } // 第一步:获取所有桌面应用(空值安全处理) - private List getAllDesktopSortApps() { + private List getAllDesktopSortApps() { try { - List result = mAppRepository.getAllApp(); + List result = mAppRepository.getAllApp(); return result != null ? result : Collections.emptyList(); } catch (Exception e) { Log.e(TAG, "获取桌面应用列表失败", e); @@ -166,16 +169,27 @@ public class AppManager { return; } - List allFirstApps = allLauncherApps.stream() + List allFirstApps = allLauncherApps.stream() .filter(Objects::nonNull) .map(this::resolveInfoToDesktopApp) .filter(Objects::nonNull) - .sorted((o1, o2) -> Boolean.compare(ApkUtils.isSystemApp(mContext, o1.getPackageName()), ApkUtils.isSystemApp(mContext, o2.getPackageName()))) + .sorted((o1, o2) -> Boolean.compare(ApkUtils.isSystemApp(mContext, o2.getPackageName()), ApkUtils.isSystemApp(mContext, o1.getPackageName()))) .sorted(getAppComparator()) .collect(Collectors.toList()); IntStream.range(0, allFirstApps.size()) - .forEach(index -> allFirstApps.get(index).setPosition(index)); + .forEach(new IntConsumer() { + @Override + public void accept(int index) { + AppInfo appInfo = allFirstApps.get(index); + if (DEFAULT_APP_PACKAGES.contains(appInfo.getPackageName())) { + appInfo.setOutside(1); + } else { + appInfo.setOutside(0); + } + appInfo.setPosition(index); + } + }); // 批量插入首次数据 allFirstApps.forEach(app -> { @@ -195,15 +209,15 @@ public class AppManager { } // 处理未安装的应用(删除操作) - private CompletableFuture processUninstalledApps(List desktopSortApps) { + private CompletableFuture processUninstalledApps(List appInfos) { return CompletableFuture.runAsync(() -> { notifyProgress(STEP_REMOVE_UNINSTALLED, 1, TOTAL_STEPS_NORMAL); - if (desktopSortApps.isEmpty()) { + if (appInfos.isEmpty()) { Log.w(TAG, "桌面应用列表为空,跳过删除处理"); return; } - List ids = desktopSortApps.stream() + List ids = appInfos.stream() .filter(Objects::nonNull) .filter(app -> !ApkUtils.isInstalled(mContext, app.getPackageName())) .map(app -> { @@ -240,7 +254,7 @@ public class AppManager { return; } - List newApps = resolveInfos.stream() + List newApps = resolveInfos.stream() .filter(Objects::nonNull) .map(this::resolveInfoToDesktopApp) .filter(Objects::nonNull) @@ -273,20 +287,20 @@ public class AppManager { private CompletableFuture updatePosition() { return CompletableFuture.runAsync(() -> { try { - List desktopSortApps = getAllDesktopSortApps(); - if (desktopSortApps.isEmpty()) { + List appInfos = getAllDesktopSortApps(); + if (appInfos.isEmpty()) { Log.w(TAG, "无应用数据,跳过位置更新"); return; } - List sortedApps = desktopSortApps.stream() + List sortedApps = appInfos.stream() .filter(Objects::nonNull) - .sorted(Comparator.comparingInt(DesktopSortApp::getPosition)) + .sorted(Comparator.comparingInt(AppInfo::getPosition)) .collect(Collectors.toList()); IntStream.range(0, sortedApps.size()) .forEach(index -> { - DesktopSortApp app = sortedApps.get(index); + AppInfo app = sortedApps.get(index); app.setPosition(index); try { mAppRepository.update(app); @@ -303,16 +317,16 @@ public class AppManager { } // 工具方法:ResolveInfo转换为DesktopSortApp - private DesktopSortApp resolveInfoToDesktopApp(ResolveInfo resolveInfo) { + private AppInfo resolveInfoToDesktopApp(ResolveInfo resolveInfo) { ComponentName component = new ComponentName( resolveInfo.activityInfo.packageName, resolveInfo.activityInfo.name ); - return new DesktopSortApp(mContext, component); + return new AppInfo(mContext, component); } // 工具方法:检查应用是否已存在 - private boolean isAppExists(DesktopSortApp app) { + private boolean isAppExists(AppInfo app) { try { return mAppRepository.checkAppInfoExists(app.getPackageName(), app.getClassName()) > 0; } catch (Exception e) { @@ -322,8 +336,8 @@ public class AppManager { } // 工具方法:获取应用排序器(统一排序逻辑) - private Comparator getAppComparator() { - return Comparator.comparing(DesktopSortApp::getLabel, Collator.getInstance(Locale.CHINESE)); + private Comparator getAppComparator() { + return Comparator.comparing(AppInfo::getLabel, Collator.getInstance(Locale.CHINESE)); } public void updateApp(String packageName) { @@ -347,7 +361,7 @@ public class AppManager { // 重构getAllApp方法,复用现有处理逻辑 public void refreshAllApps() { CompletableFuture.runAsync(() -> { - List allApps = getAllDesktopSortApps(); + List allApps = getAllDesktopSortApps(); if (allApps.isEmpty()) { processFirstTimeApps().join(); } else { @@ -362,12 +376,12 @@ public class AppManager { PackageManager pm = mContext.getPackageManager(); List resolveInfos = ApkUtils.getAllLauncherResolveInfo(mContext); - List defaultApps = resolveInfos.stream() + List defaultApps = resolveInfos.stream() .filter(ri -> DEFAULT_APP_PACKAGES.contains(ri.activityInfo.packageName)) .sorted((o1, o2) -> Collator.getInstance(Locale.CHINESE) .compare(o1.activityInfo.loadLabel(pm), o2.activityInfo.loadLabel(pm))) .map(ri -> new ComponentName(ri.activityInfo.packageName, ri.activityInfo.name)) - .map(component -> new DesktopSortApp(mContext, component)) + .map(component -> new AppInfo(mContext, component)) .sorted((a, b) -> Boolean.compare( ApkUtils.isSystemApp(mContext, b.getPackageName()), ApkUtils.isSystemApp(mContext, a.getPackageName()))) diff --git a/app/src/main/java/com/ttstd/dialer/view/ApkPagerAdapter.java b/app/src/main/java/com/ttstd/dialer/view/ApkPagerAdapter.java new file mode 100644 index 0000000..927e2e4 --- /dev/null +++ b/app/src/main/java/com/ttstd/dialer/view/ApkPagerAdapter.java @@ -0,0 +1,36 @@ +package com.ttstd.dialer.view; + +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentManager; +import androidx.fragment.app.FragmentPagerAdapter; + +import java.util.List; + +public class ApkPagerAdapter extends FragmentPagerAdapter { + + private List fragments; + + public ApkPagerAdapter(FragmentManager fm) { + super(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT); + } + + public void setFragments(List fragments) { + this.fragments = fragments; + } + + @Override + public Fragment getItem(int position) { + return fragments.get(position); + } + + @Override + public int getCount() { + return fragments == null ? 0 : fragments.size(); + } + + // 解决数据更新不刷新的问题 + @Override + public int getItemPosition(Object object) { + return POSITION_NONE; + } +} \ No newline at end of file diff --git a/app/src/main/res/drawable/bg_permissions.xml b/app/src/main/res/drawable/default_dialog_background.xml similarity index 100% rename from app/src/main/res/drawable/bg_permissions.xml rename to app/src/main/res/drawable/default_dialog_background.xml diff --git a/app/src/main/res/drawable/default_negative_background.xml b/app/src/main/res/drawable/default_negative_background.xml new file mode 100644 index 0000000..aba0358 --- /dev/null +++ b/app/src/main/res/drawable/default_negative_background.xml @@ -0,0 +1,13 @@ + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/default_positive_background.xml b/app/src/main/res/drawable/default_positive_background.xml new file mode 100644 index 0000000..3f8e31c --- /dev/null +++ b/app/src/main/res/drawable/default_positive_background.xml @@ -0,0 +1,13 @@ + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/dialog_fragment_permissions.xml b/app/src/main/res/layout/dialog_fragment_permissions.xml index fbc426c..0475012 100644 --- a/app/src/main/res/layout/dialog_fragment_permissions.xml +++ b/app/src/main/res/layout/dialog_fragment_permissions.xml @@ -18,7 +18,7 @@ - + diff --git a/app/src/main/res/layout/fragment_dialog_shortcut.xml b/app/src/main/res/layout/fragment_dialog_shortcut.xml new file mode 100644 index 0000000..525827e --- /dev/null +++ b/app/src/main/res/layout/fragment_dialog_shortcut.xml @@ -0,0 +1,163 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_app.xml b/app/src/main/res/layout/item_app.xml index 7f32c74..9220114 100644 --- a/app/src/main/res/layout/item_app.xml +++ b/app/src/main/res/layout/item_app.xml @@ -13,7 +13,7 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent"> - + + + + + + + + + + + + \ No newline at end of file diff --git a/iconloader/src/main/java/com/ttstd/iconloader/IconCacheManager.java b/iconloader/src/main/java/com/ttstd/iconloader/IconCacheManager.java index 45dedf3..a5ad624 100644 --- a/iconloader/src/main/java/com/ttstd/iconloader/IconCacheManager.java +++ b/iconloader/src/main/java/com/ttstd/iconloader/IconCacheManager.java @@ -129,19 +129,31 @@ public class IconCacheManager { } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { if (icon instanceof AdaptiveIconDrawable) { // 分别获取背景和前景Drawable - Drawable[] layers = new Drawable[2]; - layers[0] = ((AdaptiveIconDrawable) icon).getBackground(); - layers[1] = ((AdaptiveIconDrawable) icon).getForeground(); - LayerDrawable layerDrawable = new LayerDrawable(layers); +// Drawable[] layers = new Drawable[2]; +// layers[0] = ((AdaptiveIconDrawable) icon).getBackground(); +// layers[1] = ((AdaptiveIconDrawable) icon).getForeground(); +// LayerDrawable layerDrawable = new LayerDrawable(layers); +// +// int width = icon.getIntrinsicWidth(); +// int height = icon.getIntrinsicHeight(); +// +// Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); +// Canvas canvas = new Canvas(bitmap); +// +// layerDrawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight()); +// layerDrawable.draw(canvas); - int width = icon.getIntrinsicWidth(); - int height = icon.getIntrinsicHeight(); - - Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); + // 创建一个大小与原始Drawable相同的位图 + Bitmap bitmap = Bitmap.createBitmap( + icon.getIntrinsicWidth(), + icon.getIntrinsicHeight(), + Bitmap.Config.ARGB_8888 + ); Canvas canvas = new Canvas(bitmap); + // 关键步骤:设置Drawable的绘制边界 + icon.setBounds(0, 0, canvas.getWidth(), canvas.getHeight()); + icon.draw(canvas); - layerDrawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight()); - layerDrawable.draw(canvas); bitmap.compress(Bitmap.CompressFormat.PNG, 100, editor.newOutputStream(0)); editor.commit(); }