From 26258e1bf1d578d297f3a1adf95034617caccad3 Mon Sep 17 00:00:00 2001 From: Joey Date: Wed, 23 Jan 2019 17:49:25 +0100 Subject: Trebuchet: implement hidden apps Signed-off-by: Joey Signed-off-by: Luca Stefani Change-Id: I10c35407820373a1d5f84b237ac449398e076dcd --- AndroidManifest.xml | 6 + proguard.flags | 4 + res/drawable/avd_hidden_lock.xml | 65 +++++++++ res/drawable/avd_hidden_unlock.xml | 63 +++++++++ res/drawable/ic_hidden_locked.xml | 24 ++++ res/drawable/ic_hidden_unlocked.xml | 26 ++++ res/layout/activity_hidden_apps.xml | 52 +++++++ res/layout/item_hidden_app.xml | 43 ++++++ res/values/config.xml | 2 +- res/values/lineage_strings.xml | 6 + res/xml/launcher_preferences.xml | 8 +- src/com/android/launcher3/SettingsActivity.java | 12 ++ .../lineage/hidden/HiddenAppsActivity.java | 155 +++++++++++++++++++++ .../lineage/hidden/HiddenAppsAdapter.java | 154 ++++++++++++++++++++ .../launcher3/lineage/hidden/HiddenAppsFilter.java | 40 ++++++ .../lineage/hidden/LoadHiddenComponentsTask.java | 102 ++++++++++++++ .../lineage/hidden/UpdateItemVisibilityTask.java | 62 +++++++++ .../lineage/hidden/db/HiddenComponent.java | 73 ++++++++++ .../lineage/hidden/db/HiddenDatabaseHelper.java | 119 ++++++++++++++++ 19 files changed, 1014 insertions(+), 2 deletions(-) create mode 100644 res/drawable/avd_hidden_lock.xml create mode 100644 res/drawable/avd_hidden_unlock.xml create mode 100644 res/drawable/ic_hidden_locked.xml create mode 100644 res/drawable/ic_hidden_unlocked.xml create mode 100644 res/layout/activity_hidden_apps.xml create mode 100644 res/layout/item_hidden_app.xml create mode 100644 src/com/android/launcher3/lineage/hidden/HiddenAppsActivity.java create mode 100644 src/com/android/launcher3/lineage/hidden/HiddenAppsAdapter.java create mode 100644 src/com/android/launcher3/lineage/hidden/HiddenAppsFilter.java create mode 100644 src/com/android/launcher3/lineage/hidden/LoadHiddenComponentsTask.java create mode 100644 src/com/android/launcher3/lineage/hidden/UpdateItemVisibilityTask.java create mode 100644 src/com/android/launcher3/lineage/hidden/db/HiddenComponent.java create mode 100644 src/com/android/launcher3/lineage/hidden/db/HiddenDatabaseHelper.java diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 6141d56c9..5eac53a87 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -105,6 +105,12 @@ + + + + + + + + + + + + + + + + + + + + + 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 @@ + + + + + + + + + + + + + + + + + + + + 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 @@ + + + + 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 @@ + + + + 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 @@ + + + + + + + + + + + + + \ 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 @@ + + + + + + + + + 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 @@ - + com.android.launcher3.lineage.hidden.HiddenAppsFilter 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 @@ Swipe down to show notifications + + + Hidden apps + Unlock to manage the hidden apps + Loading\u2026 + Please set up a secure lock screen to restrict app access 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" /> - + + + { + 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 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 { + private List mList = new ArrayList<>(); + private Listener mListener; + + HiddenAppsAdapter(Listener listener) { + mListener = listener; + } + + public void update(List 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 mOldList; + List mNewList; + + public Callback(List oldList, + List 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> { + @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 doInBackground(Void... voids) { + List list = new ArrayList<>(); + + Intent filter = new Intent(Intent.ACTION_MAIN, null); + filter.addCategory(Intent.CATEGORY_LAUNCHER); + + List 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 hiddenComponents) { + mCallback.onLoadCompleted(hiddenComponents); + } + + interface Callback { + void onLoadListProgress(int progress); + void onLoadCompleted(List 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 { + @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; + } +} -- cgit v1.2.3