diff options
author | Joey <joey@lineageos.org> | 2019-01-23 17:49:25 +0100 |
---|---|---|
committer | Bruno Martins <bgcngm@gmail.com> | 2019-01-26 23:53:25 +0100 |
commit | 26258e1bf1d578d297f3a1adf95034617caccad3 (patch) | |
tree | 0c8ae1fe505974b276c0d3173a38163c29b12800 | |
parent | 35f4a332c7399938f2766a76c7285c3daef1b195 (diff) | |
download | android_packages_apps_Trebuchet-26258e1bf1d578d297f3a1adf95034617caccad3.tar.gz android_packages_apps_Trebuchet-26258e1bf1d578d297f3a1adf95034617caccad3.tar.bz2 android_packages_apps_Trebuchet-26258e1bf1d578d297f3a1adf95034617caccad3.zip |
Trebuchet: implement hidden apps
Signed-off-by: Joey <joey@lineageos.org>
Signed-off-by: Luca Stefani <luca.stefani.ge1@gmail.com>
Change-Id: I10c35407820373a1d5f84b237ac449398e076dcd
19 files changed, 1014 insertions, 2 deletions
diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 6141d56c9..5eac53a87 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -105,6 +105,12 @@ </intent-filter> </activity> + <activity + android:name=".lineage.hidden.HiddenAppsActivity" + android:label="@string/hidden_apps_manager_name" + android:theme="@android:style/Theme.DeviceDefault.Settings" + android:autoRemoveFromRecents="true" /> + <!-- The settings provider contains Home's data, like the workspace favorites. The permissions should be changed to what is defined above. The authorities should also be changed to diff --git a/proguard.flags b/proguard.flags index 8c9855944..7a5f1bb0b 100644 --- a/proguard.flags +++ b/proguard.flags @@ -144,3 +144,7 @@ -keep class com.android.launcher3.qsb.QsbContainerView$QsbFragment { public <init>(...); } + +-keep class com.android.launcher3.lineage.hidden.** { + *; +} diff --git a/res/drawable/avd_hidden_lock.xml b/res/drawable/avd_hidden_lock.xml new file mode 100644 index 000000000..d208150f9 --- /dev/null +++ b/res/drawable/avd_hidden_lock.xml @@ -0,0 +1,65 @@ +<!-- + Copyright (C) 2019 The LineageOS Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<animated-vector + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:aapt="http://schemas.android.com/aapt"> + <aapt:attr name="android:drawable"> + <vector + android:name="visibilitystrike" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:name="strike_thru_path" + android:pathData="M 2 4.27 L 3.27 3 L 3.27 3 L 2 4.27 Z" + android:fillColor="?android:attr/textColorSecondary" + android:strokeWidth="1"/> + <clip-path + android:name="strike_thru_mask" + android:pathData="M 0 0 L 24 0 L 24 24 L 0 24 L 0 0 Z M 4.54 1.73 L 3.27 3 L 3.27 3 L 4.54 1.73 Z"/> + <path + android:name="eye_path" + android:pathData="M 12 4.5 C 7 4.5 2.73 7.61 1 12 C 2.73 16.39 7 19.5 12 19.5 C 17 19.5 21.27 16.39 23 12 C 21.27 7.61 17 4.5 12 4.5 L 12 4.5 Z M 12 17 C 9.24 17 7 14.76 7 12 C 7 9.24 9.24 7 12 7 C 14.76 7 17 9.24 17 12 C 17 14.76 14.76 17 12 17 L 12 17 Z M 12 9 C 10.34 9 9 10.34 9 12 C 9 13.66 10.34 15 12 15 C 13.66 15 15 13.66 15 12 C 15 10.34 13.66 9 12 9 L 12 9 Z" + android:fillColor="?android:attr/textColorSecondary" + android:strokeWidth="1"/> + </vector> + </aapt:attr> + <target android:name="strike_thru_path"> + <aapt:attr name="android:animation"> + <objectAnimator + android:propertyName="pathData" + android:startOffset="268" + android:duration="1271" + android:valueFrom="M 2 4.27 L 3.27 3 L 3.27 3 L 2 4.27 Z" + android:valueTo="M 19.73 22 L 21 20.73 L 3.27 3 L 2 4.27 Z" + android:valueType="pathType" + android:interpolator="@android:interpolator/fast_out_slow_in"/> + </aapt:attr> + </target> + <target android:name="strike_thru_mask"> + <aapt:attr name="android:animation"> + <objectAnimator + android:propertyName="pathData" + android:startOffset="268" + android:duration="1271" + android:valueFrom="M 0 0 L 24 0 L 24 24 L 0 24 L 0 0 Z M 4.54 1.73 L 3.27 3 L 3.27 3 L 4.54 1.73 Z" + android:valueTo="M 0 0 L 24 0 L 24 24 L 0 24 L 0 0 Z M 4.54 1.73 L 3.27 3 L 21 20.73 L 22.27 19.46 Z" + android:valueType="pathType" + android:interpolator="@android:interpolator/fast_out_slow_in"/> + </aapt:attr> + </target> +</animated-vector> diff --git a/res/drawable/avd_hidden_unlock.xml b/res/drawable/avd_hidden_unlock.xml new file mode 100644 index 000000000..2199709fb --- /dev/null +++ b/res/drawable/avd_hidden_unlock.xml @@ -0,0 +1,63 @@ +<!-- + Copyright (C) 2019 The LineageOS Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<animated-vector + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:aapt="http://schemas.android.com/aapt"> + <aapt:attr name="android:drawable"> + <vector + android:name="visibilitystrike" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:name="strike_thru_path" + android:pathData="M 2 4.27 L 3.27 3 L 3.27 3 L 2 4.27 Z" + android:fillColor="?android:attr/textColorSecondary" + android:strokeWidth="1"/> + <clip-path + android:name="strike_thru_mask" + android:pathData="M 0 0 L 24 0 L 24 24 L 0 24 L 0 0 Z M 4.54 1.73 L 3.27 3 L 3.27 3 L 4.54 1.73 Z"/> + <path + android:name="eye_path" + android:pathData="M 12 4.5 C 7 4.5 2.73 7.61 1 12 C 2.73 16.39 7 19.5 12 19.5 C 17 19.5 21.27 16.39 23 12 C 21.27 7.61 17 4.5 12 4.5 L 12 4.5 Z M 12 17 C 9.24 17 7 14.76 7 12 C 7 9.24 9.24 7 12 7 C 14.76 7 17 9.24 17 12 C 17 14.76 14.76 17 12 17 L 12 17 Z M 12 9 C 10.34 9 9 10.34 9 12 C 9 13.66 10.34 15 12 15 C 13.66 15 15 13.66 15 12 C 15 10.34 13.66 9 12 9 L 12 9 Z" + android:fillColor="?android:attr/textColorSecondary" + android:strokeWidth="1"/> + </vector> + </aapt:attr> + <target android:name="strike_thru_path"> + <aapt:attr name="android:animation"> + <objectAnimator + android:propertyName="pathData" + android:duration="1271" + android:valueFrom="M 19.73 22 L 21 20.73 L 3.27 3 L 2 4.27 Z" + android:valueTo="M 2 4.27 L 3.27 3 L 3.27 3 L 2 4.27 Z" + android:valueType="pathType" + android:interpolator="@android:interpolator/fast_out_slow_in"/> + </aapt:attr> + </target> + <target android:name="strike_thru_mask"> + <aapt:attr name="android:animation"> + <objectAnimator + android:propertyName="pathData" + android:duration="1271" + android:valueFrom="M 0 0 L 24 0 L 24 24 L 0 24 L 0 0 Z M 4.54 1.73 L 3.27 3 L 21 20.73 L 22.27 19.46 Z" + android:valueTo="M 0 0 L 24 0 L 24 24 L 0 24 L 0 0 Z M 4.54 1.73 L 3.27 3 L 3.27 3 L 4.54 1.73 Z" + android:valueType="pathType" + android:interpolator="@android:interpolator/fast_out_slow_in"/> + </aapt:attr> + </target> +</animated-vector> diff --git a/res/drawable/ic_hidden_locked.xml b/res/drawable/ic_hidden_locked.xml new file mode 100644 index 000000000..4cf3a0b67 --- /dev/null +++ b/res/drawable/ic_hidden_locked.xml @@ -0,0 +1,24 @@ +<!-- + Copyright (C) 2019 The LineageOS Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:fillColor="?android:attr/textColorSecondary" + android:pathData="M11.83,9L15,12.16C15,12.11 15,12.05 15,12A3,3 0 0,0 12,9C11.94,9 11.89,9 11.83,9M7.53,9.8L9.08,11.35C9.03,11.56 9,11.77 9,12A3,3 0 0,0 12,15C12.22,15 12.44,14.97 12.65,14.92L14.2,16.47C13.53,16.8 12.79,17 12,17A5,5 0 0,1 7,12C7,11.21 7.2,10.47 7.53,9.8M2,4.27L4.28,6.55L4.73,7C3.08,8.3 1.78,10 1,12C2.73,16.39 7,19.5 12,19.5C13.55,19.5 15.03,19.2 16.38,18.66L16.81,19.08L19.73,22L21,20.73L3.27,3M12,7A5,5 0 0,1 17,12C17,12.64 16.87,13.26 16.64,13.82L19.57,16.75C21.07,15.5 22.27,13.86 23,12C21.27,7.61 17,4.5 12,4.5C10.6,4.5 9.26,4.75 8,5.2L10.17,7.35C10.74,7.13 11.35,7 12,7Z" /> +</vector> diff --git a/res/drawable/ic_hidden_unlocked.xml b/res/drawable/ic_hidden_unlocked.xml new file mode 100644 index 000000000..c98d1813e --- /dev/null +++ b/res/drawable/ic_hidden_unlocked.xml @@ -0,0 +1,26 @@ +<!-- + Copyright (C) 2019 The LineageOS Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:name="visibilitystrike" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M 12 4.5 C 7 4.5 2.73 7.61 1 12 C 2.73 16.39 7 19.5 12 19.5 C 17 19.5 21.27 16.39 23 12 C 21.27 7.61 17 4.5 12 4.5 L 12 4.5 Z M 12 17 C 9.24 17 7 14.76 7 12 C 7 9.24 9.24 7 12 7 C 14.76 7 17 9.24 17 12 C 17 14.76 14.76 17 12 17 L 12 17 Z M 12 9 C 10.34 9 9 10.34 9 12 C 9 13.66 10.34 15 12 15 C 13.66 15 15 13.66 15 12 C 15 10.34 13.66 9 12 9 L 12 9 Z" + android:fillColor="?android:attr/textColorSecondary" + android:strokeWidth="1"/> +</vector> diff --git a/res/layout/activity_hidden_apps.xml b/res/layout/activity_hidden_apps.xml new file mode 100644 index 000000000..be3fc7333 --- /dev/null +++ b/res/layout/activity_hidden_apps.xml @@ -0,0 +1,52 @@ +<!-- + Copyright (C) 2019 The LineageOS Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="vertical"> + + + <android.support.v7.widget.RecyclerView + android:id="@+id/hidden_apps_list" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:visibility="gone" /> + + <LinearLayout + android:id="@+id/hidden_apps_loading" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:gravity="center" + android:orientation="vertical"> + + <ProgressBar + android:id="@+id/hidden_apps_progress_bar" + style="@android:style/Widget.DeviceDefault.ProgressBar.Horizontal" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:paddingStart="32dp" + android:paddingEnd="32dp" + android:max="100" + android:progress="0" /> + + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="16dp" + android:text="@string/protected_apps_loading" + android:textSize="16sp" /> + </LinearLayout> +</LinearLayout>
\ No newline at end of file diff --git a/res/layout/item_hidden_app.xml b/res/layout/item_hidden_app.xml new file mode 100644 index 000000000..73c604620 --- /dev/null +++ b/res/layout/item_hidden_app.xml @@ -0,0 +1,43 @@ +<!-- + Copyright (C) 2019 The LineageOS Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="64dp"> + + <ImageView + android:id="@+id/item_hidden_app_icon" + android:layout_width="48dp" + android:layout_height="48dp" + android:layout_centerVertical="true" + android:layout_marginStart="16dp" /> + + <ImageView + android:id="@+id/item_hidden_app_switch" + android:layout_width="24dp" + android:layout_height="24dp" + android:layout_alignParentEnd="true" + android:layout_centerVertical="true" + android:layout_marginEnd="16dp" /> + + <TextView + android:id="@+id/item_hidden_app_title" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_alignEnd="@id/item_hidden_app_switch" + android:layout_centerVertical="true" + android:layout_marginEnd="56dp" + android:layout_marginStart="88dp" /> +</RelativeLayout> diff --git a/res/values/config.xml b/res/values/config.xml index 3886de936..2e7592b77 100644 --- a/res/values/config.xml +++ b/res/values/config.xml @@ -78,7 +78,7 @@ <!-- Name of a subclass of com.android.launcher3.AppFilter used to filter the activities shown in the launcher. Can be empty. --> - <string name="app_filter_class" translatable="false"></string> + <string name="app_filter_class" translatable="false">com.android.launcher3.lineage.hidden.HiddenAppsFilter</string> <!-- Name of an icon provider class. --> <string name="icon_provider_class" translatable="false"></string> diff --git a/res/values/lineage_strings.xml b/res/values/lineage_strings.xml index 603198bbe..828f2d465 100644 --- a/res/values/lineage_strings.xml +++ b/res/values/lineage_strings.xml @@ -64,4 +64,10 @@ <!-- Expand statusbar --> <string name="statusbar_expand">Swipe down to show notifications</string> + + <!-- Hidden apps --> + <string name="hidden_apps_manager_name">Hidden apps</string> + <string name="hidden_apps_auth_manager">Unlock to manage the hidden apps</string> + <string name="protected_apps_loading">Loading\u2026</string> + <string name="hidden_apps_no_lock_error">Please set up a secure lock screen to restrict app access</string> </resources> diff --git a/res/xml/launcher_preferences.xml b/res/xml/launcher_preferences.xml index 17a7925eb..e33f48511 100644 --- a/res/xml/launcher_preferences.xml +++ b/res/xml/launcher_preferences.xml @@ -65,13 +65,19 @@ android:persistent="true" /> </PreferenceCategory> - <PreferenceCategory android:title="@string/settings_category_drawer"> + <PreferenceCategory + android:key="category_drawer" + android:title="@string/settings_category_drawer"> <SwitchPreference android:key="pref_drawer_show_labels" android:title="@string/drawer_show_labels" android:defaultValue="true" android:persistent="true" /> + + <Preference + android:key="pref_hidden_apps" + android:title="@string/hidden_apps_manager_name" /> </PreferenceCategory> <PreferenceCategory diff --git a/src/com/android/launcher3/SettingsActivity.java b/src/com/android/launcher3/SettingsActivity.java index c055c130f..bbb3eeff6 100644 --- a/src/com/android/launcher3/SettingsActivity.java +++ b/src/com/android/launcher3/SettingsActivity.java @@ -54,6 +54,7 @@ import android.widget.NumberPicker; import com.android.launcher3.graphics.IconShapeOverride; import com.android.launcher3.lineage.LineageLauncherCallbacks; import com.android.launcher3.lineage.LineageUtils; +import com.android.launcher3.lineage.hidden.HiddenAppsActivity; import com.android.launcher3.notification.NotificationListener; import com.android.launcher3.util.ListViewHighlighter; import com.android.launcher3.util.SettingsObserver; @@ -132,6 +133,8 @@ public class SettingsActivity extends Activity { PreferenceCategory homeGroup = (PreferenceCategory) findPreference("category_home"); + PreferenceCategory drawerGroup = (PreferenceCategory) + findPreference("category_drawer"); PreferenceCategory iconGroup = (PreferenceCategory) findPreference("category_icons"); @@ -186,6 +189,15 @@ public class SettingsActivity extends Activity { mGridPref.setSummary(mPrefs.getString(KEY_GRID_SIZE, getDefaultGridSize())); } + + Preference hiddenApps = drawerGroup.findPreference("pref_hidden_apps"); + if (hiddenApps != null) { + hiddenApps.setOnPreferenceClickListener(preference -> { + Intent intent = new Intent(getActivity(), HiddenAppsActivity.class); + startActivity(intent); + return true; + }); + } } @Override diff --git a/src/com/android/launcher3/lineage/hidden/HiddenAppsActivity.java b/src/com/android/launcher3/lineage/hidden/HiddenAppsActivity.java new file mode 100644 index 000000000..bd7056417 --- /dev/null +++ b/src/com/android/launcher3/lineage/hidden/HiddenAppsActivity.java @@ -0,0 +1,155 @@ +/* + * Copyright (C) 2019 The LineageOS Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.launcher3.lineage.hidden; + +import android.app.ActionBar; +import android.app.Activity; +import android.app.KeyguardManager; +import android.content.Context; +import android.content.Intent; +import android.os.Build; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v7.widget.DefaultItemAnimator; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.view.MenuItem; +import android.view.View; +import android.widget.LinearLayout; +import android.widget.ProgressBar; +import android.widget.Toast; + +import com.android.launcher3.LauncherAppState; +import com.android.launcher3.R; +import com.android.launcher3.lineage.hidden.db.HiddenComponent; +import com.android.launcher3.lineage.hidden.db.HiddenDatabaseHelper; + +import java.util.List; + +public class HiddenAppsActivity extends Activity implements + HiddenAppsAdapter.Listener, + LoadHiddenComponentsTask.Callback, + UpdateItemVisibilityTask.UpdateCallback { + private static final int REQUEST_AUTH_CODE = 92; + + private RecyclerView mRecyclerView; + private LinearLayout mLoadingView; + private ProgressBar mProgressBar; + + private HiddenDatabaseHelper mDbHelper; + private HiddenAppsAdapter mAdapter; + + @Override + protected void onCreate(@Nullable Bundle savedInstance) { + super.onCreate(savedInstance); + + ActionBar actionBar = getActionBar(); + if (actionBar != null) { + actionBar.setDisplayHomeAsUpEnabled(true); + } + + setContentView(R.layout.activity_hidden_apps); + mRecyclerView = findViewById(R.id.hidden_apps_list); + mLoadingView = findViewById(R.id.hidden_apps_loading); + mProgressBar = findViewById(R.id.hidden_apps_progress_bar); + + mAdapter = new HiddenAppsAdapter(this); + mDbHelper = HiddenDatabaseHelper.getInstance(this); + + mRecyclerView.setLayoutManager(new LinearLayoutManager(this)); + mRecyclerView.setItemAnimator(new DefaultItemAnimator()); + mRecyclerView.setAdapter(mAdapter); + + authenticate(); + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + + if (requestCode == REQUEST_AUTH_CODE) { + if (resultCode == Activity.RESULT_OK) { + showUi(); + } else { + finish(); + } + } + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + if (item.getItemId() == android.R.id.home) { + finish(); + return true; + } + + return super.onOptionsItemSelected(item); + } + + @Override + public void onItemChanged(@NonNull HiddenComponent component) { + new UpdateItemVisibilityTask(mDbHelper, this).execute(component); + } + + @Override + public void onUpdated(boolean result) { + LauncherAppState state = LauncherAppState.getInstanceNoCreate(); + if (state != null) { + state.getModel().forceReload(); + } + } + + @Override + public void onLoadListProgress(int progress) { + mProgressBar.setProgress(progress); + } + + @Override + public void onLoadCompleted(List<HiddenComponent> result) { + mLoadingView.setVisibility(View.GONE); + mRecyclerView.setVisibility(View.VISIBLE); + mAdapter.update(result); + } + + private void authenticate() { + KeyguardManager manager = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M ? + getSystemService(KeyguardManager.class) : + (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE); + if (manager == null) { + throw new NullPointerException("No KeyguardManager found!"); + } + + String title = getString(R.string.hidden_apps_manager_name); + String message = getString(R.string.hidden_apps_auth_manager); + Intent intent = manager.createConfirmDeviceCredentialIntent(title, message); + + if (intent != null) { + startActivityForResult(intent, REQUEST_AUTH_CODE); + return; + } + + Toast.makeText(this, R.string.hidden_apps_no_lock_error, + Toast.LENGTH_LONG).show(); + finish(); + } + + private void showUi() { + mLoadingView.setVisibility(View.VISIBLE); + + new LoadHiddenComponentsTask(mDbHelper, getPackageManager(), this).execute(); + } +} diff --git a/src/com/android/launcher3/lineage/hidden/HiddenAppsAdapter.java b/src/com/android/launcher3/lineage/hidden/HiddenAppsAdapter.java new file mode 100644 index 000000000..acb07ee90 --- /dev/null +++ b/src/com/android/launcher3/lineage/hidden/HiddenAppsAdapter.java @@ -0,0 +1,154 @@ +/* + * Copyright (C) 2019 The LineageOS Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.launcher3.lineage.hidden; + +import android.graphics.drawable.Animatable2; +import android.graphics.drawable.AnimatedVectorDrawable; +import android.graphics.drawable.Drawable; +import android.os.Build; +import android.support.annotation.NonNull; +import android.support.v7.util.DiffUtil; +import android.support.v7.widget.RecyclerView; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.TextView; + +import com.android.launcher3.R; +import com.android.launcher3.lineage.hidden.db.HiddenComponent; + +import java.util.ArrayList; +import java.util.List; + +class HiddenAppsAdapter extends RecyclerView.Adapter<HiddenAppsAdapter.ViewHolder> { + private List<HiddenComponent> mList = new ArrayList<>(); + private Listener mListener; + + HiddenAppsAdapter(Listener listener) { + mListener = listener; + } + + public void update(List<HiddenComponent> list) { + DiffUtil.DiffResult result = DiffUtil.calculateDiff(new Callback(mList, list)); + mList = list; + result.dispatchUpdatesTo(this); + } + + @NonNull + @Override + public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int type) { + return new ViewHolder(LayoutInflater.from(parent.getContext()) + .inflate(R.layout.item_hidden_app, parent, false)); + } + + @Override + public void onBindViewHolder(@NonNull ViewHolder viewHolder, int i) { + viewHolder.bind(mList.get(i)); + } + + @Override + public int getItemCount() { + return mList.size(); + } + + public interface Listener { + void onItemChanged(@NonNull HiddenComponent component); + } + + class ViewHolder extends RecyclerView.ViewHolder { + private ImageView mIconView; + private TextView mLabelView; + private ImageView mLockView; + + ViewHolder(@NonNull View itemView) { + super(itemView); + + mIconView = itemView.findViewById(R.id.item_hidden_app_icon); + mLabelView = itemView.findViewById(R.id.item_hidden_app_title); + mLockView = itemView.findViewById(R.id.item_hidden_app_switch); + } + + void bind(HiddenComponent component) { + mIconView.setImageDrawable(component.getIcon()); + mLabelView.setText(component.getLabel()); + mLockView.setImageResource(component.isHidden() ? + R.drawable.ic_hidden_locked : R.drawable.ic_hidden_unlocked); + + itemView.setOnClickListener(v -> { + component.invertVisibility(); + + mLockView.setImageResource(component.isHidden() ? + R.drawable.avd_hidden_lock : R.drawable.avd_hidden_unlock); + AnimatedVectorDrawable avd = (AnimatedVectorDrawable) mLockView.getDrawable(); + + int position = getAdapterPosition(); + if (Build.VERSION.SDK_INT > Build.VERSION_CODES.M) { + avd.registerAnimationCallback(new Animatable2.AnimationCallback() { + @Override + public void onAnimationEnd(Drawable drawable) { + updateList(position, component); + } + }); + avd.start(); + } else { + avd.start(); + updateList(position, component); + } + }); + } + + private void updateList(int position, HiddenComponent component) { + mListener.onItemChanged(component); + mList.set(position, component); + notifyItemChanged(position); + } + } + + private static class Callback extends DiffUtil.Callback { + List<HiddenComponent> mOldList; + List<HiddenComponent> mNewList; + + public Callback(List<HiddenComponent> oldList, + List<HiddenComponent> newList) { + mOldList = oldList; + mNewList = newList; + } + + + @Override + public int getOldListSize() { + return mOldList.size(); + } + + @Override + public int getNewListSize() { + return mNewList.size(); + } + + @Override + public boolean areItemsTheSame(int iOld, int iNew) { + String oldPkg = mOldList.get(iOld).getPackageName(); + String newPkg = mNewList.get(iNew).getPackageName(); + return oldPkg.equals(newPkg); + } + + @Override + public boolean areContentsTheSame(int iOld, int iNew) { + return mOldList.get(iOld).equals(mNewList.get(iNew)); + } + } +} diff --git a/src/com/android/launcher3/lineage/hidden/HiddenAppsFilter.java b/src/com/android/launcher3/lineage/hidden/HiddenAppsFilter.java new file mode 100644 index 000000000..47274f73e --- /dev/null +++ b/src/com/android/launcher3/lineage/hidden/HiddenAppsFilter.java @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2019 The LineageOS Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.launcher3.lineage.hidden; + +import android.content.ComponentName; +import android.content.Context; + +import com.android.launcher3.AppFilter; +import com.android.launcher3.lineage.hidden.db.HiddenDatabaseHelper; + +@SuppressWarnings("unused") +public class HiddenAppsFilter extends AppFilter { + private HiddenDatabaseHelper mDbHelper; + + public HiddenAppsFilter(Context context) { + if (context == null) { + throw new IllegalArgumentException("Context must not be null!"); + } + + mDbHelper = HiddenDatabaseHelper.getInstance(context); + } + + @Override + public boolean shouldShowApp(ComponentName app) { + return !mDbHelper.isPackageHidden(app.getPackageName()); + } +} diff --git a/src/com/android/launcher3/lineage/hidden/LoadHiddenComponentsTask.java b/src/com/android/launcher3/lineage/hidden/LoadHiddenComponentsTask.java new file mode 100644 index 000000000..4636cebd7 --- /dev/null +++ b/src/com/android/launcher3/lineage/hidden/LoadHiddenComponentsTask.java @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2019 The LineageOS Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.launcher3.lineage.hidden; + +import android.content.Intent; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.graphics.drawable.Drawable; +import android.os.AsyncTask; +import android.os.Build; +import android.support.annotation.NonNull; + +import com.android.launcher3.lineage.hidden.db.HiddenComponent; +import com.android.launcher3.lineage.hidden.db.HiddenDatabaseHelper; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class LoadHiddenComponentsTask extends AsyncTask<Void, Integer, List<HiddenComponent>> { + @NonNull + private HiddenDatabaseHelper mDbHelper; + + @NonNull + private PackageManager mPackageManager; + + @NonNull + private Callback mCallback; + + LoadHiddenComponentsTask(@NonNull HiddenDatabaseHelper dbHelper, + @NonNull PackageManager packageManager, + @NonNull Callback callback) { + mDbHelper = dbHelper; + mPackageManager = packageManager; + mCallback = callback; + } + + @Override + protected List<HiddenComponent> doInBackground(Void... voids) { + List<HiddenComponent> list = new ArrayList<>(); + + Intent filter = new Intent(Intent.ACTION_MAIN, null); + filter.addCategory(Intent.CATEGORY_LAUNCHER); + + List<ResolveInfo> apps = mPackageManager.queryIntentActivities(filter, + PackageManager.GET_META_DATA); + + int numPackages = apps.size(); + for (int i = 0; i < numPackages; i++) { + ResolveInfo app = apps.get(i); + try { + String pkgName = app.activityInfo.packageName; + String label = mPackageManager.getApplicationLabel( + mPackageManager.getApplicationInfo(pkgName, + PackageManager.GET_META_DATA)).toString(); + Drawable icon = app.loadIcon(mPackageManager); + boolean isHidden = mDbHelper.isPackageHidden(pkgName); + + list.add(new HiddenComponent(pkgName, icon, label, isHidden)); + + publishProgress(Math.round(i * 100f / numPackages)); + } catch (PackageManager.NameNotFoundException ignored) { + } + } + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + Collections.sort(list, (a, b) -> a.getLabel().compareTo(b.getLabel())); + } + + return list; + } + + @Override + protected void onProgressUpdate(Integer... values) { + if (values.length > 0) { + mCallback.onLoadListProgress(values[0]); + } + } + + @Override + protected void onPostExecute(List<HiddenComponent> hiddenComponents) { + mCallback.onLoadCompleted(hiddenComponents); + } + + interface Callback { + void onLoadListProgress(int progress); + void onLoadCompleted(List<HiddenComponent> result); + } +} diff --git a/src/com/android/launcher3/lineage/hidden/UpdateItemVisibilityTask.java b/src/com/android/launcher3/lineage/hidden/UpdateItemVisibilityTask.java new file mode 100644 index 000000000..b751fdc4f --- /dev/null +++ b/src/com/android/launcher3/lineage/hidden/UpdateItemVisibilityTask.java @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2019 The LineageOS Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.launcher3.lineage.hidden; + +import android.os.AsyncTask; +import android.support.annotation.NonNull; + +import com.android.launcher3.lineage.hidden.db.HiddenComponent; +import com.android.launcher3.lineage.hidden.db.HiddenDatabaseHelper; + +public class UpdateItemVisibilityTask extends AsyncTask<HiddenComponent, Void, Boolean> { + @NonNull + private HiddenDatabaseHelper mDbHelper; + @NonNull + private UpdateCallback mCallback; + + UpdateItemVisibilityTask(@NonNull HiddenDatabaseHelper dbHelper, + @NonNull UpdateCallback callback) { + mDbHelper = dbHelper; + mCallback = callback; + } + + @Override + protected Boolean doInBackground(HiddenComponent... hiddenComponents) { + if (hiddenComponents.length < 1) { + return false; + } + + HiddenComponent component = hiddenComponents[0]; + String pkgName = component.getPackageName(); + + if (component.isHidden()) { + mDbHelper.addApp(pkgName); + } else { + mDbHelper.removeApp(pkgName); + } + + return true; + } + + @Override + protected void onPostExecute(Boolean result) { + mCallback.onUpdated(result); + } + + interface UpdateCallback { + void onUpdated(boolean result); + } +} diff --git a/src/com/android/launcher3/lineage/hidden/db/HiddenComponent.java b/src/com/android/launcher3/lineage/hidden/db/HiddenComponent.java new file mode 100644 index 000000000..d95d5c823 --- /dev/null +++ b/src/com/android/launcher3/lineage/hidden/db/HiddenComponent.java @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2019 The LineageOS Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.launcher3.lineage.hidden.db; + +import android.graphics.drawable.Drawable; +import android.support.annotation.NonNull; + +public class HiddenComponent { + @NonNull private final String mPackageName; + @NonNull private final Drawable mIcon; + @NonNull private final String mLabel; + private boolean mIsHidden; + + public HiddenComponent(@NonNull String packageName, @NonNull Drawable icon, + @NonNull String label, boolean isHidden) { + mPackageName = packageName; + mIcon = icon; + mLabel = label; + mIsHidden = isHidden; + } + + @NonNull + public String getPackageName() { + return mPackageName; + } + + @NonNull + public Drawable getIcon() { + return mIcon; + } + + @NonNull + public String getLabel() { + return mLabel; + } + + public boolean isHidden() { + return mIsHidden; + } + + public void invertVisibility() { + mIsHidden = !mIsHidden; + } + + @Override + public boolean equals(Object other) { + if (!(other instanceof HiddenComponent)) { + return false; + } + + HiddenComponent otherComponent = (HiddenComponent) other; + return otherComponent.getPackageName().equals(mPackageName) && + otherComponent.isHidden() == mIsHidden; + } + + @Override + public int hashCode() { + return mPackageName.hashCode() + (mIsHidden ? 1 : 0); + } +} diff --git a/src/com/android/launcher3/lineage/hidden/db/HiddenDatabaseHelper.java b/src/com/android/launcher3/lineage/hidden/db/HiddenDatabaseHelper.java new file mode 100644 index 000000000..bfc4dfa30 --- /dev/null +++ b/src/com/android/launcher3/lineage/hidden/db/HiddenDatabaseHelper.java @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2019 The LineageOS Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.launcher3.lineage.hidden.db; + +import android.content.ContentValues; +import android.content.Context; +import android.database.Cursor; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteOpenHelper; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; + +public class HiddenDatabaseHelper extends SQLiteOpenHelper { + private static final int DATABASE_VERSION = 1; + private static final String DATABSE_NAME = "hidden_apps_db"; + + private static final String TABLE_NAME = "hidden_apps"; + private static final String KEY_UID = "uid"; + private static final String KEY_PKGNAME = "pkgname"; + + @Nullable + private static HiddenDatabaseHelper sSingleton; + + private HiddenDatabaseHelper(@NonNull Context context) { + super(context, DATABSE_NAME, null, DATABASE_VERSION); + } + + public static synchronized HiddenDatabaseHelper getInstance(@NonNull Context context) { + if (sSingleton == null) { + sSingleton = new HiddenDatabaseHelper(context); + } + + return sSingleton; + } + + @Override + public void onCreate(SQLiteDatabase db) { + String CMD_CREATE_TABLE = "CREATE TABLE " + TABLE_NAME + + "(" + + KEY_UID + " INTEGER PRIMARY KEY AUTOINCREMENT," + + KEY_PKGNAME + " TEXT" + + ")"; + db.execSQL(CMD_CREATE_TABLE); + } + + @Override + public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { + } + + public void addApp(@NonNull String packageName) { + if (isPackageHidden(packageName)) { + return; + } + + SQLiteDatabase db = getWritableDatabase(); + db.beginTransaction(); + + try { + ContentValues values = new ContentValues(); + values.put(KEY_PKGNAME, packageName); + + db.insertOrThrow(TABLE_NAME, null, values); + db.setTransactionSuccessful(); + } catch (Exception e) { + // Ignored + } finally { + db.endTransaction(); + } + } + + public void removeApp(@NonNull String packageName) { + if (!isPackageHidden(packageName)) { + return; + } + + SQLiteDatabase db = getWritableDatabase(); + db.beginTransaction(); + + try { + db.delete(TABLE_NAME, KEY_PKGNAME + "=?", new String[]{packageName}); + db.setTransactionSuccessful(); + } catch (Exception e) { + // Ignored + } finally { + db.endTransaction(); + } + } + + public boolean isPackageHidden(@NonNull String packageName) { + String query = String.format("SELECT * FROM %s WHERE %s = ?", TABLE_NAME, KEY_PKGNAME); + SQLiteDatabase db = getReadableDatabase(); + Cursor cursor = db.rawQuery(query, new String[]{packageName}); + boolean result = false; + try { + result = cursor.getCount() != 0; + } catch (Exception e) { + // Ignored + } finally { + if (cursor != null && !cursor.isClosed()) { + cursor.close(); + } + } + + return result; + } +} |