增加app在内外显示,支持长按显示隐藏,优化命名,主页app显示还有问题
This commit is contained in:
@@ -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<AppListViewModel, Activity
|
||||
@Override
|
||||
protected void initView() {
|
||||
mMoreAppAdapter = new MoreAppAdapter(LoaderManager.getInstance(this));
|
||||
mMoreAppAdapter.setShortcutCallback(new MoreAppAdapter.ShortcutCallback() {
|
||||
@Override
|
||||
public void setAppOutside(AppInfo appInfo) {
|
||||
appInfo.setOutside(1);
|
||||
mViewModel.updateAppInfo(appInfo);
|
||||
}
|
||||
});
|
||||
mViewDataBinding.recyclerView.setLayoutManager(new GridLayoutManager(this, 3));
|
||||
mViewDataBinding.recyclerView.setAdapter(mMoreAppAdapter);
|
||||
|
||||
@@ -55,15 +62,24 @@ public class AppListActivity extends BaseMvvmActivity<AppListViewModel, Activity
|
||||
|
||||
@Override
|
||||
protected void initData() {
|
||||
mViewModel.mDesktopSortAppData.observe(this, new Observer<List<DesktopSortApp>>() {
|
||||
mViewModel.mDesktopSortAppData.observe(this, new Observer<List<AppInfo>>() {
|
||||
@Override
|
||||
public void onChanged(List<DesktopSortApp> desktopSortApps) {
|
||||
mMoreAppAdapter.setDesktopSortApps(desktopSortApps);
|
||||
public void onChanged(List<AppInfo> appInfos) {
|
||||
mMoreAppAdapter.setAppInfos(appInfos);
|
||||
}
|
||||
});
|
||||
|
||||
// mViewModel.getLauncherAppList();
|
||||
mViewModel.getDbAppList();
|
||||
|
||||
mViewModel.mAppUpdateData.observe(this, new Observer<Integer>() {
|
||||
@Override
|
||||
public void onChanged(Integer integer) {
|
||||
if (integer > 0) {
|
||||
|
||||
}
|
||||
mViewModel.getDbAppList();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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<ActivityAppListBinding, Acti
|
||||
mAppRepository = new AppRepository(context);
|
||||
}
|
||||
|
||||
public MutableLiveData<List<DesktopSortApp>> mDesktopSortAppData = new MutableLiveData<>();
|
||||
public MutableLiveData<List<AppInfo>> mDesktopSortAppData = new MutableLiveData<>();
|
||||
|
||||
public void getDbAppList() {
|
||||
Observable.fromCallable(new Callable<List<DesktopSortApp>>() {
|
||||
Observable.fromCallable(new Callable<List<AppInfo>>() {
|
||||
@Override
|
||||
public List<DesktopSortApp> call() throws Exception {
|
||||
return mAppRepository.getAllApp();
|
||||
public List<AppInfo> call() throws Exception {
|
||||
return mAppRepository.getInsideApp();
|
||||
}
|
||||
}).compose(RxLifecycle.bindUntilEvent(getLifecycle(), ActivityEvent.DESTROY))
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(new Observer<List<DesktopSortApp>>() {
|
||||
.subscribe(new Observer<List<AppInfo>>() {
|
||||
@Override
|
||||
public void onSubscribe(@NonNull Disposable d) {
|
||||
Log.e("getDbAppList", "onSubscribe: ");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNext(@NonNull List<DesktopSortApp> desktopSortApps) {
|
||||
Log.e("getDbAppList", "onNext: " + desktopSortApps);
|
||||
mDesktopSortAppData.setValue(desktopSortApps);
|
||||
public void onNext(@NonNull List<AppInfo> appInfos) {
|
||||
Log.e("getDbAppList", "onNext: " + appInfos);
|
||||
mDesktopSortAppData.setValue(appInfos);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -74,80 +74,41 @@ public class AppListViewModel extends BaseViewModel<ActivityAppListBinding, Acti
|
||||
Log.e("getDbAppList", "onComplete: ");
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
public void getLauncherAppList() {
|
||||
Observable.fromCallable(new Callable<List<ResolveInfo>>() {
|
||||
public MutableLiveData<Integer> mAppUpdateData = new MutableLiveData<>();
|
||||
|
||||
public void updateAppInfo(AppInfo appInfo){
|
||||
Observable.fromCallable(new Callable<Integer>() {
|
||||
@Override
|
||||
public List<ResolveInfo> 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<ResolveInfo>, List<ComponentName>>() {
|
||||
@Override
|
||||
public List<ComponentName> apply(List<ResolveInfo> resolveInfos) throws Throwable {
|
||||
List<ComponentName> componentNames = resolveInfos.stream().map(new java.util.function.Function<ResolveInfo, ComponentName>() {
|
||||
@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<ComponentName>, List<DesktopSortApp>>() {
|
||||
@Override
|
||||
public List<DesktopSortApp> apply(List<ComponentName> componentNames) throws Throwable {
|
||||
List<DesktopSortApp> desktopSortApps = componentNames.stream().map(new java.util.function.Function<ComponentName, DesktopSortApp>() {
|
||||
@Override
|
||||
public DesktopSortApp apply(ComponentName componentName) {
|
||||
DesktopSortApp desktopSortApp = new DesktopSortApp(getSafeContext(), componentName);
|
||||
return desktopSortApp;
|
||||
}
|
||||
}).sorted(new Comparator<DesktopSortApp>() {
|
||||
@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<List<DesktopSortApp>>() {
|
||||
.subscribe(new Observer<Integer>() {
|
||||
@Override
|
||||
public void onSubscribe(@NonNull Disposable d) {
|
||||
|
||||
Log.e("updateAppInfo", "onSubscribe: ");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNext(@NonNull List<DesktopSortApp> 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: ");
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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<ActivityContactAddBinding
|
||||
@Override
|
||||
public void subscribe(@NonNull ObservableEmitter<Long> 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))
|
||||
|
||||
@@ -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<ContactListViewModel,
|
||||
|
||||
private ContactInfoAdapter mContactInfoAdapter;
|
||||
|
||||
private List<Contact> mContacts;
|
||||
private List<ContactInfo> mContactInfos;
|
||||
|
||||
@Override
|
||||
public boolean setNightMode() {
|
||||
@@ -63,14 +60,14 @@ public class ContactListActivity extends BaseMvvmActivity<ContactListViewModel,
|
||||
@Override
|
||||
public void onItemMove(int fromPosition, int toPosition) {
|
||||
Log.e(TAG, "onItemMove: ");
|
||||
Contact fromContact = mContacts.get(fromPosition);
|
||||
int fromContactPosition = fromContact.getPosition();
|
||||
Contact toContact = mContacts.get(toPosition);
|
||||
int toContactPosition = toContact.getPosition();
|
||||
fromContact.setPosition(toContactPosition);
|
||||
mViewModel.updateItemPosition(fromContact);
|
||||
toContact.setPosition(fromContactPosition);
|
||||
mViewModel.updateItemPosition(toContact);
|
||||
ContactInfo fromContactInfo = mContactInfos.get(fromPosition);
|
||||
int fromContactPosition = fromContactInfo.getPosition();
|
||||
ContactInfo toContactInfo = mContactInfos.get(toPosition);
|
||||
int toContactPosition = toContactInfo.getPosition();
|
||||
fromContactInfo.setPosition(toContactPosition);
|
||||
mViewModel.updateItemPosition(fromContactInfo);
|
||||
toContactInfo.setPosition(fromContactPosition);
|
||||
mViewModel.updateItemPosition(toContactInfo);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -81,8 +78,8 @@ public class ContactListActivity extends BaseMvvmActivity<ContactListViewModel,
|
||||
});
|
||||
mContactInfoAdapter.setOnClickListener(new ContactInfoAdapter.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(Contact contact) {
|
||||
new CallFragment(contact).show(getSupportFragmentManager(), "CallFragment");
|
||||
public void onClick(ContactInfo contactInfo) {
|
||||
new CallFragment(contactInfo).show(getSupportFragmentManager(), "CallFragment");
|
||||
}
|
||||
});
|
||||
// 设置ItemTouchHelper,实现拖动和滑动删除
|
||||
@@ -98,12 +95,12 @@ public class ContactListActivity extends BaseMvvmActivity<ContactListViewModel,
|
||||
|
||||
@Override
|
||||
protected void initData() {
|
||||
mViewModel.mContactListData.observe(this, new Observer<List<Contact>>() {
|
||||
mViewModel.mContactListData.observe(this, new Observer<List<ContactInfo>>() {
|
||||
@Override
|
||||
public void onChanged(List<Contact> contacts) {
|
||||
Log.e(TAG, "mContactListData: " + contacts);
|
||||
mContacts = contacts;
|
||||
mContactInfoAdapter.setContacts(mContacts);
|
||||
public void onChanged(List<ContactInfo> contactInfos) {
|
||||
Log.e(TAG, "mContactListData: " + contactInfos);
|
||||
mContactInfos = contactInfos;
|
||||
mContactInfoAdapter.setContactInfos(mContactInfos);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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<ActivityContactListBindi
|
||||
mRepository = new ContactRepository(context);
|
||||
}
|
||||
|
||||
public MutableLiveData<List<Contact>> mContactListData = new MutableLiveData<>();
|
||||
public MutableLiveData<List<ContactInfo>> mContactListData = new MutableLiveData<>();
|
||||
|
||||
public void getAllContacts() {
|
||||
Observable.create(new ObservableOnSubscribe<List<Contact>>() {
|
||||
Observable.create(new ObservableOnSubscribe<List<ContactInfo>>() {
|
||||
@Override
|
||||
public void subscribe(@NonNull ObservableEmitter<List<Contact>> emitter) throws Throwable {
|
||||
List<Contact> contacts = mRepository.getAllContacts();
|
||||
emitter.onNext(contacts);
|
||||
public void subscribe(@NonNull ObservableEmitter<List<ContactInfo>> emitter) throws Throwable {
|
||||
List<ContactInfo> contactInfos = mRepository.getAllContacts();
|
||||
emitter.onNext(contactInfos);
|
||||
emitter.onComplete();
|
||||
}
|
||||
}).compose(RxLifecycle.bindUntilEvent(getLifecycle(), ActivityEvent.DESTROY))
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(new Observer<List<Contact>>() {
|
||||
.subscribe(new Observer<List<ContactInfo>>() {
|
||||
@Override
|
||||
public void onSubscribe(@NonNull Disposable d) {
|
||||
Log.e("getAllContacts", "onSubscribe: ");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNext(@NonNull List<Contact> contacts) {
|
||||
public void onNext(@NonNull List<ContactInfo> contactInfos) {
|
||||
Log.e("getAllContacts", "onNext: ");
|
||||
mContactListData.setValue(contacts);
|
||||
mContactListData.setValue(contactInfos);
|
||||
|
||||
// List<Contact> sorted = contacts.stream().sorted(new Comparator<Contact>() {
|
||||
// @Override
|
||||
@@ -78,12 +78,12 @@ public class ContactListViewModel extends BaseViewModel<ActivityContactListBindi
|
||||
});
|
||||
}
|
||||
|
||||
public void updateItemPosition(Contact contact) {
|
||||
Log.e(TAG, "updateItemPosition: " + contact);
|
||||
public void updateItemPosition(ContactInfo contactInfo) {
|
||||
Log.e(TAG, "updateItemPosition: " + contactInfo);
|
||||
Observable.create(new ObservableOnSubscribe<Integer>() {
|
||||
@Override
|
||||
public void subscribe(@NonNull ObservableEmitter<Integer> emitter) throws Throwable {
|
||||
int id = mRepository.update(contact);
|
||||
int id = mRepository.update(contactInfo);
|
||||
emitter.onNext(id);
|
||||
emitter.onComplete();
|
||||
}
|
||||
|
||||
@@ -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<MainViewModel, ActivityMainBi
|
||||
protected MMKV mMMKV = MMKV.mmkvWithID(CommonConfig.MMKV_ID, MMKV.MULTI_PROCESS_MODE);
|
||||
|
||||
private FragmentManager mFragmentManager = getSupportFragmentManager();
|
||||
private BaseFragmentPagerAdapter mBaseFragmentPagerAdapter;
|
||||
// private BaseFragmentPagerAdapter mBaseFragmentPagerAdapter;
|
||||
private ApkPagerAdapter mApkPagerAdapter;
|
||||
|
||||
private List<Fragment> mFragments = new ArrayList<>();
|
||||
private HomeFragment mHomeFragment;
|
||||
@@ -34,8 +40,12 @@ public class MainActivity extends BaseMvvmActivity<MainViewModel, ActivityMainBi
|
||||
private int mCurrentIndex = 0;
|
||||
private int mFragmentSize = 0;
|
||||
|
||||
private int APK_PER_FRAGMENT = 9;
|
||||
|
||||
private ScaleCircleNavigator mScaleCircleNavigator;
|
||||
|
||||
private List<AppInfo> mAppInfos;
|
||||
|
||||
|
||||
@Override
|
||||
public boolean setNightMode() {
|
||||
@@ -62,18 +72,21 @@ public class MainActivity extends BaseMvvmActivity<MainViewModel, ActivityMainBi
|
||||
|
||||
@Override
|
||||
protected void initView() {
|
||||
// mBaseFragmentPagerAdapter = new BaseFragmentPagerAdapter(mFragmentManager, mFragments);
|
||||
mApkPagerAdapter = new ApkPagerAdapter(mFragmentManager);
|
||||
|
||||
mScaleCircleNavigator = new ScaleCircleNavigator(this);
|
||||
|
||||
boolean contactHome = mMMKV.decodeBool(CommonConfig.CONTACT_HOME_PAGE, false);
|
||||
if (!contactHome) {
|
||||
mCurrentIndex += 1;
|
||||
}
|
||||
if (mContactFragment == null) {
|
||||
mContactFragment = new ContactFragment();
|
||||
mFragments.add(mContactFragment);
|
||||
mFragmentSize += 1;
|
||||
}
|
||||
|
||||
boolean contactHome = mMMKV.decodeBool(CommonConfig.CONTACT_HOME_PAGE, false);
|
||||
if (!contactHome) {
|
||||
mCurrentIndex += 1;
|
||||
}
|
||||
if (mHomeFragment == null) {
|
||||
mHomeFragment = new HomeFragment();
|
||||
mFragments.add(mHomeFragment);
|
||||
@@ -91,28 +104,64 @@ public class MainActivity extends BaseMvvmActivity<MainViewModel, ActivityMainBi
|
||||
mViewDataBinding.viewPager.setCurrentItem(index);
|
||||
}
|
||||
});
|
||||
mBaseFragmentPagerAdapter = new BaseFragmentPagerAdapter(mFragmentManager, mFragments);
|
||||
mViewDataBinding.viewPager.setAdapter(mBaseFragmentPagerAdapter);
|
||||
|
||||
mViewDataBinding.viewPager.setAdapter(mApkPagerAdapter);
|
||||
mViewDataBinding.viewPager.setOffscreenPageLimit(10);
|
||||
mViewDataBinding.viewPager.setCurrentItem(mCurrentIndex);
|
||||
|
||||
mViewDataBinding.magicIndicator.setNavigator(mScaleCircleNavigator);
|
||||
ViewPagerHelper.bind(mViewDataBinding.magicIndicator, mViewDataBinding.viewPager);
|
||||
|
||||
Log.e(TAG, "initView: mCurrentIndex = " + mCurrentIndex);
|
||||
Log.e(TAG, "initView: mFragmentSize = " + mFragmentSize);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initData() {
|
||||
|
||||
mViewModel.mDesktopSortAppData.observe(this, new Observer<List<AppInfo>>() {
|
||||
@Override
|
||||
public void onChanged(List<AppInfo> appInfos) {
|
||||
mAppInfos = appInfos;
|
||||
Log.e(TAG, "onChanged: mAppInfos size = " + mAppInfos.size());
|
||||
setAppList();
|
||||
}
|
||||
});
|
||||
mViewModel.getOutsideApp();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
Log.e(TAG, "onResume: ");
|
||||
setAppList();
|
||||
mViewModel.getOutsideApp();
|
||||
}
|
||||
|
||||
private void setAppList() {
|
||||
Log.e(TAG, "setAppList: mFragments size = " + mFragments.size());
|
||||
mFragments = mFragments.subList(0, mFragmentSize);
|
||||
Log.e(TAG, "setAppList: subList mFragments size = " + mFragments.size());
|
||||
int fragmentCount = (int) Math.ceil((double) mAppInfos.size() / APK_PER_FRAGMENT);
|
||||
for (int i = 0; i < fragmentCount; i++) {
|
||||
int start = i * APK_PER_FRAGMENT;
|
||||
int end = Math.min(start + APK_PER_FRAGMENT, mAppInfos.size());
|
||||
List<AppInfo> subList = new ArrayList<>(mAppInfos.subList(start, end));
|
||||
Log.e(TAG, "setAppList: subList size = " + subList.size());
|
||||
// AppFragment fragment = AppFragment.newInstance(subList);
|
||||
AppFragment fragment = new AppFragment(subList);
|
||||
fragment.setUpdateCallback(new AppFragment.UpdateCallback() {
|
||||
@Override
|
||||
public void onUpdate() {
|
||||
mViewModel.getOutsideApp();
|
||||
}
|
||||
});
|
||||
mFragments.add(fragment);
|
||||
Log.e(TAG, "setAppList: add mFragments size = " + mFragments.size());
|
||||
}
|
||||
mScaleCircleNavigator.setCircleCount(mFragments.size());
|
||||
mScaleCircleNavigator.notifyDataSetChanged();
|
||||
|
||||
mApkPagerAdapter.setFragments(mFragments);
|
||||
mApkPagerAdapter.notifyDataSetChanged();
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,12 +1,28 @@
|
||||
package com.ttstd.dialer.activity.main;
|
||||
|
||||
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.ActivityMainBinding;
|
||||
import com.ttstd.dialer.db.app.AppInfo;
|
||||
import com.ttstd.dialer.db.app.AppRepository;
|
||||
|
||||
import java.util.List;
|
||||
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 MainViewModel extends BaseViewModel<ActivityMainBinding, ActivityEvent> {
|
||||
private static final String TAG = "MainViewModel";
|
||||
|
||||
@@ -18,4 +34,38 @@ public class MainViewModel extends BaseViewModel<ActivityMainBinding, ActivityEv
|
||||
mAppRepository = new AppRepository(context);
|
||||
}
|
||||
|
||||
public MutableLiveData<List<AppInfo>> mDesktopSortAppData = new MutableLiveData<>();
|
||||
|
||||
public void getOutsideApp() {
|
||||
Observable.fromCallable(new Callable<List<AppInfo>>() {
|
||||
@Override
|
||||
public List<AppInfo> call() throws Exception {
|
||||
return mAppRepository.getOutsideApp();
|
||||
}
|
||||
}).compose(RxLifecycle.bindUntilEvent(getLifecycle(), ActivityEvent.DESTROY))
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(new Observer<List<AppInfo>>() {
|
||||
@Override
|
||||
public void onSubscribe(@NonNull Disposable d) {
|
||||
Log.e("getOutsideApp", "onSubscribe: ");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNext(@NonNull List<AppInfo> 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: ");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
152
app/src/main/java/com/ttstd/dialer/adapter/AppAdapter.java
Normal file
152
app/src/main/java/com/ttstd/dialer/adapter/AppAdapter.java
Normal file
@@ -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<AppAdapter.AppHolder> implements LoaderManager.LoaderCallbacks<Drawable> {
|
||||
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<AppInfo> mAppInfos;
|
||||
|
||||
public void setAppInfos(List<AppInfo> 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<Drawable> 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<Drawable> loader, Drawable data) {
|
||||
int position = loader.getId();
|
||||
notifyItemChanged(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoaderReset(@NonNull @NotNull Loader<Drawable> 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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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<ContactInfoAdapter.
|
||||
|
||||
private FragmentActivity mContext;
|
||||
|
||||
private List<Contact> mContacts;
|
||||
private List<ContactInfo> mContactInfos;
|
||||
|
||||
public void setContacts(List<Contact> contacts) {
|
||||
mContacts = contacts;
|
||||
public void setContactInfos(List<ContactInfo> contactInfos) {
|
||||
mContactInfos = contactInfos;
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
@@ -48,7 +43,7 @@ public class ContactInfoAdapter extends RecyclerView.Adapter<ContactInfoAdapter.
|
||||
}
|
||||
|
||||
public interface OnClickListener {
|
||||
void onClick(Contact contact);
|
||||
void onClick(ContactInfo contactInfo);
|
||||
}
|
||||
|
||||
private OnClickListener mOnClickListener;
|
||||
@@ -66,17 +61,17 @@ public class ContactInfoAdapter extends RecyclerView.Adapter<ContactInfoAdapter.
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull ContactInfoHolder holder, int position) {
|
||||
Contact contact = mContacts.get(position);
|
||||
String name = contact.getName();
|
||||
ContactInfo contactInfo = mContactInfos.get(position);
|
||||
String name = contactInfo.getName();
|
||||
holder.tv_name.setText(name);
|
||||
String phone = contact.getPhoneNumber();
|
||||
String phone = contactInfo.getPhoneNumber();
|
||||
holder.tv_phone.setText(phone);
|
||||
holder.root.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
Log.e(TAG, "onClick: " + contact);
|
||||
Log.e(TAG, "onClick: " + contactInfo);
|
||||
if (mOnClickListener != null) {
|
||||
mOnClickListener.onClick(contact);
|
||||
mOnClickListener.onClick(contactInfo);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -84,7 +79,7 @@ public class ContactInfoAdapter extends RecyclerView.Adapter<ContactInfoAdapter.
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return mContacts == null ? 0 : mContacts.size();
|
||||
return mContactInfos == null ? 0 : mContactInfos.size();
|
||||
}
|
||||
|
||||
|
||||
@@ -98,11 +93,11 @@ public class ContactInfoAdapter extends RecyclerView.Adapter<ContactInfoAdapter.
|
||||
|
||||
if (fromPosition < toPosition) {
|
||||
for (int i = fromPosition; i < toPosition; i++) {
|
||||
Collections.swap(mContacts, i, i + 1);
|
||||
Collections.swap(mContactInfos, i, i + 1);
|
||||
}
|
||||
} else {
|
||||
for (int i = fromPosition; i > toPosition; i--) {
|
||||
Collections.swap(mContacts, i, i - 1);
|
||||
Collections.swap(mContactInfos, i, i - 1);
|
||||
}
|
||||
}
|
||||
notifyItemMoved(fromPosition, toPosition);
|
||||
|
||||
@@ -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<HomeContactAdapter.
|
||||
|
||||
private FragmentActivity mContext;
|
||||
|
||||
private List<Contact> mContacts;
|
||||
private List<ContactInfo> mContactInfos;
|
||||
|
||||
public void setContacts(List<Contact> contacts) {
|
||||
mContacts = contacts;
|
||||
public void setContactInfos(List<ContactInfo> contactInfos) {
|
||||
mContactInfos = contactInfos;
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ public class HomeContactAdapter extends RecyclerView.Adapter<HomeContactAdapter.
|
||||
}
|
||||
|
||||
public interface OnClickListener {
|
||||
void onClick(Contact contact);
|
||||
void onClick(ContactInfo contactInfo);
|
||||
}
|
||||
|
||||
private OnClickListener mOnClickListener;
|
||||
@@ -61,17 +61,17 @@ public class HomeContactAdapter extends RecyclerView.Adapter<HomeContactAdapter.
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull ContactInfoHolder holder, int position) {
|
||||
Contact contact = mContacts.get(position);
|
||||
String name = contact.getName();
|
||||
ContactInfo contactInfo = mContactInfos.get(position);
|
||||
String name = contactInfo.getName();
|
||||
holder.tv_name.setText(name);
|
||||
String phone = contact.getPhoneNumber();
|
||||
String phone = contactInfo.getPhoneNumber();
|
||||
holder.tv_phone.setText(phone);
|
||||
holder.root.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
Log.e(TAG, "onClick: " + contact);
|
||||
Log.e(TAG, "onClick: " + contactInfo);
|
||||
if (mOnClickListener != null) {
|
||||
mOnClickListener.onClick(contact);
|
||||
mOnClickListener.onClick(contactInfo);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -79,7 +79,7 @@ public class HomeContactAdapter extends RecyclerView.Adapter<HomeContactAdapter.
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return mContacts == null ? 0 : mContacts.size();
|
||||
return mContactInfos == null ? 0 : mContactInfos.size();
|
||||
}
|
||||
|
||||
|
||||
@@ -93,11 +93,11 @@ public class HomeContactAdapter extends RecyclerView.Adapter<HomeContactAdapter.
|
||||
|
||||
if (fromPosition < toPosition) {
|
||||
for (int i = fromPosition; i < toPosition; i++) {
|
||||
Collections.swap(mContacts, i, i + 1);
|
||||
Collections.swap(mContactInfos, i, i + 1);
|
||||
}
|
||||
} else {
|
||||
for (int i = fromPosition; i > toPosition; i--) {
|
||||
Collections.swap(mContacts, i, i - 1);
|
||||
Collections.swap(mContactInfos, i, i - 1);
|
||||
}
|
||||
}
|
||||
notifyItemMoved(fromPosition, toPosition);
|
||||
|
||||
@@ -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<MoreAppAdapter.AppHolde
|
||||
mLoaderManager = loaderManager;
|
||||
}
|
||||
|
||||
public void setSelectApps(List<DesktopSortApp> selectApps) {
|
||||
public void setSelectApps(List<AppInfo> selectApps) {
|
||||
|
||||
}
|
||||
|
||||
private List<DesktopSortApp> mDesktopSortApps;
|
||||
private List<AppInfo> mAppInfos;
|
||||
|
||||
public void setDesktopSortApps(List<DesktopSortApp> desktopSortApps) {
|
||||
mDesktopSortApps = desktopSortApps;
|
||||
public void setAppInfos(List<AppInfo> 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<Drawable> 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<MoreAppAdapter.AppHolde
|
||||
public class AppHolder extends RecyclerView.ViewHolder {
|
||||
|
||||
ConstraintLayout root;
|
||||
ImageView iv_icon;
|
||||
NiceImageView iv_icon;
|
||||
TextView tv_app_name;
|
||||
|
||||
public AppHolder(@NonNull @NotNull View itemView) {
|
||||
|
||||
@@ -19,7 +19,7 @@ public interface AppDao {
|
||||
Integer getCountById();
|
||||
|
||||
@Query("SELECT * FROM app_list WHERE package_name = :packageName AND class_name = :className")
|
||||
DesktopSortApp getAppInfo(String packageName, String className);
|
||||
AppInfo 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);
|
||||
@@ -29,16 +29,16 @@ public interface AppDao {
|
||||
Integer checkAppInfoExists(String pkgName, String clsName);
|
||||
|
||||
@Insert
|
||||
long insert(DesktopSortApp desktopSortApp);
|
||||
long insert(AppInfo appInfo);
|
||||
|
||||
@Insert
|
||||
long[] insert(List<DesktopSortApp> desktopSortApps);
|
||||
long[] insert(List<AppInfo> 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<DesktopSortApp> getAllApp();
|
||||
List<AppInfo> getAllApp();
|
||||
|
||||
@Query("SELECT * FROM app_list WHERE outside = 1 ORDER BY position ASC")
|
||||
List<AppInfo> getOutsideApp();
|
||||
|
||||
@Query("SELECT * FROM app_list WHERE outside = 0 ORDER BY position ASC")
|
||||
List<AppInfo> 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<DesktopSortApp> searchApp(String searchQuery);
|
||||
List<AppInfo> searchApp(String searchQuery);
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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<AppInfo> CREATOR = new Creator<AppInfo>() {
|
||||
@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);
|
||||
}
|
||||
}
|
||||
@@ -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<DesktopSortApp> getAllApp() {
|
||||
public List<AppInfo> getAllApp() {
|
||||
return mAppDao.getAllApp();
|
||||
}
|
||||
|
||||
// 获取在外面显示的APP
|
||||
public List<AppInfo> getOutsideApp() {
|
||||
return mAppDao.getOutsideApp();
|
||||
}
|
||||
|
||||
// 获取在里面显示的APP
|
||||
public List<AppInfo> getInsideApp() {
|
||||
return mAppDao.getInsideApp();
|
||||
}
|
||||
|
||||
// 根据ID获取APP
|
||||
public DesktopSortApp getAppById(int id) {
|
||||
public AppInfo getAppById(int id) {
|
||||
return mAppDao.getAppById(id);
|
||||
}
|
||||
|
||||
// 搜索APP
|
||||
public List<DesktopSortApp> searchApp(String query) {
|
||||
public List<AppInfo> 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<DesktopSortApp> desktopSortApps) {
|
||||
return mAppDao.insert(desktopSortApps);
|
||||
public long[] insert(List<AppInfo> 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
|
||||
|
||||
@@ -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<Contact> getAllContacts();
|
||||
List<ContactInfo> 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<Contact> searchContacts(String searchQuery);
|
||||
List<ContactInfo> searchContacts(String searchQuery);
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -22,33 +22,33 @@ public class ContactRepository {
|
||||
}
|
||||
|
||||
// 获取所有联系人
|
||||
public List<Contact> getAllContacts() {
|
||||
public List<ContactInfo> getAllContacts() {
|
||||
return mContactDao.getAllContacts();
|
||||
}
|
||||
|
||||
// 根据ID获取联系人
|
||||
public Contact getContactById(int id) {
|
||||
public ContactInfo getContactById(int id) {
|
||||
return mContactDao.getContactById(id);
|
||||
}
|
||||
|
||||
// 搜索联系人
|
||||
public List<Contact> searchContacts(String query) {
|
||||
public List<ContactInfo> 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删除联系人
|
||||
|
||||
@@ -14,28 +14,28 @@ public class ContactViewModel extends AndroidViewModel {
|
||||
mRepository = new ContactRepository(application);
|
||||
}
|
||||
|
||||
public List<Contact> getAllContacts() {
|
||||
public List<ContactInfo> getAllContacts() {
|
||||
return mRepository.getAllContacts();
|
||||
}
|
||||
|
||||
public Contact getContactById(int id) {
|
||||
public ContactInfo getContactById(int id) {
|
||||
return mRepository.getContactById(id);
|
||||
}
|
||||
|
||||
public List<Contact> searchContacts(String query) {
|
||||
public List<ContactInfo> 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) {
|
||||
|
||||
@@ -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<AppViewModel, FragmentAppBinding> {
|
||||
private static final String TAG = "AppFragment";
|
||||
|
||||
private static final String ARG_APP_LIST = "app_list";
|
||||
|
||||
private Activity mContext;
|
||||
|
||||
private AppAdapter mAppAdapter;
|
||||
private List<AppInfo> mAppInfos;
|
||||
|
||||
// public static AppFragment newInstance(List<AppInfo> 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<AppInfo> 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<AppViewModel, FragmentAppBindi
|
||||
|
||||
@Override
|
||||
protected void initView(Bundle bundle) {
|
||||
Log.e(TAG, "initView: ");
|
||||
|
||||
mAppAdapter = new AppAdapter(LoaderManager.getInstance(this));
|
||||
mAppAdapter.setShortcutCallback(new AppAdapter.ShortcutCallback() {
|
||||
@Override
|
||||
public void setAppInside(AppInfo appInfo) {
|
||||
appInfo.setOutside(0);
|
||||
mViewModel.updateAppInfo(appInfo);
|
||||
}
|
||||
});
|
||||
mViewDataBinding.recyclerView.setLayoutManager(new GridLayoutManager(mContext, 3));
|
||||
mViewDataBinding.recyclerView.addItemDecoration(new EqualHeightDecoration(3));
|
||||
mViewDataBinding.recyclerView.setAdapter(mAppAdapter);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initData(Bundle savedInstanceState) {
|
||||
Log.e(TAG, "initData: ");
|
||||
Log.e(TAG, "initData: " + mViewModel.mAppUpdateData);
|
||||
mViewModel.mAppUpdateData.observe(this, new Observer<Integer>() {
|
||||
@Override
|
||||
public void onChanged(Integer integer) {
|
||||
if (integer > 0) {
|
||||
|
||||
}
|
||||
if (mUpdateCallback != null) {
|
||||
mUpdateCallback.onUpdate();
|
||||
}
|
||||
}
|
||||
});
|
||||
// if (getArguments() != null) {
|
||||
// mAppInfos = (List<AppInfo>) 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 {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<FragmentAppBinding, FragmentEvent> {
|
||||
private static final String TAG = "AppViewModel";
|
||||
|
||||
private AppRepository mAppRepository;
|
||||
|
||||
@Override
|
||||
public void setContext(Context context) {
|
||||
super.setContext(context);
|
||||
mAppRepository = new AppRepository(context);
|
||||
}
|
||||
|
||||
public MutableLiveData<Integer> mAppUpdateData = new MutableLiveData<>();
|
||||
|
||||
public void resetLiveData() {
|
||||
mAppUpdateData = new MutableLiveData<>();
|
||||
}
|
||||
|
||||
public void updateAppInfo(AppInfo appInfo) {
|
||||
Observable.fromCallable(new Callable<Integer>() {
|
||||
@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<Integer>() {
|
||||
@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: ");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<ContactViewModel, Fragment
|
||||
|
||||
private Activity mContext;
|
||||
private HomeContactAdapter mHomeContactAdapter;
|
||||
private List<Contact> mContacts;
|
||||
private List<ContactInfo> mContactInfos;
|
||||
|
||||
private static final int REQUEST_CODE_CALL = 7897;
|
||||
|
||||
@@ -52,8 +46,8 @@ public class ContactFragment extends BaseMvvmFragment<ContactViewModel, Fragment
|
||||
mHomeContactAdapter = new HomeContactAdapter();
|
||||
mHomeContactAdapter.setOnClickListener(new HomeContactAdapter.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(Contact contact) {
|
||||
new CallFragment(contact).show(getChildFragmentManager(), "CallFragment");
|
||||
public void onClick(ContactInfo contactInfo) {
|
||||
new CallFragment(contactInfo).show(getChildFragmentManager(), "CallFragment");
|
||||
}
|
||||
});
|
||||
GridLayoutManager gridLayoutManager = new GridLayoutManager(mContext, 2);
|
||||
@@ -64,12 +58,12 @@ public class ContactFragment extends BaseMvvmFragment<ContactViewModel, Fragment
|
||||
|
||||
@Override
|
||||
protected void initData(Bundle savedInstanceState) {
|
||||
mViewModel.mContactListData.observe(this, new Observer<List<Contact>>() {
|
||||
mViewModel.mContactListData.observe(this, new Observer<List<ContactInfo>>() {
|
||||
@Override
|
||||
public void onChanged(List<Contact> contacts) {
|
||||
Log.e(TAG, "mContactListData: " + contacts);
|
||||
mContacts = contacts;
|
||||
mHomeContactAdapter.setContacts(mContacts);
|
||||
public void onChanged(List<ContactInfo> contactInfos) {
|
||||
Log.e(TAG, "mContactListData: " + contactInfos);
|
||||
mContactInfos = contactInfos;
|
||||
mHomeContactAdapter.setContactInfos(mContactInfos);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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<FragmentContactBinding, Frag
|
||||
mRepository = new ContactRepository(context);
|
||||
}
|
||||
|
||||
public MutableLiveData<List<Contact>> mContactListData = new MutableLiveData<>();
|
||||
public MutableLiveData<List<ContactInfo>> mContactListData = new MutableLiveData<>();
|
||||
|
||||
public void getAllContacts() {
|
||||
Observable.create(new ObservableOnSubscribe<List<Contact>>() {
|
||||
Observable.create(new ObservableOnSubscribe<List<ContactInfo>>() {
|
||||
@Override
|
||||
public void subscribe(@NonNull ObservableEmitter<List<Contact>> emitter) throws Throwable {
|
||||
List<Contact> contacts = mRepository.getAllContacts();
|
||||
emitter.onNext(contacts);
|
||||
public void subscribe(@NonNull ObservableEmitter<List<ContactInfo>> emitter) throws Throwable {
|
||||
List<ContactInfo> contactInfos = mRepository.getAllContacts();
|
||||
emitter.onNext(contactInfos);
|
||||
emitter.onComplete();
|
||||
}
|
||||
}).compose(RxLifecycle.bindUntilEvent(getLifecycle(), FragmentEvent.DESTROY))
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(new Observer<List<Contact>>() {
|
||||
.subscribe(new Observer<List<ContactInfo>>() {
|
||||
@Override
|
||||
public void onSubscribe(@NonNull Disposable d) {
|
||||
Log.e("getAllContacts", "onSubscribe: ");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNext(@NonNull List<Contact> contacts) {
|
||||
public void onNext(@NonNull List<ContactInfo> contactInfos) {
|
||||
Log.e("getAllContacts", "onNext: ");
|
||||
mContactListData.setValue(contacts);
|
||||
mContactListData.setValue(contactInfos);
|
||||
|
||||
// List<Contact> sorted = contacts.stream().sorted(new Comparator<Contact>() {
|
||||
// @Override
|
||||
|
||||
@@ -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<CallViewModel, FragmentCallBinding> {
|
||||
private static final String TAG = "CallFragment";
|
||||
@@ -32,10 +31,10 @@ public class CallFragment extends BaseMvvmDialogFragment<CallViewModel, Fragment
|
||||
private static final int REQUEST_CODE_CALL = 7897;
|
||||
|
||||
private Activity mContext;
|
||||
private Contact mContact;
|
||||
private ContactInfo mContactInfo;
|
||||
|
||||
public CallFragment(Contact contact) {
|
||||
mContact = contact;
|
||||
public CallFragment(ContactInfo contactInfo) {
|
||||
mContactInfo = contactInfo;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -112,7 +111,7 @@ public class CallFragment extends BaseMvvmDialogFragment<CallViewModel, Fragment
|
||||
|
||||
public void call() {
|
||||
try {
|
||||
String phone = mContact.getPhoneNumber();
|
||||
String phone = mContactInfo.getPhoneNumber();
|
||||
Intent dialIntent = new Intent(Intent.ACTION_CALL);
|
||||
Uri data = Uri.parse("tel:" + phone);
|
||||
dialIntent.setData(data);
|
||||
|
||||
@@ -0,0 +1,183 @@
|
||||
package com.ttstd.dialer.fragment.dialog.shortcut;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.drawable.ColorDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Bundle;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import android.view.Gravity;
|
||||
import android.view.View;
|
||||
import android.view.Window;
|
||||
import android.view.WindowManager;
|
||||
|
||||
import androidx.fragment.app.DialogFragment;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.fragment.app.FragmentTransaction;
|
||||
|
||||
import com.ttstd.dialer.R;
|
||||
import com.ttstd.dialer.base.mvvm.fragment.BaseMvvmDialogFragment;
|
||||
import com.ttstd.dialer.databinding.FragmentDialogShortcutBinding;
|
||||
import com.ttstd.dialer.db.app.AppInfo;
|
||||
|
||||
public class ShortcutDialogFagment extends BaseMvvmDialogFragment<ShortcutViewModel, FragmentDialogShortcutBinding> {
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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 <FragmentDialogShortcutBinding, FragmentEvent>{
|
||||
|
||||
}
|
||||
@@ -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<DesktopSortApp> getAllDesktopSortApps() {
|
||||
private List<AppInfo> getAllDesktopSortApps() {
|
||||
try {
|
||||
List<DesktopSortApp> result = mAppRepository.getAllApp();
|
||||
List<AppInfo> 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<DesktopSortApp> allFirstApps = allLauncherApps.stream()
|
||||
List<AppInfo> 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<Void> processUninstalledApps(List<DesktopSortApp> desktopSortApps) {
|
||||
private CompletableFuture<Void> processUninstalledApps(List<AppInfo> appInfos) {
|
||||
return CompletableFuture.runAsync(() -> {
|
||||
notifyProgress(STEP_REMOVE_UNINSTALLED, 1, TOTAL_STEPS_NORMAL);
|
||||
if (desktopSortApps.isEmpty()) {
|
||||
if (appInfos.isEmpty()) {
|
||||
Log.w(TAG, "桌面应用列表为空,跳过删除处理");
|
||||
return;
|
||||
}
|
||||
|
||||
List<Integer> ids = desktopSortApps.stream()
|
||||
List<Integer> ids = appInfos.stream()
|
||||
.filter(Objects::nonNull)
|
||||
.filter(app -> !ApkUtils.isInstalled(mContext, app.getPackageName()))
|
||||
.map(app -> {
|
||||
@@ -240,7 +254,7 @@ public class AppManager {
|
||||
return;
|
||||
}
|
||||
|
||||
List<DesktopSortApp> newApps = resolveInfos.stream()
|
||||
List<AppInfo> newApps = resolveInfos.stream()
|
||||
.filter(Objects::nonNull)
|
||||
.map(this::resolveInfoToDesktopApp)
|
||||
.filter(Objects::nonNull)
|
||||
@@ -273,20 +287,20 @@ public class AppManager {
|
||||
private CompletableFuture<Void> updatePosition() {
|
||||
return CompletableFuture.runAsync(() -> {
|
||||
try {
|
||||
List<DesktopSortApp> desktopSortApps = getAllDesktopSortApps();
|
||||
if (desktopSortApps.isEmpty()) {
|
||||
List<AppInfo> appInfos = getAllDesktopSortApps();
|
||||
if (appInfos.isEmpty()) {
|
||||
Log.w(TAG, "无应用数据,跳过位置更新");
|
||||
return;
|
||||
}
|
||||
|
||||
List<DesktopSortApp> sortedApps = desktopSortApps.stream()
|
||||
List<AppInfo> 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<DesktopSortApp> getAppComparator() {
|
||||
return Comparator.comparing(DesktopSortApp::getLabel, Collator.getInstance(Locale.CHINESE));
|
||||
private Comparator<AppInfo> 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<DesktopSortApp> allApps = getAllDesktopSortApps();
|
||||
List<AppInfo> allApps = getAllDesktopSortApps();
|
||||
if (allApps.isEmpty()) {
|
||||
processFirstTimeApps().join();
|
||||
} else {
|
||||
@@ -362,12 +376,12 @@ public class AppManager {
|
||||
PackageManager pm = mContext.getPackageManager();
|
||||
List<ResolveInfo> resolveInfos = ApkUtils.getAllLauncherResolveInfo(mContext);
|
||||
|
||||
List<DesktopSortApp> defaultApps = resolveInfos.stream()
|
||||
List<AppInfo> 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())))
|
||||
|
||||
36
app/src/main/java/com/ttstd/dialer/view/ApkPagerAdapter.java
Normal file
36
app/src/main/java/com/ttstd/dialer/view/ApkPagerAdapter.java
Normal file
@@ -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<Fragment> fragments;
|
||||
|
||||
public ApkPagerAdapter(FragmentManager fm) {
|
||||
super(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT);
|
||||
}
|
||||
|
||||
public void setFragments(List<Fragment> 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;
|
||||
}
|
||||
}
|
||||
13
app/src/main/res/drawable/default_negative_background.xml
Normal file
13
app/src/main/res/drawable/default_negative_background.xml
Normal file
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<!-- 内部颜色 -->
|
||||
<solid android:color="@color/lightGray" />
|
||||
<!-- 圆角的幅度 -->
|
||||
<corners android:radius="32dp" />
|
||||
|
||||
<padding
|
||||
android:bottom="4dp"
|
||||
android:left="20dp"
|
||||
android:right="20dp"
|
||||
android:top="4dp" />
|
||||
</shape>
|
||||
13
app/src/main/res/drawable/default_positive_background.xml
Normal file
13
app/src/main/res/drawable/default_positive_background.xml
Normal file
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<!-- 内部颜色 -->
|
||||
<solid android:color="#5591F3" />
|
||||
<!-- 圆角的幅度 -->
|
||||
<corners android:radius="32dp" />
|
||||
|
||||
<padding
|
||||
android:bottom="4dp"
|
||||
android:left="20dp"
|
||||
android:right="20dp"
|
||||
android:top="4dp" />
|
||||
</shape>
|
||||
@@ -18,7 +18,7 @@
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="300dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/bg_permissions"
|
||||
android:background="@drawable/default_dialog_background"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
|
||||
@@ -15,7 +15,10 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/recyclerView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"/>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
|
||||
163
app/src/main/res/layout/fragment_dialog_shortcut.xml
Normal file
163
app/src/main/res/layout/fragment_dialog_shortcut.xml
Normal file
@@ -0,0 +1,163 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<layout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
tools:context=".fragment.dialog.shortcut.ShortcutDialogFagment">
|
||||
|
||||
<data>
|
||||
|
||||
<variable
|
||||
name="click"
|
||||
type="com.ttstd.dialer.fragment.dialog.shortcut.ShortcutDialogFagment.BtnClick" />
|
||||
</data>
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="300dp"
|
||||
android:layout_height="240dp"
|
||||
android:layout_centerInParent="true"
|
||||
android:background="@drawable/default_dialog_background"
|
||||
android:orientation="vertical"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/linearLayout"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:gravity="center"
|
||||
android:orientation="vertical"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:gravity="center_vertical"
|
||||
android:textColor="@color/black"
|
||||
android:textSize="18sp"
|
||||
android:textStyle="bold"
|
||||
android:visibility="visible"
|
||||
tools:text="消息" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_message"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginTop="8dp"
|
||||
android:gravity="center_vertical"
|
||||
android:textColor="@color/black"
|
||||
android:textSize="16sp"
|
||||
android:visibility="visible"
|
||||
tools:text="消息" />
|
||||
</LinearLayout>
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintBottom_toTopOf="@+id/linearLayout2"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/linearLayout">
|
||||
|
||||
<com.shehuan.niv.NiceImageView
|
||||
android:id="@+id/iv_icon"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:adjustViewBounds="true"
|
||||
android:scaleType="centerCrop"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:src="@mipmap/ic_launcher" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/iv_app_icon"
|
||||
android:layout_width="16dp"
|
||||
android:layout_height="16dp"
|
||||
android:layout_marginStart="26dp"
|
||||
android:layout_marginTop="26dp"
|
||||
android:adjustViewBounds="true"
|
||||
android:scaleType="centerCrop"
|
||||
app:layout_constraintStart_toStartOf="@+id/iv_icon"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:src="@mipmap/ic_launcher" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_app_name"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="20dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginEnd="20dp"
|
||||
android:gravity="center"
|
||||
android:lineSpacingExtra="3dp"
|
||||
android:maxLines="1"
|
||||
android:textColor="#676767"
|
||||
android:textSize="14sp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/iv_icon"
|
||||
tools:text="app" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/linearLayout2"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="24dp"
|
||||
android:layout_marginEnd="24dp"
|
||||
android:layout_marginBottom="20dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_negative"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:background="@drawable/default_negative_background"
|
||||
android:gravity="center"
|
||||
android:onClick="@{click::onNegative}"
|
||||
android:singleLine="true"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="14sp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="取消" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_positive"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:background="@drawable/default_positive_background"
|
||||
android:gravity="center"
|
||||
android:onClick="@{click::onPositive}"
|
||||
android:singleLine="true"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="14sp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="确定" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</layout>
|
||||
@@ -13,7 +13,7 @@
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<ImageView
|
||||
<com.shehuan.niv.NiceImageView
|
||||
android:id="@+id/iv_icon"
|
||||
android:layout_width="60dp"
|
||||
android:layout_height="60dp"
|
||||
|
||||
49
app/src/main/res/layout/item_more_app.xml
Normal file
49
app/src/main/res/layout/item_more_app.xml
Normal file
@@ -0,0 +1,49 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="120dp">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/root"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<com.shehuan.niv.NiceImageView
|
||||
android:id="@+id/iv_icon"
|
||||
android:layout_width="60dp"
|
||||
android:layout_height="60dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:adjustViewBounds="true"
|
||||
android:scaleType="centerCrop"
|
||||
android:src="@mipmap/ic_launcher"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_app_name"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:singleLine="true"
|
||||
android:text="appname"
|
||||
android:textColor="@color/black"
|
||||
android:textSize="16sp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/iv_icon" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user