You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
268 lines
9.5 KiB
268 lines
9.5 KiB
/*
|
|
* Copyright (C) 2019 The Android Open Source 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.apppredictionservice;
|
|
|
|
import static android.os.Process.myUserHandle;
|
|
import static android.text.TextUtils.isEmpty;
|
|
|
|
import static java.util.Collections.emptyList;
|
|
|
|
import android.app.prediction.AppPredictionContext;
|
|
import android.app.prediction.AppPredictionSessionId;
|
|
import android.app.prediction.AppTarget;
|
|
import android.app.prediction.AppTargetEvent;
|
|
import android.app.prediction.AppTargetId;
|
|
import android.content.ComponentName;
|
|
import android.content.Context;
|
|
import android.content.Intent;
|
|
import android.content.SharedPreferences;
|
|
import android.content.pm.ApplicationInfo;
|
|
import android.content.pm.LauncherActivityInfo;
|
|
import android.content.pm.LauncherApps;
|
|
import android.content.pm.PackageManager;
|
|
import android.content.pm.ResolveInfo;
|
|
import android.os.CancellationSignal;
|
|
import android.service.appprediction.AppPredictionService;
|
|
import android.util.Log;
|
|
import java.util.ArrayList;
|
|
import java.util.HashSet;
|
|
import java.util.List;
|
|
import java.util.Set;
|
|
import java.util.function.Consumer;
|
|
|
|
/*
|
|
* New plugin that replaces prediction driven Aiai APK in P
|
|
* PredictionService simply populates the top row of the app
|
|
* drawer with the 5 most recently used apps. Each time a new
|
|
* app is launched, it is added to the left of the top row.
|
|
* Duplicates are not added.
|
|
*/
|
|
public class PredictionService extends AppPredictionService {
|
|
|
|
private static final String TAG = PredictionService.class.getSimpleName();
|
|
|
|
private final Set<AppPredictionSessionId> activeLauncherSessions = new HashSet<>();
|
|
|
|
private boolean mAppSuggestionsEnabled = true;
|
|
|
|
public static final String MY_PREF = "mypref";
|
|
|
|
private final List<AppTarget> predictionList = new ArrayList<>(5);
|
|
|
|
private final List<String> appNames = new ArrayList<>(5);
|
|
private final String[] appNameKeys = new String[] {
|
|
"first", "second", "third", "fourth", "fifth" };
|
|
|
|
SharedPreferences sharedPreferences;
|
|
SharedPreferences.Editor editor;
|
|
|
|
@Override
|
|
public void onCreate() {
|
|
super.onCreate();
|
|
|
|
Intent calendarIntent = new Intent(Intent.ACTION_MAIN);
|
|
calendarIntent.addCategory(Intent.CATEGORY_APP_CALENDAR);
|
|
|
|
Intent galleryIntent = new Intent(Intent.ACTION_MAIN);
|
|
galleryIntent.addCategory(Intent.CATEGORY_APP_GALLERY);
|
|
|
|
Intent mapsIntent = new Intent(Intent.ACTION_MAIN);
|
|
mapsIntent.addCategory(Intent.CATEGORY_APP_MAPS);
|
|
|
|
Intent emailIntent = new Intent(Intent.ACTION_MAIN);
|
|
emailIntent.addCategory(Intent.CATEGORY_APP_EMAIL);
|
|
|
|
Intent browserIntent = new Intent(Intent.ACTION_MAIN);
|
|
browserIntent.addCategory(Intent.CATEGORY_APP_BROWSER);
|
|
|
|
String[] DEFAULT_PACKAGES = new String[] {
|
|
getDefaultSystemHandlerActivityPackageName(calendarIntent),
|
|
getDefaultSystemHandlerActivityPackageName(galleryIntent),
|
|
getDefaultSystemHandlerActivityPackageName(mapsIntent),
|
|
getDefaultSystemHandlerActivityPackageName(emailIntent),
|
|
getDefaultSystemHandlerActivityPackageName(browserIntent),
|
|
};
|
|
|
|
Log.d(TAG, "AppPredictionService onCreate");
|
|
this.sharedPreferences = getSharedPreferences(MY_PREF, Context.MODE_PRIVATE);
|
|
this.editor = sharedPreferences.edit();
|
|
|
|
if (sharedPreferences.getString(appNameKeys[0], "").isEmpty()) {
|
|
// fill the list with defaults if first one is null when devices powers up for the first time
|
|
for (int i = 0; i < appNameKeys.length; i++) {
|
|
editor.putString(appNameKeys[i],
|
|
getLauncherComponent(DEFAULT_PACKAGES[i]).flattenToShortString());
|
|
}
|
|
this.editor.apply();
|
|
}
|
|
|
|
for (int i = 0; i < appNameKeys.length; i++) {
|
|
String appName = sharedPreferences.getString(appNameKeys[i], "");
|
|
ComponentName cn = ComponentName.unflattenFromString(appName);
|
|
AppTarget target = new AppTarget.Builder(
|
|
new AppTargetId(Integer.toString(i + 1)), cn.getPackageName(), myUserHandle())
|
|
.setClassName(cn.getClassName())
|
|
.build();
|
|
appNames.add(appName);
|
|
predictionList.add(target);
|
|
}
|
|
postPredictionUpdateToAllClients();
|
|
}
|
|
|
|
private ComponentName getLauncherComponent(String packageName) {
|
|
List<LauncherActivityInfo> infos = getSystemService(LauncherApps.class)
|
|
.getActivityList(packageName, myUserHandle());
|
|
if (infos.isEmpty()) {
|
|
return new ComponentName(packageName, "#");
|
|
} else {
|
|
return infos.get(0).getComponentName();
|
|
}
|
|
}
|
|
|
|
private void postPredictionUpdate(AppPredictionSessionId sessionId) {
|
|
updatePredictions(sessionId, mAppSuggestionsEnabled ? predictionList : emptyList());
|
|
}
|
|
|
|
private void postPredictionUpdateToAllClients() {
|
|
for (AppPredictionSessionId session : activeLauncherSessions) {
|
|
postPredictionUpdate(session);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void onCreatePredictionSession(
|
|
AppPredictionContext context, AppPredictionSessionId sessionId) {
|
|
Log.d(TAG, "onCreatePredictionSession");
|
|
|
|
if (context.getUiSurface().equals("home") || context.getUiSurface().equals("overview")) {
|
|
activeLauncherSessions.add(sessionId);
|
|
postPredictionUpdate(sessionId);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void onAppTargetEvent(AppPredictionSessionId sessionId, AppTargetEvent event) {
|
|
|
|
if (!activeLauncherSessions.contains(sessionId)) {
|
|
return;
|
|
}
|
|
|
|
boolean found = false;
|
|
Log.d(TAG, "onAppTargetEvent");
|
|
|
|
AppTarget target = event.getTarget();
|
|
if (target == null || isEmpty(target.getPackageName()) || isEmpty(target.getClassName())) {
|
|
return;
|
|
}
|
|
String mostRecentComponent = new ComponentName(
|
|
target.getPackageName(), target.getClassName()).flattenToString();
|
|
|
|
// Check if packageName already exists in existing list of appNames
|
|
for (String packageName:appNames) {
|
|
if (packageName.contains(target.getPackageName())) {
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!found) {
|
|
appNames.remove(appNames.size() - 1);
|
|
appNames.add(0, mostRecentComponent);
|
|
|
|
for (int i = 0; i < appNameKeys.length; i++) {
|
|
editor.putString(appNameKeys[i], appNames.get(i));
|
|
}
|
|
editor.apply();
|
|
|
|
predictionList.remove(predictionList.size() - 1);
|
|
predictionList.add(0, event.getTarget());
|
|
|
|
Log.d(TAG, "onAppTargetEvent:: update predictions");
|
|
postPredictionUpdateToAllClients();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void onLaunchLocationShown(
|
|
AppPredictionSessionId sessionId, String launchLocation, List<AppTargetId> targetIds) {
|
|
Log.d(TAG, "onLaunchLocationShown");
|
|
}
|
|
|
|
@Override
|
|
public void onSortAppTargets(
|
|
AppPredictionSessionId sessionId,
|
|
List<AppTarget> targets,
|
|
CancellationSignal cancellationSignal,
|
|
Consumer<List<AppTarget>> callback) {
|
|
|
|
Log.d(TAG, "onSortAppTargets");
|
|
if (!activeLauncherSessions.contains(sessionId)) {
|
|
callback.accept(emptyList());
|
|
} else {
|
|
// No-op
|
|
callback.accept(targets);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void onRequestPredictionUpdate(AppPredictionSessionId sessionId) {
|
|
Log.d(TAG, "onRequestPredictionUpdate");
|
|
|
|
if (!activeLauncherSessions.contains(sessionId)) {
|
|
updatePredictions(sessionId, emptyList());
|
|
} else {
|
|
postPredictionUpdate(sessionId);
|
|
Log.d(TAG, "update predictions");
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void onDestroyPredictionSession(AppPredictionSessionId sessionId) {
|
|
Log.d(TAG, "onDestroyPredictionSession");
|
|
activeLauncherSessions.remove(sessionId);
|
|
}
|
|
|
|
@Override
|
|
public void onStartPredictionUpdates() {
|
|
Log.d(TAG, "onStartPredictionUpdates");
|
|
}
|
|
|
|
@Override
|
|
public void onStopPredictionUpdates() {
|
|
Log.d(TAG, "onStopPredictionUpdates");
|
|
}
|
|
|
|
public void setAppSuggestionsEnabled(boolean enabled) {
|
|
mAppSuggestionsEnabled = enabled;
|
|
postPredictionUpdateToAllClients();
|
|
}
|
|
|
|
private String getDefaultSystemHandlerActivityPackageName(Intent intent) {
|
|
return getDefaultSystemHandlerActivityPackageName(intent, 0);
|
|
}
|
|
|
|
private String getDefaultSystemHandlerActivityPackageName(Intent intent, int flags) {
|
|
ResolveInfo handler = getPackageManager().resolveActivity(intent, flags | PackageManager.MATCH_SYSTEM_ONLY);
|
|
if (handler == null) {
|
|
return null;
|
|
}
|
|
if ((handler.activityInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
|
|
return handler.activityInfo.packageName;
|
|
}
|
|
return null;
|
|
}
|
|
}
|