diff options
Diffstat (limited to 'packages/ExtServices/src')
7 files changed, 0 insertions, 1169 deletions
diff --git a/packages/ExtServices/src/android/ext/services/Version.java b/packages/ExtServices/src/android/ext/services/Version.java deleted file mode 100644 index 026cccd37334..000000000000 --- a/packages/ExtServices/src/android/ext/services/Version.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (C) 2016 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 android.ext.services; - -/** - * Class that provides the version of the library. - */ -public final class Version { - - private Version() { - /* do nothing - hide constructor */ - } - - /** - * Gets the version of the library. - * - * @return The version. - */ - public static int getVersionCode() { - return 1; - } -}
\ No newline at end of file diff --git a/packages/ExtServices/src/android/ext/services/autofill/AutofillFieldClassificationServiceImpl.java b/packages/ExtServices/src/android/ext/services/autofill/AutofillFieldClassificationServiceImpl.java deleted file mode 100644 index 9ba7e092f34b..000000000000 --- a/packages/ExtServices/src/android/ext/services/autofill/AutofillFieldClassificationServiceImpl.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (C) 2018 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 android.ext.services.autofill; - -import static android.ext.services.autofill.EditDistanceScorer.DEFAULT_ALGORITHM; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.os.Bundle; -import android.service.autofill.AutofillFieldClassificationService; -import android.util.Log; -import android.view.autofill.AutofillValue; - -import com.android.internal.util.ArrayUtils; - -import java.util.List; - -public class AutofillFieldClassificationServiceImpl extends AutofillFieldClassificationService { - - private static final String TAG = "AutofillFieldClassificationServiceImpl"; - - @Nullable - @Override - public float[][] onGetScores(@Nullable String algorithmName, - @Nullable Bundle algorithmArgs, @NonNull List<AutofillValue> actualValues, - @NonNull List<String> userDataValues) { - if (ArrayUtils.isEmpty(actualValues) || ArrayUtils.isEmpty(userDataValues)) { - Log.w(TAG, "getScores(): empty currentvalues (" + actualValues + ") or userValues (" - + userDataValues + ")"); - return null; - } - if (algorithmName != null && !algorithmName.equals(DEFAULT_ALGORITHM)) { - Log.w(TAG, "Ignoring invalid algorithm (" + algorithmName + ") and using " - + DEFAULT_ALGORITHM + " instead"); - } - - return EditDistanceScorer.getScores(actualValues, userDataValues); - } -} diff --git a/packages/ExtServices/src/android/ext/services/autofill/EditDistanceScorer.java b/packages/ExtServices/src/android/ext/services/autofill/EditDistanceScorer.java deleted file mode 100644 index 302b16022c26..000000000000 --- a/packages/ExtServices/src/android/ext/services/autofill/EditDistanceScorer.java +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Copyright (C) 2017 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 android.ext.services.autofill; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.util.Log; -import android.view.autofill.AutofillValue; - -import com.android.internal.annotations.VisibleForTesting; - -import java.util.List; - -final class EditDistanceScorer { - - private static final String TAG = "EditDistanceScorer"; - - // TODO(b/70291841): STOPSHIP - set to false before launching - private static final boolean DEBUG = true; - - static final String DEFAULT_ALGORITHM = "EDIT_DISTANCE"; - - /** - * Gets the field classification score of 2 values based on the edit distance between them. - * - * <p>The score is defined as: @(max_length - edit_distance) / max_length - */ - @VisibleForTesting - static float getScore(@Nullable AutofillValue actualValue, @Nullable String userDataValue) { - if (actualValue == null || !actualValue.isText() || userDataValue == null) return 0; - - final String actualValueText = actualValue.getTextValue().toString(); - final int actualValueLength = actualValueText.length(); - final int userDatalength = userDataValue.length(); - if (userDatalength == 0) { - return (actualValueLength == 0) ? 1 : 0; - } - - final int distance = editDistance(actualValueText.toLowerCase(), - userDataValue.toLowerCase()); - final int maxLength = Math.max(actualValueLength, userDatalength); - return ((float) maxLength - distance) / maxLength; - } - - /** - * Computes the edit distance (number of insertions, deletions or substitutions to edit one - * string into the other) between two strings. In particular, this will compute the Levenshtein - * distance. - * - * <p>See http://en.wikipedia.org/wiki/Levenshtein_distance for details. - * - * @param s the first string to compare - * @param t the second string to compare - * @return the edit distance between the two strings - */ - // Note: copied verbatim from com.android.tools.lint.detector.api.LintUtils.java - public static int editDistance(@NonNull String s, @NonNull String t) { - return editDistance(s, t, Integer.MAX_VALUE); - } - - /** - * Computes the edit distance (number of insertions, deletions or substitutions to edit one - * string into the other) between two strings. In particular, this will compute the Levenshtein - * distance. - * - * <p>See http://en.wikipedia.org/wiki/Levenshtein_distance for details. - * - * @param s the first string to compare - * @param t the second string to compare - * @param max the maximum edit distance that we care about; if for example the string length - * delta is greater than this we don't bother computing the exact edit distance since the - * caller has indicated they're not interested in the result - * @return the edit distance between the two strings, or some other value greater than that if - * the edit distance is at least as big as the {@code max} parameter - */ - // Note: copied verbatim from com.android.tools.lint.detector.api.LintUtils.java - private static int editDistance(@NonNull String s, @NonNull String t, int max) { - if (s.equals(t)) { - return 0; - } - - if (Math.abs(s.length() - t.length()) > max) { - // The string lengths differ more than the allowed edit distance; - // no point in even attempting to compute the edit distance (requires - // O(n*m) storage and O(n*m) speed, where n and m are the string lengths) - return Integer.MAX_VALUE; - } - - int m = s.length(); - int n = t.length(); - int[][] d = new int[m + 1][n + 1]; - for (int i = 0; i <= m; i++) { - d[i][0] = i; - } - for (int j = 0; j <= n; j++) { - d[0][j] = j; - } - for (int j = 1; j <= n; j++) { - for (int i = 1; i <= m; i++) { - if (s.charAt(i - 1) == t.charAt(j - 1)) { - d[i][j] = d[i - 1][j - 1]; - } else { - int deletion = d[i - 1][j] + 1; - int insertion = d[i][j - 1] + 1; - int substitution = d[i - 1][j - 1] + 1; - d[i][j] = Math.min(deletion, Math.min(insertion, substitution)); - } - } - } - - return d[m][n]; - } - /** - * Gets the scores in a batch. - */ - static float[][] getScores(@NonNull List<AutofillValue> actualValues, - @NonNull List<String> userDataValues) { - final int actualValuesSize = actualValues.size(); - final int userDataValuesSize = userDataValues.size(); - if (DEBUG) { - Log.d(TAG, "getScores() will return a " + actualValuesSize + "x" - + userDataValuesSize + " matrix for " + DEFAULT_ALGORITHM); - } - final float[][] scores = new float[actualValuesSize][userDataValuesSize]; - - for (int i = 0; i < actualValuesSize; i++) { - for (int j = 0; j < userDataValuesSize; j++) { - final float score = getScore(actualValues.get(i), userDataValues.get(j)); - scores[i][j] = score; - } - } - return scores; - } - -} diff --git a/packages/ExtServices/src/android/ext/services/notification/Assistant.java b/packages/ExtServices/src/android/ext/services/notification/Assistant.java deleted file mode 100644 index f8788226fc51..000000000000 --- a/packages/ExtServices/src/android/ext/services/notification/Assistant.java +++ /dev/null @@ -1,382 +0,0 @@ -/** - * Copyright (C) 2017 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 android.ext.services.notification; - -import static android.app.NotificationManager.IMPORTANCE_MIN; -import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_NEGATIVE; - -import android.app.INotificationManager; -import android.content.ContentResolver; -import android.content.Context; -import android.database.ContentObserver; -import android.ext.services.R; -import android.net.Uri; -import android.os.AsyncTask; -import android.os.Bundle; -import android.os.Environment; -import android.os.Handler; -import android.os.storage.StorageManager; -import android.provider.Settings; -import android.service.notification.Adjustment; -import android.service.notification.NotificationAssistantService; -import android.service.notification.NotificationStats; -import android.service.notification.StatusBarNotification; -import android.util.ArrayMap; -import android.util.AtomicFile; -import android.util.Log; -import android.util.Slog; -import android.util.Xml; - -import com.android.internal.util.FastXmlSerializer; -import com.android.internal.util.XmlUtils; - -import libcore.io.IoUtils; - -import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; -import org.xmlpull.v1.XmlSerializer; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.Map; - -/** - * Notification assistant that provides guidance on notification channel blocking - */ -public class Assistant extends NotificationAssistantService { - private static final String TAG = "ExtAssistant"; - private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); - - private static final String TAG_ASSISTANT = "assistant"; - private static final String TAG_IMPRESSION = "impression-set"; - private static final String ATT_KEY = "key"; - private static final int DB_VERSION = 1; - private static final String ATTR_VERSION = "version"; - - private static final ArrayList<Integer> PREJUDICAL_DISMISSALS = new ArrayList<>(); - static { - PREJUDICAL_DISMISSALS.add(REASON_CANCEL); - PREJUDICAL_DISMISSALS.add(REASON_LISTENER_CANCEL); - } - - private float mDismissToViewRatioLimit; - private int mStreakLimit; - - // key : impressions tracker - // TODO: prune deleted channels and apps - final ArrayMap<String, ChannelImpressions> mkeyToImpressions = new ArrayMap<>(); - // SBN key : channel id - ArrayMap<String, String> mLiveNotifications = new ArrayMap<>(); - - private Ranking mFakeRanking = null; - private AtomicFile mFile = null; - - public Assistant() { - } - - @Override - public void onCreate() { - super.onCreate(); - // Contexts are correctly hooked up by the creation step, which is required for the observer - // to be hooked up/initialized. - new SettingsObserver(mHandler); - } - - private void loadFile() { - if (DEBUG) Slog.d(TAG, "loadFile"); - AsyncTask.execute(() -> { - InputStream infile = null; - try { - infile = mFile.openRead(); - readXml(infile); - } catch (FileNotFoundException e) { - Log.d(TAG, "File doesn't exist or isn't readable yet"); - } catch (IOException e) { - Log.e(TAG, "Unable to read channel impressions", e); - } catch (NumberFormatException | XmlPullParserException e) { - Log.e(TAG, "Unable to parse channel impressions", e); - } finally { - IoUtils.closeQuietly(infile); - } - }); - } - - protected void readXml(InputStream stream) - throws XmlPullParserException, NumberFormatException, IOException { - final XmlPullParser parser = Xml.newPullParser(); - parser.setInput(stream, StandardCharsets.UTF_8.name()); - final int outerDepth = parser.getDepth(); - while (XmlUtils.nextElementWithin(parser, outerDepth)) { - if (!TAG_ASSISTANT.equals(parser.getName())) { - continue; - } - final int impressionOuterDepth = parser.getDepth(); - while (XmlUtils.nextElementWithin(parser, impressionOuterDepth)) { - if (!TAG_IMPRESSION.equals(parser.getName())) { - continue; - } - String key = parser.getAttributeValue(null, ATT_KEY); - ChannelImpressions ci = createChannelImpressionsWithThresholds(); - ci.populateFromXml(parser); - synchronized (mkeyToImpressions) { - ci.append(mkeyToImpressions.get(key)); - mkeyToImpressions.put(key, ci); - } - } - } - } - - private void saveFile() throws IOException { - AsyncTask.execute(() -> { - final FileOutputStream stream; - try { - stream = mFile.startWrite(); - } catch (IOException e) { - Slog.w(TAG, "Failed to save policy file", e); - return; - } - try { - final XmlSerializer out = new FastXmlSerializer(); - out.setOutput(stream, StandardCharsets.UTF_8.name()); - writeXml(out); - mFile.finishWrite(stream); - } catch (IOException e) { - Slog.w(TAG, "Failed to save impressions file, restoring backup", e); - mFile.failWrite(stream); - } - }); - } - - protected void writeXml(XmlSerializer out) throws IOException { - out.startDocument(null, true); - out.startTag(null, TAG_ASSISTANT); - out.attribute(null, ATTR_VERSION, Integer.toString(DB_VERSION)); - synchronized (mkeyToImpressions) { - for (Map.Entry<String, ChannelImpressions> entry - : mkeyToImpressions.entrySet()) { - // TODO: ensure channel still exists - out.startTag(null, TAG_IMPRESSION); - out.attribute(null, ATT_KEY, entry.getKey()); - entry.getValue().writeXml(out); - out.endTag(null, TAG_IMPRESSION); - } - } - out.endTag(null, TAG_ASSISTANT); - out.endDocument(); - } - - @Override - public Adjustment onNotificationEnqueued(StatusBarNotification sbn) { - if (DEBUG) Log.i(TAG, "ENQUEUED " + sbn.getKey()); - return null; - } - - @Override - public void onNotificationPosted(StatusBarNotification sbn, RankingMap rankingMap) { - if (DEBUG) Log.i(TAG, "POSTED " + sbn.getKey()); - try { - Ranking ranking = getRanking(sbn.getKey(), rankingMap); - if (ranking != null && ranking.getChannel() != null) { - String key = getKey( - sbn.getPackageName(), sbn.getUserId(), ranking.getChannel().getId()); - ChannelImpressions ci = mkeyToImpressions.getOrDefault(key, - createChannelImpressionsWithThresholds()); - if (ranking.getImportance() > IMPORTANCE_MIN && ci.shouldTriggerBlock()) { - adjustNotification(createNegativeAdjustment( - sbn.getPackageName(), sbn.getKey(), sbn.getUserId())); - } - mkeyToImpressions.put(key, ci); - mLiveNotifications.put(sbn.getKey(), ranking.getChannel().getId()); - } - } catch (Throwable e) { - Log.e(TAG, "Error occurred processing post", e); - } - } - - @Override - public void onNotificationRemoved(StatusBarNotification sbn, RankingMap rankingMap, - NotificationStats stats, int reason) { - try { - boolean updatedImpressions = false; - String channelId = mLiveNotifications.remove(sbn.getKey()); - String key = getKey(sbn.getPackageName(), sbn.getUserId(), channelId); - synchronized (mkeyToImpressions) { - ChannelImpressions ci = mkeyToImpressions.getOrDefault(key, - createChannelImpressionsWithThresholds()); - if (stats.hasSeen()) { - ci.incrementViews(); - updatedImpressions = true; - } - if (PREJUDICAL_DISMISSALS.contains(reason)) { - if ((!sbn.isAppGroup() || sbn.getNotification().isGroupChild()) - && !stats.hasInteracted() - && stats.getDismissalSurface() != NotificationStats.DISMISSAL_AOD - && stats.getDismissalSurface() != NotificationStats.DISMISSAL_PEEK - && stats.getDismissalSurface() != NotificationStats.DISMISSAL_OTHER) { - if (DEBUG) Log.i(TAG, "increment dismissals " + key); - ci.incrementDismissals(); - updatedImpressions = true; - } else { - if (DEBUG) Slog.i(TAG, "reset streak " + key); - if (ci.getStreak() > 0) { - updatedImpressions = true; - } - ci.resetStreak(); - } - } - mkeyToImpressions.put(key, ci); - } - if (updatedImpressions) { - saveFile(); - } - } catch (Throwable e) { - Slog.e(TAG, "Error occurred processing removal", e); - } - } - - @Override - public void onNotificationSnoozedUntilContext(StatusBarNotification sbn, - String snoozeCriterionId) { - } - - @Override - public void onListenerConnected() { - if (DEBUG) Log.i(TAG, "CONNECTED"); - try { - mFile = new AtomicFile(new File(new File( - Environment.getDataUserCePackageDirectory( - StorageManager.UUID_PRIVATE_INTERNAL, getUserId(), getPackageName()), - "assistant"), "blocking_helper_stats.xml")); - loadFile(); - for (StatusBarNotification sbn : getActiveNotifications()) { - onNotificationPosted(sbn); - } - } catch (Throwable e) { - Log.e(TAG, "Error occurred on connection", e); - } - } - - protected String getKey(String pkg, int userId, String channelId) { - return pkg + "|" + userId + "|" + channelId; - } - - private Ranking getRanking(String key, RankingMap rankingMap) { - if (mFakeRanking != null) { - return mFakeRanking; - } - Ranking ranking = new Ranking(); - rankingMap.getRanking(key, ranking); - return ranking; - } - - private Adjustment createNegativeAdjustment(String packageName, String key, int user) { - if (DEBUG) Log.d(TAG, "User probably doesn't want " + key); - Bundle signals = new Bundle(); - signals.putInt(Adjustment.KEY_USER_SENTIMENT, USER_SENTIMENT_NEGATIVE); - return new Adjustment(packageName, key, signals, - getContext().getString(R.string.prompt_block_reason), user); - } - - // for testing - - protected void setFile(AtomicFile file) { - mFile = file; - } - - protected void setFakeRanking(Ranking ranking) { - mFakeRanking = ranking; - } - - protected void setNoMan(INotificationManager noMan) { - mNoMan = noMan; - } - - protected void setContext(Context context) { - mSystemContext = context; - } - - protected ChannelImpressions getImpressions(String key) { - synchronized (mkeyToImpressions) { - return mkeyToImpressions.get(key); - } - } - - protected void insertImpressions(String key, ChannelImpressions ci) { - synchronized (mkeyToImpressions) { - mkeyToImpressions.put(key, ci); - } - } - - private ChannelImpressions createChannelImpressionsWithThresholds() { - ChannelImpressions impressions = new ChannelImpressions(); - impressions.updateThresholds(mDismissToViewRatioLimit, mStreakLimit); - return impressions; - } - - /** - * Observer for updates on blocking helper threshold values. - */ - private final class SettingsObserver extends ContentObserver { - private final Uri STREAK_LIMIT_URI = - Settings.Global.getUriFor(Settings.Global.BLOCKING_HELPER_STREAK_LIMIT); - private final Uri DISMISS_TO_VIEW_RATIO_LIMIT_URI = - Settings.Global.getUriFor( - Settings.Global.BLOCKING_HELPER_DISMISS_TO_VIEW_RATIO_LIMIT); - - public SettingsObserver(Handler handler) { - super(handler); - ContentResolver resolver = getApplicationContext().getContentResolver(); - resolver.registerContentObserver( - DISMISS_TO_VIEW_RATIO_LIMIT_URI, false, this, getUserId()); - resolver.registerContentObserver(STREAK_LIMIT_URI, false, this, getUserId()); - - // Update all uris on creation. - update(null); - } - - @Override - public void onChange(boolean selfChange, Uri uri) { - update(uri); - } - - private void update(Uri uri) { - ContentResolver resolver = getApplicationContext().getContentResolver(); - if (uri == null || DISMISS_TO_VIEW_RATIO_LIMIT_URI.equals(uri)) { - mDismissToViewRatioLimit = Settings.Global.getFloat( - resolver, Settings.Global.BLOCKING_HELPER_DISMISS_TO_VIEW_RATIO_LIMIT, - ChannelImpressions.DEFAULT_DISMISS_TO_VIEW_RATIO_LIMIT); - } - if (uri == null || STREAK_LIMIT_URI.equals(uri)) { - mStreakLimit = Settings.Global.getInt( - resolver, Settings.Global.BLOCKING_HELPER_STREAK_LIMIT, - ChannelImpressions.DEFAULT_STREAK_LIMIT); - } - - // Update all existing channel impression objects with any new limits/thresholds. - synchronized (mkeyToImpressions) { - for (ChannelImpressions channelImpressions: mkeyToImpressions.values()) { - channelImpressions.updateThresholds(mDismissToViewRatioLimit, mStreakLimit); - } - } - } - } -}
\ No newline at end of file diff --git a/packages/ExtServices/src/android/ext/services/notification/ChannelImpressions.java b/packages/ExtServices/src/android/ext/services/notification/ChannelImpressions.java deleted file mode 100644 index 29ee920d4dde..000000000000 --- a/packages/ExtServices/src/android/ext/services/notification/ChannelImpressions.java +++ /dev/null @@ -1,209 +0,0 @@ -/** - * Copyright (C) 2017 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 android.ext.services.notification; - -import android.os.Parcel; -import android.os.Parcelable; -import android.text.TextUtils; -import android.util.Log; - -import com.android.internal.annotations.VisibleForTesting; - -import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlSerializer; - -import java.io.IOException; - -public final class ChannelImpressions implements Parcelable { - private static final String TAG = "ExtAssistant.CI"; - private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); - - static final float DEFAULT_DISMISS_TO_VIEW_RATIO_LIMIT = .8f; - static final int DEFAULT_STREAK_LIMIT = 2; - static final String ATT_DISMISSALS = "dismisses"; - static final String ATT_VIEWS = "views"; - static final String ATT_STREAK = "streak"; - - private int mDismissals = 0; - private int mViews = 0; - private int mStreak = 0; - - private float mDismissToViewRatioLimit; - private int mStreakLimit; - - public ChannelImpressions() { - mDismissToViewRatioLimit = DEFAULT_DISMISS_TO_VIEW_RATIO_LIMIT; - mStreakLimit = DEFAULT_STREAK_LIMIT; - } - - protected ChannelImpressions(Parcel in) { - mDismissals = in.readInt(); - mViews = in.readInt(); - mStreak = in.readInt(); - mDismissToViewRatioLimit = in.readFloat(); - mStreakLimit = in.readInt(); - } - - public int getStreak() { - return mStreak; - } - - public int getDismissals() { - return mDismissals; - } - - public int getViews() { - return mViews; - } - - public void incrementDismissals() { - mDismissals++; - mStreak++; - } - - void updateThresholds(float dismissToViewRatioLimit, int streakLimit) { - mDismissToViewRatioLimit = dismissToViewRatioLimit; - mStreakLimit = streakLimit; - } - - @VisibleForTesting - float getDismissToViewRatioLimit() { - return mDismissToViewRatioLimit; - } - - @VisibleForTesting - int getStreakLimit() { - return mStreakLimit; - } - - public void append(ChannelImpressions additionalImpressions) { - if (additionalImpressions != null) { - mViews += additionalImpressions.getViews(); - mStreak += additionalImpressions.getStreak(); - mDismissals += additionalImpressions.getDismissals(); - } - } - - public void incrementViews() { - mViews++; - } - - public void resetStreak() { - mStreak = 0; - } - - public boolean shouldTriggerBlock() { - if (getViews() == 0) { - return false; - } - if (DEBUG) { - Log.d(TAG, "should trigger? " + getDismissals() + " " + getViews() + " " + getStreak()); - } - return ((float) getDismissals() / getViews()) > mDismissToViewRatioLimit - && getStreak() > mStreakLimit; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - dest.writeInt(mDismissals); - dest.writeInt(mViews); - dest.writeInt(mStreak); - dest.writeFloat(mDismissToViewRatioLimit); - dest.writeInt(mStreakLimit); - } - - @Override - public int describeContents() { - return 0; - } - - public static final Creator<ChannelImpressions> CREATOR = new Creator<ChannelImpressions>() { - @Override - public ChannelImpressions createFromParcel(Parcel in) { - return new ChannelImpressions(in); - } - - @Override - public ChannelImpressions[] newArray(int size) { - return new ChannelImpressions[size]; - } - }; - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - ChannelImpressions that = (ChannelImpressions) o; - - if (mDismissals != that.mDismissals) return false; - if (mViews != that.mViews) return false; - return mStreak == that.mStreak; - } - - @Override - public int hashCode() { - int result = mDismissals; - result = 31 * result + mViews; - result = 31 * result + mStreak; - return result; - } - - @Override - public String toString() { - final StringBuilder sb = new StringBuilder("ChannelImpressions{"); - sb.append("mDismissals=").append(mDismissals); - sb.append(", mViews=").append(mViews); - sb.append(", mStreak=").append(mStreak); - sb.append(", thresholds=(").append(mDismissToViewRatioLimit); - sb.append(",").append(mStreakLimit); - sb.append(")}"); - return sb.toString(); - } - - protected void populateFromXml(XmlPullParser parser) { - mDismissals = safeInt(parser, ATT_DISMISSALS, 0); - mStreak = safeInt(parser, ATT_STREAK, 0); - mViews = safeInt(parser, ATT_VIEWS, 0); - } - - protected void writeXml(XmlSerializer out) throws IOException { - if (mDismissals != 0) { - out.attribute(null, ATT_DISMISSALS, String.valueOf(mDismissals)); - } - if (mStreak != 0) { - out.attribute(null, ATT_STREAK, String.valueOf(mStreak)); - } - if (mViews != 0) { - out.attribute(null, ATT_VIEWS, String.valueOf(mViews)); - } - } - - private static int safeInt(XmlPullParser parser, String att, int defValue) { - final String val = parser.getAttributeValue(null, att); - return tryParseInt(val, defValue); - } - - private static int tryParseInt(String value, int defValue) { - if (TextUtils.isEmpty(value)) return defValue; - try { - return Integer.parseInt(value); - } catch (NumberFormatException e) { - return defValue; - } - } -} diff --git a/packages/ExtServices/src/android/ext/services/resolver/LRResolverRankerService.java b/packages/ExtServices/src/android/ext/services/resolver/LRResolverRankerService.java deleted file mode 100644 index 9d7a5689dcd1..000000000000 --- a/packages/ExtServices/src/android/ext/services/resolver/LRResolverRankerService.java +++ /dev/null @@ -1,199 +0,0 @@ -/* - * Copyright (C) 2017 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 android.ext.services.resolver; - -import android.content.Context; -import android.content.Intent; -import android.content.SharedPreferences; -import android.os.Environment; -import android.os.IBinder; -import android.os.storage.StorageManager; -import android.service.resolver.ResolverRankerService; -import android.service.resolver.ResolverTarget; -import android.util.ArrayMap; -import android.util.Log; - -import java.io.File; -import java.util.Collection; -import java.util.List; -import java.util.Map; - -/** - * A Logistic Regression based {@link android.service.resolver.ResolverRankerService}, to be used - * in {@link ResolverComparator}. - */ -public final class LRResolverRankerService extends ResolverRankerService { - private static final String TAG = "LRResolverRankerService"; - - private static final boolean DEBUG = false; - - private static final String PARAM_SHARED_PREF_NAME = "resolver_ranker_params"; - private static final String BIAS_PREF_KEY = "bias"; - private static final String VERSION_PREF_KEY = "version"; - - private static final String LAUNCH_SCORE = "launch"; - private static final String TIME_SPENT_SCORE = "timeSpent"; - private static final String RECENCY_SCORE = "recency"; - private static final String CHOOSER_SCORE = "chooser"; - - // parameters for a pre-trained model, to initialize the app ranker. When updating the - // pre-trained model, please update these params, as well as initModel(). - private static final int CURRENT_VERSION = 1; - private static final float LEARNING_RATE = 0.0001f; - private static final float REGULARIZER_PARAM = 0.0001f; - - private SharedPreferences mParamSharedPref; - private ArrayMap<String, Float> mFeatureWeights; - private float mBias; - - @Override - public IBinder onBind(Intent intent) { - initModel(); - return super.onBind(intent); - } - - @Override - public void onPredictSharingProbabilities(List<ResolverTarget> targets) { - final int size = targets.size(); - for (int i = 0; i < size; ++i) { - ResolverTarget target = targets.get(i); - ArrayMap<String, Float> features = getFeatures(target); - target.setSelectProbability(predict(features)); - } - } - - @Override - public void onTrainRankingModel(List<ResolverTarget> targets, int selectedPosition) { - final int size = targets.size(); - if (selectedPosition < 0 || selectedPosition >= size) { - if (DEBUG) { - Log.d(TAG, "Invalid Position of Selected App " + selectedPosition); - } - return; - } - final ArrayMap<String, Float> positive = getFeatures(targets.get(selectedPosition)); - final float positiveProbability = targets.get(selectedPosition).getSelectProbability(); - final int targetSize = targets.size(); - for (int i = 0; i < targetSize; ++i) { - if (i == selectedPosition) { - continue; - } - final ArrayMap<String, Float> negative = getFeatures(targets.get(i)); - final float negativeProbability = targets.get(i).getSelectProbability(); - if (negativeProbability > positiveProbability) { - update(negative, negativeProbability, false); - update(positive, positiveProbability, true); - } - } - commitUpdate(); - } - - private void initModel() { - mParamSharedPref = getParamSharedPref(); - mFeatureWeights = new ArrayMap<>(4); - if (mParamSharedPref == null || - mParamSharedPref.getInt(VERSION_PREF_KEY, 0) < CURRENT_VERSION) { - // Initializing the app ranker to a pre-trained model. When updating the pre-trained - // model, please increment CURRENT_VERSION, and update LEARNING_RATE and - // REGULARIZER_PARAM. - mBias = -1.6568f; - mFeatureWeights.put(LAUNCH_SCORE, 2.5543f); - mFeatureWeights.put(TIME_SPENT_SCORE, 2.8412f); - mFeatureWeights.put(RECENCY_SCORE, 0.269f); - mFeatureWeights.put(CHOOSER_SCORE, 4.2222f); - } else { - mBias = mParamSharedPref.getFloat(BIAS_PREF_KEY, 0.0f); - mFeatureWeights.put(LAUNCH_SCORE, mParamSharedPref.getFloat(LAUNCH_SCORE, 0.0f)); - mFeatureWeights.put( - TIME_SPENT_SCORE, mParamSharedPref.getFloat(TIME_SPENT_SCORE, 0.0f)); - mFeatureWeights.put(RECENCY_SCORE, mParamSharedPref.getFloat(RECENCY_SCORE, 0.0f)); - mFeatureWeights.put(CHOOSER_SCORE, mParamSharedPref.getFloat(CHOOSER_SCORE, 0.0f)); - } - } - - private ArrayMap<String, Float> getFeatures(ResolverTarget target) { - ArrayMap<String, Float> features = new ArrayMap<>(4); - features.put(RECENCY_SCORE, target.getRecencyScore()); - features.put(TIME_SPENT_SCORE, target.getTimeSpentScore()); - features.put(LAUNCH_SCORE, target.getLaunchScore()); - features.put(CHOOSER_SCORE, target.getChooserScore()); - return features; - } - - private float predict(ArrayMap<String, Float> target) { - if (target == null) { - return 0.0f; - } - final int featureSize = target.size(); - float sum = 0.0f; - for (int i = 0; i < featureSize; i++) { - String featureName = target.keyAt(i); - float weight = mFeatureWeights.getOrDefault(featureName, 0.0f); - sum += weight * target.valueAt(i); - } - return (float) (1.0 / (1.0 + Math.exp(-mBias - sum))); - } - - private void update(ArrayMap<String, Float> target, float predict, boolean isSelected) { - if (target == null) { - return; - } - final int featureSize = target.size(); - float error = isSelected ? 1.0f - predict : -predict; - for (int i = 0; i < featureSize; i++) { - String featureName = target.keyAt(i); - float currentWeight = mFeatureWeights.getOrDefault(featureName, 0.0f); - mBias += LEARNING_RATE * error; - currentWeight = currentWeight - LEARNING_RATE * REGULARIZER_PARAM * currentWeight + - LEARNING_RATE * error * target.valueAt(i); - mFeatureWeights.put(featureName, currentWeight); - } - if (DEBUG) { - Log.d(TAG, "Weights: " + mFeatureWeights + " Bias: " + mBias); - } - } - - private void commitUpdate() { - try { - SharedPreferences.Editor editor = mParamSharedPref.edit(); - editor.putFloat(BIAS_PREF_KEY, mBias); - final int size = mFeatureWeights.size(); - for (int i = 0; i < size; i++) { - editor.putFloat(mFeatureWeights.keyAt(i), mFeatureWeights.valueAt(i)); - } - editor.putInt(VERSION_PREF_KEY, CURRENT_VERSION); - editor.apply(); - } catch (Exception e) { - Log.e(TAG, "Failed to commit update" + e); - } - } - - private SharedPreferences getParamSharedPref() { - // The package info in the context isn't initialized in the way it is for normal apps, - // so the standard, name-based context.getSharedPreferences doesn't work. Instead, we - // build the path manually below using the same policy that appears in ContextImpl. - if (DEBUG) { - Log.d(TAG, "Context Package Name: " + getPackageName()); - } - final File prefsFile = new File(new File( - Environment.getDataUserCePackageDirectory( - StorageManager.UUID_PRIVATE_INTERNAL, getUserId(), getPackageName()), - "shared_prefs"), - PARAM_SHARED_PREF_NAME + ".xml"); - return getSharedPreferences(prefsFile, Context.MODE_PRIVATE); - } -}
\ No newline at end of file diff --git a/packages/ExtServices/src/android/ext/services/storage/CacheQuotaServiceImpl.java b/packages/ExtServices/src/android/ext/services/storage/CacheQuotaServiceImpl.java deleted file mode 100644 index 862f50b2b627..000000000000 --- a/packages/ExtServices/src/android/ext/services/storage/CacheQuotaServiceImpl.java +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Copyright (C) 2017 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 android.ext.services.storage; - -import android.app.usage.CacheQuotaHint; -import android.app.usage.CacheQuotaService; -import android.os.Environment; -import android.os.storage.StorageManager; -import android.os.storage.VolumeInfo; -import android.util.ArrayMap; - -import java.util.ArrayList; -import java.util.Comparator; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - -/** - * CacheQuotaServiceImpl implements the CacheQuotaService with a strategy for populating the quota - * of {@link CacheQuotaHint}. - */ -public class CacheQuotaServiceImpl extends CacheQuotaService { - private static final double CACHE_RESERVE_RATIO = 0.15; - - @Override - public List<CacheQuotaHint> onComputeCacheQuotaHints(List<CacheQuotaHint> requests) { - ArrayMap<String, List<CacheQuotaHint>> byUuid = new ArrayMap<>(); - final int requestCount = requests.size(); - for (int i = 0; i < requestCount; i++) { - CacheQuotaHint request = requests.get(i); - String uuid = request.getVolumeUuid(); - List<CacheQuotaHint> listForUuid = byUuid.get(uuid); - if (listForUuid == null) { - listForUuid = new ArrayList<>(); - byUuid.put(uuid, listForUuid); - } - listForUuid.add(request); - } - - List<CacheQuotaHint> processed = new ArrayList<>(); - byUuid.entrySet().forEach( - requestListEntry -> { - // Collapse all usage stats to the same uid. - Map<Integer, List<CacheQuotaHint>> byUid = requestListEntry.getValue() - .stream() - .collect(Collectors.groupingBy(CacheQuotaHint::getUid)); - byUid.values().forEach(uidGroupedList -> { - int size = uidGroupedList.size(); - if (size < 2) { - return; - } - CacheQuotaHint first = uidGroupedList.get(0); - for (int i = 1; i < size; i++) { - /* Note: We can't use the UsageStats built-in addition function because - UIDs may span multiple packages and usage stats adding has - matching package names as a precondition. */ - first.getUsageStats().mTotalTimeInForeground += - uidGroupedList.get(i).getUsageStats().mTotalTimeInForeground; - } - }); - - // Because the foreground stats have been added to the first element, we need - // a list of only the first values (which contain the merged foreground time). - List<CacheQuotaHint> flattenedRequests = - byUid.values() - .stream() - .map(entryList -> entryList.get(0)) - .filter(entry -> entry.getUsageStats().mTotalTimeInForeground != 0) - .sorted(sCacheQuotaRequestComparator) - .collect(Collectors.toList()); - - // Because the elements are sorted, we can use the index to also be the sorted - // index for cache quota calculation. - double sum = getSumOfFairShares(flattenedRequests.size()); - String uuid = requestListEntry.getKey(); - long reservedSize = getReservedCacheSize(uuid); - for (int count = 0; count < flattenedRequests.size(); count++) { - double share = getFairShareForPosition(count) / sum; - CacheQuotaHint entry = flattenedRequests.get(count); - CacheQuotaHint.Builder builder = new CacheQuotaHint.Builder(entry); - builder.setQuota(Math.round(share * reservedSize)); - processed.add(builder.build()); - } - } - ); - - return processed.stream() - .filter(request -> request.getQuota() > 0).collect(Collectors.toList()); - } - - private double getFairShareForPosition(int position) { - double value = 1.0 / Math.log(position + 3) - 0.285; - return (value > 0.01) ? value : 0.01; - } - - private double getSumOfFairShares(int size) { - double sum = 0; - for (int i = 0; i < size; i++) { - sum += getFairShareForPosition(i); - } - return sum; - } - - private long getReservedCacheSize(String uuid) { - // TODO: Revisit the cache size after running more storage tests. - // TODO: Figure out how to ensure ExtServices has the permissions to call - // StorageStatsManager, because this is ignoring the cache... - StorageManager storageManager = getSystemService(StorageManager.class); - long freeBytes = 0; - if (uuid == StorageManager.UUID_PRIVATE_INTERNAL) { // regular equals because of null - freeBytes = Environment.getDataDirectory().getUsableSpace(); - } else { - final VolumeInfo vol = storageManager.findVolumeByUuid(uuid); - freeBytes = vol.getPath().getUsableSpace(); - } - return Math.round(freeBytes * CACHE_RESERVE_RATIO); - } - - // Compares based upon foreground time. - private static Comparator<CacheQuotaHint> sCacheQuotaRequestComparator = - new Comparator<CacheQuotaHint>() { - @Override - public int compare(CacheQuotaHint o, CacheQuotaHint t1) { - long x = t1.getUsageStats().getTotalTimeInForeground(); - long y = o.getUsageStats().getTotalTimeInForeground(); - return (x < y) ? -1 : ((x == y) ? 0 : 1); - } - }; -} |