Merge "Renaming setAsyncExecutor to setExecutor" into oc-dev
diff --git a/api/current.txt b/api/current.txt
index 3dc875b..3af3c85 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -1710,6 +1710,7 @@
field public static final int ic_notification_clear_all = 17301594; // 0x108005a
field public static final int ic_notification_overlay = 17301595; // 0x108005b
field public static final int ic_partial_secure = 17301596; // 0x108005c
+ field public static final int ic_picture_in_picture = 17301685; // 0x10800b5
field public static final int ic_popup_disk_full = 17301597; // 0x108005d
field public static final int ic_popup_reminder = 17301598; // 0x108005e
field public static final int ic_popup_sync = 17301599; // 0x108005f
@@ -3615,7 +3616,6 @@
method public android.net.Uri getReferrer();
method public int getRequestedOrientation();
method public final android.view.SearchEvent getSearchEvent();
- method public long getStartInitiatedTime();
method public int getTaskId();
method public final java.lang.CharSequence getTitle();
method public final int getTitleColor();
@@ -3723,7 +3723,7 @@
method public void onTrimMemory(int);
method public void onUserInteraction();
method protected void onUserLeaveHint();
- method public void onVisibleBehindCanceled();
+ method public deprecated void onVisibleBehindCanceled();
method public void onWindowAttributesChanged(android.view.WindowManager.LayoutParams);
method public void onWindowFocusChanged(boolean);
method public android.view.ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback);
@@ -3740,7 +3740,7 @@
method public android.view.DragAndDropPermissions requestDragAndDropPermissions(android.view.DragEvent);
method public final void requestPermissions(java.lang.String[], int);
method public final void requestShowKeyboardShortcuts();
- method public boolean requestVisibleBehind(boolean);
+ method public deprecated boolean requestVisibleBehind(boolean);
method public final boolean requestWindowFeature(int);
method public final void runOnUiThread(java.lang.Runnable);
method public void setActionBar(android.widget.Toolbar);
@@ -4577,6 +4577,7 @@
method public final android.app.FragmentManager getFragmentManager();
method public final java.lang.Object getHost();
method public final int getId();
+ method public final android.view.LayoutInflater getLayoutInflater();
method public android.app.LoaderManager getLoaderManager();
method public final android.app.Fragment getParentFragment();
method public android.transition.Transition getReenterTransition();
@@ -6626,7 +6627,7 @@
method public float getAlpha();
method public java.lang.String[] getAutofillHints();
method public android.view.autofill.AutofillId getAutofillId();
- method public java.lang.String[] getAutofillOptions();
+ method public java.lang.CharSequence[] getAutofillOptions();
method public int getAutofillType();
method public android.view.autofill.AutofillValue getAutofillValue();
method public android.app.assist.AssistStructure.ViewNode getChildAt(int);
@@ -7063,6 +7064,7 @@
method public static void deleteAllHosts();
method public void deleteAppWidgetId(int);
method public void deleteHost();
+ method public int[] getAppWidgetIds();
method protected android.appwidget.AppWidgetHostView onCreateView(android.content.Context, int, android.appwidget.AppWidgetProviderInfo);
method protected void onProviderChanged(int, android.appwidget.AppWidgetProviderInfo);
method protected void onProvidersChanged();
@@ -8874,9 +8876,9 @@
method public abstract deprecated android.graphics.drawable.Drawable peekWallpaper();
method public void registerComponentCallbacks(android.content.ComponentCallbacks);
method public abstract android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter);
- method public abstract android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter, boolean);
+ method public abstract android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter, int);
method public abstract android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter, java.lang.String, android.os.Handler);
- method public abstract android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter, java.lang.String, android.os.Handler, boolean);
+ method public abstract android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter, java.lang.String, android.os.Handler, int);
method public abstract deprecated void removeStickyBroadcast(android.content.Intent);
method public abstract deprecated void removeStickyBroadcastAsUser(android.content.Intent, android.os.UserHandle);
method public abstract void revokeUriPermission(android.net.Uri, int);
@@ -8967,6 +8969,7 @@
field public static final java.lang.String NSD_SERVICE = "servicediscovery";
field public static final java.lang.String POWER_SERVICE = "power";
field public static final java.lang.String PRINT_SERVICE = "print";
+ field public static final int RECEIVER_VISIBLE_TO_INSTANT_APPS = 1; // 0x1
field public static final java.lang.String RESTRICTIONS_SERVICE = "restrictions";
field public static final java.lang.String SEARCH_SERVICE = "search";
field public static final java.lang.String SENSOR_SERVICE = "sensor";
@@ -9066,9 +9069,9 @@
method public android.database.sqlite.SQLiteDatabase openOrCreateDatabase(java.lang.String, int, android.database.sqlite.SQLiteDatabase.CursorFactory, android.database.DatabaseErrorHandler);
method public deprecated android.graphics.drawable.Drawable peekWallpaper();
method public android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter);
- method public android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter, boolean);
+ method public android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter, int);
method public android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter, java.lang.String, android.os.Handler);
- method public android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter, java.lang.String, android.os.Handler, boolean);
+ method public android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter, java.lang.String, android.os.Handler, int);
method public deprecated void removeStickyBroadcast(android.content.Intent);
method public deprecated void removeStickyBroadcastAsUser(android.content.Intent, android.os.UserHandle);
method public void revokeUriPermission(android.net.Uri, int);
@@ -9381,7 +9384,6 @@
field public static final java.lang.String ACTION_PACKAGE_ADDED = "android.intent.action.PACKAGE_ADDED";
field public static final java.lang.String ACTION_PACKAGE_CHANGED = "android.intent.action.PACKAGE_CHANGED";
field public static final java.lang.String ACTION_PACKAGE_DATA_CLEARED = "android.intent.action.PACKAGE_DATA_CLEARED";
- field public static final java.lang.String ACTION_PACKAGE_FIRST_ADDED = "android.intent.action.PACKAGE_FIRST_ADDED";
field public static final java.lang.String ACTION_PACKAGE_FIRST_LAUNCH = "android.intent.action.PACKAGE_FIRST_LAUNCH";
field public static final java.lang.String ACTION_PACKAGE_FULLY_REMOVED = "android.intent.action.PACKAGE_FULLY_REMOVED";
field public static final deprecated java.lang.String ACTION_PACKAGE_INSTALL = "android.intent.action.PACKAGE_INSTALL";
@@ -9891,7 +9893,7 @@
}
public abstract interface ServiceConnection {
- method public default void onBindingDead(android.content.ComponentName);
+ method public default void onBindingDied(android.content.ComponentName);
method public abstract void onServiceConnected(android.content.ComponentName, android.os.IBinder);
method public abstract void onServiceDisconnected(android.content.ComponentName);
}
@@ -10569,6 +10571,7 @@
method public abstract int checkPermission(java.lang.String, java.lang.String);
method public abstract int checkSignatures(java.lang.String, java.lang.String);
method public abstract int checkSignatures(int, int);
+ method public abstract void clearInstantAppCookie();
method public abstract void clearPackagePreferredActivities(java.lang.String);
method public abstract java.lang.String[] currentToCanonicalPackageNames(java.lang.String[]);
method public abstract void extendVerificationTimeout(int, int, long);
@@ -10597,7 +10600,7 @@
method public abstract java.util.List<android.content.pm.PackageInfo> getInstalledPackages(int);
method public abstract java.lang.String getInstallerPackageName(java.lang.String);
method public abstract byte[] getInstantAppCookie();
- method public abstract int getInstantAppCookieMaxSize();
+ method public abstract int getInstantAppCookieMaxBytes();
method public abstract android.content.pm.InstrumentationInfo getInstrumentationInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
method public abstract android.content.Intent getLaunchIntentForPackage(java.lang.String);
method public abstract android.content.Intent getLeanbackLaunchIntentForPackage(java.lang.String);
@@ -10652,7 +10655,7 @@
method public abstract void setApplicationEnabledSetting(java.lang.String, int, int);
method public abstract void setComponentEnabledSetting(android.content.ComponentName, int, int);
method public abstract void setInstallerPackageName(java.lang.String, java.lang.String);
- method public abstract boolean setInstantAppCookie(byte[]);
+ method public abstract void updateInstantAppCookie(byte[]);
method public abstract void verifyPendingInstall(int, int);
field public static final int COMPONENT_ENABLED_STATE_DEFAULT = 0; // 0x0
field public static final int COMPONENT_ENABLED_STATE_DISABLED = 2; // 0x2
@@ -14816,7 +14819,7 @@
field public static final java.lang.String STRING_TYPE_HEART_RATE = "android.sensor.heart_rate";
field public static final java.lang.String STRING_TYPE_LIGHT = "android.sensor.light";
field public static final java.lang.String STRING_TYPE_LINEAR_ACCELERATION = "android.sensor.linear_acceleration";
- field public static final java.lang.String STRING_TYPE_LOW_LATENCY_OFFBODY_DETECT = "android.sensor.low_latency_offbody";
+ field public static final java.lang.String STRING_TYPE_LOW_LATENCY_OFFBODY_DETECT = "android.sensor.low_latency_offbody_detect";
field public static final java.lang.String STRING_TYPE_MAGNETIC_FIELD = "android.sensor.magnetic_field";
field public static final java.lang.String STRING_TYPE_MAGNETIC_FIELD_UNCALIBRATED = "android.sensor.magnetic_field_uncalibrated";
field public static final java.lang.String STRING_TYPE_MOTION_DETECT = "android.sensor.motion_detect";
@@ -20925,7 +20928,6 @@
method public int getContentType();
method public int getFlags();
method public int getUsage();
- method public static deprecated int getVolumeControlStream(android.media.AudioAttributes);
method public int getVolumeControlStream();
method public void writeToParcel(android.os.Parcel, int);
field public static final int CONTENT_TYPE_MOVIE = 3; // 0x3
@@ -34498,7 +34500,6 @@
}
public static final class FontsContract.Columns implements android.provider.BaseColumns {
- ctor public FontsContract.Columns();
field public static final java.lang.String FILE_ID = "file_id";
field public static final java.lang.String ITALIC = "font_italic";
field public static final java.lang.String RESULT_CODE = "result_code";
@@ -34515,6 +34516,7 @@
method public android.provider.FontsContract.FontInfo[] getFonts();
method public int getStatusCode();
field public static final int STATUS_OK = 0; // 0x0
+ field public static final int STATUS_REJECTED = 3; // 0x3
field public static final int STATUS_UNEXPECTED_DATA_PROVIDED = 2; // 0x2
field public static final int STATUS_WRONG_CERTIFICATES = 1; // 0x1
}
@@ -35448,8 +35450,8 @@
}
public static final class Telephony.ServiceStateTable {
- method public static android.net.Uri getUriForSubId(int);
- method public static android.net.Uri getUriForSubIdAndField(int, java.lang.String);
+ method public static android.net.Uri getUriForSubscriptionId(int);
+ method public static android.net.Uri getUriForSubscriptionIdAndField(int, java.lang.String);
field public static final java.lang.String AUTHORITY = "service-state";
field public static final android.net.Uri CONTENT_URI;
field public static final java.lang.String IS_MANUAL_NETWORK_SELECTION = "is_manual_network_selection";
@@ -40880,9 +40882,9 @@
method public android.database.sqlite.SQLiteDatabase openOrCreateDatabase(java.lang.String, int, android.database.sqlite.SQLiteDatabase.CursorFactory, android.database.DatabaseErrorHandler);
method public android.graphics.drawable.Drawable peekWallpaper();
method public android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter);
- method public android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter, boolean);
+ method public android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter, int);
method public android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter, java.lang.String, android.os.Handler);
- method public android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter, java.lang.String, android.os.Handler, boolean);
+ method public android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter, java.lang.String, android.os.Handler, int);
method public void removeStickyBroadcast(android.content.Intent);
method public void removeStickyBroadcastAsUser(android.content.Intent, android.os.UserHandle);
method public void revokeUriPermission(android.net.Uri, int);
@@ -40977,6 +40979,7 @@
method public int checkPermission(java.lang.String, java.lang.String);
method public int checkSignatures(java.lang.String, java.lang.String);
method public int checkSignatures(int, int);
+ method public void clearInstantAppCookie();
method public void clearPackagePreferredActivities(java.lang.String);
method public java.lang.String[] currentToCanonicalPackageNames(java.lang.String[]);
method public void extendVerificationTimeout(int, int, long);
@@ -41006,7 +41009,7 @@
method public java.util.List<android.content.pm.PackageInfo> getInstalledPackages(int);
method public java.lang.String getInstallerPackageName(java.lang.String);
method public byte[] getInstantAppCookie();
- method public int getInstantAppCookieMaxSize();
+ method public int getInstantAppCookieMaxBytes();
method public android.content.pm.InstrumentationInfo getInstrumentationInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
method public android.content.Intent getLaunchIntentForPackage(java.lang.String);
method public android.content.Intent getLeanbackLaunchIntentForPackage(java.lang.String);
@@ -41060,7 +41063,7 @@
method public void setApplicationEnabledSetting(java.lang.String, int, int);
method public void setComponentEnabledSetting(android.content.ComponentName, int, int);
method public void setInstallerPackageName(java.lang.String, java.lang.String);
- method public boolean setInstantAppCookie(byte[]);
+ method public void updateInstantAppCookie(byte[]);
method public void verifyPendingInstall(int, int);
}
@@ -46557,7 +46560,7 @@
method public abstract void setAlpha(float);
method public abstract void setAutofillHints(java.lang.String[]);
method public abstract void setAutofillId(android.view.ViewStructure, int);
- method public abstract void setAutofillOptions(java.lang.String[]);
+ method public abstract void setAutofillOptions(java.lang.CharSequence[]);
method public abstract void setAutofillType(int);
method public abstract void setAutofillValue(android.view.autofill.AutofillValue);
method public abstract void setCheckable(boolean);
@@ -47149,7 +47152,6 @@
}
public final class AccessibilityManager {
- method public boolean addAccessibilityServicesStateChangeListener(android.view.accessibility.AccessibilityManager.AccessibilityServicesStateChangeListener);
method public boolean addAccessibilityStateChangeListener(android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener);
method public boolean addTouchExplorationStateChangeListener(android.view.accessibility.AccessibilityManager.TouchExplorationStateChangeListener);
method public deprecated java.util.List<android.content.pm.ServiceInfo> getAccessibilityServiceList();
@@ -47158,16 +47160,11 @@
method public void interrupt();
method public boolean isEnabled();
method public boolean isTouchExplorationEnabled();
- method public boolean removeAccessibilityServicesStateChangeListener(android.view.accessibility.AccessibilityManager.AccessibilityServicesStateChangeListener);
method public boolean removeAccessibilityStateChangeListener(android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener);
method public boolean removeTouchExplorationStateChangeListener(android.view.accessibility.AccessibilityManager.TouchExplorationStateChangeListener);
method public void sendAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
}
- public static abstract interface AccessibilityManager.AccessibilityServicesStateChangeListener {
- method public abstract void onAccessibilityServicesStateChanged();
- }
-
public static abstract interface AccessibilityManager.AccessibilityStateChangeListener {
method public abstract void onAccessibilityStateChanged(boolean);
}
@@ -49378,6 +49375,7 @@
}
public abstract interface Adapter {
+ method public default java.lang.CharSequence[] getAutofillOptions();
method public abstract int getCount();
method public abstract java.lang.Object getItem(int);
method public abstract long getItemId(int);
@@ -49527,6 +49525,7 @@
method public void addAll(T...);
method public void clear();
method public static android.widget.ArrayAdapter<java.lang.CharSequence> createFromResource(android.content.Context, int, int);
+ method public java.lang.CharSequence[] getAutofillOptions();
method public android.content.Context getContext();
method public int getCount();
method public android.content.res.Resources.Theme getDropDownViewTheme();
@@ -51492,8 +51491,8 @@
method public void removeTextChangedListener(android.text.TextWatcher);
method public void setAllCaps(boolean);
method public final void setAutoLinkMask(int);
- method public void setAutoSizeTextTypeUniformWithConfiguration(int, int, int, int) throws java.lang.IllegalArgumentException;
- method public void setAutoSizeTextTypeUniformWithPresetSizes(int[], int) throws java.lang.IllegalArgumentException;
+ method public void setAutoSizeTextTypeUniformWithConfiguration(int, int, int, int);
+ method public void setAutoSizeTextTypeUniformWithPresetSizes(int[], int);
method public void setAutoSizeTextTypeWithDefaults(int);
method public void setBreakStrategy(int);
method public void setCompoundDrawablePadding(int);
diff --git a/api/removed.txt b/api/removed.txt
index b6c2a98..189536d 100644
--- a/api/removed.txt
+++ b/api/removed.txt
@@ -63,6 +63,10 @@
field public static final int REQUESTED_PERMISSION_REQUIRED = 1; // 0x1
}
+ public abstract class PackageManager {
+ method public abstract boolean setInstantAppCookie(byte[]);
+ }
+
public final class SharedLibraryInfo implements android.os.Parcelable {
method public boolean isBuiltin();
method public boolean isDynamic();
diff --git a/api/system-current.txt b/api/system-current.txt
index c58caf3..9a5ede3 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -1834,6 +1834,7 @@
field public static final int ic_notification_clear_all = 17301594; // 0x108005a
field public static final int ic_notification_overlay = 17301595; // 0x108005b
field public static final int ic_partial_secure = 17301596; // 0x108005c
+ field public static final int ic_picture_in_picture = 17301685; // 0x10800b5
field public static final int ic_popup_disk_full = 17301597; // 0x108005d
field public static final int ic_popup_reminder = 17301598; // 0x108005e
field public static final int ic_popup_sync = 17301599; // 0x108005f
@@ -3745,7 +3746,6 @@
method public android.net.Uri getReferrer();
method public int getRequestedOrientation();
method public final android.view.SearchEvent getSearchEvent();
- method public long getStartInitiatedTime();
method public int getTaskId();
method public final java.lang.CharSequence getTitle();
method public final int getTitleColor();
@@ -3756,7 +3756,7 @@
method public boolean hasWindowFocus();
method public void invalidateOptionsMenu();
method public boolean isActivityTransitionRunning();
- method public boolean isBackgroundVisibleBehind();
+ method public deprecated boolean isBackgroundVisibleBehind();
method public boolean isChangingConfigurations();
method public final boolean isChild();
method public boolean isDestroyed();
@@ -3780,7 +3780,7 @@
method public void onAttachFragment(android.app.Fragment);
method public void onAttachedToWindow();
method public void onBackPressed();
- method public void onBackgroundVisibleBehindChanged(boolean);
+ method public deprecated void onBackgroundVisibleBehindChanged(boolean);
method protected void onChildTitleChanged(android.app.Activity, java.lang.CharSequence);
method public void onConfigurationChanged(android.content.res.Configuration);
method public void onContentChanged();
@@ -3855,7 +3855,7 @@
method public void onTrimMemory(int);
method public void onUserInteraction();
method protected void onUserLeaveHint();
- method public void onVisibleBehindCanceled();
+ method public deprecated void onVisibleBehindCanceled();
method public void onWindowAttributesChanged(android.view.WindowManager.LayoutParams);
method public void onWindowFocusChanged(boolean);
method public android.view.ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback);
@@ -3872,7 +3872,7 @@
method public android.view.DragAndDropPermissions requestDragAndDropPermissions(android.view.DragEvent);
method public final void requestPermissions(java.lang.String[], int);
method public final void requestShowKeyboardShortcuts();
- method public boolean requestVisibleBehind(boolean);
+ method public deprecated boolean requestVisibleBehind(boolean);
method public final boolean requestWindowFeature(int);
method public final void runOnUiThread(java.lang.Runnable);
method public void setActionBar(android.widget.Toolbar);
@@ -4744,6 +4744,7 @@
method public final android.app.FragmentManager getFragmentManager();
method public final java.lang.Object getHost();
method public final int getId();
+ method public final android.view.LayoutInflater getLayoutInflater();
method public android.app.LoaderManager getLoaderManager();
method public final android.app.Fragment getParentFragment();
method public android.transition.Transition getReenterTransition();
@@ -6871,7 +6872,7 @@
method public float getAlpha();
method public java.lang.String[] getAutofillHints();
method public android.view.autofill.AutofillId getAutofillId();
- method public java.lang.String[] getAutofillOptions();
+ method public java.lang.CharSequence[] getAutofillOptions();
method public int getAutofillType();
method public android.view.autofill.AutofillValue getAutofillValue();
method public android.app.assist.AssistStructure.ViewNode getChildAt(int);
@@ -7529,6 +7530,7 @@
method public static void deleteAllHosts();
method public void deleteAppWidgetId(int);
method public void deleteHost();
+ method public int[] getAppWidgetIds();
method protected android.appwidget.AppWidgetHostView onCreateView(android.content.Context, int, android.appwidget.AppWidgetProviderInfo);
method protected void onProviderChanged(int, android.appwidget.AppWidgetProviderInfo);
method protected void onProvidersChanged();
@@ -9374,9 +9376,9 @@
method public abstract deprecated android.graphics.drawable.Drawable peekWallpaper();
method public void registerComponentCallbacks(android.content.ComponentCallbacks);
method public abstract android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter);
- method public abstract android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter, boolean);
+ method public abstract android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter, int);
method public abstract android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter, java.lang.String, android.os.Handler);
- method public abstract android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter, java.lang.String, android.os.Handler, boolean);
+ method public abstract android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter, java.lang.String, android.os.Handler, int);
method public abstract deprecated void removeStickyBroadcast(android.content.Intent);
method public abstract deprecated void removeStickyBroadcastAsUser(android.content.Intent, android.os.UserHandle);
method public abstract void revokeUriPermission(android.net.Uri, int);
@@ -9476,6 +9478,7 @@
field public static final java.lang.String PERSISTENT_DATA_BLOCK_SERVICE = "persistent_data_block";
field public static final java.lang.String POWER_SERVICE = "power";
field public static final java.lang.String PRINT_SERVICE = "print";
+ field public static final int RECEIVER_VISIBLE_TO_INSTANT_APPS = 1; // 0x1
field public static final java.lang.String RESTRICTIONS_SERVICE = "restrictions";
field public static final java.lang.String SEARCH_SERVICE = "search";
field public static final java.lang.String SENSOR_SERVICE = "sensor";
@@ -9581,9 +9584,9 @@
method public android.database.sqlite.SQLiteDatabase openOrCreateDatabase(java.lang.String, int, android.database.sqlite.SQLiteDatabase.CursorFactory, android.database.DatabaseErrorHandler);
method public deprecated android.graphics.drawable.Drawable peekWallpaper();
method public android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter);
- method public android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter, boolean);
+ method public android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter, int);
method public android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter, java.lang.String, android.os.Handler);
- method public android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter, java.lang.String, android.os.Handler, boolean);
+ method public android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter, java.lang.String, android.os.Handler, int);
method public deprecated void removeStickyBroadcast(android.content.Intent);
method public deprecated void removeStickyBroadcastAsUser(android.content.Intent, android.os.UserHandle);
method public void revokeUriPermission(android.net.Uri, int);
@@ -9913,7 +9916,6 @@
field public static final java.lang.String ACTION_PACKAGE_ADDED = "android.intent.action.PACKAGE_ADDED";
field public static final java.lang.String ACTION_PACKAGE_CHANGED = "android.intent.action.PACKAGE_CHANGED";
field public static final java.lang.String ACTION_PACKAGE_DATA_CLEARED = "android.intent.action.PACKAGE_DATA_CLEARED";
- field public static final java.lang.String ACTION_PACKAGE_FIRST_ADDED = "android.intent.action.PACKAGE_FIRST_ADDED";
field public static final java.lang.String ACTION_PACKAGE_FIRST_LAUNCH = "android.intent.action.PACKAGE_FIRST_LAUNCH";
field public static final java.lang.String ACTION_PACKAGE_FULLY_REMOVED = "android.intent.action.PACKAGE_FULLY_REMOVED";
field public static final deprecated java.lang.String ACTION_PACKAGE_INSTALL = "android.intent.action.PACKAGE_INSTALL";
@@ -10465,7 +10467,7 @@
}
public abstract interface ServiceConnection {
- method public default void onBindingDead(android.content.ComponentName);
+ method public default void onBindingDied(android.content.ComponentName);
method public abstract void onServiceConnected(android.content.ComponentName, android.os.IBinder);
method public abstract void onServiceDisconnected(android.content.ComponentName);
}
@@ -11242,6 +11244,7 @@
method public abstract int checkPermission(java.lang.String, java.lang.String);
method public abstract int checkSignatures(java.lang.String, java.lang.String);
method public abstract int checkSignatures(int, int);
+ method public abstract void clearInstantAppCookie();
method public abstract void clearPackagePreferredActivities(java.lang.String);
method public abstract java.lang.String[] currentToCanonicalPackageNames(java.lang.String[]);
method public abstract void extendVerificationTimeout(int, int, long);
@@ -11273,7 +11276,7 @@
method public abstract java.util.List<android.content.pm.PackageInfo> getInstalledPackagesAsUser(int, int);
method public abstract java.lang.String getInstallerPackageName(java.lang.String);
method public abstract byte[] getInstantAppCookie();
- method public abstract int getInstantAppCookieMaxSize();
+ method public abstract int getInstantAppCookieMaxBytes();
method public abstract android.graphics.drawable.Drawable getInstantAppIcon(java.lang.String);
method public abstract android.content.ComponentName getInstantAppInstallerComponent();
method public abstract android.content.ComponentName getInstantAppResolverSettingsComponent();
@@ -11340,8 +11343,8 @@
method public abstract void setComponentEnabledSetting(android.content.ComponentName, int, int);
method public abstract boolean setDefaultBrowserPackageNameAsUser(java.lang.String, int);
method public abstract void setInstallerPackageName(java.lang.String, java.lang.String);
- method public abstract boolean setInstantAppCookie(byte[]);
method public abstract void setUpdateAvailable(java.lang.String, boolean);
+ method public abstract void updateInstantAppCookie(byte[]);
method public abstract boolean updateIntentVerificationStatusAsUser(java.lang.String, int, int);
method public abstract void updatePermissionFlags(java.lang.String, java.lang.String, int, int, android.os.UserHandle);
method public abstract void verifyIntentFilter(int, int, java.util.List<java.lang.String>);
@@ -15593,7 +15596,7 @@
field public static final java.lang.String STRING_TYPE_HEART_RATE = "android.sensor.heart_rate";
field public static final java.lang.String STRING_TYPE_LIGHT = "android.sensor.light";
field public static final java.lang.String STRING_TYPE_LINEAR_ACCELERATION = "android.sensor.linear_acceleration";
- field public static final java.lang.String STRING_TYPE_LOW_LATENCY_OFFBODY_DETECT = "android.sensor.low_latency_offbody";
+ field public static final java.lang.String STRING_TYPE_LOW_LATENCY_OFFBODY_DETECT = "android.sensor.low_latency_offbody_detect";
field public static final java.lang.String STRING_TYPE_MAGNETIC_FIELD = "android.sensor.magnetic_field";
field public static final java.lang.String STRING_TYPE_MAGNETIC_FIELD_UNCALIBRATED = "android.sensor.magnetic_field_uncalibrated";
field public static final java.lang.String STRING_TYPE_MOTION_DETECT = "android.sensor.motion_detect";
@@ -22707,7 +22710,6 @@
method public int getContentType();
method public int getFlags();
method public int getUsage();
- method public static deprecated int getVolumeControlStream(android.media.AudioAttributes);
method public int getVolumeControlStream();
method public void writeToParcel(android.os.Parcel, int);
field public static final int CONTENT_TYPE_MOVIE = 3; // 0x3
@@ -29314,19 +29316,19 @@
}
public class WifiScanner {
- method public void configureWifiChange(int, int, int, int, int, android.net.wifi.WifiScanner.BssidInfo[]);
- method public void configureWifiChange(android.net.wifi.WifiScanner.WifiChangeSettings);
+ method public deprecated void configureWifiChange(int, int, int, int, int, android.net.wifi.WifiScanner.BssidInfo[]);
+ method public deprecated void configureWifiChange(android.net.wifi.WifiScanner.WifiChangeSettings);
method public boolean getScanResults();
method public void startBackgroundScan(android.net.wifi.WifiScanner.ScanSettings, android.net.wifi.WifiScanner.ScanListener);
method public void startBackgroundScan(android.net.wifi.WifiScanner.ScanSettings, android.net.wifi.WifiScanner.ScanListener, android.os.WorkSource);
method public void startScan(android.net.wifi.WifiScanner.ScanSettings, android.net.wifi.WifiScanner.ScanListener);
method public void startScan(android.net.wifi.WifiScanner.ScanSettings, android.net.wifi.WifiScanner.ScanListener, android.os.WorkSource);
- method public void startTrackingBssids(android.net.wifi.WifiScanner.BssidInfo[], int, android.net.wifi.WifiScanner.BssidListener);
- method public void startTrackingWifiChange(android.net.wifi.WifiScanner.WifiChangeListener);
+ method public deprecated void startTrackingBssids(android.net.wifi.WifiScanner.BssidInfo[], int, android.net.wifi.WifiScanner.BssidListener);
+ method public deprecated void startTrackingWifiChange(android.net.wifi.WifiScanner.WifiChangeListener);
method public void stopBackgroundScan(android.net.wifi.WifiScanner.ScanListener);
method public void stopScan(android.net.wifi.WifiScanner.ScanListener);
- method public void stopTrackingBssids(android.net.wifi.WifiScanner.BssidListener);
- method public void stopTrackingWifiChange(android.net.wifi.WifiScanner.WifiChangeListener);
+ method public deprecated void stopTrackingBssids(android.net.wifi.WifiScanner.BssidListener);
+ method public deprecated void stopTrackingWifiChange(android.net.wifi.WifiScanner.WifiChangeListener);
field public static final int MAX_SCAN_PERIOD_MS = 1024000; // 0xfa000
field public static final int MIN_SCAN_PERIOD_MS = 1000; // 0x3e8
field public static final int REASON_DUPLICATE_REQEUST = -5; // 0xfffffffb
@@ -29353,7 +29355,7 @@
method public abstract void onSuccess();
}
- public static class WifiScanner.BssidInfo {
+ public static deprecated class WifiScanner.BssidInfo {
ctor public WifiScanner.BssidInfo();
field public java.lang.String bssid;
field public int frequencyHint;
@@ -29361,7 +29363,7 @@
field public int low;
}
- public static abstract interface WifiScanner.BssidListener implements android.net.wifi.WifiScanner.ActionListener {
+ public static abstract deprecated interface WifiScanner.BssidListener implements android.net.wifi.WifiScanner.ActionListener {
method public abstract void onFound(android.net.wifi.ScanResult[]);
method public abstract void onLost(android.net.wifi.ScanResult[]);
}
@@ -29371,7 +29373,7 @@
field public int frequency;
}
- public static class WifiScanner.HotlistSettings implements android.os.Parcelable {
+ public static deprecated class WifiScanner.HotlistSettings implements android.os.Parcelable {
ctor public WifiScanner.HotlistSettings();
method public int describeContents();
method public void writeToParcel(android.os.Parcel, int);
@@ -29425,12 +29427,12 @@
field public int stepCount;
}
- public static abstract interface WifiScanner.WifiChangeListener implements android.net.wifi.WifiScanner.ActionListener {
+ public static abstract deprecated interface WifiScanner.WifiChangeListener implements android.net.wifi.WifiScanner.ActionListener {
method public abstract void onChanging(android.net.wifi.ScanResult[]);
method public abstract void onQuiescence(android.net.wifi.ScanResult[]);
}
- public static class WifiScanner.WifiChangeSettings implements android.os.Parcelable {
+ public static deprecated class WifiScanner.WifiChangeSettings implements android.os.Parcelable {
ctor public WifiScanner.WifiChangeSettings();
method public int describeContents();
method public void writeToParcel(android.os.Parcel, int);
@@ -33571,7 +33573,9 @@
field public static final java.lang.String ACTION_UPDATE_CARRIER_PROVISIONING_URLS = "android.intent.action.UPDATE_CARRIER_PROVISIONING_URLS";
field public static final java.lang.String ACTION_UPDATE_CT_LOGS = "android.intent.action.UPDATE_CT_LOGS";
field public static final java.lang.String ACTION_UPDATE_INTENT_FIREWALL = "android.intent.action.UPDATE_INTENT_FIREWALL";
+ field public static final java.lang.String ACTION_UPDATE_LANG_ID = "android.intent.action.UPDATE_LANG_ID";
field public static final java.lang.String ACTION_UPDATE_PINS = "android.intent.action.UPDATE_PINS";
+ field public static final java.lang.String ACTION_UPDATE_SMART_SELECTION = "android.intent.action.UPDATE_SMART_SELECTION";
field public static final java.lang.String ACTION_UPDATE_SMS_SHORT_CODES = "android.intent.action.UPDATE_SMS_SHORT_CODES";
field public static final java.lang.String ACTION_UPDATE_TZDATA = "android.intent.action.UPDATE_TZDATA";
}
@@ -37485,7 +37489,6 @@
}
public static final class FontsContract.Columns implements android.provider.BaseColumns {
- ctor public FontsContract.Columns();
field public static final java.lang.String FILE_ID = "file_id";
field public static final java.lang.String ITALIC = "font_italic";
field public static final java.lang.String RESULT_CODE = "result_code";
@@ -37502,6 +37505,7 @@
method public android.provider.FontsContract.FontInfo[] getFonts();
method public int getStatusCode();
field public static final int STATUS_OK = 0; // 0x0
+ field public static final int STATUS_REJECTED = 3; // 0x3
field public static final int STATUS_UNEXPECTED_DATA_PROVIDED = 2; // 0x2
field public static final int STATUS_WRONG_CERTIFICATES = 1; // 0x1
}
@@ -38549,8 +38553,8 @@
}
public static final class Telephony.ServiceStateTable {
- method public static android.net.Uri getUriForSubId(int);
- method public static android.net.Uri getUriForSubIdAndField(int, java.lang.String);
+ method public static android.net.Uri getUriForSubscriptionId(int);
+ method public static android.net.Uri getUriForSubscriptionIdAndField(int, java.lang.String);
field public static final java.lang.String AUTHORITY = "service-state";
field public static final android.net.Uri CONTENT_URI;
field public static final java.lang.String IS_MANUAL_NETWORK_SELECTION = "is_manual_network_selection";
@@ -44434,9 +44438,9 @@
method public android.database.sqlite.SQLiteDatabase openOrCreateDatabase(java.lang.String, int, android.database.sqlite.SQLiteDatabase.CursorFactory, android.database.DatabaseErrorHandler);
method public android.graphics.drawable.Drawable peekWallpaper();
method public android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter);
- method public android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter, boolean);
+ method public android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter, int);
method public android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter, java.lang.String, android.os.Handler);
- method public android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter, java.lang.String, android.os.Handler, boolean);
+ method public android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter, java.lang.String, android.os.Handler, int);
method public void removeStickyBroadcast(android.content.Intent);
method public void removeStickyBroadcastAsUser(android.content.Intent, android.os.UserHandle);
method public void revokeUriPermission(android.net.Uri, int);
@@ -44535,6 +44539,7 @@
method public int checkPermission(java.lang.String, java.lang.String);
method public int checkSignatures(java.lang.String, java.lang.String);
method public int checkSignatures(int, int);
+ method public void clearInstantAppCookie();
method public void clearPackagePreferredActivities(java.lang.String);
method public java.lang.String[] currentToCanonicalPackageNames(java.lang.String[]);
method public void extendVerificationTimeout(int, int, long);
@@ -44566,7 +44571,7 @@
method public java.util.List<android.content.pm.PackageInfo> getInstalledPackagesAsUser(int, int);
method public java.lang.String getInstallerPackageName(java.lang.String);
method public byte[] getInstantAppCookie();
- method public int getInstantAppCookieMaxSize();
+ method public int getInstantAppCookieMaxBytes();
method public android.graphics.drawable.Drawable getInstantAppIcon(java.lang.String);
method public android.content.ComponentName getInstantAppInstallerComponent();
method public android.content.ComponentName getInstantAppResolverSettingsComponent();
@@ -44631,8 +44636,8 @@
method public void setComponentEnabledSetting(android.content.ComponentName, int, int);
method public boolean setDefaultBrowserPackageNameAsUser(java.lang.String, int);
method public void setInstallerPackageName(java.lang.String, java.lang.String);
- method public boolean setInstantAppCookie(byte[]);
method public void setUpdateAvailable(java.lang.String, boolean);
+ method public void updateInstantAppCookie(byte[]);
method public boolean updateIntentVerificationStatusAsUser(java.lang.String, int, int);
method public void updatePermissionFlags(java.lang.String, java.lang.String, int, int, android.os.UserHandle);
method public void verifyIntentFilter(int, int, java.util.List<java.lang.String>);
@@ -50133,7 +50138,7 @@
method public abstract void setAlpha(float);
method public abstract void setAutofillHints(java.lang.String[]);
method public abstract void setAutofillId(android.view.ViewStructure, int);
- method public abstract void setAutofillOptions(java.lang.String[]);
+ method public abstract void setAutofillOptions(java.lang.CharSequence[]);
method public abstract void setAutofillType(int);
method public abstract void setAutofillValue(android.view.autofill.AutofillValue);
method public abstract void setCheckable(boolean);
@@ -50728,7 +50733,6 @@
}
public final class AccessibilityManager {
- method public boolean addAccessibilityServicesStateChangeListener(android.view.accessibility.AccessibilityManager.AccessibilityServicesStateChangeListener);
method public boolean addAccessibilityStateChangeListener(android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener);
method public boolean addTouchExplorationStateChangeListener(android.view.accessibility.AccessibilityManager.TouchExplorationStateChangeListener);
method public deprecated java.util.List<android.content.pm.ServiceInfo> getAccessibilityServiceList();
@@ -50737,16 +50741,11 @@
method public void interrupt();
method public boolean isEnabled();
method public boolean isTouchExplorationEnabled();
- method public boolean removeAccessibilityServicesStateChangeListener(android.view.accessibility.AccessibilityManager.AccessibilityServicesStateChangeListener);
method public boolean removeAccessibilityStateChangeListener(android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener);
method public boolean removeTouchExplorationStateChangeListener(android.view.accessibility.AccessibilityManager.TouchExplorationStateChangeListener);
method public void sendAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
}
- public static abstract interface AccessibilityManager.AccessibilityServicesStateChangeListener {
- method public abstract void onAccessibilityServicesStateChanged();
- }
-
public static abstract interface AccessibilityManager.AccessibilityStateChangeListener {
method public abstract void onAccessibilityStateChanged(boolean);
}
@@ -53322,6 +53321,7 @@
}
public abstract interface Adapter {
+ method public default java.lang.CharSequence[] getAutofillOptions();
method public abstract int getCount();
method public abstract java.lang.Object getItem(int);
method public abstract long getItemId(int);
@@ -53471,6 +53471,7 @@
method public void addAll(T...);
method public void clear();
method public static android.widget.ArrayAdapter<java.lang.CharSequence> createFromResource(android.content.Context, int, int);
+ method public java.lang.CharSequence[] getAutofillOptions();
method public android.content.Context getContext();
method public int getCount();
method public android.content.res.Resources.Theme getDropDownViewTheme();
@@ -55436,8 +55437,8 @@
method public void removeTextChangedListener(android.text.TextWatcher);
method public void setAllCaps(boolean);
method public final void setAutoLinkMask(int);
- method public void setAutoSizeTextTypeUniformWithConfiguration(int, int, int, int) throws java.lang.IllegalArgumentException;
- method public void setAutoSizeTextTypeUniformWithPresetSizes(int[], int) throws java.lang.IllegalArgumentException;
+ method public void setAutoSizeTextTypeUniformWithConfiguration(int, int, int, int);
+ method public void setAutoSizeTextTypeUniformWithPresetSizes(int[], int);
method public void setAutoSizeTextTypeWithDefaults(int);
method public void setBreakStrategy(int);
method public void setCompoundDrawablePadding(int);
diff --git a/api/system-removed.txt b/api/system-removed.txt
index 6d82a49..559ce12 100644
--- a/api/system-removed.txt
+++ b/api/system-removed.txt
@@ -61,6 +61,10 @@
field public static final int REQUESTED_PERMISSION_REQUIRED = 1; // 0x1
}
+ public abstract class PackageManager {
+ method public abstract boolean setInstantAppCookie(byte[]);
+ }
+
public final class SharedLibraryInfo implements android.os.Parcelable {
method public boolean isBuiltin();
method public boolean isDynamic();
diff --git a/api/test-current.txt b/api/test-current.txt
index 9706de2..6beff09 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -1710,6 +1710,7 @@
field public static final int ic_notification_clear_all = 17301594; // 0x108005a
field public static final int ic_notification_overlay = 17301595; // 0x108005b
field public static final int ic_partial_secure = 17301596; // 0x108005c
+ field public static final int ic_picture_in_picture = 17301685; // 0x10800b5
field public static final int ic_popup_disk_full = 17301597; // 0x108005d
field public static final int ic_popup_reminder = 17301598; // 0x108005e
field public static final int ic_popup_sync = 17301599; // 0x108005f
@@ -3617,7 +3618,6 @@
method public android.net.Uri getReferrer();
method public int getRequestedOrientation();
method public final android.view.SearchEvent getSearchEvent();
- method public long getStartInitiatedTime();
method public int getTaskId();
method public final java.lang.CharSequence getTitle();
method public final int getTitleColor();
@@ -3725,7 +3725,7 @@
method public void onTrimMemory(int);
method public void onUserInteraction();
method protected void onUserLeaveHint();
- method public void onVisibleBehindCanceled();
+ method public deprecated void onVisibleBehindCanceled();
method public void onWindowAttributesChanged(android.view.WindowManager.LayoutParams);
method public void onWindowFocusChanged(boolean);
method public android.view.ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback);
@@ -3742,7 +3742,7 @@
method public android.view.DragAndDropPermissions requestDragAndDropPermissions(android.view.DragEvent);
method public final void requestPermissions(java.lang.String[], int);
method public final void requestShowKeyboardShortcuts();
- method public boolean requestVisibleBehind(boolean);
+ method public deprecated boolean requestVisibleBehind(boolean);
method public final boolean requestWindowFeature(int);
method public final void runOnUiThread(java.lang.Runnable);
method public void setActionBar(android.widget.Toolbar);
@@ -4590,6 +4590,7 @@
method public final android.app.FragmentManager getFragmentManager();
method public final java.lang.Object getHost();
method public final int getId();
+ method public final android.view.LayoutInflater getLayoutInflater();
method public android.app.LoaderManager getLoaderManager();
method public final android.app.Fragment getParentFragment();
method public android.transition.Transition getReenterTransition();
@@ -6656,7 +6657,7 @@
method public float getAlpha();
method public java.lang.String[] getAutofillHints();
method public android.view.autofill.AutofillId getAutofillId();
- method public java.lang.String[] getAutofillOptions();
+ method public java.lang.CharSequence[] getAutofillOptions();
method public int getAutofillType();
method public android.view.autofill.AutofillValue getAutofillValue();
method public android.app.assist.AssistStructure.ViewNode getChildAt(int);
@@ -7094,6 +7095,7 @@
method public static void deleteAllHosts();
method public void deleteAppWidgetId(int);
method public void deleteHost();
+ method public int[] getAppWidgetIds();
method protected android.appwidget.AppWidgetHostView onCreateView(android.content.Context, int, android.appwidget.AppWidgetProviderInfo);
method protected void onProviderChanged(int, android.appwidget.AppWidgetProviderInfo);
method protected void onProvidersChanged();
@@ -8907,9 +8909,9 @@
method public abstract deprecated android.graphics.drawable.Drawable peekWallpaper();
method public void registerComponentCallbacks(android.content.ComponentCallbacks);
method public abstract android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter);
- method public abstract android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter, boolean);
+ method public abstract android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter, int);
method public abstract android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter, java.lang.String, android.os.Handler);
- method public abstract android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter, java.lang.String, android.os.Handler, boolean);
+ method public abstract android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter, java.lang.String, android.os.Handler, int);
method public abstract deprecated void removeStickyBroadcast(android.content.Intent);
method public abstract deprecated void removeStickyBroadcastAsUser(android.content.Intent, android.os.UserHandle);
method public abstract void revokeUriPermission(android.net.Uri, int);
@@ -9000,6 +9002,7 @@
field public static final java.lang.String NSD_SERVICE = "servicediscovery";
field public static final java.lang.String POWER_SERVICE = "power";
field public static final java.lang.String PRINT_SERVICE = "print";
+ field public static final int RECEIVER_VISIBLE_TO_INSTANT_APPS = 1; // 0x1
field public static final java.lang.String RESTRICTIONS_SERVICE = "restrictions";
field public static final java.lang.String SEARCH_SERVICE = "search";
field public static final java.lang.String SENSOR_SERVICE = "sensor";
@@ -9100,9 +9103,9 @@
method public android.database.sqlite.SQLiteDatabase openOrCreateDatabase(java.lang.String, int, android.database.sqlite.SQLiteDatabase.CursorFactory, android.database.DatabaseErrorHandler);
method public deprecated android.graphics.drawable.Drawable peekWallpaper();
method public android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter);
- method public android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter, boolean);
+ method public android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter, int);
method public android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter, java.lang.String, android.os.Handler);
- method public android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter, java.lang.String, android.os.Handler, boolean);
+ method public android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter, java.lang.String, android.os.Handler, int);
method public deprecated void removeStickyBroadcast(android.content.Intent);
method public deprecated void removeStickyBroadcastAsUser(android.content.Intent, android.os.UserHandle);
method public void revokeUriPermission(android.net.Uri, int);
@@ -9415,7 +9418,6 @@
field public static final java.lang.String ACTION_PACKAGE_ADDED = "android.intent.action.PACKAGE_ADDED";
field public static final java.lang.String ACTION_PACKAGE_CHANGED = "android.intent.action.PACKAGE_CHANGED";
field public static final java.lang.String ACTION_PACKAGE_DATA_CLEARED = "android.intent.action.PACKAGE_DATA_CLEARED";
- field public static final java.lang.String ACTION_PACKAGE_FIRST_ADDED = "android.intent.action.PACKAGE_FIRST_ADDED";
field public static final java.lang.String ACTION_PACKAGE_FIRST_LAUNCH = "android.intent.action.PACKAGE_FIRST_LAUNCH";
field public static final java.lang.String ACTION_PACKAGE_FULLY_REMOVED = "android.intent.action.PACKAGE_FULLY_REMOVED";
field public static final deprecated java.lang.String ACTION_PACKAGE_INSTALL = "android.intent.action.PACKAGE_INSTALL";
@@ -9925,7 +9927,7 @@
}
public abstract interface ServiceConnection {
- method public default void onBindingDead(android.content.ComponentName);
+ method public default void onBindingDied(android.content.ComponentName);
method public abstract void onServiceConnected(android.content.ComponentName, android.os.IBinder);
method public abstract void onServiceDisconnected(android.content.ComponentName);
}
@@ -10606,6 +10608,7 @@
method public abstract int checkPermission(java.lang.String, java.lang.String);
method public abstract int checkSignatures(java.lang.String, java.lang.String);
method public abstract int checkSignatures(int, int);
+ method public abstract void clearInstantAppCookie();
method public abstract void clearPackagePreferredActivities(java.lang.String);
method public abstract java.lang.String[] currentToCanonicalPackageNames(java.lang.String[]);
method public abstract void extendVerificationTimeout(int, int, long);
@@ -10636,7 +10639,7 @@
method public abstract java.util.List<android.content.pm.PackageInfo> getInstalledPackages(int);
method public abstract java.lang.String getInstallerPackageName(java.lang.String);
method public abstract byte[] getInstantAppCookie();
- method public abstract int getInstantAppCookieMaxSize();
+ method public abstract int getInstantAppCookieMaxBytes();
method public abstract android.content.pm.InstrumentationInfo getInstrumentationInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
method public abstract android.content.Intent getLaunchIntentForPackage(java.lang.String);
method public abstract android.content.Intent getLeanbackLaunchIntentForPackage(java.lang.String);
@@ -10692,7 +10695,7 @@
method public abstract void setApplicationEnabledSetting(java.lang.String, int, int);
method public abstract void setComponentEnabledSetting(android.content.ComponentName, int, int);
method public abstract void setInstallerPackageName(java.lang.String, java.lang.String);
- method public abstract boolean setInstantAppCookie(byte[]);
+ method public abstract void updateInstantAppCookie(byte[]);
method public abstract void verifyPendingInstall(int, int);
field public static final int COMPONENT_ENABLED_STATE_DEFAULT = 0; // 0x0
field public static final int COMPONENT_ENABLED_STATE_DISABLED = 2; // 0x2
@@ -14861,7 +14864,7 @@
field public static final java.lang.String STRING_TYPE_HEART_RATE = "android.sensor.heart_rate";
field public static final java.lang.String STRING_TYPE_LIGHT = "android.sensor.light";
field public static final java.lang.String STRING_TYPE_LINEAR_ACCELERATION = "android.sensor.linear_acceleration";
- field public static final java.lang.String STRING_TYPE_LOW_LATENCY_OFFBODY_DETECT = "android.sensor.low_latency_offbody";
+ field public static final java.lang.String STRING_TYPE_LOW_LATENCY_OFFBODY_DETECT = "android.sensor.low_latency_offbody_detect";
field public static final java.lang.String STRING_TYPE_MAGNETIC_FIELD = "android.sensor.magnetic_field";
field public static final java.lang.String STRING_TYPE_MAGNETIC_FIELD_UNCALIBRATED = "android.sensor.magnetic_field_uncalibrated";
field public static final java.lang.String STRING_TYPE_MOTION_DETECT = "android.sensor.motion_detect";
@@ -21032,7 +21035,6 @@
method public int getContentType();
method public int getFlags();
method public int getUsage();
- method public static deprecated int getVolumeControlStream(android.media.AudioAttributes);
method public int getVolumeControlStream();
method public void writeToParcel(android.os.Parcel, int);
field public static final int CONTENT_TYPE_MOVIE = 3; // 0x3
@@ -34633,7 +34635,6 @@
}
public static final class FontsContract.Columns implements android.provider.BaseColumns {
- ctor public FontsContract.Columns();
field public static final java.lang.String FILE_ID = "file_id";
field public static final java.lang.String ITALIC = "font_italic";
field public static final java.lang.String RESULT_CODE = "result_code";
@@ -34650,6 +34651,7 @@
method public android.provider.FontsContract.FontInfo[] getFonts();
method public int getStatusCode();
field public static final int STATUS_OK = 0; // 0x0
+ field public static final int STATUS_REJECTED = 3; // 0x3
field public static final int STATUS_UNEXPECTED_DATA_PROVIDED = 2; // 0x2
field public static final int STATUS_WRONG_CERTIFICATES = 1; // 0x1
}
@@ -35588,8 +35590,8 @@
}
public static final class Telephony.ServiceStateTable {
- method public static android.net.Uri getUriForSubId(int);
- method public static android.net.Uri getUriForSubIdAndField(int, java.lang.String);
+ method public static android.net.Uri getUriForSubscriptionId(int);
+ method public static android.net.Uri getUriForSubscriptionIdAndField(int, java.lang.String);
field public static final java.lang.String AUTHORITY = "service-state";
field public static final android.net.Uri CONTENT_URI;
field public static final java.lang.String IS_MANUAL_NETWORK_SELECTION = "is_manual_network_selection";
@@ -41075,9 +41077,9 @@
method public android.database.sqlite.SQLiteDatabase openOrCreateDatabase(java.lang.String, int, android.database.sqlite.SQLiteDatabase.CursorFactory, android.database.DatabaseErrorHandler);
method public android.graphics.drawable.Drawable peekWallpaper();
method public android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter);
- method public android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter, boolean);
+ method public android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter, int);
method public android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter, java.lang.String, android.os.Handler);
- method public android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter, java.lang.String, android.os.Handler, boolean);
+ method public android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter, java.lang.String, android.os.Handler, int);
method public void removeStickyBroadcast(android.content.Intent);
method public void removeStickyBroadcastAsUser(android.content.Intent, android.os.UserHandle);
method public void revokeUriPermission(android.net.Uri, int);
@@ -41172,6 +41174,7 @@
method public int checkPermission(java.lang.String, java.lang.String);
method public int checkSignatures(java.lang.String, java.lang.String);
method public int checkSignatures(int, int);
+ method public void clearInstantAppCookie();
method public void clearPackagePreferredActivities(java.lang.String);
method public java.lang.String[] currentToCanonicalPackageNames(java.lang.String[]);
method public void extendVerificationTimeout(int, int, long);
@@ -41203,7 +41206,7 @@
method public java.util.List<android.content.pm.PackageInfo> getInstalledPackages(int);
method public java.lang.String getInstallerPackageName(java.lang.String);
method public byte[] getInstantAppCookie();
- method public int getInstantAppCookieMaxSize();
+ method public int getInstantAppCookieMaxBytes();
method public android.content.pm.InstrumentationInfo getInstrumentationInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
method public android.content.Intent getLaunchIntentForPackage(java.lang.String);
method public android.content.Intent getLeanbackLaunchIntentForPackage(java.lang.String);
@@ -41258,7 +41261,7 @@
method public void setApplicationEnabledSetting(java.lang.String, int, int);
method public void setComponentEnabledSetting(android.content.ComponentName, int, int);
method public void setInstallerPackageName(java.lang.String, java.lang.String);
- method public boolean setInstantAppCookie(byte[]);
+ method public void updateInstantAppCookie(byte[]);
method public void verifyPendingInstall(int, int);
}
@@ -46931,7 +46934,7 @@
method public abstract void setAlpha(float);
method public abstract void setAutofillHints(java.lang.String[]);
method public abstract void setAutofillId(android.view.ViewStructure, int);
- method public abstract void setAutofillOptions(java.lang.String[]);
+ method public abstract void setAutofillOptions(java.lang.CharSequence[]);
method public abstract void setAutofillType(int);
method public abstract void setAutofillValue(android.view.autofill.AutofillValue);
method public abstract void setCheckable(boolean);
@@ -47525,7 +47528,6 @@
}
public final class AccessibilityManager {
- method public boolean addAccessibilityServicesStateChangeListener(android.view.accessibility.AccessibilityManager.AccessibilityServicesStateChangeListener);
method public boolean addAccessibilityStateChangeListener(android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener);
method public boolean addTouchExplorationStateChangeListener(android.view.accessibility.AccessibilityManager.TouchExplorationStateChangeListener);
method public deprecated java.util.List<android.content.pm.ServiceInfo> getAccessibilityServiceList();
@@ -47534,16 +47536,11 @@
method public void interrupt();
method public boolean isEnabled();
method public boolean isTouchExplorationEnabled();
- method public boolean removeAccessibilityServicesStateChangeListener(android.view.accessibility.AccessibilityManager.AccessibilityServicesStateChangeListener);
method public boolean removeAccessibilityStateChangeListener(android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener);
method public boolean removeTouchExplorationStateChangeListener(android.view.accessibility.AccessibilityManager.TouchExplorationStateChangeListener);
method public void sendAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
}
- public static abstract interface AccessibilityManager.AccessibilityServicesStateChangeListener {
- method public abstract void onAccessibilityServicesStateChanged();
- }
-
public static abstract interface AccessibilityManager.AccessibilityStateChangeListener {
method public abstract void onAccessibilityStateChanged(boolean);
}
@@ -49756,6 +49753,7 @@
}
public abstract interface Adapter {
+ method public default java.lang.CharSequence[] getAutofillOptions();
method public abstract int getCount();
method public abstract java.lang.Object getItem(int);
method public abstract long getItemId(int);
@@ -49905,6 +49903,7 @@
method public void addAll(T...);
method public void clear();
method public static android.widget.ArrayAdapter<java.lang.CharSequence> createFromResource(android.content.Context, int, int);
+ method public java.lang.CharSequence[] getAutofillOptions();
method public android.content.Context getContext();
method public int getCount();
method public android.content.res.Resources.Theme getDropDownViewTheme();
@@ -51877,8 +51876,8 @@
method public void removeTextChangedListener(android.text.TextWatcher);
method public void setAllCaps(boolean);
method public final void setAutoLinkMask(int);
- method public void setAutoSizeTextTypeUniformWithConfiguration(int, int, int, int) throws java.lang.IllegalArgumentException;
- method public void setAutoSizeTextTypeUniformWithPresetSizes(int[], int) throws java.lang.IllegalArgumentException;
+ method public void setAutoSizeTextTypeUniformWithConfiguration(int, int, int, int);
+ method public void setAutoSizeTextTypeUniformWithPresetSizes(int[], int);
method public void setAutoSizeTextTypeWithDefaults(int);
method public void setBreakStrategy(int);
method public void setCompoundDrawablePadding(int);
diff --git a/api/test-removed.txt b/api/test-removed.txt
index b6c2a98..189536d 100644
--- a/api/test-removed.txt
+++ b/api/test-removed.txt
@@ -63,6 +63,10 @@
field public static final int REQUESTED_PERMISSION_REQUIRED = 1; // 0x1
}
+ public abstract class PackageManager {
+ method public abstract boolean setInstantAppCookie(byte[]);
+ }
+
public final class SharedLibraryInfo implements android.os.Parcelable {
method public boolean isBuiltin();
method public boolean isDynamic();
diff --git a/cmds/app_process/Android.mk b/cmds/app_process/Android.mk
index eaad3a7..72fe051 100644
--- a/cmds/app_process/Android.mk
+++ b/cmds/app_process/Android.mk
@@ -5,6 +5,7 @@
libbinder \
libcutils \
libdl \
+ libhwbinder \
liblog \
libnativeloader \
libutils \
diff --git a/cmds/app_process/app_main.cpp b/cmds/app_process/app_main.cpp
index 0ea141c..e56417b 100644
--- a/cmds/app_process/app_main.cpp
+++ b/cmds/app_process/app_main.cpp
@@ -14,7 +14,7 @@
#include <unistd.h>
#include <binder/IPCThreadState.h>
-#include <binder/ProcessState.h>
+#include <hwbinder/IPCThreadState.h>
#include <utils/Log.h>
#include <cutils/memory.h>
#include <cutils/properties.h>
@@ -85,6 +85,7 @@
ar->callMain(mClassName, mClass, mArgs);
IPCThreadState::self()->stopProcess();
+ hardware::IPCThreadState::self()->stopProcess();
}
virtual void onZygoteInit()
@@ -99,6 +100,7 @@
if (mClassName.isEmpty()) {
// if zygote
IPCThreadState::self()->stopProcess();
+ hardware::IPCThreadState::self()->stopProcess();
}
AndroidRuntime::onExit(code);
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index c4b7ed7..4b55e17 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -17,7 +17,6 @@
package android.app;
import android.graphics.Rect;
-import android.os.SystemClock;
import android.view.ViewRootImpl.ActivityConfigCallback;
import android.view.autofill.AutofillManager;
import android.view.autofill.AutofillPopupWindow;
@@ -803,6 +802,7 @@
final FragmentController mFragments = FragmentController.createController(new HostCallbacks());
// Most recent call to requestVisibleBehind().
+ @Deprecated
boolean mVisibleBehind;
private static final class ManagedCursor {
@@ -6384,9 +6384,13 @@
* <p>False will be returned any time this method is called between the return of onPause and
* the next call to onResume.
*
+ * @deprecated This method's functionality is no longer supported as of
+ * {@link android.os.Build.VERSION_CODES#O} and will be removed in a future release.
+ *
* @param visible true to notify the system that the activity wishes to be visible behind other
* translucent activities, false to indicate otherwise. Resources must be
* released when passing false to this method.
+ *
* @return the resulting visibiity state. If true the activity will remain visible beyond
* {@link #onPause()} if the next activity is translucent or not fullscreen. If false
* then the activity may not count on being visible behind other translucent activities,
@@ -6396,6 +6400,7 @@
*
* @see #onVisibleBehindCanceled()
*/
+ @Deprecated
public boolean requestVisibleBehind(boolean visible) {
if (!mResumed) {
// Do not permit paused or stopped activities to do this.
@@ -6422,7 +6427,11 @@
* process. Otherwise {@link #onStop()} will be called following return.
*
* @see #requestVisibleBehind(boolean)
+ *
+ * @deprecated This method's functionality is no longer supported as of
+ * {@link android.os.Build.VERSION_CODES#O} and will be removed in a future release.
*/
+ @Deprecated
@CallSuper
public void onVisibleBehindCanceled() {
mCalled = true;
@@ -6432,6 +6441,9 @@
* Translucent activities may call this to determine if there is an activity below them that
* is currently set to be visible in the background.
*
+ * @deprecated This method's functionality is no longer supported as of
+ * {@link android.os.Build.VERSION_CODES#O} and will be removed in a future release.
+ *
* @return true if an activity below is set to visible according to the most recent call to
* {@link #requestVisibleBehind(boolean)}, false otherwise.
*
@@ -6440,6 +6452,7 @@
* @see #onBackgroundVisibleBehindChanged(boolean)
* @hide
*/
+ @Deprecated
@SystemApi
public boolean isBackgroundVisibleBehind() {
try {
@@ -6456,12 +6469,16 @@
* This call may be a consequence of {@link #requestVisibleBehind(boolean)} or might be
* due to a background activity finishing itself.
*
+ * @deprecated This method's functionality is no longer supported as of
+ * {@link android.os.Build.VERSION_CODES#O} and will be removed in a future release.
+ *
* @param visible true if a background activity is visible, false otherwise.
*
* @see #requestVisibleBehind(boolean)
* @see #onVisibleBehindCanceled()
* @hide
*/
+ @Deprecated
@SystemApi
public void onBackgroundVisibleBehindChanged(boolean visible) {
}
@@ -7501,25 +7518,6 @@
}
}
- /**
- * Return the timestamp at which this activity start was last initiated by the system in the
- * {@link SystemClock#uptimeMillis()} time base.
- *
- * This can be used to understand how much time is taken for an activity to be started and
- * displayed to the user.
- *
- * @return timestamp at which this activity start was initiated by the system
- * or {@code 0} if for any reason the timestamp could not be retrieved.
- */
- public long getStartInitiatedTime() {
- try {
- return ActivityManager.getService().getActivityStartInitiatedTime(mToken);
- } catch (RemoteException e) {
- Log.e(TAG, "Failed to call getActivityStartTime", e);
- return 0;
- }
- }
-
class HostCallbacks extends FragmentHostCallback<Activity> {
public HostCallbacks() {
super(Activity.this /*activity*/);
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index a4dcf63..44c275f 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -852,7 +852,11 @@
/**
* Returns true if activities contained in this stack can request visible behind by
* calling {@link Activity#requestVisibleBehind}.
+ *
+ * @deprecated This method's functionality is no longer supported as of
+ * {@link android.os.Build.VERSION_CODES#O} and will be removed in a future release.
*/
+ @Deprecated
public static boolean activitiesCanRequestVisibleBehind(int stackId) {
return stackId == FULLSCREEN_WORKSPACE_STACK_ID ||
stackId == ASSISTANT_STACK_ID;
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index 02d1884..63e8cc6 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -1211,9 +1211,6 @@
* methods that take an options Bundle.
*/
public Bundle toBundle() {
- if (mAnimationType == ANIM_DEFAULT) {
- return null;
- }
Bundle b = new Bundle();
if (mPackageName != null) {
b.putString(KEY_PACKAGE_NAME, mPackageName);
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 027ddf5..e50c307 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -820,14 +820,18 @@
}
}
- @Override
- public int getInstantAppCookieMaxSize() {
+ public int getInstantAppCookieMaxBytes() {
return Settings.Global.getInt(mContext.getContentResolver(),
Settings.Global.EPHEMERAL_COOKIE_MAX_SIZE_BYTES,
DEFAULT_EPHEMERAL_COOKIE_MAX_SIZE_BYTES);
}
@Override
+ public int getInstantAppCookieMaxSize() {
+ return getInstantAppCookieMaxBytes();
+ }
+
+ @Override
public @NonNull byte[] getInstantAppCookie() {
try {
final byte[] cookie = mPM.getInstantAppCookie(
@@ -843,6 +847,25 @@
}
@Override
+ public void clearInstantAppCookie() {
+ updateInstantAppCookie(null);
+ }
+
+ @Override
+ public void updateInstantAppCookie(@NonNull byte[] cookie) {
+ if (cookie != null && cookie.length > getInstantAppCookieMaxBytes()) {
+ throw new IllegalArgumentException("instant cookie longer than "
+ + getInstantAppCookieMaxBytes());
+ }
+ try {
+ mPM.setInstantAppCookie(mContext.getPackageName(),
+ cookie, mContext.getUserId());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ @Override
public boolean setInstantAppCookie(@NonNull byte[] cookie) {
try {
return mPM.setInstantAppCookie(mContext.getPackageName(),
@@ -2630,4 +2653,13 @@
throw e.rethrowAsRuntimeException();
}
}
+
+ @Override
+ public String getInstantAppAndroidId(String packageName, UserHandle user) {
+ try {
+ return mPM.getInstantAppAndroidId(packageName, user.getIdentifier());
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ }
+ }
}
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 80de64b..424e783 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -1357,34 +1357,34 @@
@Override
public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,
- boolean visibleToInstantApps) {
- return registerReceiver(receiver, filter, null, null, visibleToInstantApps);
+ int flags) {
+ return registerReceiver(receiver, filter, null, null, flags);
}
@Override
public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,
String broadcastPermission, Handler scheduler) {
return registerReceiverInternal(receiver, getUserId(),
- filter, broadcastPermission, scheduler, getOuterContext(), false);
+ filter, broadcastPermission, scheduler, getOuterContext(), 0);
}
@Override
public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,
- String broadcastPermission, Handler scheduler, boolean visibleToInstantApps) {
+ String broadcastPermission, Handler scheduler, int flags) {
return registerReceiverInternal(receiver, getUserId(),
- filter, broadcastPermission, scheduler, getOuterContext(), visibleToInstantApps);
+ filter, broadcastPermission, scheduler, getOuterContext(), flags);
}
@Override
public Intent registerReceiverAsUser(BroadcastReceiver receiver, UserHandle user,
IntentFilter filter, String broadcastPermission, Handler scheduler) {
return registerReceiverInternal(receiver, user.getIdentifier(),
- filter, broadcastPermission, scheduler, getOuterContext(), false);
+ filter, broadcastPermission, scheduler, getOuterContext(), 0);
}
private Intent registerReceiverInternal(BroadcastReceiver receiver, int userId,
IntentFilter filter, String broadcastPermission,
- Handler scheduler, Context context, boolean visibleToInstantApps) {
+ Handler scheduler, Context context, int flags) {
IIntentReceiver rd = null;
if (receiver != null) {
if (mPackageInfo != null && context != null) {
@@ -1405,7 +1405,7 @@
try {
final Intent intent = ActivityManager.getService().registerReceiver(
mMainThread.getApplicationThread(), mBasePackageName, rd, filter,
- broadcastPermission, userId, visibleToInstantApps);
+ broadcastPermission, userId, flags);
if (intent != null) {
intent.setExtrasClassLoader(getClassLoader());
intent.prepareToEnterProcess();
diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java
index c7bcc54..c5b93cd 100644
--- a/core/java/android/app/Fragment.java
+++ b/core/java/android/app/Fragment.java
@@ -509,6 +509,10 @@
// True if mHidden has been changed and the animation should be scheduled.
boolean mHiddenChanged;
+ // The cached value from onGetLayoutInflater(Bundle) that will be returned from
+ // getLayoutInflater()
+ LayoutInflater mLayoutInflater;
+
/**
* State information that has been retrieved from a fragment instance
* through {@link FragmentManager#saveFragmentInstanceState(Fragment)
@@ -1389,6 +1393,38 @@
}
/**
+ * Returns the cached LayoutInflater used to inflate Views of this Fragment. If
+ * {@link #onGetLayoutInflater(Bundle)} has not been called {@link #onGetLayoutInflater(Bundle)}
+ * will be called with a {@code null} argument and that value will be cached.
+ * <p>
+ * The cached LayoutInflater will be replaced immediately prior to
+ * {@link #onCreateView(LayoutInflater, ViewGroup, Bundle)} and cleared immediately after
+ * {@link #onDetach()}.
+ *
+ * @return The LayoutInflater used to inflate Views of this Fragment.
+ */
+ public final LayoutInflater getLayoutInflater() {
+ if (mLayoutInflater == null) {
+ return performGetLayoutInflater(null);
+ }
+ return mLayoutInflater;
+ }
+
+ /**
+ * Calls {@link #onGetLayoutInflater(Bundle)} and caches the result for use by
+ * {@link #getLayoutInflater()}.
+ *
+ * @param savedInstanceState If the fragment is being re-created from
+ * a previous saved state, this is the state.
+ * @return The LayoutInflater used to inflate Views of this Fragment.
+ */
+ LayoutInflater performGetLayoutInflater(Bundle savedInstanceState) {
+ LayoutInflater layoutInflater = onGetLayoutInflater(savedInstanceState);
+ mLayoutInflater = layoutInflater;
+ return mLayoutInflater;
+ }
+
+ /**
* @deprecated Use {@link #onInflate(Context, AttributeSet, Bundle)} instead.
*/
@Deprecated
@@ -2835,6 +2871,7 @@
void performDetach() {
mCalled = false;
onDetach();
+ mLayoutInflater = null;
if (!mCalled) {
throw new SuperNotCalledException("Fragment " + this
+ " did not call through to super.onDetach()");
diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java
index 91578a2..508d704 100644
--- a/core/java/android/app/FragmentManager.java
+++ b/core/java/android/app/FragmentManager.java
@@ -1259,7 +1259,7 @@
}
}
f.mContainer = container;
- f.mView = f.performCreateView(f.onGetLayoutInflater(
+ f.mView = f.performCreateView(f.performGetLayoutInflater(
f.mSavedFragmentState), container, f.mSavedFragmentState);
if (f.mView != null) {
f.mView.setSaveFromParentEnabled(false);
@@ -1334,6 +1334,9 @@
f.performDestroyView();
dispatchOnFragmentViewDestroyed(f, false);
if (f.mView != null && f.mContainer != null) {
+ // Stop any current animations:
+ f.mView.clearAnimation();
+ f.mContainer.endViewTransition(f.mView);
Animator anim = null;
if (mCurState > Fragment.INITIALIZING && !mDestroyed
&& f.mView.getVisibility() == View.VISIBLE
@@ -1431,7 +1434,7 @@
void ensureInflatedFragmentView(Fragment f) {
if (f.mFromLayout && !f.mPerformedCreateView) {
- f.mView = f.performCreateView(f.onGetLayoutInflater(
+ f.mView = f.performCreateView(f.performGetLayoutInflater(
f.mSavedFragmentState), null, f.mSavedFragmentState);
if (f.mView != null) {
f.mView.setSaveFromParentEnabled(false);
@@ -1462,18 +1465,26 @@
if (fragment.isHideReplaced()) {
fragment.setHideReplaced(false);
} else {
+ final ViewGroup container = fragment.mContainer;
+ final View animatingView = fragment.mView;
+ if (container != null) {
+ container.startViewTransition(animatingView);
+ }
// Delay the actual hide operation until the animation finishes, otherwise
// the fragment will just immediately disappear
anim.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
- animation.removeListener(this);
- if (fragment.mView != null) {
- fragment.mView.setVisibility(View.GONE);
+ if (container != null) {
+ container.endViewTransition(animatingView);
}
+ animation.removeListener(this);
+ animatingView.setVisibility(View.GONE);
}
});
}
+ } else {
+ fragment.mView.setVisibility(View.VISIBLE);
}
setHWLayerAnimListenerIfAlpha(fragment.mView, anim);
anim.start();
@@ -3001,6 +3012,7 @@
mExecutingActions = false;
}
}
+ execPendingActions();
}
/**
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index d270244..d1eea3b 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -100,7 +100,7 @@
boolean finishActivity(in IBinder token, int code, in Intent data, int finishTask);
Intent registerReceiver(in IApplicationThread caller, in String callerPackage,
in IIntentReceiver receiver, in IntentFilter filter,
- in String requiredPermission, int userId, boolean visibleToInstantApps);
+ in String requiredPermission, int userId, int flags);
void unregisterReceiver(in IIntentReceiver receiver);
int broadcastIntent(in IApplicationThread caller, in Intent intent,
in String resolvedType, in IIntentReceiver resultTo, int resultCode,
@@ -631,8 +631,6 @@
*/
void backgroundWhitelistUid(int uid);
- long getActivityStartInitiatedTime(IBinder token);
-
// WARNING: when these transactions are updated, check if they are any callers on the native
// side. If so, make sure they are using the correct transaction ids and arguments.
// If a transaction which will also be used on the native side is being inserted, add it
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index 4205db0..bbcf7ba 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -1598,7 +1598,7 @@
mConnection.onServiceDisconnected(name);
}
if (dead) {
- mConnection.onBindingDead(name);
+ mConnection.onBindingDied(name);
}
// If there is a new service, it is now connected.
if (service != null) {
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index cab2114..602cccb 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -3251,7 +3251,6 @@
* However, for {@link MediaStyle} and {@link DecoratedMediaCustomViewStyle} notifications
* that have a media session attached there is no such requirement.
*
- * @see Builder#setOngoing(boolean)
* @see Builder#setColor(int)
* @see MediaStyle#setMediaSession(MediaSession.Token)
*/
@@ -3742,6 +3741,11 @@
return mActionBarColor;
}
+ private int getActionBarColorDeEmphasized() {
+ int backgroundColor = getBackgroundColor();
+ return NotificationColorUtil.getShiftedColor(backgroundColor, 12);
+ }
+
private void setTextViewColorSecondary(RemoteViews contentView, int id) {
ensureColors();
contentView.setTextColor(id, mSecondaryTextColor);
@@ -4316,8 +4320,13 @@
// TODO: handle emphasized mode / actions right
if (emphazisedMode) {
// change the background bgColor
- int bgColor = mContext.getColor(oddAction ? R.color.notification_action_list
- : R.color.notification_action_list_dark);
+ int bgColor;
+ if (isColorized()) {
+ bgColor = oddAction ? getActionBarColor() : getActionBarColorDeEmphasized();
+ } else {
+ bgColor = mContext.getColor(oddAction ? R.color.notification_action_list
+ : R.color.notification_action_list_dark);
+ }
button.setDrawableParameters(R.id.button_holder, true, -1, bgColor,
PorterDuff.Mode.SRC_ATOP, -1);
CharSequence title = action.title;
diff --git a/core/java/android/app/assist/AssistStructure.java b/core/java/android/app/assist/AssistStructure.java
index 9f911f5..9e5c9e7 100644
--- a/core/java/android/app/assist/AssistStructure.java
+++ b/core/java/android/app/assist/AssistStructure.java
@@ -595,7 +595,7 @@
@View.AutofillType int mAutofillType;
@Nullable String[] mAutofillHints;
AutofillValue mAutofillValue;
- String[] mAutofillOptions;
+ CharSequence[] mAutofillOptions;
boolean mSanitized;
HtmlInfo mHtmlInfo;
@@ -689,7 +689,7 @@
mAutofillType = in.readInt();
mAutofillHints = in.readStringArray();
mAutofillValue = in.readParcelable(null);
- mAutofillOptions = in.readStringArray();
+ mAutofillOptions = in.readCharSequenceArray();
final Parcelable p = in.readParcelable(null);
if (p instanceof HtmlInfo) {
mHtmlInfo = (HtmlInfo) p;
@@ -850,7 +850,7 @@
sanitizedValue = null;
}
out.writeParcelable(sanitizedValue, 0);
- out.writeStringArray(mAutofillOptions);
+ out.writeCharSequenceArray(mAutofillOptions);
if (mHtmlInfo instanceof Parcelable) {
out.writeParcelable((Parcelable) mHtmlInfo, 0);
} else {
@@ -1002,7 +1002,7 @@
* <p>It's only set when the {@link AssistStructure} is used for autofilling purposes, not
* for assist.
*/
- public String[] getAutofillOptions() {
+ public CharSequence[] getAutofillOptions() {
return mAutofillOptions;
}
@@ -1694,7 +1694,7 @@
}
@Override
- public void setAutofillOptions(String[] options) {
+ public void setAutofillOptions(CharSequence[] options) {
mNode.mAutofillOptions = options;
}
diff --git a/core/java/android/appwidget/AppWidgetHost.java b/core/java/android/appwidget/AppWidgetHost.java
index 6ba52b7..c1ff580 100644
--- a/core/java/android/appwidget/AppWidgetHost.java
+++ b/core/java/android/appwidget/AppWidgetHost.java
@@ -276,8 +276,6 @@
/**
* Gets a list of all the appWidgetIds that are bound to the current host
- *
- * @hide
*/
public int[] getAppWidgetIds() {
try {
diff --git a/core/java/android/companion/AssociationRequest.java b/core/java/android/companion/AssociationRequest.java
index 919f4ba..922224a 100644
--- a/core/java/android/companion/AssociationRequest.java
+++ b/core/java/android/companion/AssociationRequest.java
@@ -84,6 +84,14 @@
}
@Override
+ public String toString() {
+ return "AssociationRequest{" +
+ "mSingleDevice=" + mSingleDevice +
+ ", mDeviceFilters=" + mDeviceFilters +
+ '}';
+ }
+
+ @Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeByte((byte) (mSingleDevice ? 1 : 0));
dest.writeParcelableList(mDeviceFilters, flags);
diff --git a/core/java/android/companion/BluetoothLEDeviceFilter.java b/core/java/android/companion/BluetoothLEDeviceFilter.java
index 76051d7..e5ea4e9 100644
--- a/core/java/android/companion/BluetoothLEDeviceFilter.java
+++ b/core/java/android/companion/BluetoothLEDeviceFilter.java
@@ -225,6 +225,23 @@
return 0;
}
+ @Override
+ public String toString() {
+ return "BluetoothLEDeviceFilter{" +
+ "mNamePattern=" + mNamePattern +
+ ", mScanFilter=" + mScanFilter +
+ ", mRawDataFilter=" + Arrays.toString(mRawDataFilter) +
+ ", mRawDataFilterMask=" + Arrays.toString(mRawDataFilterMask) +
+ ", mRenamePrefix='" + mRenamePrefix + '\'' +
+ ", mRenameSuffix='" + mRenameSuffix + '\'' +
+ ", mRenameBytesFrom=" + mRenameBytesFrom +
+ ", mRenameBytesTo=" + mRenameBytesTo +
+ ", mRenameNameFrom=" + mRenameNameFrom +
+ ", mRenameNameTo=" + mRenameNameTo +
+ ", mRenameBytesReverseOrder=" + mRenameBytesReverseOrder +
+ '}';
+ }
+
public static final Creator<BluetoothLEDeviceFilter> CREATOR
= new Creator<BluetoothLEDeviceFilter>() {
@Override
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 0adab1a..8af791a 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -57,6 +57,7 @@
import android.os.StatFs;
import android.os.UserHandle;
import android.os.UserManager;
+import android.os.storage.StorageManager;
import android.provider.MediaStore;
import android.util.AttributeSet;
import android.view.Display;
@@ -365,6 +366,19 @@
*/
public static final int BIND_EXTERNAL_SERVICE = 0x80000000;
+ /** @hide */
+ @IntDef(flag = true,
+ value = {
+ RECEIVER_VISIBLE_TO_INSTANT_APPS
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface RegisterReceiverFlags {}
+
+ /**
+ * Flag for {@link #registerReceiver}: The receiver can receive broadcasts from Instant Apps.
+ */
+ public static final int RECEIVER_VISIBLE_TO_INSTANT_APPS = 0x1;
+
/**
* Returns an AssetManager instance for the application's package.
* <p>
@@ -1146,16 +1160,26 @@
/**
* Returns the absolute path to the application specific cache directory on
- * the filesystem. These files will be ones that get deleted first when the
- * device runs low on storage. There is no guarantee when these files will
- * be deleted.
+ * the filesystem.
* <p>
- * <strong>Note: you should not <em>rely</em> on the system deleting these
- * files for you; you should always have a reasonable maximum, such as 1 MB,
- * for the amount of space you consume with cache files, and prune those
- * files when exceeding that space.</strong> If your app requires a larger
- * cache (larger than 1 MB), you should use {@link #getExternalCacheDir()}
- * instead.
+ * The system will automatically delete files in this directory as disk
+ * space is needed elsewhere on the device. The system will always delete
+ * older files first, as reported by {@link File#lastModified()}. If
+ * desired, you can exert more control over how files are deleted using
+ * {@link StorageManager#setCacheBehaviorGroup(File, boolean)} and
+ * {@link StorageManager#setCacheBehaviorTombstone(File, boolean)}.
+ * <p>
+ * Apps are strongly encouraged to keep their usage of cache space below the
+ * quota returned by
+ * {@link StorageManager#getCacheQuotaBytes(java.util.UUID)}. If your app
+ * goes above this quota, your cached files will be some of the first to be
+ * deleted when additional disk space is needed. Conversely, if your app
+ * stays under this quota, your cached files will be some of the last to be
+ * deleted when additional disk space is needed.
+ * <p>
+ * Note that your cache quota will change over time depending on how
+ * frequently the user interacts with your app, and depending on how much
+ * system-wide disk space is used.
* <p>
* The returned path may change over time if the calling app is moved to an
* adopted storage device, so only relative paths should be persisted.
@@ -1173,9 +1197,11 @@
/**
* Returns the absolute path to the application specific cache directory on
- * the filesystem designed for storing cached code. The system will delete
- * any files stored in this location both when your specific application is
- * upgraded, and when the entire platform is upgraded.
+ * the filesystem designed for storing cached code.
+ * <p>
+ * The system will delete any files stored in this location both when your
+ * specific application is upgraded, and when the entire platform is
+ * upgraded.
* <p>
* This location is optimal for storing compiled or optimized code generated
* by your application at runtime.
@@ -2424,7 +2450,8 @@
*
* @param receiver The BroadcastReceiver to handle the broadcast.
* @param filter Selects the Intent broadcasts to be received.
- * @param visibleToInstantApps If the receiver accepts broadcasts from Instant Apps.
+ * @param flags Additional options for the receiver. May be 0 or
+ * {@link #RECEIVER_VISIBLE_TO_INSTANT_APPS}.
*
* @return The first sticky intent found that matches <var>filter</var>,
* or null if there are none.
@@ -2436,7 +2463,7 @@
@Nullable
public abstract Intent registerReceiver(@Nullable BroadcastReceiver receiver,
IntentFilter filter,
- boolean visibleToInstantApps);
+ @RegisterReceiverFlags int flags);
/**
* Register to receive intent broadcasts, to run in the context of
@@ -2475,9 +2502,9 @@
@Nullable Handler scheduler);
/**
- * Register to receive intent broadcasts, with the receiver optionally being
- * exposed to Instant Apps. See
- * {@link #registerReceiver(BroadcastReceiver, IntentFilter, boolean)} and
+ * Register to receive intent broadcasts, to run in the context of
+ * <var>scheduler</var>. See
+ * {@link #registerReceiver(BroadcastReceiver, IntentFilter, int)} and
* {@link #registerReceiver(BroadcastReceiver, IntentFilter, String, Handler)}
* for more information.
*
@@ -2496,12 +2523,13 @@
* no permission is required.
* @param scheduler Handler identifying the thread that will receive
* the Intent. If null, the main thread of the process will be used.
- * @param visibleToInstantApps If the receiver accepts broadcasts from Instant Apps.
+ * @param flags Additional options for the receiver. May be 0 or
+ * {@link #RECEIVER_VISIBLE_TO_INSTANT_APPS}.
*
* @return The first sticky intent found that matches <var>filter</var>,
* or null if there are none.
*
- * @see #registerReceiver(BroadcastReceiver, IntentFilter, boolean)
+ * @see #registerReceiver(BroadcastReceiver, IntentFilter, int)
* @see #registerReceiver(BroadcastReceiver, IntentFilter, String, Handler)
* @see #sendBroadcast
* @see #unregisterReceiver
@@ -2509,7 +2537,7 @@
@Nullable
public abstract Intent registerReceiver(BroadcastReceiver receiver,
IntentFilter filter, @Nullable String broadcastPermission,
- @Nullable Handler scheduler, boolean visibleToInstantApps);
+ @Nullable Handler scheduler, @RegisterReceiverFlags int flags);
/**
* @hide
@@ -3722,6 +3750,7 @@
public static final String PRINT_SERVICE = "print";
/**
+ * Use with {@link #getSystemService} to retrieve a
* {@link android.companion.CompanionDeviceManager} for managing companion devices
*
* @see #getSystemService
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index b59fc3dd..5264cd7 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -605,8 +605,8 @@
@Override
public Intent registerReceiver(
- BroadcastReceiver receiver, IntentFilter filter, boolean visibleToInstantApps) {
- return mBase.registerReceiver(receiver, filter, visibleToInstantApps);
+ BroadcastReceiver receiver, IntentFilter filter, int flags) {
+ return mBase.registerReceiver(receiver, filter, flags);
}
@Override
@@ -620,9 +620,9 @@
@Override
public Intent registerReceiver(
BroadcastReceiver receiver, IntentFilter filter,
- String broadcastPermission, Handler scheduler, boolean visibleToInstantApps) {
+ String broadcastPermission, Handler scheduler, int flags) {
return mBase.registerReceiver(receiver, filter, broadcastPermission,
- scheduler, visibleToInstantApps);
+ scheduler, flags);
}
/** @hide */
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 5ca4fa3..3e3f1ee 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1517,7 +1517,7 @@
* Output: If {@link #EXTRA_RETURN_RESULT}, returns whether the install
* succeeded.
* <p>
- * <strong>Note:</strong>If your app is targeting API level higher than 22 you
+ * <strong>Note:</strong>If your app is targeting API level higher than 25 you
* need to hold {@link android.Manifest.permission#REQUEST_INSTALL_PACKAGES}
* in order to launch the application installer.
* </p>
@@ -1656,6 +1656,8 @@
/**
* Used as an int extra field with {@link #ACTION_INSTALL_PACKAGE} and
* {@link #ACTION_VIEW} to indicate the uid of the package that initiated the install
+ * Currently only a system app that hosts the provider authority "downloads" or holds the
+ * permission {@link android.Manifest.permission.MANAGE_DOCUMENTS} can use this.
* @hide
*/
@SystemApi
@@ -2072,13 +2074,13 @@
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_PACKAGE_INSTALL = "android.intent.action.PACKAGE_INSTALL";
/**
- * Broadcast Action: An application package has been installed or updated on the
+ * Broadcast Action: A new application package has been installed on the
* device. The data contains the name of the package. Note that the
* newly installed package does <em>not</em> receive this broadcast.
* <p>May include the following extras:
* <ul>
- * <li> {@link #EXTRA_UID} containing the integer uid assigned to this package.
- * <li> {@link #EXTRA_REPLACING} is set to {@code true} if this is following
+ * <li> {@link #EXTRA_UID} containing the integer uid assigned to the new package.
+ * <li> {@link #EXTRA_REPLACING} is set to true if this is following
* an {@link #ACTION_PACKAGE_REMOVED} broadcast for the same package.
* </ul>
*
@@ -2088,22 +2090,6 @@
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_PACKAGE_ADDED = "android.intent.action.PACKAGE_ADDED";
/**
- * Broadcast Action: A new application package has been installed on the
- * device. The data contains the name of the package. Note that the
- * newly installed package does <em>not</em> receive this broadcast.
- * <p class="note">Unlike {@link #ACTION_PACKAGE_ADDED}, this broadcast is delivered
- * to manifest receivers as well as those registered at runtime.
- * <p>May include the following extras:
- * <ul>
- * <li> {@link #EXTRA_UID} containing the integer uid assigned to the new package.
- * </ul>
- *
- * <p class="note">This is a protected intent that can only be sent
- * by the system.
- */
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_PACKAGE_FIRST_ADDED = "android.intent.action.PACKAGE_FIRST_ADDED";
- /**
* Broadcast Action: A new version of an application package has been
* installed, replacing an existing version that was previously installed.
* The data contains the name of the package.
@@ -8616,6 +8602,32 @@
* a single statement.
* @see #setFlags(int)
* @see #removeFlags(int)
+ *
+ * @see #FLAG_GRANT_READ_URI_PERMISSION
+ * @see #FLAG_GRANT_WRITE_URI_PERMISSION
+ * @see #FLAG_GRANT_PERSISTABLE_URI_PERMISSION
+ * @see #FLAG_GRANT_PREFIX_URI_PERMISSION
+ * @see #FLAG_DEBUG_LOG_RESOLUTION
+ * @see #FLAG_FROM_BACKGROUND
+ * @see #FLAG_ACTIVITY_BROUGHT_TO_FRONT
+ * @see #FLAG_ACTIVITY_CLEAR_TASK
+ * @see #FLAG_ACTIVITY_CLEAR_TOP
+ * @see #FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET
+ * @see #FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
+ * @see #FLAG_ACTIVITY_FORWARD_RESULT
+ * @see #FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY
+ * @see #FLAG_ACTIVITY_MULTIPLE_TASK
+ * @see #FLAG_ACTIVITY_NEW_DOCUMENT
+ * @see #FLAG_ACTIVITY_NEW_TASK
+ * @see #FLAG_ACTIVITY_NO_ANIMATION
+ * @see #FLAG_ACTIVITY_NO_HISTORY
+ * @see #FLAG_ACTIVITY_NO_USER_ACTION
+ * @see #FLAG_ACTIVITY_PREVIOUS_IS_TOP
+ * @see #FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
+ * @see #FLAG_ACTIVITY_REORDER_TO_FRONT
+ * @see #FLAG_ACTIVITY_SINGLE_TOP
+ * @see #FLAG_ACTIVITY_TASK_ON_HOME
+ * @see #FLAG_RECEIVER_REGISTERED_ONLY
*/
public Intent addFlags(int flags) {
mFlags |= flags;
@@ -8628,6 +8640,32 @@
* @param flags The flags to remove.
* @see #setFlags(int)
* @see #addFlags(int)
+ *
+ * @see #FLAG_GRANT_READ_URI_PERMISSION
+ * @see #FLAG_GRANT_WRITE_URI_PERMISSION
+ * @see #FLAG_GRANT_PERSISTABLE_URI_PERMISSION
+ * @see #FLAG_GRANT_PREFIX_URI_PERMISSION
+ * @see #FLAG_DEBUG_LOG_RESOLUTION
+ * @see #FLAG_FROM_BACKGROUND
+ * @see #FLAG_ACTIVITY_BROUGHT_TO_FRONT
+ * @see #FLAG_ACTIVITY_CLEAR_TASK
+ * @see #FLAG_ACTIVITY_CLEAR_TOP
+ * @see #FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET
+ * @see #FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
+ * @see #FLAG_ACTIVITY_FORWARD_RESULT
+ * @see #FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY
+ * @see #FLAG_ACTIVITY_MULTIPLE_TASK
+ * @see #FLAG_ACTIVITY_NEW_DOCUMENT
+ * @see #FLAG_ACTIVITY_NEW_TASK
+ * @see #FLAG_ACTIVITY_NO_ANIMATION
+ * @see #FLAG_ACTIVITY_NO_HISTORY
+ * @see #FLAG_ACTIVITY_NO_USER_ACTION
+ * @see #FLAG_ACTIVITY_PREVIOUS_IS_TOP
+ * @see #FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
+ * @see #FLAG_ACTIVITY_REORDER_TO_FRONT
+ * @see #FLAG_ACTIVITY_SINGLE_TOP
+ * @see #FLAG_ACTIVITY_TASK_ON_HOME
+ * @see #FLAG_RECEIVER_REGISTERED_ONLY
*/
public void removeFlags(int flags) {
mFlags &= ~flags;
diff --git a/core/java/android/content/ServiceConnection.java b/core/java/android/content/ServiceConnection.java
index 8e428f9..6ff4900 100644
--- a/core/java/android/content/ServiceConnection.java
+++ b/core/java/android/content/ServiceConnection.java
@@ -61,6 +61,6 @@
* @param name The concrete component name of the service whose
* connection is dead.
*/
- default void onBindingDead(ComponentName name) {
+ default void onBindingDied(ComponentName name) {
}
}
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 8b2809a..b0f8aa7 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -1203,7 +1203,12 @@
dest.writeInt(requiresSmallestWidthDp);
dest.writeInt(compatibleWidthLimitDp);
dest.writeInt(largestWidthLimitDp);
- dest.writeUuid(storageUuid);
+ if (storageUuid != null) {
+ dest.writeInt(1);
+ dest.writeUuid(storageUuid);
+ } else {
+ dest.writeInt(0);
+ }
dest.writeString(scanSourceDir);
dest.writeString(scanPublicSourceDir);
dest.writeString(sourceDir);
@@ -1265,8 +1270,10 @@
requiresSmallestWidthDp = source.readInt();
compatibleWidthLimitDp = source.readInt();
largestWidthLimitDp = source.readInt();
- storageUuid = source.readUuid();
- volumeUuid = StorageManager.convert(storageUuid);
+ if (source.readInt() != 0) {
+ storageUuid = source.readUuid();
+ volumeUuid = StorageManager.convert(storageUuid);
+ }
scanSourceDir = source.readString();
scanPublicSourceDir = source.readString();
sourceDir = source.readString();
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index bbc942a..bc7a612 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -634,4 +634,6 @@
ComponentName getInstantAppResolverSettingsComponent();
ComponentName getInstantAppInstallerComponent();
+
+ String getInstantAppAndroidId(String packageName, int userId);
}
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 178b967..b8c87e6 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -1815,12 +1815,8 @@
* will enumerate at least one {@code VkPhysicalDevice}, and the feature version will indicate
* what level of optional compute features are supported beyond the Vulkan 1.0 requirements.
* <p>
- * Compute level 0 indicates support for:
- * <ul>
- * <li>Ability to use pointers to buffer data from shaders</li>
- * <li>Ability to load/store 16-bit values from buffers</li>
- * <li>Ability to control shader floating point rounding mode</li>
- * </ul>
+ * Compute level 0 indicates support for the {@code VariablePointers} SPIR-V capability defined
+ * by the SPV_KHR_variable_pointers extension.
*/
@SdkConstant(SdkConstantType.FEATURE)
public static final String FEATURE_VULKAN_HARDWARE_COMPUTE = "android.hardware.vulkan.compute";
@@ -2824,7 +2820,7 @@
* by passing {@link #VERSION_CODE_HIGHEST} in the {@link VersionedPackage}
* constructor.
*
- * @param versionedPackage The versioned packages for which to query.
+ * @param versionedPackage The versioned package for which to query.
* @param flags Additional option flags. Use any combination of
* {@link #GET_ACTIVITIES}, {@link #GET_CONFIGURATIONS},
* {@link #GET_GIDS}, {@link #GET_INSTRUMENTATION},
@@ -3846,9 +3842,9 @@
* @return Whether caller is an instant app.
*
* @see #isInstantApp(String)
- * @see #setInstantAppCookie(byte[])
+ * @see #updateInstantAppCookie(byte[])
* @see #getInstantAppCookie()
- * @see #getInstantAppCookieMaxSize()
+ * @see #getInstantAppCookieMaxBytes()
*/
public abstract boolean isInstantApp();
@@ -3859,9 +3855,10 @@
* @return Whether the given package is an instant app.
*
* @see #isInstantApp()
- * @see #setInstantAppCookie(byte[])
+ * @see #updateInstantAppCookie(byte[])
* @see #getInstantAppCookie()
- * @see #getInstantAppCookieMaxSize()
+ * @see #getInstantAppCookieMaxBytes()
+ * @see #clearInstantAppCookie()
*/
public abstract boolean isInstantApp(String packageName);
@@ -3873,8 +3870,15 @@
*
* @see #isInstantApp()
* @see #isInstantApp(String)
- * @see #setInstantAppCookie(byte[])
+ * @see #updateInstantAppCookie(byte[])
* @see #getInstantAppCookie()
+ * @see #clearInstantAppCookie()
+ */
+ public abstract int getInstantAppCookieMaxBytes();
+
+ /**
+ * @deprecated
+ * @hide
*/
public abstract int getInstantAppCookieMaxSize();
@@ -3882,7 +3886,7 @@
* Gets the instant application cookie for this app. Non
* instant apps and apps that were instant but were upgraded
* to normal apps can still access this API. For instant apps
- * this cooke is cached for some time after uninstall while for
+ * this cookie is cached for some time after uninstall while for
* normal apps the cookie is deleted after the app is uninstalled.
* The cookie is always present while the app is installed.
*
@@ -3890,31 +3894,49 @@
*
* @see #isInstantApp()
* @see #isInstantApp(String)
- * @see #setInstantAppCookie(byte[])
- * @see #getInstantAppCookieMaxSize()
+ * @see #updateInstantAppCookie(byte[])
+ * @see #getInstantAppCookieMaxBytes()
+ * @see #clearInstantAppCookie()
*/
public abstract @NonNull byte[] getInstantAppCookie();
/**
- * Sets the instant application cookie for the calling app. Non
- * instant apps and apps that were instant but were upgraded
- * to normal apps can still access this API. For instant apps
- * this cooke is cached for some time after uninstall while for
- * normal apps the cookie is deleted after the app is uninstalled.
- * The cookie is always present while the app is installed. The
- * cookie size is limited by {@link #getInstantAppCookieMaxSize()}.
- * If the provided cookie size is over the limit this method
- * returns <code>false</code>. Passing <code>null</code> or an empty
- * array clears the cookie.
- * </p>
- *
- * @param cookie The cookie data.
- * @return Whether the cookie was set.
+ * Clears the instant application cookie for the calling app.
*
* @see #isInstantApp()
* @see #isInstantApp(String)
- * @see #getInstantAppCookieMaxSize()
+ * @see #getInstantAppCookieMaxBytes()
* @see #getInstantAppCookie()
+ * @see #clearInstantAppCookie()
+ */
+ public abstract void clearInstantAppCookie();
+
+ /**
+ * Updates the instant application cookie for the calling app. Non
+ * instant apps and apps that were instant but were upgraded
+ * to normal apps can still access this API. For instant apps
+ * this cookie is cached for some time after uninstall while for
+ * normal apps the cookie is deleted after the app is uninstalled.
+ * The cookie is always present while the app is installed. The
+ * cookie size is limited by {@link #getInstantAppCookieMaxBytes()}.
+ * Passing <code>null</code> or an empty array clears the cookie.
+ * </p>
+ *
+ * @param cookie The cookie data.
+ *
+ * @see #isInstantApp()
+ * @see #isInstantApp(String)
+ * @see #getInstantAppCookieMaxBytes()
+ * @see #getInstantAppCookie()
+ * @see #clearInstantAppCookie()
+ *
+ * @throws IllegalArgumentException if the array exceeds max cookie size.
+ */
+ public abstract void updateInstantAppCookie(@Nullable byte[] cookie);
+
+ /**
+ * @removed
+ * @hide
*/
public abstract boolean setInstantAppCookie(@Nullable byte[] cookie);
@@ -3934,9 +3956,6 @@
* @param flags To filter the libraries to return.
* @return The shared library list.
*
- * @see #MATCH_FACTORY_ONLY
- * @see #MATCH_KNOWN_PACKAGES
- * @see #MATCH_ANY_USER
* @see #MATCH_UNINSTALLED_PACKAGES
*/
public abstract @NonNull List<SharedLibraryInfo> getSharedLibraries(
@@ -5940,8 +5959,20 @@
* <p>
* This hint can only be set by the app which installed this package, as
* determined by {@link #getInstallerPackageName(String)}.
+ *
+ * @param packageName the package to change the category hint for.
+ * @param categoryHint the category hint to set; one of
+ * {@link ApplicationInfo#CATEGORY_AUDIO},
+ * {@link ApplicationInfo#CATEGORY_GAME},
+ * {@link ApplicationInfo#CATEGORY_IMAGE},
+ * {@link ApplicationInfo#CATEGORY_MAPS},
+ * {@link ApplicationInfo#CATEGORY_NEWS},
+ * {@link ApplicationInfo#CATEGORY_PRODUCTIVITY},
+ * {@link ApplicationInfo#CATEGORY_SOCIAL},
+ * {@link ApplicationInfo#CATEGORY_UNDEFINED}, or
+ * {@link ApplicationInfo#CATEGORY_VIDEO}.
*/
- public abstract void setApplicationCategoryHint(String packageName,
+ public abstract void setApplicationCategoryHint(@NonNull String packageName,
@ApplicationInfo.Category int categoryHint);
/** {@hide} */
@@ -6293,4 +6324,12 @@
*/
@SystemApi
public abstract ComponentName getInstantAppInstallerComponent();
+
+ /**
+ * Return the Android Id for a given Instant App.
+ *
+ * @see {@link android.provider.Settings.Secure#ANDROID_ID}
+ * @hide
+ */
+ public abstract String getInstantAppAndroidId(String packageName, @NonNull UserHandle user);
}
diff --git a/core/java/android/content/pm/ShortcutManager.java b/core/java/android/content/pm/ShortcutManager.java
index b992d29..a7c09b5 100644
--- a/core/java/android/content/pm/ShortcutManager.java
+++ b/core/java/android/content/pm/ShortcutManager.java
@@ -17,8 +17,6 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.annotation.SdkConstant;
-import android.annotation.SdkConstant.SdkConstantType;
import android.annotation.TestApi;
import android.annotation.UserIdInt;
import android.app.Activity;
@@ -26,15 +24,12 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentSender;
-import android.os.Binder;
-import android.os.Parcel;
-import android.os.Parcelable;
+import android.os.Build.VERSION_CODES;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.Preconditions;
import java.util.List;
@@ -289,6 +284,12 @@
* <p><b>Note:</b> If the user doesn't allow the shortcut to be pinned to the launcher, the
* pinning process fails, and the {@link Intent} object that is passed into this
* {@link android.app.PendingIntent} object isn't executed.
+ * <div class="note"><p><b>Note:</b> Due to background execution limits introduced in Android
+ * {@link VERSION_CODES#O}, it's best to use a
+ * <a href="{@docRoot}guide/components/broadcasts.html#manifest-declared_receivers">
+ * manifest-declared receiver</a> to receive a callback.
+ * <p>Also, to prevent other apps from invoking the receiver, add the attribute assignment
+ * <code>android:exported="false"</code> to the receiver's manifest entry.</p></div>
* </ul>
*
* The following code snippet shows how to pin a single shortcut that already exists and is enabled:
@@ -313,10 +314,8 @@
* // needs to be notified that the user allowed the shortcut to be pinned.
* // Use a boolean value, such as "appNeedsNotifying", to define this behavior.
* if (appNeedsNotifying) {
- * // We assume here that the app has implemented a method called
- * // createShortcutResultIntent() that returns a broadcast intent.
- * Intent pinnedShortcutCallbackIntent =
- * createShortcutResultIntent(pinShortcutInfo);
+ * // We assume here the app has a manifest-declared receiver "MyReceiver".
+ * Intent pinnedShortcutCallbackIntent = new Intent(context, MyReceiver.class);
*
* // Configure the intent so that your app's broadcast receiver gets
* // the callback successfully.
@@ -921,6 +920,9 @@
/**
* Return {@code TRUE} if the app is running on a device whose default launcher supports
* {@link #requestPinShortcut(ShortcutInfo, IntentSender)}.
+ *
+ * <p><b>Note:</b> The return value may change in subsequent calls, if the user changes
+ * the default launcher app.
*/
public boolean isRequestPinShortcutSupported() {
try {
@@ -952,6 +954,8 @@
* set.
* @param resultIntent If not null, this intent will be sent when the shortcut is pinned.
* Use {@link android.app.PendingIntent#getIntentSender()} to create an {@link IntentSender}.
+ * To avoid background execution limits, use an unexported, manifest-declared receiver.
+ * For more details, see the overview documentation for the {@link ShortcutManager} class.
*
* @return {@code TRUE} if the launcher supports this feature. Note the API will return without
* waiting for the user to respond, so getting {@code TRUE} from this API does *not* mean
diff --git a/core/java/android/content/res/TypedArray.java b/core/java/android/content/res/TypedArray.java
index f48afb5..88bb1a4 100644
--- a/core/java/android/content/res/TypedArray.java
+++ b/core/java/android/content/res/TypedArray.java
@@ -56,12 +56,13 @@
// Reset the assets, which may have changed due to configuration changes
// or further resource loading.
attrs.mAssets = res.getAssets();
+ attrs.mMetrics = res.getDisplayMetrics();
attrs.resize(len);
return attrs;
}
private final Resources mResources;
- private final DisplayMetrics mMetrics;
+ private DisplayMetrics mMetrics;
private AssetManager mAssets;
private boolean mRecycled;
diff --git a/core/java/android/hardware/Sensor.java b/core/java/android/hardware/Sensor.java
index a895f82..f02e484 100644
--- a/core/java/android/hardware/Sensor.java
+++ b/core/java/android/hardware/Sensor.java
@@ -664,7 +664,7 @@
* @see #TYPE_LOW_LATENCY_OFFBODY_DETECT
*/
public static final String STRING_TYPE_LOW_LATENCY_OFFBODY_DETECT =
- "android.sensor.low_latency_offbody";
+ "android.sensor.low_latency_offbody_detect";
/**
* A constant describing an uncalibrated accelerometer sensor.
diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
index afca0b0..bf7207c 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -19,6 +19,7 @@
import android.os.Parcel;
import android.os.Parcelable;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.BitUtils;
import java.util.Objects;
@@ -230,7 +231,8 @@
* Capabilities that suggest that a network is restricted.
* {@see #maybeMarkCapabilitiesRestricted}.
*/
- private static final long RESTRICTED_CAPABILITIES =
+ @VisibleForTesting
+ /* package */ static final long RESTRICTED_CAPABILITIES =
(1 << NET_CAPABILITY_CBS) |
(1 << NET_CAPABILITY_DUN) |
(1 << NET_CAPABILITY_EIMS) |
@@ -241,6 +243,17 @@
(1 << NET_CAPABILITY_XCAP);
/**
+ * Capabilities that suggest that a network is unrestricted.
+ * {@see #maybeMarkCapabilitiesRestricted}.
+ */
+ @VisibleForTesting
+ /* package */ static final long UNRESTRICTED_CAPABILITIES =
+ (1 << NET_CAPABILITY_INTERNET) |
+ (1 << NET_CAPABILITY_MMS) |
+ (1 << NET_CAPABILITY_SUPL) |
+ (1 << NET_CAPABILITY_WIFI_P2P);
+
+ /**
* Adds the given capability to this {@code NetworkCapability} instance.
* Multiple capabilities may be applied sequentially. Note that when searching
* for a network to satisfy a request, all capabilities requested must be satisfied.
@@ -353,12 +366,16 @@
* @hide
*/
public void maybeMarkCapabilitiesRestricted() {
- // If all the capabilities are typically provided by restricted networks, conclude that this
- // network is restricted.
- if ((mNetworkCapabilities & ~(DEFAULT_CAPABILITIES | RESTRICTED_CAPABILITIES)) == 0 &&
- // Must have at least some restricted capabilities, otherwise a request for an
- // internet-less network will get marked restricted.
- (mNetworkCapabilities & RESTRICTED_CAPABILITIES) != 0) {
+ // Verify there aren't any unrestricted capabilities. If there are we say
+ // the whole thing is unrestricted.
+ final boolean hasUnrestrictedCapabilities =
+ ((mNetworkCapabilities & UNRESTRICTED_CAPABILITIES) != 0);
+
+ // Must have at least some restricted capabilities.
+ final boolean hasRestrictedCapabilities =
+ ((mNetworkCapabilities & RESTRICTED_CAPABILITIES) != 0);
+
+ if (hasRestrictedCapabilities && !hasUnrestrictedCapabilities) {
removeCapability(NET_CAPABILITY_NOT_RESTRICTED);
}
}
diff --git a/core/java/android/net/nsd/NsdManager.java b/core/java/android/net/nsd/NsdManager.java
index 33d12a3..1dde3ca 100644
--- a/core/java/android/net/nsd/NsdManager.java
+++ b/core/java/android/net/nsd/NsdManager.java
@@ -45,7 +45,7 @@
* http://files.dns-sd.org/draft-cheshire-dnsext-dns-sd.txt
*
* <p> The API is asynchronous and responses to requests from an application are on listener
- * callbacks on a seperate thread.
+ * callbacks on a seperate internal thread.
*
* <p> There are three main operations the API supports - registration, discovery and resolution.
* <pre>
@@ -119,8 +119,8 @@
* {@see NsdServiceInfo}
*/
public final class NsdManager {
- private static final String TAG = "NsdManager";
- INsdManager mService;
+ private static final String TAG = NsdManager.class.getSimpleName();
+ private static final boolean DBG = false;
/**
* Broadcast intent action to indicate whether network service discovery is
@@ -130,8 +130,7 @@
* @see #EXTRA_NSD_STATE
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_NSD_STATE_CHANGED =
- "android.net.nsd.STATE_CHANGED";
+ public static final String ACTION_NSD_STATE_CHANGED = "android.net.nsd.STATE_CHANGED";
/**
* The lookup key for an int that indicates whether network service discovery is enabled
@@ -208,13 +207,47 @@
/** Dns based service discovery protocol */
public static final int PROTOCOL_DNS_SD = 0x0001;
- private Context mContext;
+ private static final SparseArray<String> EVENT_NAMES = new SparseArray<>();
+ static {
+ EVENT_NAMES.put(DISCOVER_SERVICES, "DISCOVER_SERVICES");
+ EVENT_NAMES.put(DISCOVER_SERVICES_STARTED, "DISCOVER_SERVICES_STARTED");
+ EVENT_NAMES.put(DISCOVER_SERVICES_FAILED, "DISCOVER_SERVICES_FAILED");
+ EVENT_NAMES.put(SERVICE_FOUND, "SERVICE_FOUND");
+ EVENT_NAMES.put(SERVICE_LOST, "SERVICE_LOST");
+ EVENT_NAMES.put(STOP_DISCOVERY, "STOP_DISCOVERY");
+ EVENT_NAMES.put(STOP_DISCOVERY_FAILED, "STOP_DISCOVERY_FAILED");
+ EVENT_NAMES.put(STOP_DISCOVERY_SUCCEEDED, "STOP_DISCOVERY_SUCCEEDED");
+ EVENT_NAMES.put(REGISTER_SERVICE, "REGISTER_SERVICE");
+ EVENT_NAMES.put(REGISTER_SERVICE_FAILED, "REGISTER_SERVICE_FAILED");
+ EVENT_NAMES.put(REGISTER_SERVICE_SUCCEEDED, "REGISTER_SERVICE_SUCCEEDED");
+ EVENT_NAMES.put(UNREGISTER_SERVICE, "UNREGISTER_SERVICE");
+ EVENT_NAMES.put(UNREGISTER_SERVICE_FAILED, "UNREGISTER_SERVICE_FAILED");
+ EVENT_NAMES.put(UNREGISTER_SERVICE_SUCCEEDED, "UNREGISTER_SERVICE_SUCCEEDED");
+ EVENT_NAMES.put(RESOLVE_SERVICE, "RESOLVE_SERVICE");
+ EVENT_NAMES.put(RESOLVE_SERVICE_FAILED, "RESOLVE_SERVICE_FAILED");
+ EVENT_NAMES.put(RESOLVE_SERVICE_SUCCEEDED, "RESOLVE_SERVICE_SUCCEEDED");
+ EVENT_NAMES.put(ENABLE, "ENABLE");
+ EVENT_NAMES.put(DISABLE, "DISABLE");
+ EVENT_NAMES.put(NATIVE_DAEMON_EVENT, "NATIVE_DAEMON_EVENT");
+ }
+
+ /** @hide */
+ public static String nameOf(int event) {
+ String name = EVENT_NAMES.get(event);
+ if (name == null) {
+ return Integer.toString(event);
+ }
+ return name;
+ }
+
+ private final INsdManager mService;
+ private final Context mContext;
private static final int INVALID_LISTENER_KEY = 0;
private static final int BUSY_LISTENER_KEY = -1;
private int mListenerKey = 1;
private final SparseArray mListenerMap = new SparseArray();
- private final SparseArray<NsdServiceInfo> mServiceMap = new SparseArray<NsdServiceInfo>();
+ private final SparseArray<NsdServiceInfo> mServiceMap = new SparseArray<>();
private final Object mMapLock = new Object();
private final AsyncChannel mAsyncChannel = new AsyncChannel();
@@ -300,6 +333,7 @@
@Override
public void handleMessage(Message message) {
+ if (DBG) Log.d(TAG, "received " + nameOf(message.what));
switch (message.what) {
case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
mAsyncChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION);
@@ -377,7 +411,6 @@
// if the listener is already in the map, reject it. Otherwise, add it and
// return its key.
-
private int putListener(Object listener, NsdServiceInfo s) {
if (listener == null) return INVALID_LISTENER_KEY;
int key;
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 832031e..235f24c 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -1365,8 +1365,6 @@
public static final int EVENT_WAKEUP_AP = 0x0013;
// Event for reporting that a specific partial wake lock has been held for a long duration.
public static final int EVENT_LONG_WAKE_LOCK = 0x0014;
- // Event reporting the new estimated (learned) capacity of the battery in mAh.
- public static final int EVENT_ESTIMATED_BATTERY_CAP = 0x0015;
// Number of event types.
public static final int EVENT_COUNT = 0x0016;
@@ -2501,6 +2499,16 @@
public abstract int getEstimatedBatteryCapacity();
/**
+ * @return The minimum learned battery capacity in uAh.
+ */
+ public abstract int getMinLearnedBatteryCapacity();
+
+ /**
+ * @return The maximum learned battery capacity in uAh.
+ */
+ public abstract int getMaxLearnedBatteryCapacity() ;
+
+ /**
* Return the array of discharge step durations.
*/
public abstract LevelStepTracker getDischargeLevelStepTracker();
@@ -2990,13 +2998,14 @@
final String category = STAT_NAMES[which];
// Dump "battery" stat
- dumpLine(pw, 0 /* uid */, category, BATTERY_DATA,
+ dumpLine(pw, 0 /* uid */, category, BATTERY_DATA,
which == STATS_SINCE_CHARGED ? getStartCount() : "N/A",
whichBatteryRealtime / 1000, whichBatteryUptime / 1000,
totalRealtime / 1000, totalUptime / 1000,
getStartClockTime(),
whichBatteryScreenOffRealtime / 1000, whichBatteryScreenOffUptime / 1000,
- getEstimatedBatteryCapacity());
+ getEstimatedBatteryCapacity(),
+ getMinLearnedBatteryCapacity(), getMaxLearnedBatteryCapacity());
// Calculate wakelock times across all uids.
@@ -3583,6 +3592,25 @@
pw.println(sb.toString());
}
+ final int minLearnedBatteryCapacity = getMinLearnedBatteryCapacity();
+ if (minLearnedBatteryCapacity > 0) {
+ sb.setLength(0);
+ sb.append(prefix);
+ sb.append(" Min learned battery capacity: ");
+ sb.append(BatteryStatsHelper.makemAh(minLearnedBatteryCapacity / 1000));
+ sb.append(" mAh");
+ pw.println(sb.toString());
+ }
+ final int maxLearnedBatteryCapacity = getMaxLearnedBatteryCapacity();
+ if (maxLearnedBatteryCapacity > 0) {
+ sb.setLength(0);
+ sb.append(prefix);
+ sb.append(" Max learned battery capacity: ");
+ sb.append(BatteryStatsHelper.makemAh(maxLearnedBatteryCapacity / 1000));
+ sb.append(" mAh");
+ pw.println(sb.toString());
+ }
+
sb.setLength(0);
sb.append(prefix);
sb.append(" Time on battery: ");
diff --git a/core/java/android/os/ConfigUpdate.java b/core/java/android/os/ConfigUpdate.java
index 793a90e..1396877 100644
--- a/core/java/android/os/ConfigUpdate.java
+++ b/core/java/android/os/ConfigUpdate.java
@@ -74,6 +74,21 @@
@SystemApi
public static final String ACTION_UPDATE_TZDATA = "android.intent.action.UPDATE_TZDATA";
+ /**
+ * Update language detection model file.
+ * @hide
+ */
+ @SystemApi
+ public static final String ACTION_UPDATE_LANG_ID = "android.intent.action.UPDATE_LANG_ID";
+
+ /**
+ * Update smart selection model file.
+ * @hide
+ */
+ @SystemApi
+ public static final String ACTION_UPDATE_SMART_SELECTION
+ = "android.intent.action.UPDATE_SMART_SELECTION";
+
private ConfigUpdate() {
}
}
diff --git a/core/java/android/os/HwParcel.java b/core/java/android/os/HwParcel.java
index 94fd5b0..4ba1144 100644
--- a/core/java/android/os/HwParcel.java
+++ b/core/java/android/os/HwParcel.java
@@ -209,10 +209,11 @@
public native final IHwBinder readStrongBinder();
// Handle is stored as part of the blob.
- public native final HwBlob readBuffer();
+ public native final HwBlob readBuffer(long expectedSize);
public native final HwBlob readEmbeddedBuffer(
- long parentHandle, long offset, boolean nullable);
+ long expectedSize, long parentHandle, long offset,
+ boolean nullable);
public native final void writeBuffer(HwBlob blob);
diff --git a/core/java/android/os/RecoverySystem.java b/core/java/android/os/RecoverySystem.java
index bb0fdbe..447f280 100644
--- a/core/java/android/os/RecoverySystem.java
+++ b/core/java/android/os/RecoverySystem.java
@@ -353,9 +353,7 @@
if (list.isEmpty()) {
throw new IOException("no entries found in the compatibility file");
}
- // TODO(b/36814503): Enable the actual verification when VintfObject APIs are ready.
- // return (VintfObject.verify(list.toArray(new String[list.size()])) == 0);
- return true;
+ return (VintfObject.verify(list.toArray(new String[list.size()])) == 0);
}
/**
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 3942531..1c15004 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -1518,7 +1518,8 @@
* last to be deleted when additional disk space is needed.
* <p>
* This quota will change over time depending on how frequently the user
- * interacts with your app, and depending on how much disk space is used.
+ * interacts with your app, and depending on how much system-wide disk space
+ * is used.
* <p class="note">
* Note: if your app uses the {@code android:sharedUserId} manifest feature,
* then cached data for all packages in your shared UID is tracked together
diff --git a/core/java/android/provider/FontsContract.java b/core/java/android/provider/FontsContract.java
index e9ef770..34c77b6 100644
--- a/core/java/android/provider/FontsContract.java
+++ b/core/java/android/provider/FontsContract.java
@@ -78,6 +78,10 @@
* client application.
*/
public static final class Columns implements BaseColumns {
+
+ // Do not instantiate.
+ private Columns() {}
+
/**
* Constant used to request data from a font provider. The cursor returned from the query
* may populate this column with a long for the font file ID. The client will request a file
@@ -283,6 +287,12 @@
*/
public static final int STATUS_UNEXPECTED_DATA_PROVIDED = 2;
+ /**
+ * Constant represents that the fetching font data was rejected by system. This happens if
+ * the passed context is restricted.
+ */
+ public static final int STATUS_REJECTED = 3;
+
/** @hide */
@IntDef({STATUS_OK, STATUS_WRONG_CERTIFICATES, STATUS_UNEXPECTED_DATA_PROVIDED})
@Retention(RetentionPolicy.SOURCE)
@@ -555,6 +565,10 @@
public static @NonNull FontFamilyResult fetchFonts(
@NonNull Context context, @Nullable CancellationSignal cancellationSignal,
@NonNull FontRequest request) throws NameNotFoundException {
+ if (context.isRestricted()) {
+ // TODO: Should we allow if the peer process is system or myself?
+ return new FontFamilyResult(FontFamilyResult.STATUS_REJECTED, null);
+ }
ProviderInfo providerInfo = getProvider(context.getPackageManager(), request);
if (providerInfo == null) {
return new FontFamilyResult(FontFamilyResult.STATUS_WRONG_CERTIFICATES, null);
@@ -590,6 +604,10 @@
public static Typeface buildTypeface(@NonNull Context context,
@Nullable CancellationSignal cancellationSignal, @NonNull FontInfo[] fonts,
int weight, boolean italic, @Nullable String fallbackFontName) {
+ if (context.isRestricted()) {
+ // TODO: Should we allow if the peer process is system or myself?
+ return null;
+ }
final Map<Uri, ByteBuffer> uriBuffer =
prepareFontData(context, fonts, cancellationSignal);
return new Typeface.Builder(fonts, uriBuffer)
@@ -613,6 +631,10 @@
*/
public static Typeface buildTypeface(@NonNull Context context,
@Nullable CancellationSignal cancellationSignal, @NonNull FontInfo[] fonts) {
+ if (context.isRestricted()) {
+ // TODO: Should we allow if the peer process is system or myself?
+ return null;
+ }
final Map<Uri, ByteBuffer> uriBuffer =
prepareFontData(context, fonts, cancellationSignal);
return new Typeface.Builder(fonts, uriBuffer).build();
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index f32f163..f9d81da 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -5082,6 +5082,10 @@
* (available on certain devices running Android 4.2 or higher), each user appears as a
* completely separate device, so the {@code ANDROID_ID} value is unique to each
* user.</p>
+ *
+ * <p class="note"><strong>Note:</strong> If the caller is an Instant App the id is scoped
+ * to the Instant App, it is generated when the Instant App is first installed and reset if
+ * the user clears the Instant App.
*/
public static final String ANDROID_ID = "android_id";
@@ -9517,6 +9521,32 @@
"intent_firewall_metadata_url";
/**
+ * URL for lang id model updates
+ * @hide
+ */
+ public static final String LANG_ID_UPDATE_CONTENT_URL = "lang_id_content_url";
+
+ /**
+ * URL for lang id model update metadata
+ * @hide
+ */
+ public static final String LANG_ID_UPDATE_METADATA_URL = "lang_id_metadata_url";
+
+ /**
+ * URL for smart selection model updates
+ * @hide
+ */
+ public static final String SMART_SELECTION_UPDATE_CONTENT_URL =
+ "smart_selection_content_url";
+
+ /**
+ * URL for smart selection model update metadata
+ * @hide
+ */
+ public static final String SMART_SELECTION_UPDATE_METADATA_URL =
+ "smart_selection_metadata_url";
+
+ /**
* SELinux enforcement status. If 0, permissive; if 1, enforcing.
* @hide
*/
diff --git a/core/java/android/text/style/AccessibilityClickableSpan.java b/core/java/android/text/style/AccessibilityClickableSpan.java
index 9c305ff..7f39cc1 100644
--- a/core/java/android/text/style/AccessibilityClickableSpan.java
+++ b/core/java/android/text/style/AccessibilityClickableSpan.java
@@ -16,6 +16,9 @@
package android.text.style;
import static android.view.accessibility.AccessibilityNodeInfo.ACTION_ARGUMENT_ACCESSIBLE_CLICKABLE_SPAN;
+import static android.view.accessibility.AccessibilityNodeInfo.UNDEFINED_CONNECTION_ID;
+import static android.view.accessibility.AccessibilityNodeInfo.UNDEFINED_NODE_ID;
+import static android.view.accessibility.AccessibilityWindowInfo.UNDEFINED_WINDOW_ID;
import android.os.Bundle;
import android.os.Parcel;
@@ -24,13 +27,11 @@
import android.text.Spanned;
import android.text.TextUtils;
import android.view.View;
+import android.view.accessibility.AccessibilityInteractionClient;
import android.view.accessibility.AccessibilityNodeInfo;
import com.android.internal.R;
-import java.lang.ref.WeakReference;
-
-
/**
* {@link ClickableSpan} cannot be parceled, but accessibility services need to be able to cause
* their callback handlers to be called. This class serves as a parcelable placeholder for the
@@ -47,10 +48,9 @@
// The id of the span this one replaces
private final int mOriginalClickableSpanId;
- // Only retain a weak reference to the node to avoid referencing cycles that could create memory
- // leaks.
- private WeakReference<AccessibilityNodeInfo> mAccessibilityNodeInfoRef;
-
+ private int mWindowId = UNDEFINED_WINDOW_ID;
+ private long mSourceNodeId = UNDEFINED_NODE_ID;
+ private int mConnectionId = UNDEFINED_CONNECTION_ID;
/**
* @param originalClickableSpanId The id of the span this one replaces
@@ -110,13 +110,15 @@
}
/**
- * Set the accessibilityNodeInfo that this placeholder belongs to. This node is not
- * included in the parceling logic, and must be set to allow the onClick handler to function.
+ * Configure this object to perform clicks on the view that contains the original span.
*
- * @param accessibilityNodeInfo The info this span is part of
+ * @param accessibilityNodeInfo The info corresponding to the view containing the original
+ * span.
*/
- public void setAccessibilityNodeInfo(AccessibilityNodeInfo accessibilityNodeInfo) {
- mAccessibilityNodeInfoRef = new WeakReference<>(accessibilityNodeInfo);
+ public void copyConnectionDataFrom(AccessibilityNodeInfo accessibilityNodeInfo) {
+ mConnectionId = accessibilityNodeInfo.getConnectionId();
+ mWindowId = accessibilityNodeInfo.getWindowId();
+ mSourceNodeId = accessibilityNodeInfo.getSourceNodeId();
}
/**
@@ -128,17 +130,18 @@
*/
@Override
public void onClick(View unused) {
- if (mAccessibilityNodeInfoRef == null) {
- return;
- }
- AccessibilityNodeInfo info = mAccessibilityNodeInfoRef.get();
- if (info == null) {
- return;
- }
Bundle arguments = new Bundle();
arguments.putParcelable(ACTION_ARGUMENT_ACCESSIBLE_CLICKABLE_SPAN, this);
- info.performAction(R.id.accessibilityActionClickOnClickableSpan, arguments);
+ if ((mWindowId == UNDEFINED_WINDOW_ID) || (mSourceNodeId == UNDEFINED_NODE_ID)
+ || (mConnectionId == UNDEFINED_CONNECTION_ID)) {
+ throw new RuntimeException(
+ "ClickableSpan for accessibility service not properly initialized");
+ }
+
+ AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
+ client.performAccessibilityAction(mConnectionId, mWindowId, mSourceNodeId,
+ R.id.accessibilityActionClickOnClickableSpan, arguments);
}
public static final Parcelable.Creator<AccessibilityClickableSpan> CREATOR =
diff --git a/core/java/android/text/style/AccessibilityURLSpan.java b/core/java/android/text/style/AccessibilityURLSpan.java
index 0147009..bd81623 100644
--- a/core/java/android/text/style/AccessibilityURLSpan.java
+++ b/core/java/android/text/style/AccessibilityURLSpan.java
@@ -73,7 +73,7 @@
* Delegated to AccessibilityClickableSpan
* @param accessibilityNodeInfo
*/
- public void setAccessibilityNodeInfo(AccessibilityNodeInfo accessibilityNodeInfo) {
- mAccessibilityClickableSpan.setAccessibilityNodeInfo(accessibilityNodeInfo);
+ public void copyConnectionDataFrom(AccessibilityNodeInfo accessibilityNodeInfo) {
+ mAccessibilityClickableSpan.copyConnectionDataFrom(accessibilityNodeInfo);
}
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 9df7de8..bcf0b90 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -3887,6 +3887,10 @@
private Drawable mDefaultFocusHighlight;
private Drawable mDefaultFocusHighlightCache;
private boolean mDefaultFocusHighlightSizeChanged;
+ /**
+ * True if the default focus highlight is needed on the target device.
+ */
+ private static boolean sUseDefaultFocusHighlight;
private String mTransitionName;
@@ -4464,6 +4468,9 @@
sAutoFocusableOffUIThreadWontNotifyParents = targetSdkVersion < Build.VERSION_CODES.O;
+ sUseDefaultFocusHighlight = context.getResources().getBoolean(
+ com.android.internal.R.bool.config_useDefaultFocusHighlight);
+
sCompatibilityDone = true;
}
}
@@ -7273,7 +7280,8 @@
* <li>The view contents does not include PII (Personally Identifiable Information), so it
* can call {@link ViewStructure#setDataIsSensitive(boolean)} passing {@code false}.
* <li>It must set fields such {@link ViewStructure#setText(CharSequence)},
- * {@link ViewStructure#setAutofillOptions(String[])}, or {@link ViewStructure#setUrl(String)}.
+ * {@link ViewStructure#setAutofillOptions(CharSequence[])},
+ * or {@link ViewStructure#setUrl(String)}.
* </ol>
*
* @param structure Fill in with structured view data. The default implementation
@@ -7530,7 +7538,11 @@
@ViewDebug.ExportedProperty(mapping = {
@ViewDebug.IntToString(from = IMPORTANT_FOR_AUTOFILL_AUTO, to = "auto"),
@ViewDebug.IntToString(from = IMPORTANT_FOR_AUTOFILL_YES, to = "yes"),
- @ViewDebug.IntToString(from = IMPORTANT_FOR_AUTOFILL_NO, to = "no")})
+ @ViewDebug.IntToString(from = IMPORTANT_FOR_AUTOFILL_NO, to = "no"),
+ @ViewDebug.IntToString(from = IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS,
+ to = "yesExcludeDescendants"),
+ @ViewDebug.IntToString(from = IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS,
+ to = "noExcludeDescendants")})
public @AutofillImportance int getImportantForAutofill() {
return (mPrivateFlags3
& PFLAG3_IMPORTANT_FOR_AUTOFILL_MASK) >> PFLAG3_IMPORTANT_FOR_AUTOFILL_SHIFT;
@@ -7542,7 +7554,8 @@
* <p>See {@link #setImportantForAutofill(int)} for more info about this mode.
*
* @param mode {@link #IMPORTANT_FOR_AUTOFILL_AUTO}, {@link #IMPORTANT_FOR_AUTOFILL_YES},
- * or {@link #IMPORTANT_FOR_AUTOFILL_NO}.
+ * {@link #IMPORTANT_FOR_AUTOFILL_NO}, {@link #IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS},
+ * or {@link #IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS}.
*
* @attr ref android.R.styleable#View_importantForAutofill
*/
@@ -9732,7 +9745,7 @@
@ViewDebug.IntToString(from = NOT_FOCUSABLE, to = "NOT_FOCUSABLE"),
@ViewDebug.IntToString(from = FOCUSABLE, to = "FOCUSABLE"),
@ViewDebug.IntToString(from = FOCUSABLE_AUTO, to = "FOCUSABLE_AUTO")
- })
+ }, category = "focus")
@Focusable
public int getFocusable() {
return (mViewFlags & FOCUSABLE_AUTO) > 0 ? FOCUSABLE_AUTO : mViewFlags & FOCUSABLE;
@@ -9746,7 +9759,7 @@
* @return Whether the view is focusable in touch mode.
* @attr ref android.R.styleable#View_focusableInTouchMode
*/
- @ViewDebug.ExportedProperty
+ @ViewDebug.ExportedProperty(category = "focus")
public final boolean isFocusableInTouchMode() {
return FOCUSABLE_IN_TOUCH_MODE == (mViewFlags & FOCUSABLE_IN_TOUCH_MODE);
}
@@ -9774,7 +9787,7 @@
* @return True if this view is a root of a cluster, or false otherwise.
* @attr ref android.R.styleable#View_keyboardNavigationCluster
*/
- @ViewDebug.ExportedProperty(category = "keyboardNavigationCluster")
+ @ViewDebug.ExportedProperty(category = "focus")
public final boolean isKeyboardNavigationCluster() {
return (mPrivateFlags3 & PFLAG3_CLUSTER) != 0;
}
@@ -9849,7 +9862,7 @@
* @return {@code true} if this view is the default-focus view, {@code false} otherwise
* @attr ref android.R.styleable#View_focusedByDefault
*/
- @ViewDebug.ExportedProperty(category = "focusedByDefault")
+ @ViewDebug.ExportedProperty(category = "focus")
public final boolean isFocusedByDefault() {
return (mPrivateFlags3 & PFLAG3_FOCUSED_BY_DEFAULT) != 0;
}
@@ -9962,7 +9975,7 @@
* @return True if this View should use a default focus highlight.
* @attr ref android.R.styleable#View_defaultFocusHighlightEnabled
*/
- @ViewDebug.ExportedProperty(category = "defaultFocusHighlightEnabled")
+ @ViewDebug.ExportedProperty(category = "focus")
public final boolean getDefaultFocusHighlightEnabled() {
return mDefaultFocusHighlightEnabled;
}
@@ -19677,7 +19690,7 @@
final boolean hasFocusStateSpecified = background == null || !background.isStateful()
|| !background.hasFocusStateSpecified();
return !isInTouchMode() && getDefaultFocusHighlightEnabled() && hasFocusStateSpecified
- && isAttachedToWindow();
+ && isAttachedToWindow() && sUseDefaultFocusHighlight;
}
/**
@@ -25785,6 +25798,7 @@
// focus
stream.addProperty("focus:hasFocus", hasFocus());
stream.addProperty("focus:isFocused", isFocused());
+ stream.addProperty("focus:focusable", getFocusable());
stream.addProperty("focus:isFocusable", isFocusable());
stream.addProperty("focus:isFocusableInTouchMode", isFocusableInTouchMode());
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index d4000113..1977ef5 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -1300,6 +1300,7 @@
/**
* Check whether this ViewGroup should ignore focus requests for itself and its children.
*/
+ @ViewDebug.ExportedProperty(category = "focus")
public boolean getTouchscreenBlocksFocus() {
return (mGroupFlags & FLAG_TOUCHSCREEN_BLOCKS_FOCUS) != 0;
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 080ffeb..9ecced6 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -4675,7 +4675,8 @@
if (focused == null && mView.restoreDefaultFocus()) {
return true;
}
- View cluster = focused.keyboardNavigationClusterSearch(null, direction);
+ View cluster = focused == null ? keyboardNavigationClusterSearch(null, direction)
+ : focused.keyboardNavigationClusterSearch(null, direction);
// Since requestFocus only takes "real" focus directions (and therefore also
// restoreFocusInCluster), convert forward/backward focus into FOCUS_DOWN.
diff --git a/core/java/android/view/ViewStructure.java b/core/java/android/view/ViewStructure.java
index 92b0d98..435610e 100644
--- a/core/java/android/view/ViewStructure.java
+++ b/core/java/android/view/ViewStructure.java
@@ -314,7 +314,7 @@
* <p>Typically used by nodes whose {@link View#getAutofillType()} is a list to indicate the
* meaning of each possible value in the list.
*/
- public abstract void setAutofillOptions(String[] options);
+ public abstract void setAutofillOptions(CharSequence[] options);
/**
* Sets the {@link android.text.InputType} bits of this node.
diff --git a/core/java/android/view/accessibility/AccessibilityManager.java b/core/java/android/view/accessibility/AccessibilityManager.java
index 41f1df7..6c884c4 100644
--- a/core/java/android/view/accessibility/AccessibilityManager.java
+++ b/core/java/android/view/accessibility/AccessibilityManager.java
@@ -183,13 +183,17 @@
* Listener for changes to the state of accessibility services. Changes include services being
* enabled or disabled, or changes to the {@link AccessibilityServiceInfo} of a running service.
* {@see #addAccessibilityServicesStateChangeListener}.
+ *
+ * @hide
*/
public interface AccessibilityServicesStateChangeListener {
/**
* Called when the state of accessibility services changes.
+ *
+ * @param manager The manager that is calling back
*/
- void onAccessibilityServicesStateChanged();
+ void onAccessibilityServicesStateChanged(AccessibilityManager manager);
}
/**
@@ -614,11 +618,13 @@
*
* @param listener The listener.
* @return True if successfully registered.
+ *
+ * @hide
*/
- public boolean addAccessibilityServicesStateChangeListener(
+ public void addAccessibilityServicesStateChangeListener(
@NonNull AccessibilityServicesStateChangeListener listener) {
// Final CopyOnWriteArrayList - no lock needed.
- return mServicesStateChangeListeners.add(listener);
+ mServicesStateChangeListeners.add(listener);
}
/**
@@ -626,11 +632,13 @@
*
* @param listener The listener.
* @return True if successfully unregistered.
+ *
+ * @hide
*/
- public boolean removeAccessibilityServicesStateChangeListener(
+ public void removeAccessibilityServicesStateChangeListener(
@NonNull AccessibilityServicesStateChangeListener listener) {
// Final CopyOnWriteArrayList - no lock needed.
- return mServicesStateChangeListeners.remove(listener);
+ mServicesStateChangeListeners.remove(listener);
}
/**
@@ -969,7 +977,7 @@
private void handleNotifyServicesStateChanged() {
// Listeners are a final CopyOnWriteArrayList, hence no lock needed.
for (AccessibilityServicesStateChangeListener listener : mServicesStateChangeListeners) {
- listener.onAccessibilityServicesStateChanged();
+ listener.onAccessibilityServicesStateChanged(this);
}
}
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index 255574f..94a4547 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -695,7 +695,7 @@
private boolean mSealed;
// Data.
- private int mWindowId = UNDEFINED_ITEM_ID;
+ private int mWindowId = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID;
private long mSourceNodeId = UNDEFINED_NODE_ID;
private long mParentNodeId = UNDEFINED_NODE_ID;
private long mLabelForId = UNDEFINED_NODE_ID;
@@ -2417,12 +2417,12 @@
AccessibilityClickableSpan[] clickableSpans =
spanned.getSpans(0, mText.length(), AccessibilityClickableSpan.class);
for (int i = 0; i < clickableSpans.length; i++) {
- clickableSpans[i].setAccessibilityNodeInfo(this);
+ clickableSpans[i].copyConnectionDataFrom(this);
}
AccessibilityURLSpan[] urlSpans =
spanned.getSpans(0, mText.length(), AccessibilityURLSpan.class);
for (int i = 0; i < urlSpans.length; i++) {
- urlSpans[i].setAccessibilityNodeInfo(this);
+ urlSpans[i].copyConnectionDataFrom(this);
}
}
return mText;
@@ -2841,6 +2841,17 @@
}
/**
+ * Get the connection ID.
+ *
+ * @return The connection id
+ *
+ * @hide
+ */
+ public int getConnectionId() {
+ return mConnectionId;
+ }
+
+ /**
* {@inheritDoc}
*/
@Override
@@ -3354,7 +3365,7 @@
mLabeledById = UNDEFINED_NODE_ID;
mTraversalBefore = UNDEFINED_NODE_ID;
mTraversalAfter = UNDEFINED_NODE_ID;
- mWindowId = UNDEFINED_ITEM_ID;
+ mWindowId = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID;
mConnectionId = UNDEFINED_CONNECTION_ID;
mMaxTextLength = -1;
mMovementGranularities = 0;
@@ -3517,9 +3528,9 @@
}
private boolean canPerformRequestOverConnection(long accessibilityNodeId) {
- return (mWindowId != UNDEFINED_ITEM_ID
- && getAccessibilityViewId(accessibilityNodeId) != UNDEFINED_ITEM_ID
- && mConnectionId != UNDEFINED_CONNECTION_ID);
+ return ((mWindowId != AccessibilityWindowInfo.UNDEFINED_WINDOW_ID)
+ && (getAccessibilityViewId(accessibilityNodeId) != UNDEFINED_ITEM_ID)
+ && (mConnectionId != UNDEFINED_CONNECTION_ID));
}
@Override
diff --git a/core/java/android/view/textclassifier/TextClassificationResult.java b/core/java/android/view/textclassifier/TextClassificationResult.java
index 8912ef3..e188d11a 100644
--- a/core/java/android/view/textclassifier/TextClassificationResult.java
+++ b/core/java/android/view/textclassifier/TextClassificationResult.java
@@ -47,6 +47,7 @@
@Nullable private final OnClickListener mOnClickListener;
@NonNull private final EntityConfidence<String> mEntityConfidence;
@NonNull private final List<String> mEntities;
+ private int mLogType;
private TextClassificationResult(
@NonNull String text,
@@ -54,7 +55,8 @@
String label,
Intent intent,
OnClickListener onClickListener,
- @NonNull EntityConfidence<String> entityConfidence) {
+ @NonNull EntityConfidence<String> entityConfidence,
+ int logType) {
mText = text;
mIcon = icon;
mLabel = label;
@@ -62,6 +64,7 @@
mOnClickListener = onClickListener;
mEntityConfidence = new EntityConfidence<>(entityConfidence);
mEntities = mEntityConfidence.getEntities();
+ mLogType = logType;
}
/**
@@ -134,6 +137,14 @@
return mOnClickListener;
}
+ /**
+ * Returns the MetricsLogger subtype for the action that is performed for this result.
+ * @hide
+ */
+ public int getLogType() {
+ return mLogType;
+ }
+
@Override
public String toString() {
return String.format("TextClassificationResult {"
@@ -167,6 +178,7 @@
@Nullable private OnClickListener mOnClickListener;
@NonNull private final EntityConfidence<String> mEntityConfidence =
new EntityConfidence<>();
+ private int mLogType;
/**
* Sets the classified text.
@@ -215,6 +227,15 @@
}
/**
+ * Sets the MetricsLogger subtype for the action that is performed for this result.
+ * @hide
+ */
+ public Builder setLogType(int type) {
+ mLogType = type;
+ return this;
+ }
+
+ /**
* Sets an OnClickListener that may be triggered to act on the classified text.
*/
public Builder setOnClickListener(@Nullable OnClickListener onClickListener) {
@@ -227,7 +248,7 @@
*/
public TextClassificationResult build() {
return new TextClassificationResult(
- mText, mIcon, mLabel, mIntent, mOnClickListener, mEntityConfidence);
+ mText, mIcon, mLabel, mIntent, mOnClickListener, mEntityConfidence, mLogType);
}
}
}
diff --git a/core/java/android/view/textclassifier/TextClassifierImpl.java b/core/java/android/view/textclassifier/TextClassifierImpl.java
index f634a1b..246fab3 100644
--- a/core/java/android/view/textclassifier/TextClassifierImpl.java
+++ b/core/java/android/view/textclassifier/TextClassifierImpl.java
@@ -37,6 +37,7 @@
import android.util.Log;
import android.util.Patterns;
import android.view.View;
+import android.widget.TextViewMetrics;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.Preconditions;
@@ -53,7 +54,6 @@
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
-import java.util.StringJoiner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -89,7 +89,7 @@
@Override
public TextSelection suggestSelection(
@NonNull CharSequence text, int selectionStartIndex, int selectionEndIndex,
- LocaleList defaultLocales) {
+ @Nullable LocaleList defaultLocales) {
validateInput(text, selectionStartIndex, selectionEndIndex);
try {
if (text.length() > 0) {
@@ -128,7 +128,8 @@
@Override
public TextClassificationResult getTextClassificationResult(
- @NonNull CharSequence text, int startIndex, int endIndex, LocaleList defaultLocales) {
+ @NonNull CharSequence text, int startIndex, int endIndex,
+ @Nullable LocaleList defaultLocales) {
validateInput(text, startIndex, endIndex);
try {
if (text.length() > 0) {
@@ -156,7 +157,8 @@
}
@Override
- public LinksInfo getLinks(CharSequence text, int linkMask, LocaleList defaultLocales) {
+ public LinksInfo getLinks(
+ @NonNull CharSequence text, int linkMask, @Nullable LocaleList defaultLocales) {
Preconditions.checkArgument(text != null);
try {
return LinksInfoFactory.create(
@@ -199,12 +201,11 @@
@GuardedBy("mSmartSelectionLock") // Do not call outside this lock.
@Nullable
private Locale findBestSupportedLocaleLocked(LocaleList localeList) {
- final List<Locale.LanguageRange> languageRangeList = Locale.LanguageRange.parse(
- new StringJoiner(",")
- // Specified localeList takes priority over the system default
- .add(localeList.toLanguageTags())
- .add(LocaleList.getDefault().toLanguageTags())
- .toString());
+ // Specified localeList takes priority over the system default, so it is listed first.
+ final String languages = localeList.isEmpty()
+ ? LocaleList.getDefault().toLanguageTags()
+ : localeList.toLanguageTags() + "," + LocaleList.getDefault().toLanguageTags();
+ final List<Locale.LanguageRange> languageRangeList = Locale.LanguageRange.parse(languages);
return Locale.lookup(languageRangeList, loadModelFilePathsLocked().keySet());
}
@@ -243,6 +244,8 @@
}
final String type = getHighestScoringType(classifications);
+ builder.setLogType(IntentFactory.getLogType(type));
+
final Intent intent = IntentFactory.create(mContext, type, text.toString());
final PackageManager pm;
final ResolveInfo resolveInfo;
@@ -543,5 +546,22 @@
return null;
}
}
+
+ @Nullable
+ public static int getLogType(String type) {
+ type = type.trim().toLowerCase(Locale.ENGLISH);
+ switch (type) {
+ case TextClassifier.TYPE_EMAIL:
+ return TextViewMetrics.SUBTYPE_ASSIST_MENU_ITEM_EMAIL;
+ case TextClassifier.TYPE_PHONE:
+ return TextViewMetrics.SUBTYPE_ASSIST_MENU_ITEM_PHONE;
+ case TextClassifier.TYPE_ADDRESS:
+ return TextViewMetrics.SUBTYPE_ASSIST_MENU_ITEM_ADDRESS;
+ case TextClassifier.TYPE_URL:
+ return TextViewMetrics.SUBTYPE_ASSIST_MENU_ITEM_URL;
+ default:
+ return TextViewMetrics.SUBTYPE_ASSIST_MENU_ITEM_OTHER;
+ }
+ }
}
}
diff --git a/core/java/android/widget/AbsSpinner.java b/core/java/android/widget/AbsSpinner.java
index 352e7de..f80c9e6 100644
--- a/core/java/android/widget/AbsSpinner.java
+++ b/core/java/android/widget/AbsSpinner.java
@@ -27,7 +27,6 @@
import android.util.SparseArray;
import android.view.View;
import android.view.ViewGroup;
-import android.view.ViewStructure;
import android.view.autofill.AutofillValue;
import com.android.internal.R;
@@ -495,37 +494,6 @@
// TODO(b/33197203): add unit/CTS tests for auto-fill methods (and make sure they handle enable)
@Override
- public void onProvideAutofillStructure(ViewStructure structure, int flags) {
- super.onProvideAutofillStructure(structure, flags);
-
- final SpinnerAdapter adapter = getAdapter();
-
- if (adapter == null) return;
-
- // TODO(b/33197203): implement sanitization so initial value is only sanitized when coming
- // from resources.
-
- final int count = adapter.getCount();
- int size = 0;
- if (count > 0) {
- final String[] options = new String[count];
- for (int i = 0; i < count; i++) {
- final Object item = adapter.getItem(i);
- if (item != null) {
- options[size++] = item.toString();
- }
- }
- if (size == count) {
- structure.setAutofillOptions(options);
- } else {
- final String[] validOptions = new String[size];
- System.arraycopy(options, 0, validOptions, 0, size);
- structure.setAutofillOptions(validOptions);
- }
- }
- }
-
- @Override
public void autofill(AutofillValue value) {
if (!isEnabled()) return;
diff --git a/core/java/android/widget/Adapter.java b/core/java/android/widget/Adapter.java
index 518718f..4e463dd 100644
--- a/core/java/android/widget/Adapter.java
+++ b/core/java/android/widget/Adapter.java
@@ -16,6 +16,7 @@
package android.widget;
+import android.annotation.Nullable;
import android.database.DataSetObserver;
import android.view.View;
import android.view.ViewGroup;
@@ -146,4 +147,22 @@
* adapters might want a different behavior.
*/
boolean isEmpty();
+
+ /**
+ * Gets a string representation of the adapter data that can help
+ * {@link android.service.autofill.AutofillService} autofill the view backed by the adapter.
+ *
+ * <p>
+ * It should only be set (i.e., non-{@code null} if the values do not represent PII
+ * (Personally Identifiable Information - sensitive data such as email addresses,
+ * credit card numbers, passwords, etc...). For
+ * example, it's ok to return a list of month names, but not a list of usernames. A good rule of
+ * thumb is that if the adapter data comes from static resources, such data is not PII - see
+ * {@link android.view.ViewStructure#setDataIsSensitive(boolean)} for more info.
+ *
+ * @return {@code null} by default, unless implementations override it.
+ */
+ default @Nullable CharSequence[] getAutofillOptions() {
+ return null;
+ }
}
diff --git a/core/java/android/widget/AdapterView.java b/core/java/android/widget/AdapterView.java
index be54869..dd01251 100644
--- a/core/java/android/widget/AdapterView.java
+++ b/core/java/android/widget/AdapterView.java
@@ -31,6 +31,7 @@
import android.view.ViewDebug;
import android.view.ViewGroup;
import android.view.ViewHierarchyEncoder;
+import android.view.ViewStructure;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.AccessibilityNodeInfo;
@@ -1283,4 +1284,24 @@
encoder.addProperty("list:selectedPosition", mSelectedPosition);
encoder.addProperty("list:itemCount", mItemCount);
}
-}
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p>It also sets the autofill options in the structure; when overridden, it should set it as
+ * well, either explicitly by calling {@link ViewStructure#setAutofillOptions(CharSequence[])}
+ * or implicitly by calling {@code super.onProvideAutofillStructure(structure, flags)}.
+ */
+ @Override
+ public void onProvideAutofillStructure(ViewStructure structure, int flags) {
+ super.onProvideAutofillStructure(structure, flags);
+
+ final Adapter adapter = getAdapter();
+ if (adapter == null) return;
+
+ final CharSequence[] options = adapter.getAutofillOptions();
+ if (options != null) {
+ structure.setAutofillOptions(options);
+ }
+ }
+}
\ No newline at end of file
diff --git a/core/java/android/widget/ArrayAdapter.java b/core/java/android/widget/ArrayAdapter.java
index 81f0d3d..869ef71 100644
--- a/core/java/android/widget/ArrayAdapter.java
+++ b/core/java/android/widget/ArrayAdapter.java
@@ -83,6 +83,11 @@
private List<T> mObjects;
/**
+ * Indicates whether the contents of {@link #mObjects} came from static resources.
+ */
+ private boolean mObjectsFromResources;
+
+ /**
* If the inflated resource is not a TextView, {@code mFieldId} is used to find
* a TextView inside the inflated views hierarchy. This field must contain the
* identifier that matches the one defined in the resource file.
@@ -177,10 +182,16 @@
*/
public ArrayAdapter(@NonNull Context context, @LayoutRes int resource,
@IdRes int textViewResourceId, @NonNull List<T> objects) {
+ this(context, resource, textViewResourceId, objects, false);
+ }
+
+ private ArrayAdapter(@NonNull Context context, @LayoutRes int resource,
+ @IdRes int textViewResourceId, @NonNull List<T> objects, boolean objsFromResources) {
mContext = context;
mInflater = LayoutInflater.from(context);
mResource = mDropDownResource = resource;
mObjects = objects;
+ mObjectsFromResources = objsFromResources;
mFieldId = textViewResourceId;
}
@@ -196,6 +207,7 @@
} else {
mObjects.add(object);
}
+ mObjectsFromResources = false;
}
if (mNotifyOnChange) notifyDataSetChanged();
}
@@ -221,6 +233,7 @@
} else {
mObjects.addAll(collection);
}
+ mObjectsFromResources = false;
}
if (mNotifyOnChange) notifyDataSetChanged();
}
@@ -237,6 +250,7 @@
} else {
Collections.addAll(mObjects, items);
}
+ mObjectsFromResources = false;
}
if (mNotifyOnChange) notifyDataSetChanged();
}
@@ -254,6 +268,7 @@
} else {
mObjects.add(index, object);
}
+ mObjectsFromResources = false;
}
if (mNotifyOnChange) notifyDataSetChanged();
}
@@ -270,6 +285,7 @@
} else {
mObjects.remove(object);
}
+ mObjectsFromResources = false;
}
if (mNotifyOnChange) notifyDataSetChanged();
}
@@ -284,6 +300,7 @@
} else {
mObjects.clear();
}
+ mObjectsFromResources = false;
}
if (mNotifyOnChange) notifyDataSetChanged();
}
@@ -470,7 +487,7 @@
public static @NonNull ArrayAdapter<CharSequence> createFromResource(@NonNull Context context,
@ArrayRes int textArrayResId, @LayoutRes int textViewResId) {
final CharSequence[] strings = context.getResources().getTextArray(textArrayResId);
- return new ArrayAdapter<>(context, textViewResId, strings);
+ return new ArrayAdapter<>(context, textViewResId, 0, Arrays.asList(strings), true);
}
@Override
@@ -482,6 +499,24 @@
}
/**
+ * {@inheritDoc}
+ *
+ * @return values from the string array used by {@link #createFromResource(Context, int, int)},
+ * or {@code null} if object was created otherwsie or if contents were dynamically changed after
+ * creation.
+ */
+ @Override
+ public CharSequence[] getAutofillOptions() {
+ if (!mObjectsFromResources || mObjects == null || mObjects.isEmpty()) {
+ return null;
+ }
+ final int size = mObjects.size();
+ final CharSequence[] options = new CharSequence[size];
+ mObjects.toArray(options);
+ return options;
+ }
+
+ /**
* <p>An array filter constrains the content of the array adapter with
* a prefix. Each item that does not start with the supplied prefix
* is removed from the list.</p>
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 0d3baa8..4ae3510 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -41,6 +41,7 @@
import android.graphics.RectF;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
+import android.metrics.LogMaker;
import android.os.Bundle;
import android.os.LocaleList;
import android.os.Parcel;
@@ -165,6 +166,8 @@
final UndoInputFilter mUndoInputFilter = new UndoInputFilter(this);
boolean mAllowUndo = true;
+ private final MetricsLogger mMetricsLogger = new MetricsLogger();
+
// Cursor Controllers.
private InsertionPointCursorController mInsertionPointCursorController;
SelectionModifierCursorController mSelectionModifierCursorController;
@@ -3894,6 +3897,10 @@
menu.add(TextView.ID_ASSIST, TextView.ID_ASSIST, MENU_ITEM_ORDER_ASSIST, label)
.setIcon(icon)
.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
+ mMetricsLogger.write(
+ new LogMaker(MetricsEvent.TEXT_SELECTION_MENU_ITEM_ASSIST)
+ .setType(MetricsEvent.TYPE_OPEN)
+ .setSubtype(textClassificationResult.getLogType()));
}
}
}
@@ -3922,6 +3929,9 @@
.onClick(mTextView);
}
}
+ mMetricsLogger.action(
+ MetricsEvent.ACTION_TEXT_SELECTION_MENU_ITEM_ASSIST,
+ textClassificationResult.getLogType());
stopTextActionMode();
return true;
}
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 9245134..036b391 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -252,9 +252,7 @@
if (mEnterAnimationId != 0) {
opts = ActivityOptions.makeCustomAnimation(context, mEnterAnimationId, 0);
} else {
- opts = ActivityOptions.makeScaleUpAnimation(view,
- 0, 0,
- view.getMeasuredWidth(), view.getMeasuredHeight());
+ opts = ActivityOptions.makeBasic();
}
if (launchStackId != StackId.INVALID_STACK_ID) {
diff --git a/core/java/android/widget/SimpleAdapter.java b/core/java/android/widget/SimpleAdapter.java
index 9190117..57e2ece 100644
--- a/core/java/android/widget/SimpleAdapter.java
+++ b/core/java/android/widget/SimpleAdapter.java
@@ -320,6 +320,9 @@
return mFilter;
}
+ // TODO(b/33197203): implement getAutofillOptions
+
+
/**
* This class can be used by external clients of SimpleAdapter to bind
* values to views.
diff --git a/core/java/android/widget/TextClock.java b/core/java/android/widget/TextClock.java
index a6a9db4..1279040 100644
--- a/core/java/android/widget/TextClock.java
+++ b/core/java/android/widget/TextClock.java
@@ -133,6 +133,7 @@
private CharSequence mDescFormat;
private boolean mRegistered;
+ private boolean mShouldRunTicker;
private Calendar mTime;
private String mTimeZone;
@@ -252,8 +253,7 @@
}
createTime(mTimeZone);
- // Wait until registering for events to handle the ticker
- chooseFormat(false);
+ chooseFormat();
}
private void createTime(String timeZone) {
@@ -461,16 +461,6 @@
}
/**
- * Selects either one of {@link #getFormat12Hour()} or {@link #getFormat24Hour()}
- * depending on whether the user has selected 24-hour format.
- *
- * Calling this method does not schedule or unschedule the time ticker.
- */
- private void chooseFormat() {
- chooseFormat(true);
- }
-
- /**
* Returns the current format string. Always valid after constructor has
* finished, and will never be {@code null}.
*
@@ -483,11 +473,8 @@
/**
* Selects either one of {@link #getFormat12Hour()} or {@link #getFormat24Hour()}
* depending on whether the user has selected 24-hour format.
- *
- * @param handleTicker true if calling this method should schedule/unschedule the
- * time ticker, false otherwise
*/
- private void chooseFormat(boolean handleTicker) {
+ private void chooseFormat() {
final boolean format24Requested = is24HourModeEnabled();
LocaleData ld = LocaleData.get(getContext().getResources().getConfiguration().locale);
@@ -503,7 +490,7 @@
boolean hadSeconds = mHasSeconds;
mHasSeconds = DateFormat.hasSeconds(mFormat);
- if (handleTicker && mRegistered && hadSeconds != mHasSeconds) {
+ if (mShouldRunTicker && hadSeconds != mHasSeconds) {
if (hadSeconds) getHandler().removeCallbacks(mTicker);
else mTicker.run();
}
@@ -517,26 +504,44 @@
}
@Override
- public void onVisibilityAggregated(boolean isVisible) {
- if (!mRegistered && isVisible) {
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+
+ if (!mRegistered) {
mRegistered = true;
registerReceiver();
registerObserver();
createTime(mTimeZone);
+ }
+ }
+ @Override
+ public void onVisibilityAggregated(boolean isVisible) {
+ super.onVisibilityAggregated(isVisible);
+
+ if (!mShouldRunTicker && isVisible) {
+ mShouldRunTicker = true;
if (mHasSeconds) {
mTicker.run();
} else {
onTimeChanged();
}
- } else if (mRegistered && !isVisible) {
+ } else if (mShouldRunTicker && !isVisible) {
+ mShouldRunTicker = false;
+ getHandler().removeCallbacks(mTicker);
+ }
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+
+ if (mRegistered) {
unregisterReceiver();
unregisterObserver();
- getHandler().removeCallbacks(mTicker);
-
mRegistered = false;
}
}
@@ -586,10 +591,16 @@
}
}
+ /**
+ * Update the displayed time if this view and its ancestors and window is visible
+ */
private void onTimeChanged() {
- mTime.setTimeInMillis(System.currentTimeMillis());
- setText(DateFormat.format(mFormat, mTime));
- setContentDescription(DateFormat.format(mDescFormat, mTime));
+ // mShouldRunTicker always equals the last value passed into onVisibilityAggregated
+ if (mShouldRunTicker) {
+ mTime.setTimeInMillis(System.currentTimeMillis());
+ setText(DateFormat.format(mFormat, mTime));
+ setContentDescription(DateFormat.format(mDescFormat, mTime));
+ }
}
/** @hide */
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index f1a3ff5..0fbb84b 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -1670,6 +1670,8 @@
* {@link TextView#AUTO_SIZE_TEXT_TYPE_NONE} or
* {@link TextView#AUTO_SIZE_TEXT_TYPE_UNIFORM}
*
+ * @throws IllegalArgumentException if <code>autoSizeTextType</code> is none of the types above.
+ *
* @attr ref android.R.styleable#TextView_autoSizeTextType
*
* @see #getAutoSizeTextType()
@@ -1731,11 +1733,8 @@
* @see #getAutoSizeStepGranularity()
* @see #getAutoSizeTextAvailableSizes()
*/
- public void setAutoSizeTextTypeUniformWithConfiguration(
- int autoSizeMinTextSize,
- int autoSizeMaxTextSize,
- int autoSizeStepGranularity,
- int unit) throws IllegalArgumentException {
+ public void setAutoSizeTextTypeUniformWithConfiguration(int autoSizeMinTextSize,
+ int autoSizeMaxTextSize, int autoSizeStepGranularity, int unit) {
if (supportsAutoSizeText()) {
final DisplayMetrics displayMetrics = getResources().getDisplayMetrics();
final int autoSizeMinTextSizeInPx = (int) TypedValue.applyDimension(
@@ -1772,8 +1771,7 @@
* @see #getAutoSizeMaxTextSize()
* @see #getAutoSizeTextAvailableSizes()
*/
- public void setAutoSizeTextTypeUniformWithPresetSizes(@NonNull int[] presetSizes, int unit)
- throws IllegalArgumentException {
+ public void setAutoSizeTextTypeUniformWithPresetSizes(@NonNull int[] presetSizes, int unit) {
if (supportsAutoSizeText()) {
final int presetSizesLength = presetSizes.length;
if (presetSizesLength > 0) {
@@ -1897,10 +1895,8 @@
*
* @throws IllegalArgumentException if any of the params are invalid
*/
- private void validateAndSetAutoSizeTextTypeUniformConfiguration(
- int autoSizeMinTextSizeInPx,
- int autoSizeMaxTextSizeInPx,
- int autoSizeStepGranularityInPx) throws IllegalArgumentException {
+ private void validateAndSetAutoSizeTextTypeUniformConfiguration(int autoSizeMinTextSizeInPx,
+ int autoSizeMaxTextSizeInPx, int autoSizeStepGranularityInPx) {
// First validate.
if (autoSizeMinTextSizeInPx <= 0) {
throw new IllegalArgumentException("Minimum auto-size text size ("
diff --git a/core/java/android/widget/TextViewMetrics.java b/core/java/android/widget/TextViewMetrics.java
index 0a14d3e..96d1794 100644
--- a/core/java/android/widget/TextViewMetrics.java
+++ b/core/java/android/widget/TextViewMetrics.java
@@ -21,20 +21,45 @@
*
* @hide
*/
-final class TextViewMetrics {
+public final class TextViewMetrics {
private TextViewMetrics() {}
/**
* Long press on TextView - no special classification.
*/
- static final int SUBTYPE_LONG_PRESS_OTHER = 0;
+ public static final int SUBTYPE_LONG_PRESS_OTHER = 0;
/**
* Long press on TextView - selection started.
*/
- static final int SUBTYPE_LONG_PRESS_SELECTION = 1;
+ public static final int SUBTYPE_LONG_PRESS_SELECTION = 1;
/**
* Long press on TextView - drag and drop started.
*/
- static final int SUBTYPE_LONG_PRESS_DRAG_AND_DROP = 2;
+ public static final int SUBTYPE_LONG_PRESS_DRAG_AND_DROP = 2;
+
+ /**
+ * Assist menu item (shown or clicked) - classification: other.
+ */
+ public static final int SUBTYPE_ASSIST_MENU_ITEM_OTHER = 0;
+
+ /**
+ * Assist menu item (shown or clicked) - classification: email.
+ */
+ public static final int SUBTYPE_ASSIST_MENU_ITEM_EMAIL = 1;
+
+ /**
+ * Assist menu item (shown or clicked) - classification: phone.
+ */
+ public static final int SUBTYPE_ASSIST_MENU_ITEM_PHONE = 2;
+
+ /**
+ * Assist menu item (shown or clicked) - classification: address.
+ */
+ public static final int SUBTYPE_ASSIST_MENU_ITEM_ADDRESS = 3;
+
+ /**
+ * Assist menu item (shown or clicked) - classification: url.
+ */
+ public static final int SUBTYPE_ASSIST_MENU_ITEM_URL = 4;
}
diff --git a/core/java/com/android/internal/content/FileSystemProvider.java b/core/java/com/android/internal/content/FileSystemProvider.java
index 6e9e350..79544df 100644
--- a/core/java/com/android/internal/content/FileSystemProvider.java
+++ b/core/java/com/android/internal/content/FileSystemProvider.java
@@ -17,6 +17,7 @@
package com.android.internal.content;
import android.annotation.CallSuper;
+import android.annotation.Nullable;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Intent;
@@ -150,14 +151,17 @@
return childId;
}
- private void addFolderToMediaStore(File visibleFolder) {
- assert(visibleFolder.isDirectory());
+ private void addFolderToMediaStore(@Nullable File visibleFolder) {
+ // visibleFolder is null if we're adding a folder to external thumb drive or SD card.
+ if (visibleFolder != null) {
+ assert (visibleFolder.isDirectory());
- final ContentResolver resolver = getContext().getContentResolver();
- final Uri uri = MediaStore.Files.getDirectoryUri("external");
- ContentValues values = new ContentValues();
- values.put(MediaStore.Files.FileColumns.DATA, visibleFolder.getAbsolutePath());
- resolver.insert(uri, values);
+ final ContentResolver resolver = getContext().getContentResolver();
+ final Uri uri = MediaStore.Files.getDirectoryUri("external");
+ ContentValues values = new ContentValues();
+ values.put(MediaStore.Files.FileColumns.DATA, visibleFolder.getAbsolutePath());
+ resolver.insert(uri, values);
+ }
}
@Override
@@ -204,8 +208,12 @@
return docId;
}
- private void moveInMediaStore(File oldVisibleFile, File newVisibleFile) {
- if (newVisibleFile != null) {
+ private void moveInMediaStore(@Nullable File oldVisibleFile, @Nullable File newVisibleFile) {
+ // visibleFolders are null if we're moving a document in external thumb drive or SD card.
+ //
+ // They should be all null or not null at the same time. File#renameTo() doesn't work across
+ // volumes so an exception will be thrown before calling this method.
+ if (oldVisibleFile != null && newVisibleFile != null) {
final ContentResolver resolver = getContext().getContentResolver();
final Uri externalUri = newVisibleFile.isDirectory()
? MediaStore.Files.getDirectoryUri("external")
@@ -241,8 +249,9 @@
removeFromMediaStore(visibleFile, isDirectory);
}
- private void removeFromMediaStore(File visibleFile, boolean isFolder)
+ private void removeFromMediaStore(@Nullable File visibleFile, boolean isFolder)
throws FileNotFoundException {
+ // visibleFolder is null if we're removing a document from external thumb drive or SD card.
if (visibleFile != null) {
final ContentResolver resolver = getContext().getContentResolver();
final Uri externalUri = MediaStore.Files.getContentUri("external");
diff --git a/core/java/com/android/internal/graphics/ColorUtils.java b/core/java/com/android/internal/graphics/ColorUtils.java
new file mode 100644
index 0000000..6c1efa4
--- /dev/null
+++ b/core/java/com/android/internal/graphics/ColorUtils.java
@@ -0,0 +1,618 @@
+/*
+ * 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 com.android.internal.graphics;
+
+import android.annotation.ColorInt;
+import android.annotation.FloatRange;
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.graphics.Color;
+
+/**
+ * Copied from: frameworks/support/core-utils/java/android/support/v4/graphics/ColorUtils.java
+ *
+ * A set of color-related utility methods, building upon those available in {@code Color}.
+ */
+public final class ColorUtils {
+
+ private static final double XYZ_WHITE_REFERENCE_X = 95.047;
+ private static final double XYZ_WHITE_REFERENCE_Y = 100;
+ private static final double XYZ_WHITE_REFERENCE_Z = 108.883;
+ private static final double XYZ_EPSILON = 0.008856;
+ private static final double XYZ_KAPPA = 903.3;
+
+ private static final int MIN_ALPHA_SEARCH_MAX_ITERATIONS = 10;
+ private static final int MIN_ALPHA_SEARCH_PRECISION = 1;
+
+ private static final ThreadLocal<double[]> TEMP_ARRAY = new ThreadLocal<>();
+
+ private ColorUtils() {}
+
+ /**
+ * Composite two potentially translucent colors over each other and returns the result.
+ */
+ public static int compositeColors(@ColorInt int foreground, @ColorInt int background) {
+ int bgAlpha = Color.alpha(background);
+ int fgAlpha = Color.alpha(foreground);
+ int a = compositeAlpha(fgAlpha, bgAlpha);
+
+ int r = compositeComponent(Color.red(foreground), fgAlpha,
+ Color.red(background), bgAlpha, a);
+ int g = compositeComponent(Color.green(foreground), fgAlpha,
+ Color.green(background), bgAlpha, a);
+ int b = compositeComponent(Color.blue(foreground), fgAlpha,
+ Color.blue(background), bgAlpha, a);
+
+ return Color.argb(a, r, g, b);
+ }
+
+ private static int compositeAlpha(int foregroundAlpha, int backgroundAlpha) {
+ return 0xFF - (((0xFF - backgroundAlpha) * (0xFF - foregroundAlpha)) / 0xFF);
+ }
+
+ private static int compositeComponent(int fgC, int fgA, int bgC, int bgA, int a) {
+ if (a == 0) return 0;
+ return ((0xFF * fgC * fgA) + (bgC * bgA * (0xFF - fgA))) / (a * 0xFF);
+ }
+
+ /**
+ * Returns the luminance of a color as a float between {@code 0.0} and {@code 1.0}.
+ * <p>Defined as the Y component in the XYZ representation of {@code color}.</p>
+ */
+ @FloatRange(from = 0.0, to = 1.0)
+ public static double calculateLuminance(@ColorInt int color) {
+ final double[] result = getTempDouble3Array();
+ colorToXYZ(color, result);
+ // Luminance is the Y component
+ return result[1] / 100;
+ }
+
+ /**
+ * Returns the contrast ratio between {@code foreground} and {@code background}.
+ * {@code background} must be opaque.
+ * <p>
+ * Formula defined
+ * <a href="http://www.w3.org/TR/2008/REC-WCAG20-20081211/#contrast-ratiodef">here</a>.
+ */
+ public static double calculateContrast(@ColorInt int foreground, @ColorInt int background) {
+ if (Color.alpha(background) != 255) {
+ throw new IllegalArgumentException("background can not be translucent: #"
+ + Integer.toHexString(background));
+ }
+ if (Color.alpha(foreground) < 255) {
+ // If the foreground is translucent, composite the foreground over the background
+ foreground = compositeColors(foreground, background);
+ }
+
+ final double luminance1 = calculateLuminance(foreground) + 0.05;
+ final double luminance2 = calculateLuminance(background) + 0.05;
+
+ // Now return the lighter luminance divided by the darker luminance
+ return Math.max(luminance1, luminance2) / Math.min(luminance1, luminance2);
+ }
+
+ /**
+ * Calculates the minimum alpha value which can be applied to {@code foreground} so that would
+ * have a contrast value of at least {@code minContrastRatio} when compared to
+ * {@code background}.
+ *
+ * @param foreground the foreground color
+ * @param background the opaque background color
+ * @param minContrastRatio the minimum contrast ratio
+ * @return the alpha value in the range 0-255, or -1 if no value could be calculated
+ */
+ public static int calculateMinimumAlpha(@ColorInt int foreground, @ColorInt int background,
+ float minContrastRatio) {
+ if (Color.alpha(background) != 255) {
+ throw new IllegalArgumentException("background can not be translucent: #"
+ + Integer.toHexString(background));
+ }
+
+ // First lets check that a fully opaque foreground has sufficient contrast
+ int testForeground = setAlphaComponent(foreground, 255);
+ double testRatio = calculateContrast(testForeground, background);
+ if (testRatio < minContrastRatio) {
+ // Fully opaque foreground does not have sufficient contrast, return error
+ return -1;
+ }
+
+ // Binary search to find a value with the minimum value which provides sufficient contrast
+ int numIterations = 0;
+ int minAlpha = 0;
+ int maxAlpha = 255;
+
+ while (numIterations <= MIN_ALPHA_SEARCH_MAX_ITERATIONS &&
+ (maxAlpha - minAlpha) > MIN_ALPHA_SEARCH_PRECISION) {
+ final int testAlpha = (minAlpha + maxAlpha) / 2;
+
+ testForeground = setAlphaComponent(foreground, testAlpha);
+ testRatio = calculateContrast(testForeground, background);
+
+ if (testRatio < minContrastRatio) {
+ minAlpha = testAlpha;
+ } else {
+ maxAlpha = testAlpha;
+ }
+
+ numIterations++;
+ }
+
+ // Conservatively return the max of the range of possible alphas, which is known to pass.
+ return maxAlpha;
+ }
+
+ /**
+ * Convert RGB components to HSL (hue-saturation-lightness).
+ * <ul>
+ * <li>outHsl[0] is Hue [0 .. 360)</li>
+ * <li>outHsl[1] is Saturation [0...1]</li>
+ * <li>outHsl[2] is Lightness [0...1]</li>
+ * </ul>
+ *
+ * @param r red component value [0..255]
+ * @param g green component value [0..255]
+ * @param b blue component value [0..255]
+ * @param outHsl 3-element array which holds the resulting HSL components
+ */
+ public static void RGBToHSL(@IntRange(from = 0x0, to = 0xFF) int r,
+ @IntRange(from = 0x0, to = 0xFF) int g, @IntRange(from = 0x0, to = 0xFF) int b,
+ @NonNull float[] outHsl) {
+ final float rf = r / 255f;
+ final float gf = g / 255f;
+ final float bf = b / 255f;
+
+ final float max = Math.max(rf, Math.max(gf, bf));
+ final float min = Math.min(rf, Math.min(gf, bf));
+ final float deltaMaxMin = max - min;
+
+ float h, s;
+ float l = (max + min) / 2f;
+
+ if (max == min) {
+ // Monochromatic
+ h = s = 0f;
+ } else {
+ if (max == rf) {
+ h = ((gf - bf) / deltaMaxMin) % 6f;
+ } else if (max == gf) {
+ h = ((bf - rf) / deltaMaxMin) + 2f;
+ } else {
+ h = ((rf - gf) / deltaMaxMin) + 4f;
+ }
+
+ s = deltaMaxMin / (1f - Math.abs(2f * l - 1f));
+ }
+
+ h = (h * 60f) % 360f;
+ if (h < 0) {
+ h += 360f;
+ }
+
+ outHsl[0] = constrain(h, 0f, 360f);
+ outHsl[1] = constrain(s, 0f, 1f);
+ outHsl[2] = constrain(l, 0f, 1f);
+ }
+
+ /**
+ * Convert the ARGB color to its HSL (hue-saturation-lightness) components.
+ * <ul>
+ * <li>outHsl[0] is Hue [0 .. 360)</li>
+ * <li>outHsl[1] is Saturation [0...1]</li>
+ * <li>outHsl[2] is Lightness [0...1]</li>
+ * </ul>
+ *
+ * @param color the ARGB color to convert. The alpha component is ignored
+ * @param outHsl 3-element array which holds the resulting HSL components
+ */
+ public static void colorToHSL(@ColorInt int color, @NonNull float[] outHsl) {
+ RGBToHSL(Color.red(color), Color.green(color), Color.blue(color), outHsl);
+ }
+
+ /**
+ * Convert HSL (hue-saturation-lightness) components to a RGB color.
+ * <ul>
+ * <li>hsl[0] is Hue [0 .. 360)</li>
+ * <li>hsl[1] is Saturation [0...1]</li>
+ * <li>hsl[2] is Lightness [0...1]</li>
+ * </ul>
+ * If hsv values are out of range, they are pinned.
+ *
+ * @param hsl 3-element array which holds the input HSL components
+ * @return the resulting RGB color
+ */
+ @ColorInt
+ public static int HSLToColor(@NonNull float[] hsl) {
+ final float h = hsl[0];
+ final float s = hsl[1];
+ final float l = hsl[2];
+
+ final float c = (1f - Math.abs(2 * l - 1f)) * s;
+ final float m = l - 0.5f * c;
+ final float x = c * (1f - Math.abs((h / 60f % 2f) - 1f));
+
+ final int hueSegment = (int) h / 60;
+
+ int r = 0, g = 0, b = 0;
+
+ switch (hueSegment) {
+ case 0:
+ r = Math.round(255 * (c + m));
+ g = Math.round(255 * (x + m));
+ b = Math.round(255 * m);
+ break;
+ case 1:
+ r = Math.round(255 * (x + m));
+ g = Math.round(255 * (c + m));
+ b = Math.round(255 * m);
+ break;
+ case 2:
+ r = Math.round(255 * m);
+ g = Math.round(255 * (c + m));
+ b = Math.round(255 * (x + m));
+ break;
+ case 3:
+ r = Math.round(255 * m);
+ g = Math.round(255 * (x + m));
+ b = Math.round(255 * (c + m));
+ break;
+ case 4:
+ r = Math.round(255 * (x + m));
+ g = Math.round(255 * m);
+ b = Math.round(255 * (c + m));
+ break;
+ case 5:
+ case 6:
+ r = Math.round(255 * (c + m));
+ g = Math.round(255 * m);
+ b = Math.round(255 * (x + m));
+ break;
+ }
+
+ r = constrain(r, 0, 255);
+ g = constrain(g, 0, 255);
+ b = constrain(b, 0, 255);
+
+ return Color.rgb(r, g, b);
+ }
+
+ /**
+ * Set the alpha component of {@code color} to be {@code alpha}.
+ */
+ @ColorInt
+ public static int setAlphaComponent(@ColorInt int color,
+ @IntRange(from = 0x0, to = 0xFF) int alpha) {
+ if (alpha < 0 || alpha > 255) {
+ throw new IllegalArgumentException("alpha must be between 0 and 255.");
+ }
+ return (color & 0x00ffffff) | (alpha << 24);
+ }
+
+ /**
+ * Convert the ARGB color to its CIE Lab representative components.
+ *
+ * @param color the ARGB color to convert. The alpha component is ignored
+ * @param outLab 3-element array which holds the resulting LAB components
+ */
+ public static void colorToLAB(@ColorInt int color, @NonNull double[] outLab) {
+ RGBToLAB(Color.red(color), Color.green(color), Color.blue(color), outLab);
+ }
+
+ /**
+ * Convert RGB components to its CIE Lab representative components.
+ *
+ * <ul>
+ * <li>outLab[0] is L [0 ...1)</li>
+ * <li>outLab[1] is a [-128...127)</li>
+ * <li>outLab[2] is b [-128...127)</li>
+ * </ul>
+ *
+ * @param r red component value [0..255]
+ * @param g green component value [0..255]
+ * @param b blue component value [0..255]
+ * @param outLab 3-element array which holds the resulting LAB components
+ */
+ public static void RGBToLAB(@IntRange(from = 0x0, to = 0xFF) int r,
+ @IntRange(from = 0x0, to = 0xFF) int g, @IntRange(from = 0x0, to = 0xFF) int b,
+ @NonNull double[] outLab) {
+ // First we convert RGB to XYZ
+ RGBToXYZ(r, g, b, outLab);
+ // outLab now contains XYZ
+ XYZToLAB(outLab[0], outLab[1], outLab[2], outLab);
+ // outLab now contains LAB representation
+ }
+
+ /**
+ * Convert the ARGB color to its CIE XYZ representative components.
+ *
+ * <p>The resulting XYZ representation will use the D65 illuminant and the CIE
+ * 2° Standard Observer (1931).</p>
+ *
+ * <ul>
+ * <li>outXyz[0] is X [0 ...95.047)</li>
+ * <li>outXyz[1] is Y [0...100)</li>
+ * <li>outXyz[2] is Z [0...108.883)</li>
+ * </ul>
+ *
+ * @param color the ARGB color to convert. The alpha component is ignored
+ * @param outXyz 3-element array which holds the resulting LAB components
+ */
+ public static void colorToXYZ(@ColorInt int color, @NonNull double[] outXyz) {
+ RGBToXYZ(Color.red(color), Color.green(color), Color.blue(color), outXyz);
+ }
+
+ /**
+ * Convert RGB components to its CIE XYZ representative components.
+ *
+ * <p>The resulting XYZ representation will use the D65 illuminant and the CIE
+ * 2° Standard Observer (1931).</p>
+ *
+ * <ul>
+ * <li>outXyz[0] is X [0 ...95.047)</li>
+ * <li>outXyz[1] is Y [0...100)</li>
+ * <li>outXyz[2] is Z [0...108.883)</li>
+ * </ul>
+ *
+ * @param r red component value [0..255]
+ * @param g green component value [0..255]
+ * @param b blue component value [0..255]
+ * @param outXyz 3-element array which holds the resulting XYZ components
+ */
+ public static void RGBToXYZ(@IntRange(from = 0x0, to = 0xFF) int r,
+ @IntRange(from = 0x0, to = 0xFF) int g, @IntRange(from = 0x0, to = 0xFF) int b,
+ @NonNull double[] outXyz) {
+ if (outXyz.length != 3) {
+ throw new IllegalArgumentException("outXyz must have a length of 3.");
+ }
+
+ double sr = r / 255.0;
+ sr = sr < 0.04045 ? sr / 12.92 : Math.pow((sr + 0.055) / 1.055, 2.4);
+ double sg = g / 255.0;
+ sg = sg < 0.04045 ? sg / 12.92 : Math.pow((sg + 0.055) / 1.055, 2.4);
+ double sb = b / 255.0;
+ sb = sb < 0.04045 ? sb / 12.92 : Math.pow((sb + 0.055) / 1.055, 2.4);
+
+ outXyz[0] = 100 * (sr * 0.4124 + sg * 0.3576 + sb * 0.1805);
+ outXyz[1] = 100 * (sr * 0.2126 + sg * 0.7152 + sb * 0.0722);
+ outXyz[2] = 100 * (sr * 0.0193 + sg * 0.1192 + sb * 0.9505);
+ }
+
+ /**
+ * Converts a color from CIE XYZ to CIE Lab representation.
+ *
+ * <p>This method expects the XYZ representation to use the D65 illuminant and the CIE
+ * 2° Standard Observer (1931).</p>
+ *
+ * <ul>
+ * <li>outLab[0] is L [0 ...1)</li>
+ * <li>outLab[1] is a [-128...127)</li>
+ * <li>outLab[2] is b [-128...127)</li>
+ * </ul>
+ *
+ * @param x X component value [0...95.047)
+ * @param y Y component value [0...100)
+ * @param z Z component value [0...108.883)
+ * @param outLab 3-element array which holds the resulting Lab components
+ */
+ public static void XYZToLAB(@FloatRange(from = 0f, to = XYZ_WHITE_REFERENCE_X) double x,
+ @FloatRange(from = 0f, to = XYZ_WHITE_REFERENCE_Y) double y,
+ @FloatRange(from = 0f, to = XYZ_WHITE_REFERENCE_Z) double z,
+ @NonNull double[] outLab) {
+ if (outLab.length != 3) {
+ throw new IllegalArgumentException("outLab must have a length of 3.");
+ }
+ x = pivotXyzComponent(x / XYZ_WHITE_REFERENCE_X);
+ y = pivotXyzComponent(y / XYZ_WHITE_REFERENCE_Y);
+ z = pivotXyzComponent(z / XYZ_WHITE_REFERENCE_Z);
+ outLab[0] = Math.max(0, 116 * y - 16);
+ outLab[1] = 500 * (x - y);
+ outLab[2] = 200 * (y - z);
+ }
+
+ /**
+ * Converts a color from CIE Lab to CIE XYZ representation.
+ *
+ * <p>The resulting XYZ representation will use the D65 illuminant and the CIE
+ * 2° Standard Observer (1931).</p>
+ *
+ * <ul>
+ * <li>outXyz[0] is X [0 ...95.047)</li>
+ * <li>outXyz[1] is Y [0...100)</li>
+ * <li>outXyz[2] is Z [0...108.883)</li>
+ * </ul>
+ *
+ * @param l L component value [0...100)
+ * @param a A component value [-128...127)
+ * @param b B component value [-128...127)
+ * @param outXyz 3-element array which holds the resulting XYZ components
+ */
+ public static void LABToXYZ(@FloatRange(from = 0f, to = 100) final double l,
+ @FloatRange(from = -128, to = 127) final double a,
+ @FloatRange(from = -128, to = 127) final double b,
+ @NonNull double[] outXyz) {
+ final double fy = (l + 16) / 116;
+ final double fx = a / 500 + fy;
+ final double fz = fy - b / 200;
+
+ double tmp = Math.pow(fx, 3);
+ final double xr = tmp > XYZ_EPSILON ? tmp : (116 * fx - 16) / XYZ_KAPPA;
+ final double yr = l > XYZ_KAPPA * XYZ_EPSILON ? Math.pow(fy, 3) : l / XYZ_KAPPA;
+
+ tmp = Math.pow(fz, 3);
+ final double zr = tmp > XYZ_EPSILON ? tmp : (116 * fz - 16) / XYZ_KAPPA;
+
+ outXyz[0] = xr * XYZ_WHITE_REFERENCE_X;
+ outXyz[1] = yr * XYZ_WHITE_REFERENCE_Y;
+ outXyz[2] = zr * XYZ_WHITE_REFERENCE_Z;
+ }
+
+ /**
+ * Converts a color from CIE XYZ to its RGB representation.
+ *
+ * <p>This method expects the XYZ representation to use the D65 illuminant and the CIE
+ * 2° Standard Observer (1931).</p>
+ *
+ * @param x X component value [0...95.047)
+ * @param y Y component value [0...100)
+ * @param z Z component value [0...108.883)
+ * @return int containing the RGB representation
+ */
+ @ColorInt
+ public static int XYZToColor(@FloatRange(from = 0f, to = XYZ_WHITE_REFERENCE_X) double x,
+ @FloatRange(from = 0f, to = XYZ_WHITE_REFERENCE_Y) double y,
+ @FloatRange(from = 0f, to = XYZ_WHITE_REFERENCE_Z) double z) {
+ double r = (x * 3.2406 + y * -1.5372 + z * -0.4986) / 100;
+ double g = (x * -0.9689 + y * 1.8758 + z * 0.0415) / 100;
+ double b = (x * 0.0557 + y * -0.2040 + z * 1.0570) / 100;
+
+ r = r > 0.0031308 ? 1.055 * Math.pow(r, 1 / 2.4) - 0.055 : 12.92 * r;
+ g = g > 0.0031308 ? 1.055 * Math.pow(g, 1 / 2.4) - 0.055 : 12.92 * g;
+ b = b > 0.0031308 ? 1.055 * Math.pow(b, 1 / 2.4) - 0.055 : 12.92 * b;
+
+ return Color.rgb(
+ constrain((int) Math.round(r * 255), 0, 255),
+ constrain((int) Math.round(g * 255), 0, 255),
+ constrain((int) Math.round(b * 255), 0, 255));
+ }
+
+ /**
+ * Converts a color from CIE Lab to its RGB representation.
+ *
+ * @param l L component value [0...100]
+ * @param a A component value [-128...127]
+ * @param b B component value [-128...127]
+ * @return int containing the RGB representation
+ */
+ @ColorInt
+ public static int LABToColor(@FloatRange(from = 0f, to = 100) final double l,
+ @FloatRange(from = -128, to = 127) final double a,
+ @FloatRange(from = -128, to = 127) final double b) {
+ final double[] result = getTempDouble3Array();
+ LABToXYZ(l, a, b, result);
+ return XYZToColor(result[0], result[1], result[2]);
+ }
+
+ /**
+ * Returns the euclidean distance between two LAB colors.
+ */
+ public static double distanceEuclidean(@NonNull double[] labX, @NonNull double[] labY) {
+ return Math.sqrt(Math.pow(labX[0] - labY[0], 2)
+ + Math.pow(labX[1] - labY[1], 2)
+ + Math.pow(labX[2] - labY[2], 2));
+ }
+
+ private static float constrain(float amount, float low, float high) {
+ return amount < low ? low : (amount > high ? high : amount);
+ }
+
+ private static int constrain(int amount, int low, int high) {
+ return amount < low ? low : (amount > high ? high : amount);
+ }
+
+ private static double pivotXyzComponent(double component) {
+ return component > XYZ_EPSILON
+ ? Math.pow(component, 1 / 3.0)
+ : (XYZ_KAPPA * component + 16) / 116;
+ }
+
+ /**
+ * Blend between two ARGB colors using the given ratio.
+ *
+ * <p>A blend ratio of 0.0 will result in {@code color1}, 0.5 will give an even blend,
+ * 1.0 will result in {@code color2}.</p>
+ *
+ * @param color1 the first ARGB color
+ * @param color2 the second ARGB color
+ * @param ratio the blend ratio of {@code color1} to {@code color2}
+ */
+ @ColorInt
+ public static int blendARGB(@ColorInt int color1, @ColorInt int color2,
+ @FloatRange(from = 0.0, to = 1.0) float ratio) {
+ final float inverseRatio = 1 - ratio;
+ float a = Color.alpha(color1) * inverseRatio + Color.alpha(color2) * ratio;
+ float r = Color.red(color1) * inverseRatio + Color.red(color2) * ratio;
+ float g = Color.green(color1) * inverseRatio + Color.green(color2) * ratio;
+ float b = Color.blue(color1) * inverseRatio + Color.blue(color2) * ratio;
+ return Color.argb((int) a, (int) r, (int) g, (int) b);
+ }
+
+ /**
+ * Blend between {@code hsl1} and {@code hsl2} using the given ratio. This will interpolate
+ * the hue using the shortest angle.
+ *
+ * <p>A blend ratio of 0.0 will result in {@code hsl1}, 0.5 will give an even blend,
+ * 1.0 will result in {@code hsl2}.</p>
+ *
+ * @param hsl1 3-element array which holds the first HSL color
+ * @param hsl2 3-element array which holds the second HSL color
+ * @param ratio the blend ratio of {@code hsl1} to {@code hsl2}
+ * @param outResult 3-element array which holds the resulting HSL components
+ */
+ public static void blendHSL(@NonNull float[] hsl1, @NonNull float[] hsl2,
+ @FloatRange(from = 0.0, to = 1.0) float ratio, @NonNull float[] outResult) {
+ if (outResult.length != 3) {
+ throw new IllegalArgumentException("result must have a length of 3.");
+ }
+ final float inverseRatio = 1 - ratio;
+ // Since hue is circular we will need to interpolate carefully
+ outResult[0] = circularInterpolate(hsl1[0], hsl2[0], ratio);
+ outResult[1] = hsl1[1] * inverseRatio + hsl2[1] * ratio;
+ outResult[2] = hsl1[2] * inverseRatio + hsl2[2] * ratio;
+ }
+
+ /**
+ * Blend between two CIE-LAB colors using the given ratio.
+ *
+ * <p>A blend ratio of 0.0 will result in {@code lab1}, 0.5 will give an even blend,
+ * 1.0 will result in {@code lab2}.</p>
+ *
+ * @param lab1 3-element array which holds the first LAB color
+ * @param lab2 3-element array which holds the second LAB color
+ * @param ratio the blend ratio of {@code lab1} to {@code lab2}
+ * @param outResult 3-element array which holds the resulting LAB components
+ */
+ public static void blendLAB(@NonNull double[] lab1, @NonNull double[] lab2,
+ @FloatRange(from = 0.0, to = 1.0) double ratio, @NonNull double[] outResult) {
+ if (outResult.length != 3) {
+ throw new IllegalArgumentException("outResult must have a length of 3.");
+ }
+ final double inverseRatio = 1 - ratio;
+ outResult[0] = lab1[0] * inverseRatio + lab2[0] * ratio;
+ outResult[1] = lab1[1] * inverseRatio + lab2[1] * ratio;
+ outResult[2] = lab1[2] * inverseRatio + lab2[2] * ratio;
+ }
+
+ static float circularInterpolate(float a, float b, float f) {
+ if (Math.abs(b - a) > 180) {
+ if (b > a) {
+ a += 360;
+ } else {
+ b += 360;
+ }
+ }
+ return (a + ((b - a) * f)) % 360;
+ }
+
+ private static double[] getTempDouble3Array() {
+ double[] result = TEMP_ARRAY.get();
+ if (result == null) {
+ result = new double[3];
+ TEMP_ARRAY.set(result);
+ }
+ return result;
+ }
+
+}
\ No newline at end of file
diff --git a/core/java/com/android/internal/graphics/palette/ColorCutQuantizer.java b/core/java/com/android/internal/graphics/palette/ColorCutQuantizer.java
new file mode 100644
index 0000000..2d0ad66
--- /dev/null
+++ b/core/java/com/android/internal/graphics/palette/ColorCutQuantizer.java
@@ -0,0 +1,535 @@
+/*
+ * 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 com.android.internal.graphics.palette;
+
+/*
+ * Copyright 2014 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.
+ */
+
+import android.graphics.Color;
+import android.util.TimingLogger;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.List;
+import java.util.PriorityQueue;
+
+import com.android.internal.graphics.ColorUtils;
+import com.android.internal.graphics.palette.Palette.Swatch;
+
+/**
+ * Copied from: frameworks/support/v7/palette/src/main/java/android/support/v7/
+ * graphics/ColorCutQuantizer.java
+ *
+ * An color quantizer based on the Median-cut algorithm, but optimized for picking out distinct
+ * colors rather than representation colors.
+ *
+ * The color space is represented as a 3-dimensional cube with each dimension being an RGB
+ * component. The cube is then repeatedly divided until we have reduced the color space to the
+ * requested number of colors. An average color is then generated from each cube.
+ *
+ * What makes this different to median-cut is that median-cut divided cubes so that all of the cubes
+ * have roughly the same population, where this quantizer divides boxes based on their color volume.
+ * This means that the color space is divided into distinct colors, rather than representative
+ * colors.
+ */
+final class ColorCutQuantizer {
+
+ private static final String LOG_TAG = "ColorCutQuantizer";
+ private static final boolean LOG_TIMINGS = false;
+
+ static final int COMPONENT_RED = -3;
+ static final int COMPONENT_GREEN = -2;
+ static final int COMPONENT_BLUE = -1;
+
+ private static final int QUANTIZE_WORD_WIDTH = 5;
+ private static final int QUANTIZE_WORD_MASK = (1 << QUANTIZE_WORD_WIDTH) - 1;
+
+ final int[] mColors;
+ final int[] mHistogram;
+ final List<Swatch> mQuantizedColors;
+ final TimingLogger mTimingLogger;
+ final Palette.Filter[] mFilters;
+
+ private final float[] mTempHsl = new float[3];
+
+ /**
+ * Constructor.
+ *
+ * @param pixels histogram representing an image's pixel data
+ * @param maxColors The maximum number of colors that should be in the result palette.
+ * @param filters Set of filters to use in the quantization stage
+ */
+ ColorCutQuantizer(final int[] pixels, final int maxColors, final Palette.Filter[] filters) {
+ mTimingLogger = LOG_TIMINGS ? new TimingLogger(LOG_TAG, "Creation") : null;
+ mFilters = filters;
+
+ final int[] hist = mHistogram = new int[1 << (QUANTIZE_WORD_WIDTH * 3)];
+ for (int i = 0; i < pixels.length; i++) {
+ final int quantizedColor = quantizeFromRgb888(pixels[i]);
+ // Now update the pixel value to the quantized value
+ pixels[i] = quantizedColor;
+ // And update the histogram
+ hist[quantizedColor]++;
+ }
+
+ if (LOG_TIMINGS) {
+ mTimingLogger.addSplit("Histogram created");
+ }
+
+ // Now let's count the number of distinct colors
+ int distinctColorCount = 0;
+ for (int color = 0; color < hist.length; color++) {
+ if (hist[color] > 0 && shouldIgnoreColor(color)) {
+ // If we should ignore the color, set the population to 0
+ hist[color] = 0;
+ }
+ if (hist[color] > 0) {
+ // If the color has population, increase the distinct color count
+ distinctColorCount++;
+ }
+ }
+
+ if (LOG_TIMINGS) {
+ mTimingLogger.addSplit("Filtered colors and distinct colors counted");
+ }
+
+ // Now lets go through create an array consisting of only distinct colors
+ final int[] colors = mColors = new int[distinctColorCount];
+ int distinctColorIndex = 0;
+ for (int color = 0; color < hist.length; color++) {
+ if (hist[color] > 0) {
+ colors[distinctColorIndex++] = color;
+ }
+ }
+
+ if (LOG_TIMINGS) {
+ mTimingLogger.addSplit("Distinct colors copied into array");
+ }
+
+ if (distinctColorCount <= maxColors) {
+ // The image has fewer colors than the maximum requested, so just return the colors
+ mQuantizedColors = new ArrayList<>();
+ for (int color : colors) {
+ mQuantizedColors.add(new Swatch(approximateToRgb888(color), hist[color]));
+ }
+
+ if (LOG_TIMINGS) {
+ mTimingLogger.addSplit("Too few colors present. Copied to Swatches");
+ mTimingLogger.dumpToLog();
+ }
+ } else {
+ // We need use quantization to reduce the number of colors
+ mQuantizedColors = quantizePixels(maxColors);
+
+ if (LOG_TIMINGS) {
+ mTimingLogger.addSplit("Quantized colors computed");
+ mTimingLogger.dumpToLog();
+ }
+ }
+ }
+
+ /**
+ * @return the list of quantized colors
+ */
+ List<Swatch> getQuantizedColors() {
+ return mQuantizedColors;
+ }
+
+ private List<Swatch> quantizePixels(int maxColors) {
+ // Create the priority queue which is sorted by volume descending. This means we always
+ // split the largest box in the queue
+ final PriorityQueue<Vbox> pq = new PriorityQueue<>(maxColors, VBOX_COMPARATOR_VOLUME);
+
+ // To start, offer a box which contains all of the colors
+ pq.offer(new Vbox(0, mColors.length - 1));
+
+ // Now go through the boxes, splitting them until we have reached maxColors or there are no
+ // more boxes to split
+ splitBoxes(pq, maxColors);
+
+ // Finally, return the average colors of the color boxes
+ return generateAverageColors(pq);
+ }
+
+ /**
+ * Iterate through the {@link java.util.Queue}, popping
+ * {@link ColorCutQuantizer.Vbox} objects from the queue
+ * and splitting them. Once split, the new box and the remaining box are offered back to the
+ * queue.
+ *
+ * @param queue {@link java.util.PriorityQueue} to poll for boxes
+ * @param maxSize Maximum amount of boxes to split
+ */
+ private void splitBoxes(final PriorityQueue<Vbox> queue, final int maxSize) {
+ while (queue.size() < maxSize) {
+ final Vbox vbox = queue.poll();
+
+ if (vbox != null && vbox.canSplit()) {
+ // First split the box, and offer the result
+ queue.offer(vbox.splitBox());
+
+ if (LOG_TIMINGS) {
+ mTimingLogger.addSplit("Box split");
+ }
+ // Then offer the box back
+ queue.offer(vbox);
+ } else {
+ if (LOG_TIMINGS) {
+ mTimingLogger.addSplit("All boxes split");
+ }
+ // If we get here then there are no more boxes to split, so return
+ return;
+ }
+ }
+ }
+
+ private List<Swatch> generateAverageColors(Collection<Vbox> vboxes) {
+ ArrayList<Swatch> colors = new ArrayList<>(vboxes.size());
+ for (Vbox vbox : vboxes) {
+ Swatch swatch = vbox.getAverageColor();
+ if (!shouldIgnoreColor(swatch)) {
+ // As we're averaging a color box, we can still get colors which we do not want, so
+ // we check again here
+ colors.add(swatch);
+ }
+ }
+ return colors;
+ }
+
+ /**
+ * Represents a tightly fitting box around a color space.
+ */
+ private class Vbox {
+ // lower and upper index are inclusive
+ private int mLowerIndex;
+ private int mUpperIndex;
+ // Population of colors within this box
+ private int mPopulation;
+
+ private int mMinRed, mMaxRed;
+ private int mMinGreen, mMaxGreen;
+ private int mMinBlue, mMaxBlue;
+
+ Vbox(int lowerIndex, int upperIndex) {
+ mLowerIndex = lowerIndex;
+ mUpperIndex = upperIndex;
+ fitBox();
+ }
+
+ final int getVolume() {
+ return (mMaxRed - mMinRed + 1) * (mMaxGreen - mMinGreen + 1) *
+ (mMaxBlue - mMinBlue + 1);
+ }
+
+ final boolean canSplit() {
+ return getColorCount() > 1;
+ }
+
+ final int getColorCount() {
+ return 1 + mUpperIndex - mLowerIndex;
+ }
+
+ /**
+ * Recomputes the boundaries of this box to tightly fit the colors within the box.
+ */
+ final void fitBox() {
+ final int[] colors = mColors;
+ final int[] hist = mHistogram;
+
+ // Reset the min and max to opposite values
+ int minRed, minGreen, minBlue;
+ minRed = minGreen = minBlue = Integer.MAX_VALUE;
+ int maxRed, maxGreen, maxBlue;
+ maxRed = maxGreen = maxBlue = Integer.MIN_VALUE;
+ int count = 0;
+
+ for (int i = mLowerIndex; i <= mUpperIndex; i++) {
+ final int color = colors[i];
+ count += hist[color];
+
+ final int r = quantizedRed(color);
+ final int g = quantizedGreen(color);
+ final int b = quantizedBlue(color);
+ if (r > maxRed) {
+ maxRed = r;
+ }
+ if (r < minRed) {
+ minRed = r;
+ }
+ if (g > maxGreen) {
+ maxGreen = g;
+ }
+ if (g < minGreen) {
+ minGreen = g;
+ }
+ if (b > maxBlue) {
+ maxBlue = b;
+ }
+ if (b < minBlue) {
+ minBlue = b;
+ }
+ }
+
+ mMinRed = minRed;
+ mMaxRed = maxRed;
+ mMinGreen = minGreen;
+ mMaxGreen = maxGreen;
+ mMinBlue = minBlue;
+ mMaxBlue = maxBlue;
+ mPopulation = count;
+ }
+
+ /**
+ * Split this color box at the mid-point along its longest dimension
+ *
+ * @return the new ColorBox
+ */
+ final Vbox splitBox() {
+ if (!canSplit()) {
+ throw new IllegalStateException("Can not split a box with only 1 color");
+ }
+
+ // find median along the longest dimension
+ final int splitPoint = findSplitPoint();
+
+ Vbox newBox = new Vbox(splitPoint + 1, mUpperIndex);
+
+ // Now change this box's upperIndex and recompute the color boundaries
+ mUpperIndex = splitPoint;
+ fitBox();
+
+ return newBox;
+ }
+
+ /**
+ * @return the dimension which this box is largest in
+ */
+ final int getLongestColorDimension() {
+ final int redLength = mMaxRed - mMinRed;
+ final int greenLength = mMaxGreen - mMinGreen;
+ final int blueLength = mMaxBlue - mMinBlue;
+
+ if (redLength >= greenLength && redLength >= blueLength) {
+ return COMPONENT_RED;
+ } else if (greenLength >= redLength && greenLength >= blueLength) {
+ return COMPONENT_GREEN;
+ } else {
+ return COMPONENT_BLUE;
+ }
+ }
+
+ /**
+ * Finds the point within this box's lowerIndex and upperIndex index of where to split.
+ *
+ * This is calculated by finding the longest color dimension, and then sorting the
+ * sub-array based on that dimension value in each color. The colors are then iterated over
+ * until a color is found with at least the midpoint of the whole box's dimension midpoint.
+ *
+ * @return the index of the colors array to split from
+ */
+ final int findSplitPoint() {
+ final int longestDimension = getLongestColorDimension();
+ final int[] colors = mColors;
+ final int[] hist = mHistogram;
+
+ // We need to sort the colors in this box based on the longest color dimension.
+ // As we can't use a Comparator to define the sort logic, we modify each color so that
+ // its most significant is the desired dimension
+ modifySignificantOctet(colors, longestDimension, mLowerIndex, mUpperIndex);
+
+ // Now sort... Arrays.sort uses a exclusive toIndex so we need to add 1
+ Arrays.sort(colors, mLowerIndex, mUpperIndex + 1);
+
+ // Now revert all of the colors so that they are packed as RGB again
+ modifySignificantOctet(colors, longestDimension, mLowerIndex, mUpperIndex);
+
+ final int midPoint = mPopulation / 2;
+ for (int i = mLowerIndex, count = 0; i <= mUpperIndex; i++) {
+ count += hist[colors[i]];
+ if (count >= midPoint) {
+ return i;
+ }
+ }
+
+ return mLowerIndex;
+ }
+
+ /**
+ * @return the average color of this box.
+ */
+ final Swatch getAverageColor() {
+ final int[] colors = mColors;
+ final int[] hist = mHistogram;
+ int redSum = 0;
+ int greenSum = 0;
+ int blueSum = 0;
+ int totalPopulation = 0;
+
+ for (int i = mLowerIndex; i <= mUpperIndex; i++) {
+ final int color = colors[i];
+ final int colorPopulation = hist[color];
+
+ totalPopulation += colorPopulation;
+ redSum += colorPopulation * quantizedRed(color);
+ greenSum += colorPopulation * quantizedGreen(color);
+ blueSum += colorPopulation * quantizedBlue(color);
+ }
+
+ final int redMean = Math.round(redSum / (float) totalPopulation);
+ final int greenMean = Math.round(greenSum / (float) totalPopulation);
+ final int blueMean = Math.round(blueSum / (float) totalPopulation);
+
+ return new Swatch(approximateToRgb888(redMean, greenMean, blueMean), totalPopulation);
+ }
+ }
+
+ /**
+ * Modify the significant octet in a packed color int. Allows sorting based on the value of a
+ * single color component. This relies on all components being the same word size.
+ *
+ * @see Vbox#findSplitPoint()
+ */
+ static void modifySignificantOctet(final int[] a, final int dimension,
+ final int lower, final int upper) {
+ switch (dimension) {
+ case COMPONENT_RED:
+ // Already in RGB, no need to do anything
+ break;
+ case COMPONENT_GREEN:
+ // We need to do a RGB to GRB swap, or vice-versa
+ for (int i = lower; i <= upper; i++) {
+ final int color = a[i];
+ a[i] = quantizedGreen(color) << (QUANTIZE_WORD_WIDTH + QUANTIZE_WORD_WIDTH)
+ | quantizedRed(color) << QUANTIZE_WORD_WIDTH
+ | quantizedBlue(color);
+ }
+ break;
+ case COMPONENT_BLUE:
+ // We need to do a RGB to BGR swap, or vice-versa
+ for (int i = lower; i <= upper; i++) {
+ final int color = a[i];
+ a[i] = quantizedBlue(color) << (QUANTIZE_WORD_WIDTH + QUANTIZE_WORD_WIDTH)
+ | quantizedGreen(color) << QUANTIZE_WORD_WIDTH
+ | quantizedRed(color);
+ }
+ break;
+ }
+ }
+
+ private boolean shouldIgnoreColor(int color565) {
+ final int rgb = approximateToRgb888(color565);
+ ColorUtils.colorToHSL(rgb, mTempHsl);
+ return shouldIgnoreColor(rgb, mTempHsl);
+ }
+
+ private boolean shouldIgnoreColor(Swatch color) {
+ return shouldIgnoreColor(color.getRgb(), color.getHsl());
+ }
+
+ private boolean shouldIgnoreColor(int rgb, float[] hsl) {
+ if (mFilters != null && mFilters.length > 0) {
+ for (int i = 0, count = mFilters.length; i < count; i++) {
+ if (!mFilters[i].isAllowed(rgb, hsl)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Comparator which sorts {@link Vbox} instances based on their volume, in descending order
+ */
+ private static final Comparator<Vbox> VBOX_COMPARATOR_VOLUME = new Comparator<Vbox>() {
+ @Override
+ public int compare(Vbox lhs, Vbox rhs) {
+ return rhs.getVolume() - lhs.getVolume();
+ }
+ };
+
+ /**
+ * Quantized a RGB888 value to have a word width of {@value #QUANTIZE_WORD_WIDTH}.
+ */
+ private static int quantizeFromRgb888(int color) {
+ int r = modifyWordWidth(Color.red(color), 8, QUANTIZE_WORD_WIDTH);
+ int g = modifyWordWidth(Color.green(color), 8, QUANTIZE_WORD_WIDTH);
+ int b = modifyWordWidth(Color.blue(color), 8, QUANTIZE_WORD_WIDTH);
+ return r << (QUANTIZE_WORD_WIDTH + QUANTIZE_WORD_WIDTH) | g << QUANTIZE_WORD_WIDTH | b;
+ }
+
+ /**
+ * Quantized RGB888 values to have a word width of {@value #QUANTIZE_WORD_WIDTH}.
+ */
+ static int approximateToRgb888(int r, int g, int b) {
+ return Color.rgb(modifyWordWidth(r, QUANTIZE_WORD_WIDTH, 8),
+ modifyWordWidth(g, QUANTIZE_WORD_WIDTH, 8),
+ modifyWordWidth(b, QUANTIZE_WORD_WIDTH, 8));
+ }
+
+ private static int approximateToRgb888(int color) {
+ return approximateToRgb888(quantizedRed(color), quantizedGreen(color), quantizedBlue(color));
+ }
+
+ /**
+ * @return red component of the quantized color
+ */
+ static int quantizedRed(int color) {
+ return (color >> (QUANTIZE_WORD_WIDTH + QUANTIZE_WORD_WIDTH)) & QUANTIZE_WORD_MASK;
+ }
+
+ /**
+ * @return green component of a quantized color
+ */
+ static int quantizedGreen(int color) {
+ return (color >> QUANTIZE_WORD_WIDTH) & QUANTIZE_WORD_MASK;
+ }
+
+ /**
+ * @return blue component of a quantized color
+ */
+ static int quantizedBlue(int color) {
+ return color & QUANTIZE_WORD_MASK;
+ }
+
+ private static int modifyWordWidth(int value, int currentWidth, int targetWidth) {
+ final int newValue;
+ if (targetWidth > currentWidth) {
+ // If we're approximating up in word width, we'll shift up
+ newValue = value << (targetWidth - currentWidth);
+ } else {
+ // Else, we will just shift and keep the MSB
+ newValue = value >> (currentWidth - targetWidth);
+ }
+ return newValue & ((1 << targetWidth) - 1);
+ }
+
+}
\ No newline at end of file
diff --git a/core/java/com/android/internal/graphics/palette/Palette.java b/core/java/com/android/internal/graphics/palette/Palette.java
new file mode 100644
index 0000000..9f1504a
--- /dev/null
+++ b/core/java/com/android/internal/graphics/palette/Palette.java
@@ -0,0 +1,990 @@
+/*
+ * 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 com.android.internal.graphics.palette;
+
+import android.annotation.ColorInt;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.graphics.Bitmap;
+import android.graphics.Color;
+import android.graphics.Rect;
+import android.os.AsyncTask;
+import android.util.ArrayMap;
+import android.util.Log;
+import android.util.SparseBooleanArray;
+import android.util.TimingLogger;
+
+import com.android.internal.graphics.ColorUtils;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+
+/**
+ * Copied from: /frameworks/support/v7/palette/src/main/java/android/support/v7/
+ * graphics/Palette.java
+ *
+ * A helper class to extract prominent colors from an image.
+ * <p>
+ * A number of colors with different profiles are extracted from the image:
+ * <ul>
+ * <li>Vibrant</li>
+ * <li>Vibrant Dark</li>
+ * <li>Vibrant Light</li>
+ * <li>Muted</li>
+ * <li>Muted Dark</li>
+ * <li>Muted Light</li>
+ * </ul>
+ * These can be retrieved from the appropriate getter method.
+ *
+ * <p>
+ * Instances are created with a {@link Palette.Builder} which supports several options to tweak the
+ * generated Palette. See that class' documentation for more information.
+ * <p>
+ * Generation should always be completed on a background thread, ideally the one in
+ * which you load your image on. {@link Palette.Builder} supports both synchronous and asynchronous
+ * generation:
+ *
+ * <pre>
+ * // Synchronous
+ * Palette p = Palette.from(bitmap).generate();
+ *
+ * // Asynchronous
+ * Palette.from(bitmap).generate(new PaletteAsyncListener() {
+ * public void onGenerated(Palette p) {
+ * // Use generated instance
+ * }
+ * });
+ * </pre>
+ */
+public final class Palette {
+
+ /**
+ * Listener to be used with {@link #generateAsync(Bitmap, Palette.PaletteAsyncListener)} or
+ * {@link #generateAsync(Bitmap, int, Palette.PaletteAsyncListener)}
+ */
+ public interface PaletteAsyncListener {
+
+ /**
+ * Called when the {@link Palette} has been generated.
+ */
+ void onGenerated(Palette palette);
+ }
+
+ static final int DEFAULT_RESIZE_BITMAP_AREA = 112 * 112;
+ static final int DEFAULT_CALCULATE_NUMBER_COLORS = 16;
+
+ static final float MIN_CONTRAST_TITLE_TEXT = 3.0f;
+ static final float MIN_CONTRAST_BODY_TEXT = 4.5f;
+
+ static final String LOG_TAG = "Palette";
+ static final boolean LOG_TIMINGS = false;
+
+ /**
+ * Start generating a {@link Palette} with the returned {@link Palette.Builder} instance.
+ */
+ public static Palette.Builder from(Bitmap bitmap) {
+ return new Palette.Builder(bitmap);
+ }
+
+ /**
+ * Generate a {@link Palette} from the pre-generated list of {@link Palette.Swatch} swatches.
+ * This is useful for testing, or if you want to resurrect a {@link Palette} instance from a
+ * list of swatches. Will return null if the {@code swatches} is null.
+ */
+ public static Palette from(List<Palette.Swatch> swatches) {
+ return new Palette.Builder(swatches).generate();
+ }
+
+ /**
+ * @deprecated Use {@link Palette.Builder} to generate the Palette.
+ */
+ @Deprecated
+ public static Palette generate(Bitmap bitmap) {
+ return from(bitmap).generate();
+ }
+
+ /**
+ * @deprecated Use {@link Palette.Builder} to generate the Palette.
+ */
+ @Deprecated
+ public static Palette generate(Bitmap bitmap, int numColors) {
+ return from(bitmap).maximumColorCount(numColors).generate();
+ }
+
+ /**
+ * @deprecated Use {@link Palette.Builder} to generate the Palette.
+ */
+ @Deprecated
+ public static AsyncTask<Bitmap, Void, Palette> generateAsync(
+ Bitmap bitmap, Palette.PaletteAsyncListener listener) {
+ return from(bitmap).generate(listener);
+ }
+
+ /**
+ * @deprecated Use {@link Palette.Builder} to generate the Palette.
+ */
+ @Deprecated
+ public static AsyncTask<Bitmap, Void, Palette> generateAsync(
+ final Bitmap bitmap, final int numColors, final Palette.PaletteAsyncListener listener) {
+ return from(bitmap).maximumColorCount(numColors).generate(listener);
+ }
+
+ private final List<Palette.Swatch> mSwatches;
+ private final List<Target> mTargets;
+
+ private final Map<Target, Palette.Swatch> mSelectedSwatches;
+ private final SparseBooleanArray mUsedColors;
+
+ private final Palette.Swatch mDominantSwatch;
+
+ Palette(List<Palette.Swatch> swatches, List<Target> targets) {
+ mSwatches = swatches;
+ mTargets = targets;
+
+ mUsedColors = new SparseBooleanArray();
+ mSelectedSwatches = new ArrayMap<>();
+
+ mDominantSwatch = findDominantSwatch();
+ }
+
+ /**
+ * Returns all of the swatches which make up the palette.
+ */
+ @NonNull
+ public List<Palette.Swatch> getSwatches() {
+ return Collections.unmodifiableList(mSwatches);
+ }
+
+ /**
+ * Returns the targets used to generate this palette.
+ */
+ @NonNull
+ public List<Target> getTargets() {
+ return Collections.unmodifiableList(mTargets);
+ }
+
+ /**
+ * Returns the most vibrant swatch in the palette. Might be null.
+ *
+ * @see Target#VIBRANT
+ */
+ @Nullable
+ public Palette.Swatch getVibrantSwatch() {
+ return getSwatchForTarget(Target.VIBRANT);
+ }
+
+ /**
+ * Returns a light and vibrant swatch from the palette. Might be null.
+ *
+ * @see Target#LIGHT_VIBRANT
+ */
+ @Nullable
+ public Palette.Swatch getLightVibrantSwatch() {
+ return getSwatchForTarget(Target.LIGHT_VIBRANT);
+ }
+
+ /**
+ * Returns a dark and vibrant swatch from the palette. Might be null.
+ *
+ * @see Target#DARK_VIBRANT
+ */
+ @Nullable
+ public Palette.Swatch getDarkVibrantSwatch() {
+ return getSwatchForTarget(Target.DARK_VIBRANT);
+ }
+
+ /**
+ * Returns a muted swatch from the palette. Might be null.
+ *
+ * @see Target#MUTED
+ */
+ @Nullable
+ public Palette.Swatch getMutedSwatch() {
+ return getSwatchForTarget(Target.MUTED);
+ }
+
+ /**
+ * Returns a muted and light swatch from the palette. Might be null.
+ *
+ * @see Target#LIGHT_MUTED
+ */
+ @Nullable
+ public Palette.Swatch getLightMutedSwatch() {
+ return getSwatchForTarget(Target.LIGHT_MUTED);
+ }
+
+ /**
+ * Returns a muted and dark swatch from the palette. Might be null.
+ *
+ * @see Target#DARK_MUTED
+ */
+ @Nullable
+ public Palette.Swatch getDarkMutedSwatch() {
+ return getSwatchForTarget(Target.DARK_MUTED);
+ }
+
+ /**
+ * Returns the most vibrant color in the palette as an RGB packed int.
+ *
+ * @param defaultColor value to return if the swatch isn't available
+ * @see #getVibrantSwatch()
+ */
+ @ColorInt
+ public int getVibrantColor(@ColorInt final int defaultColor) {
+ return getColorForTarget(Target.VIBRANT, defaultColor);
+ }
+
+ /**
+ * Returns a light and vibrant color from the palette as an RGB packed int.
+ *
+ * @param defaultColor value to return if the swatch isn't available
+ * @see #getLightVibrantSwatch()
+ */
+ @ColorInt
+ public int getLightVibrantColor(@ColorInt final int defaultColor) {
+ return getColorForTarget(Target.LIGHT_VIBRANT, defaultColor);
+ }
+
+ /**
+ * Returns a dark and vibrant color from the palette as an RGB packed int.
+ *
+ * @param defaultColor value to return if the swatch isn't available
+ * @see #getDarkVibrantSwatch()
+ */
+ @ColorInt
+ public int getDarkVibrantColor(@ColorInt final int defaultColor) {
+ return getColorForTarget(Target.DARK_VIBRANT, defaultColor);
+ }
+
+ /**
+ * Returns a muted color from the palette as an RGB packed int.
+ *
+ * @param defaultColor value to return if the swatch isn't available
+ * @see #getMutedSwatch()
+ */
+ @ColorInt
+ public int getMutedColor(@ColorInt final int defaultColor) {
+ return getColorForTarget(Target.MUTED, defaultColor);
+ }
+
+ /**
+ * Returns a muted and light color from the palette as an RGB packed int.
+ *
+ * @param defaultColor value to return if the swatch isn't available
+ * @see #getLightMutedSwatch()
+ */
+ @ColorInt
+ public int getLightMutedColor(@ColorInt final int defaultColor) {
+ return getColorForTarget(Target.LIGHT_MUTED, defaultColor);
+ }
+
+ /**
+ * Returns a muted and dark color from the palette as an RGB packed int.
+ *
+ * @param defaultColor value to return if the swatch isn't available
+ * @see #getDarkMutedSwatch()
+ */
+ @ColorInt
+ public int getDarkMutedColor(@ColorInt final int defaultColor) {
+ return getColorForTarget(Target.DARK_MUTED, defaultColor);
+ }
+
+ /**
+ * Returns the selected swatch for the given target from the palette, or {@code null} if one
+ * could not be found.
+ */
+ @Nullable
+ public Palette.Swatch getSwatchForTarget(@NonNull final Target target) {
+ return mSelectedSwatches.get(target);
+ }
+
+ /**
+ * Returns the selected color for the given target from the palette as an RGB packed int.
+ *
+ * @param defaultColor value to return if the swatch isn't available
+ */
+ @ColorInt
+ public int getColorForTarget(@NonNull final Target target, @ColorInt final int defaultColor) {
+ Palette.Swatch swatch = getSwatchForTarget(target);
+ return swatch != null ? swatch.getRgb() : defaultColor;
+ }
+
+ /**
+ * Returns the dominant swatch from the palette.
+ *
+ * <p>The dominant swatch is defined as the swatch with the greatest population (frequency)
+ * within the palette.</p>
+ */
+ @Nullable
+ public Palette.Swatch getDominantSwatch() {
+ return mDominantSwatch;
+ }
+
+ /**
+ * Returns the color of the dominant swatch from the palette, as an RGB packed int.
+ *
+ * @param defaultColor value to return if the swatch isn't available
+ * @see #getDominantSwatch()
+ */
+ @ColorInt
+ public int getDominantColor(@ColorInt int defaultColor) {
+ return mDominantSwatch != null ? mDominantSwatch.getRgb() : defaultColor;
+ }
+
+ void generate() {
+ // We need to make sure that the scored targets are generated first. This is so that
+ // inherited targets have something to inherit from
+ for (int i = 0, count = mTargets.size(); i < count; i++) {
+ final Target target = mTargets.get(i);
+ target.normalizeWeights();
+ mSelectedSwatches.put(target, generateScoredTarget(target));
+ }
+ // We now clear out the used colors
+ mUsedColors.clear();
+ }
+
+ private Palette.Swatch generateScoredTarget(final Target target) {
+ final Palette.Swatch maxScoreSwatch = getMaxScoredSwatchForTarget(target);
+ if (maxScoreSwatch != null && target.isExclusive()) {
+ // If we have a swatch, and the target is exclusive, add the color to the used list
+ mUsedColors.append(maxScoreSwatch.getRgb(), true);
+ }
+ return maxScoreSwatch;
+ }
+
+ private Palette.Swatch getMaxScoredSwatchForTarget(final Target target) {
+ float maxScore = 0;
+ Palette.Swatch maxScoreSwatch = null;
+ for (int i = 0, count = mSwatches.size(); i < count; i++) {
+ final Palette.Swatch swatch = mSwatches.get(i);
+ if (shouldBeScoredForTarget(swatch, target)) {
+ final float score = generateScore(swatch, target);
+ if (maxScoreSwatch == null || score > maxScore) {
+ maxScoreSwatch = swatch;
+ maxScore = score;
+ }
+ }
+ }
+ return maxScoreSwatch;
+ }
+
+ private boolean shouldBeScoredForTarget(final Palette.Swatch swatch, final Target target) {
+ // Check whether the HSL values are within the correct ranges, and this color hasn't
+ // been used yet.
+ final float hsl[] = swatch.getHsl();
+ return hsl[1] >= target.getMinimumSaturation() && hsl[1] <= target.getMaximumSaturation()
+ && hsl[2] >= target.getMinimumLightness() && hsl[2] <= target.getMaximumLightness()
+ && !mUsedColors.get(swatch.getRgb());
+ }
+
+ private float generateScore(Palette.Swatch swatch, Target target) {
+ final float[] hsl = swatch.getHsl();
+
+ float saturationScore = 0;
+ float luminanceScore = 0;
+ float populationScore = 0;
+
+ final int maxPopulation = mDominantSwatch != null ? mDominantSwatch.getPopulation() : 1;
+
+ if (target.getSaturationWeight() > 0) {
+ saturationScore = target.getSaturationWeight()
+ * (1f - Math.abs(hsl[1] - target.getTargetSaturation()));
+ }
+ if (target.getLightnessWeight() > 0) {
+ luminanceScore = target.getLightnessWeight()
+ * (1f - Math.abs(hsl[2] - target.getTargetLightness()));
+ }
+ if (target.getPopulationWeight() > 0) {
+ populationScore = target.getPopulationWeight()
+ * (swatch.getPopulation() / (float) maxPopulation);
+ }
+
+ return saturationScore + luminanceScore + populationScore;
+ }
+
+ private Palette.Swatch findDominantSwatch() {
+ int maxPop = Integer.MIN_VALUE;
+ Palette.Swatch maxSwatch = null;
+ for (int i = 0, count = mSwatches.size(); i < count; i++) {
+ Palette.Swatch swatch = mSwatches.get(i);
+ if (swatch.getPopulation() > maxPop) {
+ maxSwatch = swatch;
+ maxPop = swatch.getPopulation();
+ }
+ }
+ return maxSwatch;
+ }
+
+ private static float[] copyHslValues(Palette.Swatch color) {
+ final float[] newHsl = new float[3];
+ System.arraycopy(color.getHsl(), 0, newHsl, 0, 3);
+ return newHsl;
+ }
+
+ /**
+ * Represents a color swatch generated from an image's palette. The RGB color can be retrieved
+ * by calling {@link #getRgb()}.
+ */
+ public static final class Swatch {
+ private final int mRed, mGreen, mBlue;
+ private final int mRgb;
+ private final int mPopulation;
+
+ private boolean mGeneratedTextColors;
+ private int mTitleTextColor;
+ private int mBodyTextColor;
+
+ private float[] mHsl;
+
+ public Swatch(@ColorInt int color, int population) {
+ mRed = Color.red(color);
+ mGreen = Color.green(color);
+ mBlue = Color.blue(color);
+ mRgb = color;
+ mPopulation = population;
+ }
+
+ Swatch(int red, int green, int blue, int population) {
+ mRed = red;
+ mGreen = green;
+ mBlue = blue;
+ mRgb = Color.rgb(red, green, blue);
+ mPopulation = population;
+ }
+
+ Swatch(float[] hsl, int population) {
+ this(ColorUtils.HSLToColor(hsl), population);
+ mHsl = hsl;
+ }
+
+ /**
+ * @return this swatch's RGB color value
+ */
+ @ColorInt
+ public int getRgb() {
+ return mRgb;
+ }
+
+ /**
+ * Return this swatch's HSL values.
+ * hsv[0] is Hue [0 .. 360)
+ * hsv[1] is Saturation [0...1]
+ * hsv[2] is Lightness [0...1]
+ */
+ public float[] getHsl() {
+ if (mHsl == null) {
+ mHsl = new float[3];
+ }
+ ColorUtils.RGBToHSL(mRed, mGreen, mBlue, mHsl);
+ return mHsl;
+ }
+
+ /**
+ * @return the number of pixels represented by this swatch
+ */
+ public int getPopulation() {
+ return mPopulation;
+ }
+
+ /**
+ * Returns an appropriate color to use for any 'title' text which is displayed over this
+ * {@link Palette.Swatch}'s color. This color is guaranteed to have sufficient contrast.
+ */
+ @ColorInt
+ public int getTitleTextColor() {
+ ensureTextColorsGenerated();
+ return mTitleTextColor;
+ }
+
+ /**
+ * Returns an appropriate color to use for any 'body' text which is displayed over this
+ * {@link Palette.Swatch}'s color. This color is guaranteed to have sufficient contrast.
+ */
+ @ColorInt
+ public int getBodyTextColor() {
+ ensureTextColorsGenerated();
+ return mBodyTextColor;
+ }
+
+ private void ensureTextColorsGenerated() {
+ if (!mGeneratedTextColors) {
+ // First check white, as most colors will be dark
+ final int lightBodyAlpha = ColorUtils.calculateMinimumAlpha(
+ Color.WHITE, mRgb, MIN_CONTRAST_BODY_TEXT);
+ final int lightTitleAlpha = ColorUtils.calculateMinimumAlpha(
+ Color.WHITE, mRgb, MIN_CONTRAST_TITLE_TEXT);
+
+ if (lightBodyAlpha != -1 && lightTitleAlpha != -1) {
+ // If we found valid light values, use them and return
+ mBodyTextColor = ColorUtils.setAlphaComponent(Color.WHITE, lightBodyAlpha);
+ mTitleTextColor = ColorUtils.setAlphaComponent(Color.WHITE, lightTitleAlpha);
+ mGeneratedTextColors = true;
+ return;
+ }
+
+ final int darkBodyAlpha = ColorUtils.calculateMinimumAlpha(
+ Color.BLACK, mRgb, MIN_CONTRAST_BODY_TEXT);
+ final int darkTitleAlpha = ColorUtils.calculateMinimumAlpha(
+ Color.BLACK, mRgb, MIN_CONTRAST_TITLE_TEXT);
+
+ if (darkBodyAlpha != -1 && darkTitleAlpha != -1) {
+ // If we found valid dark values, use them and return
+ mBodyTextColor = ColorUtils.setAlphaComponent(Color.BLACK, darkBodyAlpha);
+ mTitleTextColor = ColorUtils.setAlphaComponent(Color.BLACK, darkTitleAlpha);
+ mGeneratedTextColors = true;
+ return;
+ }
+
+ // If we reach here then we can not find title and body values which use the same
+ // lightness, we need to use mismatched values
+ mBodyTextColor = lightBodyAlpha != -1
+ ? ColorUtils.setAlphaComponent(Color.WHITE, lightBodyAlpha)
+ : ColorUtils.setAlphaComponent(Color.BLACK, darkBodyAlpha);
+ mTitleTextColor = lightTitleAlpha != -1
+ ? ColorUtils.setAlphaComponent(Color.WHITE, lightTitleAlpha)
+ : ColorUtils.setAlphaComponent(Color.BLACK, darkTitleAlpha);
+ mGeneratedTextColors = true;
+ }
+ }
+
+ @Override
+ public String toString() {
+ return new StringBuilder(getClass().getSimpleName())
+ .append(" [RGB: #").append(Integer.toHexString(getRgb())).append(']')
+ .append(" [HSL: ").append(Arrays.toString(getHsl())).append(']')
+ .append(" [Population: ").append(mPopulation).append(']')
+ .append(" [Title Text: #").append(Integer.toHexString(getTitleTextColor()))
+ .append(']')
+ .append(" [Body Text: #").append(Integer.toHexString(getBodyTextColor()))
+ .append(']').toString();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ Palette.Swatch
+ swatch = (Palette.Swatch) o;
+ return mPopulation == swatch.mPopulation && mRgb == swatch.mRgb;
+ }
+
+ @Override
+ public int hashCode() {
+ return 31 * mRgb + mPopulation;
+ }
+ }
+
+ /**
+ * Builder class for generating {@link Palette} instances.
+ */
+ public static final class Builder {
+ private final List<Palette.Swatch> mSwatches;
+ private final Bitmap mBitmap;
+
+ private final List<Target> mTargets = new ArrayList<>();
+
+ private int mMaxColors = DEFAULT_CALCULATE_NUMBER_COLORS;
+ private int mResizeArea = DEFAULT_RESIZE_BITMAP_AREA;
+ private int mResizeMaxDimension = -1;
+
+ private final List<Palette.Filter> mFilters = new ArrayList<>();
+ private Rect mRegion;
+
+ /**
+ * Construct a new {@link Palette.Builder} using a source {@link Bitmap}
+ */
+ public Builder(Bitmap bitmap) {
+ if (bitmap == null || bitmap.isRecycled()) {
+ throw new IllegalArgumentException("Bitmap is not valid");
+ }
+ mFilters.add(DEFAULT_FILTER);
+ mBitmap = bitmap;
+ mSwatches = null;
+
+ // Add the default targets
+ mTargets.add(Target.LIGHT_VIBRANT);
+ mTargets.add(Target.VIBRANT);
+ mTargets.add(Target.DARK_VIBRANT);
+ mTargets.add(Target.LIGHT_MUTED);
+ mTargets.add(Target.MUTED);
+ mTargets.add(Target.DARK_MUTED);
+ }
+
+ /**
+ * Construct a new {@link Palette.Builder} using a list of {@link Palette.Swatch} instances.
+ * Typically only used for testing.
+ */
+ public Builder(List<Palette.Swatch> swatches) {
+ if (swatches == null || swatches.isEmpty()) {
+ throw new IllegalArgumentException("List of Swatches is not valid");
+ }
+ mFilters.add(DEFAULT_FILTER);
+ mSwatches = swatches;
+ mBitmap = null;
+ }
+
+ /**
+ * Set the maximum number of colors to use in the quantization step when using a
+ * {@link android.graphics.Bitmap} as the source.
+ * <p>
+ * Good values for depend on the source image type. For landscapes, good values are in
+ * the range 10-16. For images which are largely made up of people's faces then this
+ * value should be increased to ~24.
+ */
+ @NonNull
+ public Palette.Builder maximumColorCount(int colors) {
+ mMaxColors = colors;
+ return this;
+ }
+
+ /**
+ * Set the resize value when using a {@link android.graphics.Bitmap} as the source.
+ * If the bitmap's largest dimension is greater than the value specified, then the bitmap
+ * will be resized so that its largest dimension matches {@code maxDimension}. If the
+ * bitmap is smaller or equal, the original is used as-is.
+ *
+ * @deprecated Using {@link #resizeBitmapArea(int)} is preferred since it can handle
+ * abnormal aspect ratios more gracefully.
+ *
+ * @param maxDimension the number of pixels that the max dimension should be scaled down to,
+ * or any value <= 0 to disable resizing.
+ */
+ @NonNull
+ @Deprecated
+ public Palette.Builder resizeBitmapSize(final int maxDimension) {
+ mResizeMaxDimension = maxDimension;
+ mResizeArea = -1;
+ return this;
+ }
+
+ /**
+ * Set the resize value when using a {@link android.graphics.Bitmap} as the source.
+ * If the bitmap's area is greater than the value specified, then the bitmap
+ * will be resized so that its area matches {@code area}. If the
+ * bitmap is smaller or equal, the original is used as-is.
+ * <p>
+ * This value has a large effect on the processing time. The larger the resized image is,
+ * the greater time it will take to generate the palette. The smaller the image is, the
+ * more detail is lost in the resulting image and thus less precision for color selection.
+ *
+ * @param area the number of pixels that the intermediary scaled down Bitmap should cover,
+ * or any value <= 0 to disable resizing.
+ */
+ @NonNull
+ public Palette.Builder resizeBitmapArea(final int area) {
+ mResizeArea = area;
+ mResizeMaxDimension = -1;
+ return this;
+ }
+
+ /**
+ * Clear all added filters. This includes any default filters added automatically by
+ * {@link Palette}.
+ */
+ @NonNull
+ public Palette.Builder clearFilters() {
+ mFilters.clear();
+ return this;
+ }
+
+ /**
+ * Add a filter to be able to have fine grained control over which colors are
+ * allowed in the resulting palette.
+ *
+ * @param filter filter to add.
+ */
+ @NonNull
+ public Palette.Builder addFilter(
+ Palette.Filter filter) {
+ if (filter != null) {
+ mFilters.add(filter);
+ }
+ return this;
+ }
+
+ /**
+ * Set a region of the bitmap to be used exclusively when calculating the palette.
+ * <p>This only works when the original input is a {@link Bitmap}.</p>
+ *
+ * @param left The left side of the rectangle used for the region.
+ * @param top The top of the rectangle used for the region.
+ * @param right The right side of the rectangle used for the region.
+ * @param bottom The bottom of the rectangle used for the region.
+ */
+ @NonNull
+ public Palette.Builder setRegion(int left, int top, int right, int bottom) {
+ if (mBitmap != null) {
+ if (mRegion == null) mRegion = new Rect();
+ // Set the Rect to be initially the whole Bitmap
+ mRegion.set(0, 0, mBitmap.getWidth(), mBitmap.getHeight());
+ // Now just get the intersection with the region
+ if (!mRegion.intersect(left, top, right, bottom)) {
+ throw new IllegalArgumentException("The given region must intersect with "
+ + "the Bitmap's dimensions.");
+ }
+ }
+ return this;
+ }
+
+ /**
+ * Clear any previously region set via {@link #setRegion(int, int, int, int)}.
+ */
+ @NonNull
+ public Palette.Builder clearRegion() {
+ mRegion = null;
+ return this;
+ }
+
+ /**
+ * Add a target profile to be generated in the palette.
+ *
+ * <p>You can retrieve the result via {@link Palette#getSwatchForTarget(Target)}.</p>
+ */
+ @NonNull
+ public Palette.Builder addTarget(@NonNull final Target target) {
+ if (!mTargets.contains(target)) {
+ mTargets.add(target);
+ }
+ return this;
+ }
+
+ /**
+ * Clear all added targets. This includes any default targets added automatically by
+ * {@link Palette}.
+ */
+ @NonNull
+ public Palette.Builder clearTargets() {
+ if (mTargets != null) {
+ mTargets.clear();
+ }
+ return this;
+ }
+
+ /**
+ * Generate and return the {@link Palette} synchronously.
+ */
+ @NonNull
+ public Palette generate() {
+ final TimingLogger logger = LOG_TIMINGS
+ ? new TimingLogger(LOG_TAG, "Generation")
+ : null;
+
+ List<Palette.Swatch> swatches;
+
+ if (mBitmap != null) {
+ // We have a Bitmap so we need to use quantization to reduce the number of colors
+
+ // First we'll scale down the bitmap if needed
+ final Bitmap bitmap = scaleBitmapDown(mBitmap);
+
+ if (logger != null) {
+ logger.addSplit("Processed Bitmap");
+ }
+
+ final Rect region = mRegion;
+ if (bitmap != mBitmap && region != null) {
+ // If we have a scaled bitmap and a selected region, we need to scale down the
+ // region to match the new scale
+ final double scale = bitmap.getWidth() / (double) mBitmap.getWidth();
+ region.left = (int) Math.floor(region.left * scale);
+ region.top = (int) Math.floor(region.top * scale);
+ region.right = Math.min((int) Math.ceil(region.right * scale),
+ bitmap.getWidth());
+ region.bottom = Math.min((int) Math.ceil(region.bottom * scale),
+ bitmap.getHeight());
+ }
+
+ // Now generate a quantizer from the Bitmap
+ final ColorCutQuantizer quantizer = new ColorCutQuantizer(
+ getPixelsFromBitmap(bitmap),
+ mMaxColors,
+ mFilters.isEmpty() ? null : mFilters.toArray(new Palette.Filter[mFilters.size()]));
+
+ // If created a new bitmap, recycle it
+ if (bitmap != mBitmap) {
+ bitmap.recycle();
+ }
+
+ swatches = quantizer.getQuantizedColors();
+
+ if (logger != null) {
+ logger.addSplit("Color quantization completed");
+ }
+ } else {
+ // Else we're using the provided swatches
+ swatches = mSwatches;
+ }
+
+ // Now create a Palette instance
+ final Palette p = new Palette(swatches, mTargets);
+ // And make it generate itself
+ p.generate();
+
+ if (logger != null) {
+ logger.addSplit("Created Palette");
+ logger.dumpToLog();
+ }
+
+ return p;
+ }
+
+ /**
+ * Generate the {@link Palette} asynchronously. The provided listener's
+ * {@link Palette.PaletteAsyncListener#onGenerated} method will be called with the palette when
+ * generated.
+ */
+ @NonNull
+ public AsyncTask<Bitmap, Void, Palette> generate(final Palette.PaletteAsyncListener listener) {
+ if (listener == null) {
+ throw new IllegalArgumentException("listener can not be null");
+ }
+
+ return new AsyncTask<Bitmap, Void, Palette>() {
+ @Override
+ protected Palette doInBackground(Bitmap... params) {
+ try {
+ return generate();
+ } catch (Exception e) {
+ Log.e(LOG_TAG, "Exception thrown during async generate", e);
+ return null;
+ }
+ }
+
+ @Override
+ protected void onPostExecute(Palette colorExtractor) {
+ listener.onGenerated(colorExtractor);
+ }
+ }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, mBitmap);
+ }
+
+ private int[] getPixelsFromBitmap(Bitmap bitmap) {
+ final int bitmapWidth = bitmap.getWidth();
+ final int bitmapHeight = bitmap.getHeight();
+ final int[] pixels = new int[bitmapWidth * bitmapHeight];
+ bitmap.getPixels(pixels, 0, bitmapWidth, 0, 0, bitmapWidth, bitmapHeight);
+
+ if (mRegion == null) {
+ // If we don't have a region, return all of the pixels
+ return pixels;
+ } else {
+ // If we do have a region, lets create a subset array containing only the region's
+ // pixels
+ final int regionWidth = mRegion.width();
+ final int regionHeight = mRegion.height();
+ // pixels contains all of the pixels, so we need to iterate through each row and
+ // copy the regions pixels into a new smaller array
+ final int[] subsetPixels = new int[regionWidth * regionHeight];
+ for (int row = 0; row < regionHeight; row++) {
+ System.arraycopy(pixels, ((row + mRegion.top) * bitmapWidth) + mRegion.left,
+ subsetPixels, row * regionWidth, regionWidth);
+ }
+ return subsetPixels;
+ }
+ }
+
+ /**
+ * Scale the bitmap down as needed.
+ */
+ private Bitmap scaleBitmapDown(final Bitmap bitmap) {
+ double scaleRatio = -1;
+
+ if (mResizeArea > 0) {
+ final int bitmapArea = bitmap.getWidth() * bitmap.getHeight();
+ if (bitmapArea > mResizeArea) {
+ scaleRatio = Math.sqrt(mResizeArea / (double) bitmapArea);
+ }
+ } else if (mResizeMaxDimension > 0) {
+ final int maxDimension = Math.max(bitmap.getWidth(), bitmap.getHeight());
+ if (maxDimension > mResizeMaxDimension) {
+ scaleRatio = mResizeMaxDimension / (double) maxDimension;
+ }
+ }
+
+ if (scaleRatio <= 0) {
+ // Scaling has been disabled or not needed so just return the Bitmap
+ return bitmap;
+ }
+
+ return Bitmap.createScaledBitmap(bitmap,
+ (int) Math.ceil(bitmap.getWidth() * scaleRatio),
+ (int) Math.ceil(bitmap.getHeight() * scaleRatio),
+ false);
+ }
+ }
+
+ /**
+ * A Filter provides a mechanism for exercising fine-grained control over which colors
+ * are valid within a resulting {@link Palette}.
+ */
+ public interface Filter {
+ /**
+ * Hook to allow clients to be able filter colors from resulting palette.
+ *
+ * @param rgb the color in RGB888.
+ * @param hsl HSL representation of the color.
+ *
+ * @return true if the color is allowed, false if not.
+ *
+ * @see Palette.Builder#addFilter(Palette.Filter)
+ */
+ boolean isAllowed(int rgb, float[] hsl);
+ }
+
+ /**
+ * The default filter.
+ */
+ static final Palette.Filter
+ DEFAULT_FILTER = new Palette.Filter() {
+ private static final float BLACK_MAX_LIGHTNESS = 0.05f;
+ private static final float WHITE_MIN_LIGHTNESS = 0.95f;
+
+ @Override
+ public boolean isAllowed(int rgb, float[] hsl) {
+ return !isWhite(hsl) && !isBlack(hsl) && !isNearRedILine(hsl);
+ }
+
+ /**
+ * @return true if the color represents a color which is close to black.
+ */
+ private boolean isBlack(float[] hslColor) {
+ return hslColor[2] <= BLACK_MAX_LIGHTNESS;
+ }
+
+ /**
+ * @return true if the color represents a color which is close to white.
+ */
+ private boolean isWhite(float[] hslColor) {
+ return hslColor[2] >= WHITE_MIN_LIGHTNESS;
+ }
+
+ /**
+ * @return true if the color lies close to the red side of the I line.
+ */
+ private boolean isNearRedILine(float[] hslColor) {
+ return hslColor[0] >= 10f && hslColor[0] <= 37f && hslColor[1] <= 0.82f;
+ }
+ };
+}
diff --git a/core/java/com/android/internal/graphics/palette/Target.java b/core/java/com/android/internal/graphics/palette/Target.java
new file mode 100644
index 0000000..0540d80
--- /dev/null
+++ b/core/java/com/android/internal/graphics/palette/Target.java
@@ -0,0 +1,435 @@
+/*
+ * 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 com.android.internal.graphics.palette;
+
+/*
+ * Copyright 2015 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.
+ */
+
+import android.annotation.FloatRange;
+
+/**
+ * Copied from: frameworks/support/v7/palette/src/main/java/android/support/v7/graphics/Target.java
+ *
+ * A class which allows custom selection of colors in a {@link Palette}'s generation. Instances
+ * can be created via the {@link android.support.v7.graphics.Target.Builder} class.
+ *
+ * <p>To use the target, use the {@link Palette.Builder#addTarget(Target)} API when building a
+ * Palette.</p>
+ */
+public final class Target {
+
+ private static final float TARGET_DARK_LUMA = 0.26f;
+ private static final float MAX_DARK_LUMA = 0.45f;
+
+ private static final float MIN_LIGHT_LUMA = 0.55f;
+ private static final float TARGET_LIGHT_LUMA = 0.74f;
+
+ private static final float MIN_NORMAL_LUMA = 0.3f;
+ private static final float TARGET_NORMAL_LUMA = 0.5f;
+ private static final float MAX_NORMAL_LUMA = 0.7f;
+
+ private static final float TARGET_MUTED_SATURATION = 0.3f;
+ private static final float MAX_MUTED_SATURATION = 0.4f;
+
+ private static final float TARGET_VIBRANT_SATURATION = 1f;
+ private static final float MIN_VIBRANT_SATURATION = 0.35f;
+
+ private static final float WEIGHT_SATURATION = 0.24f;
+ private static final float WEIGHT_LUMA = 0.52f;
+ private static final float WEIGHT_POPULATION = 0.24f;
+
+ static final int INDEX_MIN = 0;
+ static final int INDEX_TARGET = 1;
+ static final int INDEX_MAX = 2;
+
+ static final int INDEX_WEIGHT_SAT = 0;
+ static final int INDEX_WEIGHT_LUMA = 1;
+ static final int INDEX_WEIGHT_POP = 2;
+
+ /**
+ * A target which has the characteristics of a vibrant color which is light in luminance.
+ */
+ public static final Target LIGHT_VIBRANT;
+
+ /**
+ * A target which has the characteristics of a vibrant color which is neither light or dark.
+ */
+ public static final Target VIBRANT;
+
+ /**
+ * A target which has the characteristics of a vibrant color which is dark in luminance.
+ */
+ public static final Target DARK_VIBRANT;
+
+ /**
+ * A target which has the characteristics of a muted color which is light in luminance.
+ */
+ public static final Target LIGHT_MUTED;
+
+ /**
+ * A target which has the characteristics of a muted color which is neither light or dark.
+ */
+ public static final Target MUTED;
+
+ /**
+ * A target which has the characteristics of a muted color which is dark in luminance.
+ */
+ public static final Target DARK_MUTED;
+
+ static {
+ LIGHT_VIBRANT = new Target();
+ setDefaultLightLightnessValues(LIGHT_VIBRANT);
+ setDefaultVibrantSaturationValues(LIGHT_VIBRANT);
+
+ VIBRANT = new Target();
+ setDefaultNormalLightnessValues(VIBRANT);
+ setDefaultVibrantSaturationValues(VIBRANT);
+
+ DARK_VIBRANT = new Target();
+ setDefaultDarkLightnessValues(DARK_VIBRANT);
+ setDefaultVibrantSaturationValues(DARK_VIBRANT);
+
+ LIGHT_MUTED = new Target();
+ setDefaultLightLightnessValues(LIGHT_MUTED);
+ setDefaultMutedSaturationValues(LIGHT_MUTED);
+
+ MUTED = new Target();
+ setDefaultNormalLightnessValues(MUTED);
+ setDefaultMutedSaturationValues(MUTED);
+
+ DARK_MUTED = new Target();
+ setDefaultDarkLightnessValues(DARK_MUTED);
+ setDefaultMutedSaturationValues(DARK_MUTED);
+ }
+
+ final float[] mSaturationTargets = new float[3];
+ final float[] mLightnessTargets = new float[3];
+ final float[] mWeights = new float[3];
+ boolean mIsExclusive = true; // default to true
+
+ Target() {
+ setTargetDefaultValues(mSaturationTargets);
+ setTargetDefaultValues(mLightnessTargets);
+ setDefaultWeights();
+ }
+
+ Target(Target from) {
+ System.arraycopy(from.mSaturationTargets, 0, mSaturationTargets, 0,
+ mSaturationTargets.length);
+ System.arraycopy(from.mLightnessTargets, 0, mLightnessTargets, 0,
+ mLightnessTargets.length);
+ System.arraycopy(from.mWeights, 0, mWeights, 0, mWeights.length);
+ }
+
+ /**
+ * The minimum saturation value for this target.
+ */
+ @FloatRange(from = 0, to = 1)
+ public float getMinimumSaturation() {
+ return mSaturationTargets[INDEX_MIN];
+ }
+
+ /**
+ * The target saturation value for this target.
+ */
+ @FloatRange(from = 0, to = 1)
+ public float getTargetSaturation() {
+ return mSaturationTargets[INDEX_TARGET];
+ }
+
+ /**
+ * The maximum saturation value for this target.
+ */
+ @FloatRange(from = 0, to = 1)
+ public float getMaximumSaturation() {
+ return mSaturationTargets[INDEX_MAX];
+ }
+
+ /**
+ * The minimum lightness value for this target.
+ */
+ @FloatRange(from = 0, to = 1)
+ public float getMinimumLightness() {
+ return mLightnessTargets[INDEX_MIN];
+ }
+
+ /**
+ * The target lightness value for this target.
+ */
+ @FloatRange(from = 0, to = 1)
+ public float getTargetLightness() {
+ return mLightnessTargets[INDEX_TARGET];
+ }
+
+ /**
+ * The maximum lightness value for this target.
+ */
+ @FloatRange(from = 0, to = 1)
+ public float getMaximumLightness() {
+ return mLightnessTargets[INDEX_MAX];
+ }
+
+ /**
+ * Returns the weight of importance that this target places on a color's saturation within
+ * the image.
+ *
+ * <p>The larger the weight, relative to the other weights, the more important that a color
+ * being close to the target value has on selection.</p>
+ *
+ * @see #getTargetSaturation()
+ */
+ public float getSaturationWeight() {
+ return mWeights[INDEX_WEIGHT_SAT];
+ }
+
+ /**
+ * Returns the weight of importance that this target places on a color's lightness within
+ * the image.
+ *
+ * <p>The larger the weight, relative to the other weights, the more important that a color
+ * being close to the target value has on selection.</p>
+ *
+ * @see #getTargetLightness()
+ */
+ public float getLightnessWeight() {
+ return mWeights[INDEX_WEIGHT_LUMA];
+ }
+
+ /**
+ * Returns the weight of importance that this target places on a color's population within
+ * the image.
+ *
+ * <p>The larger the weight, relative to the other weights, the more important that a
+ * color's population being close to the most populous has on selection.</p>
+ */
+ public float getPopulationWeight() {
+ return mWeights[INDEX_WEIGHT_POP];
+ }
+
+ /**
+ * Returns whether any color selected for this target is exclusive for this target only.
+ *
+ * <p>If false, then the color can be selected for other targets.</p>
+ */
+ public boolean isExclusive() {
+ return mIsExclusive;
+ }
+
+ private static void setTargetDefaultValues(final float[] values) {
+ values[INDEX_MIN] = 0f;
+ values[INDEX_TARGET] = 0.5f;
+ values[INDEX_MAX] = 1f;
+ }
+
+ private void setDefaultWeights() {
+ mWeights[INDEX_WEIGHT_SAT] = WEIGHT_SATURATION;
+ mWeights[INDEX_WEIGHT_LUMA] = WEIGHT_LUMA;
+ mWeights[INDEX_WEIGHT_POP] = WEIGHT_POPULATION;
+ }
+
+ void normalizeWeights() {
+ float sum = 0;
+ for (int i = 0, z = mWeights.length; i < z; i++) {
+ float weight = mWeights[i];
+ if (weight > 0) {
+ sum += weight;
+ }
+ }
+ if (sum != 0) {
+ for (int i = 0, z = mWeights.length; i < z; i++) {
+ if (mWeights[i] > 0) {
+ mWeights[i] /= sum;
+ }
+ }
+ }
+ }
+
+ private static void setDefaultDarkLightnessValues(Target target) {
+ target.mLightnessTargets[INDEX_TARGET] = TARGET_DARK_LUMA;
+ target.mLightnessTargets[INDEX_MAX] = MAX_DARK_LUMA;
+ }
+
+ private static void setDefaultNormalLightnessValues(Target target) {
+ target.mLightnessTargets[INDEX_MIN] = MIN_NORMAL_LUMA;
+ target.mLightnessTargets[INDEX_TARGET] = TARGET_NORMAL_LUMA;
+ target.mLightnessTargets[INDEX_MAX] = MAX_NORMAL_LUMA;
+ }
+
+ private static void setDefaultLightLightnessValues(Target target) {
+ target.mLightnessTargets[INDEX_MIN] = MIN_LIGHT_LUMA;
+ target.mLightnessTargets[INDEX_TARGET] = TARGET_LIGHT_LUMA;
+ }
+
+ private static void setDefaultVibrantSaturationValues(Target target) {
+ target.mSaturationTargets[INDEX_MIN] = MIN_VIBRANT_SATURATION;
+ target.mSaturationTargets[INDEX_TARGET] = TARGET_VIBRANT_SATURATION;
+ }
+
+ private static void setDefaultMutedSaturationValues(Target target) {
+ target.mSaturationTargets[INDEX_TARGET] = TARGET_MUTED_SATURATION;
+ target.mSaturationTargets[INDEX_MAX] = MAX_MUTED_SATURATION;
+ }
+
+ /**
+ * Builder class for generating custom {@link Target} instances.
+ */
+ public final static class Builder {
+ private final Target mTarget;
+
+ /**
+ * Create a new {@link Target} builder from scratch.
+ */
+ public Builder() {
+ mTarget = new Target();
+ }
+
+ /**
+ * Create a new builder based on an existing {@link Target}.
+ */
+ public Builder(Target target) {
+ mTarget = new Target(target);
+ }
+
+ /**
+ * Set the minimum saturation value for this target.
+ */
+ public Target.Builder setMinimumSaturation(@FloatRange(from = 0, to = 1) float value) {
+ mTarget.mSaturationTargets[INDEX_MIN] = value;
+ return this;
+ }
+
+ /**
+ * Set the target/ideal saturation value for this target.
+ */
+ public Target.Builder setTargetSaturation(@FloatRange(from = 0, to = 1) float value) {
+ mTarget.mSaturationTargets[INDEX_TARGET] = value;
+ return this;
+ }
+
+ /**
+ * Set the maximum saturation value for this target.
+ */
+ public Target.Builder setMaximumSaturation(@FloatRange(from = 0, to = 1) float value) {
+ mTarget.mSaturationTargets[INDEX_MAX] = value;
+ return this;
+ }
+
+ /**
+ * Set the minimum lightness value for this target.
+ */
+ public Target.Builder setMinimumLightness(@FloatRange(from = 0, to = 1) float value) {
+ mTarget.mLightnessTargets[INDEX_MIN] = value;
+ return this;
+ }
+
+ /**
+ * Set the target/ideal lightness value for this target.
+ */
+ public Target.Builder setTargetLightness(@FloatRange(from = 0, to = 1) float value) {
+ mTarget.mLightnessTargets[INDEX_TARGET] = value;
+ return this;
+ }
+
+ /**
+ * Set the maximum lightness value for this target.
+ */
+ public Target.Builder setMaximumLightness(@FloatRange(from = 0, to = 1) float value) {
+ mTarget.mLightnessTargets[INDEX_MAX] = value;
+ return this;
+ }
+
+ /**
+ * Set the weight of importance that this target will place on saturation values.
+ *
+ * <p>The larger the weight, relative to the other weights, the more important that a color
+ * being close to the target value has on selection.</p>
+ *
+ * <p>A weight of 0 means that it has no weight, and thus has no
+ * bearing on the selection.</p>
+ *
+ * @see #setTargetSaturation(float)
+ */
+ public Target.Builder setSaturationWeight(@FloatRange(from = 0) float weight) {
+ mTarget.mWeights[INDEX_WEIGHT_SAT] = weight;
+ return this;
+ }
+
+ /**
+ * Set the weight of importance that this target will place on lightness values.
+ *
+ * <p>The larger the weight, relative to the other weights, the more important that a color
+ * being close to the target value has on selection.</p>
+ *
+ * <p>A weight of 0 means that it has no weight, and thus has no
+ * bearing on the selection.</p>
+ *
+ * @see #setTargetLightness(float)
+ */
+ public Target.Builder setLightnessWeight(@FloatRange(from = 0) float weight) {
+ mTarget.mWeights[INDEX_WEIGHT_LUMA] = weight;
+ return this;
+ }
+
+ /**
+ * Set the weight of importance that this target will place on a color's population within
+ * the image.
+ *
+ * <p>The larger the weight, relative to the other weights, the more important that a
+ * color's population being close to the most populous has on selection.</p>
+ *
+ * <p>A weight of 0 means that it has no weight, and thus has no
+ * bearing on the selection.</p>
+ */
+ public Target.Builder setPopulationWeight(@FloatRange(from = 0) float weight) {
+ mTarget.mWeights[INDEX_WEIGHT_POP] = weight;
+ return this;
+ }
+
+ /**
+ * Set whether any color selected for this target is exclusive to this target only.
+ * Defaults to true.
+ *
+ * @param exclusive true if any the color is exclusive to this target, or false is the
+ * color can be selected for other targets.
+ */
+ public Target.Builder setExclusive(boolean exclusive) {
+ mTarget.mIsExclusive = exclusive;
+ return this;
+ }
+
+ /**
+ * Builds and returns the resulting {@link Target}.
+ */
+ public Target build() {
+ return mTarget;
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 7fbfb8b..a582c2c 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -114,7 +114,7 @@
private static final int MAGIC = 0xBA757475; // 'BATSTATS'
// Current on-disk Parcel version
- private static final int VERSION = 154 + (USE_OLD_HISTORY ? 1000 : 0);
+ private static final int VERSION = 155 + (USE_OLD_HISTORY ? 1000 : 0);
// Maximum number of items we will record in the history.
private static final int MAX_HISTORY_ITEMS = 2000;
@@ -565,9 +565,8 @@
private int mEstimatedBatteryCapacity = -1;
- // Last learned capacity reported by BatteryService in
- // setBatteryState().
- private int mLastChargeFullUAh = 0;
+ private int mMinLearnedBatteryCapacity = -1;
+ private int mMaxLearnedBatteryCapacity = -1;
private final NetworkStats.Entry mTmpNetworkStatsEntry = new NetworkStats.Entry();
@@ -605,6 +604,16 @@
return mEstimatedBatteryCapacity;
}
+ @Override
+ public int getMinLearnedBatteryCapacity() {
+ return mMinLearnedBatteryCapacity;
+ }
+
+ @Override
+ public int getMaxLearnedBatteryCapacity() {
+ return mMaxLearnedBatteryCapacity;
+ }
+
public BatteryStatsImpl() {
this(new SystemClocks());
}
@@ -8832,6 +8841,8 @@
} else {
mEstimatedBatteryCapacity = -1;
}
+ mMinLearnedBatteryCapacity = -1;
+ mMaxLearnedBatteryCapacity = -1;
mInteractiveTimer.reset(false);
mPowerSaveModeEnabledTimer.reset(false);
mLastIdleTimeStart = elapsedRealtimeMillis;
@@ -10193,15 +10204,12 @@
mRecordingHistory = DEBUG;
}
- if (differsByMoreThan(chargeFullUAh, mLastChargeFullUAh, 100)) {
- mLastChargeFullUAh = chargeFullUAh;
- addHistoryEventLocked(elapsedRealtime, uptime, HistoryItem.EVENT_ESTIMATED_BATTERY_CAP,
- "", chargeFullUAh / 1000);
+ if (mMinLearnedBatteryCapacity == -1) {
+ mMinLearnedBatteryCapacity = chargeFullUAh;
+ } else {
+ Math.min(mMinLearnedBatteryCapacity, chargeFullUAh);
}
- }
-
- private static boolean differsByMoreThan(int left, int right, int diff) {
- return Math.abs(left - right) > diff;
+ mMaxLearnedBatteryCapacity = Math.max(mMaxLearnedBatteryCapacity, chargeFullUAh);
}
public long getAwakeTimeBattery() {
@@ -10814,6 +10822,8 @@
mDischargeCurrentLevel = in.readInt();
mCurrentBatteryLevel = in.readInt();
mEstimatedBatteryCapacity = in.readInt();
+ mMinLearnedBatteryCapacity = in.readInt();
+ mMaxLearnedBatteryCapacity = in.readInt();
mLowDischargeAmountSinceCharge = in.readInt();
mHighDischargeAmountSinceCharge = in.readInt();
mDischargeAmountScreenOnSinceCharge = in.readInt();
@@ -11189,6 +11199,8 @@
out.writeInt(mDischargeCurrentLevel);
out.writeInt(mCurrentBatteryLevel);
out.writeInt(mEstimatedBatteryCapacity);
+ out.writeInt(mMinLearnedBatteryCapacity);
+ out.writeInt(mMaxLearnedBatteryCapacity);
out.writeInt(getLowDischargeAmountSinceCharge());
out.writeInt(getHighDischargeAmountSinceCharge());
out.writeInt(getDischargeAmountScreenOnSinceCharge());
@@ -11581,6 +11593,8 @@
mRealtimeStart = in.readLong();
mOnBattery = in.readInt() != 0;
mEstimatedBatteryCapacity = in.readInt();
+ mMinLearnedBatteryCapacity = in.readInt();
+ mMaxLearnedBatteryCapacity = in.readInt();
mOnBatteryInternal = false; // we are no longer really running.
mOnBatteryTimeBase.readFromParcel(in);
mOnBatteryScreenOffTimeBase.readFromParcel(in);
@@ -11775,6 +11789,8 @@
out.writeLong(mRealtimeStart);
out.writeInt(mOnBattery ? 1 : 0);
out.writeInt(mEstimatedBatteryCapacity);
+ out.writeInt(mMinLearnedBatteryCapacity);
+ out.writeInt(mMaxLearnedBatteryCapacity);
mOnBatteryTimeBase.writeToParcel(out, uSecUptime, uSecRealtime);
mOnBatteryScreenOffTimeBase.writeToParcel(out, uSecUptime, uSecRealtime);
diff --git a/core/java/com/android/internal/util/NotificationColorUtil.java b/core/java/com/android/internal/util/NotificationColorUtil.java
index 44b21b4..5cb66e5 100644
--- a/core/java/com/android/internal/util/NotificationColorUtil.java
+++ b/core/java/com/android/internal/util/NotificationColorUtil.java
@@ -460,13 +460,25 @@
if (backgroundColor == Notification.COLOR_DEFAULT) {
return context.getColor(com.android.internal.R.color.notification_action_list);
}
- boolean useDark = shouldUseDark(backgroundColor);
+ return getShiftedColor(backgroundColor, 7);
+ }
+
+ /**
+ * Get a color that stays in the same tint, but darkens or lightens it by a certain
+ * amount.
+ * This also looks at the lightness of the provided color and shifts it appropriately.
+ *
+ * @param color the base color to use
+ * @param amount the amount from 1 to 100 how much to modify the color
+ * @return the now color that was modified
+ */
+ public static int getShiftedColor(int color, int amount) {
final double[] result = ColorUtilsFromCompat.getTempDouble3Array();
- ColorUtilsFromCompat.colorToLAB(backgroundColor, result);
- if (useDark && result[0] < 97 || !useDark && result[0] < 4) {
- result[0] = Math.min(100, result[0] + 7);
+ ColorUtilsFromCompat.colorToLAB(color, result);
+ if (result[0] >= 4) {
+ result[0] = Math.max(0, result[0] - amount);
} else {
- result[0] = Math.max(0, result[0] - 7);
+ result[0] = Math.min(100, result[0] + amount);
}
return ColorUtilsFromCompat.LABToColor(result[0], result[1], result[2]);
}
diff --git a/core/java/com/android/internal/widget/NotificationExpandButton.java b/core/java/com/android/internal/widget/NotificationExpandButton.java
index c64ace4..b702898 100644
--- a/core/java/com/android/internal/widget/NotificationExpandButton.java
+++ b/core/java/com/android/internal/widget/NotificationExpandButton.java
@@ -20,6 +20,7 @@
import android.content.Context;
import android.graphics.Rect;
import android.util.AttributeSet;
+import android.view.View;
import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.Button;
import android.widget.ImageView;
@@ -30,6 +31,8 @@
*/
@RemoteViews.RemoteView
public class NotificationExpandButton extends ImageView {
+ private View mLabeledBy;
+
public NotificationExpandButton(Context context) {
super(context);
}
@@ -66,5 +69,12 @@
public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
super.onInitializeAccessibilityNodeInfo(info);
info.setClassName(Button.class.getName());
+ if (mLabeledBy != null) {
+ info.setLabeledBy(mLabeledBy);
+ }
+ }
+
+ public void setLabeledBy(View labeledBy) {
+ mLabeledBy = labeledBy;
}
}
diff --git a/core/jni/android_hardware_SensorManager.cpp b/core/jni/android_hardware_SensorManager.cpp
index 2c7174d..d046996 100644
--- a/core/jni/android_hardware_SensorManager.cpp
+++ b/core/jni/android_hardware_SensorManager.cpp
@@ -75,6 +75,12 @@
jmethodID add;
} gListOffsets;
+struct StringOffsets {
+ jclass clazz;
+ jmethodID intern;
+ jstring emptyString;
+} gStringOffsets;
+
/*
* nativeClassInit is not inteneded to be thread-safe. It should be called before other native...
* functions (except nativeCreate).
@@ -84,75 +90,55 @@
{
//android.hardware.Sensor
SensorOffsets& sensorOffsets = gSensorOffsets;
- jclass sensorClass = (jclass) _env->NewGlobalRef(_env->FindClass("android/hardware/Sensor"));
- sensorOffsets.clazz = sensorClass;
- sensorOffsets.name = _env->GetFieldID(sensorClass, "mName", "Ljava/lang/String;");
- sensorOffsets.vendor = _env->GetFieldID(sensorClass, "mVendor", "Ljava/lang/String;");
- sensorOffsets.version = _env->GetFieldID(sensorClass, "mVersion", "I");
- sensorOffsets.handle = _env->GetFieldID(sensorClass, "mHandle", "I");
- sensorOffsets.range = _env->GetFieldID(sensorClass, "mMaxRange", "F");
- sensorOffsets.resolution = _env->GetFieldID(sensorClass, "mResolution","F");
- sensorOffsets.power = _env->GetFieldID(sensorClass, "mPower", "F");
- sensorOffsets.minDelay = _env->GetFieldID(sensorClass, "mMinDelay", "I");
+ jclass sensorClass = (jclass)
+ MakeGlobalRefOrDie(_env, FindClassOrDie(_env, "android/hardware/Sensor"));
+ sensorOffsets.clazz = sensorClass;
+ sensorOffsets.name = GetFieldIDOrDie(_env, sensorClass, "mName", "Ljava/lang/String;");
+ sensorOffsets.vendor = GetFieldIDOrDie(_env, sensorClass, "mVendor", "Ljava/lang/String;");
+ sensorOffsets.version = GetFieldIDOrDie(_env, sensorClass, "mVersion", "I");
+ sensorOffsets.handle = GetFieldIDOrDie(_env, sensorClass, "mHandle", "I");
+ sensorOffsets.range = GetFieldIDOrDie(_env, sensorClass, "mMaxRange", "F");
+ sensorOffsets.resolution = GetFieldIDOrDie(_env, sensorClass, "mResolution","F");
+ sensorOffsets.power = GetFieldIDOrDie(_env, sensorClass, "mPower", "F");
+ sensorOffsets.minDelay = GetFieldIDOrDie(_env, sensorClass, "mMinDelay", "I");
sensorOffsets.fifoReservedEventCount =
- _env->GetFieldID(sensorClass, "mFifoReservedEventCount", "I");
- sensorOffsets.fifoMaxEventCount = _env->GetFieldID(sensorClass, "mFifoMaxEventCount", "I");
- sensorOffsets.stringType = _env->GetFieldID(sensorClass, "mStringType", "Ljava/lang/String;");
- sensorOffsets.requiredPermission = _env->GetFieldID(sensorClass, "mRequiredPermission",
- "Ljava/lang/String;");
- sensorOffsets.maxDelay = _env->GetFieldID(sensorClass, "mMaxDelay", "I");
- sensorOffsets.flags = _env->GetFieldID(sensorClass, "mFlags", "I");
+ GetFieldIDOrDie(_env,sensorClass, "mFifoReservedEventCount", "I");
+ sensorOffsets.fifoMaxEventCount = GetFieldIDOrDie(_env,sensorClass, "mFifoMaxEventCount", "I");
+ sensorOffsets.stringType =
+ GetFieldIDOrDie(_env,sensorClass, "mStringType", "Ljava/lang/String;");
+ sensorOffsets.requiredPermission =
+ GetFieldIDOrDie(_env,sensorClass, "mRequiredPermission", "Ljava/lang/String;");
+ sensorOffsets.maxDelay = GetFieldIDOrDie(_env,sensorClass, "mMaxDelay", "I");
+ sensorOffsets.flags = GetFieldIDOrDie(_env,sensorClass, "mFlags", "I");
- sensorOffsets.setType = _env->GetMethodID(sensorClass, "setType", "(I)Z");
- sensorOffsets.setUuid = _env->GetMethodID(sensorClass, "setUuid", "(JJ)V");
- sensorOffsets.init = _env->GetMethodID(sensorClass, "<init>", "()V");
+ sensorOffsets.setType = GetMethodIDOrDie(_env,sensorClass, "setType", "(I)Z");
+ sensorOffsets.setUuid = GetMethodIDOrDie(_env,sensorClass, "setUuid", "(JJ)V");
+ sensorOffsets.init = GetMethodIDOrDie(_env,sensorClass, "<init>", "()V");
// java.util.List;
ListOffsets& listOffsets = gListOffsets;
- jclass listClass = (jclass) _env->NewGlobalRef(_env->FindClass("java/util/List"));
+ jclass listClass = (jclass) MakeGlobalRefOrDie(_env, FindClassOrDie(_env, "java/util/List"));
listOffsets.clazz = listClass;
- listOffsets.add = _env->GetMethodID(listClass, "add", "(Ljava/lang/Object;)Z");
+ listOffsets.add = GetMethodIDOrDie(_env,listClass, "add", "(Ljava/lang/Object;)Z");
+
+ // initialize java.lang.String and empty string intern
+ StringOffsets& stringOffsets = gStringOffsets;
+ stringOffsets.clazz = MakeGlobalRefOrDie(_env, FindClassOrDie(_env, "java/lang/String"));
+ stringOffsets.intern =
+ GetMethodIDOrDie(_env, stringOffsets.clazz, "intern", "()Ljava/lang/String;");
+ ScopedLocalRef<jstring> empty(_env, _env->NewStringUTF(""));
+ stringOffsets.emptyString = (jstring)
+ MakeGlobalRefOrDie(_env, _env->CallObjectMethod(empty.get(), stringOffsets.intern));
}
-/**
- * A key comparator predicate.
- * It is used to intern strings associated with Sensor data.
- * It defines a 'Strict weak ordering' for the interned strings.
- */
-class InternedStringCompare {
-public:
- bool operator()(const String8* string1, const String8* string2) const {
- if (string1 == NULL) {
- return string2 != NULL;
- }
- if (string2 == NULL) {
- return false;
- }
- return string1->compare(*string2) < 0;
+static jstring getJavaInternedString(JNIEnv *env, const String8 &string) {
+ if (string == "") {
+ return gStringOffsets.emptyString;
}
-};
-/**
- * A localized interning mechanism for Sensor strings.
- * We implement our own interning to avoid the overhead of using java.lang.String#intern().
- * It is common that Vendor, StringType, and RequirePermission data is common between many of the
- * Sensors, by interning the memory usage to represent Sensors is optimized.
- */
-static jstring
-getInternedString(JNIEnv *env, const String8* string) {
- static std::map<const String8*, jstring, InternedStringCompare> internedStrings;
-
- jstring internedString;
- std::map<const String8*, jstring>::iterator iterator = internedStrings.find(string);
- if (iterator != internedStrings.end()) {
- internedString = iterator->second;
- } else {
- jstring localString = env->NewStringUTF(string->string());
- // we are implementing our own interning so expect these strings to be backed by global refs
- internedString = (jstring) env->NewGlobalRef(localString);
- internedStrings.insert(std::make_pair(string, internedString));
- env->DeleteLocalRef(localString);
- }
+ ScopedLocalRef<jstring> javaString(env, env->NewStringUTF(string.string()));
+ jstring internedString = (jstring)
+ env->CallObjectMethod(javaString.get(), gStringOffsets.intern);
return internedString;
}
@@ -174,10 +160,10 @@
}
if (sensor != NULL) {
- jstring name = env->NewStringUTF(nativeSensor.getName().string());
- jstring vendor = env->NewStringUTF(nativeSensor.getVendor().string());
+ jstring name = getJavaInternedString(env, nativeSensor.getName());
+ jstring vendor = getJavaInternedString(env, nativeSensor.getVendor());
jstring requiredPermission =
- env->NewStringUTF(nativeSensor.getRequiredPermission().string());
+ getJavaInternedString(env, nativeSensor.getRequiredPermission());
env->SetObjectField(sensor, sensorOffsets.name, name);
env->SetObjectField(sensor, sensorOffsets.vendor, vendor);
@@ -198,7 +184,7 @@
if (env->CallBooleanMethod(sensor, sensorOffsets.setType, nativeSensor.getType())
== JNI_FALSE) {
- jstring stringType = getInternedString(env, &nativeSensor.getStringType());
+ jstring stringType = getJavaInternedString(env, nativeSensor.getStringType());
env->SetObjectField(sensor, sensorOffsets.stringType, stringType);
}
diff --git a/core/jni/android_os_HwParcel.cpp b/core/jni/android_os_HwParcel.cpp
index 678041f..b21ea828 100644
--- a/core/jni/android_os_HwParcel.cpp
+++ b/core/jni/android_os_HwParcel.cpp
@@ -574,7 +574,7 @@
size_t parentHandle;
const hidl_string *s;
- status_t err = parcel->readBuffer(&parentHandle,
+ status_t err = parcel->readBuffer(sizeof(*s), &parentHandle,
reinterpret_cast<const void**>(&s));
if (err != OK) {
@@ -583,7 +583,7 @@
}
err = ::android::hardware::readEmbeddedFromParcel(
- const_cast<hidl_string *>(s),
+ const_cast<hidl_string &>(*s),
*parcel, parentHandle, 0 /* parentOffset */);
if (err != OK) {
@@ -602,7 +602,7 @@
size_t parentHandle; \
\
const hidl_vec<Type> *vec; \
- status_t err = parcel->readBuffer(&parentHandle, \
+ status_t err = parcel->readBuffer(sizeof(*vec), &parentHandle, \
reinterpret_cast<const void**>(&vec)); \
\
if (err != OK) { \
@@ -613,7 +613,7 @@
size_t childHandle; \
\
err = ::android::hardware::readEmbeddedFromParcel( \
- const_cast<hidl_vec<Type> *>(vec), \
+ const_cast<hidl_vec<Type> &>(*vec), \
*parcel, \
parentHandle, \
0 /* parentOffset */, \
@@ -645,7 +645,7 @@
size_t parentHandle;
const hidl_vec<bool> *vec;
- status_t err = parcel->readBuffer(&parentHandle,
+ status_t err = parcel->readBuffer(sizeof(*vec), &parentHandle,
reinterpret_cast<const void**>(&vec));
if (err != OK) {
@@ -656,7 +656,7 @@
size_t childHandle;
err = ::android::hardware::readEmbeddedFromParcel(
- const_cast<hidl_vec<bool> *>(vec),
+ const_cast<hidl_vec<bool> &>(*vec),
*parcel,
parentHandle,
0 /* parentOffset */,
@@ -709,7 +709,7 @@
size_t parentHandle;
const string_vec *vec;
- status_t err = parcel->readBuffer(&parentHandle,
+ status_t err = parcel->readBuffer(sizeof(*vec), &parentHandle,
reinterpret_cast<const void **>(&vec));
if (err != OK) {
@@ -719,16 +719,15 @@
size_t childHandle;
err = ::android::hardware::readEmbeddedFromParcel(
- const_cast<string_vec *>(vec),
+ const_cast<string_vec &>(*vec),
*parcel, parentHandle, 0 /* parentOffset */, &childHandle);
for (size_t i = 0; (err == OK) && (i < vec->size()); ++i) {
err = android::hardware::readEmbeddedFromParcel(
- const_cast<hidl_vec<hidl_string> *>(vec),
+ const_cast<hidl_string &>((*vec)[i]),
*parcel,
childHandle,
- i * sizeof(hidl_string),
- nullptr /* childHandle */);
+ i * sizeof(hidl_string) /* parentOffset */);
}
if (err != OK) {
@@ -810,13 +809,20 @@
return JHwRemoteBinder::NewObject(env, binder);
}
-static jobject JHwParcel_native_readBuffer(JNIEnv *env, jobject thiz) {
+static jobject JHwParcel_native_readBuffer(JNIEnv *env, jobject thiz,
+ jlong expectedSize) {
hardware::Parcel *parcel =
JHwParcel::GetNativeContext(env, thiz)->getParcel();
size_t handle;
const void *ptr;
- status_t status = parcel->readBuffer(&handle, &ptr);
+
+ if (expectedSize < 0) {
+ jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+ return nullptr;
+ }
+
+ status_t status = parcel->readBuffer(expectedSize, &handle, &ptr);
if (status != OK) {
jniThrowException(env, "java/util/NoSuchElementException", NULL);
@@ -827,8 +833,8 @@
}
static jobject JHwParcel_native_readEmbeddedBuffer(
- JNIEnv *env, jobject thiz, jlong parentHandle, jlong offset,
- jboolean nullable) {
+ JNIEnv *env, jobject thiz, jlong expectedSize,
+ jlong parentHandle, jlong offset, jboolean nullable) {
hardware::Parcel *parcel =
JHwParcel::GetNativeContext(env, thiz)->getParcel();
@@ -836,8 +842,13 @@
const void *ptr;
status_t status =
- parcel->readNullableEmbeddedBuffer(&childHandle, parentHandle, offset,
- &ptr);
+ parcel->readNullableEmbeddedBuffer(expectedSize,
+ &childHandle, parentHandle, offset, &ptr);
+
+ if (expectedSize < 0) {
+ jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+ return nullptr;
+ }
if (status != OK) {
jniThrowException(env, "java/util/NoSuchElementException", NULL);
@@ -952,10 +963,10 @@
{ "send", "()V", (void *)JHwParcel_native_send },
- { "readBuffer", "()L" PACKAGE_PATH "/HwBlob;",
+ { "readBuffer", "(J)L" PACKAGE_PATH "/HwBlob;",
(void *)JHwParcel_native_readBuffer },
- { "readEmbeddedBuffer", "(JJZ)L" PACKAGE_PATH "/HwBlob;",
+ { "readEmbeddedBuffer", "(JJJZ)L" PACKAGE_PATH "/HwBlob;",
(void *)JHwParcel_native_readEmbeddedBuffer },
{ "writeBuffer", "(L" PACKAGE_PATH "/HwBlob;)V",
diff --git a/core/proto/android/os/incident.proto b/core/proto/android/os/incident.proto
index a2f07d9..2042bf62 100644
--- a/core/proto/android/os/incident.proto
+++ b/core/proto/android/os/incident.proto
@@ -21,10 +21,14 @@
import "frameworks/base/libs/incident/proto/android/privacy.proto";
import "frameworks/base/core/proto/android/service/appwidget.proto";
+import "frameworks/base/core/proto/android/service/battery.proto";
import "frameworks/base/core/proto/android/service/graphicsstats.proto";
import "frameworks/base/core/proto/android/service/fingerprint.proto";
+import "frameworks/base/core/proto/android/service/diskstats.proto";
import "frameworks/base/core/proto/android/service/netstats.proto";
import "frameworks/base/core/proto/android/service/notification.proto";
+import "frameworks/base/core/proto/android/service/package.proto";
+import "frameworks/base/core/proto/android/service/power.proto";
import "frameworks/base/core/proto/android/providers/settings.proto";
package android.os;
@@ -57,6 +61,10 @@
android.service.NetworkStatsServiceDumpProto netstats = 3001;
android.providers.settings.SettingsServiceDumpProto settings = 3002;
android.service.appwidget.AppWidgetServiceDumpProto appwidget = 3003;
+ android.service.battery.BatteryServiceDumpProto battery = 3006;
+ android.service.diskstats.DiskStatsServiceDumpProto diskstats = 3007;
android.service.notification.NotificationServiceDumpProto notification = 3004;
+ android.service.pm.PackageServiceDumpProto package = 3008;
+ android.service.power.PowerServiceDumpProto power = 3009;
android.service.GraphicsStatsServiceDumpProto graphicsstats = 3005;
}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 8869593..155a939 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -37,7 +37,6 @@
<protected-broadcast android:name="android.intent.action.BOOT_COMPLETED" />
<protected-broadcast android:name="android.intent.action.PACKAGE_INSTALL" />
<protected-broadcast android:name="android.intent.action.PACKAGE_ADDED" />
- <protected-broadcast android:name="android.intent.action.PACKAGE_FIRST_ADDED" />
<protected-broadcast android:name="android.intent.action.PACKAGE_REPLACED" />
<protected-broadcast android:name="android.intent.action.MY_PACKAGE_REPLACED" />
<protected-broadcast android:name="android.intent.action.PACKAGE_REMOVED" />
@@ -3624,6 +3623,22 @@
</intent-filter>
</receiver>
+ <receiver android:name="com.android.server.updates.LangIdInstallReceiver"
+ android:permission="android.permission.UPDATE_CONFIG">
+ <intent-filter>
+ <action android:name="android.intent.action.UPDATE_LANG_ID" />
+ <data android:scheme="content" android:host="*" android:mimeType="*/*" />
+ </intent-filter>
+ </receiver>
+
+ <receiver android:name="com.android.server.updates.SmartSelectionInstallReceiver"
+ android:permission="android.permission.UPDATE_CONFIG">
+ <intent-filter>
+ <action android:name="android.intent.action.UPDATE_SMART_SELECTION" />
+ <data android:scheme="content" android:host="*" android:mimeType="*/*" />
+ </intent-filter>
+ </receiver>
+
<receiver android:name="com.android.server.MasterClearReceiver"
android:permission="android.permission.MASTER_CLEAR">
<intent-filter
diff --git a/core/res/res/drawable/ic_picture_in_picture.xml b/core/res/res/drawable/ic_picture_in_picture.xml
new file mode 100644
index 0000000..e2dda33
--- /dev/null
+++ b/core/res/res/drawable/ic_picture_in_picture.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<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="#FFFFFF"
+ android:pathData="M19 11h-8v6h8v-6zm4 8V4.98C23 3.88 22.1 3 21 3H3c-1.1 0-2 .88-2 1.98V19c0 1.1 .9
+2 2 2h18c1.1 0 2-.9 2-2zm-2 .02H3V4.97h18v14.05z" />
+ <path
+ android:pathData="M0 0h24v24H0V0z" />
+</vector>
\ No newline at end of file
diff --git a/core/res/res/values-television/config.xml b/core/res/res/values-television/config.xml
index 78eeee9..d62b93e 100644
--- a/core/res/res/values-television/config.xml
+++ b/core/res/res/values-television/config.xml
@@ -36,4 +36,7 @@
<!-- The default gravity for the picture-in-picture window.
Currently, this maps to Gravity.BOTTOM | Gravity.RIGHT -->
<integer name="config_defaultPictureInPictureGravity">0x55</integer>
+
+ <!-- Whether the device uses the default focus highlight when focus state isn't specified. -->
+ <bool name="config_useDefaultFocusHighlight">false</bool>
</resources>
diff --git a/core/res/res/values/colors_material.xml b/core/res/res/values/colors_material.xml
index e0cc5b5..8c37d4b 100644
--- a/core/res/res/values/colors_material.xml
+++ b/core/res/res/values/colors_material.xml
@@ -74,10 +74,10 @@
<item name="disabled_alpha_material_light" format="float" type="dimen">0.26</item>
<item name="disabled_alpha_material_dark" format="float" type="dimen">0.30</item>
- <item name="primary_content_alpha_material_light" format="float" type="dimen">1</item>
- <item name="primary_content_alpha_material_dark" format="float" type="dimen">0.87</item>
- <item name="secondary_content_alpha_material_light" format="float" type="dimen">.7</item>
- <item name="secondary_content_alpha_material_dark" format="float" type="dimen">0.54</item>
+ <item name="primary_content_alpha_material_dark" format="float" type="dimen">1</item>
+ <item name="primary_content_alpha_material_light" format="float" type="dimen">0.87</item>
+ <item name="secondary_content_alpha_material_dark" format="float" type="dimen">.7</item>
+ <item name="secondary_content_alpha_material_light" format="float" type="dimen">0.54</item>
<item name="highlight_alpha_material_light" format="float" type="dimen">0.12</item>
<item name="highlight_alpha_material_dark" format="float" type="dimen">0.20</item>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 6a31e16..27a4d5c 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2796,7 +2796,7 @@
<string name="config_defaultCellBroadcastReceiverPkg" translatable="false">com.android.cellbroadcastreceiver</string>
<!-- Specifies the path that is used by AdaptiveIconDrawable class to crop launcher icons. -->
- <string name="config_icon_mask" translatable="false">"M50,0L92,0 A8,8,0,0 1 100,8 L100,92 A8,8,0,0 1 92,100 L8,100 A8,8,0,0 1 0,92 L 0,8 A8,8,0,0 1 8,0z"</string>
+ <string name="config_icon_mask" translatable="false">"M50,0L92,0C96.42,0 100,4.58 100 8L100,92C100, 96.42 96.42 100 92 100L8 100C4.58, 100 0 96.42 0 92L0 8 C 0 4.42 4.42 0 8 0L50 0Z"</string>
<!-- The component name, flattened to a string, for the default accessibility service to be
enabled by the accessibility shortcut. This service must be trusted, as it can be activated
@@ -2830,4 +2830,7 @@
specified name exists on the device, autofill will be disabled by default.
-->
<string name="config_defaultAutofillService" translatable="false"></string>
+
+ <!-- Whether the device uses the default focus highlight when focus state isn't specified. -->
+ <bool name="config_useDefaultFocusHighlight">true</bool>
</resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 9e98efd..89c912fd 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2834,6 +2834,7 @@
<public-group type="drawable" first-id="0x010800b4">
<public name="autofilled_highlight" />
+ <public name="ic_picture_in_picture" />
</public-group>
<public-group type="string" first-id="0x01040019">
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 907294d..1dd8227 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -427,6 +427,7 @@
<java-symbol type="integer" name="config_mdc_initial_max_retry" />
<java-symbol type="integer" name="config_keepPreloadsMinDays" />
<java-symbol type="bool" name="config_hasPermanentDpad" />
+ <java-symbol type="bool" name="config_useDefaultFocusHighlight" />
<java-symbol type="color" name="tab_indicator_text_v4" />
diff --git a/core/res/res/values/themes_device_defaults.xml b/core/res/res/values/themes_device_defaults.xml
index e0b4ec5..d80ff1d 100644
--- a/core/res/res/values/themes_device_defaults.xml
+++ b/core/res/res/values/themes_device_defaults.xml
@@ -794,6 +794,8 @@
<!-- Theme used for the intent picker activity. -->
<style name="Theme.DeviceDefault.Resolver" parent="Theme.Material.Light">
+ <item name="windowEnterTransition">@empty</item>
+ <item name="windowExitTransition">@empty</item>
<item name="windowIsTranslucent">true</item>
<item name="windowNoTitle">true</item>
<item name="windowBackground">@color/transparent</item>
diff --git a/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java b/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java
index 0acff9b..39b999d 100644
--- a/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java
@@ -24,11 +24,6 @@
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
-import android.view.textclassifier.TextClassificationManager;
-import android.view.textclassifier.TextClassificationResult;
-import android.view.textclassifier.TextClassifier;
-import android.view.textclassifier.TextLanguage;
-import android.view.textclassifier.TextSelection;
import org.hamcrest.BaseMatcher;
import org.hamcrest.Description;
@@ -74,6 +69,23 @@
}
@Test
+ public void testSmartSelection_nullLocaleList() {
+ if (isTextClassifierDisabled()) return;
+
+ String text = "Contact me at droid@android.com";
+ String selected = "droid";
+ String suggested = "droid@android.com";
+ int startIndex = text.indexOf(selected);
+ int endIndex = startIndex + selected.length();
+ int smartStartIndex = text.indexOf(suggested);
+ int smartEndIndex = smartStartIndex + suggested.length();
+ LocaleList nullLocales = null;
+
+ assertThat(mClassifier.suggestSelection(text, startIndex, endIndex, nullLocales),
+ isTextSelection(smartStartIndex, smartEndIndex, TextClassifier.TYPE_EMAIL));
+ }
+
+ @Test
public void testSmartSelection_url() {
if (isTextClassifierDisabled()) return;
@@ -114,6 +126,19 @@
}
@Test
+ public void testTextClassificationResult_nullLocaleList() {
+ if (isTextClassifierDisabled()) return;
+
+ String text = "Contact me at droid@android.com";
+ String classifiedText = "droid@android.com";
+ int startIndex = text.indexOf(classifiedText);
+ int endIndex = startIndex + classifiedText.length();
+ LocaleList nullLocales = null;
+ assertThat(mClassifier.getTextClassificationResult(text, startIndex, endIndex, nullLocales),
+ isTextClassificationResult(classifiedText, TextClassifier.TYPE_EMAIL));
+ }
+
+ @Test
public void testLanguageDetection() {
if (isTextClassifierDisabled()) return;
diff --git a/docs/html/reference/_book.yaml b/docs/html/reference/_book.yaml
new file mode 100644
index 0000000..b902a61
--- /dev/null
+++ b/docs/html/reference/_book.yaml
@@ -0,0 +1,853 @@
+reference:
+- title: Class Index
+ path: /reference/classes.html
+ status_text: no-toggle
+- title: Package Index
+ path: /reference/packages.html
+ status_text: no-toggle
+- title: android
+ path: /reference/android/package-summary.html
+ status_text: apilevel-1
+- title: android.accessibilityservice
+ path: /reference/android/accessibilityservice/package-summary.html
+ status_text: apilevel-4
+- title: android.accounts
+ path: /reference/android/accounts/package-summary.html
+ status_text: apilevel-5
+- title: android.animation
+ path: /reference/android/animation/package-summary.html
+ status_text: apilevel-11
+- title: android.annotation
+ path: /reference/android/annotation/package-summary.html
+ status_text: apilevel-16
+- title: android.app
+ path: /reference/android/app/package-summary.html
+ status_text: apilevel-1
+- title: android.app.admin
+ path: /reference/android/app/admin/package-summary.html
+ status_text: apilevel-8
+- title: android.app.assist
+ path: /reference/android/app/assist/package-summary.html
+ status_text: apilevel-23
+- title: android.app.backup
+ path: /reference/android/app/backup/package-summary.html
+ status_text: apilevel-8
+- title: android.app.job
+ path: /reference/android/app/job/package-summary.html
+ status_text: apilevel-21
+- title: android.app.usage
+ path: /reference/android/app/usage/package-summary.html
+ status_text: apilevel-21
+- title: android.appwidget
+ path: /reference/android/appwidget/package-summary.html
+ status_text: apilevel-3
+- title: android.bluetooth
+ path: /reference/android/bluetooth/package-summary.html
+ status_text: apilevel-5
+- title: android.bluetooth.le
+ path: /reference/android/bluetooth/le/package-summary.html
+ status_text: apilevel-21
+- title: android.companion
+ path: /reference/android/companion/package-summary.html
+ status_text: apilevel-O
+- title: android.content
+ path: /reference/android/content/package-summary.html
+ status_text: apilevel-1
+- title: android.content.pm
+ path: /reference/android/content/pm/package-summary.html
+ status_text: apilevel-1
+- title: android.content.res
+ path: /reference/android/content/res/package-summary.html
+ status_text: apilevel-1
+- title: android.database
+ path: /reference/android/database/package-summary.html
+ status_text: apilevel-1
+- title: android.database.sqlite
+ path: /reference/android/database/sqlite/package-summary.html
+ status_text: apilevel-1
+- title: android.databinding
+ path: /reference/android/databinding/package-summary.html
+ status_text: apilevel-
+- title: android.drm
+ path: /reference/android/drm/package-summary.html
+ status_text: apilevel-11
+- title: android.gesture
+ path: /reference/android/gesture/package-summary.html
+ status_text: apilevel-4
+- title: android.graphics
+ path: /reference/android/graphics/package-summary.html
+ status_text: apilevel-1
+- title: android.graphics.drawable
+ path: /reference/android/graphics/drawable/package-summary.html
+ status_text: apilevel-1
+- title: android.graphics.drawable.shapes
+ path: /reference/android/graphics/drawable/shapes/package-summary.html
+ status_text: apilevel-1
+- title: android.graphics.fonts
+ path: /reference/android/graphics/fonts/package-summary.html
+ status_text: apilevel-O
+- title: android.graphics.pdf
+ path: /reference/android/graphics/pdf/package-summary.html
+ status_text: apilevel-19
+- title: android.hardware
+ path: /reference/android/hardware/package-summary.html
+ status_text: apilevel-1
+- title: android.hardware.camera2
+ path: /reference/android/hardware/camera2/package-summary.html
+ status_text: apilevel-21
+- title: android.hardware.camera2.params
+ path: /reference/android/hardware/camera2/params/package-summary.html
+ status_text: apilevel-21
+- title: android.hardware.display
+ path: /reference/android/hardware/display/package-summary.html
+ status_text: apilevel-17
+- title: android.hardware.fingerprint
+ path: /reference/android/hardware/fingerprint/package-summary.html
+ status_text: apilevel-23
+- title: android.hardware.input
+ path: /reference/android/hardware/input/package-summary.html
+ status_text: apilevel-16
+- title: android.hardware.usb
+ path: /reference/android/hardware/usb/package-summary.html
+ status_text: apilevel-12
+- title: android.icu.lang
+ path: /reference/android/icu/lang/package-summary.html
+ status_text: apilevel-24
+- title: android.icu.math
+ path: /reference/android/icu/math/package-summary.html
+ status_text: apilevel-24
+- title: android.icu.text
+ path: /reference/android/icu/text/package-summary.html
+ status_text: apilevel-24
+- title: android.icu.util
+ path: /reference/android/icu/util/package-summary.html
+ status_text: apilevel-24
+- title: android.inputmethodservice
+ path: /reference/android/inputmethodservice/package-summary.html
+ status_text: apilevel-3
+- title: android.location
+ path: /reference/android/location/package-summary.html
+ status_text: apilevel-1
+- title: android.media
+ path: /reference/android/media/package-summary.html
+ status_text: apilevel-1
+- title: android.media.audiofx
+ path: /reference/android/media/audiofx/package-summary.html
+ status_text: apilevel-9
+- title: android.media.browse
+ path: /reference/android/media/browse/package-summary.html
+ status_text: apilevel-21
+- title: android.media.effect
+ path: /reference/android/media/effect/package-summary.html
+ status_text: apilevel-14
+- title: android.media.midi
+ path: /reference/android/media/midi/package-summary.html
+ status_text: apilevel-23
+- title: android.media.projection
+ path: /reference/android/media/projection/package-summary.html
+ status_text: apilevel-21
+- title: android.media.session
+ path: /reference/android/media/session/package-summary.html
+ status_text: apilevel-21
+- title: android.media.tv
+ path: /reference/android/media/tv/package-summary.html
+ status_text: apilevel-21
+- title: android.mtp
+ path: /reference/android/mtp/package-summary.html
+ status_text: apilevel-12
+- title: android.net
+ path: /reference/android/net/package-summary.html
+ status_text: apilevel-1
+- title: android.net.http
+ path: /reference/android/net/http/package-summary.html
+ status_text: apilevel-1
+- title: android.net.nsd
+ path: /reference/android/net/nsd/package-summary.html
+ status_text: apilevel-16
+- title: android.net.rtp
+ path: /reference/android/net/rtp/package-summary.html
+ status_text: apilevel-12
+- title: android.net.sip
+ path: /reference/android/net/sip/package-summary.html
+ status_text: apilevel-9
+- title: android.net.wifi
+ path: /reference/android/net/wifi/package-summary.html
+ status_text: apilevel-1
+- title: android.net.wifi.aware
+ path: /reference/android/net/wifi/aware/package-summary.html
+ status_text: apilevel-O
+- title: android.net.wifi.hotspot2
+ path: /reference/android/net/wifi/hotspot2/package-summary.html
+ status_text: apilevel-O
+- title: android.net.wifi.hotspot2.omadm
+ path: /reference/android/net/wifi/hotspot2/omadm/package-summary.html
+ status_text: apilevel-O
+- title: android.net.wifi.hotspot2.pps
+ path: /reference/android/net/wifi/hotspot2/pps/package-summary.html
+ status_text: apilevel-O
+- title: android.net.wifi.p2p
+ path: /reference/android/net/wifi/p2p/package-summary.html
+ status_text: apilevel-14
+- title: android.net.wifi.p2p.nsd
+ path: /reference/android/net/wifi/p2p/nsd/package-summary.html
+ status_text: apilevel-16
+- title: android.nfc
+ path: /reference/android/nfc/package-summary.html
+ status_text: apilevel-9
+- title: android.nfc.cardemulation
+ path: /reference/android/nfc/cardemulation/package-summary.html
+ status_text: apilevel-19
+- title: android.nfc.tech
+ path: /reference/android/nfc/tech/package-summary.html
+ status_text: apilevel-10
+- title: android.opengl
+ path: /reference/android/opengl/package-summary.html
+ status_text: apilevel-1
+- title: android.os
+ path: /reference/android/os/package-summary.html
+ status_text: apilevel-1
+- title: android.os.health
+ path: /reference/android/os/health/package-summary.html
+ status_text: apilevel-24
+- title: android.os.storage
+ path: /reference/android/os/storage/package-summary.html
+ status_text: apilevel-9
+- title: android.preference
+ path: /reference/android/preference/package-summary.html
+ status_text: apilevel-1
+- title: android.print
+ path: /reference/android/print/package-summary.html
+ status_text: apilevel-19
+- title: android.print.pdf
+ path: /reference/android/print/pdf/package-summary.html
+ status_text: apilevel-19
+- title: android.printservice
+ path: /reference/android/printservice/package-summary.html
+ status_text: apilevel-19
+- title: android.provider
+ path: /reference/android/provider/package-summary.html
+ status_text: apilevel-1
+- title: android.renderscript
+ path: /reference/android/renderscript/package-summary.html
+ status_text: apilevel-11
+- title: android.sax
+ path: /reference/android/sax/package-summary.html
+ status_text: apilevel-1
+- title: android.security
+ path: /reference/android/security/package-summary.html
+ status_text: apilevel-14
+- title: android.security.keystore
+ path: /reference/android/security/keystore/package-summary.html
+ status_text: apilevel-23
+- title: android.service.autofill
+ path: /reference/android/service/autofill/package-summary.html
+ status_text: apilevel-O
+- title: android.service.carrier
+ path: /reference/android/service/carrier/package-summary.html
+ status_text: apilevel-22
+- title: android.service.chooser
+ path: /reference/android/service/chooser/package-summary.html
+ status_text: apilevel-23
+- title: android.service.dreams
+ path: /reference/android/service/dreams/package-summary.html
+ status_text: apilevel-17
+- title: android.service.media
+ path: /reference/android/service/media/package-summary.html
+ status_text: apilevel-21
+- title: android.service.notification
+ path: /reference/android/service/notification/package-summary.html
+ status_text: apilevel-18
+- title: android.service.quicksettings
+ path: /reference/android/service/quicksettings/package-summary.html
+ status_text: apilevel-24
+- title: android.service.restrictions
+ path: /reference/android/service/restrictions/package-summary.html
+ status_text: apilevel-21
+- title: android.service.textservice
+ path: /reference/android/service/textservice/package-summary.html
+ status_text: apilevel-14
+- title: android.service.voice
+ path: /reference/android/service/voice/package-summary.html
+ status_text: apilevel-21
+- title: android.service.vr
+ path: /reference/android/service/vr/package-summary.html
+ status_text: apilevel-24
+- title: android.service.wallpaper
+ path: /reference/android/service/wallpaper/package-summary.html
+ status_text: apilevel-7
+- title: android.speech
+ path: /reference/android/speech/package-summary.html
+ status_text: apilevel-3
+- title: android.speech.tts
+ path: /reference/android/speech/tts/package-summary.html
+ status_text: apilevel-4
+- title: android.support.animation
+ path: /reference/android/support/animation/package-summary.html
+ status_text: apilevel-25.3.0
+- title: android.support.annotation
+ path: /reference/android/support/annotation/package-summary.html
+ status_text: apilevel-
+- title: android.support.app.recommendation
+ path: /reference/android/support/app/recommendation/package-summary.html
+ status_text: apilevel-23.0.0
+- title: android.support.compat
+ path: /reference/android/support/compat/package-summary.html
+ status_text: apilevel-
+- title: android.support.coreui
+ path: /reference/android/support/coreui/package-summary.html
+ status_text: apilevel-
+- title: android.support.coreutils
+ path: /reference/android/support/coreutils/package-summary.html
+ status_text: apilevel-
+- title: android.support.customtabs
+ path: /reference/android/support/customtabs/package-summary.html
+ status_text: apilevel-23.0.0
+- title: android.support.design
+ path: /reference/android/support/design/package-summary.html
+ status_text: apilevel-
+- title: android.support.design.widget
+ path: /reference/android/support/design/widget/package-summary.html
+ status_text: apilevel-22.2.0
+- title: android.support.dynamicanimation
+ path: /reference/android/support/dynamicanimation/package-summary.html
+ status_text: apilevel-
+- title: android.support.exifinterface
+ path: /reference/android/support/exifinterface/package-summary.html
+ status_text: apilevel-
+- title: android.support.fragment
+ path: /reference/android/support/fragment/package-summary.html
+ status_text: apilevel-
+- title: android.support.graphics.drawable
+ path: /reference/android/support/graphics/drawable/package-summary.html
+ status_text: apilevel-23.2.0
+- title: android.support.graphics.drawable.animated
+ path: /reference/android/support/graphics/drawable/animated/package-summary.html
+ status_text: apilevel-
+- title: android.support.media
+ path: /reference/android/support/media/package-summary.html
+ status_text: apilevel-25.1.0
+- title: android.support.media.instantvideo
+ path: /reference/android/support/media/instantvideo/package-summary.html
+ status_text: apilevel-
+- title: android.support.media.instantvideo.preload
+ path: /reference/android/support/media/instantvideo/preload/package-summary.html
+ status_text: apilevel-26.0.0-alpha1
+- title: android.support.media.instantvideo.widget
+ path: /reference/android/support/media/instantvideo/widget/package-summary.html
+ status_text: apilevel-26.0.0-alpha1
+- title: android.support.media.tv
+ path: /reference/android/support/media/tv/package-summary.html
+ status_text: apilevel-26.0.0-alpha1
+- title: android.support.mediacompat
+ path: /reference/android/support/mediacompat/package-summary.html
+ status_text: apilevel-
+- title: android.support.multidex
+ path: /reference/android/support/multidex/package-summary.html
+ status_text: apilevel-
+- title: android.support.percent
+ path: /reference/android/support/percent/package-summary.html
+ status_text: apilevel-23.0.0
+- title: android.support.recommendation
+ path: /reference/android/support/recommendation/package-summary.html
+ status_text: apilevel-
+- title: android.support.transition
+ path: /reference/android/support/transition/package-summary.html
+ status_text: apilevel-24.2.0
+- title: android.support.v13
+ path: /reference/android/support/v13/package-summary.html
+ status_text: apilevel-
+- title: android.support.v13.app
+ path: /reference/android/support/v13/app/package-summary.html
+ status_text: apilevel-22.0.0
+- title: android.support.v13.view
+ path: /reference/android/support/v13/view/package-summary.html
+ status_text: apilevel-24.0.0
+- title: android.support.v13.view.inputmethod
+ path: /reference/android/support/v13/view/inputmethod/package-summary.html
+ status_text: apilevel-25.0.0
+- title: android.support.v14.preference
+ path: /reference/android/support/v14/preference/package-summary.html
+ status_text: apilevel-23.0.0
+- title: android.support.v17.leanback
+ path: /reference/android/support/v17/leanback/package-summary.html
+ status_text: apilevel-
+- title: android.support.v17.leanback.app
+ path: /reference/android/support/v17/leanback/app/package-summary.html
+ status_text: apilevel-22.0.0
+- title: android.support.v17.leanback.database
+ path: /reference/android/support/v17/leanback/database/package-summary.html
+ status_text: apilevel-22.0.0
+- title: android.support.v17.leanback.graphics
+ path: /reference/android/support/v17/leanback/graphics/package-summary.html
+ status_text: apilevel-22.0.0
+- title: android.support.v17.leanback.media
+ path: /reference/android/support/v17/leanback/media/package-summary.html
+ status_text: apilevel-25.1.0
+- title: android.support.v17.leanback.system
+ path: /reference/android/support/v17/leanback/system/package-summary.html
+ status_text: apilevel-22.2.1
+- title: android.support.v17.leanback.widget
+ path: /reference/android/support/v17/leanback/widget/package-summary.html
+ status_text: apilevel-22.0.0
+- title: android.support.v17.leanback.widget.picker
+ path: /reference/android/support/v17/leanback/widget/picker/package-summary.html
+ status_text: apilevel-23.2.0
+- title: android.support.v17.preference
+ path: /reference/android/support/v17/preference/package-summary.html
+ status_text: apilevel-23.0.0
+- title: android.support.v4
+ path: /reference/android/support/v4/package-summary.html
+ status_text: apilevel-
+- title: android.support.v4.accessibilityservice
+ path: /reference/android/support/v4/accessibilityservice/package-summary.html
+ status_text: apilevel-22.0.0
+- title: android.support.v4.app
+ path: /reference/android/support/v4/app/package-summary.html
+ status_text: apilevel-22.0.0
+- title: android.support.v4.content
+ path: /reference/android/support/v4/content/package-summary.html
+ status_text: apilevel-22.0.0
+- title: android.support.v4.content.pm
+ path: /reference/android/support/v4/content/pm/package-summary.html
+ status_text: apilevel-22.2.0
+- title: android.support.v4.content.res
+ path: /reference/android/support/v4/content/res/package-summary.html
+ status_text: apilevel-22.2.0
+- title: android.support.v4.database
+ path: /reference/android/support/v4/database/package-summary.html
+ status_text: apilevel-22.0.0
+- title: android.support.v4.graphics
+ path: /reference/android/support/v4/graphics/package-summary.html
+ status_text: apilevel-22.0.0
+- title: android.support.v4.graphics.drawable
+ path: /reference/android/support/v4/graphics/drawable/package-summary.html
+ status_text: apilevel-22.0.0
+- title: android.support.v4.hardware.display
+ path: /reference/android/support/v4/hardware/display/package-summary.html
+ status_text: apilevel-22.0.0
+- title: android.support.v4.hardware.fingerprint
+ path: /reference/android/support/v4/hardware/fingerprint/package-summary.html
+ status_text: apilevel-23.0.0
+- title: android.support.v4.math
+ path: /reference/android/support/v4/math/package-summary.html
+ status_text: apilevel-26.0.0-alpha1
+- title: android.support.v4.media
+ path: /reference/android/support/v4/media/package-summary.html
+ status_text: apilevel-22.0.0
+- title: android.support.v4.media.session
+ path: /reference/android/support/v4/media/session/package-summary.html
+ status_text: apilevel-22.0.0
+- title: android.support.v4.net
+ path: /reference/android/support/v4/net/package-summary.html
+ status_text: apilevel-22.0.0
+- title: android.support.v4.os
+ path: /reference/android/support/v4/os/package-summary.html
+ status_text: apilevel-22.0.0
+- title: android.support.v4.print
+ path: /reference/android/support/v4/print/package-summary.html
+ status_text: apilevel-22.0.0
+- title: android.support.v4.provider
+ path: /reference/android/support/v4/provider/package-summary.html
+ status_text: apilevel-22.0.0
+- title: android.support.v4.text
+ path: /reference/android/support/v4/text/package-summary.html
+ status_text: apilevel-22.0.0
+- title: android.support.v4.text.util
+ path: /reference/android/support/v4/text/util/package-summary.html
+ status_text: apilevel-24.2.0
+- title: android.support.v4.util
+ path: /reference/android/support/v4/util/package-summary.html
+ status_text: apilevel-22.0.0
+- title: android.support.v4.view
+ path: /reference/android/support/v4/view/package-summary.html
+ status_text: apilevel-22.0.0
+- title: android.support.v4.view.accessibility
+ path: /reference/android/support/v4/view/accessibility/package-summary.html
+ status_text: apilevel-22.0.0
+- title: android.support.v4.view.animation
+ path: /reference/android/support/v4/view/animation/package-summary.html
+ status_text: apilevel-22.1.0
+- title: android.support.v4.widget
+ path: /reference/android/support/v4/widget/package-summary.html
+ status_text: apilevel-22.0.0
+- title: android.support.v7.app
+ path: /reference/android/support/v7/app/package-summary.html
+ status_text: apilevel-22.0.0
+- title: android.support.v7.appcompat
+ path: /reference/android/support/v7/appcompat/package-summary.html
+ status_text: apilevel-22.2.0
+- title: android.support.v7.cardview
+ path: /reference/android/support/v7/cardview/package-summary.html
+ status_text: apilevel-
+- title: android.support.v7.content.res
+ path: /reference/android/support/v7/content/res/package-summary.html
+ status_text: apilevel-24.0.0
+- title: android.support.v7.graphics
+ path: /reference/android/support/v7/graphics/package-summary.html
+ status_text: apilevel-22.0.0
+- title: android.support.v7.graphics.drawable
+ path: /reference/android/support/v7/graphics/drawable/package-summary.html
+ status_text: apilevel-23.0.0
+- title: android.support.v7.gridlayout
+ path: /reference/android/support/v7/gridlayout/package-summary.html
+ status_text: apilevel-
+- title: android.support.v7.media
+ path: /reference/android/support/v7/media/package-summary.html
+ status_text: apilevel-22.0.0
+- title: android.support.v7.mediarouter
+ path: /reference/android/support/v7/mediarouter/package-summary.html
+ status_text: apilevel-
+- title: android.support.v7.palette
+ path: /reference/android/support/v7/palette/package-summary.html
+ status_text: apilevel-
+- title: android.support.v7.preference
+ path: /reference/android/support/v7/preference/package-summary.html
+ status_text: apilevel-23.0.0
+- title: android.support.v7.recyclerview
+ path: /reference/android/support/v7/recyclerview/package-summary.html
+ status_text: apilevel-22.2.0
+- title: android.support.v7.util
+ path: /reference/android/support/v7/util/package-summary.html
+ status_text: apilevel-22.1.0
+- title: android.support.v7.view
+ path: /reference/android/support/v7/view/package-summary.html
+ status_text: apilevel-22.0.0
+- title: android.support.v7.widget
+ path: /reference/android/support/v7/widget/package-summary.html
+ status_text: apilevel-22.0.0
+- title: android.support.v7.widget.helper
+ path: /reference/android/support/v7/widget/helper/package-summary.html
+ status_text: apilevel-22.2.0
+- title: android.support.v7.widget.util
+ path: /reference/android/support/v7/widget/util/package-summary.html
+ status_text: apilevel-22.1.0
+- title: android.support.v8.renderscript
+ path: /reference/android/support/v8/renderscript/package-summary.html
+ status_text: apilevel-23.0.0
+- title: android.support.wearable
+ path: /reference/android/support/wearable/package-summary.html
+ status_text: apilevel-
+- title: android.support.wearable.view
+ path: /reference/android/support/wearable/view/package-summary.html
+ status_text: apilevel-26.0.0-alpha1
+- title: android.system
+ path: /reference/android/system/package-summary.html
+ status_text: apilevel-21
+- title: android.telecom
+ path: /reference/android/telecom/package-summary.html
+ status_text: apilevel-21
+- title: android.telephony
+ path: /reference/android/telephony/package-summary.html
+ status_text: apilevel-1
+- title: android.telephony.cdma
+ path: /reference/android/telephony/cdma/package-summary.html
+ status_text: apilevel-5
+- title: android.telephony.gsm
+ path: /reference/android/telephony/gsm/package-summary.html
+ status_text: apilevel-1
+- title: android.test
+ path: /reference/android/test/package-summary.html
+ status_text: apilevel-1
+- title: android.test.mock
+ path: /reference/android/test/mock/package-summary.html
+ status_text: apilevel-1
+- title: android.test.suitebuilder
+ path: /reference/android/test/suitebuilder/package-summary.html
+ status_text: apilevel-1
+- title: android.test.suitebuilder.annotation
+ path: /reference/android/test/suitebuilder/annotation/package-summary.html
+ status_text: apilevel-1
+- title: android.text
+ path: /reference/android/text/package-summary.html
+ status_text: apilevel-1
+- title: android.text.format
+ path: /reference/android/text/format/package-summary.html
+ status_text: apilevel-3
+- title: android.text.method
+ path: /reference/android/text/method/package-summary.html
+ status_text: apilevel-1
+- title: android.text.style
+ path: /reference/android/text/style/package-summary.html
+ status_text: apilevel-1
+- title: android.text.util
+ path: /reference/android/text/util/package-summary.html
+ status_text: apilevel-1
+- title: android.transition
+ path: /reference/android/transition/package-summary.html
+ status_text: apilevel-19
+- title: android.util
+ path: /reference/android/util/package-summary.html
+ status_text: apilevel-1
+- title: android.view
+ path: /reference/android/view/package-summary.html
+ status_text: apilevel-1
+- title: android.view.accessibility
+ path: /reference/android/view/accessibility/package-summary.html
+ status_text: apilevel-4
+- title: android.view.animation
+ path: /reference/android/view/animation/package-summary.html
+ status_text: apilevel-1
+- title: android.view.autofill
+ path: /reference/android/view/autofill/package-summary.html
+ status_text: apilevel-O
+- title: android.view.inputmethod
+ path: /reference/android/view/inputmethod/package-summary.html
+ status_text: apilevel-3
+- title: android.view.textclassifier
+ path: /reference/android/view/textclassifier/package-summary.html
+ status_text: apilevel-O
+- title: android.view.textservice
+ path: /reference/android/view/textservice/package-summary.html
+ status_text: apilevel-14
+- title: android.webkit
+ path: /reference/android/webkit/package-summary.html
+ status_text: apilevel-1
+- title: android.widget
+ path: /reference/android/widget/package-summary.html
+ status_text: apilevel-1
+- title: com.android.test.runner
+ path: /reference/com/android/test/runner/package-summary.html
+ status_text: apilevel-
+- title: dalvik.annotation
+ path: /reference/dalvik/annotation/package-summary.html
+ status_text: apilevel-1
+- title: dalvik.bytecode
+ path: /reference/dalvik/bytecode/package-summary.html
+ status_text: apilevel-1
+- title: dalvik.system
+ path: /reference/dalvik/system/package-summary.html
+ status_text: apilevel-1
+- title: java.awt.font
+ path: /reference/java/awt/font/package-summary.html
+ status_text: apilevel-1
+- title: java.beans
+ path: /reference/java/beans/package-summary.html
+ status_text: apilevel-3
+- title: java.io
+ path: /reference/java/io/package-summary.html
+ status_text: apilevel-1
+- title: java.lang
+ path: /reference/java/lang/package-summary.html
+ status_text: apilevel-1
+- title: java.lang.annotation
+ path: /reference/java/lang/annotation/package-summary.html
+ status_text: apilevel-1
+- title: java.lang.invoke
+ path: /reference/java/lang/invoke/package-summary.html
+ status_text: apilevel-O
+- title: java.lang.ref
+ path: /reference/java/lang/ref/package-summary.html
+ status_text: apilevel-1
+- title: java.lang.reflect
+ path: /reference/java/lang/reflect/package-summary.html
+ status_text: apilevel-1
+- title: java.math
+ path: /reference/java/math/package-summary.html
+ status_text: apilevel-1
+- title: java.net
+ path: /reference/java/net/package-summary.html
+ status_text: apilevel-1
+- title: java.nio
+ path: /reference/java/nio/package-summary.html
+ status_text: apilevel-1
+- title: java.nio.channels
+ path: /reference/java/nio/channels/package-summary.html
+ status_text: apilevel-1
+- title: java.nio.channels.spi
+ path: /reference/java/nio/channels/spi/package-summary.html
+ status_text: apilevel-1
+- title: java.nio.charset
+ path: /reference/java/nio/charset/package-summary.html
+ status_text: apilevel-1
+- title: java.nio.charset.spi
+ path: /reference/java/nio/charset/spi/package-summary.html
+ status_text: apilevel-1
+- title: java.nio.file
+ path: /reference/java/nio/file/package-summary.html
+ status_text: apilevel-O
+- title: java.nio.file.attribute
+ path: /reference/java/nio/file/attribute/package-summary.html
+ status_text: apilevel-O
+- title: java.nio.file.spi
+ path: /reference/java/nio/file/spi/package-summary.html
+ status_text: apilevel-O
+- title: java.security
+ path: /reference/java/security/package-summary.html
+ status_text: apilevel-1
+- title: java.security.acl
+ path: /reference/java/security/acl/package-summary.html
+ status_text: apilevel-1
+- title: java.security.cert
+ path: /reference/java/security/cert/package-summary.html
+ status_text: apilevel-1
+- title: java.security.interfaces
+ path: /reference/java/security/interfaces/package-summary.html
+ status_text: apilevel-1
+- title: java.security.spec
+ path: /reference/java/security/spec/package-summary.html
+ status_text: apilevel-1
+- title: java.sql
+ path: /reference/java/sql/package-summary.html
+ status_text: apilevel-1
+- title: java.text
+ path: /reference/java/text/package-summary.html
+ status_text: apilevel-1
+- title: java.time
+ path: /reference/java/time/package-summary.html
+ status_text: apilevel-O
+- title: java.time.chrono
+ path: /reference/java/time/chrono/package-summary.html
+ status_text: apilevel-O
+- title: java.time.format
+ path: /reference/java/time/format/package-summary.html
+ status_text: apilevel-O
+- title: java.time.temporal
+ path: /reference/java/time/temporal/package-summary.html
+ status_text: apilevel-O
+- title: java.time.zone
+ path: /reference/java/time/zone/package-summary.html
+ status_text: apilevel-O
+- title: java.util
+ path: /reference/java/util/package-summary.html
+ status_text: apilevel-1
+- title: java.util.concurrent
+ path: /reference/java/util/concurrent/package-summary.html
+ status_text: apilevel-1
+- title: java.util.concurrent.atomic
+ path: /reference/java/util/concurrent/atomic/package-summary.html
+ status_text: apilevel-1
+- title: java.util.concurrent.locks
+ path: /reference/java/util/concurrent/locks/package-summary.html
+ status_text: apilevel-1
+- title: java.util.function
+ path: /reference/java/util/function/package-summary.html
+ status_text: apilevel-24
+- title: java.util.jar
+ path: /reference/java/util/jar/package-summary.html
+ status_text: apilevel-1
+- title: java.util.logging
+ path: /reference/java/util/logging/package-summary.html
+ status_text: apilevel-1
+- title: java.util.prefs
+ path: /reference/java/util/prefs/package-summary.html
+ status_text: apilevel-1
+- title: java.util.regex
+ path: /reference/java/util/regex/package-summary.html
+ status_text: apilevel-1
+- title: java.util.stream
+ path: /reference/java/util/stream/package-summary.html
+ status_text: apilevel-24
+- title: java.util.zip
+ path: /reference/java/util/zip/package-summary.html
+ status_text: apilevel-1
+- title: javax.crypto
+ path: /reference/javax/crypto/package-summary.html
+ status_text: apilevel-1
+- title: javax.crypto.interfaces
+ path: /reference/javax/crypto/interfaces/package-summary.html
+ status_text: apilevel-1
+- title: javax.crypto.spec
+ path: /reference/javax/crypto/spec/package-summary.html
+ status_text: apilevel-1
+- title: javax.microedition.khronos.egl
+ path: /reference/javax/microedition/khronos/egl/package-summary.html
+ status_text: apilevel-1
+- title: javax.microedition.khronos.opengles
+ path: /reference/javax/microedition/khronos/opengles/package-summary.html
+ status_text: apilevel-1
+- title: javax.net
+ path: /reference/javax/net/package-summary.html
+ status_text: apilevel-1
+- title: javax.net.ssl
+ path: /reference/javax/net/ssl/package-summary.html
+ status_text: apilevel-1
+- title: javax.security.auth
+ path: /reference/javax/security/auth/package-summary.html
+ status_text: apilevel-1
+- title: javax.security.auth.callback
+ path: /reference/javax/security/auth/callback/package-summary.html
+ status_text: apilevel-1
+- title: javax.security.auth.login
+ path: /reference/javax/security/auth/login/package-summary.html
+ status_text: apilevel-1
+- title: javax.security.auth.x500
+ path: /reference/javax/security/auth/x500/package-summary.html
+ status_text: apilevel-1
+- title: javax.security.cert
+ path: /reference/javax/security/cert/package-summary.html
+ status_text: apilevel-1
+- title: javax.sql
+ path: /reference/javax/sql/package-summary.html
+ status_text: apilevel-1
+- title: javax.xml
+ path: /reference/javax/xml/package-summary.html
+ status_text: apilevel-1
+- title: javax.xml.datatype
+ path: /reference/javax/xml/datatype/package-summary.html
+ status_text: apilevel-8
+- title: javax.xml.namespace
+ path: /reference/javax/xml/namespace/package-summary.html
+ status_text: apilevel-8
+- title: javax.xml.parsers
+ path: /reference/javax/xml/parsers/package-summary.html
+ status_text: apilevel-1
+- title: javax.xml.transform
+ path: /reference/javax/xml/transform/package-summary.html
+ status_text: apilevel-8
+- title: javax.xml.transform.dom
+ path: /reference/javax/xml/transform/dom/package-summary.html
+ status_text: apilevel-8
+- title: javax.xml.transform.sax
+ path: /reference/javax/xml/transform/sax/package-summary.html
+ status_text: apilevel-8
+- title: javax.xml.transform.stream
+ path: /reference/javax/xml/transform/stream/package-summary.html
+ status_text: apilevel-8
+- title: javax.xml.validation
+ path: /reference/javax/xml/validation/package-summary.html
+ status_text: apilevel-8
+- title: javax.xml.xpath
+ path: /reference/javax/xml/xpath/package-summary.html
+ status_text: apilevel-8
+- title: junit.framework
+ path: /reference/junit/framework/package-summary.html
+ status_text: apilevel-1
+- title: junit.runner
+ path: /reference/junit/runner/package-summary.html
+ status_text: apilevel-1
+- title: org.apache.http.conn
+ path: /reference/org/apache/http/conn/package-summary.html
+ status_text: apilevel-1
+- title: org.apache.http.conn.scheme
+ path: /reference/org/apache/http/conn/scheme/package-summary.html
+ status_text: apilevel-1
+- title: org.apache.http.conn.ssl
+ path: /reference/org/apache/http/conn/ssl/package-summary.html
+ status_text: apilevel-1
+- title: org.apache.http.params
+ path: /reference/org/apache/http/params/package-summary.html
+ status_text: apilevel-1
+- title: org.json
+ path: /reference/org/json/package-summary.html
+ status_text: apilevel-1
+- title: org.w3c.dom
+ path: /reference/org/w3c/dom/package-summary.html
+ status_text: apilevel-1
+- title: org.w3c.dom.ls
+ path: /reference/org/w3c/dom/ls/package-summary.html
+ status_text: apilevel-8
+- title: org.xml.sax
+ path: /reference/org/xml/sax/package-summary.html
+ status_text: apilevel-1
+- title: org.xml.sax.ext
+ path: /reference/org/xml/sax/ext/package-summary.html
+ status_text: apilevel-1
+- title: org.xml.sax.helpers
+ path: /reference/org/xml/sax/helpers/package-summary.html
+ status_text: apilevel-1
+- title: org.xmlpull.v1
+ path: /reference/org/xmlpull/v1/package-summary.html
+ status_text: apilevel-1
+- title: org.xmlpull.v1.sax2
+ path: /reference/org/xmlpull/v1/sax2/package-summary.html
+ status_text: apilevel-1
diff --git a/docs/html/reference/_project.yaml b/docs/html/reference/_project.yaml
new file mode 100644
index 0000000..e5c26e7
--- /dev/null
+++ b/docs/html/reference/_project.yaml
@@ -0,0 +1,6 @@
+name: "Reference"
+home_url: /reference/
+description: "API Reference packages and classes."
+content_license: cc3-apache2
+buganizer_id: 30209417
+parent_project_metadata_path: /develop/_project.yaml
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java
index 599406c..abdab39 100644
--- a/graphics/java/android/graphics/Bitmap.java
+++ b/graphics/java/android/graphics/Bitmap.java
@@ -996,7 +996,9 @@
}
Bitmap bm;
- if (config != Config.ARGB_8888) {
+ // nullptr color spaces have a particular meaning in native and are interpreted as sRGB
+ // (we also avoid the unnecessary extra work of the else branch)
+ if (config != Config.ARGB_8888 || colorSpace == ColorSpace.get(ColorSpace.Named.SRGB)) {
bm = nativeCreate(null, 0, width, width, height, config.nativeInt, true, null, null);
} else {
if (!(colorSpace instanceof ColorSpace.Rgb)) {
diff --git a/graphics/java/android/graphics/ComposeShader.java b/graphics/java/android/graphics/ComposeShader.java
index e107ea7..0b1141a 100644
--- a/graphics/java/android/graphics/ComposeShader.java
+++ b/graphics/java/android/graphics/ComposeShader.java
@@ -76,6 +76,16 @@
mShaderA.getNativeInstance(), mShaderB.getNativeInstance(), mPorterDuffMode);
}
+ @Override
+ void verifyNativeInstance() {
+ if (mShaderA.getNativeInstance() != mNativeInstanceShaderA
+ || mShaderB.getNativeInstance() != mNativeInstanceShaderB) {
+ // Child shader native instance has been updated,
+ // so our cached native instance is no longer valid - discard it
+ discardNativeInstance();
+ }
+ }
+
/**
* @hide
*/
diff --git a/graphics/java/android/graphics/Shader.java b/graphics/java/android/graphics/Shader.java
index c744757..8410ab2 100644
--- a/graphics/java/android/graphics/Shader.java
+++ b/graphics/java/android/graphics/Shader.java
@@ -105,13 +105,20 @@
return 0;
}
- private void discardNativeInstance() {
+ void discardNativeInstance() {
if (mNativeInstance != 0) {
nativeSafeUnref(mNativeInstance);
mNativeInstance = 0;
}
}
+ /**
+ * Callback for subclasses to call {@link #discardNativeInstance()} if the most recently
+ * constructed native instance is no longer valid.
+ */
+ void verifyNativeInstance() {
+ }
+
@Override
protected void finalize() throws Throwable {
try {
@@ -148,6 +155,9 @@
throw new IllegalStateException("attempting to use a finalized Shader");
}
+ // verify mNativeInstance is valid
+ verifyNativeInstance();
+
if (mNativeInstance == 0) {
mNativeInstance = createNativeInstance(mLocalMatrix == null
? 0 : mLocalMatrix.native_instance);
diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java
index 97d3e5e..18dc0dc 100644
--- a/graphics/java/android/graphics/Typeface.java
+++ b/graphics/java/android/graphics/Typeface.java
@@ -563,6 +563,9 @@
/**
* Constructs a builder with a file descriptor.
*
+ * Caller is responsible for closing the passed file descriptor after {@link #build} is
+ * called.
+ *
* @param fd The file descriptor. The passed fd must be mmap-able.
*/
public Builder(@NonNull FileDescriptor fd) {
diff --git a/libs/hwui/tests/unit/SkiaBehaviorTests.cpp b/libs/hwui/tests/unit/SkiaBehaviorTests.cpp
index 7ae58a6..dafa074 100644
--- a/libs/hwui/tests/unit/SkiaBehaviorTests.cpp
+++ b/libs/hwui/tests/unit/SkiaBehaviorTests.cpp
@@ -20,6 +20,7 @@
#include <SkColorMatrixFilter.h>
#include <SkColorSpace.h>
#include <SkImagePriv.h>
+#include <SkPathOps.h>
#include <SkShader.h>
using namespace android;
@@ -90,6 +91,16 @@
ASSERT_EQ(expected, paint.getBlendMode());
}
+TEST(SkiaBehavior, pathIntersection) {
+ SkPath p0, p1, result;
+ p0.addRect(SkRect::MakeXYWH(-5.0f, 0.0f, 1080.0f, 242.0f));
+ p1.addRect(SkRect::MakeXYWH(0.0f, 0.0f, 1080.0f, 242.0f));
+ Op(p0, p1, kIntersect_SkPathOp, &result);
+ SkRect resultRect;
+ ASSERT_TRUE(result.isRect(&resultRect));
+ ASSERT_EQ(SkRect::MakeXYWH(0.0f, 0.0f, 1075.0f, 242.0f), resultRect);
+}
+
TEST(SkiaBehavior, srgbColorSpaceIsSingleton) {
sk_sp<SkColorSpace> sRGB1 = SkColorSpace::MakeSRGB();
sk_sp<SkColorSpace> sRGB2 = SkColorSpace::MakeSRGB();
diff --git a/media/java/android/media/AudioAttributes.java b/media/java/android/media/AudioAttributes.java
index 77a82ec..e36ceb8 100644
--- a/media/java/android/media/AudioAttributes.java
+++ b/media/java/android/media/AudioAttributes.java
@@ -913,29 +913,6 @@
}
}
- // TODO remove, replaced by non-static API getVolumeControlStream()
- /**
- * Returns the stream type matching the given attributes for volume control.
- * Use this method to derive the stream type needed to configure the volume
- * control slider in an {@link android.app.Activity} with
- * {@link android.app.Activity#setVolumeControlStream(int)}.
- * <BR>Do not use this method to set the stream type on an audio player object
- * (e.g. {@link AudioTrack}, {@link MediaPlayer}) as this is deprecated,
- * use <code>AudioAttributes</code> instead.
- * @param aa non-null AudioAttributes.
- * @return a valid stream type for <code>Activity</code> or stream volume control that matches
- * the attributes, or {@link AudioManager#USE_DEFAULT_STREAM_TYPE} if there isn't a direct
- * match. Note that <code>USE_DEFAULT_STREAM_TYPE</code> is not a valid value
- * for {@link AudioManager#setStreamVolume(int, int, int)}.
- * @deprecated use {@link #getVolumeControlStream()}
- */
- public static int getVolumeControlStream(@NonNull AudioAttributes aa) {
- if (aa == null) {
- throw new IllegalArgumentException("Invalid null audio attributes");
- }
- return toVolumeStreamType(true /*fromGetVolumeControlStream*/, aa);
- }
-
/**
* Returns the stream type matching this {@code AudioAttributes} instance for volume control.
* Use this method to derive the stream type needed to configure the volume
diff --git a/media/java/android/media/tv/TvView.java b/media/java/android/media/tv/TvView.java
index e5af357..9264fe4 100644
--- a/media/java/android/media/tv/TvView.java
+++ b/media/java/android/media/tv/TvView.java
@@ -25,6 +25,7 @@
import android.graphics.Canvas;
import android.graphics.PorterDuff;
import android.graphics.Rect;
+import android.graphics.RectF;
import android.graphics.Region;
import android.media.PlaybackParams;
import android.media.tv.TvInputManager.Session;
@@ -838,10 +839,12 @@
}
private Rect getViewFrameOnScreen() {
- int[] location = new int[2];
- getLocationOnScreen(location);
- return new Rect(location[0], location[1],
- location[0] + getWidth(), location[1] + getHeight());
+ Rect frame = new Rect();
+ getGlobalVisibleRect(frame);
+ RectF frameF = new RectF(frame);
+ getMatrix().mapRect(frameF);
+ frameF.round(frame);
+ return frame;
}
/**
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java
index 5beb412..11c858f 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java
@@ -75,17 +75,21 @@
private BluetoothAdapter mBluetoothAdapter;
private WifiManager mWifiManager;
+ private BluetoothLeScanner mBLEScanner;
private ScanSettings mDefaultScanSettings = new ScanSettings.Builder().build();
+
private List<DeviceFilter<?>> mFilters;
private List<BluetoothLEDeviceFilter> mBLEFilters;
private List<BluetoothDeviceFilter> mBluetoothFilters;
private List<WifiDeviceFilter> mWifiFilters;
private List<ScanFilter> mBLEScanFilters;
+
AssociationRequest mRequest;
List<DeviceFilterPair> mDevicesFound;
DeviceFilterPair mSelectedDevice;
DevicesAdapter mDevicesAdapter;
IFindDeviceCallback mFindCallback;
+
ICompanionDeviceDiscoveryServiceCallback mServiceCallback;
private final ICompanionDeviceDiscoveryService mBinder =
@@ -107,65 +111,9 @@
}
};
- private final ScanCallback mBLEScanCallback = new ScanCallback() {
- @Override
- public void onScanResult(int callbackType, ScanResult result) {
- if (DEBUG) {
- Log.i(LOG_TAG,
- "BLE.onScanResult(callbackType = " + callbackType + ", result = " + result
- + ")");
- }
- final DeviceFilterPair<ScanResult> deviceFilterPair
- = DeviceFilterPair.findMatch(result, mBLEFilters);
- if (deviceFilterPair == null) return;
- if (callbackType == ScanSettings.CALLBACK_TYPE_MATCH_LOST) {
- onDeviceLost(deviceFilterPair);
- } else {
- onDeviceFound(deviceFilterPair);
- }
- }
- };
-
- private BluetoothLeScanner mBLEScanner;
-
- private BroadcastReceiver mBluetoothDeviceFoundBroadcastReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- if (DEBUG) {
- Log.i(LOG_TAG,
- "BL.onReceive(context = " + context + ", intent = " + intent + ")");
- }
- final BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
- final DeviceFilterPair<BluetoothDevice> deviceFilterPair
- = DeviceFilterPair.findMatch(device, mBluetoothFilters);
- if (deviceFilterPair == null) return;
- if (intent.getAction().equals(BluetoothDevice.ACTION_FOUND)) {
- onDeviceFound(deviceFilterPair);
- } else {
- onDeviceLost(deviceFilterPair);
- }
- }
- };
-
- private BroadcastReceiver mWifiDeviceFoundBroadcastReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- if (intent.getAction().equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) {
- List<android.net.wifi.ScanResult> scanResults = mWifiManager.getScanResults();
-
- if (DEBUG) {
- Log.i(LOG_TAG, "Wifi scan results: " + TextUtils.join("\n", scanResults));
- }
-
- for (int i = 0; i < scanResults.size(); i++) {
- DeviceFilterPair<android.net.wifi.ScanResult> deviceFilterPair =
- DeviceFilterPair.findMatch(scanResults.get(i), mWifiFilters);
- if (deviceFilterPair != null) onDeviceFound(deviceFilterPair);
- }
- }
-
- }
- };
+ private ScanCallback mBLEScanCallback;
+ private BluetoothBroadcastReceiver mBluetoothBroadcastReceiver;
+ private WifiBroadcastReceiver mWifiBroadcastReceiver;
@Override
public IBinder onBind(Intent intent) {
@@ -211,16 +159,19 @@
intentFilter.addAction(BluetoothDevice.ACTION_FOUND);
intentFilter.addAction(BluetoothDevice.ACTION_DISAPPEARED);
- registerReceiver(mBluetoothDeviceFoundBroadcastReceiver, intentFilter);
+ mBluetoothBroadcastReceiver = new BluetoothBroadcastReceiver();
+ registerReceiver(mBluetoothBroadcastReceiver, intentFilter);
mBluetoothAdapter.startDiscovery();
}
if (shouldScan(mBLEFilters)) {
+ mBLEScanCallback = new BLEScanCallback();
mBLEScanner.startScan(mBLEScanFilters, mDefaultScanSettings, mBLEScanCallback);
}
if (shouldScan(mWifiFilters)) {
- registerReceiver(mWifiDeviceFoundBroadcastReceiver,
+ mWifiBroadcastReceiver = new WifiBroadcastReceiver();
+ registerReceiver(mWifiBroadcastReceiver,
new IntentFilter(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION));
mWifiManager.startScan();
}
@@ -232,6 +183,7 @@
private void reset() {
if (DEBUG) Log.i(LOG_TAG, "reset()");
+ stopScan();
mDevicesFound.clear();
mSelectedDevice = null;
mDevicesAdapter.notifyDataSetChanged();
@@ -244,20 +196,18 @@
}
private void stopScan() {
- if (DEBUG) Log.i(LOG_TAG, "stopScan() called");
+ if (DEBUG) Log.i(LOG_TAG, "stopScan()");
- if (shouldScan(mBluetoothFilters)) {
- mBluetoothAdapter.cancelDiscovery();
- unregisterReceiver(mBluetoothDeviceFoundBroadcastReceiver);
+ mBluetoothAdapter.cancelDiscovery();
+ if (mBluetoothBroadcastReceiver != null) {
+ unregisterReceiver(mBluetoothBroadcastReceiver);
+ mBluetoothBroadcastReceiver = null;
}
- if (shouldScan(mBLEFilters)) {
- mBLEScanner.stopScan(mBLEScanCallback);
+ mBLEScanner.stopScan(mBLEScanCallback);
+ if (mWifiBroadcastReceiver != null) {
+ unregisterReceiver(mWifiBroadcastReceiver);
+ mWifiBroadcastReceiver = null;
}
- if (shouldScan(mWifiFilters)) {
- unregisterReceiver(mWifiDeviceFoundBroadcastReceiver);
- }
-
- stopSelf();
}
private void onDeviceFound(@Nullable DeviceFilterPair device) {
@@ -265,8 +215,7 @@
return;
}
- if (DEBUG) Log.i(LOG_TAG, "Found device " + device.getDisplayName() + " "
- + getDeviceMacAddress(device.device));
+ if (DEBUG) Log.i(LOG_TAG, "Found device " + device);
if (mDevicesFound.isEmpty()) {
onReadyToShowUI();
@@ -306,6 +255,7 @@
}
void onCancel() {
+ if (DEBUG) Log.i(LOG_TAG, "onCancel()");
try {
mServiceCallback.onDeviceSelectionCancel();
} catch (RemoteException e) {
@@ -430,5 +380,76 @@
public int hashCode() {
return Objects.hash(getDeviceMacAddress(device));
}
+
+ @Override
+ public String toString() {
+ return "DeviceFilterPair{" +
+ "device=" + device +
+ ", filter=" + filter +
+ '}';
+ }
+ }
+
+ private class BLEScanCallback extends ScanCallback {
+
+ public BLEScanCallback() {
+ if (DEBUG) Log.i(LOG_TAG, "new BLEScanCallback() -> " + this);
+ }
+
+ @Override
+ public void onScanResult(int callbackType, ScanResult result) {
+ if (DEBUG) {
+ Log.i(LOG_TAG,
+ "BLE.onScanResult(callbackType = " + callbackType + ", result = " + result
+ + ")");
+ }
+ final DeviceFilterPair<ScanResult> deviceFilterPair
+ = DeviceFilterPair.findMatch(result, mBLEFilters);
+ if (deviceFilterPair == null) return;
+ if (callbackType == ScanSettings.CALLBACK_TYPE_MATCH_LOST) {
+ onDeviceLost(deviceFilterPair);
+ } else {
+ onDeviceFound(deviceFilterPair);
+ }
+ }
+ }
+
+ private class BluetoothBroadcastReceiver extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (DEBUG) {
+ Log.i(LOG_TAG,
+ "BL.onReceive(context = " + context + ", intent = " + intent + ")");
+ }
+ final BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
+ final DeviceFilterPair<BluetoothDevice> deviceFilterPair
+ = DeviceFilterPair.findMatch(device, mBluetoothFilters);
+ if (deviceFilterPair == null) return;
+ if (intent.getAction().equals(BluetoothDevice.ACTION_FOUND)) {
+ onDeviceFound(deviceFilterPair);
+ } else {
+ onDeviceLost(deviceFilterPair);
+ }
+ }
+ }
+
+ private class WifiBroadcastReceiver extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (intent.getAction().equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) {
+ List<android.net.wifi.ScanResult> scanResults = mWifiManager.getScanResults();
+
+ if (DEBUG) {
+ Log.i(LOG_TAG, "Wifi scan results: " + TextUtils.join("\n", scanResults));
+ }
+
+ for (int i = 0; i < scanResults.size(); i++) {
+ DeviceFilterPair<android.net.wifi.ScanResult> deviceFilterPair =
+ DeviceFilterPair.findMatch(scanResults.get(i), mWifiFilters);
+ if (deviceFilterPair != null) onDeviceFound(deviceFilterPair);
+ }
+ }
+
+ }
}
}
diff --git a/packages/SettingsLib/res/layout/usage_view.xml b/packages/SettingsLib/res/layout/usage_view.xml
index 1d56668..151d1ee 100644
--- a/packages/SettingsLib/res/layout/usage_view.xml
+++ b/packages/SettingsLib/res/layout/usage_view.xml
@@ -76,17 +76,23 @@
android:id="@+id/bottom_label_space"
android:layout_width="@dimen/usage_graph_labels_width"
android:layout_height="wrap_content"/>
- <include android:id="@+id/label_start"
- layout="@layout/usage_side_label" />
-
- <Space
+ <LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
- android:layout_weight="1" />
+ android:layout_weight="1"
+ android:orientation="horizontal"
+ android:layoutDirection="ltr">
+ <include android:id="@+id/label_start"
+ layout="@layout/usage_side_label" />
- <include android:id="@+id/label_end"
- layout="@layout/usage_side_label" />
+ <Space
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1" />
+ <include android:id="@+id/label_end"
+ layout="@layout/usage_side_label" />
+ </LinearLayout>
</LinearLayout>
</LinearLayout>
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 82ffa68..e15df14 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -733,11 +733,6 @@
<!-- Services settings screen, setting option summary for the user to go to the screen to view running services -->
<string name="runningservices_settings_summary">View and control currently running services</string>
- <!-- Developer settings: enable WebView multiprocess name [CHAR LIMIT=50] -->
- <string name="enable_webview_multiprocess">Multiprocess WebView</string>
- <!-- Developer settings: enable WebView multiprocess summary [CHAR LIMIT=60] -->
- <string name="enable_webview_multiprocess_desc">Run WebView renderers separately</string>
-
<!-- Developer settings: select WebView provider title [CHAR LIMIT=30] -->
<string name="select_webview_provider_title">WebView implementation</string>
<!-- Developer settings: select WebView provider dialog title [CHAR LIMIT=30] -->
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java b/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java
index 6bcf256..fb48054 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java
@@ -513,7 +513,7 @@
return null;
}
if (!providerMap.containsKey(authority)) {
- providerMap.put(authority, context.getContentResolver().acquireProvider(uri));
+ providerMap.put(authority, context.getContentResolver().acquireUnstableProvider(uri));
}
return providerMap.get(authority);
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java
index 5310b7a..8415dc5 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java
@@ -302,8 +302,10 @@
when(mIContentProvider.call(anyString(),
eq(TileUtils.getMethodFromUri(Uri.parse(URI_GET_SUMMARY))), eq(URI_GET_SUMMARY),
any())).thenReturn(bundle);
- when(mContentResolver.acquireProvider(anyString())).thenReturn(mIContentProvider);
- when(mContentResolver.acquireProvider(any(Uri.class))).thenReturn(mIContentProvider);
+ when(mContentResolver.acquireUnstableProvider(anyString()))
+ .thenReturn(mIContentProvider);
+ when(mContentResolver.acquireUnstableProvider(any(Uri.class)))
+ .thenReturn(mIContentProvider);
TileUtils.getTilesForIntent(mContext, UserHandle.CURRENT, intent, addedCache,
null /* defaultCategory */, outTiles, false /* usePriority */,
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 169a034..48429e8 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -1109,6 +1109,33 @@
// Retrieve the ssaid from the table if present.
final Setting ssaid = mSettingsRegistry.getSettingLocked(SETTINGS_TYPE_SSAID, owningUserId,
name);
+ // If the app is an Instant App use its stored SSAID instead of our own.
+ final String instantSsaid;
+ final long token = Binder.clearCallingIdentity();
+ try {
+ instantSsaid = mPackageManager.getInstantAppAndroidId(callingPkg.packageName,
+ owningUserId);
+ } catch (RemoteException e) {
+ Slog.e(LOG_TAG, "Failed to get Instant App Android ID", e);
+ return null;
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ if (instantSsaid != null) {
+ // Use the stored value if it is still valid.
+ if (ssaid != null && instantSsaid.equals(ssaid.getValue())) {
+ return ssaid;
+ }
+ // The value has changed, update the stored value.
+ final SettingsState ssaidSettings = mSettingsRegistry.getSettingsLocked(
+ SETTINGS_TYPE_SSAID, owningUserId);
+ final boolean success = ssaidSettings.insertSettingLocked(name, instantSsaid, null,
+ true, callingPkg.packageName);
+ if (!success) {
+ throw new IllegalStateException("Failed to update instant app android id");
+ }
+ return mSettingsRegistry.getSettingLocked(SETTINGS_TYPE_SSAID, owningUserId, name);
+ }
// Lazy initialize ssaid if not yet present in ssaid table.
if (ssaid == null || ssaid.isNull() || ssaid.getValue() == null) {
diff --git a/packages/SystemUI/res/drawable/ic_qs_wifi_disabled.xml b/packages/SystemUI/res/drawable/ic_qs_wifi_disabled.xml
index bed37b1..70e4780 100644
--- a/packages/SystemUI/res/drawable/ic_qs_wifi_disabled.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_wifi_disabled.xml
@@ -20,8 +20,10 @@
android:viewportHeight="24.0">
<path
android:fillColor="#FFFFFFFF"
- android:pathData="M17.500000,16.500000L5.800000,3.400000c0.000000,0.000000 0.000000,0.000000 0.000000,0.000000l-2.700000,-3.000000L1.600000,1.800000l2.200000,2.500000c-2.000000,1.000000 -3.200000,2.000000 -3.400000,2.200000L13.000000,22.000000l0.000000,0.000000l0.000000,0.000000l0.000000,0.000000l0.000000,0.000000l3.200000,-3.900000l2.400000,2.700000l1.500000,-1.400000L17.500000,16.500000L17.500000,16.500000z"/>
+ android:pathData="M17.500000,16.500000L5.800000,3.400000c0.000000,0.000000 0.000000,0.000000 0.000000,0.000000l-2.700000,-3.000000L1.600000,1.800000l2.200000,2.500000c-2.000000,1.000000 -3.200000,2.000000 -3.400000,2.200000L13.000000,22.000000l0.000000,0.000000l0.000000,0.000000l0.000000,0.000000l0.000000,0.000000l3.200000,-3.900000l2.400000,2.700000l1.500000,-1.400000L17.500000,16.500000L17.500000,16.500000z"
+ android:fillAlpha=".3"/>
<path
android:fillColor="#FFFFFFFF"
- android:pathData="M25.600000,6.500000C25.100000,6.100000 20.299999,2.100000 13.000000,2.100000c-1.900000,0.000000 -3.600000,0.300000 -5.200000,0.700000L18.700001,15.000000L25.600000,6.500000z"/>
+ android:pathData="M25.600000,6.500000C25.100000,6.100000 20.299999,2.100000 13.000000,2.100000c-1.900000,0.000000 -3.600000,0.300000 -5.200000,0.700000L18.700001,15.000000L25.600000,6.500000z"
+ android:fillAlpha=".3"/>
</vector>
diff --git a/packages/SystemUI/res/drawable/ic_volume_accessibility.xml b/packages/SystemUI/res/drawable/ic_volume_accessibility.xml
index 657efaa..88fb2d2 100644
--- a/packages/SystemUI/res/drawable/ic_volume_accessibility.xml
+++ b/packages/SystemUI/res/drawable/ic_volume_accessibility.xml
@@ -18,8 +18,9 @@
android:width="32dp"
android:height="32dp"
android:viewportWidth="24.0"
- android:viewportHeight="24.0">
+ android:viewportHeight="24.0"
+ android:tint="?android:attr/colorControlNormal">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M20.5,6c-2.61,0.7 -5.67,1 -8.5,1s-5.89,-0.3 -8.5,-1L3,8c1.86,0.5 4,0.83 6,1v13h2v-6h2v6h2V9c2,-0.17 4.14,-0.5 6,-1l-0.5,-2zM12,6c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2z"/>
-</vector>
\ No newline at end of file
+</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_wifi_signal_4.xml b/packages/SystemUI/res/drawable/stat_sys_wifi_signal_4.xml
index 5701356..7d1bfe1 100644
--- a/packages/SystemUI/res/drawable/stat_sys_wifi_signal_4.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_wifi_signal_4.xml
@@ -20,8 +20,8 @@
android:viewportHeight="24.0">
<path
android:pathData="M13.8,12.2l5.7,0.0L23.6,7.0C23.2,6.7 18.7,3.0 12.0,3.0C5.3,3.0 0.8,6.7 0.4,7.0L12.0,21.5l0.0,0.0l0.0,0.0l1.8,-2.2L13.8,12.2z"
- android:fillColor="?attr/fillColor"/>
+ android:fillColor="?attr/singleToneColor"/>
<path
android:pathData="M21.9,15.4l-1.1,-1.2 -1.9,1.900001 -1.9,-1.900001 -1.1,1.2 1.9,1.9 -1.9,1.800001 1.1,1.199999 1.9,-1.9 1.9,1.9 1.1,-1.199999 -1.9,-1.800001z"
- android:fillColor="?attr/fillColor"/>
+ android:fillColor="?attr/singleToneColor"/>
</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_wifi_signal_disconnected.xml b/packages/SystemUI/res/drawable/stat_sys_wifi_signal_disconnected.xml
index f4e8af4..8e626e9 100644
--- a/packages/SystemUI/res/drawable/stat_sys_wifi_signal_disconnected.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_wifi_signal_disconnected.xml
@@ -26,8 +26,7 @@
S0.9,5.9 0.42,6.32
l12.57,15.6 4.21,-5.17
c-0.76,-0.87 -1.22,-2.0 -1.22,-3.25
- c0.0,-2.76 2.24,-5.0 5.0,-5.0z"
- android:fillAlpha=".3"/>
+ c0.0,-2.76 2.24,-5.0 5.0,-5.0z"/>
<path
android:fillColor="?attr/backgroundColor"
android:pathData="M21.0,10.0
diff --git a/packages/SystemUI/res/layout/notification_snooze.xml b/packages/SystemUI/res/layout/notification_snooze.xml
index 5bd64de..b70f24b 100644
--- a/packages/SystemUI/res/layout/notification_snooze.xml
+++ b/packages/SystemUI/res/layout/notification_snooze.xml
@@ -19,47 +19,56 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:minHeight="@dimen/snooze_snackbar_min_height"
- android:id="@+id/notification_snooze"
- android:clickable="true"
- android:gravity="center_vertical"
- android:orientation="horizontal"
- android:paddingStart="24dp"
- android:paddingEnd="24dp"
- android:background="@color/snooze_snackbar_bg">
-
- <TextView
- android:id="@+id/snooze_option_default"
- style="@style/TextAppearance.SnoozeSnackBar"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:gravity="center_vertical"
- android:drawableTint="@android:color/white"
- android:drawableEnd="@drawable/notification_expand_more"/>
-
- <android.widget.Space
- android:layout_width="0dp"
- android:layout_height="0dp"
- android:layout_weight="1"
- />
-
- <TextView
- android:id="@+id/undo"
- style="@style/TextAppearance.SnoozeSnackBar.Button"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:layout_marginEnd="8dp"
- android:layout_marginStart="8dp"
- android:background="@drawable/btn_borderless_rect"
- android:layout_gravity="end"
- android:text="@string/snooze_undo" />
-
+ android:orientation="vertical"
+ android:background="@color/notification_guts_bg_color"
+ android:theme="@*android:style/Theme.DeviceDefault.Light">
+
+ <RelativeLayout
+ android:layout_width="match_parent"
+ android:id="@+id/notification_snooze"
+ android:layout_height="@dimen/snooze_snackbar_min_height">
+
+ <TextView
+ android:id="@+id/snooze_option_default"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentStart="true"
+ android:layout_centerVertical="true"
+ android:paddingStart="16dp"
+ android:textColor="#DD000000"
+ android:paddingEnd="4dp"/>
+
+ <ImageView
+ android:id="@+id/expand_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_toEndOf="@+id/snooze_option_default"
+ android:layout_centerVertical="true"
+ android:paddingTop="1dp"
+ android:tint="#9E9E9E" />
+
+ <TextView
+ android:id="@+id/undo"
+ style="@style/TextAppearance.NotificationInfo.Button"
+ android:layout_width="wrap_content"
+ android:layout_height="36dp"
+ android:layout_marginEnd="8dp"
+ android:layout_alignParentEnd="true"
+ android:layout_centerVertical="true"
+ android:text="@string/snooze_undo" />
+ </RelativeLayout>
+
+ <View
+ android:id="@+id/divider"
+ android:layout_width="match_parent"
+ android:layout_height="0.5dp"
+ android:background="#9E9E9E" />
+
<LinearLayout
android:id="@+id/snooze_options"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:paddingTop="8dp"
android:paddingBottom="8dp"
- android:orientation="vertical"/>
-
+ android:orientation="vertical" />
+
</com.android.systemui.statusbar.NotificationSnooze>
diff --git a/packages/SystemUI/res/layout/notification_snooze_option.xml b/packages/SystemUI/res/layout/notification_snooze_option.xml
new file mode 100644
index 0000000..aaf45f3
--- /dev/null
+++ b/packages/SystemUI/res/layout/notification_snooze_option.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 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.
+-->
+<TextView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="48dp"
+ android:layout_marginStart="@*android:dimen/notification_content_margin_start"
+ android:layout_marginEnd="@*android:dimen/notification_content_margin_end"
+ android:gravity="center_vertical"
+ android:textSize="14sp"
+ android:textColor="#DD000000"/>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/qs_footer.xml b/packages/SystemUI/res/layout/qs_footer.xml
index 82e1ae7..0a848c0 100644
--- a/packages/SystemUI/res/layout/qs_footer.xml
+++ b/packages/SystemUI/res/layout/qs_footer.xml
@@ -34,8 +34,12 @@
<include
android:id="@+id/date_time_alarm_group"
layout="@layout/status_bar_alarm_group"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent" />
+
+ <Space
android:layout_width="0dp"
- android:layout_height="match_parent"
+ android:layout_height="0dp"
android:layout_weight="1" />
<com.android.systemui.statusbar.phone.MultiUserSwitch
diff --git a/packages/SystemUI/res/layout/qs_tile_label.xml b/packages/SystemUI/res/layout/qs_tile_label.xml
index 9b53a97..35a9477 100644
--- a/packages/SystemUI/res/layout/qs_tile_label.xml
+++ b/packages/SystemUI/res/layout/qs_tile_label.xml
@@ -24,10 +24,10 @@
android:paddingTop="12dp">
<LinearLayout
android:id="@+id/label_group"
- android:layout_width="wrap_content"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
- android:layout_centerHorizontal="true"
+ android:gravity="center"
android:clipChildren="false"
android:clipToPadding="false"
android:orientation="horizontal">
diff --git a/packages/SystemUI/res/layout/quick_settings_footer.xml b/packages/SystemUI/res/layout/quick_settings_footer.xml
index bb1b288..846c538 100644
--- a/packages/SystemUI/res/layout/quick_settings_footer.xml
+++ b/packages/SystemUI/res/layout/quick_settings_footer.xml
@@ -23,7 +23,7 @@
android:paddingStart="@dimen/qs_footer_padding_start"
android:paddingEnd="@dimen/qs_footer_padding_end"
android:gravity="center_vertical"
- android:background="?android:attr/colorPrimaryDark" >
+ android:background="?android:attr/colorPrimary" >
<TextView
android:id="@+id/footer_text"
@@ -39,6 +39,7 @@
android:layout_width="@dimen/qs_footer_icon_size"
android:layout_height="@dimen/qs_footer_icon_size"
android:contentDescription="@null"
- android:src="@drawable/ic_info_outline" />
+ android:src="@drawable/ic_info_outline"
+ android:tint="?android:attr/textColorSecondary"/>
</LinearLayout>
diff --git a/packages/SystemUI/res/layout/quick_settings_footer_dialog.xml b/packages/SystemUI/res/layout/quick_settings_footer_dialog.xml
index 397fbf1..307b538 100644
--- a/packages/SystemUI/res/layout/quick_settings_footer_dialog.xml
+++ b/packages/SystemUI/res/layout/quick_settings_footer_dialog.xml
@@ -27,90 +27,105 @@
android:paddingTop="?android:attr/dialogPreferredPadding"
android:paddingRight="?android:attr/dialogPreferredPadding"
android:paddingLeft="?android:attr/dialogPreferredPadding"
- android:paddingBottom="?android:attr/dialogPreferredPadding"
android:orientation="vertical">
- <TextView
- android:id="@+id/device_owner_warning"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- style="@android:style/TextAppearance.Material.Subhead"
- android:textColor="?android:attr/textColorPrimaryInverse"
- />
<LinearLayout
+ android:id="@+id/device_management_disclosures"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:orientation="horizontal">
- <ImageView
- android:id="@+id/vpn_icon"
- android:layout_width="@dimen/qs_footer_dialog_icon_size"
- android:layout_height="wrap_content"
- android:paddingTop="?android:attr/dialogPreferredPadding"
- android:layout_marginStart="@dimen/qs_footer_dialog_icon_margin"
- android:layout_marginEnd="@dimen/qs_footer_dialog_icon_margin"
- android:scaleType="fitCenter"
- android:src="@drawable/ic_qs_vpn"
- android:tint="?android:attr/textColorPrimaryInverse"
- android:adjustViewBounds="true"/>
- <LinearLayout
+ android:paddingBottom="?android:attr/dialogPreferredPadding"
+ android:orientation="vertical">
+ <TextView
+ android:id="@+id/device_management_subtitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:orientation="vertical">
- <TextView
- android:id="@+id/vpn_subtitle"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:paddingTop="?android:attr/dialogPreferredPadding"
- android:text="@string/monitoring_subtitle_vpn"
- style="@android:style/TextAppearance.Material.Title"
- android:textColor="?android:attr/textColorPrimaryInverse"
- />
- <TextView
- android:id="@+id/vpn_warning"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="@null"
- style="@android:style/TextAppearance.Material.Subhead"
- android:textColor="?android:attr/textColorPrimaryInverse"
- />
- </LinearLayout>
+ android:text="@string/monitoring_title_device_owned"
+ style="@android:style/TextAppearance.Material.Title"
+ android:textColor="?android:attr/textColorPrimary"
+ android:paddingBottom="@dimen/qs_footer_dialog_subtitle_padding"
+ />
+ <TextView
+ android:id="@+id/device_management_warning"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@null"
+ style="@android:style/TextAppearance.Material.Subhead"
+ android:textColor="?android:attr/textColorPrimary"
+ />
</LinearLayout>
+
<LinearLayout
+ android:id="@+id/ca_certs_disclosures"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:orientation="horizontal">
- <ImageView
- android:id="@+id/network_logging_icon"
- android:layout_width="@dimen/qs_footer_dialog_icon_size"
- android:layout_height="wrap_content"
- android:paddingTop="?android:attr/dialogPreferredPadding"
- android:layout_marginStart="@dimen/qs_footer_dialog_icon_margin"
- android:layout_marginEnd="@dimen/qs_footer_dialog_icon_margin"
- android:scaleType="fitCenter"
- android:src="@drawable/ic_qs_network_logging"
- android:tint="?android:attr/textColorPrimaryInverse"
- android:adjustViewBounds="true"/>
- <LinearLayout
+ android:paddingBottom="?android:attr/dialogPreferredPadding"
+ android:orientation="vertical">
+ <TextView
+ android:id="@+id/ca_certs_subtitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:orientation="vertical">
- <TextView
- android:id="@+id/network_logging_subtitle"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:paddingTop="?android:attr/dialogPreferredPadding"
- android:text="@string/monitoring_subtitle_network_logging"
- style="@android:style/TextAppearance.Material.Title"
- android:textColor="?android:attr/textColorPrimaryInverse"
- />
- <TextView
- android:id="@+id/network_logging_warning"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="@string/monitoring_description_network_logging"
- style="@android:style/TextAppearance.Material.Subhead"
- android:textColor="?android:attr/textColorPrimaryInverse"
- />
- </LinearLayout>
+ android:text="@string/monitoring_subtitle_ca_certificate"
+ style="@android:style/TextAppearance.Material.Title"
+ android:textColor="?android:attr/textColorPrimary"
+ android:paddingBottom="@dimen/qs_footer_dialog_subtitle_padding"
+ />
+ <TextView
+ android:id="@+id/ca_certs_warning"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@null"
+ style="@android:style/TextAppearance.Material.Subhead"
+ android:textColor="?android:attr/textColorPrimary"
+ />
+ </LinearLayout>
+
+ <LinearLayout
+ android:id="@+id/network_logging_disclosures"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingBottom="?android:attr/dialogPreferredPadding"
+ android:orientation="vertical">
+ <TextView
+ android:id="@+id/network_logging_subtitle"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/monitoring_subtitle_network_logging"
+ style="@android:style/TextAppearance.Material.Title"
+ android:textColor="?android:attr/textColorPrimary"
+ android:paddingBottom="@dimen/qs_footer_dialog_subtitle_padding"
+ />
+ <TextView
+ android:id="@+id/network_logging_warning"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@null"
+ style="@android:style/TextAppearance.Material.Subhead"
+ android:textColor="?android:attr/textColorPrimary"
+ />
+ </LinearLayout>
+
+ <LinearLayout
+ android:id="@+id/vpn_disclosures"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingBottom="?android:attr/dialogPreferredPadding"
+ android:orientation="vertical">
+ <TextView
+ android:id="@+id/vpn_subtitle"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/monitoring_subtitle_vpn"
+ style="@android:style/TextAppearance.Material.Title"
+ android:textColor="?android:attr/textColorPrimary"
+ android:paddingBottom="@dimen/qs_footer_dialog_subtitle_padding"
+ />
+ <TextView
+ android:id="@+id/vpn_warning"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@null"
+ style="@android:style/TextAppearance.Material.Subhead"
+ android:textColor="?android:attr/textColorPrimary"
+ />
</LinearLayout>
</LinearLayout>
</ScrollView>
diff --git a/packages/SystemUI/res/layout/status_bar_alarm_group.xml b/packages/SystemUI/res/layout/status_bar_alarm_group.xml
index 7a5b6dc..78b580f 100644
--- a/packages/SystemUI/res/layout/status_bar_alarm_group.xml
+++ b/packages/SystemUI/res/layout/status_bar_alarm_group.xml
@@ -18,9 +18,9 @@
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:systemui="http://schemas.android.com/apk/res-auto"
android:id="@+id/date_time_alarm_group"
- android:layout_width="0dp"
- android:layout_height="48dp"
- android:layout_weight="1"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:padding="4dp"
android:gravity="center_vertical"
android:orientation="horizontal"
android:background="?android:attr/selectableItemBackground">
@@ -28,7 +28,7 @@
<com.android.systemui.statusbar.policy.DateView
android:id="@+id/date"
android:layout_width="wrap_content"
- android:layout_height="match_parent"
+ android:layout_height="wrap_content"
android:singleLine="true"
android:textAppearance="@style/TextAppearance.StatusBar.Expanded.Clock"
android:textSize="@dimen/qs_time_collapsed_size"
@@ -38,7 +38,7 @@
<com.android.systemui.statusbar.AlphaOptimizedImageView
android:id="@+id/alarm_status_collapsed"
android:layout_width="wrap_content"
- android:layout_height="match_parent"
+ android:layout_height="wrap_content"
android:src="@drawable/ic_access_alarms_small"
android:tint="?android:attr/textColorPrimary"
android:paddingStart="6dp"
@@ -49,7 +49,7 @@
<com.android.systemui.statusbar.AlphaOptimizedButton
android:id="@+id/alarm_status"
android:layout_width="wrap_content"
- android:layout_height="match_parent"
+ android:layout_height="wrap_content"
android:textAppearance="@style/TextAppearance.StatusBar.Expanded.Clock"
android:gravity="center_vertical"
android:background="@null"
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index f461bb3..83a0b7b 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -96,10 +96,6 @@
<!-- The "inside" of a notification, reached via longpress -->
<color name="notification_guts_bg_color">#eeeeee</color>
- <!-- Colors of the snooze menu reached via snooze icon behind a notification -->
- <color name="snooze_snackbar_bg">#FF4A4A4A</color>
- <color name="snooze_snackbar_text">#FFA6BAFF</color>
-
<color name="assist_orb_color">#ffffff</color>
<color name="keyguard_user_switcher_background_gradient_color">#77000000</color>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 1a3e6ce1..cdb5af9 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -119,7 +119,7 @@
<dimen name="notification_menu_icon_padding">20dp</dimen>
<!-- The minimum height for the snackbar shown after the snooze option has been chosen. -->
- <dimen name="snooze_snackbar_min_height">48dp</dimen>
+ <dimen name="snooze_snackbar_min_height">56dp</dimen>
<!-- The text size of options in the snooze menu. -->
<dimen name="snooze_option_text_size">14sp</dimen>
@@ -282,6 +282,8 @@
<dimen name="qs_footer_dialog_icon_size">24sp</dimen>
<!-- Left and right margin of the icons -->
<dimen name="qs_footer_dialog_icon_margin">8sp</dimen>
+ <!-- Padding between subtitles and the following text in the QSFooter dialog -->
+ <dimen name="qs_footer_dialog_subtitle_padding">20dp</dimen>
<!-- Zen mode panel: condition item button padding -->
<dimen name="zen_mode_condition_detail_button_padding">8dp</dimen>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index b87da27..b70597f 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1065,7 +1065,7 @@
<string name="quick_settings_disclosure_named_vpn">Device connected to <xliff:g id="vpn_app" example="Foo VPN App">%1$s</xliff:g></string>
<!-- Monitoring dialog title for device owned devices [CHAR LIMIT=35] -->
- <string name="monitoring_title_device_owned">Device monitoring</string>
+ <string name="monitoring_title_device_owned">Device management</string>
<!-- Monitoring dialog title for profile owned devices [CHAR LIMIT=35] -->
<string name="monitoring_title_profile_owned">Profile monitoring</string>
@@ -1093,10 +1093,10 @@
<string name="monitoring_button_view_policies">View Policies</string>
<!-- Monitoring dialog: Description of the device owner by name. [CHAR LIMIT=NONE]-->
- <string name="monitoring_description_named_management">Your device is managed by <xliff:g id="organization_name" example="Foo, Inc.">%1$s</xliff:g>.\n\nYour admin can monitor and manage settings, corporate access, apps, data associated with your device, and your device's location information.\n\nFor more information, contact your admin." </string>
+ <string name="monitoring_description_named_management">Your device is managed by <xliff:g id="organization_name" example="Foo, Inc.">%1$s</xliff:g>.\n\nYour admin can monitor and manage settings, corporate access, apps, data associated with your device, and your device\'s location information.\n\nFor more information, contact your admin.</string>
<!-- Monitoring dialog: Description of a device owner. [CHAR LIMIT=NONE]-->
- <string name="monitoring_description_management">Your device is managed by your organization.\n\nYour admin can monitor and manage settings, corporate access, apps, data associated with your device, and your device's location information.\n\nFor more information, contact your admin." </string>
+ <string name="monitoring_description_management">Your device is managed by your organization.\n\nYour admin can monitor and manage settings, corporate access, apps, data associated with your device, and your device\'s location information.\n\nFor more information, contact your admin.</string>
<!-- Monitoring dialog: Description of a CA Certificate. [CHAR LIMIT=NONE]-->
<string name="monitoring_description_management_ca_certificate">Your organization installed a certificate authority on this device. Your secure network traffic may be monitored or modified.</string>
@@ -1111,10 +1111,10 @@
<string name="monitoring_description_management_network_logging">Your admin has turned on network logging, which monitors traffic on your device.</string>
<!-- Monitoring dialog: Description of an active VPN. [CHAR LIMIT=NONE]-->
- <string name="monitoring_description_named_vpn">You're connected to <xliff:g id="vpn_app" example="Foo VPN App">%1$s</xliff:g>, which can monitor your network activity, including emails, apps, and websites.</string>
+ <string name="monitoring_description_named_vpn">You\'re connected to <xliff:g id="vpn_app" example="Foo VPN App">%1$s</xliff:g>, which can monitor your network activity, including emails, apps, and websites.</string>
<!-- Monitoring dialog: Description of two active VPNs. [CHAR LIMIT=NONE]-->
- <string name="monitoring_description_two_named_vpns">You're connected to <xliff:g id="vpn_app" example="Foo VPN App">%1$s</xliff:g> and <xliff:g id="vpn_app" example="Bar VPN App">%2$s</xliff:g>, which can monitor your network activity, including emails, apps, and websites.</string>
+ <string name="monitoring_description_two_named_vpns">You\'re connected to <xliff:g id="vpn_app" example="Foo VPN App">%1$s</xliff:g> and <xliff:g id="vpn_app" example="Bar VPN App">%2$s</xliff:g>, which can monitor your network activity, including emails, apps, and websites.</string>
<!-- Monitoring dialog: Description of an active VPN in the work profile. [CHAR LIMIT=NONE]-->
<string name="monitoring_description_managed_profile_named_vpn">Your work profile is connected to <xliff:g id="vpn_app" example="Foo VPN App">%1$s</xliff:g>, which can monitor your network activity, including emails, apps, and websites.</string>
@@ -1502,8 +1502,6 @@
<string name="snooze_option_30_min">30 minutes</string>
<!-- Notification: Menu row: Snooze options: 1 hour option. [CHAR LIMIT=50]-->
<string name="snooze_option_1_hour">1 hour</string>
- <!-- Notification: Menu row: Snooze options: cancel snoozing option. [CHAR LIMIT=50] -->
- <string name="snooze_option_dont_snooze">Cancel</string>
<!-- Notification: Menu row: Snooze undo button label. [CHAR LIMIT=50]-->
<string name="snooze_undo">UNDO</string>
@@ -1916,11 +1914,11 @@
<!-- Tuner string -->
<string name="default_theme" translatable="false">Default</string>
- <!-- Title for notification & dialog that the user's phone last shut down because it got too hot. [CHAR LIMIT=30] -->
+ <!-- Title for notification & dialog that the user's phone last shut down because it got too hot. [CHAR LIMIT=40] -->
<string name="thermal_shutdown_title">Phone turned off due to heat</string>
<!-- Message body for notification that user's phone last shut down because it got too hot. [CHAR LIMIT=100] -->
<string name="thermal_shutdown_message">Your phone is now running normally</string>
- <!-- Text body for dialog alerting user that their phone last shut down bewcause it got too hot. [CHAR LIMIT=300] -->
+ <!-- Text body for dialog alerting user that their phone last shut down because it got too hot. [CHAR LIMIT=450] -->
<string name="thermal_shutdown_dialog_message">Your phone was too hot, so it turned off to cool down. Your phone is now running normally.\n\nYour phone may get too hot if you:\n\t• Use resource-intensive apps (such as gaming, video, or navigation apps)\n\t• Download or upload large files\n\t• Use your phone in high temperatures</string>
<!-- Title for notification (and dialog) that user's phone has reached a certain temperature and may start to slow down in order to cool down. [CHAR LIMIT=30] -->
@@ -1990,6 +1988,9 @@
<!-- Action label for launching app info on the specified app [CHAR LIMIT=20] -->
<string name="app_info">App info</string>
+ <!-- Action label for switching to web for an instant app [CHAR LIMIT=20] -->
+ <string name="go_to_web">Go to web</string>
+
<!-- Quick settings tile for toggling mobile data [CHAR LIMIT=20] -->
<string name="mobile_data">Mobile data</string>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index e5f04c6..dbdbd1e 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -386,20 +386,6 @@
<item name="android:paddingEnd">8dp</item>
</style>
- <style name="TextAppearance.SnoozeSnackBar">
- <item name="android:textSize">14sp</item>
- <item name="android:fontFamily">sans-serif</item>
- <item name="android:textColor">@android:color/white</item>
- </style>
-
- <style name="TextAppearance.SnoozeSnackBar.Button">
- <item name="android:textSize">14sp</item>
- <item name="android:textAllCaps">true</item>
- <item name="android:fontFamily">sans-serif-medium</item>
- <item name="android:gravity">center</item>
- <item name="android:textColor">@color/snooze_snackbar_text</item>
- </style>
-
<style name="edit_theme" parent="@*android:style/Theme.DeviceDefault.QuickSettings">
<item name="android:colorBackground">?android:attr/colorSecondary</item>
</style>
diff --git a/packages/SystemUI/src/com/android/systemui/DockedStackExistsListener.java b/packages/SystemUI/src/com/android/systemui/DockedStackExistsListener.java
new file mode 100644
index 0000000..c382882
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/DockedStackExistsListener.java
@@ -0,0 +1,69 @@
+/*
+ * 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 com.android.systemui;
+
+import android.os.RemoteException;
+import android.util.Log;
+import android.view.IDockedStackListener;
+import android.view.WindowManagerGlobal;
+
+import java.util.function.Consumer;
+
+/**
+ * Utility wrapper to listen for whether or not a docked stack exists, to be
+ * used for things like the different overview icon in that mode.
+ */
+public class DockedStackExistsListener extends IDockedStackListener.Stub {
+
+ private static final String TAG = "DockedStackExistsListener";
+
+ private final Consumer<Boolean> mCallback;
+
+ private DockedStackExistsListener(Consumer<Boolean> callback) {
+ mCallback = callback;
+ }
+
+ @Override
+ public void onDividerVisibilityChanged(boolean visible) throws RemoteException {
+ }
+
+ @Override
+ public void onDockedStackExistsChanged(final boolean exists) throws RemoteException {
+ mCallback.accept(exists);
+ }
+
+ @Override
+ public void onDockedStackMinimizedChanged(boolean minimized, long animDuration,
+ boolean isHomeStackResizable) throws RemoteException {
+ }
+
+ @Override
+ public void onAdjustedForImeChanged(boolean adjustedForIme, long animDuration)
+ throws RemoteException {
+ }
+
+ @Override
+ public void onDockSideChanged(int newDockSide) throws RemoteException {
+ }
+
+ public static void register(Consumer<Boolean> callback) {
+ try {
+ WindowManagerGlobal.getWindowManagerService().registerDockedStackListener(
+ new DockedStackExistsListener(callback));
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed registering docked stack exists listener", e);
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/Interpolators.java b/packages/SystemUI/src/com/android/systemui/Interpolators.java
index 9b5577c..b8cfa3e 100644
--- a/packages/SystemUI/src/com/android/systemui/Interpolators.java
+++ b/packages/SystemUI/src/com/android/systemui/Interpolators.java
@@ -41,6 +41,8 @@
public static final Interpolator CUSTOM_40_40 = new PathInterpolator(0.4f, 0f, 0.6f, 1f);
public static final Interpolator HEADS_UP_APPEAR = new HeadsUpAppearInterpolator();
public static final Interpolator ICON_OVERSHOT = new PathInterpolator(0.4f, 0f, 0.2f, 1.4f);
+ public static final Interpolator PANEL_CLOSE_ACCELERATED
+ = new PathInterpolator(0.3f, 0, 0.5f, 1);
/**
* Interpolator to be used when animating a move based on a click. Pair with enough duration.
diff --git a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
index 5a04108d..8c4159a 100644
--- a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
@@ -462,11 +462,20 @@
int duration = SNAP_ANIM_LEN;
anim.setDuration(duration);
anim.addListener(new AnimatorListenerAdapter() {
+ boolean wasCancelled = false;
+
+ @Override
+ public void onAnimationCancel(Animator animator) {
+ wasCancelled = true;
+ }
+
@Override
public void onAnimationEnd(Animator animator) {
mSnappingChild = false;
- updateSwipeProgressFromOffset(animView, canBeDismissed);
- mCallback.onChildSnappedBack(animView, targetLeft);
+ if (!wasCancelled) {
+ updateSwipeProgressFromOffset(animView, canBeDismissed);
+ mCallback.onChildSnappedBack(animView, targetLeft);
+ }
}
});
prepareSnapBackAnimation(animView, anim);
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java b/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java
index 90e1c07..7139d59 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java
@@ -43,6 +43,8 @@
public static final int PULSE_REASON_SENSOR_PICKUP = 3;
public static final int PULSE_REASON_SENSOR_DOUBLE_TAP = 4;
+ private static boolean sRegisterKeyguardCallback = true;
+
private static long[] sTimes;
private static String[] sMessages;
private static int sPosition;
@@ -103,7 +105,9 @@
sProxStats[i][1] = new SummaryStats();
}
log("init");
- KeyguardUpdateMonitor.getInstance(context).registerCallback(sKeyguardCallback);
+ if (sRegisterKeyguardCallback) {
+ KeyguardUpdateMonitor.getInstance(context).registerCallback(sKeyguardCallback);
+ }
}
}
}
@@ -218,6 +222,31 @@
if (DEBUG) Log.d(TAG, msg);
}
+ public static void tracePulseDropped(Context context, boolean pulsePending,
+ DozeMachine.State state, boolean blocked) {
+ if (!ENABLED) return;
+ init(context);
+ log("pulseDropped pulsePending=" + pulsePending + " state="
+ + state + " blocked=" + blocked);
+ }
+
+ public static void tracePulseCanceledByProx(Context context) {
+ if (!ENABLED) return;
+ init(context);
+ log("pulseCanceledByProx");
+ }
+
+ public static void setRegisterKeyguardCallback(boolean registerKeyguardCallback) {
+ if (!ENABLED) return;
+ synchronized (DozeLog.class) {
+ if (sRegisterKeyguardCallback != registerKeyguardCallback && sMessages != null) {
+ throw new IllegalStateException("Cannot change setRegisterKeyguardCallback "
+ + "after init()");
+ }
+ sRegisterKeyguardCallback = registerKeyguardCallback;
+ }
+ }
+
private static class SummaryStats {
private int mCount;
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java b/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java
index 1cc5fb9..38b32e9 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java
@@ -42,7 +42,7 @@
static final String TAG = "DozeMachine";
static final boolean DEBUG = DozeService.DEBUG;
- enum State {
+ public enum State {
/** Default state. Transition to INITIALIZED to get Doze going. */
UNINITIALIZED,
/** Doze components are set up. Followed by transition to DOZE or DOZE_AOD. */
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
index 9b3593b..ea55c5f 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
@@ -119,6 +119,7 @@
DozeMachine.State state = mMachine.getState();
if (near && state == DozeMachine.State.DOZE_PULSING) {
if (DEBUG) Log.i(TAG, "Prox NEAR, ending pulse");
+ DozeLog.tracePulseCanceledByProx(mContext);
mMachine.requestState(DozeMachine.State.DOZE_PULSE_DONE);
}
if (far && state == DozeMachine.State.DOZE_AOD_PAUSED) {
@@ -181,6 +182,10 @@
Assert.isMainThread();
mDozeHost.extendPulse();
if (mPulsePending || !mAllowPulseTriggers || !canPulse()) {
+ if (mAllowPulseTriggers) {
+ DozeLog.tracePulseDropped(mContext, mPulsePending, mMachine.getState(),
+ mDozeHost.isPulsingBlocked());
+ }
return;
}
@@ -204,6 +209,7 @@
}
// avoid pulsing in pockets
if (result == RESULT_NEAR) {
+ mPulsePending = false;
return;
}
@@ -221,6 +227,8 @@
private void continuePulseRequest(int reason) {
mPulsePending = false;
if (mDozeHost.isPulsingBlocked() || !canPulse()) {
+ DozeLog.tracePulseDropped(mContext, mPulsePending, mMachine.getState(),
+ mDozeHost.isPulsingBlocked());
return;
}
mMachine.requestState(DozeMachine.State.DOZE_REQUEST_PULSE);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java
index 53c36e6..4f484b6 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java
@@ -48,6 +48,8 @@
import com.android.systemui.R.id;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.qs.TouchAnimator.Builder;
+import com.android.systemui.qs.TouchAnimator.Listener;
+import com.android.systemui.qs.TouchAnimator.ListenerAdapter;
import com.android.systemui.statusbar.phone.ExpandableIndicator;
import com.android.systemui.statusbar.phone.MultiUserSwitch;
import com.android.systemui.statusbar.phone.SettingsButton;
@@ -166,8 +168,20 @@
.addFloat(mAlarmStatus, "alpha", 0, 1);
if (mAlarmShowing) {
builder.addFloat(mDate, "alpha", 1, 0)
- .addFloat(mDateTimeGroup, "translationX", 0, -mDate.getWidth());
+ .addFloat(mDateTimeGroup, "translationX", 0, -mDate.getWidth())
+ .setListener(new ListenerAdapter() {
+ @Override
+ public void onAnimationAtStart() {
+ mAlarmStatus.setVisibility(View.GONE);
+ }
+
+ @Override
+ public void onAnimationStarted() {
+ mAlarmStatus.setVisibility(View.VISIBLE);
+ }
+ });
} else {
+ mAlarmStatus.setVisibility(View.GONE);
mDate.setAlpha(1);
mDateTimeGroup.setTranslationX(0);
}
@@ -277,8 +291,7 @@
}
private void updateAlarmVisibilities() {
- mAlarmStatus.setVisibility(mAlarmShowing ? View.VISIBLE : View.INVISIBLE);
- mAlarmStatusCollapsed.setVisibility(mAlarmShowing ? View.VISIBLE : View.INVISIBLE);
+ mAlarmStatusCollapsed.setVisibility(mAlarmShowing ? View.VISIBLE : View.GONE);
}
public void setListening(boolean listening) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java b/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java
index 51c6ad8..d434f2f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java
@@ -31,6 +31,7 @@
import android.view.View;
import android.view.ViewGroup;
import android.view.View.OnClickListener;
+import android.view.Window;
import android.widget.ImageView;
import android.widget.TextView;
@@ -224,117 +225,152 @@
@Override
public void onClick(DialogInterface dialog, int which) {
if (which == DialogInterface.BUTTON_NEGATIVE) {
- final Intent settingsIntent = new Intent(ACTION_VPN_SETTINGS);
- mActivityStarter.postStartActivityDismissingKeyguard(settingsIntent, 0);
+ final Intent intent = new Intent(Settings.ACTION_ENTERPRISE_PRIVACY_SETTINGS);
+ mDialog.dismiss();
+ mActivityStarter.postStartActivityDismissingKeyguard(intent, 0);
}
}
private void createDialog() {
- final String deviceOwnerPackage = mSecurityController.getDeviceOwnerName();
- final String profileOwnerPackage = mSecurityController.getProfileOwnerName();
- final boolean isNetworkLoggingEnabled = mSecurityController.isNetworkLoggingEnabled();
- final String primaryVpn = mSecurityController.getPrimaryVpnName();
- final String profileVpn = mSecurityController.getWorkProfileVpnName();
+ final boolean isDeviceManaged = mSecurityController.isDeviceManaged();
+ final boolean hasWorkProfile = mSecurityController.hasWorkProfile();
final CharSequence deviceOwnerOrganization =
mSecurityController.getDeviceOwnerOrganizationName();
- boolean hasProfileOwner = mSecurityController.hasProfileOwner();
+ final boolean hasCACerts = mSecurityController.hasCACertInCurrentUser();
+ final boolean hasCACertsInWorkProfile = mSecurityController.hasCACertInWorkProfile();
+ final boolean isNetworkLoggingEnabled = mSecurityController.isNetworkLoggingEnabled();
+ final String vpnName = mSecurityController.getPrimaryVpnName();
+ final String vpnNameWorkProfile = mSecurityController.getWorkProfileVpnName();
mDialog = new SystemUIDialog(mContext);
- mDialog.setTitle(getTitle(deviceOwnerPackage));
- CharSequence msg = getMessage(deviceOwnerPackage, profileOwnerPackage, primaryVpn,
- profileVpn, deviceOwnerOrganization, hasProfileOwner);
- if (deviceOwnerPackage == null) {
- mDialog.setMessage(msg);
- if (mSecurityController.isVpnEnabled() && !mSecurityController.isVpnRestricted()) {
- mDialog.setButton(DialogInterface.BUTTON_NEGATIVE, getSettingsButton(), this);
- }
- } else {
- View dialogView = LayoutInflater.from(mContext)
- .inflate(R.layout.quick_settings_footer_dialog, null, false);
- mDialog.setView(dialogView);
- TextView deviceOwnerWarning =
- (TextView) dialogView.findViewById(R.id.device_owner_warning);
- deviceOwnerWarning.setText(msg);
- // Make the link "learn more" clickable.
- deviceOwnerWarning.setMovementMethod(new LinkMovementMethod());
- if (primaryVpn == null) {
- dialogView.findViewById(R.id.vpn_icon).setVisibility(View.GONE);
- dialogView.findViewById(R.id.vpn_subtitle).setVisibility(View.GONE);
- dialogView.findViewById(R.id.vpn_warning).setVisibility(View.GONE);
- } else {
- final SpannableStringBuilder message = new SpannableStringBuilder();
- message.append(mContext.getString(R.string.monitoring_description_do_body_vpn,
- primaryVpn));
- if (!mSecurityController.isVpnRestricted()) {
- message.append(mContext.getString(
- R.string.monitoring_description_vpn_settings_separator));
- message.append(mContext.getString(R.string.monitoring_description_vpn_settings),
- new VpnSpan(), 0);
- }
+ mDialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
+ View dialogView = LayoutInflater.from(mContext)
+ .inflate(R.layout.quick_settings_footer_dialog, null, false);
+ mDialog.setView(dialogView);
+ mDialog.setButton(DialogInterface.BUTTON_POSITIVE, getPositiveButton(), this);
- TextView vpnWarning = (TextView) dialogView.findViewById(R.id.vpn_warning);
- vpnWarning.setText(message);
- // Make the link "Open VPN Settings" clickable.
- vpnWarning.setMovementMethod(new LinkMovementMethod());
- }
- if (!isNetworkLoggingEnabled) {
- dialogView.findViewById(R.id.network_logging_icon).setVisibility(View.GONE);
- dialogView.findViewById(R.id.network_logging_subtitle).setVisibility(View.GONE);
- dialogView.findViewById(R.id.network_logging_warning).setVisibility(View.GONE);
- }
+ // device management section
+ CharSequence managementMessage = getManagementMessage(isDeviceManaged,
+ deviceOwnerOrganization);
+ if (managementMessage == null) {
+ dialogView.findViewById(R.id.device_management_disclosures).setVisibility(View.GONE);
+ } else {
+ dialogView.findViewById(R.id.device_management_disclosures).setVisibility(View.VISIBLE);
+ TextView deviceManagementWarning =
+ (TextView) dialogView.findViewById(R.id.device_management_warning);
+ deviceManagementWarning.setText(managementMessage);
+ mDialog.setButton(DialogInterface.BUTTON_NEGATIVE, getSettingsButton(), this);
}
- mDialog.setButton(DialogInterface.BUTTON_POSITIVE, getPositiveButton(), this);
+ // ca certificate section
+ CharSequence caCertsMessage = getCaCertsMessage(isDeviceManaged, hasCACerts,
+ hasCACertsInWorkProfile);
+ if (caCertsMessage == null) {
+ dialogView.findViewById(R.id.ca_certs_disclosures).setVisibility(View.GONE);
+ } else {
+ dialogView.findViewById(R.id.ca_certs_disclosures).setVisibility(View.VISIBLE);
+ TextView caCertsWarning = (TextView) dialogView.findViewById(R.id.ca_certs_warning);
+ caCertsWarning.setText(caCertsMessage);
+ // Make "Open trusted credentials"-link clickable
+ caCertsWarning.setMovementMethod(new LinkMovementMethod());
+ }
+
+ // network logging section
+ CharSequence networkLoggingMessage = getNetworkLoggingMessage(isNetworkLoggingEnabled);
+ if (networkLoggingMessage == null) {
+ dialogView.findViewById(R.id.network_logging_disclosures).setVisibility(View.GONE);
+ } else {
+ dialogView.findViewById(R.id.network_logging_disclosures).setVisibility(View.VISIBLE);
+ TextView networkLoggingWarning =
+ (TextView) dialogView.findViewById(R.id.network_logging_warning);
+ networkLoggingWarning.setText(networkLoggingMessage);
+ }
+
+ // vpn section
+ CharSequence vpnMessage = getVpnMessage(isDeviceManaged, hasWorkProfile, vpnName,
+ vpnNameWorkProfile);
+ if (vpnMessage == null) {
+ dialogView.findViewById(R.id.vpn_disclosures).setVisibility(View.GONE);
+ } else {
+ dialogView.findViewById(R.id.vpn_disclosures).setVisibility(View.VISIBLE);
+ TextView vpnWarning = (TextView) dialogView.findViewById(R.id.vpn_warning);
+ vpnWarning.setText(vpnMessage);
+ // Make "Open VPN Settings"-link clickable
+ vpnWarning.setMovementMethod(new LinkMovementMethod());
+ }
+
mDialog.show();
- mDialog.getWindow().setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
+ mDialog.getWindow().setLayout(ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.WRAP_CONTENT);
}
private String getSettingsButton() {
- return mContext.getString(R.string.status_bar_settings_settings_button);
+ return mContext.getString(R.string.monitoring_button_view_policies);
}
private String getPositiveButton() {
return mContext.getString(R.string.quick_settings_done);
}
- protected CharSequence getMessage(String deviceOwnerPackage, String profileOwnerPackage,
- String primaryVpn, String profileVpn, CharSequence deviceOwnerOrganization,
- boolean hasProfileOwner) {
- if (deviceOwnerPackage != null) {
- final SpannableStringBuilder message = new SpannableStringBuilder();
- if (deviceOwnerOrganization != null) {
- message.append(mContext.getString(
- R.string.monitoring_description_do_header_with_name,
- deviceOwnerOrganization, deviceOwnerPackage));
- } else {
- message.append(mContext.getString(R.string.monitoring_description_do_header_generic,
- deviceOwnerPackage));
- }
- message.append("\n\n");
- message.append(mContext.getString(R.string.monitoring_description_do_body));
- message.append(mContext.getString(
- R.string.monitoring_description_do_learn_more_separator));
- message.append(mContext.getString(R.string.monitoring_description_do_learn_more),
- new EnterprisePrivacySpan(), 0);
- return message;
- } else if (primaryVpn != null) {
- if (profileVpn != null) {
- return mContext.getString(R.string.monitoring_description_app_personal_work,
- profileOwnerPackage, profileVpn, primaryVpn);
- } else {
- return mContext.getString(R.string.monitoring_description_app_personal,
- primaryVpn);
- }
- } else if (profileVpn != null) {
- return mContext.getString(R.string.monitoring_description_app_work,
- profileOwnerPackage, profileVpn);
- } else if (profileOwnerPackage != null && hasProfileOwner) {
- return mContext.getString(R.string.do_disclosure_with_name,
- profileOwnerPackage);
- } else {
- // No device owner, no personal VPN, no work VPN, no user owner. Why are we here?
- return null;
+ protected CharSequence getManagementMessage(boolean isDeviceManaged,
+ CharSequence organizationName) {
+ if (!isDeviceManaged) return null;
+ if (organizationName != null)
+ return mContext.getString(
+ R.string.monitoring_description_named_management, organizationName);
+ return mContext.getString(R.string.monitoring_description_management);
+ }
+
+ protected CharSequence getCaCertsMessage(boolean isDeviceManaged, boolean hasCACerts,
+ boolean hasCACertsInWorkProfile) {
+ if (!(hasCACerts || hasCACertsInWorkProfile)) return null;
+ if (isDeviceManaged) {
+ return mContext.getString(R.string.monitoring_description_management_ca_certificate);
}
+ if (hasCACertsInWorkProfile) {
+ return mContext.getString(
+ R.string.monitoring_description_managed_profile_ca_certificate);
+ }
+ return mContext.getString(R.string.monitoring_description_ca_certificate);
+ }
+
+ protected CharSequence getNetworkLoggingMessage(boolean isNetworkLoggingEnabled) {
+ if (!isNetworkLoggingEnabled) return null;
+ return mContext.getString(R.string.monitoring_description_management_network_logging);
+ }
+
+ protected CharSequence getVpnMessage(boolean isDeviceManaged, boolean hasWorkProfile,
+ String vpnName, String vpnNameWorkProfile) {
+ if (vpnName == null && vpnNameWorkProfile == null) return null;
+ final SpannableStringBuilder message = new SpannableStringBuilder();
+ if (isDeviceManaged) {
+ if (vpnName != null && vpnNameWorkProfile != null) {
+ message.append(mContext.getString(R.string.monitoring_description_two_named_vpns,
+ vpnName, vpnNameWorkProfile));
+ } else {
+ message.append(mContext.getString(R.string.monitoring_description_named_vpn,
+ vpnName != null ? vpnName : vpnNameWorkProfile));
+ }
+ } else {
+ if (vpnName != null && vpnNameWorkProfile != null) {
+ message.append(mContext.getString(R.string.monitoring_description_two_named_vpns,
+ vpnName, vpnNameWorkProfile));
+ } else if (vpnNameWorkProfile != null) {
+ message.append(mContext.getString(
+ R.string.monitoring_description_managed_profile_named_vpn,
+ vpnNameWorkProfile));
+ } else if (hasWorkProfile) {
+ message.append(mContext.getString(
+ R.string.monitoring_description_personal_profile_named_vpn, vpnName));
+ } else {
+ message.append(mContext.getString(R.string.monitoring_description_named_vpn,
+ vpnName));
+ }
+ }
+ message.append(mContext.getString(R.string.monitoring_description_vpn_settings_separator));
+ message.append(mContext.getString(R.string.monitoring_description_vpn_settings),
+ new VpnSpan(), 0);
+ return message;
}
private int getTitle(String deviceOwner) {
@@ -397,20 +433,6 @@
}
}
- protected class EnterprisePrivacySpan extends ClickableSpan {
- @Override
- public void onClick(View widget) {
- final Intent intent = new Intent(Settings.ACTION_ENTERPRISE_PRIVACY_SETTINGS);
- mDialog.dismiss();
- mActivityStarter.postStartActivityDismissingKeyguard(intent, 0);
- }
-
- @Override
- public boolean equals(Object object) {
- return object instanceof EnterprisePrivacySpan;
- }
- }
-
protected class VpnSpan extends ClickableSpan {
@Override
public void onClick(View widget) {
@@ -418,5 +440,16 @@
mDialog.dismiss();
mActivityStarter.postStartActivityDismissingKeyguard(intent, 0);
}
+
+ // for testing, to compare two CharSequences containing VpnSpans
+ @Override
+ public boolean equals(Object object) {
+ return object instanceof VpnSpan;
+ }
+
+ @Override
+ public int hashCode() {
+ return 314159257; // prime
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
index 6781c16..976efb2 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
@@ -340,12 +340,12 @@
switch (state) {
case Tile.STATE_UNAVAILABLE:
return Utils.getDisabled(context,
- Utils.getColorAttr(context, android.R.attr.textColorTertiary));
+ Utils.getColorAttr(context, android.R.attr.textColorPrimary));
case Tile.STATE_INACTIVE:
return Utils.getDisabled(context,
- Utils.getColorAttr(context, android.R.attr.textColorSecondary));
+ Utils.getColorAttr(context, android.R.attr.colorForeground));
case Tile.STATE_ACTIVE:
- return Utils.getColorAttr(context, attr.textColorSecondary);
+ return Utils.getColorAttr(context, android.R.attr.textColorPrimary);
default:
Log.e("QSTile", "Invalid state " + state);
return 0;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
index d27bb85..9b20a7a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
@@ -259,22 +259,27 @@
ArrayList<Item> items = new ArrayList<Item>();
final Collection<CachedBluetoothDevice> devices = mController.getDevices();
if (devices != null) {
+ int connectedDevices = 0;
for (CachedBluetoothDevice device : devices) {
if (device.getBondState() == BluetoothDevice.BOND_NONE) continue;
final Item item = new Item();
item.icon = R.drawable.ic_qs_bluetooth_on;
item.line1 = device.getName();
+ item.tag = device;
int state = device.getMaxConnectionState();
if (state == BluetoothProfile.STATE_CONNECTED) {
item.icon = R.drawable.ic_qs_bluetooth_connected;
item.line2 = mContext.getString(R.string.quick_settings_connected);
item.canDisconnect = true;
+ items.add(connectedDevices, item);
+ connectedDevices++;
} else if (state == BluetoothProfile.STATE_CONNECTING) {
item.icon = R.drawable.ic_qs_bluetooth_connecting;
item.line2 = mContext.getString(R.string.quick_settings_connecting);
+ items.add(connectedDevices, item);
+ } else {
+ items.add(item);
}
- item.tag = device;
- items.add(item);
}
}
mItems.setItems(items.toArray(new Item[items.size()]));
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
index 5a23d3b..1afce64 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
@@ -184,7 +184,7 @@
state.dualLabelContentDescription = r.getString(
R.string.accessibility_quick_settings_open_settings, getTileLabel());
state.expandedAccessibilityClassName = Switch.class.getName();
- state.state = state.value || cb.isTransient ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
+ state.state = Tile.STATE_ACTIVE;
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index 5c9360a..30ff30f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -171,7 +171,14 @@
mDisable1 = state1;
mDisable2 = state2;
mHandler.removeMessages(MSG_DISABLE);
- mHandler.obtainMessage(MSG_DISABLE, state1, state2, animate).sendToTarget();
+ Message msg = mHandler.obtainMessage(MSG_DISABLE, state1, state2, animate);
+ if (Looper.myLooper() == mHandler.getLooper()) {
+ // If its the right looper execute immediately so hides can be handled quickly.
+ mHandler.handleMessage(msg);
+ msg.recycle();
+ } else {
+ msg.sendToTarget();
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index cc91753..dff09bd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -1494,7 +1494,7 @@
return getActualHeight();
}
if (mGuts != null && mGuts.isExposed()) {
- return mGuts.getHeight();
+ return mGuts.getIntrinsicHeight();
} else if ((isChildInGroup() && !isGroupExpanded())) {
return mPrivateLayout.getMinHeight();
} else if (mShowAmbient) {
@@ -1835,7 +1835,9 @@
@Override
public int getMinHeight() {
- if (!mOnKeyguard && mIsHeadsUp && mHeadsUpManager.isTrackingHeadsUp()) {
+ if (mGuts != null && mGuts.isExposed()) {
+ return mGuts.getIntrinsicHeight();
+ } else if (!mOnKeyguard && mIsHeadsUp && mHeadsUpManager.isTrackingHeadsUp()) {
return getPinnedHeadsUpHeight(false /* atLeastMinHeight */);
} else if (mIsSummaryWithChildren && !isGroupExpanded() && !mShowingPublic) {
return mChildrenContainer.getMinHeight();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
index 0a99ee6..1375310 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
@@ -74,7 +74,8 @@
private Handler mHandler;
private Runnable mFalsingCheck;
private boolean mNeedsFalsingProtection;
- private OnGutsClosedListener mListener;
+ private OnGutsClosedListener mClosedListener;
+ private OnHeightChangedListener mHeightListener;
private GutsContent mGutsContent;
@@ -88,6 +89,11 @@
public View getContentView();
/**
+ * @return the actual height of the content.
+ */
+ public int getActualHeight();
+
+ /**
* Called when the guts view have been told to close, typically after an outside
* interaction. Returning {@code true} here will prevent the guts view to close.
*/
@@ -103,6 +109,10 @@
public void onGutsClosed(NotificationGuts guts);
}
+ public interface OnHeightChangedListener {
+ public void onHeightChanged(NotificationGuts guts);
+ }
+
interface OnSettingsClickListener {
void onClick(View v, int appUid);
}
@@ -126,7 +136,6 @@
public NotificationGuts(Context context) {
this(context, null);
-
}
public void setGutsContent(GutsContent content) {
@@ -190,8 +199,8 @@
public void closeControls(int x, int y, boolean save) {
if (getWindowToken() == null) {
- if (mListener != null) {
- mListener.onGutsClosed(this);
+ if (mClosedListener != null) {
+ mClosedListener.onGutsClosed(this);
}
return;
}
@@ -199,8 +208,8 @@
animateClose(x, y);
}
setExposed(false, mNeedsFalsingProtection);
- if (mListener != null) {
- mListener.onGutsClosed(this);
+ if (mClosedListener != null) {
+ mClosedListener.onGutsClosed(this);
}
}
@@ -235,6 +244,10 @@
return mActualHeight;
}
+ public int getIntrinsicHeight() {
+ return mGutsContent != null && mExposed ? mGutsContent.getActualHeight() : getHeight();
+ }
+
public void setClipTopAmount(int clipTopAmount) {
mClipTopAmount = clipTopAmount;
invalidate();
@@ -252,7 +265,17 @@
}
public void setClosedListener(OnGutsClosedListener listener) {
- mListener = listener;
+ mClosedListener = listener;
+ }
+
+ public void setHeightChangedListener(OnHeightChangedListener listener) {
+ mHeightListener = listener;
+ }
+
+ protected void onHeightChanged() {
+ if (mHeightListener != null) {
+ mHeightListener.onHeightChanged(this);
+ }
}
public void setExposed(boolean exposed, boolean needsFalsingProtection) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java
index 8925189..f3c7b84 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java
@@ -403,4 +403,9 @@
}
return false;
}
+
+ @Override
+ public int getActualHeight() {
+ return getHeight();
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMenuRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMenuRow.java
index 802925a..7563fd1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMenuRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMenuRow.java
@@ -317,6 +317,10 @@
}
private void dismiss(View animView, float velocity) {
+ if (mFadeAnimator != null) {
+ mFadeAnimator.cancel();
+ }
+ mHandler.removeCallbacks(mCheckForDrag);
mMenuSnappedTo = false;
mDismissing = true;
mSwipeHelper.dismiss(animView, velocity);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationSnooze.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationSnooze.java
index 4a3f112..ccc99c5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationSnooze.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationSnooze.java
@@ -21,35 +21,47 @@
import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper;
import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper.SnoozeOption;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
import android.content.Context;
import android.content.res.Resources;
-import android.graphics.Color;
+import android.graphics.Typeface;
import android.service.notification.SnoozeCriterion;
import android.service.notification.StatusBarNotification;
+import android.text.SpannableString;
+import android.text.style.StyleSpan;
import android.util.AttributeSet;
import android.util.Log;
-import android.util.TypedValue;
+import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
+
+import com.android.systemui.Interpolators;
import com.android.systemui.R;
public class NotificationSnooze extends LinearLayout
implements NotificationGuts.GutsContent, View.OnClickListener {
- private static final int MAX_ASSISTANT_SUGGESTIONS = 2;
+ private static final int MAX_ASSISTANT_SUGGESTIONS = 1;
private NotificationGuts mGutsContainer;
private NotificationSwipeActionHelper mSnoozeListener;
private StatusBarNotification mSbn;
private TextView mSelectedOptionText;
private TextView mUndoButton;
- private ViewGroup mSnoozeOptionView;
+ private ImageView mExpandButton;
+ private View mDivider;
+ private ViewGroup mSnoozeOptionContainer;
private List<SnoozeOption> mSnoozeOptions;
- private boolean mSnoozing;
+ private int mCollapsedHeight;
private SnoozeOption mSelectedOption;
+ private boolean mSnoozing;
+ private boolean mExpanded;
+ private AnimatorSet mExpandAnimation;
public NotificationSnooze(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -58,16 +70,21 @@
@Override
protected void onFinishInflate() {
super.onFinishInflate();
+ mCollapsedHeight = getResources().getDimensionPixelSize(R.dimen.snooze_snackbar_min_height);
+ findViewById(R.id.notification_snooze).setOnClickListener(this);
+ mSelectedOptionText = (TextView) findViewById(R.id.snooze_option_default);
+ mUndoButton = (TextView) findViewById(R.id.undo);
+ mUndoButton.setOnClickListener(this);
+ mExpandButton = (ImageView) findViewById(R.id.expand_button);
+ mDivider = findViewById(R.id.divider);
+ mDivider.setAlpha(0f);
+ mSnoozeOptionContainer = (ViewGroup) findViewById(R.id.snooze_options);
+ mSnoozeOptionContainer.setAlpha(0f);
+
// Create the different options based on list
mSnoozeOptions = getDefaultSnoozeOptions();
createOptionViews();
- // Snackbar
- mSelectedOptionText = findViewById(R.id.snooze_option_default);
- mSelectedOptionText.setOnClickListener(this);
- mUndoButton = findViewById(R.id.undo);
- mUndoButton.setOnClickListener(this);
-
// Default to first option in list
setSelected(mSnoozeOptions.get(0));
}
@@ -96,52 +113,68 @@
private SnoozeOption createOption(int descriptionResId, int minutes) {
Resources res = getResources();
- String resultText = String.format(
- res.getString(R.string.snoozed_for_time), res.getString(descriptionResId));
- return new SnoozeOption(null, minutes, res.getString(descriptionResId), resultText);
+ final String description = res.getString(descriptionResId);
+ String resultText = String.format(res.getString(R.string.snoozed_for_time), description);
+ SpannableString string = new SpannableString(resultText);
+ string.setSpan(new StyleSpan(Typeface.BOLD),
+ resultText.length() - description.length(), resultText.length(), 0 /* flags */);
+ return new SnoozeOption(null, minutes, res.getString(descriptionResId), string);
}
private void createOptionViews() {
- mSnoozeOptionView = findViewById(R.id.snooze_options);
- mSnoozeOptionView.removeAllViews();
- mSnoozeOptionView.setVisibility(View.GONE);
- final Resources res = getResources();
- final int textSize = res.getDimensionPixelSize(R.dimen.snooze_option_text_size);
- final int p = res.getDimensionPixelSize(R.dimen.snooze_option_padding);
-
- // Add all the options
+ mSnoozeOptionContainer.removeAllViews();
+ LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(
+ Context.LAYOUT_INFLATER_SERVICE);
for (int i = 0; i < mSnoozeOptions.size(); i++) {
SnoozeOption option = mSnoozeOptions.get(i);
- TextView tv = new TextView(getContext());
- tv.setTextColor(Color.WHITE);
- tv.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize);
- tv.setPadding(p, p, p, p);
- mSnoozeOptionView.addView(tv);
+ TextView tv = (TextView) inflater.inflate(R.layout.notification_snooze_option,
+ mSnoozeOptionContainer, false);
+ mSnoozeOptionContainer.addView(tv);
tv.setText(option.description);
tv.setTag(option);
tv.setOnClickListener(this);
}
+ }
- // Add the undo option as final item
- TextView tv = new TextView(getContext());
- tv.setTextColor(Color.WHITE);
- tv.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize);
- tv.setPadding(p, p, p, p);
- mSnoozeOptionView.addView(tv);
- tv.setText(R.string.snooze_option_dont_snooze);
- tv.setOnClickListener(this);
+ private void hideSelectedOption() {
+ final int childCount = mSnoozeOptionContainer.getChildCount();
+ for (int i = 0; i < childCount; i++) {
+ final View child = mSnoozeOptionContainer.getChildAt(i);
+ child.setVisibility(child.getTag() == mSelectedOption ? View.GONE : View.VISIBLE);
+ }
}
private void showSnoozeOptions(boolean show) {
- mSelectedOptionText.setVisibility(show ? View.GONE : View.VISIBLE);
- mUndoButton.setVisibility(show ? View.GONE : View.VISIBLE);
- mSnoozeOptionView.setVisibility(show ? View.VISIBLE : View.GONE);
+ mExpanded = show;
+ animateSnoozeOptions(show);
+ int drawableId = show ? com.android.internal.R.drawable.ic_collapse_notification
+ : com.android.internal.R.drawable.ic_expand_notification;
+ mExpandButton.setImageResource(drawableId);
+ if (mGutsContainer != null) {
+ mGutsContainer.onHeightChanged();
+ }
+ }
+
+ private void animateSnoozeOptions(boolean show) {
+ if (mExpandAnimation != null) {
+ mExpandAnimation.cancel();
+ }
+ ObjectAnimator dividerAnim = ObjectAnimator.ofFloat(mDivider, View.ALPHA,
+ mDivider.getAlpha(), show ? 1f : 0f);
+ ObjectAnimator optionAnim = ObjectAnimator.ofFloat(mSnoozeOptionContainer, View.ALPHA,
+ mSnoozeOptionContainer.getAlpha(), show ? 1f : 0f);
+ mExpandAnimation = new AnimatorSet();
+ mExpandAnimation.playTogether(dividerAnim, optionAnim);
+ mExpandAnimation.setDuration(150);
+ mExpandAnimation.setInterpolator(show ? Interpolators.ALPHA_IN : Interpolators.ALPHA_OUT);
+ mExpandAnimation.start();
}
private void setSelected(SnoozeOption option) {
mSelectedOption = option;
mSelectedOptionText.setText(option.confirmation);
showSnoozeOptions(false);
+ hideSelectedOption();
}
@Override
@@ -153,17 +186,28 @@
final SnoozeOption tag = (SnoozeOption) v.getTag();
if (tag != null) {
setSelected(tag);
- } else if (id == R.id.snooze_option_default) {
- // Show more snooze options
- showSnoozeOptions(true);
+ } else if (id == R.id.notification_snooze) {
+ // Toggle snooze options
+ showSnoozeOptions(!mExpanded);
} else {
- undoSnooze();
+ // Undo snooze was selected
+ mSelectedOption = null;
+ int[] parentLoc = new int[2];
+ int[] targetLoc = new int[2];
+ mGutsContainer.getLocationOnScreen(parentLoc);
+ v.getLocationOnScreen(targetLoc);
+ final int centerX = v.getWidth() / 2;
+ final int centerY = v.getHeight() / 2;
+ final int x = targetLoc[0] - parentLoc[0] + centerX;
+ final int y = targetLoc[1] - parentLoc[1] + centerY;
+ showSnoozeOptions(false);
+ mGutsContainer.closeControls(x, y, false /* save */);
}
}
- private void undoSnooze() {
- mSelectedOption = null;
- mGutsContainer.closeControls(-1 /* x */, -1 /* y */, true /* notify */);
+ @Override
+ public int getActualHeight() {
+ return mExpanded ? getHeight() : mCollapsedHeight;
}
@Override
@@ -173,6 +217,8 @@
@Override
public View getContentView() {
+ // Reset the view before use
+ setSelected(mSnoozeOptions.get(0));
return this;
}
@@ -197,11 +243,8 @@
mSnoozing = true;
mSnoozeListener.snooze(mSbn, mSelectedOption);
return true;
- } else {
- // Reset the view once it's closed
- setSelected(mSnoozeOptions.get(0));
- showSnoozeOptions(false);
}
+ // The view should be closed
return false;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
index ec15d10..263df79 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
@@ -459,9 +459,13 @@
}
CharSequence title = n.extras.getCharSequence(Notification.EXTRA_TITLE);
+ CharSequence text = n.extras.getCharSequence(Notification.EXTRA_TEXT);
CharSequence ticker = n.tickerText;
- CharSequence desc = !TextUtils.isEmpty(title) ? title
+ // Some apps just put the app name into the title
+ CharSequence titleOrText = TextUtils.equals(title, appName) ? text : title;
+
+ CharSequence desc = !TextUtils.isEmpty(titleOrText) ? titleOrText
: !TextUtils.isEmpty(ticker) ? ticker : "";
return c.getString(R.string.accessibility_desc_notification_icon, appName, desc);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationHeaderViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationHeaderViewWrapper.java
index 1ffc944..0b9244a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationHeaderViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationHeaderViewWrapper.java
@@ -29,6 +29,7 @@
import android.widget.ImageView;
import android.widget.TextView;
+import com.android.internal.widget.NotificationExpandButton;
import com.android.systemui.Interpolators;
import com.android.systemui.ViewInvertHelper;
import com.android.systemui.statusbar.ExpandableNotificationRow;
@@ -54,7 +55,7 @@
protected int mColor;
private ImageView mIcon;
- private ImageView mExpandButton;
+ private NotificationExpandButton mExpandButton;
private NotificationHeaderView mNotificationHeader;
private TextView mHeaderText;
private ImageView mWorkProfileImage;
@@ -106,13 +107,13 @@
}
protected void resolveHeaderViews() {
- mIcon = (ImageView) mView.findViewById(com.android.internal.R.id.icon);
- mHeaderText = (TextView) mView.findViewById(com.android.internal.R.id.header_text);
- mExpandButton = (ImageView) mView.findViewById(com.android.internal.R.id.expand_button);
- mWorkProfileImage = (ImageView) mView.findViewById(com.android.internal.R.id.profile_badge);
+ mIcon = mView.findViewById(com.android.internal.R.id.icon);
+ mHeaderText = mView.findViewById(com.android.internal.R.id.header_text);
+ mExpandButton = mView.findViewById(com.android.internal.R.id.expand_button);
+ mExpandButton.setLabeledBy(mRow);
+ mWorkProfileImage = mView.findViewById(com.android.internal.R.id.profile_badge);
mColor = resolveColor(mExpandButton);
- mNotificationHeader = (NotificationHeaderView) mView.findViewById(
- com.android.internal.R.id.notification_header);
+ mNotificationHeader = mView.findViewById(com.android.internal.R.id.notification_header);
getDozer().setColor(mColor);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java
index 9206914..f216d6c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java
@@ -83,7 +83,7 @@
/**
* How much faster we collapse the lockscreen when authenticating with fingerprint.
*/
- private static final float FINGERPRINT_COLLAPSE_SPEEDUP_FACTOR = 1.3f;
+ private static final float FINGERPRINT_COLLAPSE_SPEEDUP_FACTOR = 1.1f;
private PowerManager mPowerManager;
private Handler mHandler = new Handler();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
index fa404b5..4bfc16b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
@@ -402,7 +402,7 @@
ButtonDispatcher accessibilityButton = mNavigationBarView.getAccessibilityButton();
accessibilityButton.setOnClickListener(this::onAccessibilityClick);
accessibilityButton.setOnLongClickListener(this::onAccessibilityLongClick);
- updateAccessibilityServicesState();
+ updateAccessibilityServicesState(mAccessibilityManager);
}
private boolean onHomeTouch(View v, MotionEvent event) {
@@ -565,7 +565,7 @@
return true;
}
- private void updateAccessibilityServicesState() {
+ private void updateAccessibilityServicesState(AccessibilityManager accessibilityManager) {
int requestingServices = 0;
try {
if (Settings.Secure.getIntForUser(mContentResolver,
@@ -579,7 +579,7 @@
// AccessibilityManagerService resolves services for the current user since the local
// AccessibilityManager is created from a Context with the INTERACT_ACROSS_USERS permission
final List<AccessibilityServiceInfo> services =
- mAccessibilityManager.getEnabledAccessibilityServiceList(
+ accessibilityManager.getEnabledAccessibilityServiceList(
AccessibilityServiceInfo.FEEDBACK_ALL_MASK);
for (int i = services.size() - 1; i >= 0; --i) {
AccessibilityServiceInfo info = services.get(i);
@@ -638,7 +638,7 @@
@Override
public void onChange(boolean selfChange) {
- NavigationBarFragment.this.updateAccessibilityServicesState();
+ NavigationBarFragment.this.updateAccessibilityServicesState(mAccessibilityManager);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index a5d7c57..1fd329c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -47,6 +47,7 @@
import android.widget.FrameLayout;
import com.android.systemui.Dependency;
+import com.android.systemui.DockedStackExistsListener;
import com.android.systemui.R;
import com.android.systemui.RecentsComponent;
import com.android.systemui.plugins.PluginListener;
@@ -566,40 +567,10 @@
getImeSwitchButton().setOnClickListener(mImeSwitcherClickListener);
- try {
- WindowManagerGlobal.getWindowManagerService().registerDockedStackListener(new Stub() {
- @Override
- public void onDividerVisibilityChanged(boolean visible) throws RemoteException {
- }
-
- @Override
- public void onDockedStackExistsChanged(final boolean exists) throws RemoteException {
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- mDockedStackExists = exists;
- updateRecentsIcon();
- }
- });
- }
-
- @Override
- public void onDockedStackMinimizedChanged(boolean minimized, long animDuration,
- boolean isHomeStackResizable) throws RemoteException {
- }
-
- @Override
- public void onAdjustedForImeChanged(boolean adjustedForIme, long animDuration)
- throws RemoteException {
- }
-
- @Override
- public void onDockSideChanged(int newDockSide) throws RemoteException {
- }
- });
- } catch (RemoteException e) {
- Log.e(TAG, "Failed registering docked stack exists listener", e);
- }
+ DockedStackExistsListener.register(exists -> mHandler.post(() -> {
+ mDockedStackExists = exists;
+ updateRecentsIcon();
+ }));
}
void updateRotatedViews() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index f1b4498..8a97be5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -2022,7 +2022,7 @@
@Override
protected boolean shouldUseDismissingAnimation() {
return mStatusBarState != StatusBarState.SHADE
- && !mStatusBar.isKeyguardCurrentlySecure();
+ && (!mStatusBar.isKeyguardCurrentlySecure() || !isTracking());
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
index 48a8329..e86fd48 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -725,8 +725,14 @@
}
} else {
if (shouldUseDismissingAnimation()) {
- mFlingAnimationUtilsDismissing.apply(animator, mExpandedHeight, target, vel,
- getHeight());
+ if (vel == 0) {
+ animator.setInterpolator(Interpolators.PANEL_CLOSE_ACCELERATED);
+ long duration = (long) (200 + mExpandedHeight / getHeight() * 100);
+ animator.setDuration(duration);
+ } else {
+ mFlingAnimationUtilsDismissing.apply(animator, mExpandedHeight, target, vel,
+ getHeight());
+ }
} else {
mFlingAnimationUtilsClosing
.apply(animator, mExpandedHeight, target, vel, getHeight());
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
index 5910557..5690495 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -28,6 +28,7 @@
import android.app.PendingIntent;
import android.app.SynchronousUserSwitchObserver;
import android.content.BroadcastReceiver;
+import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
@@ -50,11 +51,11 @@
import android.util.ArraySet;
import android.util.Log;
import android.util.Pair;
-
import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
import com.android.internal.telephony.IccCardConstants;
import com.android.internal.telephony.TelephonyIntents;
import com.android.systemui.Dependency;
+import com.android.systemui.DockedStackExistsListener;
import com.android.systemui.R;
import com.android.systemui.SysUiServiceProvider;
import com.android.systemui.qs.tiles.DndTile;
@@ -82,6 +83,8 @@
import com.android.systemui.statusbar.policy.ZenModeController;
import com.android.systemui.util.NotificationChannels;
+import java.util.List;
+
/**
* This class contains all of the policy about which icons are installed in the status
* bar at boot time. It goes through the normal API for icons, even though it probably
@@ -94,6 +97,7 @@
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
public static final int LOCATION_STATUS_ICON_ID = R.drawable.stat_sys_location;
+ public static final int NUM_TASKS_FOR_INSTANT_APP_INFO = 5;
private final String mSlotCast;
private final String mSlotHotspot;
@@ -132,6 +136,7 @@
private boolean mZenVisible;
private boolean mVolumeVisible;
private boolean mCurrentUserSetup;
+ private boolean mDockedStackExists;
private boolean mManagedProfileIconVisible = false;
private boolean mManagedProfileInQuietMode = false;
@@ -248,6 +253,10 @@
noMan.cancel(notification.getTag(), notification.getId());
}
}
+ DockedStackExistsListener.register(exists -> {
+ mDockedStackExists = exists;
+ updateForegroundInstantApps();
+ });
}
public void destroy() {
@@ -495,23 +504,18 @@
IPackageManager pm = AppGlobals.getPackageManager();
mCurrentNotifs.clear();
try {
+ ArraySet<Integer> stacksToCheck = new ArraySet<>();
int[] STACKS_TO_CHECK = new int[]{
StackId.FULLSCREEN_WORKSPACE_STACK_ID,
StackId.DOCKED_STACK_ID,
};
- for (int i = 0; i < STACKS_TO_CHECK.length; i++) {
- StackInfo info = ActivityManager.getService().getStackInfo(STACKS_TO_CHECK[i]);
- if (info == null || info.topActivity == null) continue;
- String pkg = info.topActivity.getPackageName();
- if (!hasNotif(notifs, pkg, info.userId)) {
- // TODO: Optimize by not always needing to get application info.
- // Maybe cache non-ephemeral packages?
- ApplicationInfo appInfo = pm.getApplicationInfo(pkg,
- PackageManager.MATCH_UNINSTALLED_PACKAGES, info.userId);
- if (appInfo.isInstantApp()) {
- postEphemeralNotif(pkg, info.userId, appInfo, noMan);
- }
- }
+ int focusedId = ActivityManager.getService().getFocusedStackId();
+ if (focusedId == StackId.FULLSCREEN_WORKSPACE_STACK_ID
+ || focusedId == StackId.FULLSCREEN_WORKSPACE_STACK_ID) {
+ checkStack(StackId.FULLSCREEN_WORKSPACE_STACK_ID, notifs, noMan, pm);
+ }
+ if (mDockedStackExists) {
+ checkStack(StackId.DOCKED_STACK_ID, notifs, noMan, pm);
}
} catch (RemoteException e) {
e.rethrowFromSystemServer();
@@ -521,8 +525,28 @@
new UserHandle(v.second)));
}
+ private void checkStack(int stackId, ArraySet<Pair<String, Integer>> notifs,
+ NotificationManager noMan, IPackageManager pm) {
+ try {
+ StackInfo info = ActivityManager.getService().getStackInfo(stackId);
+ if (info == null || info.topActivity == null) return;
+ String pkg = info.topActivity.getPackageName();
+ if (!hasNotif(notifs, pkg, info.userId)) {
+ // TODO: Optimize by not always needing to get application info.
+ // Maybe cache non-ephemeral packages?
+ ApplicationInfo appInfo = pm.getApplicationInfo(pkg,
+ PackageManager.MATCH_UNINSTALLED_PACKAGES, info.userId);
+ if (appInfo.isInstantApp()) {
+ postEphemeralNotif(pkg, info.userId, appInfo, noMan, info.taskIds[info.taskIds.length - 1]);
+ }
+ }
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ }
+
private void postEphemeralNotif(String pkg, int userId, ApplicationInfo appInfo,
- NotificationManager noMan) {
+ NotificationManager noMan, int taskId) {
final Bundle extras = new Bundle();
extras.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME,
mContext.getString(R.string.instant_apps));
@@ -531,12 +555,41 @@
PendingIntent appInfoAction = PendingIntent.getActivity(mContext, 0,
new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
.setData(Uri.fromParts("package", pkg, null)), 0);
- // TODO: Add action for go to web as well.
Action action = new Notification.Action.Builder(null, mContext.getString(R.string.app_info),
appInfoAction).build();
- noMan.notifyAsUser(pkg, SystemMessage.NOTE_INSTANT_APPS,
- new Notification.Builder(mContext, NotificationChannels.GENERAL)
+ Intent browserIntent = getTaskIntent(taskId, userId);
+ Notification.Builder builder = new Notification.Builder(mContext, NotificationChannels.GENERAL);
+ if (browserIntent != null) {
+ // Make sure that this doesn't resolve back to an instant app
+ browserIntent.setComponent(null)
+ .setPackage(null)
+ .addFlags(Intent.FLAG_IGNORE_EPHEMERAL)
+ .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+
+ PendingIntent pendingIntent = PendingIntent.getActivity(mContext,
+ 0 /* requestCode */, browserIntent, 0 /* flags */);
+ ComponentName aiaComponent = null;
+ try {
+ aiaComponent = AppGlobals.getPackageManager().getInstantAppInstallerComponent();
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ Intent goToWebIntent = new Intent()
+ .setComponent(aiaComponent)
+ .setAction(Intent.ACTION_VIEW)
+ .addCategory(Intent.CATEGORY_BROWSABLE)
+ .putExtra(Intent.EXTRA_PACKAGE_NAME, appInfo.packageName)
+ .putExtra(Intent.EXTRA_VERSION_CODE, appInfo.versionCode)
+ .putExtra(Intent.EXTRA_EPHEMERAL_FAILURE, pendingIntent);
+
+ PendingIntent webPendingIntent = PendingIntent.getActivity(mContext, 0, goToWebIntent, 0);
+ Action webAction = new Notification.Action.Builder(null, mContext.getString(R.string.go_to_web),
+ webPendingIntent).build();
+ builder.addAction(webAction);
+ }
+
+ noMan.notifyAsUser(pkg, SystemMessage.NOTE_INSTANT_APPS, builder
.addExtras(extras)
.addAction(action)
.setContentIntent(appInfoAction)
@@ -551,6 +604,17 @@
new UserHandle(userId));
}
+ private Intent getTaskIntent(int taskId, int userId) {
+ List<ActivityManager.RecentTaskInfo> tasks = mContext.getSystemService(ActivityManager.class)
+ .getRecentTasksForUser(NUM_TASKS_FOR_INSTANT_APP_INFO, 0, userId);
+ for (int i = 0; i < tasks.size(); i++) {
+ if (tasks.get(i).id == taskId) {
+ return tasks.get(i).baseIntent;
+ }
+ }
+ return null;
+ }
+
private boolean hasNotif(ArraySet<Pair<String, Integer>> notifs, String pkg, int userId) {
Pair<String, Integer> key = new Pair<>(pkg, userId);
if (notifs.remove(key)) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 79191f3..46d6415 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -5774,6 +5774,9 @@
snoozeGuts.setSnoozeListener(mStackScroller.getSwipeActionHelper());
snoozeGuts.setStatusBarNotification(sbn);
snoozeGuts.setSnoozeOptions(row.getEntry().snoozeCriteria);
+ guts.setHeightChangedListener((NotificationGuts g) -> {
+ mStackScroller.onHeightChanged(row, row.isShown() /* needsAnimation */);
+ });
}
if (gutsView instanceof NotificationInfo) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationUtil.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationUtil.java
new file mode 100644
index 0000000..3aef247
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationUtil.java
@@ -0,0 +1,70 @@
+/*
+ * 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 com.android.systemui.doze;
+
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.withSettings;
+
+import com.android.internal.hardware.AmbientDisplayConfiguration;
+import com.android.systemui.statusbar.phone.DozeParameters;
+
+import org.mockito.Answers;
+import org.mockito.MockSettings;
+
+public class DozeConfigurationUtil {
+ public static DozeParameters createMockParameters() {
+ boolean[] doneHolder = new boolean[1];
+ DozeParameters params = mock(DozeParameters.class, noDefaultAnswer(doneHolder));
+
+ when(params.getPulseOnSigMotion()).thenReturn(false);
+ when(params.getSensorsWakeUpFully()).thenReturn(false);
+ when(params.getPickupVibrationThreshold()).thenReturn(0);
+ when(params.getProxCheckBeforePulse()).thenReturn(true);
+ when(params.getPickupSubtypePerformsProxCheck(anyInt())).thenReturn(true);
+
+ doneHolder[0] = true;
+ return params;
+ }
+
+ public static AmbientDisplayConfiguration createMockConfig() {
+ boolean[] doneHolder = new boolean[1];
+ AmbientDisplayConfiguration config = mock(AmbientDisplayConfiguration.class,
+ noDefaultAnswer(doneHolder));
+ when(config.pulseOnDoubleTapEnabled(anyInt())).thenReturn(false);
+ when(config.pulseOnPickupEnabled(anyInt())).thenReturn(false);
+ when(config.pulseOnNotificationEnabled(anyInt())).thenReturn(true);
+
+ when(config.doubleTapSensorType()).thenReturn(null);
+ when(config.pulseOnPickupAvailable()).thenReturn(false);
+
+ doneHolder[0] = true;
+ return config;
+ }
+
+ private static MockSettings noDefaultAnswer(boolean[] setupDoneHolder) {
+ return withSettings().defaultAnswer((i) -> {
+ if (setupDoneHolder[0]) {
+ throw new IllegalArgumentException("not defined");
+ } else {
+ return Answers.RETURNS_DEFAULTS.answer(i);
+ }
+ });
+ }
+
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeHostFake.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeHostFake.java
new file mode 100644
index 0000000..d2afa2a
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeHostFake.java
@@ -0,0 +1,84 @@
+/*
+ * 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 com.android.systemui.doze;
+
+import android.annotation.NonNull;
+import android.app.PendingIntent;
+
+/**
+ * A rudimentary fake for DozeHost.
+ */
+class DozeHostFake implements DozeHost {
+ Callback callback;
+ private boolean pulseAborted;
+ private boolean pulseExtended;
+
+ @Override
+ public void addCallback(@NonNull Callback callback) {
+ this.callback = callback;
+ }
+
+ @Override
+ public void removeCallback(@NonNull Callback callback) {
+ this.callback = null;
+ }
+
+ @Override
+ public void startDozing() {
+ throw new RuntimeException("not implemented");
+ }
+
+ @Override
+ public void pulseWhileDozing(@NonNull PulseCallback callback, int reason) {
+ throw new RuntimeException("not implemented");
+ }
+
+ @Override
+ public void stopDozing() {
+ throw new RuntimeException("not implemented");
+ }
+
+ @Override
+ public void dozeTimeTick() {
+ throw new RuntimeException("not implemented");
+ }
+
+ @Override
+ public boolean isPowerSaveActive() {
+ return false;
+ }
+
+ @Override
+ public boolean isPulsingBlocked() {
+ return false;
+ }
+
+ @Override
+ public void startPendingIntentDismissingKeyguard(PendingIntent intent) {
+ throw new RuntimeException("not implemented");
+ }
+
+ @Override
+ public void abortPulsing() {
+ pulseAborted = true;
+ }
+
+ @Override
+ public void extendPulse() {
+ pulseExtended = true;
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
new file mode 100644
index 0000000..12e75a1
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
@@ -0,0 +1,110 @@
+/*
+ * 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 com.android.systemui.doze;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.withSettings;
+
+import android.app.Instrumentation;
+import android.content.Context;
+import android.os.Handler;
+import android.os.Looper;
+import android.support.test.InstrumentationRegistry;
+
+import com.android.internal.hardware.AmbientDisplayConfiguration;
+import com.android.systemui.statusbar.phone.DozeParameters;
+import com.android.systemui.util.wakelock.WakeLock;
+import com.android.systemui.util.wakelock.WakeLockFake;
+
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.mockito.Answers;
+import org.mockito.MockSettings;
+
+public class DozeTriggersTest {
+ private Context mContext;
+ private DozeTriggers mTriggers;
+ private DozeMachine mMachine;
+ private DozeHostFake mHost;
+ private AmbientDisplayConfiguration mConfig;
+ private DozeParameters mParameters;
+ private SensorManagerFake mSensors;
+ private Handler mHandler;
+ private WakeLock mWakeLock;
+ private Instrumentation mInstrumentation;
+
+ @BeforeClass
+ public static void setupSuite() {
+ // We can't use KeyguardUpdateMonitor from tests.
+ DozeLog.setRegisterKeyguardCallback(false);
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ mInstrumentation = InstrumentationRegistry.getInstrumentation();
+ mContext = InstrumentationRegistry.getContext();
+ mMachine = mock(DozeMachine.class);
+ mHost = new DozeHostFake();
+ mConfig = DozeConfigurationUtil.createMockConfig();
+ mParameters = DozeConfigurationUtil.createMockParameters();
+ mSensors = new SensorManagerFake(mContext);
+ mHandler = new Handler(Looper.getMainLooper());
+ mWakeLock = new WakeLockFake();
+
+ mInstrumentation.runOnMainSync(() -> {
+ mTriggers = new DozeTriggers(mContext, mMachine, mHost,
+ mConfig, mParameters, mSensors, mHandler, mWakeLock, true);
+ });
+ }
+
+ @Test
+ @Ignore("setup crashes on virtual devices")
+ public void testOnNotification_stillWorksAfterOneFailedProxCheck() throws Exception {
+ when(mMachine.getState()).thenReturn(DozeMachine.State.DOZE);
+
+ mInstrumentation.runOnMainSync(()->{
+ mTriggers.transitionTo(DozeMachine.State.UNINITIALIZED, DozeMachine.State.INITIALIZED);
+ mTriggers.transitionTo(DozeMachine.State.UNINITIALIZED, DozeMachine.State.DOZE);
+
+ mHost.callback.onNotificationHeadsUp();
+ });
+
+ mInstrumentation.runOnMainSync(() -> {
+ mSensors.PROXIMITY.sendProximityResult(false); /* Near */
+ });
+
+ verify(mMachine, never()).requestState(any());
+
+ mInstrumentation.runOnMainSync(()->{
+ mHost.callback.onNotificationHeadsUp();
+ });
+
+ mInstrumentation.runOnMainSync(() -> {
+ mSensors.PROXIMITY.sendProximityResult(true); /* Far */
+ });
+
+ verify(mMachine).requestState(DozeMachine.State.DOZE_REQUEST_PULSE);
+ }
+
+}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/SensorManagerFake.java b/packages/SystemUI/tests/src/com/android/systemui/doze/SensorManagerFake.java
new file mode 100644
index 0000000..5b4b891
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/SensorManagerFake.java
@@ -0,0 +1,176 @@
+/*
+ * 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 com.android.systemui.doze;
+
+import android.content.Context;
+import android.hardware.HardwareBuffer;
+import android.hardware.Sensor;
+import android.hardware.SensorAdditionalInfo;
+import android.hardware.SensorDirectChannel;
+import android.hardware.SensorEvent;
+import android.hardware.SensorEventListener;
+import android.hardware.SensorManager;
+import android.hardware.TriggerEventListener;
+import android.os.Handler;
+import android.os.MemoryFile;
+import android.os.SystemClock;
+import android.util.ArraySet;
+
+import com.google.android.collect.Lists;
+
+import java.lang.reflect.Constructor;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Rudimentary fake for SensorManager
+ *
+ * Currently only supports the proximity sensor.
+ *
+ * Note that this class ignores the "Handler" argument, so the test is responsible for calling the
+ * listener on the right thread.
+ */
+public class SensorManagerFake extends SensorManager {
+
+ public MockSensor PROXIMITY;
+
+ public SensorManagerFake(Context context) {
+ PROXIMITY = new MockSensor(context.getSystemService(SensorManager.class)
+ .getDefaultSensor(Sensor.TYPE_PROXIMITY));
+ }
+
+ @Override
+ protected List<Sensor> getFullSensorList() {
+ return Lists.newArrayList(PROXIMITY.sensor);
+ }
+
+ @Override
+ protected List<Sensor> getFullDynamicSensorList() {
+ return new ArrayList<>();
+ }
+
+ @Override
+ protected void unregisterListenerImpl(SensorEventListener listener, Sensor sensor) {
+ if (sensor == PROXIMITY.sensor || sensor == null) {
+ PROXIMITY.listeners.remove(listener);
+ }
+ }
+
+ @Override
+ protected boolean registerListenerImpl(SensorEventListener listener, Sensor sensor,
+ int delayUs,
+ Handler handler, int maxReportLatencyUs, int reservedFlags) {
+ if (sensor == PROXIMITY.sensor) {
+ PROXIMITY.listeners.add(listener);
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ protected boolean flushImpl(SensorEventListener listener) {
+ return false;
+ }
+
+ @Override
+ protected SensorDirectChannel createDirectChannelImpl(MemoryFile memoryFile,
+ HardwareBuffer hardwareBuffer) {
+ return null;
+ }
+
+ @Override
+ protected void destroyDirectChannelImpl(SensorDirectChannel channel) {
+
+ }
+
+ @Override
+ protected int configureDirectChannelImpl(SensorDirectChannel channel, Sensor s, int rate) {
+ return 0;
+ }
+
+ @Override
+ protected void registerDynamicSensorCallbackImpl(DynamicSensorCallback callback,
+ Handler handler) {
+
+ }
+
+ @Override
+ protected void unregisterDynamicSensorCallbackImpl(
+ DynamicSensorCallback callback) {
+
+ }
+
+ @Override
+ protected boolean requestTriggerSensorImpl(TriggerEventListener listener, Sensor sensor) {
+ return false;
+ }
+
+ @Override
+ protected boolean cancelTriggerSensorImpl(TriggerEventListener listener, Sensor sensor,
+ boolean disable) {
+ return false;
+ }
+
+ @Override
+ protected boolean initDataInjectionImpl(boolean enable) {
+ return false;
+ }
+
+ @Override
+ protected boolean injectSensorDataImpl(Sensor sensor, float[] values, int accuracy,
+ long timestamp) {
+ return false;
+ }
+
+ @Override
+ protected boolean setOperationParameterImpl(SensorAdditionalInfo parameter) {
+ return false;
+ }
+
+ public class MockSensor {
+ final Sensor sensor;
+ final ArraySet<SensorEventListener> listeners = new ArraySet<>();
+
+ private MockSensor(Sensor sensor) {
+ this.sensor = sensor;
+ }
+
+ public void sendProximityResult(boolean far) {
+ SensorEvent event = createSensorEvent(1);
+ event.values[0] = far ? sensor.getMaximumRange() : 0;
+ for (SensorEventListener listener : listeners) {
+ listener.onSensorChanged(event);
+ }
+ }
+
+ private SensorEvent createSensorEvent(int valuesSize) {
+ SensorEvent event;
+ try {
+ Constructor<SensorEvent> constr =
+ SensorEvent.class.getDeclaredConstructor(Integer.TYPE);
+ constr.setAccessible(true);
+ event = constr.newInstance(valuesSize);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ event.sensor = sensor;
+ event.timestamp = SystemClock.elapsedRealtimeNanos();
+
+ return event;
+ }
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java
index ff644d8..ebd266b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java
@@ -312,62 +312,72 @@
}
@Test
- public void testGetMessageWithNoOrganizationAndNoVPN() {
- assertEquals(getExpectedMessage(false /* hasDeviceOwnerOrganization */, false /* hasVPN */),
- mFooter.getMessage(DEVICE_OWNER_PACKAGE,
- null /* profileOwnerPackage */,
- null /* primaryVpn */,
- null /* profileVpn */,
- null /* deviceOwnerOrganization */,
- false /* hasProfileOwner */));
+ public void testGetManagementMessage() {
+ assertEquals(null, mFooter.getManagementMessage(false, MANAGING_ORGANIZATION));
+ assertEquals(mContext.getString(R.string.monitoring_description_named_management,
+ MANAGING_ORGANIZATION),
+ mFooter.getManagementMessage(true, MANAGING_ORGANIZATION));
+ assertEquals(mContext.getString(R.string.monitoring_description_management),
+ mFooter.getManagementMessage(true, null));
}
@Test
- public void testGetMessageWithNoOrganizationAndVPN() {
- assertEquals(getExpectedMessage(false /* hasDeviceOwnerOrganization */, true /* hasVPN */),
- mFooter.getMessage(DEVICE_OWNER_PACKAGE,
- null /* profileOwnerPackage */,
- VPN_PACKAGE,
- null /* profileVpn */,
- null /* deviceOwnerOrganization */,
- false /* hasProfileOwner */));
+ public void testGetCaCertsMessage() {
+ assertEquals(null, mFooter.getCaCertsMessage(true, false, false));
+ assertEquals(null, mFooter.getCaCertsMessage(false, false, false));
+ assertEquals(mContext.getString(R.string.monitoring_description_management_ca_certificate),
+ mFooter.getCaCertsMessage(true, true, true));
+ assertEquals(mContext.getString(R.string.monitoring_description_management_ca_certificate),
+ mFooter.getCaCertsMessage(true, false, true));
+ assertEquals(mContext.getString(
+ R.string.monitoring_description_managed_profile_ca_certificate),
+ mFooter.getCaCertsMessage(false, false, true));
+ assertEquals(mContext.getString(
+ R.string.monitoring_description_ca_certificate),
+ mFooter.getCaCertsMessage(false, true, false));
}
@Test
- public void testGetMessageWithOrganizationAndNoVPN() {
- assertEquals(getExpectedMessage(true /* hasDeviceOwnerOrganization */, false /* hasVPN */),
- mFooter.getMessage(DEVICE_OWNER_PACKAGE,
- null /* profileOwnerPackage */,
- null /* primaryVpn */,
- null /* profileVpn */,
- MANAGING_ORGANIZATION,
- false /* hasProfileOwner */));
+ public void testGetNetworkLoggingMessage() {
+ assertEquals(null, mFooter.getNetworkLoggingMessage(false));
+ assertEquals(mContext.getString(R.string.monitoring_description_management_network_logging),
+ mFooter.getNetworkLoggingMessage(true));
}
@Test
- public void testGetMessageWithOrganizationAndVPN() {
- assertEquals(getExpectedMessage(true /* hasDeviceOwnerOrganization */, true /* hasVPN */),
- mFooter.getMessage(DEVICE_OWNER_PACKAGE,
- null /* profileOwnerPackage */,
- VPN_PACKAGE,
- null /* profileVpn */,
- MANAGING_ORGANIZATION,
- false /* hasProfileOwner */));
+ public void testGetVpnMessage() {
+ assertEquals(null, mFooter.getVpnMessage(true, true, null, null));
+ assertEquals(addLink(mContext.getString(R.string.monitoring_description_two_named_vpns,
+ VPN_PACKAGE, VPN_PACKAGE_2)),
+ mFooter.getVpnMessage(true, true, VPN_PACKAGE, VPN_PACKAGE_2));
+ assertEquals(addLink(mContext.getString(R.string.monitoring_description_two_named_vpns,
+ VPN_PACKAGE, VPN_PACKAGE_2)),
+ mFooter.getVpnMessage(false, true, VPN_PACKAGE, VPN_PACKAGE_2));
+ assertEquals(addLink(mContext.getString(R.string.monitoring_description_named_vpn,
+ VPN_PACKAGE)),
+ mFooter.getVpnMessage(true, false, VPN_PACKAGE, null));
+ assertEquals(addLink(mContext.getString(R.string.monitoring_description_named_vpn,
+ VPN_PACKAGE)),
+ mFooter.getVpnMessage(false, false, VPN_PACKAGE, null));
+ assertEquals(addLink(mContext.getString(R.string.monitoring_description_named_vpn,
+ VPN_PACKAGE_2)),
+ mFooter.getVpnMessage(true, true, null, VPN_PACKAGE_2));
+ assertEquals(addLink(mContext.getString(
+ R.string.monitoring_description_managed_profile_named_vpn,
+ VPN_PACKAGE_2)),
+ mFooter.getVpnMessage(false, true, null, VPN_PACKAGE_2));
+ assertEquals(addLink(mContext.getString(
+ R.string.monitoring_description_personal_profile_named_vpn,
+ VPN_PACKAGE)),
+ mFooter.getVpnMessage(false, true, VPN_PACKAGE, null));
}
- private CharSequence getExpectedMessage(boolean hasDeviceOwnerOrganization, boolean hasVPN) {
+ private CharSequence addLink(CharSequence description) {
final SpannableStringBuilder message = new SpannableStringBuilder();
- message.append(hasDeviceOwnerOrganization ?
- mContext.getString(R.string.monitoring_description_do_header_with_name,
- MANAGING_ORGANIZATION, DEVICE_OWNER_PACKAGE) :
- mContext.getString(R.string.monitoring_description_do_header_generic,
- DEVICE_OWNER_PACKAGE));
- message.append("\n\n");
- message.append(mContext.getString(R.string.monitoring_description_do_body));
- message.append(mContext.getString(
- R.string.monitoring_description_do_learn_more_separator));
- message.append(mContext.getString(R.string.monitoring_description_do_learn_more),
- mFooter.new EnterprisePrivacySpan(), 0);
+ message.append(description);
+ message.append(mContext.getString(R.string.monitoring_description_vpn_settings_separator));
+ message.append(mContext.getString(R.string.monitoring_description_vpn_settings),
+ mFooter.new VpnSpan(), 0);
return message;
}
}
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index f56cbdd..fc70b2b 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -3911,6 +3911,18 @@
// OS: O
APPLICATIONS_STORAGE_MOVIES = 935;
+ // OPEN: Text selection "assist" menu item shown.
+ // SUBTYPE: 1 is for EMAIL, 2 is for PHONE, 3 is for ADDRESS, 4 is for URL, 0 is for OTHER.
+ // CATEGORY: TEXT_CONTROLS
+ // OS: O
+ TEXT_SELECTION_MENU_ITEM_ASSIST = 936;
+
+ // ACTION: Text selection "assist" menu item clicked.
+ // SUBTYPE: 1 is for EMAIL, 2 is for PHONE, 3 is for ADDRESS, 4 is for URL, 0 is for OTHER.
+ // CATEGORY: TEXT_CONTROLS
+ // OS: O
+ ACTION_TEXT_SELECTION_MENU_ITEM_ASSIST = 937;
+
// ---- End O Constants, all O constants go above this line ----
// Add new aosp constants above this line.
diff --git a/services/Android.mk b/services/Android.mk
index a4c891b..5c863b0 100644
--- a/services/Android.mk
+++ b/services/Android.mk
@@ -27,6 +27,7 @@
appwidget \
autofill \
backup \
+ companion \
coverage\
devicepolicy \
midi \
diff --git a/services/companion/Android.mk b/services/companion/Android.mk
new file mode 100644
index 0000000..be48761
--- /dev/null
+++ b/services/companion/Android.mk
@@ -0,0 +1,12 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := services.companion
+
+LOCAL_SRC_FILES += \
+ $(call all-java-files-under,java)
+
+LOCAL_JAVA_LIBRARIES := services.core
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/services/print/java/com/android/server/print/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
similarity index 99%
rename from services/print/java/com/android/server/print/CompanionDeviceManagerService.java
rename to services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
index 122a954..41b70a1 100644
--- a/services/print/java/com/android/server/print/CompanionDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
@@ -15,7 +15,7 @@
*/
-package com.android.server.print;
+package com.android.server.companion;
import static com.android.internal.util.CollectionUtils.size;
import static com.android.internal.util.Preconditions.checkArgument;
@@ -81,7 +81,6 @@
import java.util.concurrent.ConcurrentMap;
import java.util.function.Function;
-//TODO move to own package!
//TODO onStop schedule unbind in 5 seconds
//TODO make sure APIs are only callable from currently focused app
//TODO schedule stopScan on activity destroy(except if configuration change)
diff --git a/services/core/java/com/android/server/LockSettingsService.java b/services/core/java/com/android/server/LockSettingsService.java
index e26630b..3a24091 100644
--- a/services/core/java/com/android/server/LockSettingsService.java
+++ b/services/core/java/com/android/server/LockSettingsService.java
@@ -1562,8 +1562,9 @@
// migration to synthetic password.
synchronized (mSpManager) {
if (shouldMigrateToSyntheticPasswordLocked(userId)) {
- initializeSyntheticPasswordLocked(storedHash.hash, credential,
- storedHash.type, userId);
+ AuthenticationToken auth = initializeSyntheticPasswordLocked(
+ storedHash.hash, credential, storedHash.type, userId);
+ activateEscrowTokens(auth, userId);
}
}
}
@@ -2071,9 +2072,11 @@
pwdHandle, null, userId).authToken;
}
}
- disableEscrowTokenOnNonManagedDevicesIfNeeded(userId);
- if (!mSpManager.hasEscrowData(userId)) {
- throw new SecurityException("Escrow token is disabled on the current user");
+ if (isSyntheticPasswordBasedCredentialLocked(userId)) {
+ disableEscrowTokenOnNonManagedDevicesIfNeeded(userId);
+ if (!mSpManager.hasEscrowData(userId)) {
+ throw new SecurityException("Escrow token is disabled on the current user");
+ }
}
long handle = mSpManager.createTokenBasedSyntheticPassword(token, userId);
if (auth != null) {
@@ -2085,6 +2088,7 @@
private void activateEscrowTokens(AuthenticationToken auth, int userId) throws RemoteException {
if (DEBUG) Slog.d(TAG, "activateEscrowTokens: user=" + userId);
+ disableEscrowTokenOnNonManagedDevicesIfNeeded(userId);
synchronized (mSpManager) {
for (long handle : mSpManager.getPendingTokensForUser(userId)) {
Slog.i(TAG, String.format("activateEscrowTokens: %x %d ", handle, userId));
diff --git a/services/core/java/com/android/server/NsdService.java b/services/core/java/com/android/server/NsdService.java
index 8ae95d5..bb530fb 100644
--- a/services/core/java/com/android/server/NsdService.java
+++ b/services/core/java/com/android/server/NsdService.java
@@ -57,46 +57,27 @@
private static final String TAG = "NsdService";
private static final String MDNS_TAG = "mDnsConnector";
- private static final boolean DBG = false;
+ private static final boolean DBG = true;
- private Context mContext;
- private ContentResolver mContentResolver;
- private NsdStateMachine mNsdStateMachine;
+ private final Context mContext;
+ private final ContentResolver mContentResolver;
+ private final NsdStateMachine mNsdStateMachine;
+ private final NativeDaemonConnector mNativeConnector;
+ private final CountDownLatch mNativeDaemonConnected = new CountDownLatch(1);
/**
* Clients receiving asynchronous messages
*/
- private HashMap<Messenger, ClientInfo> mClients = new HashMap<Messenger, ClientInfo>();
+ private final HashMap<Messenger, ClientInfo> mClients = new HashMap<>();
/* A map from unique id to client info */
- private SparseArray<ClientInfo> mIdToClientInfoMap= new SparseArray<ClientInfo>();
+ private final SparseArray<ClientInfo> mIdToClientInfoMap= new SparseArray<>();
- private AsyncChannel mReplyChannel = new AsyncChannel();
+ private final AsyncChannel mReplyChannel = new AsyncChannel();
- private int INVALID_ID = 0;
+ private static final int INVALID_ID = 0;
private int mUniqueId = 1;
- private static final int BASE = Protocol.BASE_NSD_MANAGER;
- private static final int CMD_TO_STRING_COUNT = NsdManager.RESOLVE_SERVICE - BASE + 1;
- private static String[] sCmdToString = new String[CMD_TO_STRING_COUNT];
-
- static {
- sCmdToString[NsdManager.DISCOVER_SERVICES - BASE] = "DISCOVER";
- sCmdToString[NsdManager.STOP_DISCOVERY - BASE] = "STOP-DISCOVER";
- sCmdToString[NsdManager.REGISTER_SERVICE - BASE] = "REGISTER";
- sCmdToString[NsdManager.UNREGISTER_SERVICE - BASE] = "UNREGISTER";
- sCmdToString[NsdManager.RESOLVE_SERVICE - BASE] = "RESOLVE";
- }
-
- private static String cmdToString(int cmd) {
- cmd -= BASE;
- if ((cmd >= 0) && (cmd < sCmdToString.length)) {
- return sCmdToString[cmd];
- } else {
- return null;
- }
- }
-
private class NsdStateMachine extends StateMachine {
private final DefaultState mDefaultState = new DefaultState();
@@ -105,7 +86,7 @@
@Override
protected String getWhatToString(int what) {
- return cmdToString(what);
+ return NsdManager.nameOf(what);
}
/**
@@ -114,13 +95,13 @@
private void registerForNsdSetting() {
ContentObserver contentObserver = new ContentObserver(this.getHandler()) {
@Override
- public void onChange(boolean selfChange) {
- if (isNsdEnabled()) {
- mNsdStateMachine.sendMessage(NsdManager.ENABLE);
- } else {
- mNsdStateMachine.sendMessage(NsdManager.DISABLE);
- }
+ public void onChange(boolean selfChange) {
+ if (isNsdEnabled()) {
+ mNsdStateMachine.sendMessage(NsdManager.ENABLE);
+ } else {
+ mNsdStateMachine.sendMessage(NsdManager.DISABLE);
}
+ }
};
mContext.getContentResolver().registerContentObserver(
@@ -272,20 +253,17 @@
public boolean processMessage(Message msg) {
ClientInfo clientInfo;
NsdServiceInfo servInfo;
- boolean result = HANDLED;
int id;
switch (msg.what) {
- case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
+ case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
//First client
if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL &&
mClients.size() == 0) {
startMDnsDaemon();
}
- result = NOT_HANDLED;
- break;
+ return NOT_HANDLED;
case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
- result = NOT_HANDLED;
- break;
+ return NOT_HANDLED;
case NsdManager.DISABLE:
//TODO: cleanup clients
transitionTo(mDisabledState);
@@ -396,25 +374,23 @@
case NsdManager.NATIVE_DAEMON_EVENT:
NativeEvent event = (NativeEvent) msg.obj;
if (!handleNativeEvent(event.code, event.raw, event.cooked)) {
- result = NOT_HANDLED;
+ return NOT_HANDLED;
}
break;
default:
- result = NOT_HANDLED;
- break;
+ return NOT_HANDLED;
}
- return result;
+ return HANDLED;
}
private boolean handleNativeEvent(int code, String raw, String[] cooked) {
- boolean handled = true;
NsdServiceInfo servInfo;
int id = Integer.parseInt(cooked[1]);
ClientInfo clientInfo = mIdToClientInfoMap.get(id);
if (clientInfo == null) {
- Slog.e(TAG, "Unique id with no client mapping: " + id);
- handled = false;
- return handled;
+ String name = NativeResponseCode.nameOf(code);
+ Slog.e(TAG, String.format("id %d for %s has no client mapping", id, name));
+ return false;
}
/* This goes in response as msg.arg2 */
@@ -423,42 +399,42 @@
// This can happen because of race conditions. For example,
// SERVICE_FOUND may race with STOP_SERVICE_DISCOVERY,
// and we may get in this situation.
- Slog.d(TAG, "Notification for a listener that is no longer active: " + id);
- handled = false;
- return handled;
+ String name = NativeResponseCode.nameOf(code);
+ Slog.d(TAG, String.format(
+ "Notification %s for listener id %d that is no longer active",
+ name, id));
+ return false;
}
-
+ if (DBG) {
+ String name = NativeResponseCode.nameOf(code);
+ Slog.d(TAG, String.format("Native daemon message %s: %s", name, raw));
+ }
switch (code) {
case NativeResponseCode.SERVICE_FOUND:
/* NNN uniqueId serviceName regType domain */
- if (DBG) Slog.d(TAG, "SERVICE_FOUND Raw: " + raw);
servInfo = new NsdServiceInfo(cooked[2], cooked[3]);
clientInfo.mChannel.sendMessage(NsdManager.SERVICE_FOUND, 0,
clientId, servInfo);
break;
case NativeResponseCode.SERVICE_LOST:
/* NNN uniqueId serviceName regType domain */
- if (DBG) Slog.d(TAG, "SERVICE_LOST Raw: " + raw);
servInfo = new NsdServiceInfo(cooked[2], cooked[3]);
clientInfo.mChannel.sendMessage(NsdManager.SERVICE_LOST, 0,
clientId, servInfo);
break;
case NativeResponseCode.SERVICE_DISCOVERY_FAILED:
/* NNN uniqueId errorCode */
- if (DBG) Slog.d(TAG, "SERVICE_DISC_FAILED Raw: " + raw);
clientInfo.mChannel.sendMessage(NsdManager.DISCOVER_SERVICES_FAILED,
NsdManager.FAILURE_INTERNAL_ERROR, clientId);
break;
case NativeResponseCode.SERVICE_REGISTERED:
/* NNN regId serviceName regType */
- if (DBG) Slog.d(TAG, "SERVICE_REGISTERED Raw: " + raw);
servInfo = new NsdServiceInfo(cooked[2], null);
clientInfo.mChannel.sendMessage(NsdManager.REGISTER_SERVICE_SUCCEEDED,
id, clientId, servInfo);
break;
case NativeResponseCode.SERVICE_REGISTRATION_FAILED:
/* NNN regId errorCode */
- if (DBG) Slog.d(TAG, "SERVICE_REGISTER_FAILED Raw: " + raw);
clientInfo.mChannel.sendMessage(NsdManager.REGISTER_SERVICE_FAILED,
NsdManager.FAILURE_INTERNAL_ERROR, clientId);
break;
@@ -470,7 +446,6 @@
break;
case NativeResponseCode.SERVICE_RESOLVED:
/* NNN resolveId fullName hostName port txtlen txtdata */
- if (DBG) Slog.d(TAG, "SERVICE_RESOLVED Raw: " + raw);
int index = 0;
while (index < cooked[2].length() && cooked[2].charAt(index) != '.') {
if (cooked[2].charAt(index) == '\\') {
@@ -507,7 +482,6 @@
break;
case NativeResponseCode.SERVICE_RESOLUTION_FAILED:
/* NNN resolveId errorCode */
- if (DBG) Slog.d(TAG, "SERVICE_RESOLVE_FAILED Raw: " + raw);
stopResolveService(id);
removeRequestMap(clientId, id, clientInfo);
clientInfo.mResolvedService = null;
@@ -519,13 +493,11 @@
stopGetAddrInfo(id);
removeRequestMap(clientId, id, clientInfo);
clientInfo.mResolvedService = null;
- if (DBG) Slog.d(TAG, "SERVICE_RESOLVE_FAILED Raw: " + raw);
clientInfo.mChannel.sendMessage(NsdManager.RESOLVE_SERVICE_FAILED,
NsdManager.FAILURE_INTERNAL_ERROR, clientId);
break;
case NativeResponseCode.SERVICE_GET_ADDR_SUCCESS:
/* NNN resolveId hostname ttl addr */
- if (DBG) Slog.d(TAG, "SERVICE_GET_ADDR_SUCCESS Raw: " + raw);
try {
clientInfo.mResolvedService.setHost(InetAddress.getByName(cooked[4]));
clientInfo.mChannel.sendMessage(NsdManager.RESOLVE_SERVICE_SUCCEEDED,
@@ -539,10 +511,9 @@
clientInfo.mResolvedService = null;
break;
default:
- handled = false;
- break;
+ return false;
}
- return handled;
+ return true;
}
}
}
@@ -571,9 +542,6 @@
return sb.toString();
}
- private NativeDaemonConnector mNativeConnector;
- private final CountDownLatch mNativeDaemonConnected = new CountDownLatch(1);
-
private NsdService(Context context) {
mContext = context;
mContentResolver = context.getContentResolver();
@@ -634,7 +602,7 @@
}
/* These should be in sync with system/netd/server/ResponseCode.h */
- class NativeResponseCode {
+ static final class NativeResponseCode {
public static final int SERVICE_DISCOVERY_FAILED = 602;
public static final int SERVICE_FOUND = 603;
public static final int SERVICE_LOST = 604;
@@ -650,6 +618,29 @@
public static final int SERVICE_GET_ADDR_FAILED = 611;
public static final int SERVICE_GET_ADDR_SUCCESS = 612;
+
+ private static final SparseArray<String> CODE_NAMES = new SparseArray<>();
+ static {
+ CODE_NAMES.put(SERVICE_DISCOVERY_FAILED, "SERVICE_DISCOVERY_FAILED");
+ CODE_NAMES.put(SERVICE_FOUND, "SERVICE_FOUND");
+ CODE_NAMES.put(SERVICE_LOST, "SERVICE_LOST");
+ CODE_NAMES.put(SERVICE_REGISTRATION_FAILED, "SERVICE_REGISTRATION_FAILED");
+ CODE_NAMES.put(SERVICE_REGISTERED, "SERVICE_REGISTERED");
+ CODE_NAMES.put(SERVICE_RESOLUTION_FAILED, "SERVICE_RESOLUTION_FAILED");
+ CODE_NAMES.put(SERVICE_RESOLVED, "SERVICE_RESOLVED");
+ CODE_NAMES.put(SERVICE_UPDATED, "SERVICE_UPDATED");
+ CODE_NAMES.put(SERVICE_UPDATE_FAILED, "SERVICE_UPDATE_FAILED");
+ CODE_NAMES.put(SERVICE_GET_ADDR_FAILED, "SERVICE_GET_ADDR_FAILED");
+ CODE_NAMES.put(SERVICE_GET_ADDR_SUCCESS, "SERVICE_GET_ADDR_SUCCESS");
+ }
+
+ static String nameOf(int code) {
+ String name = CODE_NAMES.get(code);
+ if (name == null) {
+ return Integer.toString(code);
+ }
+ return name;
+ }
}
private class NativeEvent {
@@ -863,10 +854,10 @@
private NsdServiceInfo mResolvedService;
/* A map from client id to unique id sent to mDns */
- private SparseArray<Integer> mClientIds = new SparseArray<Integer>();
+ private final SparseArray<Integer> mClientIds = new SparseArray<>();
/* A map from client id to the type of the request we had received */
- private SparseArray<Integer> mClientRequests = new SparseArray<Integer>();
+ private final SparseArray<Integer> mClientRequests = new SparseArray<>();
private ClientInfo(AsyncChannel c, Messenger m) {
mChannel = c;
diff --git a/services/core/java/com/android/server/SyntheticPasswordManager.java b/services/core/java/com/android/server/SyntheticPasswordManager.java
index 2517613..d23584f 100644
--- a/services/core/java/com/android/server/SyntheticPasswordManager.java
+++ b/services/core/java/com/android/server/SyntheticPasswordManager.java
@@ -48,6 +48,20 @@
* The SP has an associated password handle, which binds to the SID for that user. The password
* handle is persisted by SyntheticPasswordManager internally.
* If the user credential is null, it's treated as if the credential is DEFAULT_PASSWORD
+ *
+ * Information persisted on disk:
+ * for each user (stored under DEFAULT_HANDLE):
+ * SP_HANDLE_NAME: GateKeeper password handle of synthetic password. Only available if user
+ * credential exists, cleared when user clears their credential.
+ * SP_E0_NAME, SP_P1_NAME: Secret to derive synthetic password when combined with escrow
+ * tokens. Destroyed when escrow support is turned off for the given user.
+ *
+ * for each SP blob under the user (stored under the corresponding handle):
+ * SP_BLOB_NAME: The encrypted synthetic password. Always exists.
+ * PASSWORD_DATA_NAME: Metadata about user credential. Only exists for password based SP.
+ * SECDISCARDABLE_NAME: Part of the necessary ingredient to decrypt SP_BLOB_NAME for the
+ * purpose of secure deletion.
+ *
*/
public class SyntheticPasswordManager {
private static final String SP_BLOB_NAME = "spblob";
@@ -221,7 +235,7 @@
* If the existing credential hash is non-null, the existing SID mill be migrated so
* the synthetic password in the authentication token will produce the same SID
* (the corresponding synthetic password handle is persisted by SyntheticPasswordManager
- * in a per-user data storage.
+ * in a per-user data storage.)
*
* If the existing credential hash is null, it means the given user should have no SID so
* SyntheticPasswordManager will nuke any SP handle previously persisted. In this case,
@@ -578,8 +592,6 @@
private void destroySyntheticPassword(long handle, int userId) {
destroyState(SP_BLOB_NAME, true, handle, userId);
- destroyState(SP_E0_NAME, true, handle, userId);
- destroyState(SP_P1_NAME, true, handle, userId);
destroySPBlobKey(getHandleName(handle));
}
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 2cd14e9..b91ecf5 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -756,7 +756,7 @@
}
}
if (r.fgRequired) {
- if (DEBUG_BACKGROUND_CHECK) {
+ if (DEBUG_SERVICE || DEBUG_BACKGROUND_CHECK) {
Slog.i(TAG, "Service called startForeground() as required: " + r);
}
r.fgRequired = false;
@@ -1334,16 +1334,19 @@
final ComponentName comp = service.getComponent();
if (comp != null) {
r = smap.mServicesByName.get(comp);
+ if (DEBUG_SERVICE && r != null) Slog.v(TAG_SERVICE, "Retrieved by component: " + r);
}
if (r == null && !isBindExternal) {
Intent.FilterComparison filter = new Intent.FilterComparison(service);
r = smap.mServicesByIntent.get(filter);
+ if (DEBUG_SERVICE && r != null) Slog.v(TAG_SERVICE, "Retrieved by intent: " + r);
}
if (r != null && (r.serviceInfo.flags & ServiceInfo.FLAG_EXTERNAL_SERVICE) != 0
&& !callingPackage.equals(r.packageName)) {
// If an external service is running within its own package, other packages
// should not bind to that instance.
r = null;
+ if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Whoops, can't use existing external service");
}
if (r == null) {
try {
@@ -1403,12 +1406,14 @@
sInfo.applicationInfo = mAm.getAppInfoForUser(sInfo.applicationInfo, userId);
}
r = smap.mServicesByName.get(name);
+ if (DEBUG_SERVICE && r != null) Slog.v(TAG_SERVICE,
+ "Retrieved via pm by intent: " + r);
if (r == null && createIfNeeded) {
- Intent.FilterComparison filter
+ final Intent.FilterComparison filter
= new Intent.FilterComparison(service.cloneFilter());
- ServiceRestarter res = new ServiceRestarter();
- BatteryStatsImpl.Uid.Pkg.Serv ss = null;
- BatteryStatsImpl stats = mAm.mBatteryStatsService.getActiveStatistics();
+ final ServiceRestarter res = new ServiceRestarter();
+ final BatteryStatsImpl.Uid.Pkg.Serv ss;
+ final BatteryStatsImpl stats = mAm.mBatteryStatsService.getActiveStatistics();
synchronized (stats) {
ss = stats.getServiceStatsLocked(
sInfo.applicationInfo.uid, sInfo.packageName,
@@ -1421,12 +1426,14 @@
// Make sure this component isn't in the pending list.
for (int i=mPendingServices.size()-1; i>=0; i--) {
- ServiceRecord pr = mPendingServices.get(i);
+ final ServiceRecord pr = mPendingServices.get(i);
if (pr.serviceInfo.applicationInfo.uid == sInfo.applicationInfo.uid
&& pr.name.equals(name)) {
+ if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Remove pending: " + pr);
mPendingServices.remove(i);
}
}
+ if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Retrieve created new service: " + r);
}
} catch (RemoteException ex) {
// pm is in same process, this will never happen.
@@ -2114,7 +2121,28 @@
}
}
- if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Bringing down " + r + " " + r.intent);
+ // Check to see if the service had been started as foreground, but being
+ // brought down before actually showing a notification. That is not allowed.
+ if (r.fgRequired) {
+ Slog.w(TAG_SERVICE, "Bringing down service while still waiting for start foreground: "
+ + r);
+ r.fgRequired = false;
+ r.fgWaiting = false;
+ mAm.mHandler.removeMessages(
+ ActivityManagerService.SERVICE_FOREGROUND_TIMEOUT_MSG, r);
+ if (r.app != null) {
+ Message msg = mAm.mHandler.obtainMessage(
+ ActivityManagerService.SERVICE_FOREGROUND_CRASH_MSG);
+ msg.obj = r.app;
+ mAm.mHandler.sendMessage(msg);
+ }
+ }
+
+ if (DEBUG_SERVICE) {
+ RuntimeException here = new RuntimeException();
+ here.fillInStackTrace();
+ Slog.v(TAG_SERVICE, "Bringing down " + r + " " + r.intent, here);
+ }
r.destroyTime = SystemClock.uptimeMillis();
if (LOG_SERVICE_START_STOP) {
EventLogTags.writeAmDestroyService(
@@ -2122,7 +2150,14 @@
}
final ServiceMap smap = getServiceMapLocked(r.userId);
- smap.mServicesByName.remove(r.name);
+ ServiceRecord found = smap.mServicesByName.remove(r.name);
+ if (found != r) {
+ // This is not actually the service we think is running... this should not happen,
+ // but if it does, fail hard.
+ smap.mServicesByName.put(r.name, found);
+ throw new IllegalStateException("Bringing down " + r + " but actually running "
+ + found);
+ }
smap.mServicesByIntent.remove(r.intent);
r.totalRestartCount = 0;
unscheduleServiceRestartLocked(r, 0, true);
@@ -2962,7 +2997,7 @@
void serviceForegroundTimeout(ServiceRecord r) {
ProcessRecord app;
synchronized (mAm) {
- if (!r.fgRequired) {
+ if (!r.fgRequired || r.destroying) {
return;
}
@@ -2980,6 +3015,11 @@
}
}
+ void serviceForegroundCrash(ProcessRecord app) {
+ mAm.crashApplication(app.uid, app.pid, app.info.packageName, app.userId,
+ "Context.startForegroundService() did not then call Service.startForeground()");
+ }
+
void scheduleServiceTimeoutLocked(ProcessRecord proc) {
if (proc.executingServices.size() == 0 || proc.thread == null) {
return;
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 8f1afa8..6e9e8a4 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -1703,6 +1703,7 @@
static final int SERVICE_FOREGROUND_TIMEOUT_MSG = 66;
static final int DISPATCH_PENDING_INTENT_CANCEL_MSG = 67;
static final int PUSH_TEMP_WHITELIST_UI_MSG = 68;
+ static final int SERVICE_FOREGROUND_CRASH_MSG = 69;
static final int START_USER_SWITCH_FG_MSG = 712;
static final int FIRST_ACTIVITY_STACK_MSG = 100;
@@ -1974,6 +1975,9 @@
case SERVICE_FOREGROUND_TIMEOUT_MSG: {
mServices.serviceForegroundTimeout((ServiceRecord)msg.obj);
} break;
+ case SERVICE_FOREGROUND_CRASH_MSG: {
+ mServices.serviceForegroundCrash((ProcessRecord)msg.obj);
+ } break;
case DISPATCH_PENDING_INTENT_CANCEL_MSG: {
RemoteCallbackList<IResultReceiver> callbacks
= (RemoteCallbackList<IResultReceiver>)msg.obj;
@@ -11252,6 +11256,10 @@
holder.provider = null;
return holder;
}
+ // Don't expose instant app providers
+ if (cpr.appInfo.isInstantApp()) {
+ return null;
+ }
final long origId = Binder.clearCallingIdentity();
@@ -18368,10 +18376,12 @@
public Intent registerReceiver(IApplicationThread caller, String callerPackage,
IIntentReceiver receiver, IntentFilter filter, String permission, int userId,
- boolean visibleToInstantApps) {
+ int flags) {
enforceNotIsolatedCaller("registerReceiver");
ArrayList<Intent> stickyIntents = null;
ProcessRecord callerApp = null;
+ final boolean visibleToInstantApps
+ = (flags & Context.RECEIVER_VISIBLE_TO_INSTANT_APPS) != 0;
int callingUid;
int callingPid;
boolean instantApp;
@@ -23977,15 +23987,6 @@
}
}
- @Override
- public long getActivityStartInitiatedTime(IBinder token) {
- final ActivityRecord r = ActivityRecord.forTokenLocked(token);
- if (r != null) {
- return r.mStartInitiatedTimeMs;
- }
- return 0;
- }
-
void updateApplicationInfoLocked(@NonNull List<String> packagesToUpdate, int userId) {
final PackageManagerInternal packageManager = getPackageManagerInternalLocked();
final boolean updateFrameworkRes = packagesToUpdate.contains("android");
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 7cdddc0..43904d6 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -341,12 +341,6 @@
private final Rect mBounds = new Rect();
/**
- * Denotes the timestamp at which this activity start was last initiated in the
- * {@link SystemClock#uptimeMillis()} time base.
- */
- long mStartInitiatedTimeMs;
-
- /**
* Temp configs used in {@link #ensureActivityConfigurationLocked(int, boolean)}
*/
private final Configuration mTmpConfig1 = new Configuration();
@@ -504,8 +498,6 @@
pw.print(" forceNewConfig="); pw.println(forceNewConfig);
pw.print(prefix); pw.print("mActivityType=");
pw.println(activityTypeToString(mActivityType));
- pw.print(prefix); pw.print("mStartInitiatedTimeMs=");
- TimeUtils.formatDuration(mStartInitiatedTimeMs, now, pw);
if (requestedVrComponent != null) {
pw.print(prefix);
pw.print("requestedVrComponent=");
@@ -2130,6 +2122,11 @@
if (mWindowContainerController == null) {
return;
}
+ if (mTaskOverlay) {
+ // We don't show starting window for overlay activities.
+ return;
+ }
+
final CompatibilityInfo compatInfo =
service.compatibilityInfoForPackageLocked(info.applicationInfo);
final boolean shown = mWindowContainerController.addStartingWindow(packageName, theme,
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 85c5c64..824ec68 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -1152,6 +1152,18 @@
if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Sleep needs to pause " + mResumedActivity);
if (DEBUG_USER_LEAVING) Slog.v(TAG_USER_LEAVING,
"Sleep => pause with userLeaving=false");
+
+ // If we are in the middle of resuming the top activity in
+ // {@link #resumeTopActivityUncheckedLocked}, mResumedActivity will be set but not
+ // resumed yet. We must not proceed pausing the activity here. This method will be
+ // called again if necessary as part of
+ // {@link ActivityStackSupervisor#checkReadyForSleepLocked}.
+ if (mStackSupervisor.inResumeTopActivity) {
+ if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "In the middle of resuming top activity "
+ + mResumedActivity);
+ return true;
+ }
+
startPausingLocked(false, true, null, false);
return true;
}
@@ -1229,6 +1241,7 @@
}
}
ActivityRecord prev = mResumedActivity;
+
if (prev == null) {
if (resuming == null) {
Slog.wtf(TAG, "Trying to pause when nothing is resumed");
@@ -2191,6 +2204,13 @@
} finally {
mStackSupervisor.inResumeTopActivity = false;
}
+ // When resuming the top activity, it may be necessary to pause the top activity (for
+ // example, returning to the lock screen. We suppress the normal pause logic in
+ // {@link #resumeTopActivityUncheckedLocked}, since the top activity is resumed at the end.
+ // We call the {@link ActivityStackSupervisor#checkReadyForSleepLocked} again here to ensure
+ // any necessary pause logic occurs.
+ mStackSupervisor.checkReadyForSleepLocked();
+
return result;
}
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 152d5f4..ab70340 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -2397,10 +2397,10 @@
} else {
for (int i = 0; i < size; i++) {
final TaskRecord task = tasks.get(i);
- final int position = fullscreenStack != null
- ? Math.max(fullscreenStack.getAllTasks().size() - 1, 0) : 0;
- // Defer resume until all the tasks have been moved to the fullscreen stack
- task.reparent(FULLSCREEN_WORKSPACE_STACK_ID, position,
+ // Position the tasks in the fullscreen stack in order at the bottom of the
+ // stack. Also defer resume until all the tasks have been moved to the
+ // fullscreen stack.
+ task.reparent(FULLSCREEN_WORKSPACE_STACK_ID, i /* position */,
REPARENT_LEAVE_STACK_IN_PLACE, !ANIMATE, DEFER_RESUME,
schedulePictureInPictureModeChange,
"moveTasksToFullscreenStack - NOT_onTop");
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index 8f1c203..56594d3 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -244,7 +244,6 @@
ActivityOptions options, boolean ignoreTargetSecurity, boolean componentSpecified,
ActivityRecord[] outActivity, ActivityStackSupervisor.ActivityContainer container,
TaskRecord inTask) {
- final long activityStartTime = SystemClock.uptimeMillis();
int err = ActivityManager.START_SUCCESS;
ProcessRecord callerApp = null;
@@ -479,7 +478,6 @@
callingPackage, intent, resolvedType, aInfo, mService.getGlobalConfiguration(),
resultRecord, resultWho, requestCode, componentSpecified, voiceSession != null,
mSupervisor, container, options, sourceRecord);
- r.mStartInitiatedTimeMs = activityStartTime;
if (outActivity != null) {
outActivity[0] = r;
}
@@ -1031,7 +1029,6 @@
// so make sure the task now has the identity of the new intent.
top.getTask().setIntent(mStartActivity);
}
- top.mStartInitiatedTimeMs = mStartActivity.mStartInitiatedTimeMs;
ActivityStack.logStartActivity(AM_NEW_INTENT, mStartActivity, top.getTask());
top.deliverNewIntentLocked(mCallingUid, mStartActivity.intent,
mStartActivity.launchedFromPackage);
@@ -1055,7 +1052,6 @@
setTaskFromIntentActivity(reusedActivity);
if (!mAddingToTask && mReuseTask == null) {
- reusedActivity.mStartInitiatedTimeMs = mStartActivity.mStartInitiatedTimeMs;
// We didn't do anything... but it was needed (a.k.a., client don't use that
// intent!) And for paranoia, make sure we have correctly resumed the top activity.
resumeTargetStackIfNeeded();
@@ -1088,7 +1084,6 @@
|| mLaunchSingleTop || mLaunchSingleTask);
if (dontStart) {
ActivityStack.logStartActivity(AM_NEW_INTENT, top, top.getTask());
- top.mStartInitiatedTimeMs = mStartActivity.mStartInitiatedTimeMs;
// For paranoia, make sure we have correctly resumed the top activity.
topStack.mLastPausedActivity = null;
if (mDoResume) {
@@ -1669,7 +1664,6 @@
// desires.
if (((mLaunchFlags & FLAG_ACTIVITY_SINGLE_TOP) != 0 || mLaunchSingleTop)
&& intentActivity.realActivity.equals(mStartActivity.realActivity)) {
- intentActivity.mStartInitiatedTimeMs = mStartActivity.mStartInitiatedTimeMs;
ActivityStack.logStartActivity(AM_NEW_INTENT, mStartActivity,
intentActivity.getTask());
if (intentActivity.frontOfTask) {
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index aa1b74c..d2d69cb 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -6098,9 +6098,7 @@
// implementation of AccessibilityServicesStateChangeListener
@Override
- public void onAccessibilityServicesStateChanged() {
- final AccessibilityManager accessibilityManager =
- (AccessibilityManager) mContext.getSystemService(Context.ACCESSIBILITY_SERVICE);
+ public void onAccessibilityServicesStateChanged(AccessibilityManager accessibilityManager) {
updateA11yVolumeAlias(accessibilityManager.isAccessibilityVolumeStreamActive());
}
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index 3a1ddd7..91c32e4 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -288,6 +288,9 @@
// current setting - 4 hours
private static final long MAX_RETRY_INTERVAL = 4*60*60*1000;
+ // Timeout when holding wakelocks for downloading XTRA data.
+ private static final long DOWNLOAD_XTRA_DATA_TIMEOUT_MS = 60 * 1000;
+
private BackOff mNtpBackOff = new BackOff(RETRY_INTERVAL, MAX_RETRY_INTERVAL);
private BackOff mXtraBackOff = new BackOff(RETRY_INTERVAL, MAX_RETRY_INTERVAL);
@@ -575,6 +578,10 @@
// override default value of this if lpp_prof is not empty
properties.setProperty("LPP_PROFILE", lpp_prof);
}
+ /*
+ * Overlay carrier properties from a debug configuration file.
+ */
+ loadPropertiesFromFile(DEBUG_PROPERTIES_FILE, properties);
// TODO: we should get rid of C2K specific setting.
setSuplHostPort(properties.getProperty("SUPL_HOST"),
properties.getProperty("SUPL_PORT"));
@@ -587,10 +594,6 @@
Log.e(TAG, "unable to parse C2K_PORT: " + portString);
}
}
- /*
- * Allow carrier properties to be loaded from a debug configuration file.
- */
- loadPropertiesFromFile(DEBUG_PROPERTIES_FILE, properties);
if (native_is_gnss_configuration_supported()) {
Map<String, SetCarrierProperty> map = new HashMap<String, SetCarrierProperty>() {
{
@@ -664,7 +667,7 @@
}
} catch (IOException e) {
- Log.v(TAG, "Could not open GPS configuration file " + filename);
+ if (DEBUG) Log.d(TAG, "Could not open GPS configuration file " + filename);
return false;
}
return true;
@@ -986,7 +989,7 @@
mDownloadXtraDataPending = STATE_DOWNLOADING;
// hold wake lock while task runs
- mWakeLock.acquire();
+ mWakeLock.acquire(DOWNLOAD_XTRA_DATA_TIMEOUT_MS);
Log.i(TAG, "WakeLock acquired by handleDownloadXtraData()");
AsyncTask.THREAD_POOL_EXECUTOR.execute(new Runnable() {
@Override
@@ -1009,7 +1012,11 @@
}
// release wake lock held by task
- mWakeLock.release();
+ if (mWakeLock.isHeld()) {
+ mWakeLock.release();
+ } else {
+ Log.e(TAG, "WakeLock expired before release in handleDownloadXtraData()");
+ }
Log.i(TAG, "WakeLock released by handleDownloadXtraData()");
}
});
diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java
index ee348cf..a275f49 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecord.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecord.java
@@ -751,7 +751,12 @@
@Override
public void setActive(boolean active) {
mIsActive = active;
- mService.updateSession(MediaSessionRecord.this);
+ final long token = Binder.clearCallingIdentity();
+ try {
+ mService.updateSession(MediaSessionRecord.this);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
mHandler.post(MessageHandler.MSG_UPDATE_SESSION_STATE);
}
@@ -862,7 +867,12 @@
}
}
if (typeChanged) {
- mService.onSessionPlaybackTypeChanged(MediaSessionRecord.this);
+ final long token = Binder.clearCallingIdentity();
+ try {
+ mService.onSessionPlaybackTypeChanged(MediaSessionRecord.this);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
mHandler.post(MessageHandler.MSG_UPDATE_VOLUME);
}
}
@@ -877,7 +887,12 @@
mMaxVolume = max;
}
if (typeChanged) {
- mService.onSessionPlaybackTypeChanged(MediaSessionRecord.this);
+ final long token = Binder.clearCallingIdentity();
+ try {
+ mService.onSessionPlaybackTypeChanged(MediaSessionRecord.this);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
mHandler.post(MessageHandler.MSG_UPDATE_VOLUME);
}
}
diff --git a/services/core/java/com/android/server/media/MediaSessionStack.java b/services/core/java/com/android/server/media/MediaSessionStack.java
index 2f82915..0e69bca 100644
--- a/services/core/java/com/android/server/media/MediaSessionStack.java
+++ b/services/core/java/com/android/server/media/MediaSessionStack.java
@@ -121,9 +121,12 @@
public void removeSession(MediaSessionRecord record) {
mSessions.remove(record);
if (mMediaButtonSession == record) {
- // When the media button session is gone, try to find the alternative media session
- // in the media button session app.
- onMediaSessionChangeInMediaButtonSessionApp();
+ // When the media button session is removed, nullify the media button session and do not
+ // search for the alternative media session within the app. It's because the alternative
+ // media session might be a dummy which isn't able to handle the media key events.
+ mOnMediaButtonSessionChangedListener.onMediaButtonSessionChanged(
+ mMediaButtonSession, null);
+ mMediaButtonSession = null;
}
clearCache(record.getUserId());
}
@@ -157,7 +160,13 @@
// In that case, we pick the media session whose PlaybackState matches
// the audio playback configuration.
if (mMediaButtonSession != null && mMediaButtonSession.getUid() == record.getUid()) {
- onMediaSessionChangeInMediaButtonSessionApp();
+ MediaSessionRecord newMediaButtonSession =
+ findMediaButtonSession(mMediaButtonSession.getUid());
+ if (newMediaButtonSession != mMediaButtonSession) {
+ mOnMediaButtonSessionChangedListener.onMediaButtonSessionChanged(
+ mMediaButtonSession, newMediaButtonSession);
+ mMediaButtonSession = newMediaButtonSession;
+ }
}
}
@@ -200,22 +209,6 @@
}
/**
- * Handle the change in a media session in the media button session app.
- * <p>If the app has multiple media sessions, change in a media sesion in the app may change
- * the media button session.
- * @see #findMediaButtonSession
- */
- private void onMediaSessionChangeInMediaButtonSessionApp() {
- MediaSessionRecord newMediaButtonSession =
- findMediaButtonSession(mMediaButtonSession.getUid());
- if (newMediaButtonSession != mMediaButtonSession) {
- mOnMediaButtonSessionChangedListener.onMediaButtonSessionChanged(mMediaButtonSession,
- newMediaButtonSession);
- mMediaButtonSession = newMediaButtonSession;
- }
- }
-
- /**
* Find the media button session with the given {@param uid}.
* If the app has multiple media sessions, the media session matches the audio playback state
* becomes the media button session.
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index e13aeaf..c289204 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -3203,6 +3203,8 @@
return;
} else if (channelId == null && shouldWarnUseChannels(pkg, notificationUid)) {
// STOPSHIP TODO: remove once default channel is removed for all apps that target O.
+ Log.e(TAG, "Developer Warning for package " + pkg
+ + ", no channel specified for posted notification: " + notification);
doDebugOnlyToast("Developer warning for package \"" + pkg + "\"\n" +
"Posted notification should specify a channel");
}
diff --git a/services/core/java/com/android/server/pm/EphemeralResolverConnection.java b/services/core/java/com/android/server/pm/EphemeralResolverConnection.java
index e472928e..21d78ee 100644
--- a/services/core/java/com/android/server/pm/EphemeralResolverConnection.java
+++ b/services/core/java/com/android/server/pm/EphemeralResolverConnection.java
@@ -231,7 +231,7 @@
private final IRemoteCallback mCallback;
public GetEphemeralResolveInfoCaller() {
- super(TimedRemoteCaller.DEFAULT_CALL_TIMEOUT_MILLIS);
+ super(BIND_SERVICE_TIMEOUT_MS);
mCallback = new IRemoteCallback.Stub() {
@Override
public void sendResult(Bundle data) throws RemoteException {
diff --git a/services/core/java/com/android/server/pm/InstantAppRegistry.java b/services/core/java/com/android/server/pm/InstantAppRegistry.java
index 89a303d..fc9e0a3 100644
--- a/services/core/java/com/android/server/pm/InstantAppRegistry.java
+++ b/services/core/java/com/android/server/pm/InstantAppRegistry.java
@@ -35,6 +35,7 @@
import android.provider.Settings;
import android.util.ArrayMap;
import android.util.AtomicFile;
+import android.util.ByteStringUtils;
import android.util.PackageUtils;
import android.util.Slog;
import android.util.SparseArray;
@@ -56,8 +57,10 @@
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
+import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.List;
+import java.util.Locale;
import java.util.Set;
import java.util.function.Predicate;
@@ -81,6 +84,7 @@
private static final String INSTANT_APP_COOKIE_FILE_PREFIX = "cookie_";
private static final String INSTANT_APP_COOKIE_FILE_SIFFIX = ".dat";
private static final String INSTANT_APP_METADATA_FILE = "metadata.xml";
+ private static final String INSTANT_APP_ANDROID_ID_FILE = "android_id";
private static final String TAG_PACKAGE = "package";
private static final String TAG_PERMISSIONS = "permissions";
@@ -142,7 +146,7 @@
@Nullable byte[] cookie, @UserIdInt int userId) {
if (cookie != null && cookie.length > 0) {
final int maxCookieSize = mService.mContext.getPackageManager()
- .getInstantAppCookieMaxSize();
+ .getInstantAppCookieMaxBytes();
if (cookie.length > maxCookieSize) {
Slog.e(LOG_TAG, "Instant app cookie for package " + packageName + " size "
+ cookie.length + " bytes while max size is " + maxCookieSize);
@@ -195,6 +199,36 @@
return null;
}
+ public String getInstantAppAndroidIdLPw(@NonNull String packageName,
+ @UserIdInt int userId) {
+ File idFile = new File(getInstantApplicationDir(packageName, userId),
+ INSTANT_APP_ANDROID_ID_FILE);
+ if (idFile.exists()) {
+ try {
+ return IoUtils.readFileAsString(idFile.getAbsolutePath());
+ } catch (IOException e) {
+ Slog.e(LOG_TAG, "Failed to read instant app android id file: " + idFile, e);
+ }
+ }
+ return generateInstantAppAndroidIdLPw(packageName, userId);
+ }
+
+ private String generateInstantAppAndroidIdLPw(@NonNull String packageName,
+ @UserIdInt int userId) {
+ byte[] randomBytes = new byte[8];
+ new SecureRandom().nextBytes(randomBytes);
+ String id = ByteStringUtils.toHexString(randomBytes).toLowerCase(Locale.US);
+ File idFile = new File(getInstantApplicationDir(packageName, userId),
+ INSTANT_APP_ANDROID_ID_FILE);
+ try (FileOutputStream fos = new FileOutputStream(idFile)) {
+ fos.write(id.getBytes());
+ } catch (IOException e) {
+ Slog.e(LOG_TAG, "Error writing instant app android id file: " + idFile, e);
+ }
+ return id;
+
+ }
+
public @Nullable List<InstantAppInfo> getInstantAppsLPr(@UserIdInt int userId) {
List<InstantAppInfo> installedApps = getInstalledInstantApplicationsLPr(userId);
List<InstantAppInfo> uninstalledApps = getUninstalledInstantApplicationsLPr(userId);
@@ -462,6 +496,7 @@
File instantAppDir = getInstantApplicationDir(packageName, userId);
new File(instantAppDir, INSTANT_APP_METADATA_FILE).delete();
new File(instantAppDir, INSTANT_APP_ICON_FILE).delete();
+ new File(instantAppDir, INSTANT_APP_ANDROID_ID_FILE).delete();
File cookie = peekInstantCookieFile(packageName, userId);
if (cookie != null) {
cookie.delete();
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index 9039647..8413491 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -149,13 +149,14 @@
final boolean profileUpdated = checkForProfileUpdates &&
isProfileUpdated(pkg, sharedGid, compilerFilter);
- // TODO(calin,jeffhao): shared library paths should be adjusted to include previous code
- // paths (b/34169257).
- final String sharedLibrariesPath = getSharedLibrariesPath(sharedLibraries);
+ String sharedLibrariesPath = getSharedLibrariesPath(sharedLibraries);
// Get the dexopt flags after getRealCompilerFilter to make sure we get the correct flags.
final int dexoptFlags = getDexFlags(pkg, compilerFilter);
int result = DEX_OPT_SKIPPED;
+ // TODO: Iterate based on dependency hierarchy (currently alphabetically by name)
+ // (b/37480811).
+ String basePathCheck = null;
for (String path : paths) {
for (String dexCodeIsa : dexCodeInstructionSets) {
int newResult = dexOptPath(pkg, path, dexCodeIsa, compilerFilter, profileUpdated,
@@ -167,6 +168,22 @@
if ((result != DEX_OPT_FAILED) && (newResult != DEX_OPT_SKIPPED)) {
result = newResult;
}
+ // Add the relative path of code we just compiled to the shared libraries.
+ int slashIndex = path.lastIndexOf('/') + 1;
+ String relativePath = path.substring(slashIndex);
+ if (sharedLibrariesPath == null) {
+ sharedLibrariesPath = relativePath;
+ } else {
+ sharedLibrariesPath += ":" + relativePath;
+ }
+ // Sanity check that the base paths are all the same.
+ String basePath = path.substring(0, slashIndex);
+ if (basePathCheck == null) {
+ basePathCheck = basePath;
+ } else if (!basePath.equals(basePathCheck)) {
+ Slog.wtf(TAG, "Split paths have different base paths: " + basePath + " and " +
+ basePathCheck);
+ }
}
}
return result;
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 5535d17..4d026e3d 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -955,6 +955,11 @@
verificationIntent.setComponent(mIntentFilterVerifierComponent);
verificationIntent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+ DeviceIdleController.LocalService idleController = getDeviceIdleController();
+ idleController.addPowerSaveTempWhitelistApp(Process.myUid(),
+ mIntentFilterVerifierComponent.getPackageName(), getVerificationTimeout(),
+ userId, false, "intent filter verifier");
+
UserHandle user = new UserHandle(userId);
mContext.sendBroadcastAsUser(verificationIntent, user);
if (DEBUG_DOMAIN_VERIFICATION) Slog.d(TAG,
@@ -1834,10 +1839,6 @@
extras.putInt(Intent.EXTRA_UID, res.uid);
if (update) {
extras.putBoolean(Intent.EXTRA_REPLACING, true);
- } else {
- sendPackageBroadcast(Intent.ACTION_PACKAGE_FIRST_ADDED, packageName,
- extras, Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND,
- null /*targetPackage*/, null /*finishedReceiver*/, updateUsers);
}
sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
extras, 0 /*flags*/, null /*targetPackage*/,
@@ -2805,8 +2806,12 @@
mRequiredInstallerPackage = getRequiredInstallerLPr();
mRequiredUninstallerPackage = getRequiredUninstallerLPr();
mIntentFilterVerifierComponent = getIntentFilterVerifierComponentNameLPr();
- mIntentFilterVerifier = new IntentVerifierProxy(mContext,
- mIntentFilterVerifierComponent);
+ if (mIntentFilterVerifierComponent != null) {
+ mIntentFilterVerifier = new IntentVerifierProxy(mContext,
+ mIntentFilterVerifierComponent);
+ } else {
+ mIntentFilterVerifier = null;
+ }
mServicesSystemSharedLibraryPackageName = getRequiredSharedLibraryLPr(
PackageManager.SYSTEM_SHARED_LIBRARY_SERVICES,
SharedLibraryInfo.VERSION_UNDEFINED);
@@ -3046,9 +3051,9 @@
if (best != null) {
return best.getComponentInfo().getComponentName();
- } else {
- throw new RuntimeException("There must be at least one intent filter verifier");
}
+ Slog.w(TAG, "Intent filter verifier not found");
+ return null;
}
private @Nullable Pair<ComponentName, String> getInstantAppResolverLPr() {
@@ -13397,10 +13402,8 @@
// Set to UID of the first user, EXTRA_UID is automatically updated in sendPackageBroadcast
extras.putInt(Intent.EXTRA_UID, UserHandle.getUid(userIds[0], appId));
- sendPackageBroadcast(Intent.ACTION_PACKAGE_FIRST_ADDED, packageName,
- extras, Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND, null, null, userIds);
- sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
- extras, 0, null, null, userIds);
+ sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED,
+ packageName, extras, 0, null, null, userIds);
if (isSystem) {
mHandler.post(() -> {
for (int userId : userIds) {
@@ -13977,7 +13980,8 @@
}
/**
- * Get the verification agent timeout.
+ * Get the verification agent timeout. Used for both the APK verifier and the
+ * intent filter verifier.
*
* @return verification timeout in milliseconds
*/
@@ -23654,6 +23658,22 @@
return mInstantAppInstallerActivity == null
? null : mInstantAppInstallerActivity.getComponentName();
}
+
+ @Override
+ public String getInstantAppAndroidId(String packageName, int userId) {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_INSTANT_APPS,
+ "getInstantAppAndroidId");
+ enforceCrossUserPermission(Binder.getCallingUid(), userId,
+ true /* requireFullPermission */, false /* checkShell */,
+ "getInstantAppAndroidId");
+ // Make sure the target is an Instant App.
+ if (!isInstantApp(packageName, userId)) {
+ return null;
+ }
+ synchronized (mPackages) {
+ return mInstantAppRegistry.getInstantAppAndroidIdLPw(packageName, userId);
+ }
+ }
}
interface PackageSender {
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index bcb4121..886fd9a 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -184,7 +184,6 @@
import android.service.dreams.DreamManagerInternal;
import android.service.dreams.DreamService;
import android.service.dreams.IDreamManager;
-import android.service.vr.IPersistentVrStateCallbacks;
import android.speech.RecognizerIntent;
import android.telecom.TelecomManager;
import android.util.DisplayMetrics;
@@ -223,9 +222,8 @@
import android.view.animation.AnimationSet;
import android.view.animation.AnimationUtils;
import android.view.inputmethod.InputMethodManagerInternal;
-import android.widget.ImageView;
+
import com.android.internal.R;
-import com.android.internal.annotations.GuardedBy;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.policy.IKeyguardDismissCallback;
import com.android.internal.policy.IShortcutService;
@@ -497,9 +495,6 @@
WindowState mLastInputMethodWindow = null;
WindowState mLastInputMethodTargetWindow = null;
- @GuardedBy("mLock")
- private boolean mDismissImeOnBackKeyPressed;
-
// FIXME This state is shared between the input reader and handler thread.
// Technically it's broken and buggy but it has been like this for many years
// and we have not yet seen any problems. Someday we'll rewrite this logic
@@ -517,8 +512,7 @@
volatile boolean mGoingToSleep;
volatile boolean mRecentsVisible;
volatile boolean mPictureInPictureVisible;
- // Written by vr manager thread, only read in this class
- volatile boolean mPersistentVrModeEnabled;
+ volatile private boolean mDismissImeOnBackKeyPressed;
// Used to hold the last user key used to wake the device. This helps us prevent up events
// from being passed to the foregrounded app without a corresponding down event
@@ -1008,14 +1002,6 @@
}
MyOrientationListener mOrientationListener;
- final IPersistentVrStateCallbacks mPersistentVrModeListener =
- new IPersistentVrStateCallbacks.Stub() {
- @Override
- public void onPersistentVrStateChanged(boolean enabled) {
- mPersistentVrModeEnabled = enabled;
- }
- };
-
private final StatusBarController mStatusBarController = new StatusBarController();
private final BarController mNavigationBarController = new BarController("NavigationBar",
@@ -1403,13 +1389,7 @@
launchHomeFromHotKey(true /* awakenFromDreams */, false /*respectKeyguard*/);
break;
case SHORT_PRESS_POWER_CLOSE_IME_OR_GO_HOME: {
- final boolean dismissImeOnBackKeyPressed;
- // We can be here on both the main thread (via mHandler) and native callback
- // thread (from interceptPowerKeyUp via WindowManagerCallbacks).
- synchronized (mLock) {
- dismissImeOnBackKeyPressed = mDismissImeOnBackKeyPressed;
- }
- if (dismissImeOnBackKeyPressed) {
+ if (mDismissImeOnBackKeyPressed) {
if (mInputMethodManagerInternal == null) {
mInputMethodManagerInternal =
LocalServices.getService(InputMethodManagerInternal.class);
@@ -1974,36 +1954,24 @@
if (mStatusBar != null) {
requestTransientBars(mStatusBar);
}
- if (mPersistentVrModeEnabled) {
- exitPersistentVrMode();
- }
}
@Override
public void onSwipeFromBottom() {
if (mNavigationBar != null && mNavigationBarPosition == NAV_BAR_BOTTOM) {
requestTransientBars(mNavigationBar);
}
- if (mPersistentVrModeEnabled) {
- exitPersistentVrMode();
- }
}
@Override
public void onSwipeFromRight() {
if (mNavigationBar != null && mNavigationBarPosition == NAV_BAR_RIGHT) {
requestTransientBars(mNavigationBar);
}
- if (mPersistentVrModeEnabled) {
- exitPersistentVrMode();
- }
}
@Override
public void onSwipeFromLeft() {
if (mNavigationBar != null && mNavigationBarPosition == NAV_BAR_LEFT) {
requestTransientBars(mNavigationBar);
}
- if (mPersistentVrModeEnabled) {
- exitPersistentVrMode();
- }
}
@Override
public void onFling(int duration) {
@@ -6627,13 +6595,6 @@
mVrManagerInternal.onScreenStateChanged(isScreenOn);
}
- private void exitPersistentVrMode() {
- if (mVrManagerInternal == null) {
- return;
- }
- mVrManagerInternal.setPersistentVrModeEnabled(false);
- }
-
private void finishWindowsDrawn() {
synchronized (mLock) {
if (!mScreenOnEarly || mWindowManagerDrawComplete) {
@@ -7121,9 +7082,6 @@
mKeyguardDelegate.onSystemReady();
mVrManagerInternal = LocalServices.getService(VrManagerInternal.class);
- if (mVrManagerInternal != null) {
- mVrManagerInternal.addPersistentVrModeStateListener(mPersistentVrModeListener);
- }
readCameraLensCoverState();
updateUiMode();
@@ -7983,9 +7941,7 @@
@Override
public void setDismissImeOnBackKeyPressed(boolean newValue) {
- synchronized (mLock) {
- mDismissImeOnBackKeyPressed = newValue;
- }
+ mDismissImeOnBackKeyPressed = newValue;
}
@Override
diff --git a/services/core/java/com/android/server/updates/LangIdInstallReceiver.java b/services/core/java/com/android/server/updates/LangIdInstallReceiver.java
new file mode 100644
index 0000000..dfe02ec
--- /dev/null
+++ b/services/core/java/com/android/server/updates/LangIdInstallReceiver.java
@@ -0,0 +1,28 @@
+/*
+ * 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 com.android.server.updates;
+
+public class LangIdInstallReceiver extends ConfigUpdateInstallReceiver {
+
+ public LangIdInstallReceiver() {
+ super(
+ "/data/misc/textclassifier/",
+ "textclassifier.langid.model",
+ "metadata/langid",
+ "version");
+ }
+}
diff --git a/services/core/java/com/android/server/updates/SmartSelectionInstallReceiver.java b/services/core/java/com/android/server/updates/SmartSelectionInstallReceiver.java
new file mode 100644
index 0000000..53911c0
--- /dev/null
+++ b/services/core/java/com/android/server/updates/SmartSelectionInstallReceiver.java
@@ -0,0 +1,29 @@
+/*
+ * 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 com.android.server.updates;
+
+public class SmartSelectionInstallReceiver extends ConfigUpdateInstallReceiver {
+
+ public SmartSelectionInstallReceiver() {
+ super(
+ "/data/misc/textclassifier/",
+ "textclassifier.smartselection.model",
+ "metadata/smartselection",
+ "version");
+ }
+}
+
diff --git a/services/core/java/com/android/server/webkit/WebViewUpdateService.java b/services/core/java/com/android/server/webkit/WebViewUpdateService.java
index 3b400b4..d7458f2 100644
--- a/services/core/java/com/android/server/webkit/WebViewUpdateService.java
+++ b/services/core/java/com/android/server/webkit/WebViewUpdateService.java
@@ -92,7 +92,7 @@
(intent.getExtras().getBoolean(Intent.EXTRA_REPLACING)
? PACKAGE_ADDED_REPLACED : PACKAGE_ADDED), userId);
break;
- case Intent.ACTION_USER_ADDED:
+ case Intent.ACTION_USER_STARTED:
mImpl.handleNewUser(userId);
break;
case Intent.ACTION_USER_REMOVED:
@@ -115,7 +115,7 @@
null /* broadcast permission */, null /* handler */);
IntentFilter userAddedFilter = new IntentFilter();
- userAddedFilter.addAction(Intent.ACTION_USER_ADDED);
+ userAddedFilter.addAction(Intent.ACTION_USER_STARTED);
userAddedFilter.addAction(Intent.ACTION_USER_REMOVED);
getContext().registerReceiverAsUser(mWebViewUpdatedReceiver, UserHandle.ALL,
userAddedFilter, null /* broadcast permission */, null /* handler */);
diff --git a/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl.java b/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl.java
index 114c362..fe90ba9 100644
--- a/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl.java
+++ b/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl.java
@@ -26,6 +26,7 @@
import android.webkit.WebViewProviderResponse;
import java.io.PrintWriter;
+import java.lang.Integer;
import java.util.List;
/**
@@ -72,6 +73,9 @@
private WebViewUpdater mWebViewUpdater;
final private Context mContext;
+ private final static int MULTIPROCESS_SETTING_ON_VALUE = Integer.MAX_VALUE;
+ private final static int MULTIPROCESS_SETTING_OFF_VALUE = Integer.MIN_VALUE;
+
public WebViewUpdateServiceImpl(Context context, SystemInterface systemInterface) {
mContext = context;
mSystemInterface = systemInterface;
@@ -112,6 +116,10 @@
}
void handleNewUser(int userId) {
+ // The system user is always started at boot, and by that point we have already run one
+ // round of the package-changing logic (through prepareWebViewInSystemServer()), so early
+ // out here.
+ if (userId == UserHandle.USER_SYSTEM) return;
handleUserChange();
}
@@ -234,31 +242,20 @@
}
boolean isMultiProcessEnabled() {
- PackageInfo current = getCurrentWebViewPackage();
- if (current == null) return false;
- int currentVersion = current.versionCode;
int settingValue = mSystemInterface.getMultiProcessSetting(mContext);
if (mSystemInterface.isMultiProcessDefaultEnabled()) {
- // Multiprocess should be enabled unless the user has turned it off manually for this
- // version or newer, as we want to re-enable it when it's updated to get fresh
- // bug reports.
- return settingValue > -currentVersion;
+ // Multiprocess should be enabled unless the user has turned it off manually.
+ return settingValue > MULTIPROCESS_SETTING_OFF_VALUE;
} else {
- // Multiprocess should not be enabled, unless the user has turned it on manually for
- // any version.
- return settingValue > 0;
+ // Multiprocess should not be enabled, unless the user has turned it on manually.
+ return settingValue >= MULTIPROCESS_SETTING_ON_VALUE;
}
}
void enableMultiProcess(boolean enable) {
- // The value we store for the setting is the version code of the current package, if it's
- // enabled, or the negation of the version code of the current package, if it's disabled.
- // Users who have a setting from before this scheme was implemented will have it set to 0 or
- // 1 instead.
PackageInfo current = getCurrentWebViewPackage();
- int currentVersion = current != null ? current.versionCode : 1;
mSystemInterface.setMultiProcessSetting(mContext,
- enable ? currentVersion : -currentVersion);
+ enable ? MULTIPROCESS_SETTING_ON_VALUE : MULTIPROCESS_SETTING_OFF_VALUE);
mSystemInterface.notifyZygote(enable);
if (current != null) {
mSystemInterface.killPackageDependents(current.packageName);
diff --git a/services/core/java/com/android/server/webkit/WebViewUpdateServiceShellCommand.java b/services/core/java/com/android/server/webkit/WebViewUpdateServiceShellCommand.java
index 68448f3..39e28c7 100644
--- a/services/core/java/com/android/server/webkit/WebViewUpdateServiceShellCommand.java
+++ b/services/core/java/com/android/server/webkit/WebViewUpdateServiceShellCommand.java
@@ -43,6 +43,10 @@
return enableFallbackLogic(true);
case "set-webview-implementation":
return setWebViewImplementation();
+ case "enable-multiprocess":
+ return enableMultiProcess(true);
+ case "disable-multiprocess":
+ return enableMultiProcess(false);
default:
return handleDefaultCommands(cmd);
}
@@ -74,6 +78,13 @@
}
}
+ private int enableMultiProcess(boolean enable) throws RemoteException {
+ final PrintWriter pw = getOutPrintWriter();
+ mInterface.enableMultiProcess(enable);
+ pw.println("Success");
+ return 0;
+ }
+
@Override
public void onHelp() {
PrintWriter pw = getOutPrintWriter();
@@ -90,6 +101,10 @@
pw.println(" package is available.");
pw.println(" set-webview-implementation PACKAGE");
pw.println(" Set the WebView implementation to the specified package.");
+ pw.println(" enable-multiprocess");
+ pw.println(" Enable multi-process mode for WebView");
+ pw.println(" disable-multiprocess");
+ pw.println(" Disable multi-process mode for WebView");
pw.println();
}
}
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index 1fb34eb..7634644 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -1280,6 +1280,11 @@
// WindowStateAnimator#commitFinishDrawingLocked() will call performShowLocked().
dc.setLayoutNeeded();
mService.mH.obtainMessage(NOTIFY_ACTIVITY_DRAWN, token).sendToTarget();
+
+ final TaskStack s = getStack();
+ if (s != null) {
+ s.onAllWindowsDrawn();
+ }
}
}
diff --git a/services/core/java/com/android/server/wm/BoundsAnimationController.java b/services/core/java/com/android/server/wm/BoundsAnimationController.java
index e634552..7f3c89c 100644
--- a/services/core/java/com/android/server/wm/BoundsAnimationController.java
+++ b/services/core/java/com/android/server/wm/BoundsAnimationController.java
@@ -112,6 +112,8 @@
private final Interpolator mFastOutSlowInInterpolator;
private boolean mFinishAnimationAfterTransition = false;
+ private static final int WAIT_FOR_DRAW_TIMEOUT_MS = 3000;
+
BoundsAnimationController(Context context, AppTransition transition, Handler handler) {
mHandler = handler;
mAppTransition = transition;
@@ -175,6 +177,13 @@
}
}
+ final Runnable mResumeRunnable = new Runnable() {
+ @Override
+ public void run() {
+ resume();
+ }
+ };
+
@Override
public void onAnimationStart(Animator animation) {
if (DEBUG) Slog.d(TAG, "onAnimationStart: mTarget=" + mTarget
@@ -196,10 +205,26 @@
// the starting position so we don't jump at the beginning of the animation.
if (animatingToLargerSize()) {
mTarget.setPinnedStackSize(mFrom, mTmpRect);
+
+ // We pause the animation until the app has drawn at the new size.
+ // The target will notify us via BoundsAnimationController#resume.
+ // We do this here and pause the animation, rather than just defer starting it
+ // so we can enter the animating state and have WindowStateAnimator apply the
+ // correct logic to make this resize seamless.
+ if (mMoveToFullscreen) {
+ pause();
+ mHandler.postDelayed(mResumeRunnable, WAIT_FOR_DRAW_TIMEOUT_MS);
+ }
}
}
@Override
+ public void resume() {
+ mHandler.removeCallbacks(mResumeRunnable);
+ super.resume();
+ }
+
+ @Override
public void onAnimationUpdate(ValueAnimator animation) {
final float value = (Float) animation.getAnimatedValue();
final float remains = 1 - value;
@@ -371,4 +396,15 @@
animator.start();
return animator;
}
+
+ private void resume() {
+ for (int i = 0; i < mRunningAnimations.size(); i++) {
+ final BoundsAnimator b = mRunningAnimations.valueAt(i);
+ b.resume();
+ }
+ }
+
+ public void onAllWindowsDrawn() {
+ mHandler.post(this::resume);
+ }
}
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index d141f7c..1feb743 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -52,6 +52,7 @@
import com.android.internal.policy.DividerSnapAlgorithm.SnapTarget;
import com.android.internal.policy.DockedDividerUtils;
import com.android.server.EventLogTags;
+import com.android.server.UiThread;
import java.io.PrintWriter;
@@ -1475,6 +1476,14 @@
return true;
}
+ void onAllWindowsDrawn() {
+ if (!mBoundsAnimating) {
+ return;
+ }
+
+ mService.mBoundsAnimationController.onAllWindowsDrawn();
+ }
+
@Override // AnimatesBounds
public void onAnimationStart(boolean schedulePipModeChangedCallback) {
// Hold the lock since this is called from the BoundsAnimator running on the UiThread
@@ -1482,6 +1491,13 @@
mBoundsAnimatingRequested = false;
mBoundsAnimating = true;
mCancelCurrentBoundsAnimation = false;
+
+ // If we are changing UI mode, as in the PiP to fullscreen
+ // transition, then we need to wait for the window to draw.
+ if (schedulePipModeChangedCallback) {
+ forAllWindows((w) -> { w.mWinAnimator.resetDrawState(); },
+ false /* traverseTopToBottom */);
+ }
}
if (mStackId == PINNED_STACK_ID) {
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 9555c8d..b9776a3 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -4329,7 +4329,9 @@
int relayoutVisibleWindow(MergedConfiguration mergedConfiguration, int result, int attrChanges,
int oldVisibility) {
- result |= !isVisibleLw() ? RELAYOUT_RES_FIRST_TIME : 0;
+ final boolean wasVisible = isVisibleLw();
+
+ result |= (!wasVisible || !isDrawnLw()) ? RELAYOUT_RES_FIRST_TIME : 0;
if (mAnimatingExit) {
Slog.d(TAG, "relayoutVisibleWindow: " + this + " mAnimatingExit=true, mRemoveOnExit="
+ mRemoveOnExit + ", mDestroying=" + mDestroying);
@@ -4348,7 +4350,7 @@
mLastVisibleLayoutRotation = getDisplayContent().getRotation();
mWinAnimator.mEnteringAnimation = true;
- if ((result & RELAYOUT_RES_FIRST_TIME) != 0) {
+ if (!wasVisible) {
prepareWindowToDisplayDuringRelayout(mergedConfiguration);
}
if ((attrChanges & FORMAT_CHANGED) != 0) {
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index a2889b1..b945cf1 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -602,6 +602,22 @@
}
}
+ void resetDrawState() {
+ mDrawState = DRAW_PENDING;
+
+ if (mWin.mAppToken == null) {
+ return;
+ }
+
+ if (mWin.mAppToken.mAppAnimator.animation == null) {
+ mWin.mAppToken.clearAllDrawn();
+ } else {
+ // Currently animating, persist current state of allDrawn until animation
+ // is complete.
+ mWin.mAppToken.deferClearAllDrawn = true;
+ }
+ }
+
WindowSurfaceController createSurfaceLocked(int windowType, int ownerUid) {
final WindowState w = mWin;
if (w.restoreSavedSurface()) {
@@ -619,16 +635,7 @@
if (DEBUG_ANIM || DEBUG_ORIENTATION) Slog.i(TAG,
"createSurface " + this + ": mDrawState=DRAW_PENDING");
- mDrawState = DRAW_PENDING;
- if (w.mAppToken != null) {
- if (w.mAppToken.mAppAnimator.animation == null) {
- w.mAppToken.clearAllDrawn();
- } else {
- // Currently animating, persist current state of allDrawn until animation
- // is complete.
- w.mAppToken.deferClearAllDrawn = true;
- }
- }
+ resetDrawState();
mService.makeWindowFreezingScreenIfNeededLocked(w);
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 42a9232..978803d 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -159,7 +159,7 @@
private static final String PRINT_MANAGER_SERVICE_CLASS =
"com.android.server.print.PrintManagerService";
private static final String COMPANION_DEVICE_MANAGER_SERVICE_CLASS =
- "com.android.server.print.CompanionDeviceManagerService";
+ "com.android.server.companion.CompanionDeviceManagerService";
private static final String USB_SERVICE_CLASS =
"com.android.server.usb.UsbService$Lifecycle";
private static final String MIDI_SERVICE_CLASS =
diff --git a/services/tests/servicestests/src/com/android/server/SyntheticPasswordTests.java b/services/tests/servicestests/src/com/android/server/SyntheticPasswordTests.java
index 6e5ade1..3ec71e4 100644
--- a/services/tests/servicestests/src/com/android/server/SyntheticPasswordTests.java
+++ b/services/tests/servicestests/src/com/android/server/SyntheticPasswordTests.java
@@ -320,6 +320,26 @@
assertTrue(hasSyntheticPassword(PRIMARY_USER_ID));
}
+ public void testEscrowTokenActivatedLaterWithUserPasswordNeedsMigration() throws RemoteException {
+ final String TOKEN = "some-high-entropy-secure-token";
+ final String PASSWORD = "password";
+ // Set up pre-SP user password
+ disableSyntheticPassword(PRIMARY_USER_ID);
+ mService.setLockCredential(PASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
+ PRIMARY_USER_ID);
+ enableSyntheticPassword(PRIMARY_USER_ID);
+
+ long handle = mService.addEscrowToken(TOKEN.getBytes(), PRIMARY_USER_ID);
+ // Token not activated immediately since user password exists
+ assertFalse(mService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
+ // Activate token (password gets migrated to SP at the same time)
+ assertEquals(VerifyCredentialResponse.RESPONSE_OK,
+ mService.verifyCredential(PASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0,
+ PRIMARY_USER_ID).getResponseCode());
+ // Verify token is activated
+ assertTrue(mService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
+ }
+
// b/34600579
//TODO: add non-migration work profile case, and unify/un-unify transition.
//TODO: test token after user resets password
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java
index f42abf1..58166b6 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java
@@ -16,8 +16,10 @@
package com.android.server.am;
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
import android.content.ComponentName;
import android.platform.test.annotations.Presubmit;
@@ -50,6 +52,7 @@
"testEmptyTaskCleanupOnRemove", ActivityStack.REMOVE_TASK_MODE_DESTROYING);
assertNull(task.getWindowContainerController());
}
+
@Test
public void testOccupiedTaskCleanupOnRemove() throws Exception {
final ActivityManagerService service = createActivityManagerService();
@@ -60,4 +63,25 @@
"testOccupiedTaskCleanupOnRemove", ActivityStack.REMOVE_TASK_MODE_DESTROYING);
assertNotNull(task.getWindowContainerController());
}
+
+ @Test
+ public void testNoPauseDuringResumeTopActivity() throws Exception {
+ final ActivityManagerService service = createActivityManagerService();
+ final TaskRecord task = createTask(service, testActivityComponent, TEST_STACK_ID);
+ final ActivityRecord activityRecord = createActivity(service, testActivityComponent, task);
+ final ActivityStack testStack = service.mStackSupervisor.getStack(TEST_STACK_ID);
+
+ // Simulate the a resumed activity set during
+ // {@link ActivityStack#resumeTopActivityUncheckedLocked}.
+ service.mStackSupervisor.inResumeTopActivity = true;
+ testStack.mResumedActivity = activityRecord;
+
+ final boolean waiting = testStack.checkReadyForSleepLocked();
+
+ // Ensure we report not being ready for sleep.
+ assertTrue(waiting);
+
+ // Make sure the resumed activity is untouched.
+ assertEquals(testStack.mResumedActivity, activityRecord);
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/webkit/WebViewUpdateServiceTest.java b/services/tests/servicestests/src/com/android/server/webkit/WebViewUpdateServiceTest.java
index 9c8007a..05c4853 100644
--- a/services/tests/servicestests/src/com/android/server/webkit/WebViewUpdateServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/webkit/WebViewUpdateServiceTest.java
@@ -42,6 +42,7 @@
import org.mockito.Matchers;
import org.mockito.compat.ArgumentMatcher;
+import java.lang.Integer;
import java.util.concurrent.CountDownLatch;
@@ -1530,49 +1531,22 @@
@Test
public void testMultiProcessEnabledByDefault() {
- String primaryPackage = "primary";
- WebViewProviderInfo[] packages = new WebViewProviderInfo[] {
- new WebViewProviderInfo(
- primaryPackage, "", true /* default available */, false /* fallback */, null)};
- setupWithPackages(packages, true /* fallback logic enabled */, 1 /* numRelros */,
- true /* debuggable */, true /* multiprocess by default */);
- mTestSystemImpl.setPackageInfo(createPackageInfo(primaryPackage, true /* enabled */,
- true /* valid */, true /* installed */, null /* signatures */,
- 10 /* lastUpdateTime*/, false /* not hidden */, 1000 /* versionCode */,
- false /* isSystemApp */));
-
- runWebViewBootPreparationOnMainSync();
- checkPreparationPhasesForPackage(primaryPackage, 1 /* first preparation phase */);
-
- // Check it's on by default
- assertTrue(mWebViewUpdateServiceImpl.isMultiProcessEnabled());
-
- // Test toggling it
- mWebViewUpdateServiceImpl.enableMultiProcess(false);
- assertFalse(mWebViewUpdateServiceImpl.isMultiProcessEnabled());
- mWebViewUpdateServiceImpl.enableMultiProcess(true);
- assertTrue(mWebViewUpdateServiceImpl.isMultiProcessEnabled());
-
- // Disable, then upgrade provider, which should re-enable it
- mWebViewUpdateServiceImpl.enableMultiProcess(false);
- mTestSystemImpl.setPackageInfo(createPackageInfo(primaryPackage, true /* enabled */,
- true /* valid */, true /* installed */, null /* signatures */,
- 20 /* lastUpdateTime*/, false /* not hidden */, 2000 /* versionCode */,
- false /* isSystemApp */));
- mWebViewUpdateServiceImpl.packageStateChanged(primaryPackage,
- WebViewUpdateService.PACKAGE_ADDED_REPLACED, 0);
- checkPreparationPhasesForPackage(primaryPackage, 2);
- assertTrue(mWebViewUpdateServiceImpl.isMultiProcessEnabled());
+ testMultiProcessByDefault(true /* enabledByDefault */);
}
@Test
public void testMultiProcessDisabledByDefault() {
+ testMultiProcessByDefault(false /* enabledByDefault */);
+ }
+
+ private void testMultiProcessByDefault(boolean enabledByDefault) {
String primaryPackage = "primary";
WebViewProviderInfo[] packages = new WebViewProviderInfo[] {
new WebViewProviderInfo(
primaryPackage, "", true /* default available */, false /* fallback */, null)};
setupWithPackages(packages, true /* fallback logic enabled */, 1 /* numRelros */,
- true /* debuggable */, false /* not multiprocess by default */);
+ true /* debuggable */,
+ enabledByDefault /* not multiprocess by default */);
mTestSystemImpl.setPackageInfo(createPackageInfo(primaryPackage, true /* enabled */,
true /* valid */, true /* installed */, null /* signatures */,
10 /* lastUpdateTime*/, false /* not hidden */, 1000 /* versionCode */,
@@ -1582,37 +1556,67 @@
checkPreparationPhasesForPackage(primaryPackage, 1 /* first preparation phase */);
// Check it's off by default
- assertFalse(mWebViewUpdateServiceImpl.isMultiProcessEnabled());
+ assertEquals(enabledByDefault, mWebViewUpdateServiceImpl.isMultiProcessEnabled());
// Test toggling it
- mWebViewUpdateServiceImpl.enableMultiProcess(true);
- assertTrue(mWebViewUpdateServiceImpl.isMultiProcessEnabled());
- mWebViewUpdateServiceImpl.enableMultiProcess(false);
- assertFalse(mWebViewUpdateServiceImpl.isMultiProcessEnabled());
-
- // Disable, then upgrade provider, which should not re-enable it
- mWebViewUpdateServiceImpl.enableMultiProcess(false);
- mTestSystemImpl.setPackageInfo(createPackageInfo(primaryPackage, true /* enabled */,
- true /* valid */, true /* installed */, null /* signatures */,
- 20 /* lastUpdateTime*/, false /* not hidden */, 2000 /* versionCode */,
- false /* isSystemApp */));
- mWebViewUpdateServiceImpl.packageStateChanged(primaryPackage,
- WebViewUpdateService.PACKAGE_ADDED_REPLACED, 0);
- checkPreparationPhasesForPackage(primaryPackage, 2);
- assertFalse(mWebViewUpdateServiceImpl.isMultiProcessEnabled());
-
- // Enable, then upgrade provider, which should leave it on
- mWebViewUpdateServiceImpl.enableMultiProcess(true);
- mTestSystemImpl.setPackageInfo(createPackageInfo(primaryPackage, true /* enabled */,
- true /* valid */, true /* installed */, null /* signatures */,
- 30 /* lastUpdateTime*/, false /* not hidden */, 3000 /* versionCode */,
- false /* isSystemApp */));
- mWebViewUpdateServiceImpl.packageStateChanged(primaryPackage,
- WebViewUpdateService.PACKAGE_ADDED_REPLACED, 0);
- checkPreparationPhasesForPackage(primaryPackage, 3);
- assertTrue(mWebViewUpdateServiceImpl.isMultiProcessEnabled());
+ mWebViewUpdateServiceImpl.enableMultiProcess(!enabledByDefault);
+ assertEquals(!enabledByDefault, mWebViewUpdateServiceImpl.isMultiProcessEnabled());
+ mWebViewUpdateServiceImpl.enableMultiProcess(enabledByDefault);
+ assertEquals(enabledByDefault, mWebViewUpdateServiceImpl.isMultiProcessEnabled());
}
+ @Test
+ public void testMultiProcessEnabledByDefaultWithSettingsValue() {
+ testMultiProcessByDefaultWithSettingsValue(
+ true /* enabledByDefault */, Integer.MIN_VALUE, false /* expectEnabled */);
+ testMultiProcessByDefaultWithSettingsValue(
+ true /* enabledByDefault */, -999999, true /* expectEnabled */);
+ testMultiProcessByDefaultWithSettingsValue(
+ true /* enabledByDefault */, 0, true /* expectEnabled */);
+ testMultiProcessByDefaultWithSettingsValue(
+ true /* enabledByDefault */, 999999, true /* expectEnabled */);
+ }
+
+ @Test
+ public void testMultiProcessDisabledByDefaultWithSettingsValue() {
+ testMultiProcessByDefaultWithSettingsValue(
+ false /* enabledByDefault */, Integer.MIN_VALUE, false /* expectEnabled */);
+ testMultiProcessByDefaultWithSettingsValue(
+ false /* enabledByDefault */, 0, false /* expectEnabled */);
+ testMultiProcessByDefaultWithSettingsValue(
+ false /* enabledByDefault */, 999999, false /* expectEnabled */);
+ testMultiProcessByDefaultWithSettingsValue(
+ false /* enabledByDefault */, Integer.MAX_VALUE, true /* expectEnabled */);
+ }
+
+ /**
+ * Test the logic of the multiprocess setting depending on whether multiprocess is enabled by
+ * default, and what the setting is set to.
+ * @param enabledByDefault whether multiprocess is enabled by default.
+ * @param settingValue value of the multiprocess setting.
+ */
+ private void testMultiProcessByDefaultWithSettingsValue(
+ boolean enabledByDefault, int settingValue, boolean expectEnabled) {
+ String primaryPackage = "primary";
+ WebViewProviderInfo[] packages = new WebViewProviderInfo[] {
+ new WebViewProviderInfo(
+ primaryPackage, "", true /* default available */, false /* fallback */, null)};
+ setupWithPackages(packages, true /* fallback logic enabled */, 1 /* numRelros */,
+ true /* debuggable */, enabledByDefault /* multiprocess by default */);
+ mTestSystemImpl.setPackageInfo(createPackageInfo(primaryPackage, true /* enabled */,
+ true /* valid */, true /* installed */, null /* signatures */,
+ 10 /* lastUpdateTime*/, false /* not hidden */, 1000 /* versionCode */,
+ false /* isSystemApp */));
+
+ runWebViewBootPreparationOnMainSync();
+ checkPreparationPhasesForPackage(primaryPackage, 1 /* first preparation phase */);
+
+ mTestSystemImpl.setMultiProcessSetting(null /* context */, settingValue);
+
+ assertEquals(expectEnabled, mWebViewUpdateServiceImpl.isMultiProcessEnabled());
+ }
+
+
/**
* Ensure that packages with a targetSdkVersion targeting the current platform are valid, and
* that packages targeting an older version are not valid.
diff --git a/services/tests/servicestests/src/com/android/server/wm/BoundsAnimationControllerTests.java b/services/tests/servicestests/src/com/android/server/wm/BoundsAnimationControllerTests.java
index 7f150a2..cd7a7c7 100644
--- a/services/tests/servicestests/src/com/android/server/wm/BoundsAnimationControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/BoundsAnimationControllerTests.java
@@ -152,6 +152,8 @@
mAwaitingAnimationStart = false;
mAnimationStarted = true;
mSchedulePipModeChangedOnStart = schedulePipModeChangedCallback;
+
+ mController.onAllWindowsDrawn();
}
@Override
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index 80b73d3..31595a6 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -857,13 +857,16 @@
break;
case MSG_UPDATE_HOST_STATE:
SomeArgs args = (SomeArgs) msg.obj;
+ boolean prevHostConnected = mHostConnected;
mHostConnected = (args.argi1 == 1);
mSourcePower = (args.argi2 == 1);
mSinkPower = (args.argi3 == 1);
args.recycle();
updateUsbNotification();
if (mBootCompleted) {
- updateUsbStateBroadcastIfNeeded(false);
+ if (mHostConnected || prevHostConnected) {
+ updateUsbStateBroadcastIfNeeded(false);
+ }
} else {
mPendingBootBroadcast = true;
}
diff --git a/telephony/java/android/telephony/Telephony.java b/telephony/java/android/telephony/Telephony.java
index eeaf2c1..3282f5f 100644
--- a/telephony/java/android/telephony/Telephony.java
+++ b/telephony/java/android/telephony/Telephony.java
@@ -3008,12 +3008,12 @@
* Note, however, that using a {@link JobService} does not guarantee timely delivery of
* updates to the {@link Uri}.
*
- * @param subId the subId to receive updates on
+ * @param subscriptionId the subscriptionId to receive updates on
* @param field the ServiceState field to receive updates on
* @return the Uri used to observe {@link ServiceState} changes
*/
- public static Uri getUriForSubIdAndField(int subId, String field) {
- return CONTENT_URI.buildUpon().appendEncodedPath(String.valueOf(subId))
+ public static Uri getUriForSubscriptionIdAndField(int subscriptionId, String field) {
+ return CONTENT_URI.buildUpon().appendEncodedPath(String.valueOf(subscriptionId))
.appendEncodedPath(field).build();
}
@@ -3027,11 +3027,11 @@
* Note, however, that using a {@link JobService} does not guarantee timely delivery of
* updates to the {@link Uri}.
*
- * @param subId the subId to receive updates on
+ * @param subscriptionId the subscriptionId to receive updates on
* @return the Uri used to observe {@link ServiceState} changes
*/
- public static Uri getUriForSubId(int subId) {
- return CONTENT_URI.buildUpon().appendEncodedPath(String.valueOf(subId)).build();
+ public static Uri getUriForSubscriptionId(int subscriptionId) {
+ return CONTENT_URI.buildUpon().appendEncodedPath(String.valueOf(subscriptionId)).build();
}
/**
diff --git a/test-runner/src/android/test/mock/MockContext.java b/test-runner/src/android/test/mock/MockContext.java
index b4e3a47..bfc2d72 100644
--- a/test-runner/src/android/test/mock/MockContext.java
+++ b/test-runner/src/android/test/mock/MockContext.java
@@ -492,7 +492,7 @@
@Override
public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,
- boolean visibleToInstantApps) {
+ int flags) {
throw new UnsupportedOperationException();
}
@@ -504,7 +504,7 @@
@Override
public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,
- String broadcastPermission, Handler scheduler, boolean visibleToInstantApps) {
+ String broadcastPermission, Handler scheduler, int flags) {
throw new UnsupportedOperationException();
}
diff --git a/test-runner/src/android/test/mock/MockPackageManager.java b/test-runner/src/android/test/mock/MockPackageManager.java
index 20392e7..2d3d79a 100644
--- a/test-runner/src/android/test/mock/MockPackageManager.java
+++ b/test-runner/src/android/test/mock/MockPackageManager.java
@@ -371,12 +371,30 @@
/** @hide */
@Override
+ public int getInstantAppCookieMaxBytes() {
+ throw new UnsupportedOperationException();
+ }
+
+ /** @hide */
+ @Override
public int getInstantAppCookieMaxSize() {
throw new UnsupportedOperationException();
}
/** @hide */
@Override
+ public void clearInstantAppCookie() {
+ throw new UnsupportedOperationException();
+ }
+
+ /** @hide */
+ @Override
+ public void updateInstantAppCookie(@NonNull byte[] cookie) {
+ throw new UnsupportedOperationException();
+ }
+
+ /** @hide */
+ @Override
public boolean setInstantAppCookie(@NonNull byte[] cookie) {
throw new UnsupportedOperationException();
}
@@ -1134,4 +1152,11 @@
public ComponentName getInstantAppInstallerComponent() {
throw new UnsupportedOperationException();
}
+
+ /**
+ * @hide
+ */
+ public String getInstantAppAndroidId(String packageName, UserHandle user) {
+ throw new UnsupportedOperationException();
+ }
}
diff --git a/tests/net/java/android/net/NetworkCapabilitiesTest.java b/tests/net/java/android/net/NetworkCapabilitiesTest.java
new file mode 100644
index 0000000..e3b06c8
--- /dev/null
+++ b/tests/net/java/android/net/NetworkCapabilitiesTest.java
@@ -0,0 +1,117 @@
+/*
+ * 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.net;
+
+import static android.net.NetworkCapabilities.NET_CAPABILITY_CBS;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_EIMS;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
+import static android.net.NetworkCapabilities.RESTRICTED_CAPABILITIES;
+import static android.net.NetworkCapabilities.UNRESTRICTED_CAPABILITIES;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+
+import android.net.NetworkCapabilities;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class NetworkCapabilitiesTest {
+ @Test
+ public void testMaybeMarkCapabilitiesRestricted() {
+ // verify EIMS is restricted
+ assertEquals((1 << NET_CAPABILITY_EIMS) & RESTRICTED_CAPABILITIES,
+ (1 << NET_CAPABILITY_EIMS));
+
+ // verify CBS is also restricted
+ assertEquals((1 << NET_CAPABILITY_CBS) & RESTRICTED_CAPABILITIES,
+ (1 << NET_CAPABILITY_CBS));
+
+ // verify default is not restricted
+ assertEquals((1 << NET_CAPABILITY_INTERNET) & RESTRICTED_CAPABILITIES, 0);
+
+ // just to see
+ assertEquals(RESTRICTED_CAPABILITIES & UNRESTRICTED_CAPABILITIES, 0);
+
+ // check that internet does not get restricted
+ NetworkCapabilities netCap = new NetworkCapabilities();
+ netCap.addCapability(NET_CAPABILITY_INTERNET);
+ netCap.maybeMarkCapabilitiesRestricted();
+ assertTrue(netCap.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
+
+ // metered-ness shouldn't matter
+ netCap = new NetworkCapabilities();
+ netCap.addCapability(NET_CAPABILITY_INTERNET);
+ netCap.addCapability(NET_CAPABILITY_NOT_METERED);
+ netCap.maybeMarkCapabilitiesRestricted();
+ assertTrue(netCap.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
+ netCap = new NetworkCapabilities();
+ netCap.addCapability(NET_CAPABILITY_INTERNET);
+ netCap.removeCapability(NET_CAPABILITY_NOT_METERED);
+ netCap.maybeMarkCapabilitiesRestricted();
+ assertTrue(netCap.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
+
+ // add EIMS - bundled with unrestricted means it's unrestricted
+ netCap = new NetworkCapabilities();
+ netCap.addCapability(NET_CAPABILITY_INTERNET);
+ netCap.addCapability(NET_CAPABILITY_EIMS);
+ netCap.addCapability(NET_CAPABILITY_NOT_METERED);
+ netCap.maybeMarkCapabilitiesRestricted();
+ assertTrue(netCap.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
+ netCap = new NetworkCapabilities();
+ netCap.addCapability(NET_CAPABILITY_INTERNET);
+ netCap.addCapability(NET_CAPABILITY_EIMS);
+ netCap.removeCapability(NET_CAPABILITY_NOT_METERED);
+ netCap.maybeMarkCapabilitiesRestricted();
+ assertTrue(netCap.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
+
+ // just a restricted cap should be restricted regardless of meteredness
+ netCap = new NetworkCapabilities();
+ netCap.addCapability(NET_CAPABILITY_EIMS);
+ netCap.addCapability(NET_CAPABILITY_NOT_METERED);
+ netCap.maybeMarkCapabilitiesRestricted();
+ assertFalse(netCap.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
+ netCap = new NetworkCapabilities();
+ netCap.addCapability(NET_CAPABILITY_EIMS);
+ netCap.removeCapability(NET_CAPABILITY_NOT_METERED);
+ netCap.maybeMarkCapabilitiesRestricted();
+ assertFalse(netCap.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
+
+ // try 2 restricted caps
+ netCap = new NetworkCapabilities();
+ netCap.addCapability(NET_CAPABILITY_CBS);
+ netCap.addCapability(NET_CAPABILITY_EIMS);
+ netCap.addCapability(NET_CAPABILITY_NOT_METERED);
+ netCap.maybeMarkCapabilitiesRestricted();
+ assertFalse(netCap.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
+ netCap = new NetworkCapabilities();
+ netCap.addCapability(NET_CAPABILITY_CBS);
+ netCap.addCapability(NET_CAPABILITY_EIMS);
+ netCap.removeCapability(NET_CAPABILITY_NOT_METERED);
+ netCap.maybeMarkCapabilitiesRestricted();
+ assertFalse(netCap.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
+ }
+
+}
diff --git a/tools/aapt/Resource.cpp b/tools/aapt/Resource.cpp
index 2bf5206..bd2b2a36 100644
--- a/tools/aapt/Resource.cpp
+++ b/tools/aapt/Resource.cpp
@@ -782,7 +782,79 @@
}
}
-status_t massageManifest(Bundle* bundle, sp<XMLNode> root)
+static sp<ResourceTable::ConfigList> findEntry(const String16& packageStr, const String16& typeStr,
+ const String16& nameStr, ResourceTable* table) {
+ sp<ResourceTable::Package> pkg = table->getPackage(packageStr);
+ if (pkg != NULL) {
+ sp<ResourceTable::Type> type = pkg->getTypes().valueFor(typeStr);
+ if (type != NULL) {
+ return type->getConfigs().valueFor(nameStr);
+ }
+ }
+ return NULL;
+}
+
+static uint16_t getMaxSdkVersion(const sp<ResourceTable::ConfigList>& configList) {
+ const DefaultKeyedVector<ConfigDescription, sp<ResourceTable::Entry>>& entries =
+ configList->getEntries();
+ uint16_t maxSdkVersion = 0u;
+ for (size_t i = 0; i < entries.size(); i++) {
+ maxSdkVersion = std::max(maxSdkVersion, entries.keyAt(i).sdkVersion);
+ }
+ return maxSdkVersion;
+}
+
+static void massageRoundIconSupport(const String16& iconRef, const String16& roundIconRef,
+ ResourceTable* table) {
+ bool publicOnly = false;
+ const char* err;
+
+ String16 iconPackage, iconType, iconName;
+ if (!ResTable::expandResourceRef(iconRef.string(), iconRef.size(), &iconPackage, &iconType,
+ &iconName, NULL, &table->getAssetsPackage(), &err,
+ &publicOnly)) {
+ // Errors will be raised in later XML compilation.
+ return;
+ }
+
+ sp<ResourceTable::ConfigList> iconEntry = findEntry(iconPackage, iconType, iconName, table);
+ if (iconEntry == NULL || getMaxSdkVersion(iconEntry) < SDK_O) {
+ // The icon is not adaptive, so nothing to massage.
+ return;
+ }
+
+ String16 roundIconPackage, roundIconType, roundIconName;
+ if (!ResTable::expandResourceRef(roundIconRef.string(), roundIconRef.size(), &roundIconPackage,
+ &roundIconType, &roundIconName, NULL, &table->getAssetsPackage(),
+ &err, &publicOnly)) {
+ // Errors will be raised in later XML compilation.
+ return;
+ }
+
+ sp<ResourceTable::ConfigList> roundIconEntry = findEntry(roundIconPackage, roundIconType,
+ roundIconName, table);
+ if (roundIconEntry == NULL || getMaxSdkVersion(roundIconEntry) >= SDK_O) {
+ // The developer explicitly used a v26 compatible drawable as the roundIcon, meaning we should
+ // not generate an alias to the icon drawable.
+ return;
+ }
+
+ String16 aliasValue = String16(String8::format("@%s:%s/%s", String8(iconPackage).string(),
+ String8(iconType).string(),
+ String8(iconName).string()));
+
+ // Add an equivalent v26 entry to the roundIcon for each v26 variant of the regular icon.
+ const DefaultKeyedVector<ConfigDescription, sp<ResourceTable::Entry>>& configList =
+ iconEntry->getEntries();
+ for (size_t i = 0; i < configList.size(); i++) {
+ if (configList.keyAt(i).sdkVersion >= SDK_O) {
+ table->addEntry(SourcePos(), roundIconPackage, roundIconType, roundIconName, aliasValue,
+ NULL, &configList.keyAt(i));
+ }
+ }
+}
+
+status_t massageManifest(Bundle* bundle, ResourceTable* table, sp<XMLNode> root)
{
root = root->searchElement(String16(), String16("manifest"));
if (root == NULL) {
@@ -916,7 +988,7 @@
String8 tag(child->getElementName());
if (tag == "instrumentation") {
XMLNode::attribute_entry* attr = child->editAttribute(
- String16("http://schemas.android.com/apk/res/android"), String16("targetPackage"));
+ String16(RESOURCES_ANDROID_NAMESPACE), String16("targetPackage"));
if (attr != NULL) {
attr->string.setTo(String16(instrumentationPackageNameOverride));
}
@@ -924,6 +996,19 @@
}
}
+ sp<XMLNode> application = root->getChildElement(String16(), String16("application"));
+ if (application != NULL) {
+ XMLNode::attribute_entry* icon_attr = application->editAttribute(
+ String16(RESOURCES_ANDROID_NAMESPACE), String16("icon"));
+ if (icon_attr != NULL) {
+ XMLNode::attribute_entry* round_icon_attr = application->editAttribute(
+ String16(RESOURCES_ANDROID_NAMESPACE), String16("roundIcon"));
+ if (round_icon_attr != NULL) {
+ massageRoundIconSupport(icon_attr->string, round_icon_attr->string, table);
+ }
+ }
+ }
+
// Generate split name if feature is present.
const XMLNode::attribute_entry* attr = root->getAttribute(String16(), String16("featureName"));
if (attr != NULL) {
@@ -1638,7 +1723,7 @@
if (manifestTree == NULL) {
return UNKNOWN_ERROR;
}
- err = massageManifest(bundle, manifestTree);
+ err = massageManifest(bundle, &table, manifestTree);
if (err < NO_ERROR) {
return err;
}
diff --git a/tools/aapt/ResourceTable.cpp b/tools/aapt/ResourceTable.cpp
index 221f3c2..52b93a9 100644
--- a/tools/aapt/ResourceTable.cpp
+++ b/tools/aapt/ResourceTable.cpp
@@ -4832,8 +4832,7 @@
item.resPath = resPath;
item.file = newFile;
item.xmlRoot = root->clone();
- item.needsCompiling = false; // This step occurs after we parse/assign, so we don't need
- // to do it again.
+ item.needsCompiling = true;
mWorkQueue.push(item);
// Now mark the old entry as deleted.
diff --git a/tools/aapt/ResourceTable.h b/tools/aapt/ResourceTable.h
index aff22d4..b340fc5 100644
--- a/tools/aapt/ResourceTable.h
+++ b/tools/aapt/ResourceTable.h
@@ -590,9 +590,10 @@
const String16& comment,
bool appendComment);
+ sp<Package> getPackage(const String16& package);
+
private:
void writePublicDefinitions(const String16& package, FILE* fp, bool pub);
- sp<Package> getPackage(const String16& package);
sp<Type> getType(const String16& package,
const String16& type,
const SourcePos& pos,
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
index 1e77ac1..8bd924e 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
@@ -1614,7 +1614,7 @@
}
@Override
- public Intent registerReceiver(BroadcastReceiver arg0, IntentFilter arg1, boolean arg2) {
+ public Intent registerReceiver(BroadcastReceiver arg0, IntentFilter arg1, int arg2) {
// pass
return null;
}
@@ -1628,7 +1628,7 @@
@Override
public Intent registerReceiver(BroadcastReceiver arg0, IntentFilter arg1,
- String arg2, Handler arg3, boolean arg4) {
+ String arg2, Handler arg3, int arg4) {
// pass
return null;
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java
index ad26bc8..764eeeb 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java
@@ -17,6 +17,7 @@
package com.android.layoutlib.bridge.android;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.PackageInstallObserver;
import android.content.ComponentName;
import android.content.Intent;
@@ -328,11 +329,26 @@
}
@Override
+ public int getInstantAppCookieMaxBytes() {
+ return 0;
+ }
+
+ @Override
public int getInstantAppCookieMaxSize() {
return 0;
}
@Override
+ public void clearInstantAppCookie() {;
+
+ }
+
+ @Override
+ public void updateInstantAppCookie(@Nullable byte[] cookie) {
+
+ }
+
+ @Override
public boolean setInstantAppCookie(@NonNull byte[] cookie) {
return false;
}
@@ -928,4 +944,9 @@
public ComponentName getInstantAppInstallerComponent() {
return null;
}
+
+ @Override
+ public String getInstantAppAndroidId(String packageName, UserHandle user) {
+ return null;
+ }
}
diff --git a/wifi/java/android/net/wifi/WifiScanner.java b/wifi/java/android/net/wifi/WifiScanner.java
index 40e34b1..c02ceef 100644
--- a/wifi/java/android/net/wifi/WifiScanner.java
+++ b/wifi/java/android/net/wifi/WifiScanner.java
@@ -906,6 +906,7 @@
}
/** specifies information about an access point of interest */
+ @Deprecated
public static class BssidInfo {
/** bssid of the access point; in XX:XX:XX:XX:XX:XX format */
public String bssid;
@@ -919,6 +920,7 @@
/** @hide */
@SystemApi
+ @Deprecated
public static class WifiChangeSettings implements Parcelable {
public int rssiSampleSize; /* sample size for RSSI averaging */
public int lostApSampleSize; /* samples to confirm AP's loss */
@@ -959,6 +961,7 @@
* @param periodInMs indicates period of scan to find changes
* @param bssidInfos access points to watch
*/
+ @Deprecated
public void configureWifiChange(
int rssiSampleSize, /* sample size for RSSI averaging */
int lostApSampleSize, /* samples to confirm AP's loss */
@@ -974,6 +977,7 @@
/**
* interface to get wifi change events on; use this on {@link #startTrackingWifiChange}
*/
+ @Deprecated
public interface WifiChangeListener extends ActionListener {
/** indicates that changes were detected in wifi environment
* @param results indicate the access points that exhibited change
@@ -990,6 +994,7 @@
* @param listener object to report events on; this object must be unique and must also be
* provided on {@link #stopTrackingWifiChange}
*/
+ @Deprecated
public void startTrackingWifiChange(WifiChangeListener listener) {
throw new UnsupportedOperationException();
}
@@ -999,17 +1004,20 @@
* @param listener object that was provided to report events on {@link
* #stopTrackingWifiChange}
*/
+ @Deprecated
public void stopTrackingWifiChange(WifiChangeListener listener) {
throw new UnsupportedOperationException();
}
/** @hide */
@SystemApi
+ @Deprecated
public void configureWifiChange(WifiChangeSettings settings) {
throw new UnsupportedOperationException();
}
/** interface to receive hotlist events on; use this on {@link #setHotlist} */
+ @Deprecated
public static interface BssidListener extends ActionListener {
/** indicates that access points were found by on going scans
* @param results list of scan results, one for each access point visible currently
@@ -1023,6 +1031,7 @@
/** @hide */
@SystemApi
+ @Deprecated
public static class HotlistSettings implements Parcelable {
public BssidInfo[] bssidInfos;
public int apLostThreshold;
@@ -1057,6 +1066,7 @@
* @param listener object provided to report events on; this object must be unique and must
* also be provided on {@link #stopTrackingBssids}
*/
+ @Deprecated
public void startTrackingBssids(BssidInfo[] bssidInfos,
int apLostThreshold, BssidListener listener) {
throw new UnsupportedOperationException();
@@ -1066,6 +1076,7 @@
* remove tracking of interesting access points
* @param listener same object provided in {@link #startTrackingBssids}
*/
+ @Deprecated
public void stopTrackingBssids(BssidListener listener) {
throw new UnsupportedOperationException();
}