From a4a4bdd6a5218272ccf791bdfede6df7c4ca8cd6 Mon Sep 17 00:00:00 2001 From: Peter Cai Date: Tue, 9 Oct 2018 06:22:58 +0000 Subject: [PATCH 001/385] hotfix: fix versioning I messed it up on the last update... I mistakenly changed it to 1.4 and committed. When I installed the update locally I realized the problem and changed it back locally, but not in this repository.. --- app/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index cf534ab..5ff105e 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -8,7 +8,7 @@ android { minSdkVersion 24 targetSdkVersion 28 versionCode 9 - versionName "1.4" + versionName "1.3" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } buildTypes { From 1afcd1fdb157567fea7303d083726918df624088 Mon Sep 17 00:00:00 2001 From: Peter Cai Date: Sun, 14 Oct 2018 13:13:49 +0800 Subject: [PATCH 002/385] build.gradle: bump to 1.4-alpha --- app/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 5ff105e..cae01e9 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -7,8 +7,8 @@ android { applicationId "net.typeblog.shelter" minSdkVersion 24 targetSdkVersion 28 - versionCode 9 - versionName "1.3" + versionCode 10 + versionName "1.4-alpha" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } buildTypes { From d7c86402d80b0669d8a079f7b8e3395989b79f29 Mon Sep 17 00:00:00 2001 From: Peter Cai Date: Sun, 14 Oct 2018 13:22:07 +0800 Subject: [PATCH 003/385] upgrade build tools to 3.2.1 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 4e8009d..8d3ef8e 100644 --- a/build.gradle +++ b/build.gradle @@ -7,7 +7,7 @@ buildscript { jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:3.2.0' + classpath 'com.android.tools.build:gradle:3.2.1' // NOTE: Do not place your application dependencies here; they belong From 3a95ba5945a7afc197f58a911a09e030c0943c77 Mon Sep 17 00:00:00 2001 From: Peter Cai Date: Sun, 14 Oct 2018 13:22:29 +0800 Subject: [PATCH 004/385] AppListFragment: allow creating "linked unfreezing" shortcuts Allow creating an "unfreeze & launch" shortcut that contains several extra apps to unfreeze before launching the main one. This can be useful for apps that have dependency relationships on other apps and the user wants a quick way to unfreeze them all while still pertaining Shelter's auto-freeze feature. --- .../typeblog/shelter/ui/AppListAdapter.java | 151 +++++++++++++++++- .../typeblog/shelter/ui/AppListFragment.java | 96 +++++++++-- .../typeblog/shelter/ui/DummyActivity.java | 41 ++++- app/src/main/res/anim/scale_appear.xml | 11 ++ app/src/main/res/anim/scale_hide.xml | 11 ++ app/src/main/res/drawable/circle_accent.xml | 12 ++ app/src/main/res/layout/app_list_item.xml | 15 ++ app/src/main/res/values/colors.xml | 1 + app/src/main/res/values/styles.xml | 1 + 9 files changed, 316 insertions(+), 23 deletions(-) create mode 100644 app/src/main/res/anim/scale_appear.xml create mode 100644 app/src/main/res/anim/scale_hide.xml create mode 100644 app/src/main/res/drawable/circle_accent.xml diff --git a/app/src/main/java/net/typeblog/shelter/ui/AppListAdapter.java b/app/src/main/java/net/typeblog/shelter/ui/AppListAdapter.java index 1fe1da8..1cda6ec 100644 --- a/app/src/main/java/net/typeblog/shelter/ui/AppListAdapter.java +++ b/app/src/main/java/net/typeblog/shelter/ui/AppListAdapter.java @@ -8,6 +8,8 @@ import android.os.RemoteException; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.view.animation.Animation; +import android.view.animation.AnimationUtils; import android.widget.ImageView; import android.widget.TextView; @@ -23,6 +25,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.stream.Collectors; public class AppListAdapter extends RecyclerView.Adapter { class ViewHolder extends RecyclerView.ViewHolder { @@ -30,6 +33,8 @@ public class AppListAdapter extends RecyclerView.Adapter onClick()); + if (mAllowMultiSelect) { + view.setOnLongClickListener((v) -> onLongClick()); + } } void onClick() { if (mIndex == -1) return; - // Show available operations via the Fragment - // pass the full info to it, since we can't be sure - // the index won't change - if (mContextMenuHandler != null) { - mContextMenuHandler.showContextMenu(mList.get(mIndex), mView); + if (!mMultiSelectMode) { + // Show available operations via the Fragment + // pass the full info to it, since we can't be sure + // the index won't change + if (mContextMenuHandler != null) { + mContextMenuHandler.showContextMenu(mList.get(mIndex), mView); + } + } else { + // In multi-select mode, single clicks just adds to the selection + // or cancels the selection if already selected + if (!mSelectedIndices.contains(mIndex)) { + select(); + } else { + deselect(); + } } } + boolean onLongClick() { + if (mIndex == -1) return false; + + // If we have an action mode handler, we notify it to enter + // action mode on long click, and register this adapter + // to be in multi-select mode + if (!mMultiSelectMode && mActionModeHandler != null && mActionModeHandler.createActionMode()) { + mMultiSelectMode = true; + select(); + return true; + } else { + return false; + } + } + + // When the user selects the item + // we need to play the animation of the "select order" appearing + // on the right side of the item view + void select() { + mSelectedIndices.add(mIndex); + mSelectOrder.clearAnimation(); + mSelectOrder.startAnimation(AnimationUtils.loadAnimation(mView.getContext(), R.anim.scale_appear)); + showSelectOrder(); + } + + // When the user deselects the item + void deselect() { + mSelectedIndices.remove((Integer) mIndex); + mSelectOrder.clearAnimation(); + mView.setBackgroundResource(android.R.color.transparent); + Animation anim = AnimationUtils.loadAnimation(mView.getContext(), R.anim.scale_hide); + anim.setAnimationListener(new Animation.AnimationListener() { + @Override + public void onAnimationStart(Animation animation) { + + } + + @Override + public void onAnimationEnd(Animation animation) { + if (mIndex != -1) { + hideSelectOrder(mList.get(mIndex)); + } + } + + @Override + public void onAnimationRepeat(Animation animation) { + + } + }); + mSelectOrder.startAnimation(anim); + } + + // When an item should be displayed in selected state + // (not necessarily when the user clicked on it; the view might have been recycled) + void showSelectOrder() { + mView.setBackgroundResource(R.color.selectedAppBackground); + mSelectOrder.setVisibility(View.VISIBLE); + mSelectOrder.setText(String.valueOf(mSelectedIndices.indexOf(mIndex) + 1)); + } + + // When an item should be displayed in deselected state + void hideSelectOrder(ApplicationInfoWrapper info) { + // First, determine the hidden (frozen) state + if (!info.isHidden()) { + mView.setBackground(null); + } else { + mView.setBackgroundResource(R.color.disabledAppBackground); + } + mSelectOrder.setVisibility(View.GONE); + } + void setIndex(final int index) { mIndex = index; if (mIndex >= 0) { + // Clear all animations first + mSelectOrder.clearAnimation(); + ApplicationInfoWrapper info = mList.get(mIndex); mPackage.setText(info.getPackageName()); if (info.isHidden()) { String label = String.format(mLabelDisabled, info.getLabel()); mTitle.setText(label); - mView.setBackgroundResource(R.color.disabledAppBackground); } else { mTitle.setText(info.getLabel()); - mView.setBackground(null); + } + + // Special logic when in multi-select mode and this item is selected + if (mMultiSelectMode && mSelectedIndices.contains(mIndex)) { + showSelectOrder(); + } else { + hideSelectOrder(info); } // Load the application icon from cache @@ -99,14 +197,24 @@ public class AppListAdapter extends RecyclerView.Adapter mList = new ArrayList<>(); private IShelterService mService; private Drawable mDefaultIcon; private String mLabelDisabled; private Map mIconCache = new HashMap<>(); private ContextMenuHandler mContextMenuHandler = null; + private ActionModeHandler mActionModeHandler = null; private Handler mHandler = new Handler(Looper.getMainLooper()); + // Multi-selection mode + private boolean mAllowMultiSelect = false; + private boolean mMultiSelectMode = false; + private List mSelectedIndices = new ArrayList<>(); + AppListAdapter(IShelterService service, Drawable defaultIcon) { mService = service; mDefaultIcon = defaultIcon; @@ -116,6 +224,35 @@ public class AppListAdapter extends RecyclerView.Adapter getSelectedItems() { + if (!mMultiSelectMode) return null; + if (mSelectedIndices.size() == 0) return null; + + return mSelectedIndices.stream() + .map((idx) -> mList.get(idx)) + .collect(Collectors.toList()); + } + void setData(List apps) { mList.clear(); mIconCache.clear(); diff --git a/app/src/main/java/net/typeblog/shelter/ui/AppListFragment.java b/app/src/main/java/net/typeblog/shelter/ui/AppListFragment.java index 48070b5..3108047 100644 --- a/app/src/main/java/net/typeblog/shelter/ui/AppListFragment.java +++ b/app/src/main/java/net/typeblog/shelter/ui/AppListFragment.java @@ -23,6 +23,8 @@ import android.widget.Toast; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.app.AlertDialog; +import androidx.appcompat.app.AppCompatActivity; +import androidx.appcompat.view.ActionMode; import androidx.fragment.app.Fragment; import androidx.localbroadcastmanager.content.LocalBroadcastManager; import androidx.recyclerview.widget.LinearLayoutManager; @@ -40,6 +42,7 @@ import net.typeblog.shelter.util.LocalStorageManager; import net.typeblog.shelter.util.Utility; import java.util.List; +import java.util.stream.Collectors; public class AppListFragment extends Fragment { private static final String BROADCAST_REFRESH = "net.typeblog.shelter.broadcast.REFRESH"; @@ -133,6 +136,12 @@ public class AppListFragment extends Fragment { mSelectedApp = info; mList.showContextMenuForChild(v); }); + if (mIsRemote) { + // Allow multi-select actions if this is in the work profile + // to allow things like multi-app unfreeze shortcuts + mAdapter.allowMultiSelect(); + mAdapter.setActionModeHandler(this::createMultiSelectActionMode); + } mList.setAdapter(mAdapter); mList.setLayoutManager(new LinearLayoutManager(getActivity())); mList.setHasFixedSize(true); @@ -146,6 +155,7 @@ public class AppListFragment extends Fragment { void refresh() { if (mAdapter == null) return; if (mRefreshing) return; + if (mAdapter.isMultiSelectMode()) return; // Disallow refreshing when we are multi-selecting mRefreshing = true; mSwipeRefresh.setRefreshing(true); @@ -170,6 +180,50 @@ public class AppListFragment extends Fragment { } } + // Enter multi-select mode for work profile + boolean createMultiSelectActionMode() { + ((AppCompatActivity) getActivity()).startSupportActionMode(new ActionMode.Callback() { + @Override + public boolean onCreateActionMode(ActionMode mode, Menu menu) { + menu.add(Menu.NONE, MENU_ITEM_CREATE_UNFREEZE_SHORTCUT, Menu.NONE, R.string.create_unfreeze_shortcut) + .setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER); + return true; + } + + @Override + public boolean onPrepareActionMode(ActionMode mode, Menu menu) { + return true; + } + + @Override + public boolean onActionItemClicked(ActionMode mode, MenuItem item) { + List list = mAdapter.getSelectedItems(); + if (list == null) { + // We can't perform any action on nothing + return false; + } + + switch (item.getItemId()) { + case MENU_ITEM_CREATE_UNFREEZE_SHORTCUT: + // When multiple apps are selected for creating unfreeze & launch shortcut + // the shortcut will launch the first one, before which all the others + // will be unfrozen. This helps apps that has dependency relationships. + loadIconAndAddUnfreezeShortcut(list.get(0), list); + mode.finish(); + return true; + } + + return false; + } + + @Override + public void onDestroyActionMode(ActionMode mode) { + mAdapter.cancelMultiSelectMode(); + } + }); + return true; + } + @Override public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) { super.onCreateContextMenu(menu, v, menuInfo); @@ -267,18 +321,7 @@ public class AppListFragment extends Fragment { startActivity(intent); return true; case MENU_ITEM_CREATE_UNFREEZE_SHORTCUT: - final ApplicationInfoWrapper app = mSelectedApp; - try { - // Call the service to load the latest icon - mService.loadIcon(app, new ILoadIconCallback.Stub() { - @Override - public void callback(Bitmap icon) { - getActivity().runOnUiThread(() -> addUnfreezeShortcut(app, icon)); - } - }); - } catch (RemoteException e) { - // Ignore - } + loadIconAndAddUnfreezeShortcut(mSelectedApp, null); return true; case MENU_ITEM_AUTO_FREEZE: boolean orig = LocalStorageManager.getInstance().stringListContains( @@ -333,16 +376,41 @@ public class AppListFragment extends Fragment { } } - void addUnfreezeShortcut(ApplicationInfoWrapper app, Bitmap icon) { + void loadIconAndAddUnfreezeShortcut(final ApplicationInfoWrapper app, final List linkedApps) { + try { + // Call the service to load the latest icon + mService.loadIcon(app, new ILoadIconCallback.Stub() { + @Override + public void callback(Bitmap icon) { + getActivity().runOnUiThread(() -> addUnfreezeShortcut(app, linkedApps, icon)); + } + }); + } catch (RemoteException e) { + // Ignore + } + } + + void addUnfreezeShortcut(ApplicationInfoWrapper app, List linkedApps, Bitmap icon) { + String id = "shelter-" + app.getPackageName(); // First, create an Intent to be sent when clicking on the shortcut Intent launchIntent = new Intent(DummyActivity.PUBLIC_UNFREEZE_AND_LAUNCH); launchIntent.setComponent(new ComponentName(getContext(), DummyActivity.class)); launchIntent.putExtra("packageName", app.getPackageName()); + if (linkedApps != null) { + String appListStr = linkedApps.stream() + .map(ApplicationInfoWrapper::getPackageName).collect(Collectors.joining(",")); + id += appListStr.hashCode(); + // Multiple apps can be added so that + // these "linked" apps are all unfrozen + // before launching the main app + // Note: PersistableBundle doesn't support String array lists inside them + launchIntent.putExtra("linkedPackages", appListStr); + } launchIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); // Then tell the launcher to add the shortcut Utility.createLauncherShortcut(getContext(), launchIntent, - Icon.createWithBitmap(icon), "shelter-" + app.getPackageName(), + Icon.createWithBitmap(icon), id, app.getLabel()); } } diff --git a/app/src/main/java/net/typeblog/shelter/ui/DummyActivity.java b/app/src/main/java/net/typeblog/shelter/ui/DummyActivity.java index fed196b..cd0675c 100644 --- a/app/src/main/java/net/typeblog/shelter/ui/DummyActivity.java +++ b/app/src/main/java/net/typeblog/shelter/ui/DummyActivity.java @@ -319,11 +319,44 @@ public class DummyActivity extends Activity { SettingsManager.getInstance().getAutoFreezeServiceEnabled() && LocalStorageManager.getInstance() .stringListContains(LocalStorageManager.PREF_AUTO_FREEZE_LIST_WORK_PROFILE, packageName)); + if (getIntent().hasExtra("linkedPackages")) { + // Multiple apps should be unfrozen here + String[] packages = getIntent().getStringExtra("linkedPackages").split(","); + boolean[] packagesShouldFreeze = new boolean[packages.length]; + + for (int i = 0; i < packages.length; i++) { + // Apps in linkedPackages may also need to be auto-frozen + // thus, we loop through them and fetch the settings + packagesShouldFreeze[i] = SettingsManager.getInstance().getAutoFreezeServiceEnabled() && + LocalStorageManager.getInstance() + .stringListContains(LocalStorageManager.PREF_AUTO_FREEZE_LIST_WORK_PROFILE, packages[i]); + } + intent.putExtra("linkedPackages", packages); + intent.putExtra("linkedPackagesShouldFreeze", packagesShouldFreeze); + } startActivity(intent); finish(); return; } + // If we have multiple linked apps to unfreeze before launching the main one + if (getIntent().hasExtra("linkedPackages")) { + String[] packages = getIntent().getStringArrayExtra("linkedPackages"); + boolean[] packagesShouldFreeze = getIntent().getBooleanArrayExtra("linkedPackagesShouldFreeze"); + + for (int i = 0; i < packages.length; i++) { + // Unfreeze everything + mPolicyManager.setApplicationHidden( + new ComponentName(this, ShelterDeviceAdminReceiver.class), + packages[i], false); + // Register freeze service + if (packagesShouldFreeze[i]) { + registerAppToFreeze(packages[i]); + } + } + } + + // Here is the main package to launch String packageName = getIntent().getStringExtra("packageName"); // Unfreeze the app first @@ -336,8 +369,7 @@ public class DummyActivity extends Activity { if (launchIntent != null) { if (getIntent().getBooleanExtra("shouldFreeze", false)) { - FreezeService.registerAppToFreeze(packageName); - startService(new Intent(this, FreezeService.class)); + registerAppToFreeze(packageName); } startActivity(launchIntent); } @@ -345,6 +377,11 @@ public class DummyActivity extends Activity { finish(); } + private void registerAppToFreeze(String packageName) { + FreezeService.registerAppToFreeze(packageName); + startService(new Intent(this, FreezeService.class)); + } + private void actionPublicFreezeAll() { // For now we only support freezing apps in work profile // so forward this to DummyActivity in work profile diff --git a/app/src/main/res/anim/scale_appear.xml b/app/src/main/res/anim/scale_appear.xml new file mode 100644 index 0000000..53b8540 --- /dev/null +++ b/app/src/main/res/anim/scale_appear.xml @@ -0,0 +1,11 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/anim/scale_hide.xml b/app/src/main/res/anim/scale_hide.xml new file mode 100644 index 0000000..c9b171a --- /dev/null +++ b/app/src/main/res/anim/scale_hide.xml @@ -0,0 +1,11 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/circle_accent.xml b/app/src/main/res/drawable/circle_accent.xml new file mode 100644 index 0000000..994c482 --- /dev/null +++ b/app/src/main/res/drawable/circle_accent.xml @@ -0,0 +1,12 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/app_list_item.xml b/app/src/main/res/layout/app_list_item.xml index 47e637e..79a20b1 100644 --- a/app/src/main/res/layout/app_list_item.xml +++ b/app/src/main/res/layout/app_list_item.xml @@ -44,4 +44,19 @@ app:layout_constraintTop_toBottomOf="@id/list_app_title" app:layout_constraintEnd_toEndOf="parent" /> + + \ No newline at end of file diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index 00a25dc..4308954 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -6,4 +6,5 @@ #333333 #999999 #E0F2F1 + #EEEEEE diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index fdb8af4..0536905 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -6,6 +6,7 @@ @color/colorPrimary @color/colorPrimaryDark @color/colorAccent + true From a2b893bb926017afcf9ce6f3d3448bcc82a43f6a Mon Sep 17 00:00:00 2001 From: Peter Cai Date: Sun, 14 Oct 2018 13:41:19 +0800 Subject: [PATCH 005/385] AppListFragment: completely block refreshing when in action mode --- .../main/java/net/typeblog/shelter/ui/AppListFragment.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/net/typeblog/shelter/ui/AppListFragment.java b/app/src/main/java/net/typeblog/shelter/ui/AppListFragment.java index 3108047..6ef7383 100644 --- a/app/src/main/java/net/typeblog/shelter/ui/AppListFragment.java +++ b/app/src/main/java/net/typeblog/shelter/ui/AppListFragment.java @@ -155,7 +155,10 @@ public class AppListFragment extends Fragment { void refresh() { if (mAdapter == null) return; if (mRefreshing) return; - if (mAdapter.isMultiSelectMode()) return; // Disallow refreshing when we are multi-selecting + if (mAdapter.isMultiSelectMode()) { + mSwipeRefresh.setRefreshing(false); + return; // Disallow refreshing when we are multi-selecting + } mRefreshing = true; mSwipeRefresh.setRefreshing(true); From b95eed4e46b7c321f9aa3064106b594e4144a563 Mon Sep 17 00:00:00 2001 From: Peter Cai Date: Sun, 14 Oct 2018 13:43:10 +0800 Subject: [PATCH 006/385] AppListAdapter: force redraw on removal of selection MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When a selection is removed, the selection index of other items may also be changed. We have to notify all of them in order to display the order correctly. --- .../main/java/net/typeblog/shelter/ui/AppListAdapter.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/net/typeblog/shelter/ui/AppListAdapter.java b/app/src/main/java/net/typeblog/shelter/ui/AppListAdapter.java index 1cda6ec..afd2640 100644 --- a/app/src/main/java/net/typeblog/shelter/ui/AppListAdapter.java +++ b/app/src/main/java/net/typeblog/shelter/ui/AppListAdapter.java @@ -110,7 +110,11 @@ public class AppListAdapter extends RecyclerView.Adapter Date: Sun, 14 Oct 2018 13:46:57 +0800 Subject: [PATCH 007/385] AppListFragment: add title to action mode --- app/src/main/java/net/typeblog/shelter/ui/AppListFragment.java | 1 + app/src/main/res/values-zh-rCN/strings.xml | 1 + app/src/main/res/values/strings.xml | 1 + 3 files changed, 3 insertions(+) diff --git a/app/src/main/java/net/typeblog/shelter/ui/AppListFragment.java b/app/src/main/java/net/typeblog/shelter/ui/AppListFragment.java index 6ef7383..605f25d 100644 --- a/app/src/main/java/net/typeblog/shelter/ui/AppListFragment.java +++ b/app/src/main/java/net/typeblog/shelter/ui/AppListFragment.java @@ -195,6 +195,7 @@ public class AppListFragment extends Fragment { @Override public boolean onPrepareActionMode(ActionMode mode, Menu menu) { + mode.setTitle(R.string.batch_operation); return true; } diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index 74546cb..015c5c8 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -15,6 +15,7 @@ 主用户 Shelter [已冻结] %s + 批量操作 克隆到 Shelter (工作用户) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index ac21349..f971eaa 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -17,6 +17,7 @@ Main Shelter [Frozen] %s + Batch operation Clone to Shelter (Work Profile) From 517606da52a5c8ebd4a8c0528d9d9ddc55ad9fa8 Mon Sep 17 00:00:00 2001 From: Peter Cai Date: Sun, 14 Oct 2018 13:56:43 +0800 Subject: [PATCH 008/385] AppListAdapter: use blended color for frozen & selected apps --- .../net/typeblog/shelter/ui/AppListAdapter.java | 14 ++++++++++---- app/src/main/res/values/colors.xml | 1 + 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/net/typeblog/shelter/ui/AppListAdapter.java b/app/src/main/java/net/typeblog/shelter/ui/AppListAdapter.java index afd2640..9e2f930 100644 --- a/app/src/main/java/net/typeblog/shelter/ui/AppListAdapter.java +++ b/app/src/main/java/net/typeblog/shelter/ui/AppListAdapter.java @@ -129,15 +129,21 @@ public class AppListAdapter extends RecyclerView.Adapter