diff options
author | Yajat <yajatapps3@gmail.com> | 2017-11-10 21:08:21 +0100 |
---|---|---|
committer | Arne Coucheron <arco68@gmail.com> | 2018-01-19 00:27:13 +0100 |
commit | aca5a8bc95c1461419039a2041a8a54a84f49790 (patch) | |
tree | 1768ec3d10ef4bf859934f18030b768f513c9c32 | |
parent | 7966f340e5ce151e19a6121a3b9c1ce8a9d8c87b (diff) | |
download | android_packages_apps_Trebuchet-aca5a8bc95c1461419039a2041a8a54a84f49790.tar.gz android_packages_apps_Trebuchet-aca5a8bc95c1461419039a2041a8a54a84f49790.tar.bz2 android_packages_apps_Trebuchet-aca5a8bc95c1461419039a2041a8a54a84f49790.zip |
Trebuchet: predictive apps
jrizzoli: expose for runtime toggle
Signed-off-by: Joey <joey@lineageos.org>
-rw-r--r-- | res/values/lineage_strings.xml | 5 | ||||
-rw-r--r-- | res/xml/launcher_preferences.xml | 7 | ||||
-rw-r--r-- | src/com/android/launcher3/Launcher.java | 31 | ||||
-rw-r--r-- | src/com/android/launcher3/allapps/PredictiveAppsProvider.java | 125 | ||||
-rw-r--r-- | src/com/android/launcher3/config/BaseFlags.java | 2 |
5 files changed, 164 insertions, 6 deletions
diff --git a/res/values/lineage_strings.xml b/res/values/lineage_strings.xml index 5a453ef1f..fe574ebba 100644 --- a/res/values/lineage_strings.xml +++ b/res/values/lineage_strings.xml @@ -24,4 +24,9 @@ <!-- Expand statusbar --> <string name="statusbar_expand">Swipe down to show notifications</string> + + <!-- Predictive apps --> + <string name="predictive_apps_title">Predictive apps</string> + <string name="predictive_apps_summary_on">Your favorite apps will appear at the top of the drawer</string> + <string name="predictive_apps_summary_off">Your favorite apps won\'t appear at the top of the drawer</string> </resources> diff --git a/res/xml/launcher_preferences.xml b/res/xml/launcher_preferences.xml index 3be5d4792..7077758b2 100644 --- a/res/xml/launcher_preferences.xml +++ b/res/xml/launcher_preferences.xml @@ -59,4 +59,11 @@ android:defaultValue="true" android:persistent="true" /> + <SwitchPreference + android:key="pref_predictive_apps" + android:title="@string/predictive_apps_title" + android:summaryOn="@string/predictive_apps_summary_on" + android:summaryOff="@string/predictive_apps_summary_off" + android:defaultValue="true" + android:persistent="true" /> </PreferenceScreen> diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index 7b4313314..ea5881608 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -87,6 +87,7 @@ import com.android.launcher3.Workspace.ItemOperator; import com.android.launcher3.accessibility.LauncherAccessibilityDelegate; import com.android.launcher3.allapps.AllAppsContainerView; import com.android.launcher3.allapps.AllAppsTransitionController; +import com.android.launcher3.allapps.PredictiveAppsProvider; import com.android.launcher3.anim.AnimationLayerSet; import com.android.launcher3.compat.AppWidgetManagerCompat; import com.android.launcher3.compat.LauncherAppsCompat; @@ -348,6 +349,8 @@ public class Launcher extends BaseActivity private RotationPrefChangeHandler mRotationPrefChangeHandler; + private PredictiveAppsProvider mPredictiveAppsProvider; + @Override protected void onCreate(Bundle savedInstanceState) { if (DEBUG_STRICT_MODE) { @@ -368,6 +371,8 @@ public class Launcher extends BaseActivity Trace.beginSection("Launcher-onCreate"); } + mPredictiveAppsProvider = new PredictiveAppsProvider(this); + if (mLauncherCallbacks != null) { mLauncherCallbacks.preOnCreate(); } @@ -487,6 +492,8 @@ public class Launcher extends BaseActivity if (mLauncherCallbacks != null) { mLauncherCallbacks.onCreate(savedInstanceState); } + + tryAndUpdatePredictedApps(); } @Override @@ -2607,6 +2614,9 @@ public class Launcher extends BaseActivity } else { // Could be launching some bookkeeping activity startActivity(intent, optsBundle); + if (isAllAppsVisible()) { + mPredictiveAppsProvider.updateComponentCount(intent.getComponent()); + } } } finally { StrictMode.setVmPolicy(oldPolicy); @@ -2693,6 +2703,9 @@ public class Launcher extends BaseActivity } else if (user == null || user.equals(Process.myUserHandle())) { // Could be launching some bookkeeping activity startActivity(intent, optsBundle); + if (isAllAppsVisible()) { + mPredictiveAppsProvider.updateComponentCount(intent.getComponent()); + } } else { LauncherAppsCompat.getInstance(this).startActivityForProfile( intent.getComponent(), user, intent.getSourceBounds(), optsBundle); @@ -3053,12 +3066,20 @@ public class Launcher extends BaseActivity * resumed. */ public void tryAndUpdatePredictedApps() { - if (mLauncherCallbacks != null) { - List<ComponentKeyMapper<AppInfo>> apps = mLauncherCallbacks.getPredictedApps(); - if (apps != null) { - mAppsView.setPredictedApps(apps); - } + if (!mSharedPrefs.getBoolean("pref_predictive_apps", true)) { + mAppsView.setPredictedApps(new ArrayList<>()); + return; + } + + List<ComponentKeyMapper<AppInfo>> apps; + if (mLauncherCallbacks == null) { + apps = mPredictiveAppsProvider.getPredictions(); + mPredictiveAppsProvider.updateTopPredictedApps(); + } else { + apps = mLauncherCallbacks.getPredictedApps(); } + + mAppsView.setPredictedApps(apps); } void lockAllApps() { diff --git a/src/com/android/launcher3/allapps/PredictiveAppsProvider.java b/src/com/android/launcher3/allapps/PredictiveAppsProvider.java new file mode 100644 index 000000000..ba39094c1 --- /dev/null +++ b/src/com/android/launcher3/allapps/PredictiveAppsProvider.java @@ -0,0 +1,125 @@ +package com.android.launcher3.allapps; + +import android.content.ComponentName; +import android.content.Context; +import android.content.SharedPreferences; +import android.os.Process; + +import com.android.launcher3.AppInfo; +import com.android.launcher3.Utilities; +import com.android.launcher3.util.ComponentKey; +import com.android.launcher3.util.ComponentKeyMapper; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +public class PredictiveAppsProvider { + private static final int NUM_PREDICTIVE_APPS_TO_HOLD = 9; // since we can't have more than 9 columns + + private static final String PREDICTIVE_APPS_KEY = "predictive_apps"; + private static final String TOP_PREDICTIVE_APPS_KEY = "top_predictive_apps"; + + private SharedPreferences mPrefs; + + public PredictiveAppsProvider(Context context) { + this.mPrefs = Utilities.getPrefs(context.getApplicationContext()); + } + + public void updateComponentCount(ComponentName component) { + String key = buildComponentString(component); + long current = mPrefs.getLong(key, 0); + + mPrefs.edit().putLong(key, current + 1).apply(); + + // ensure that the set of predictive apps contains this one + Set<String> predictiveApps = + mPrefs.getStringSet(PREDICTIVE_APPS_KEY, new HashSet<>()); + if (!predictiveApps.contains(key)) { + predictiveApps.add(key); + mPrefs.edit().putStringSet(PREDICTIVE_APPS_KEY, predictiveApps).apply(); + } + } + + public void updateTopPredictedApps() { + new Thread(() -> { + List< PredictedApp > allPredictions = new ArrayList<>(); + Set<String> predictiveAppsSet = + mPrefs.getStringSet(PREDICTIVE_APPS_KEY, new HashSet<>()); + + for (String s : predictiveAppsSet) { + allPredictions.add(new PredictedApp(buildComponentFromString(s), + mPrefs.getLong(s, 0))); + } + + Collections.sort(allPredictions, (result1, result2) -> + Long.valueOf(result2.count).compareTo(result1.count)); + + if (allPredictions.size() > NUM_PREDICTIVE_APPS_TO_HOLD) { + allPredictions = allPredictions.subList(0, NUM_PREDICTIVE_APPS_TO_HOLD); + } + + mPrefs.edit().putString(TOP_PREDICTIVE_APPS_KEY, + buildStringFromAppList(allPredictions)).apply(); + }).start(); + } + + public List<ComponentKeyMapper<AppInfo>> getPredictions() { + String predictions = mPrefs.getString(TOP_PREDICTIVE_APPS_KEY, ""); + if (predictions.isEmpty()) { + return new ArrayList<>(); + } + + String[] topPredictions = predictions.split(" "); + List<ComponentKeyMapper<AppInfo>> keys = new ArrayList<>(); + + for (int i = 0; i < topPredictions.length - 1; i++) { + keys.add(buildComponentKey(topPredictions[i] + " " + topPredictions[i + 1])); + } + + return keys; + } + + private String buildStringFromAppList(List<PredictedApp> apps) { + StringBuilder string = new StringBuilder(); + for (PredictedApp app : apps) { + string.append(buildComponentString(app.component)).append(" "); + } + + try { + return string.substring(0, string.length() - 1); + } catch (StringIndexOutOfBoundsException e) { + return ""; + } + } + + private String buildComponentString(ComponentName component) { + return component.getPackageName() + " " + component.getClassName(); + } + + private ComponentName buildComponentFromString(String key) { + String[] arr = key.split(" "); + return new ComponentName(arr[0], arr[1]); + } + + private ComponentKeyMapper<AppInfo> buildComponentKey(String key) { + return buildComponentKey(buildComponentFromString(key)); + } + + private ComponentKeyMapper<AppInfo> buildComponentKey(ComponentName component) { + return new ComponentKeyMapper<>(new ComponentKey(component, Process.myUserHandle())); + } + + private class PredictedApp { + public ComponentName component; + public long count; + + public PredictedApp(ComponentName component, long count) { + this.component = component; + this.count = count; + } + } + +}
\ No newline at end of file diff --git a/src/com/android/launcher3/config/BaseFlags.java b/src/com/android/launcher3/config/BaseFlags.java index 15fa553bf..a9ad301af 100644 --- a/src/com/android/launcher3/config/BaseFlags.java +++ b/src/com/android/launcher3/config/BaseFlags.java @@ -61,7 +61,7 @@ abstract class BaseFlags { // When enabled, adaptive icons would have shadows baked when being stored to icon cache. public static final boolean ADAPTIVE_ICON_SHADOW = true; // When enabled, app discovery will be enabled if service is implemented - public static final boolean DISCOVERY_ENABLED = false; + public static final boolean DISCOVERY_ENABLED = true; // When enabled, the qsb will be moved to the hotseat. public static final boolean QSB_IN_HOTSEAT = true; |