diff options
207 files changed, 3846 insertions, 2157 deletions
diff --git a/api/current.txt b/api/current.txt index a69a8e5f98a0..dab4f641100b 100644 --- a/api/current.txt +++ b/api/current.txt @@ -260,6 +260,7 @@ package android { public static final class R.attr { ctor public R.attr(); + field public static final int __removed2 = 16843937; // 0x10104a1 field public static final int absListViewStyle = 16842858; // 0x101006a field public static final int accessibilityEventTypes = 16843648; // 0x1010380 field public static final int accessibilityFeedbackType = 16843650; // 0x1010382 @@ -482,7 +483,7 @@ package android { field public static final int datePickerMode = 16843956; // 0x10104b4 field public static final int datePickerStyle = 16843612; // 0x101035c field public static final int dateTextAppearance = 16843593; // 0x1010349 - field public static final int dayOfWeekBackgroundColor = 16843924; // 0x1010494 + field public static final int dayOfWeekBackground = 16843924; // 0x1010494 field public static final int dayOfWeekTextAppearance = 16843925; // 0x1010495 field public static final int debuggable = 16842767; // 0x101000f field public static final int defaultValue = 16843245; // 0x10101ed @@ -663,7 +664,6 @@ package android { field public static final int hasCode = 16842764; // 0x101000c field public static final int headerAmPmTextAppearance = 16843936; // 0x10104a0 field public static final int headerBackground = 16843055; // 0x101012f - field public static final int headerBackgroundColor = 16843937; // 0x10104a1 field public static final int headerDayOfMonthTextAppearance = 16843927; // 0x1010497 field public static final int headerDividersEnabled = 16843310; // 0x101022e field public static final int headerMonthTextAppearance = 16843926; // 0x1010496 @@ -968,6 +968,7 @@ package android { field public static final int pathData = 16843807; // 0x101041f field public static final int pathPattern = 16842796; // 0x101002c field public static final int pathPrefix = 16842795; // 0x101002b + field public static final int patternPathData = 16843979; // 0x10104cb field public static final int permission = 16842758; // 0x1010006 field public static final int permissionFlags = 16843719; // 0x10103c7 field public static final int permissionGroup = 16842762; // 0x101000a @@ -3455,7 +3456,7 @@ package android.app { method public boolean navigateUpToFromChild(android.app.Activity, android.content.Intent); method public void onActionModeFinished(android.view.ActionMode); method public void onActionModeStarted(android.view.ActionMode); - method protected void onActivityReenter(int, android.content.Intent); + method public void onActivityReenter(int, android.content.Intent); method protected void onActivityResult(int, int, android.content.Intent); method public void onAttachFragment(android.app.Fragment); method public void onAttachedToWindow(); @@ -3466,7 +3467,7 @@ package android.app { method public boolean onContextItemSelected(android.view.MenuItem); method public void onContextMenuClosed(android.view.Menu); method protected void onCreate(android.os.Bundle); - method protected void onCreate(android.os.Bundle, android.os.PersistableBundle); + method public void onCreate(android.os.Bundle, android.os.PersistableBundle); method public void onCreateContextMenu(android.view.ContextMenu, android.view.View, android.view.ContextMenu.ContextMenuInfo); method public java.lang.CharSequence onCreateDescription(); method protected deprecated android.app.Dialog onCreateDialog(int); @@ -3498,7 +3499,7 @@ package android.app { method public void onPanelClosed(int, android.view.Menu); method protected void onPause(); method protected void onPostCreate(android.os.Bundle); - method protected void onPostCreate(android.os.Bundle, android.os.PersistableBundle); + method public void onPostCreate(android.os.Bundle, android.os.PersistableBundle); method protected void onPostResume(); method protected deprecated void onPrepareDialog(int, android.app.Dialog); method protected deprecated void onPrepareDialog(int, android.app.Dialog, android.os.Bundle); @@ -3508,11 +3509,11 @@ package android.app { method public void onProvideAssistData(android.os.Bundle); method protected void onRestart(); method protected void onRestoreInstanceState(android.os.Bundle); - method protected void onRestoreInstanceState(android.os.Bundle, android.os.PersistableBundle); + method public void onRestoreInstanceState(android.os.Bundle, android.os.PersistableBundle); method protected void onResume(); method public deprecated java.lang.Object onRetainNonConfigurationInstance(); method protected void onSaveInstanceState(android.os.Bundle); - method protected void onSaveInstanceState(android.os.Bundle, android.os.PersistableBundle); + method public void onSaveInstanceState(android.os.Bundle, android.os.PersistableBundle); method public boolean onSearchRequested(); method protected void onStart(); method protected void onStop(); @@ -3544,8 +3545,8 @@ package android.app { method public void setContentView(android.view.View); method public void setContentView(android.view.View, android.view.ViewGroup.LayoutParams); method public final void setDefaultKeyMode(int); - method public void setEnterSharedElementListener(android.app.SharedElementListener); - method public void setExitSharedElementListener(android.app.SharedElementListener); + method public void setEnterSharedElementCallback(android.app.SharedElementCallback); + method public void setExitSharedElementCallback(android.app.SharedElementCallback); method public final void setFeatureDrawable(int, android.graphics.drawable.Drawable); method public final void setFeatureDrawableAlpha(int, int); method public final void setFeatureDrawableResource(int, int); @@ -4319,9 +4320,9 @@ package android.app { method public void setAllowEnterTransitionOverlap(boolean); method public void setAllowReturnTransitionOverlap(boolean); method public void setArguments(android.os.Bundle); - method public void setEnterSharedElementTransitionListener(android.app.SharedElementListener); + method public void setEnterSharedElementTransitionCallback(android.app.SharedElementCallback); method public void setEnterTransition(android.transition.Transition); - method public void setExitSharedElementTransitionListener(android.app.SharedElementListener); + method public void setExitSharedElementTransitionCallback(android.app.SharedElementCallback); method public void setExitTransition(android.transition.Transition); method public void setHasOptionsMenu(boolean); method public void setInitialSavedState(android.app.Fragment.SavedState); @@ -5192,14 +5193,14 @@ package android.app { field public static final int START_STICKY_COMPATIBILITY = 0; // 0x0 } - public abstract class SharedElementListener { - ctor public SharedElementListener(); - method public android.os.Parcelable captureSharedElementSnapshot(android.view.View, android.graphics.Matrix, android.graphics.RectF); - method public android.view.View createSnapshotView(android.content.Context, android.os.Parcelable); - method public void handleRejectedSharedElements(java.util.List<android.view.View>); - method public void remapSharedElements(java.util.List<java.lang.String>, java.util.Map<java.lang.String, android.view.View>); - method public void setSharedElementEnd(java.util.List<java.lang.String>, java.util.List<android.view.View>, java.util.List<android.view.View>); - method public void setSharedElementStart(java.util.List<java.lang.String>, java.util.List<android.view.View>, java.util.List<android.view.View>); + public abstract class SharedElementCallback { + ctor public SharedElementCallback(); + method public android.os.Parcelable onCaptureSharedElementSnapshot(android.view.View, android.graphics.Matrix, android.graphics.RectF); + method public android.view.View onCreateSnapshotView(android.content.Context, android.os.Parcelable); + method public void onMapSharedElements(java.util.List<java.lang.String>, java.util.Map<java.lang.String, android.view.View>); + method public void onRejectSharedElements(java.util.List<android.view.View>); + method public void onSharedElementEnd(java.util.List<java.lang.String>, java.util.List<android.view.View>, java.util.List<android.view.View>); + method public void onSharedElementStart(java.util.List<java.lang.String>, java.util.List<android.view.View>, java.util.List<android.view.View>); } public deprecated class TabActivity extends android.app.ActivityGroup { @@ -5391,8 +5392,8 @@ package android.app.admin { field public static final java.lang.String ACTION_DEVICE_ADMIN_DISABLED = "android.app.action.DEVICE_ADMIN_DISABLED"; field public static final java.lang.String ACTION_DEVICE_ADMIN_DISABLE_REQUESTED = "android.app.action.DEVICE_ADMIN_DISABLE_REQUESTED"; field public static final java.lang.String ACTION_DEVICE_ADMIN_ENABLED = "android.app.action.DEVICE_ADMIN_ENABLED"; - field public static final java.lang.String ACTION_LOCK_TASK_ENTERING = "android.app.action.ACTION_LOCK_TASK_ENTERING"; - field public static final java.lang.String ACTION_LOCK_TASK_EXITING = "android.app.action.ACTION_LOCK_TASK_EXITING"; + field public static final java.lang.String ACTION_LOCK_TASK_ENTERING = "android.app.action.LOCK_TASK_ENTERING"; + field public static final java.lang.String ACTION_LOCK_TASK_EXITING = "android.app.action.LOCK_TASK_EXITING"; field public static final java.lang.String ACTION_PASSWORD_CHANGED = "android.app.action.ACTION_PASSWORD_CHANGED"; field public static final java.lang.String ACTION_PASSWORD_EXPIRING = "android.app.action.ACTION_PASSWORD_EXPIRING"; field public static final java.lang.String ACTION_PASSWORD_FAILED = "android.app.action.ACTION_PASSWORD_FAILED"; @@ -5507,23 +5508,23 @@ package android.app.admin { field public static final int ENCRYPTION_STATUS_UNSUPPORTED = 0; // 0x0 field public static final java.lang.String EXTRA_ADD_EXPLANATION = "android.app.extra.ADD_EXPLANATION"; field public static final java.lang.String EXTRA_DEVICE_ADMIN = "android.app.extra.DEVICE_ADMIN"; - field public static final java.lang.String EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE = "android.app.extra.ADMIN_EXTRA_BUNDLE"; - field public static final java.lang.String EXTRA_PROVISIONING_DEFAULT_MANAGED_PROFILE_NAME = "android.app.extra.DEFAULT_MANAGED_PROFILE_NAME"; - field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM = "android.app.extra.DEVICE_ADMIN_PACKAGE_CHECKSUM"; - field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_COOKIE_HEADER = "android.app.extra.DEVICE_ADMIN_PACKAGE_DOWNLOAD_COOKIE_HEADER"; - field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION = "android.app.extra.DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION"; + field public static final java.lang.String EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE = "android.app.extra.PROVISIONING_ADMIN_EXTRAS_BUNDLE"; + field public static final java.lang.String EXTRA_PROVISIONING_DEFAULT_MANAGED_PROFILE_NAME = "android.app.extra.PROVISIONING_DEFAULT_MANAGED_PROFILE_NAME"; + field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM"; + field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_COOKIE_HEADER = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_COOKIE_HEADER"; + field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION"; field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME = "android.app.extra.deviceAdminPackageName"; - field public static final java.lang.String EXTRA_PROVISIONING_LOCALE = "android.app.extra.LOCALE"; - field public static final java.lang.String EXTRA_PROVISIONING_LOCAL_TIME = "android.app.extra.LOCAL_TIME"; - field public static final java.lang.String EXTRA_PROVISIONING_TIME_ZONE = "android.app.extra.TIME_ZONE"; - field public static final java.lang.String EXTRA_PROVISIONING_WIFI_HIDDEN = "android.app.extra.WIFI_HIDDEN"; - field public static final java.lang.String EXTRA_PROVISIONING_WIFI_PAC_URL = "android.app.extra.WIFI_PAC_URL"; - field public static final java.lang.String EXTRA_PROVISIONING_WIFI_PASSWORD = "android.app.extra.WIFI_PASSWORD"; - field public static final java.lang.String EXTRA_PROVISIONING_WIFI_PROXY_BYPASS = "android.app.extra.WIFI_PROXY_BYPASS_HOSTS"; - field public static final java.lang.String EXTRA_PROVISIONING_WIFI_PROXY_HOST = "android.app.extra.WIFI_PROXY_HOST"; - field public static final java.lang.String EXTRA_PROVISIONING_WIFI_PROXY_PORT = "android.app.extra.WIFI_PROXY_PORT"; - field public static final java.lang.String EXTRA_PROVISIONING_WIFI_SECURITY_TYPE = "android.app.extra.WIFI_SECURITY_TYPE"; - field public static final java.lang.String EXTRA_PROVISIONING_WIFI_SSID = "android.app.extra.WIFI_SSID"; + field public static final java.lang.String EXTRA_PROVISIONING_LOCALE = "android.app.extra.PROVISIONING_LOCALE"; + field public static final java.lang.String EXTRA_PROVISIONING_LOCAL_TIME = "android.app.extra.PROVISIONING_LOCAL_TIME"; + field public static final java.lang.String EXTRA_PROVISIONING_TIME_ZONE = "android.app.extra.PROVISIONING_TIME_ZONE"; + field public static final java.lang.String EXTRA_PROVISIONING_WIFI_HIDDEN = "android.app.extra.PROVISIONING_WIFI_HIDDEN"; + field public static final java.lang.String EXTRA_PROVISIONING_WIFI_PAC_URL = "android.app.extra.PROVISIONING_WIFI_PAC_URL"; + field public static final java.lang.String EXTRA_PROVISIONING_WIFI_PASSWORD = "android.app.extra.PROVISIONING_WIFI_PASSWORD"; + field public static final java.lang.String EXTRA_PROVISIONING_WIFI_PROXY_BYPASS = "android.app.extra.PROVISIONING_WIFI_PROXY_BYPASS"; + field public static final java.lang.String EXTRA_PROVISIONING_WIFI_PROXY_HOST = "android.app.extra.PROVISIONING_WIFI_PROXY_HOST"; + field public static final java.lang.String EXTRA_PROVISIONING_WIFI_PROXY_PORT = "android.app.extra.PROVISIONING_WIFI_PROXY_PORT"; + field public static final java.lang.String EXTRA_PROVISIONING_WIFI_SECURITY_TYPE = "android.app.extra.PROVISIONING_WIFI_SECURITY_TYPE"; + field public static final java.lang.String EXTRA_PROVISIONING_WIFI_SSID = "android.app.extra.PROVISIONING_WIFI_SSID"; field public static int FLAG_MANAGED_CAN_ACCESS_PARENT; field public static int FLAG_PARENT_CAN_ACCESS_MANAGED; field public static final int KEYGUARD_DISABLE_FEATURES_ALL = 2147483647; // 0x7fffffff @@ -5534,7 +5535,7 @@ package android.app.admin { field public static final int KEYGUARD_DISABLE_TRUST_AGENTS = 16; // 0x10 field public static final int KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS = 8; // 0x8 field public static final int KEYGUARD_DISABLE_WIDGETS_ALL = 1; // 0x1 - field public static final java.lang.String KEY_PROVISIONING_EMAIL_ADDRESS = "android.app.key.ManagedProfileEmailAddress"; + field public static final java.lang.String KEY_PROVISIONING_EMAIL_ADDRESS = "android.app.key.PROVISIONING_EMAIL_ADDRESS"; field public static final java.lang.String MIME_TYPE_PROVISIONING_NFC = "application/com.android.managedprovisioning"; field public static final int PASSWORD_QUALITY_ALPHABETIC = 262144; // 0x40000 field public static final int PASSWORD_QUALITY_ALPHANUMERIC = 327680; // 0x50000 @@ -5706,6 +5707,19 @@ package android.app.job { package android.app.usage { + public final class ConfigurationStats implements android.os.Parcelable { + ctor public ConfigurationStats(android.app.usage.ConfigurationStats); + method public int describeContents(); + method public int getActivationCount(); + method public android.content.res.Configuration getConfiguration(); + method public long getFirstTimeStamp(); + method public long getLastTimeActive(); + method public long getLastTimeStamp(); + method public long getTotalTimeActive(); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator CREATOR; + } + public final class UsageEvents implements android.os.Parcelable { method public int describeContents(); method public boolean getNextEvent(android.app.usage.UsageEvents.Event); @@ -5718,9 +5732,11 @@ package android.app.usage { public static final class UsageEvents.Event { ctor public UsageEvents.Event(); method public java.lang.String getClassName(); + method public android.content.res.Configuration getConfiguration(); method public int getEventType(); method public java.lang.String getPackageName(); method public long getTimeStamp(); + field public static final int CONFIGURATION_CHANGE = 5; // 0x5 field public static final int MOVE_TO_BACKGROUND = 2; // 0x2 field public static final int MOVE_TO_FOREGROUND = 1; // 0x1 field public static final int NONE = 0; // 0x0 @@ -5741,6 +5757,7 @@ package android.app.usage { public final class UsageStatsManager { method public java.util.Map<java.lang.String, android.app.usage.UsageStats> queryAndAggregateUsageStats(long, long); + method public java.util.List<android.app.usage.ConfigurationStats> queryConfigurations(int, long, long); method public android.app.usage.UsageEvents queryEvents(long, long); method public java.util.List<android.app.usage.UsageStats> queryUsageStats(int, long, long); field public static final int INTERVAL_BEST = 4; // 0x4 @@ -5859,7 +5876,7 @@ package android.appwidget { field public static final int RESIZE_VERTICAL = 2; // 0x2 field public static final int WIDGET_CATEGORY_HOME_SCREEN = 1; // 0x1 field public static final int WIDGET_CATEGORY_KEYGUARD = 2; // 0x2 - field public static final int WIDGET_CATEGORY_RECENTS = 4; // 0x4 + field public static final int WIDGET_CATEGORY_SEARCHBOX = 4; // 0x4 field public int autoAdvanceViewId; field public android.content.ComponentName configure; field public int icon; @@ -7867,7 +7884,7 @@ package android.content { field public static final java.lang.String EXTRA_TEXT = "android.intent.extra.TEXT"; field public static final java.lang.String EXTRA_TITLE = "android.intent.extra.TITLE"; field public static final java.lang.String EXTRA_UID = "android.intent.extra.UID"; - field public static final java.lang.String EXTRA_USER = "android.intent.extra.user"; + field public static final java.lang.String EXTRA_USER = "android.intent.extra.USER"; field public static final int FILL_IN_ACTION = 1; // 0x1 field public static final int FILL_IN_CATEGORIES = 4; // 0x4 field public static final int FILL_IN_CLIP_DATA = 128; // 0x80 @@ -8664,15 +8681,17 @@ package android.content.pm { public class PackageInstaller { method public void abandonSession(int); - method public void addSessionCallback(android.content.pm.PackageInstaller.SessionCallback); - method public void addSessionCallback(android.content.pm.PackageInstaller.SessionCallback, android.os.Handler); method public int createSession(android.content.pm.PackageInstaller.SessionParams) throws java.io.IOException; method public java.util.List<android.content.pm.PackageInstaller.SessionInfo> getAllSessions(); method public java.util.List<android.content.pm.PackageInstaller.SessionInfo> getMySessions(); method public android.content.pm.PackageInstaller.SessionInfo getSessionInfo(int); method public android.content.pm.PackageInstaller.Session openSession(int); - method public void removeSessionCallback(android.content.pm.PackageInstaller.SessionCallback); + method public void registerSessionCallback(android.content.pm.PackageInstaller.SessionCallback); + method public void registerSessionCallback(android.content.pm.PackageInstaller.SessionCallback, android.os.Handler); method public void uninstall(java.lang.String, android.content.IntentSender); + method public void unregisterSessionCallback(android.content.pm.PackageInstaller.SessionCallback); + method public void updateSessionAppIcon(int, android.graphics.Bitmap); + method public void updateSessionAppLabel(int, java.lang.CharSequence); field public static final java.lang.String ACTION_SESSION_DETAILS = "android.content.pm.action.SESSION_DETAILS"; field public static final java.lang.String EXTRA_OTHER_PACKAGE_NAME = "android.content.pm.extra.OTHER_PACKAGE_NAME"; field public static final java.lang.String EXTRA_PACKAGE_NAME = "android.content.pm.extra.PACKAGE_NAME"; @@ -8704,6 +8723,7 @@ package android.content.pm { public static abstract class PackageInstaller.SessionCallback { ctor public PackageInstaller.SessionCallback(); + method public abstract void onBadgingChanged(int); method public abstract void onClosed(int); method public abstract void onCreated(int); method public abstract void onFinished(int, boolean); @@ -8827,6 +8847,9 @@ package android.content.pm { method public abstract android.content.pm.FeatureInfo[] getSystemAvailableFeatures(); method public abstract java.lang.String[] getSystemSharedLibraryNames(); method public abstract java.lang.CharSequence getText(java.lang.String, int, android.content.pm.ApplicationInfo); + method public abstract android.graphics.drawable.Drawable getUserBadgedDrawableForDensity(android.graphics.drawable.Drawable, android.os.UserHandle, android.graphics.Rect, int); + method public abstract android.graphics.drawable.Drawable getUserBadgedIcon(android.graphics.drawable.Drawable, android.os.UserHandle); + method public abstract java.lang.CharSequence getUserBadgedLabel(java.lang.CharSequence, android.os.UserHandle); method public abstract android.content.res.XmlResourceParser getXml(java.lang.String, int, android.content.pm.ApplicationInfo); method public abstract boolean hasSystemFeature(java.lang.String); method public abstract boolean isSafeMode(); @@ -11419,8 +11442,6 @@ package android.graphics { ctor public PorterDuffColorFilter(int, android.graphics.PorterDuff.Mode); method public int getColor(); method public android.graphics.PorterDuff.Mode getMode(); - method public void setColor(int); - method public void setMode(android.graphics.PorterDuff.Mode); } public class PorterDuffXfermode extends android.graphics.Xfermode { @@ -13999,7 +14020,7 @@ package android.location { ctor public SettingInjectorService(java.lang.String); method public final android.os.IBinder onBind(android.content.Intent); method protected abstract boolean onGetEnabled(); - method protected deprecated java.lang.String onGetSummary(); + method protected abstract deprecated java.lang.String onGetSummary(); method public final void onStart(android.content.Intent, int); method public final int onStartCommand(android.content.Intent, int, int); field public static final java.lang.String ACTION_INJECTED_SETTING_CHANGED = "android.location.InjectedSettingChanged"; @@ -16998,6 +17019,7 @@ package android.mtp { package android.net { public class ConnectivityManager { + method public void addDefaultNetworkActiveListener(android.net.ConnectivityManager.OnNetworkActiveListener); method public android.net.NetworkInfo getActiveNetworkInfo(); method public android.net.NetworkInfo[] getAllNetworkInfo(); method public android.net.Network[] getAllNetworks(); @@ -17011,8 +17033,8 @@ package android.net { method public boolean isActiveNetworkMetered(); method public boolean isDefaultNetworkActive(); method public static boolean isNetworkTypeValid(int); - method public void registerDefaultNetworkActiveListener(android.net.ConnectivityManager.OnNetworkActiveListener); method public void registerNetworkCallback(android.net.NetworkRequest, android.net.ConnectivityManager.NetworkCallback); + method public void removeDefaultNetworkActiveListener(android.net.ConnectivityManager.OnNetworkActiveListener); method public void reportBadNetwork(android.net.Network); method public void requestNetwork(android.net.NetworkRequest, android.net.ConnectivityManager.NetworkCallback); method public deprecated boolean requestRouteToHost(int, int); @@ -17020,7 +17042,6 @@ package android.net { method public static boolean setProcessDefaultNetwork(android.net.Network); method public deprecated int startUsingNetworkFeature(int, java.lang.String); method public deprecated int stopUsingNetworkFeature(int, java.lang.String); - method public void unregisterDefaultNetworkActiveListener(android.net.ConnectivityManager.OnNetworkActiveListener); method public void unregisterNetworkCallback(android.net.ConnectivityManager.NetworkCallback); field public static final deprecated java.lang.String ACTION_BACKGROUND_DATA_SETTING_CHANGED = "android.net.conn.BACKGROUND_DATA_SETTING_CHANGED"; field public static final java.lang.String CONNECTIVITY_ACTION = "android.net.conn.CONNECTIVITY_CHANGE"; @@ -17094,6 +17115,7 @@ package android.net { method public int getPrefixLength(); method public int getScope(); method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator CREATOR; } public final class LinkProperties implements android.os.Parcelable { @@ -17306,6 +17328,7 @@ package android.net { method public android.net.Uri getPacFileUrl(); method public int getPort(); method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator CREATOR; } public abstract class PskKeyManager { @@ -21546,7 +21569,7 @@ package android.os { field public static final int JELLY_BEAN_MR2 = 18; // 0x12 field public static final int KITKAT = 19; // 0x13 field public static final int KITKAT_WATCH = 20; // 0x14 - field public static final int L = 10000; // 0x2710 + field public static final int L = 21; // 0x15 } public final class Bundle extends android.os.BaseBundle implements java.lang.Cloneable android.os.Parcelable { @@ -21584,6 +21607,8 @@ package android.os { method public short getShort(java.lang.String); method public short getShort(java.lang.String, short); method public short[] getShortArray(java.lang.String); + method public android.util.Size getSize(java.lang.String); + method public android.util.SizeF getSizeF(java.lang.String); method public android.util.SparseArray<T> getSparseParcelableArray(java.lang.String); method public java.util.ArrayList<java.lang.String> getStringArrayList(java.lang.String); method public boolean hasFileDescriptors(); @@ -21608,6 +21633,8 @@ package android.os { method public void putSerializable(java.lang.String, java.io.Serializable); method public void putShort(java.lang.String, short); method public void putShortArray(java.lang.String, short[]); + method public void putSize(java.lang.String, android.util.Size); + method public void putSizeF(java.lang.String, android.util.SizeF); method public void putSparseParcelableArray(java.lang.String, android.util.SparseArray<? extends android.os.Parcelable>); method public void putStringArrayList(java.lang.String, java.util.ArrayList<java.lang.String>); method public void readFromParcel(android.os.Parcel); @@ -22059,6 +22086,8 @@ package android.os { method public final android.os.PersistableBundle readPersistableBundle(); method public final android.os.PersistableBundle readPersistableBundle(java.lang.ClassLoader); method public final java.io.Serializable readSerializable(); + method public final android.util.Size readSize(); + method public final android.util.SizeF readSizeF(); method public final android.util.SparseArray readSparseArray(java.lang.ClassLoader); method public final android.util.SparseBooleanArray readSparseBooleanArray(); method public final java.lang.String readString(); @@ -22100,6 +22129,8 @@ package android.os { method public final void writeParcelableArray(T[], int); method public final void writePersistableBundle(android.os.PersistableBundle); method public final void writeSerializable(java.io.Serializable); + method public final void writeSize(android.util.Size); + method public final void writeSizeF(android.util.SizeF); method public final void writeSparseArray(android.util.SparseArray<java.lang.Object>); method public final void writeSparseBooleanArray(android.util.SparseBooleanArray); method public final void writeString(java.lang.String); @@ -22439,9 +22470,6 @@ package android.os { public class UserManager { method public android.os.Bundle getApplicationRestrictions(java.lang.String); - method public android.graphics.drawable.Drawable getBadgedDrawableForUser(android.graphics.drawable.Drawable, android.os.UserHandle, android.graphics.Rect, int); - method public android.graphics.drawable.Drawable getBadgedIconForUser(android.graphics.drawable.Drawable, android.os.UserHandle); - method public java.lang.CharSequence getBadgedLabelForUser(java.lang.CharSequence, android.os.UserHandle); method public long getSerialNumberForUser(android.os.UserHandle); method public int getUserCount(); method public android.os.UserHandle getUserForSerialNumber(long); @@ -23669,7 +23697,7 @@ package android.provider { field public static final java.lang.String DATE = "date"; field public static final java.lang.String DEFAULT_SORT_ORDER = "date DESC"; field public static final java.lang.String DURATION = "duration"; - field public static final java.lang.String EXTRA_CALL_TYPE_FILTER = "android.provider.extra.call_type_filter"; + field public static final java.lang.String EXTRA_CALL_TYPE_FILTER = "android.provider.extra.CALL_TYPE_FILTER"; field public static final java.lang.String FEATURES = "features"; field public static final int FEATURES_NONE = 0; // 0x0 field public static final int FEATURES_VIDEO = 1; // 0x1 @@ -24033,11 +24061,11 @@ package android.provider { public static final class ContactsContract.CommonDataKinds.Callable implements android.provider.ContactsContract.CommonDataKinds.CommonColumns android.provider.ContactsContract.DataColumnsWithJoins { ctor public ContactsContract.CommonDataKinds.Callable(); - field public static final java.lang.String ADDRESS_BOOK_INDEX_EXTRAS = "address_book_index_extras"; field public static final android.net.Uri CONTENT_FILTER_URI; field public static final android.net.Uri CONTENT_URI; - field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "address_book_index_counts"; - field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "address_book_index_titles"; + field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX = "android.provider.extra.ADDRESS_BOOK_INDEX"; + field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "android.provider.extra.ADDRESS_BOOK_INDEX_COUNTS"; + field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "android.provider.extra.ADDRESS_BOOK_INDEX_TITLES"; } protected static abstract interface ContactsContract.CommonDataKinds.CommonColumns implements android.provider.ContactsContract.CommonDataKinds.BaseTypes { @@ -24048,11 +24076,11 @@ package android.provider { public static final class ContactsContract.CommonDataKinds.Contactables implements android.provider.ContactsContract.CommonDataKinds.CommonColumns android.provider.ContactsContract.DataColumnsWithJoins { ctor public ContactsContract.CommonDataKinds.Contactables(); - field public static final java.lang.String ADDRESS_BOOK_INDEX_EXTRAS = "address_book_index_extras"; field public static final android.net.Uri CONTENT_FILTER_URI; field public static final android.net.Uri CONTENT_URI; - field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "address_book_index_counts"; - field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "address_book_index_titles"; + field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX = "android.provider.extra.ADDRESS_BOOK_INDEX"; + field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "android.provider.extra.ADDRESS_BOOK_INDEX_COUNTS"; + field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "android.provider.extra.ADDRESS_BOOK_INDEX_TITLES"; field public static final java.lang.String VISIBLE_CONTACTS_ONLY = "visible_contacts_only"; } @@ -24060,15 +24088,15 @@ package android.provider { method public static final java.lang.CharSequence getTypeLabel(android.content.res.Resources, int, java.lang.CharSequence); method public static final int getTypeLabelResource(int); field public static final java.lang.String ADDRESS = "data1"; - field public static final java.lang.String ADDRESS_BOOK_INDEX_EXTRAS = "address_book_index_extras"; field public static final android.net.Uri CONTENT_FILTER_URI; field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/email_v2"; field public static final android.net.Uri CONTENT_LOOKUP_URI; field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/email_v2"; field public static final android.net.Uri CONTENT_URI; field public static final java.lang.String DISPLAY_NAME = "data4"; - field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "address_book_index_counts"; - field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "address_book_index_titles"; + field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX = "android.provider.extra.ADDRESS_BOOK_INDEX"; + field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "android.provider.extra.ADDRESS_BOOK_INDEX_COUNTS"; + field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "android.provider.extra.ADDRESS_BOOK_INDEX_TITLES"; field public static final int TYPE_HOME = 1; // 0x1 field public static final int TYPE_MOBILE = 4; // 0x4 field public static final int TYPE_OTHER = 3; // 0x3 @@ -24078,10 +24106,10 @@ package android.provider { public static final class ContactsContract.CommonDataKinds.Event implements android.provider.ContactsContract.CommonDataKinds.CommonColumns android.provider.ContactsContract.DataColumnsWithJoins { method public static final java.lang.CharSequence getTypeLabel(android.content.res.Resources, int, java.lang.CharSequence); method public static int getTypeResource(java.lang.Integer); - field public static final java.lang.String ADDRESS_BOOK_INDEX_EXTRAS = "address_book_index_extras"; field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/contact_event"; - field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "address_book_index_counts"; - field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "address_book_index_titles"; + field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX = "android.provider.extra.ADDRESS_BOOK_INDEX"; + field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "android.provider.extra.ADDRESS_BOOK_INDEX_COUNTS"; + field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "android.provider.extra.ADDRESS_BOOK_INDEX_TITLES"; field public static final java.lang.String START_DATE = "data1"; field public static final int TYPE_ANNIVERSARY = 1; // 0x1 field public static final int TYPE_BIRTHDAY = 3; // 0x3 @@ -24089,19 +24117,19 @@ package android.provider { } public static final class ContactsContract.CommonDataKinds.GroupMembership implements android.provider.ContactsContract.DataColumnsWithJoins { - field public static final java.lang.String ADDRESS_BOOK_INDEX_EXTRAS = "address_book_index_extras"; field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/group_membership"; - field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "address_book_index_counts"; - field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "address_book_index_titles"; + field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX = "android.provider.extra.ADDRESS_BOOK_INDEX"; + field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "android.provider.extra.ADDRESS_BOOK_INDEX_COUNTS"; + field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "android.provider.extra.ADDRESS_BOOK_INDEX_TITLES"; field public static final java.lang.String GROUP_ROW_ID = "data1"; field public static final java.lang.String GROUP_SOURCE_ID = "group_sourceid"; } public static final class ContactsContract.CommonDataKinds.Identity implements android.provider.ContactsContract.DataColumnsWithJoins { - field public static final java.lang.String ADDRESS_BOOK_INDEX_EXTRAS = "address_book_index_extras"; field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/identity"; - field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "address_book_index_counts"; - field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "address_book_index_titles"; + field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX = "android.provider.extra.ADDRESS_BOOK_INDEX"; + field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "android.provider.extra.ADDRESS_BOOK_INDEX_COUNTS"; + field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "android.provider.extra.ADDRESS_BOOK_INDEX_TITLES"; field public static final java.lang.String IDENTITY = "data1"; field public static final java.lang.String NAMESPACE = "data2"; } @@ -24111,11 +24139,11 @@ package android.provider { method public static final int getProtocolLabelResource(int); method public static final java.lang.CharSequence getTypeLabel(android.content.res.Resources, int, java.lang.CharSequence); method public static final int getTypeLabelResource(int); - field public static final java.lang.String ADDRESS_BOOK_INDEX_EXTRAS = "address_book_index_extras"; field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/im"; field public static final java.lang.String CUSTOM_PROTOCOL = "data6"; - field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "address_book_index_counts"; - field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "address_book_index_titles"; + field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX = "android.provider.extra.ADDRESS_BOOK_INDEX"; + field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "android.provider.extra.ADDRESS_BOOK_INDEX_COUNTS"; + field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "android.provider.extra.ADDRESS_BOOK_INDEX_TITLES"; field public static final java.lang.String PROTOCOL = "data5"; field public static final int PROTOCOL_AIM = 0; // 0x0 field public static final int PROTOCOL_CUSTOM = -1; // 0xffffffff @@ -24133,10 +24161,10 @@ package android.provider { } public static final class ContactsContract.CommonDataKinds.Nickname implements android.provider.ContactsContract.CommonDataKinds.CommonColumns android.provider.ContactsContract.DataColumnsWithJoins { - field public static final java.lang.String ADDRESS_BOOK_INDEX_EXTRAS = "address_book_index_extras"; field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/nickname"; - field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "address_book_index_counts"; - field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "address_book_index_titles"; + field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX = "android.provider.extra.ADDRESS_BOOK_INDEX"; + field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "android.provider.extra.ADDRESS_BOOK_INDEX_COUNTS"; + field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "android.provider.extra.ADDRESS_BOOK_INDEX_TITLES"; field public static final java.lang.String NAME = "data1"; field public static final int TYPE_DEFAULT = 1; // 0x1 field public static final int TYPE_INITIALS = 5; // 0x5 @@ -24147,22 +24175,22 @@ package android.provider { } public static final class ContactsContract.CommonDataKinds.Note implements android.provider.ContactsContract.DataColumnsWithJoins { - field public static final java.lang.String ADDRESS_BOOK_INDEX_EXTRAS = "address_book_index_extras"; field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/note"; - field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "address_book_index_counts"; - field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "address_book_index_titles"; + field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX = "android.provider.extra.ADDRESS_BOOK_INDEX"; + field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "android.provider.extra.ADDRESS_BOOK_INDEX_COUNTS"; + field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "android.provider.extra.ADDRESS_BOOK_INDEX_TITLES"; field public static final java.lang.String NOTE = "data1"; } public static final class ContactsContract.CommonDataKinds.Organization implements android.provider.ContactsContract.CommonDataKinds.CommonColumns android.provider.ContactsContract.DataColumnsWithJoins { method public static final java.lang.CharSequence getTypeLabel(android.content.res.Resources, int, java.lang.CharSequence); method public static final int getTypeLabelResource(int); - field public static final java.lang.String ADDRESS_BOOK_INDEX_EXTRAS = "address_book_index_extras"; field public static final java.lang.String COMPANY = "data1"; field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/organization"; field public static final java.lang.String DEPARTMENT = "data5"; - field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "address_book_index_counts"; - field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "address_book_index_titles"; + field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX = "android.provider.extra.ADDRESS_BOOK_INDEX"; + field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "android.provider.extra.ADDRESS_BOOK_INDEX_COUNTS"; + field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "android.provider.extra.ADDRESS_BOOK_INDEX_TITLES"; field public static final java.lang.String JOB_DESCRIPTION = "data6"; field public static final java.lang.String OFFICE_LOCATION = "data9"; field public static final java.lang.String PHONETIC_NAME = "data8"; @@ -24175,13 +24203,13 @@ package android.provider { public static final class ContactsContract.CommonDataKinds.Phone implements android.provider.ContactsContract.CommonDataKinds.CommonColumns android.provider.ContactsContract.DataColumnsWithJoins { method public static final java.lang.CharSequence getTypeLabel(android.content.res.Resources, int, java.lang.CharSequence); method public static final int getTypeLabelResource(int); - field public static final java.lang.String ADDRESS_BOOK_INDEX_EXTRAS = "address_book_index_extras"; field public static final android.net.Uri CONTENT_FILTER_URI; field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/phone_v2"; field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/phone_v2"; field public static final android.net.Uri CONTENT_URI; - field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "address_book_index_counts"; - field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "address_book_index_titles"; + field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX = "android.provider.extra.ADDRESS_BOOK_INDEX"; + field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "android.provider.extra.ADDRESS_BOOK_INDEX_COUNTS"; + field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "android.provider.extra.ADDRESS_BOOK_INDEX_TITLES"; field public static final java.lang.String NORMALIZED_NUMBER = "data4"; field public static final java.lang.String NUMBER = "data1"; field public static final java.lang.String SEARCH_DISPLAY_NAME_KEY = "search_display_name"; @@ -24209,10 +24237,10 @@ package android.provider { } public static final class ContactsContract.CommonDataKinds.Photo implements android.provider.ContactsContract.DataColumnsWithJoins { - field public static final java.lang.String ADDRESS_BOOK_INDEX_EXTRAS = "address_book_index_extras"; field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/photo"; - field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "address_book_index_counts"; - field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "address_book_index_titles"; + field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX = "android.provider.extra.ADDRESS_BOOK_INDEX"; + field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "android.provider.extra.ADDRESS_BOOK_INDEX_COUNTS"; + field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "android.provider.extra.ADDRESS_BOOK_INDEX_TITLES"; field public static final java.lang.String PHOTO = "data15"; field public static final java.lang.String PHOTO_FILE_ID = "data14"; } @@ -24220,10 +24248,10 @@ package android.provider { public static final class ContactsContract.CommonDataKinds.Relation implements android.provider.ContactsContract.CommonDataKinds.CommonColumns android.provider.ContactsContract.DataColumnsWithJoins { method public static final java.lang.CharSequence getTypeLabel(android.content.res.Resources, int, java.lang.CharSequence); method public static final int getTypeLabelResource(int); - field public static final java.lang.String ADDRESS_BOOK_INDEX_EXTRAS = "address_book_index_extras"; field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/relation"; - field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "address_book_index_counts"; - field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "address_book_index_titles"; + field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX = "android.provider.extra.ADDRESS_BOOK_INDEX"; + field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "android.provider.extra.ADDRESS_BOOK_INDEX_COUNTS"; + field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "android.provider.extra.ADDRESS_BOOK_INDEX_TITLES"; field public static final java.lang.String NAME = "data1"; field public static final int TYPE_ASSISTANT = 1; // 0x1 field public static final int TYPE_BROTHER = 2; // 0x2 @@ -24244,10 +24272,10 @@ package android.provider { public static final class ContactsContract.CommonDataKinds.SipAddress implements android.provider.ContactsContract.CommonDataKinds.CommonColumns android.provider.ContactsContract.DataColumnsWithJoins { method public static final java.lang.CharSequence getTypeLabel(android.content.res.Resources, int, java.lang.CharSequence); method public static final int getTypeLabelResource(int); - field public static final java.lang.String ADDRESS_BOOK_INDEX_EXTRAS = "address_book_index_extras"; field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/sip_address"; - field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "address_book_index_counts"; - field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "address_book_index_titles"; + field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX = "android.provider.extra.ADDRESS_BOOK_INDEX"; + field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "android.provider.extra.ADDRESS_BOOK_INDEX_COUNTS"; + field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "android.provider.extra.ADDRESS_BOOK_INDEX_TITLES"; field public static final java.lang.String SIP_ADDRESS = "data1"; field public static final int TYPE_HOME = 1; // 0x1 field public static final int TYPE_OTHER = 3; // 0x3 @@ -24255,11 +24283,11 @@ package android.provider { } public static final class ContactsContract.CommonDataKinds.StructuredName implements android.provider.ContactsContract.DataColumnsWithJoins { - field public static final java.lang.String ADDRESS_BOOK_INDEX_EXTRAS = "address_book_index_extras"; field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/name"; field public static final java.lang.String DISPLAY_NAME = "data1"; - field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "address_book_index_counts"; - field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "address_book_index_titles"; + field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX = "android.provider.extra.ADDRESS_BOOK_INDEX"; + field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "android.provider.extra.ADDRESS_BOOK_INDEX_COUNTS"; + field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "android.provider.extra.ADDRESS_BOOK_INDEX_TITLES"; field public static final java.lang.String FAMILY_NAME = "data3"; field public static final java.lang.String FULL_NAME_STYLE = "data10"; field public static final java.lang.String GIVEN_NAME = "data2"; @@ -24274,14 +24302,14 @@ package android.provider { public static final class ContactsContract.CommonDataKinds.StructuredPostal implements android.provider.ContactsContract.CommonDataKinds.CommonColumns android.provider.ContactsContract.DataColumnsWithJoins { method public static final java.lang.CharSequence getTypeLabel(android.content.res.Resources, int, java.lang.CharSequence); method public static final int getTypeLabelResource(int); - field public static final java.lang.String ADDRESS_BOOK_INDEX_EXTRAS = "address_book_index_extras"; field public static final java.lang.String CITY = "data7"; field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/postal-address_v2"; field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/postal-address_v2"; field public static final android.net.Uri CONTENT_URI; field public static final java.lang.String COUNTRY = "data10"; - field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "address_book_index_counts"; - field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "address_book_index_titles"; + field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX = "android.provider.extra.ADDRESS_BOOK_INDEX"; + field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "android.provider.extra.ADDRESS_BOOK_INDEX_COUNTS"; + field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "android.provider.extra.ADDRESS_BOOK_INDEX_TITLES"; field public static final java.lang.String FORMATTED_ADDRESS = "data1"; field public static final java.lang.String NEIGHBORHOOD = "data6"; field public static final java.lang.String POBOX = "data5"; @@ -24294,10 +24322,10 @@ package android.provider { } public static final class ContactsContract.CommonDataKinds.Website implements android.provider.ContactsContract.CommonDataKinds.CommonColumns android.provider.ContactsContract.DataColumnsWithJoins { - field public static final java.lang.String ADDRESS_BOOK_INDEX_EXTRAS = "address_book_index_extras"; field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/website"; - field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "address_book_index_counts"; - field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "address_book_index_titles"; + field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX = "android.provider.extra.ADDRESS_BOOK_INDEX"; + field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "android.provider.extra.ADDRESS_BOOK_INDEX_COUNTS"; + field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "android.provider.extra.ADDRESS_BOOK_INDEX_TITLES"; field public static final int TYPE_BLOG = 2; // 0x2 field public static final int TYPE_FTP = 6; // 0x6 field public static final int TYPE_HOME = 4; // 0x4 @@ -24345,7 +24373,6 @@ package android.provider { method public static deprecated void markAsContacted(android.content.ContentResolver, long); method public static java.io.InputStream openContactPhotoInputStream(android.content.ContentResolver, android.net.Uri, boolean); method public static java.io.InputStream openContactPhotoInputStream(android.content.ContentResolver, android.net.Uri); - field public static final java.lang.String ADDRESS_BOOK_INDEX_EXTRAS = "address_book_index_extras"; field public static final android.net.Uri CONTENT_FILTER_URI; field public static final android.net.Uri CONTENT_FREQUENT_URI; field public static final android.net.Uri CONTENT_GROUP_URI; @@ -24358,8 +24385,9 @@ package android.provider { field public static final android.net.Uri CONTENT_URI; field public static final java.lang.String CONTENT_VCARD_TYPE = "text/x-vcard"; field public static final android.net.Uri CONTENT_VCARD_URI; - field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "address_book_index_counts"; - field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "address_book_index_titles"; + field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX = "android.provider.extra.ADDRESS_BOOK_INDEX"; + field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "android.provider.extra.ADDRESS_BOOK_INDEX_COUNTS"; + field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "android.provider.extra.ADDRESS_BOOK_INDEX_TITLES"; } public static final class ContactsContract.Contacts.AggregationSuggestions implements android.provider.BaseColumns android.provider.ContactsContract.ContactOptionsColumns android.provider.ContactsContract.ContactStatusColumns android.provider.ContactsContract.ContactsColumns { @@ -24404,11 +24432,11 @@ package android.provider { public static final class ContactsContract.Data implements android.provider.ContactsContract.DataColumnsWithJoins { method public static android.net.Uri getContactLookupUri(android.content.ContentResolver, android.net.Uri); - field public static final java.lang.String ADDRESS_BOOK_INDEX_EXTRAS = "address_book_index_extras"; field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/data"; field public static final android.net.Uri CONTENT_URI; - field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "address_book_index_counts"; - field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "address_book_index_titles"; + field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX = "android.provider.extra.ADDRESS_BOOK_INDEX"; + field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "android.provider.extra.ADDRESS_BOOK_INDEX_COUNTS"; + field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "android.provider.extra.ADDRESS_BOOK_INDEX_TITLES"; field public static final java.lang.String VISIBLE_CONTACTS_ONLY = "visible_contacts_only"; } @@ -24652,7 +24680,7 @@ package android.provider { ctor public ContactsContract.QuickContact(); method public static void showQuickContact(android.content.Context, android.view.View, android.net.Uri, int, java.lang.String[]); method public static void showQuickContact(android.content.Context, android.graphics.Rect, android.net.Uri, int, java.lang.String[]); - field public static final java.lang.String ACTION_QUICK_CONTACT = "com.android.contacts.action.QUICK_CONTACT"; + field public static final java.lang.String ACTION_QUICK_CONTACT = "android.provider.action.QUICK_CONTACT"; field public static final java.lang.String EXTRA_EXCLUDE_MIMES = "android.provider.extra.EXCLUDE_MIMES"; field public static final int MODE_LARGE = 3; // 0x3 field public static final int MODE_MEDIUM = 2; // 0x2 @@ -27160,9 +27188,9 @@ package android.service.textservice { package android.service.voice { public class AlwaysOnHotwordDetector { - method public android.content.Intent createIntentToEnroll(); - method public android.content.Intent createIntentToReEnroll(); - method public android.content.Intent createIntentToUnEnroll(); + method public android.content.Intent createEnrollIntent(); + method public android.content.Intent createReEnrollIntent(); + method public android.content.Intent createUnEnrollIntent(); method public int getSupportedRecognitionModes(); method public boolean startRecognition(int); method public boolean stopRecognition(); @@ -28474,6 +28502,7 @@ package android.telecomm { method public void addNewIncomingCall(android.telecomm.PhoneAccountHandle, android.os.Bundle); method public void cancelMissedCallsNotification(); method public void clearAccounts(java.lang.String); + method public android.telecomm.PhoneAccountHandle getConnectionManager(); method public android.telecomm.PhoneAccountHandle getDefaultOutgoingPhoneAccount(java.lang.String); method public java.util.List<android.telecomm.PhoneAccountHandle> getEnabledPhoneAccounts(); method public android.telecomm.PhoneAccount getPhoneAccount(android.telecomm.PhoneAccountHandle); @@ -28484,6 +28513,7 @@ package android.telecomm { method public void registerPhoneAccount(android.telecomm.PhoneAccount); method public void showInCallScreen(boolean); method public void unregisterPhoneAccount(android.telecomm.PhoneAccountHandle); + field public static final java.lang.String ACTION_CHANGE_PHONE_ACCOUNTS = "android.telecomm.intent.action.CHANGE_PHONE_ACCOUNTS"; field public static final java.lang.String ACTION_CONNECTION_SERVICE_CONFIGURE = "android.intent.action.CONNECTION_SERVICE_CONFIGURE"; field public static final java.lang.String ACTION_SHOW_CALL_SETTINGS = "android.telecomm.intent.action.SHOW_CALL_SETTINGS"; field public static final char DTMF_CHARACTER_PAUSE = 44; // 0x002c ',' @@ -28704,11 +28734,11 @@ package android.telephony { method public int getStatus(); method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator CREATOR; - field public static int INVALID_CHANNEL; - field public static int STATUS_MISSING_RESOURCE; - field public static int STATUS_NO_ERROR; - field public static int STATUS_NO_SUCH_ELEMENT; - field public static int STATUS_UNKNOWN_ERROR; + field public static final int INVALID_CHANNEL = -1; // 0xffffffff + field public static final int STATUS_MISSING_RESOURCE = 2; // 0x2 + field public static final int STATUS_NO_ERROR = 1; // 0x1 + field public static final int STATUS_NO_SUCH_ELEMENT = 3; // 0x3 + field public static final int STATUS_UNKNOWN_ERROR = 4; // 0x4 } public class NeighboringCellInfo implements android.os.Parcelable { @@ -28853,41 +28883,28 @@ package android.telephony { } public final class SmsManager { - method public android.net.Uri addMultimediaMessageDraft(android.net.Uri); - method public android.net.Uri addTextMessageDraft(java.lang.String, java.lang.String); - method public boolean archiveStoredConversation(long, boolean); - method public boolean deleteStoredConversation(long); - method public boolean deleteStoredMessage(android.net.Uri); method public java.util.ArrayList<java.lang.String> divideMessage(java.lang.String); - method public void downloadMultimediaMessage(java.lang.String, android.net.Uri, android.content.ContentValues, android.app.PendingIntent); - method public boolean getAutoPersisting(); + method public void downloadMultimediaMessage(java.lang.String, android.net.Uri, android.os.Bundle, android.app.PendingIntent); method public android.os.Bundle getCarrierConfigValues(); method public static android.telephony.SmsManager getDefault(); method public static android.telephony.SmsManager getSmsManagerUsingSubId(long); method public long getSubId(); - method public android.net.Uri importMultimediaMessage(android.net.Uri, java.lang.String, long, boolean, boolean); - method public android.net.Uri importTextMessage(java.lang.String, int, java.lang.String, long, boolean, boolean); method public void injectSmsPdu(byte[], java.lang.String, android.app.PendingIntent); method public void sendDataMessage(java.lang.String, java.lang.String, short, byte[], android.app.PendingIntent, android.app.PendingIntent); - method public void sendMultimediaMessage(android.net.Uri, java.lang.String, android.content.ContentValues, android.app.PendingIntent); + method public void sendMultimediaMessage(android.net.Uri, java.lang.String, android.os.Bundle, android.app.PendingIntent); method public void sendMultipartTextMessage(java.lang.String, java.lang.String, java.util.ArrayList<java.lang.String>, java.util.ArrayList<android.app.PendingIntent>, java.util.ArrayList<android.app.PendingIntent>); - method public void sendStoredMultimediaMessage(android.net.Uri, android.content.ContentValues, android.app.PendingIntent); - method public void sendStoredMultipartTextMessage(android.net.Uri, java.lang.String, java.util.ArrayList<android.app.PendingIntent>, java.util.ArrayList<android.app.PendingIntent>); - method public void sendStoredTextMessage(android.net.Uri, java.lang.String, android.app.PendingIntent, android.app.PendingIntent); method public void sendTextMessage(java.lang.String, java.lang.String, java.lang.String, android.app.PendingIntent, android.app.PendingIntent); - method public void setAutoPersisting(boolean); method public void updateMmsDownloadStatus(int, byte[]); method public void updateMmsSendStatus(int, boolean); method public void updateSmsSendStatus(int, boolean); - method public boolean updateStoredMessageStatus(android.net.Uri, android.content.ContentValues); - field public static final java.lang.String MESSAGE_STATUS_READ = "read"; - field public static final java.lang.String MESSAGE_STATUS_SEEN = "seen"; + field public static final java.lang.String EXTRA_MMS_DATA = "android.telephony.extra.MMS_DATA"; field public static final java.lang.String MMS_CONFIG_ALIAS_ENABLED = "aliasEnabled"; field public static final java.lang.String MMS_CONFIG_ALIAS_MAX_CHARS = "aliasMaxChars"; field public static final java.lang.String MMS_CONFIG_ALIAS_MIN_CHARS = "aliasMinChars"; field public static final java.lang.String MMS_CONFIG_ALLOW_ATTACH_AUDIO = "allowAttachAudio"; field public static final java.lang.String MMS_CONFIG_APPEND_TRANSACTION_ID = "enabledTransID"; field public static final java.lang.String MMS_CONFIG_EMAIL_GATEWAY_NUMBER = "emailGatewayNumber"; + field public static final java.lang.String MMS_CONFIG_GROUP_MMS_ENABLED = "enableGroupMms"; field public static final java.lang.String MMS_CONFIG_HTTP_PARAMS = "httpParams"; field public static final java.lang.String MMS_CONFIG_HTTP_SOCKET_TIMEOUT = "httpSocketTimeout"; field public static final java.lang.String MMS_CONFIG_MAX_IMAGE_HEIGHT = "maxImageHeight"; @@ -28915,13 +28932,10 @@ package android.telephony { field public static final int MMS_ERROR_IO_ERROR = 5; // 0x5 field public static final int MMS_ERROR_UNABLE_CONNECT_MMS = 3; // 0x3 field public static final int MMS_ERROR_UNSPECIFIED = 1; // 0x1 - field public static final java.lang.String MMS_EXTRA_DATA = "data"; field public static final int RESULT_ERROR_GENERIC_FAILURE = 1; // 0x1 field public static final int RESULT_ERROR_NO_SERVICE = 4; // 0x4 field public static final int RESULT_ERROR_NULL_PDU = 3; // 0x3 field public static final int RESULT_ERROR_RADIO_OFF = 2; // 0x2 - field public static final int SMS_TYPE_INCOMING = 0; // 0x0 - field public static final int SMS_TYPE_OUTGOING = 1; // 0x1 field public static final int STATUS_ON_ICC_FREE = 0; // 0x0 field public static final int STATUS_ON_ICC_READ = 1; // 0x1 field public static final int STATUS_ON_ICC_SENT = 5; // 0x5 @@ -29729,6 +29743,9 @@ package android.test.mock { method public android.content.pm.FeatureInfo[] getSystemAvailableFeatures(); method public java.lang.String[] getSystemSharedLibraryNames(); method public java.lang.CharSequence getText(java.lang.String, int, android.content.pm.ApplicationInfo); + method public android.graphics.drawable.Drawable getUserBadgedDrawableForDensity(android.graphics.drawable.Drawable, android.os.UserHandle, android.graphics.Rect, int); + method public android.graphics.drawable.Drawable getUserBadgedIcon(android.graphics.drawable.Drawable, android.os.UserHandle); + method public java.lang.CharSequence getUserBadgedLabel(java.lang.CharSequence, android.os.UserHandle); method public android.content.res.XmlResourceParser getXml(java.lang.String, int, android.content.pm.ApplicationInfo); method public boolean hasSystemFeature(java.lang.String); method public boolean isSafeMode(); @@ -31492,13 +31509,13 @@ package android.transition { method public abstract android.graphics.Path getPath(float, float, float, float); } - public class PatternMotion extends android.transition.PathMotion { - ctor public PatternMotion(); - ctor public PatternMotion(android.content.Context, android.util.AttributeSet); - ctor public PatternMotion(android.graphics.Path); + public class PatternPathMotion extends android.transition.PathMotion { + ctor public PatternPathMotion(); + ctor public PatternPathMotion(android.content.Context, android.util.AttributeSet); + ctor public PatternPathMotion(android.graphics.Path); method public android.graphics.Path getPath(float, float, float, float); - method public android.graphics.Path getPattern(); - method public void setPattern(android.graphics.Path); + method public android.graphics.Path getPatternPath(); + method public void setPatternPath(android.graphics.Path); } public final class Scene { @@ -32132,23 +32149,17 @@ package android.util { field public static final android.util.Rational ZERO; } - public final class Size implements android.os.Parcelable { + public final class Size { ctor public Size(int, int); - method public int describeContents(); method public int getHeight(); method public int getWidth(); method public static android.util.Size parseSize(java.lang.String) throws java.lang.NumberFormatException; - method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; } - public final class SizeF implements android.os.Parcelable { + public final class SizeF { ctor public SizeF(float, float); - method public int describeContents(); method public float getHeight(); method public float getWidth(); - method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; } public class SparseArray implements java.lang.Cloneable { @@ -32498,8 +32509,6 @@ package android.view { method public final long getRefreshPeriodNano(); method public final long getStartTimeNano(); field public static final long UNDEFINED_TIME_NANO = -1L; // 0xffffffffffffffffL - field protected long[] mFramesPresentedTimeNano; - field protected long mRefreshPeriodNano; } public class GestureDetector { @@ -34332,7 +34341,7 @@ package android.view { } public final class ViewAnimationUtils { - method public static final android.animation.Animator createCircularReveal(android.view.View, int, int, float, float); + method public static android.animation.Animator createCircularReveal(android.view.View, int, int, float, float); } public class ViewConfiguration { @@ -36538,6 +36547,7 @@ package android.webkit { method public abstract java.lang.String getMethod(); method public abstract java.util.Map<java.lang.String, java.lang.String> getRequestHeaders(); method public abstract android.net.Uri getUrl(); + method public abstract boolean hasGesture(); method public abstract boolean hasUserGestureInsecure(); method public abstract boolean isForMainFrame(); } @@ -36826,7 +36836,7 @@ package android.webkit { method public void setWebViewClient(android.webkit.WebViewClient); method public deprecated boolean showFindDialog(java.lang.String, boolean); method public void stopLoading(); - method public boolean zoomBy(float); + method public void zoomBy(float); method public boolean zoomIn(); method public boolean zoomOut(); field public static final java.lang.String SCHEME_GEO = "geo:0,0?q="; diff --git a/api/removed.txt b/api/removed.txt index a910e7864fa6..0aa6d54e0b01 100644 --- a/api/removed.txt +++ b/api/removed.txt @@ -30,6 +30,12 @@ package android.os { method public void wakeUp(long); } + public class UserManager { + method public android.graphics.drawable.Drawable getBadgedDrawableForUser(android.graphics.drawable.Drawable, android.os.UserHandle, android.graphics.Rect, int); + method public android.graphics.drawable.Drawable getBadgedIconForUser(android.graphics.drawable.Drawable, android.os.UserHandle); + method public java.lang.CharSequence getBadgedLabelForUser(java.lang.CharSequence, android.os.UserHandle); + } + } package android.service.notification { diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index 29ef484bd3cf..89a9692fb2c7 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -788,8 +788,8 @@ public class Activity extends ContextThemeWrapper final Handler mHandler = new Handler(); ActivityTransitionState mActivityTransitionState = new ActivityTransitionState(); - SharedElementListener mEnterTransitionListener = SharedElementListener.NULL_LISTENER; - SharedElementListener mExitTransitionListener = SharedElementListener.NULL_LISTENER; + SharedElementCallback mEnterTransitionListener = SharedElementCallback.NULL_CALLBACK; + SharedElementCallback mExitTransitionListener = SharedElementCallback.NULL_CALLBACK; /** Return the intent that started this activity. */ public Intent getIntent() { @@ -955,7 +955,7 @@ public class Activity extends ContextThemeWrapper * @see #onRestoreInstanceState * @see #onPostCreate */ - protected void onCreate(@Nullable Bundle savedInstanceState, + public void onCreate(@Nullable Bundle savedInstanceState, @Nullable PersistableBundle persistentState) { onCreate(savedInstanceState); } @@ -1040,7 +1040,7 @@ public class Activity extends ContextThemeWrapper * @see #onResume * @see #onSaveInstanceState */ - protected void onRestoreInstanceState(Bundle savedInstanceState, + public void onRestoreInstanceState(Bundle savedInstanceState, PersistableBundle persistentState) { if (savedInstanceState != null) { onRestoreInstanceState(savedInstanceState); @@ -1130,7 +1130,7 @@ public class Activity extends ContextThemeWrapper * * @see #onCreate */ - protected void onPostCreate(@Nullable Bundle savedInstanceState, + public void onPostCreate(@Nullable Bundle savedInstanceState, @Nullable PersistableBundle persistentState) { onPostCreate(savedInstanceState); } @@ -1380,7 +1380,7 @@ public class Activity extends ContextThemeWrapper * @see #onRestoreInstanceState(Bundle, PersistableBundle) * @see #onPause */ - protected void onSaveInstanceState(Bundle outState, PersistableBundle outPersistentState) { + public void onSaveInstanceState(Bundle outState, PersistableBundle outPersistentState) { onSaveInstanceState(outState); } @@ -4769,7 +4769,7 @@ public class Activity extends ContextThemeWrapper * @param data An Intent, which can return result data to the caller * (various data can be attached to Intent "extras"). */ - protected void onActivityReenter(int resultCode, Intent data) { + public void onActivityReenter(int resultCode, Intent data) { } /** @@ -5779,33 +5779,33 @@ public class Activity extends ContextThemeWrapper /** * When {@link android.app.ActivityOptions#makeSceneTransitionAnimation(Activity, - * android.view.View, String)} was used to start an Activity, <var>listener</var> + * android.view.View, String)} was used to start an Activity, <var>callback</var> * will be called to handle shared elements on the <i>launched</i> Activity. This requires * {@link Window#FEATURE_CONTENT_TRANSITIONS}. * - * @param listener Used to manipulate shared element transitions on the launched Activity. + * @param callback Used to manipulate shared element transitions on the launched Activity. */ - public void setEnterSharedElementListener(SharedElementListener listener) { - if (listener == null) { - listener = SharedElementListener.NULL_LISTENER; + public void setEnterSharedElementCallback(SharedElementCallback callback) { + if (callback == null) { + callback = SharedElementCallback.NULL_CALLBACK; } - mEnterTransitionListener = listener; + mEnterTransitionListener = callback; } /** * When {@link android.app.ActivityOptions#makeSceneTransitionAnimation(Activity, - * android.view.View, String)} was used to start an Activity, <var>listener</var> + * android.view.View, String)} was used to start an Activity, <var>callback</var> * will be called to handle shared elements on the <i>launching</i> Activity. Most * calls will only come when returning from the started Activity. * This requires {@link Window#FEATURE_CONTENT_TRANSITIONS}. * - * @param listener Used to manipulate shared element transitions on the launching Activity. + * @param callback Used to manipulate shared element transitions on the launching Activity. */ - public void setExitSharedElementListener(SharedElementListener listener) { - if (listener == null) { - listener = SharedElementListener.NULL_LISTENER; + public void setExitSharedElementCallback(SharedElementCallback callback) { + if (callback == null) { + callback = SharedElementCallback.NULL_CALLBACK; } - mExitTransitionListener = listener; + mExitTransitionListener = callback; } /** diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 38999a83f1d1..4f2a3bc5ada8 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -1938,7 +1938,7 @@ public final class ActivityThread { if (dumpFullInfo) { printRow(pw, HEAP_FULL_COLUMN, "", "Pss", "Pss", "Shared", "Private", "Shared", "Private", "Swapped", "Heap", "Heap", "Heap"); - printRow(pw, HEAP_FULL_COLUMN, "", "Total", "Clean", "Dirty", "Dirty", + printRow(pw, HEAP_FULL_COLUMN, "", "Total", "Clean", "Dirty", "", "Clean", "Clean", "Dirty", "Size", "Alloc", "Free"); printRow(pw, HEAP_FULL_COLUMN, "", "------", "------", "------", "------", "------", "------", "------", "------", "------", "------"); diff --git a/core/java/android/app/ActivityTransitionCoordinator.java b/core/java/android/app/ActivityTransitionCoordinator.java index a09a2e7d090c..9e80a4b0ec1b 100644 --- a/core/java/android/app/ActivityTransitionCoordinator.java +++ b/core/java/android/app/ActivityTransitionCoordinator.java @@ -197,7 +197,7 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver { final protected ArrayList<View> mSharedElements = new ArrayList<View>(); final protected ArrayList<String> mSharedElementNames = new ArrayList<String>(); final protected ArrayList<View> mTransitioningViews = new ArrayList<View>(); - protected SharedElementListener mListener; + protected SharedElementCallback mListener; protected ResultReceiver mResultReceiver; final private FixedEpicenterCallback mEpicenterCallback = new FixedEpicenterCallback(); final protected boolean mIsReturning; @@ -208,7 +208,7 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver { public ActivityTransitionCoordinator(Window window, ArrayList<String> allSharedElementNames, - SharedElementListener listener, boolean isReturning) { + SharedElementCallback listener, boolean isReturning) { super(new Handler()); mWindow = window; mListener = listener; @@ -218,7 +218,7 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver { protected void viewsReady(ArrayMap<String, View> sharedElements) { sharedElements.retainAll(mAllSharedElementNames); - mListener.remapSharedElements(mAllSharedElementNames, sharedElements); + mListener.onMapSharedElements(mAllSharedElementNames, sharedElements); mSharedElementNames.addAll(sharedElements.keySet()); mSharedElements.addAll(sharedElements.values()); if (getViewsTransition() != null) { @@ -251,9 +251,11 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver { */ protected void setEpicenter() { View epicenter = null; - if (!mAllSharedElementNames.isEmpty() && !mSharedElementNames.isEmpty() && - mAllSharedElementNames.get(0).equals(mSharedElementNames.get(0))) { - epicenter = mSharedElements.get(0); + if (!mAllSharedElementNames.isEmpty() && !mSharedElementNames.isEmpty()) { + int index = mSharedElementNames.indexOf(mAllSharedElementNames.get(0)); + if (index >= 0) { + epicenter = mSharedElements.get(index); + } } setEpicenter(epicenter); } @@ -458,20 +460,21 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver { tempMatrix, tempRect, null); } } - mListener.setSharedElementStart(mSharedElementNames, mSharedElements, snapshots); + mListener.onSharedElementStart(mSharedElementNames, mSharedElements, snapshots); return originalImageState; } protected void notifySharedElementEnd(ArrayList<View> snapshots) { - mListener.setSharedElementEnd(mSharedElementNames, mSharedElements, snapshots); + mListener.onSharedElementEnd(mSharedElementNames, mSharedElements, snapshots); } protected void scheduleSetSharedElementEnd(final ArrayList<View> snapshots) { - getDecor().getViewTreeObserver().addOnPreDrawListener( + final View decorView = getDecor(); + decorView.getViewTreeObserver().addOnPreDrawListener( new ViewTreeObserver.OnPreDrawListener() { @Override public boolean onPreDraw() { - getDecor().getViewTreeObserver().removeOnPreDrawListener(this); + decorView.getViewTreeObserver().removeOnPreDrawListener(this); notifySharedElementEnd(snapshots); return true; } @@ -526,7 +529,7 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver { Parcelable parcelable = sharedElementBundle.getParcelable(KEY_SNAPSHOT); View snapshot = null; if (parcelable != null) { - snapshot = mListener.createSnapshotView(context, parcelable); + snapshot = mListener.onCreateSnapshotView(context, parcelable); } if (snapshot != null) { setSharedElementState(snapshot, name, state, null, null, decorLoc); @@ -618,7 +621,7 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver { sharedElementBundle.putFloat(KEY_TRANSLATION_Z, view.getTranslationZ()); sharedElementBundle.putFloat(KEY_ELEVATION, view.getElevation()); - Parcelable bitmap = mListener.captureSharedElementSnapshot(view, tempMatrix, tempBounds); + Parcelable bitmap = mListener.onCaptureSharedElementSnapshot(view, tempMatrix, tempBounds); if (bitmap != null) { sharedElementBundle.putParcelable(KEY_SNAPSHOT, bitmap); } @@ -664,8 +667,7 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver { GhostView.addGhost(view, decor); ViewGroup parent = (ViewGroup) view.getParent(); if (moveWithParent && !isInTransitionGroup(parent, decor)) { - GhostViewListeners listener = - new GhostViewListeners(view, decor); + GhostViewListeners listener = new GhostViewListeners(view, parent, decor); parent.getViewTreeObserver().addOnPreDrawListener(listener); mGhostViewListeners.add(listener); } @@ -723,11 +725,12 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver { } protected void scheduleGhostVisibilityChange(final int visibility) { - getDecor().getViewTreeObserver() + final View decorView = getDecor(); + decorView.getViewTreeObserver() .addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { @Override public boolean onPreDraw() { - getDecor().getViewTreeObserver().removeOnPreDrawListener(this); + decorView.getViewTreeObserver().removeOnPreDrawListener(this); setGhostVisibility(visibility); return true; } @@ -769,10 +772,12 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver { private static class GhostViewListeners implements ViewTreeObserver.OnPreDrawListener { private View mView; private ViewGroup mDecor; + private View mParent; private Matrix mMatrix = new Matrix(); - public GhostViewListeners(View view, ViewGroup decor) { + public GhostViewListeners(View view, View parent, ViewGroup decor) { mView = view; + mParent = parent; mDecor = decor; } @@ -782,10 +787,9 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver { @Override public boolean onPreDraw() { - ViewGroup parent = ((ViewGroup) mView.getParent()); GhostView ghostView = GhostView.getGhost(mView); if (ghostView == null) { - parent.getViewTreeObserver().removeOnPreDrawListener(this); + mParent.getViewTreeObserver().removeOnPreDrawListener(this); } else { GhostView.calculateMatrix(mView, mDecor, mMatrix); ghostView.setMatrix(mMatrix); diff --git a/core/java/android/app/AlarmManager.java b/core/java/android/app/AlarmManager.java index a64e0ed5bb30..2c596e5c37c0 100644 --- a/core/java/android/app/AlarmManager.java +++ b/core/java/android/app/AlarmManager.java @@ -17,6 +17,7 @@ package android.app; import android.annotation.SdkConstant; +import android.annotation.SystemApi; import android.content.Context; import android.content.Intent; import android.os.Build; @@ -385,6 +386,7 @@ public class AlarmManager } /** @hide */ + @SystemApi public void set(int type, long triggerAtMillis, long windowMillis, long intervalMillis, PendingIntent operation, WorkSource workSource) { setImpl(type, triggerAtMillis, windowMillis, intervalMillis, operation, workSource, null); diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java index e2def3158eaa..9cd6d4995cbc 100644 --- a/core/java/android/app/ApplicationPackageManager.java +++ b/core/java/android/app/ApplicationPackageManager.java @@ -45,14 +45,17 @@ import android.content.pm.PermissionInfo; import android.content.pm.ProviderInfo; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; +import android.content.pm.UserInfo; import android.content.pm.VerificationParams; import android.content.pm.VerifierDeviceIdentity; import android.content.res.Resources; import android.content.res.XmlResourceParser; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Rect; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.net.Uri; -import android.os.IBinder; import android.os.Process; import android.os.RemoteException; import android.os.UserHandle; @@ -864,6 +867,49 @@ final class ApplicationPackageManager extends PackageManager { return getApplicationLogo(getApplicationInfo(packageName, 0)); } + @Override + public Drawable getUserBadgedIcon(Drawable icon, UserHandle user) { + final int badgeResId = getBadgeResIdForUser(user.getIdentifier()); + if (badgeResId == 0) { + return icon; + } + Drawable badgeIcon = getDrawable("system", badgeResId, null); + return getBadgedDrawable(icon, badgeIcon, null, true); + } + + @Override + public Drawable getUserBadgedDrawableForDensity(Drawable drawable, UserHandle user, + Rect badgeLocation, int badgeDensity) { + Drawable badgeDrawable = getUserBadgeForDensity(user, badgeDensity); + if (badgeDrawable == null) { + return drawable; + } + return getBadgedDrawable(drawable, badgeDrawable, badgeLocation, true); + } + + @Override + public Drawable getUserBadgeForDensity(UserHandle user, int density) { + UserInfo userInfo = getUserIfProfile(user.getIdentifier()); + if (userInfo != null && userInfo.isManagedProfile()) { + if (density <= 0) { + density = mContext.getResources().getDisplayMetrics().densityDpi; + } + return Resources.getSystem().getDrawableForDensity( + com.android.internal.R.drawable.ic_corp_badge, density); + } + return null; + } + + @Override + public CharSequence getUserBadgedLabel(CharSequence label, UserHandle user) { + UserInfo userInfo = getUserIfProfile(user.getIdentifier()); + if (userInfo != null && userInfo.isManagedProfile()) { + return Resources.getSystem().getString( + com.android.internal.R.string.managed_profile_label_badge, label); + } + return label; + } + @Override public Resources getResourcesForActivity( ComponentName activityName) throws NameNotFoundException { return getResourcesForApplication( @@ -1647,8 +1693,79 @@ final class ApplicationPackageManager extends PackageManager { if (dr == null) { dr = itemInfo.loadDefaultIcon(this); } - return getUserManager().getBadgedDrawableForUser(dr, - new UserHandle(mContext.getUserId())); + return getUserBadgedDrawableForDensity(dr, new UserHandle(mContext.getUserId()), null, 0); + } + + private Drawable getBadgedDrawable(Drawable drawable, Drawable badgeDrawable, + Rect badgeLocation, boolean tryBadgeInPlace) { + final int badgedWidth = drawable.getIntrinsicWidth(); + final int badgedHeight = drawable.getIntrinsicHeight(); + final boolean canBadgeInPlace = tryBadgeInPlace + && (drawable instanceof BitmapDrawable) + && ((BitmapDrawable) drawable).getBitmap().isMutable(); + + final Bitmap bitmap; + if (canBadgeInPlace) { + bitmap = ((BitmapDrawable) drawable).getBitmap(); + } else { + bitmap = Bitmap.createBitmap(badgedWidth, badgedHeight, Bitmap.Config.ARGB_8888); + } + Canvas canvas = new Canvas(bitmap); + + if (!canBadgeInPlace) { + drawable.setBounds(0, 0, badgedWidth, badgedHeight); + drawable.draw(canvas); + } + + if (badgeLocation != null) { + if (badgeLocation.left < 0 || badgeLocation.top < 0 + || badgeLocation.width() > badgedWidth || badgeLocation.height() > badgedHeight) { + throw new IllegalArgumentException("Badge location " + badgeLocation + + " not in badged drawable bounds " + + new Rect(0, 0, badgedWidth, badgedHeight)); + } + badgeDrawable.setBounds(0, 0, badgeLocation.width(), badgeLocation.height()); + + canvas.save(); + canvas.translate(badgeLocation.left, badgeLocation.top); + badgeDrawable.draw(canvas); + canvas.restore(); + } else { + badgeDrawable.setBounds(0, 0, badgedWidth, badgedHeight); + badgeDrawable.draw(canvas); + } + + if (!canBadgeInPlace) { + BitmapDrawable mergedDrawable = new BitmapDrawable(mContext.getResources(), bitmap); + + if (drawable instanceof BitmapDrawable) { + BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable; + mergedDrawable.setTargetDensity(bitmapDrawable.getBitmap().getDensity()); + } + + return mergedDrawable; + } + + return drawable; + } + + private int getBadgeResIdForUser(int userHandle) { + // Return the framework-provided badge. + UserInfo userInfo = getUserIfProfile(userHandle); + if (userInfo != null && userInfo.isManagedProfile()) { + return com.android.internal.R.drawable.ic_corp_icon_badge; + } + return 0; + } + + private UserInfo getUserIfProfile(int userHandle) { + List<UserInfo> userProfiles = getUserManager().getProfiles(UserHandle.myUserId()); + for (UserInfo user : userProfiles) { + if (user.id == userHandle) { + return user; + } + } + return null; } private final ContextImpl mContext; diff --git a/core/java/android/app/BackStackRecord.java b/core/java/android/app/BackStackRecord.java index 59f010c17c11..8227915926d1 100644 --- a/core/java/android/app/BackStackRecord.java +++ b/core/java/android/app/BackStackRecord.java @@ -1128,11 +1128,11 @@ final class BackStackRecord extends FragmentTransaction implements } if (isBack) { - outFragment.mEnterTransitionListener.remapSharedElements( + outFragment.mEnterTransitionCallback.onMapSharedElements( mSharedElementTargetNames, namedViews); setBackNameOverrides(state, namedViews, false); } else { - outFragment.mExitTransitionListener.remapSharedElements( + outFragment.mExitTransitionCallback.onMapSharedElements( mSharedElementTargetNames, namedViews); setNameOverrides(state, namedViews, false); } @@ -1248,14 +1248,14 @@ final class BackStackRecord extends FragmentTransaction implements } // Notify the start of the transition. - SharedElementListener listener = isBack ? - outFragment.mEnterTransitionListener : - inFragment.mEnterTransitionListener; + SharedElementCallback callback = isBack ? + outFragment.mEnterTransitionCallback : + inFragment.mEnterTransitionCallback; tempNames.clear(); tempNames.addAll(namedViews.keySet()); tempViewList.clear(); tempViewList.addAll(namedViews.values()); - listener.setSharedElementStart(tempNames, tempViewList, null); + callback.onSharedElementStart(tempNames, tempViewList, null); // Set the epicenter of the exit transition if (mSharedElementTargetNames != null && exitTransition != null) { @@ -1337,11 +1337,11 @@ final class BackStackRecord extends FragmentTransaction implements tempViews2, isBack); // remap shared elements and set the name mapping used in the shared element transition. if (isBack) { - inFragment.mExitTransitionListener.remapSharedElements( + inFragment.mExitTransitionCallback.onMapSharedElements( mSharedElementTargetNames, namedViews); setBackNameOverrides(state, namedViews, true); } else { - inFragment.mEnterTransitionListener.remapSharedElements( + inFragment.mEnterTransitionCallback.onMapSharedElements( mSharedElementTargetNames, namedViews); setNameOverrides(state, namedViews, true); } @@ -1355,14 +1355,14 @@ final class BackStackRecord extends FragmentTransaction implements } int containerId = inFragments.keyAt(i); - SharedElementListener sharedElementListener = isBack ? - outFragments.get(containerId).mEnterTransitionListener : - inFragment.mEnterTransitionListener; + SharedElementCallback sharedElementCallback = isBack ? + outFragments.get(containerId).mEnterTransitionCallback : + inFragment.mEnterTransitionCallback; tempNames.clear(); tempNames.addAll(namedViews.keySet()); tempViews.clear(); tempViews.addAll(namedViews.values()); - sharedElementListener.setSharedElementEnd(tempNames, tempViews, null); + sharedElementCallback.onSharedElementEnd(tempNames, tempViews, null); } // Don't include any newly-hidden fragments in the transition. diff --git a/core/java/android/app/EnterTransitionCoordinator.java b/core/java/android/app/EnterTransitionCoordinator.java index 41266476527e..f432c4954f28 100644 --- a/core/java/android/app/EnterTransitionCoordinator.java +++ b/core/java/android/app/EnterTransitionCoordinator.java @@ -21,8 +21,6 @@ import android.animation.ObjectAnimator; import android.graphics.Matrix; import android.graphics.drawable.Drawable; import android.os.Bundle; -import android.os.Handler; -import android.os.Message; import android.os.ResultReceiver; import android.text.TextUtils; import android.transition.Transition; @@ -71,12 +69,13 @@ class EnterTransitionCoordinator extends ActivityTransitionCoordinator { Bundle resultReceiverBundle = new Bundle(); resultReceiverBundle.putParcelable(KEY_REMOTE_RECEIVER, this); mResultReceiver.send(MSG_SET_REMOTE_RECEIVER, resultReceiverBundle); - getDecor().getViewTreeObserver().addOnPreDrawListener( + final View decorView = getDecor(); + decorView.getViewTreeObserver().addOnPreDrawListener( new ViewTreeObserver.OnPreDrawListener() { @Override public boolean onPreDraw() { if (mIsReadyForTransition) { - getDecor().getViewTreeObserver().removeOnPreDrawListener(this); + decorView.getViewTreeObserver().removeOnPreDrawListener(this); } return mIsReadyForTransition; } @@ -189,11 +188,12 @@ class EnterTransitionCoordinator extends ActivityTransitionCoordinator { moveSharedElementsToOverlay(); mResultReceiver.send(MSG_SHARED_ELEMENT_DESTINATION, state); } else { - getDecor().getViewTreeObserver() + final View decorView = getDecor(); + decorView.getViewTreeObserver() .addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { @Override public boolean onPreDraw() { - getDecor().getViewTreeObserver().removeOnPreDrawListener(this); + decorView.getViewTreeObserver().removeOnPreDrawListener(this); if (mResultReceiver != null) { Bundle state = captureSharedElementState(); setSharedElementMatrices(); @@ -209,7 +209,7 @@ class EnterTransitionCoordinator extends ActivityTransitionCoordinator { } } - private static SharedElementListener getListener(Activity activity, boolean isReturning) { + private static SharedElementCallback getListener(Activity activity, boolean isReturning) { return isReturning ? activity.mExitTransitionListener : activity.mEnterTransitionListener; } @@ -294,7 +294,7 @@ class EnterTransitionCoordinator extends ActivityTransitionCoordinator { ArrayList<String> rejectedNames = new ArrayList<String>(mAllSharedElementNames); rejectedNames.removeAll(mSharedElementNames); ArrayList<View> rejectedSnapshots = createSnapshots(sharedElementState, rejectedNames); - mListener.handleRejectedSharedElements(rejectedSnapshots); + mListener.onRejectSharedElements(rejectedSnapshots); startRejectedAnimations(rejectedSnapshots); // Now start shared element transition @@ -344,11 +344,12 @@ class EnterTransitionCoordinator extends ActivityTransitionCoordinator { } final Bundle sharedElementState = mSharedElementsBundle; mSharedElementsBundle = null; - getDecor().getViewTreeObserver() + final View decorView = getDecor(); + decorView.getViewTreeObserver() .addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { @Override public boolean onPreDraw() { - getDecor().getViewTreeObserver().removeOnPreDrawListener(this); + decorView.getViewTreeObserver().removeOnPreDrawListener(this); startTransition(new Runnable() { @Override public void run() { @@ -358,7 +359,7 @@ class EnterTransitionCoordinator extends ActivityTransitionCoordinator { return false; } }); - getDecor().invalidate(); + decorView.invalidate(); } private void requestLayoutForSharedElements() { diff --git a/core/java/android/app/ExitTransitionCoordinator.java b/core/java/android/app/ExitTransitionCoordinator.java index 231c93f9c993..a59a9272e495 100644 --- a/core/java/android/app/ExitTransitionCoordinator.java +++ b/core/java/android/app/ExitTransitionCoordinator.java @@ -79,7 +79,7 @@ class ExitTransitionCoordinator extends ActivityTransitionCoordinator { mActivity = activity; } - private static SharedElementListener getListener(Activity activity, boolean isReturning) { + private static SharedElementCallback getListener(Activity activity, boolean isReturning) { return isReturning ? activity.mEnterTransitionListener : activity.mExitTransitionListener; } @@ -165,18 +165,19 @@ class ExitTransitionCoordinator extends ActivityTransitionCoordinator { }); final ArrayList<View> sharedElementSnapshots = createSnapshots(mExitSharedElementBundle, mSharedElementNames); - getDecor().getViewTreeObserver() + final View decorView = getDecor(); + decorView.getViewTreeObserver() .addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { @Override public boolean onPreDraw() { - getDecor().getViewTreeObserver().removeOnPreDrawListener(this); + decorView.getViewTreeObserver().removeOnPreDrawListener(this); setSharedElementState(mExitSharedElementBundle, sharedElementSnapshots); return true; } }); setGhostVisibility(View.INVISIBLE); scheduleGhostVisibilityChange(View.INVISIBLE); - mListener.setSharedElementEnd(mSharedElementNames, mSharedElements, sharedElementSnapshots); + mListener.onSharedElementEnd(mSharedElementNames, mSharedElements, sharedElementSnapshots); TransitionManager.beginDelayedTransition(getDecor(), transition); scheduleGhostVisibilityChange(View.VISIBLE); setGhostVisibility(View.VISIBLE); diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java index dbee81e372f9..672ef7b20ee4 100644 --- a/core/java/android/app/Fragment.java +++ b/core/java/android/app/Fragment.java @@ -495,8 +495,8 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene private Boolean mAllowReturnTransitionOverlap; private Boolean mAllowEnterTransitionOverlap; - SharedElementListener mEnterTransitionListener = SharedElementListener.NULL_LISTENER; - SharedElementListener mExitTransitionListener = SharedElementListener.NULL_LISTENER; + SharedElementCallback mEnterTransitionCallback = SharedElementCallback.NULL_CALLBACK; + SharedElementCallback mExitTransitionCallback = SharedElementCallback.NULL_CALLBACK; /** * State information that has been retrieved from a fragment instance @@ -1621,31 +1621,31 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene } /** - * When custom transitions are used with Fragments, the enter transition listener + * When custom transitions are used with Fragments, the enter transition callback * is called when this Fragment is attached or detached when not popping the back stack. * - * @param listener Used to manipulate the shared element transitions on this Fragment + * @param callback Used to manipulate the shared element transitions on this Fragment * when added not as a pop from the back stack. */ - public void setEnterSharedElementTransitionListener(SharedElementListener listener) { - if (listener == null) { - listener = SharedElementListener.NULL_LISTENER; + public void setEnterSharedElementTransitionCallback(SharedElementCallback callback) { + if (callback == null) { + callback = SharedElementCallback.NULL_CALLBACK; } - mEnterTransitionListener = listener; + mEnterTransitionCallback = callback; } /** - * When custom transitions are used with Fragments, the exit transition listener + * When custom transitions are used with Fragments, the exit transition callback * is called when this Fragment is attached or detached when popping the back stack. * - * @param listener Used to manipulate the shared element transitions on this Fragment + * @param callback Used to manipulate the shared element transitions on this Fragment * when added as a pop from the back stack. */ - public void setExitSharedElementTransitionListener(SharedElementListener listener) { - if (listener == null) { - listener = SharedElementListener.NULL_LISTENER; + public void setExitSharedElementTransitionCallback(SharedElementCallback callback) { + if (callback == null) { + callback = SharedElementCallback.NULL_CALLBACK; } - mExitTransitionListener = listener; + mExitTransitionCallback = callback; } /** diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl index bdcff381b154..7d4512bd1509 100644 --- a/core/java/android/app/INotificationManager.aidl +++ b/core/java/android/app/INotificationManager.aidl @@ -71,6 +71,7 @@ interface INotificationManager ComponentName getEffectsSuppressor(); boolean matchesCallFilter(in Bundle extras); + boolean matchesCallFilterAsUser(in Bundle extras, int userId); ZenModeConfig getZenModeConfig(); boolean setZenModeConfig(in ZenModeConfig config); diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index f8dfdd9d9925..10839433e327 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -38,7 +38,6 @@ import android.os.Parcel; import android.os.Parcelable; import android.os.SystemClock; import android.os.UserHandle; -import android.os.UserManager; import android.text.TextUtils; import android.util.Log; import android.util.MathUtils; @@ -2581,8 +2580,8 @@ public class Notification implements Parcelable private Drawable getProfileBadgeDrawable() { // Note: This assumes that the current user can read the profile badge of the // originating user. - UserManager userManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE); - return userManager.getBadgeForUser(new UserHandle(mContext.getUserId()), 0); + return mContext.getPackageManager().getUserBadgeForDensity( + new UserHandle(mContext.getUserId()), 0); } private Bitmap getProfileBadge() { diff --git a/core/java/android/app/SharedElementListener.java b/core/java/android/app/SharedElementCallback.java index f36d05f49a7d..82d8e5b5393c 100644 --- a/core/java/android/app/SharedElementListener.java +++ b/core/java/android/app/SharedElementCallback.java @@ -22,7 +22,6 @@ import android.graphics.Canvas; import android.graphics.Matrix; import android.graphics.RectF; import android.graphics.drawable.BitmapDrawable; -import android.graphics.drawable.ColorDrawable; import android.os.Parcelable; import android.view.View; @@ -31,28 +30,23 @@ import java.util.Map; /** * Listener provided in - * {@link Activity#setEnterSharedElementListener(SharedElementListener)} and - * {@link Activity#setExitSharedElementListener(SharedElementListener)} - * to monitor the Activity transitions. The events can be used to customize Activity - * Transition behavior. + * {@link Activity#setEnterSharedElementCallback(SharedElementCallback)} and + * {@link Activity#setExitSharedElementCallback(SharedElementCallback)} as well as + * {@link Fragment#setEnterSharedElementTransitionCallback(SharedElementCallback)} and + * {@link Fragment#setExitSharedElementTransitionCallback(SharedElementCallback)} + * to monitor the Shared element transitions. The events can be used to customize Activity + * and Fragment Transition behavior. */ -public abstract class SharedElementListener { +public abstract class SharedElementCallback { private Matrix mTempMatrix; - static final SharedElementListener NULL_LISTENER = new SharedElementListener() { + static final SharedElementCallback NULL_CALLBACK = new SharedElementCallback() { }; /** - * Called to allow the listener to customize the start state of the shared element when - * transferring in shared element state. - * <p> - * The shared element will start at the size and position of the shared element - * in the launching Activity or Fragment. It will also transfer ImageView scaleType - * and imageMatrix if the shared elements in the calling and called Activities are - * ImageViews. Some applications may want to make additional changes, such as - * changing the clip bounds, scaling, or rotation if the shared element end state - * does not map well to the start state. - * </p> + * Called immediately after the start state is set for the shared element. + * The shared element will start at the size and position of the shared element + * in the launching Activity or Fragment. * * @param sharedElementNames The names of the shared elements that were accepted into * the View hierarchy. @@ -60,20 +54,21 @@ public abstract class SharedElementListener { * @param sharedElementSnapshots The Views containing snap shots of the shared element * from the launching Window. These elements will not * be part of the scene, but will be positioned relative - * to the Window decor View. + * to the Window decor View. This list is null for Fragment + * Transitions. */ - public void setSharedElementStart(List<String> sharedElementNames, + public void onSharedElementStart(List<String> sharedElementNames, List<View> sharedElements, List<View> sharedElementSnapshots) {} /** - * Called to allow the listener to customize the end state of the shared element when - * transferring in shared element state. + * Called after the end state is set for the shared element, but before the end state + * is captured by the shared element transition. * <p> * Any customization done in - * {@link #setSharedElementStart(java.util.List, java.util.List, java.util.List)} + * {@link #onSharedElementStart(java.util.List, java.util.List, java.util.List)} * may need to be modified to the final state of the shared element if it is not * automatically corrected by layout. For example, rotation or scale will not - * be affected by layout and if changed in {@link #setSharedElementStart(java.util.List, + * be affected by layout and if changed in {@link #onSharedElementStart(java.util.List, * java.util.List, java.util.List)}, it will also have to be set here again to correct * the end state. * </p> @@ -84,24 +79,27 @@ public abstract class SharedElementListener { * @param sharedElementSnapshots The Views containing snap shots of the shared element * from the launching Window. These elements will not * be part of the scene, but will be positioned relative - * to the Window decor View. + * to the Window decor View. This list will be null for + * Fragment Transitions. */ - public void setSharedElementEnd(List<String> sharedElementNames, + public void onSharedElementEnd(List<String> sharedElementNames, List<View> sharedElements, List<View> sharedElementSnapshots) {} /** - * Called after {@link #remapSharedElements(java.util.List, java.util.Map)} when + * Called after {@link #onMapSharedElements(java.util.List, java.util.Map)} when * transferring shared elements in. Any shared elements that have no mapping will be in * <var>rejectedSharedElements</var>. The elements remaining in * <var>rejectedSharedElements</var> will be transitioned out of the Scene. If a * View is removed from <var>rejectedSharedElements</var>, it must be handled by the - * <code>SharedElementListener</code>. + * <code>SharedElementCallback</code>. * <p> * Views in rejectedSharedElements will have their position and size set to the * position of the calling shared element, relative to the Window decor View and contain * snapshots of the View from the calling Activity or Fragment. This * view may be safely added to the decor View's overlay to remain in position. * </p> + * <p>This method is not called for Fragment Transitions. All rejected shared elements + * will be handled by the exit transition.</p> * * @param rejectedSharedElements Views containing visual information of shared elements * that are not part of the entering scene. These Views @@ -109,25 +107,27 @@ public abstract class SharedElementListener { * View removed from this list will not be transitioned * automatically. */ - public void handleRejectedSharedElements(List<View> rejectedSharedElements) {} + public void onRejectSharedElements(List<View> rejectedSharedElements) {} /** - * Lets the ActivityTransitionListener adjust the mapping of shared element names to + * Lets the SharedElementCallback adjust the mapping of shared element names to * Views. * * @param names The names of all shared elements transferred from the calling Activity - * to the started Activity. + * or Fragment in the order they were provided. * @param sharedElements The mapping of shared element names to Views. The best guess * will be filled into sharedElements based on the transitionNames. */ - public void remapSharedElements(List<String> names, Map<String, View> sharedElements) {} + public void onMapSharedElements(List<String> names, Map<String, View> sharedElements) {} /** * Creates a snapshot of a shared element to be used by the remote Activity and reconstituted - * with {@link #createSnapshotView(android.content.Context, android.os.Parcelable)}. A + * with {@link #onCreateSnapshotView(android.content.Context, android.os.Parcelable)}. A * null return value will mean that the remote Activity will have a null snapshot View in - * {@link #setSharedElementStart(java.util.List, java.util.List, java.util.List)} and - * {@link #setSharedElementEnd(java.util.List, java.util.List, java.util.List)}. + * {@link #onSharedElementStart(java.util.List, java.util.List, java.util.List)} and + * {@link #onSharedElementEnd(java.util.List, java.util.List, java.util.List)}. + * + * <p>This is not called for Fragment Transitions.</p> * * @param sharedElement The shared element View to create a snapshot for. * @param viewToGlobalMatrix A matrix containing a transform from the view to the screen @@ -135,11 +135,11 @@ public abstract class SharedElementListener { * @param screenBounds The bounds of shared element in screen coordinate space. This is * the bounds of the view with the viewToGlobalMatrix applied. * @return A snapshot to send to the remote Activity to be reconstituted with - * {@link #createSnapshotView(android.content.Context, android.os.Parcelable)} and passed - * into {@link #setSharedElementStart(java.util.List, java.util.List, java.util.List)} and - * {@link #setSharedElementEnd(java.util.List, java.util.List, java.util.List)}. + * {@link #onCreateSnapshotView(android.content.Context, android.os.Parcelable)} and passed + * into {@link #onSharedElementStart(java.util.List, java.util.List, java.util.List)} and + * {@link #onSharedElementEnd(java.util.List, java.util.List, java.util.List)}. */ - public Parcelable captureSharedElementSnapshot(View sharedElement, Matrix viewToGlobalMatrix, + public Parcelable onCaptureSharedElementSnapshot(View sharedElement, Matrix viewToGlobalMatrix, RectF screenBounds) { int bitmapWidth = Math.round(screenBounds.width()); int bitmapHeight = Math.round(screenBounds.height()); @@ -160,20 +160,22 @@ public abstract class SharedElementListener { /** * Reconstitutes a snapshot View from a Parcelable returned in - * {@link #captureSharedElementSnapshot(android.view.View, android.graphics.Matrix, - * android.graphics.RectF)} to be used in {@link #setSharedElementStart(java.util.List, - * java.util.List, java.util.List)} and {@link #setSharedElementEnd(java.util.List, + * {@link #onCaptureSharedElementSnapshot(android.view.View, android.graphics.Matrix, + * android.graphics.RectF)} to be used in {@link #onSharedElementStart(java.util.List, + * java.util.List, java.util.List)} and {@link #onSharedElementEnd(java.util.List, * java.util.List, java.util.List)}. The returned View will be sized and positioned after * this call so that it is ready to be added to the decor View's overlay. * + * <p>This is not called for Fragment Transitions.</p> + * * @param context The Context used to create the snapshot View. - * @param snapshot The Parcelable returned by {@link #captureSharedElementSnapshot( + * @param snapshot The Parcelable returned by {@link #onCaptureSharedElementSnapshot( * android.view.View, android.graphics.Matrix, android.graphics.RectF)}. - * @return A View to be sent in {@link #setSharedElementStart(java.util.List, java.util.List, - * java.util.List)} and {@link #setSharedElementEnd(java.util.List, java.util.List, + * @return A View to be sent in {@link #onSharedElementStart(java.util.List, java.util.List, + * java.util.List)} and {@link #onSharedElementEnd(java.util.List, java.util.List, * java.util.List)}. A null value will produce a null snapshot value for those two methods. */ - public View createSnapshotView(Context context, Parcelable snapshot) { + public View onCreateSnapshotView(Context context, Parcelable snapshot) { View view = null; if (snapshot instanceof Bitmap) { Bitmap bitmap = (Bitmap) snapshot; diff --git a/core/java/android/app/admin/DeviceAdminReceiver.java b/core/java/android/app/admin/DeviceAdminReceiver.java index 15def097d5e7..e2f175c10bf9 100644 --- a/core/java/android/app/admin/DeviceAdminReceiver.java +++ b/core/java/android/app/admin/DeviceAdminReceiver.java @@ -177,7 +177,7 @@ public class DeviceAdminReceiver extends BroadcastReceiver { */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String ACTION_LOCK_TASK_ENTERING - = "android.app.action.ACTION_LOCK_TASK_ENTERING"; + = "android.app.action.LOCK_TASK_ENTERING"; /** * Action sent to a device administrator to notify that the device is exiting @@ -190,7 +190,7 @@ public class DeviceAdminReceiver extends BroadcastReceiver { */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String ACTION_LOCK_TASK_EXITING - = "android.app.action.ACTION_LOCK_TASK_EXITING"; + = "android.app.action.LOCK_TASK_EXITING"; /** * A boolean describing whether the device is currently entering or exiting diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index 668de62e615e..112fc8269c8b 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -125,7 +125,7 @@ public class DevicePolicyManager { * during the managed profile provisioning. */ public static final String EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE = - "android.app.extra.ADMIN_EXTRA_BUNDLE"; + "android.app.extra.PROVISIONING_ADMIN_EXTRAS_BUNDLE"; /** * A String extra holding the package name of the mobile device management application that @@ -148,7 +148,7 @@ public class DevicePolicyManager { * <p>Use with {@link #ACTION_PROVISION_MANAGED_PROFILE} */ public static final String EXTRA_PROVISIONING_DEFAULT_MANAGED_PROFILE_NAME - = "android.app.extra.DEFAULT_MANAGED_PROFILE_NAME"; + = "android.app.extra.PROVISIONING_DEFAULT_MANAGED_PROFILE_NAME"; /** * A bundle key, used in the bundle extra {@link #EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE}. The @@ -156,7 +156,7 @@ public class DevicePolicyManager { * created for. */ public static final String KEY_PROVISIONING_EMAIL_ADDRESS - = "android.app.key.ManagedProfileEmailAddress"; + = "android.app.key.PROVISIONING_EMAIL_ADDRESS"; /** * A String extra holding the time zone {@link android.app.AlarmManager} that the device @@ -166,7 +166,7 @@ public class DevicePolicyManager { * provisioning via an Nfc bump. */ public static final String EXTRA_PROVISIONING_TIME_ZONE - = "android.app.extra.TIME_ZONE"; + = "android.app.extra.PROVISIONING_TIME_ZONE"; /** * A Long extra holding the wall clock time (in milliseconds) to be set on the device's @@ -176,7 +176,7 @@ public class DevicePolicyManager { * provisioning via an Nfc bump. */ public static final String EXTRA_PROVISIONING_LOCAL_TIME - = "android.app.extra.LOCAL_TIME"; + = "android.app.extra.PROVISIONING_LOCAL_TIME"; /** * A String extra holding the {@link java.util.Locale} that the device will be set to. @@ -186,7 +186,7 @@ public class DevicePolicyManager { * provisioning via an Nfc bump. */ public static final String EXTRA_PROVISIONING_LOCALE - = "android.app.extra.LOCALE"; + = "android.app.extra.PROVISIONING_LOCALE"; /** * A String extra holding the ssid of the wifi network that should be used during nfc device @@ -196,7 +196,7 @@ public class DevicePolicyManager { * provisioning via an Nfc bump. */ public static final String EXTRA_PROVISIONING_WIFI_SSID - = "android.app.extra.WIFI_SSID"; + = "android.app.extra.PROVISIONING_WIFI_SSID"; /** * A boolean extra indicating whether the wifi network in {@link #EXTRA_PROVISIONING_WIFI_SSID} @@ -206,7 +206,7 @@ public class DevicePolicyManager { * provisioning via an Nfc bump. */ public static final String EXTRA_PROVISIONING_WIFI_HIDDEN - = "android.app.extra.WIFI_HIDDEN"; + = "android.app.extra.PROVISIONING_WIFI_HIDDEN"; /** * A String extra indicating the security type of the wifi network in @@ -216,7 +216,7 @@ public class DevicePolicyManager { * provisioning via an Nfc bump. */ public static final String EXTRA_PROVISIONING_WIFI_SECURITY_TYPE - = "android.app.extra.WIFI_SECURITY_TYPE"; + = "android.app.extra.PROVISIONING_WIFI_SECURITY_TYPE"; /** * A String extra holding the password of the wifi network in @@ -226,7 +226,7 @@ public class DevicePolicyManager { * provisioning via an Nfc bump. */ public static final String EXTRA_PROVISIONING_WIFI_PASSWORD - = "android.app.extra.WIFI_PASSWORD"; + = "android.app.extra.PROVISIONING_WIFI_PASSWORD"; /** * A String extra holding the proxy host for the wifi network in @@ -236,7 +236,7 @@ public class DevicePolicyManager { * provisioning via an Nfc bump. */ public static final String EXTRA_PROVISIONING_WIFI_PROXY_HOST - = "android.app.extra.WIFI_PROXY_HOST"; + = "android.app.extra.PROVISIONING_WIFI_PROXY_HOST"; /** * An int extra holding the proxy port for the wifi network in @@ -246,7 +246,7 @@ public class DevicePolicyManager { * provisioning via an Nfc bump. */ public static final String EXTRA_PROVISIONING_WIFI_PROXY_PORT - = "android.app.extra.WIFI_PROXY_PORT"; + = "android.app.extra.PROVISIONING_WIFI_PROXY_PORT"; /** * A String extra holding the proxy bypass for the wifi network in @@ -256,7 +256,7 @@ public class DevicePolicyManager { * provisioning via an Nfc bump. */ public static final String EXTRA_PROVISIONING_WIFI_PROXY_BYPASS - = "android.app.extra.WIFI_PROXY_BYPASS_HOSTS"; + = "android.app.extra.PROVISIONING_WIFI_PROXY_BYPASS"; /** * A String extra holding the proxy auto-config (PAC) URL for the wifi network in @@ -266,7 +266,7 @@ public class DevicePolicyManager { * provisioning via an Nfc bump. */ public static final String EXTRA_PROVISIONING_WIFI_PAC_URL - = "android.app.extra.WIFI_PAC_URL"; + = "android.app.extra.PROVISIONING_WIFI_PAC_URL"; /** * A String extra holding a url that specifies the download location of the device admin @@ -276,7 +276,7 @@ public class DevicePolicyManager { * provisioning via an Nfc bump. */ public static final String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION - = "android.app.extra.DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION"; + = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION"; /** * A String extra holding a http cookie header which should be used in the http request to the @@ -286,7 +286,7 @@ public class DevicePolicyManager { * provisioning via an Nfc bump. */ public static final String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_COOKIE_HEADER - = "android.app.extra.DEVICE_ADMIN_PACKAGE_DOWNLOAD_COOKIE_HEADER"; + = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_COOKIE_HEADER"; /** * A String extra holding the SHA-1 checksum of the file at download location specified in @@ -298,7 +298,7 @@ public class DevicePolicyManager { * provisioning via an Nfc bump. */ public static final String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM - = "android.app.extra.DEVICE_ADMIN_PACKAGE_CHECKSUM"; + = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM"; /** * This MIME type is used for starting the Device Owner provisioning. diff --git a/core/java/android/app/usage/ConfigurationStats.java b/core/java/android/app/usage/ConfigurationStats.java new file mode 100644 index 000000000000..080216ce3b25 --- /dev/null +++ b/core/java/android/app/usage/ConfigurationStats.java @@ -0,0 +1,161 @@ +/** + * Copyright (C) 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. + */ +package android.app.usage; + +import android.content.res.Configuration; +import android.os.Parcel; +import android.os.Parcelable; + +/** + * Represents the usage statistics of a device {@link android.content.res.Configuration} for a + * specific time range. + */ +public final class ConfigurationStats implements Parcelable { + + /** + * {@hide} + */ + public Configuration mConfiguration; + + /** + * {@hide} + */ + public long mBeginTimeStamp; + + /** + * {@hide} + */ + public long mEndTimeStamp; + + /** + * {@hide} + */ + public long mLastTimeActive; + + /** + * {@hide} + */ + public long mTotalTimeActive; + + /** + * {@hide} + */ + public int mActivationCount; + + /** + * {@hide} + */ + public ConfigurationStats() { + } + + public ConfigurationStats(ConfigurationStats stats) { + mConfiguration = stats.mConfiguration; + mBeginTimeStamp = stats.mBeginTimeStamp; + mEndTimeStamp = stats.mEndTimeStamp; + mLastTimeActive = stats.mLastTimeActive; + mTotalTimeActive = stats.mTotalTimeActive; + mActivationCount = stats.mActivationCount; + } + + public Configuration getConfiguration() { + return mConfiguration; + } + + /** + * Get the beginning of the time range this {@link ConfigurationStats} represents, + * measured in milliseconds since the epoch. + * <p/> + * See {@link System#currentTimeMillis()}. + */ + public long getFirstTimeStamp() { + return mBeginTimeStamp; + } + + /** + * Get the end of the time range this {@link ConfigurationStats} represents, + * measured in milliseconds since the epoch. + * <p/> + * See {@link System#currentTimeMillis()}. + */ + public long getLastTimeStamp() { + return mEndTimeStamp; + } + + /** + * Get the last time this configuration was active, measured in milliseconds since the epoch. + * <p/> + * See {@link System#currentTimeMillis()}. + */ + public long getLastTimeActive() { + return mLastTimeActive; + } + + /** + * Get the total time this configuration was active, measured in milliseconds. + */ + public long getTotalTimeActive() { + return mTotalTimeActive; + } + + /** + * Get the number of times this configuration was active. + */ + public int getActivationCount() { + return mActivationCount; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + if (mConfiguration != null) { + dest.writeInt(1); + mConfiguration.writeToParcel(dest, flags); + } else { + dest.writeInt(0); + } + + dest.writeLong(mBeginTimeStamp); + dest.writeLong(mEndTimeStamp); + dest.writeLong(mLastTimeActive); + dest.writeLong(mTotalTimeActive); + dest.writeInt(mActivationCount); + } + + public static final Creator<ConfigurationStats> CREATOR = new Creator<ConfigurationStats>() { + @Override + public ConfigurationStats createFromParcel(Parcel source) { + ConfigurationStats stats = new ConfigurationStats(); + if (source.readInt() != 0) { + stats.mConfiguration = Configuration.CREATOR.createFromParcel(source); + } + stats.mBeginTimeStamp = source.readLong(); + stats.mEndTimeStamp = source.readLong(); + stats.mLastTimeActive = source.readLong(); + stats.mTotalTimeActive = source.readLong(); + stats.mActivationCount = source.readInt(); + return stats; + } + + @Override + public ConfigurationStats[] newArray(int size) { + return new ConfigurationStats[size]; + } + }; +} diff --git a/core/java/android/app/usage/IUsageStatsManager.aidl b/core/java/android/app/usage/IUsageStatsManager.aidl index 3b098881e73f..4ed148911a43 100644 --- a/core/java/android/app/usage/IUsageStatsManager.aidl +++ b/core/java/android/app/usage/IUsageStatsManager.aidl @@ -27,5 +27,7 @@ import android.content.pm.ParceledListSlice; interface IUsageStatsManager { ParceledListSlice queryUsageStats(int bucketType, long beginTime, long endTime, String callingPackage); + ParceledListSlice queryConfigurationStats(int bucketType, long beginTime, long endTime, + String callingPackage); UsageEvents queryEvents(long beginTime, long endTime, String callingPackage); } diff --git a/core/java/android/app/usage/UsageEvents.java b/core/java/android/app/usage/UsageEvents.java index fb80de2f4700..1a947ecf6c90 100644 --- a/core/java/android/app/usage/UsageEvents.java +++ b/core/java/android/app/usage/UsageEvents.java @@ -16,6 +16,7 @@ package android.app.usage; import android.content.ComponentName; +import android.content.res.Configuration; import android.os.Parcel; import android.os.Parcelable; @@ -63,6 +64,11 @@ public final class UsageEvents implements Parcelable { public static final int CONTINUE_PREVIOUS_DAY = 4; /** + * An event type denoting that the device configuration has changed. + */ + public static final int CONFIGURATION_CHANGE = 5; + + /** * {@hide} */ public String mPackage; @@ -83,6 +89,12 @@ public final class UsageEvents implements Parcelable { public int mEventType; /** + * Only present for {@link #CONFIGURATION_CHANGE} event types. + * {@hide} + */ + public Configuration mConfiguration; + + /** * TODO(adamlesinski): Removed before release. * {@hide} */ @@ -123,6 +135,14 @@ public final class UsageEvents implements Parcelable { public int getEventType() { return mEventType; } + + /** + * Returns a {@link Configuration} for this event if the event is of type + * {@link #CONFIGURATION_CHANGE}, otherwise it returns null. + */ + public Configuration getConfiguration() { + return mConfiguration; + } } // Only used when creating the resulting events. Not used for reading/unparceling. @@ -201,23 +221,9 @@ public final class UsageEvents implements Parcelable { return false; } - final int packageIndex = mParcel.readInt(); - if (packageIndex >= 0) { - eventOut.mPackage = mStringPool[packageIndex]; - } else { - eventOut.mPackage = null; - } + readEventFromParcel(mParcel, eventOut); - final int classIndex = mParcel.readInt(); - if (classIndex >= 0) { - eventOut.mClass = mStringPool[classIndex]; - } else { - eventOut.mClass = null; - } - eventOut.mEventType = mParcel.readInt(); - eventOut.mTimeStamp = mParcel.readLong(); mIndex++; - if (mIndex >= mEventCount) { mParcel.recycle(); mParcel = null; @@ -235,11 +241,6 @@ public final class UsageEvents implements Parcelable { } } - @Override - public int describeContents() { - return 0; - } - private int findStringIndex(String str) { final int index = Arrays.binarySearch(mStringPool, str); if (index < 0) { @@ -248,6 +249,66 @@ public final class UsageEvents implements Parcelable { return index; } + /** + * Writes a single event to the parcel. Modify this when updating {@link Event}. + */ + private void writeEventToParcel(Event event, Parcel p, int flags) { + final int packageIndex; + if (event.mPackage != null) { + packageIndex = findStringIndex(event.mPackage); + } else { + packageIndex = -1; + } + + final int classIndex; + if (event.mClass != null) { + classIndex = findStringIndex(event.mClass); + } else { + classIndex = -1; + } + p.writeInt(packageIndex); + p.writeInt(classIndex); + p.writeInt(event.mEventType); + p.writeLong(event.mTimeStamp); + + if (event.mEventType == Event.CONFIGURATION_CHANGE) { + event.mConfiguration.writeToParcel(p, flags); + } + } + + /** + * Reads a single event from the parcel. Modify this when updating {@link Event}. + */ + private void readEventFromParcel(Parcel p, Event eventOut) { + final int packageIndex = p.readInt(); + if (packageIndex >= 0) { + eventOut.mPackage = mStringPool[packageIndex]; + } else { + eventOut.mPackage = null; + } + + final int classIndex = p.readInt(); + if (classIndex >= 0) { + eventOut.mClass = mStringPool[classIndex]; + } else { + eventOut.mClass = null; + } + eventOut.mEventType = p.readInt(); + eventOut.mTimeStamp = p.readLong(); + + // Extract the configuration for configuration change events. + if (eventOut.mEventType == Event.CONFIGURATION_CHANGE) { + eventOut.mConfiguration = Configuration.CREATOR.createFromParcel(p); + } else { + eventOut.mConfiguration = null; + } + } + + @Override + public int describeContents() { + return 0; + } + @Override public void writeToParcel(Parcel dest, int flags) { dest.writeInt(mEventCount); @@ -262,25 +323,9 @@ public final class UsageEvents implements Parcelable { p.setDataPosition(0); for (int i = 0; i < mEventCount; i++) { final Event event = mEventsToWrite.get(i); - - final int packageIndex; - if (event.mPackage != null) { - packageIndex = findStringIndex(event.mPackage); - } else { - packageIndex = -1; - } - - final int classIndex; - if (event.mClass != null) { - classIndex = findStringIndex(event.mClass); - } else { - classIndex = -1; - } - p.writeInt(packageIndex); - p.writeInt(classIndex); - p.writeInt(event.getEventType()); - p.writeLong(event.getTimeStamp()); + writeEventToParcel(event, p, flags); } + final int listByteLength = p.dataPosition(); // Write the total length of the data. diff --git a/core/java/android/app/usage/UsageStatsManager.java b/core/java/android/app/usage/UsageStatsManager.java index 5830fcf49e89..bc6099a7d5e3 100644 --- a/core/java/android/app/usage/UsageStatsManager.java +++ b/core/java/android/app/usage/UsageStatsManager.java @@ -125,9 +125,9 @@ public final class UsageStatsManager { * @see #INTERVAL_YEARLY * @see #INTERVAL_BEST */ - @SuppressWarnings("unchecked") public List<UsageStats> queryUsageStats(int intervalType, long beginTime, long endTime) { try { + @SuppressWarnings("unchecked") ParceledListSlice<UsageStats> slice = mService.queryUsageStats(intervalType, beginTime, endTime, mContext.getOpPackageName()); if (slice != null) { @@ -136,7 +136,32 @@ public final class UsageStatsManager { } catch (RemoteException e) { // fallthrough and return null. } - return Collections.EMPTY_LIST; + return Collections.emptyList(); + } + + /** + * Gets the hardware configurations the device was in for the given time range, aggregated by + * the specified interval. The results are ordered as in + * {@link #queryUsageStats(int, long, long)}. + * + * @param intervalType The time interval by which the stats are aggregated. + * @param beginTime The inclusive beginning of the range of stats to include in the results. + * @param endTime The exclusive end of the range of stats to include in the results. + * @return A list of {@link ConfigurationStats} or null if none are available. + */ + public List<ConfigurationStats> queryConfigurations(int intervalType, long beginTime, + long endTime) { + try { + @SuppressWarnings("unchecked") + ParceledListSlice<ConfigurationStats> slice = mService.queryConfigurationStats( + intervalType, beginTime, endTime, mContext.getOpPackageName()); + if (slice != null) { + return slice.getList(); + } + } catch (RemoteException e) { + // fallthrough and return the empty list. + } + return Collections.emptyList(); } /** diff --git a/core/java/android/app/usage/UsageStatsManagerInternal.java b/core/java/android/app/usage/UsageStatsManagerInternal.java index 119d7054b1b5..083a48a292d3 100644 --- a/core/java/android/app/usage/UsageStatsManagerInternal.java +++ b/core/java/android/app/usage/UsageStatsManagerInternal.java @@ -17,6 +17,7 @@ package android.app.usage; import android.content.ComponentName; +import android.content.res.Configuration; /** * UsageStatsManager local system service interface. @@ -28,14 +29,19 @@ public abstract class UsageStatsManagerInternal { /** * Reports an event to the UsageStatsManager. * - * @param component The component for which this event ocurred. + * @param component The component for which this event occurred. * @param userId The user id to which the component belongs to. - * @param timeStamp The time at which this event ocurred. - * @param eventType The event that occured. Valid values can be found at + * @param eventType The event that occurred. Valid values can be found at * {@link UsageEvents} */ - public abstract void reportEvent(ComponentName component, int userId, - long timeStamp, int eventType); + public abstract void reportEvent(ComponentName component, int userId, int eventType); + + /** + * Reports a configuration change to the UsageStatsManager. + * + * @param config The new device configuration. + */ + public abstract void reportConfigurationChange(Configuration config, int userId); /** * Prepares the UsageStatsService for shutdown. diff --git a/core/java/android/appwidget/AppWidgetManager.java b/core/java/android/appwidget/AppWidgetManager.java index bd45c7ee3540..00248ccbbf32 100644 --- a/core/java/android/appwidget/AppWidgetManager.java +++ b/core/java/android/appwidget/AppWidgetManager.java @@ -188,7 +188,7 @@ public class AppWidgetManager { * this widget. Can have the value {@link * AppWidgetProviderInfo#WIDGET_CATEGORY_HOME_SCREEN} or {@link * AppWidgetProviderInfo#WIDGET_CATEGORY_KEYGUARD} or {@link - * AppWidgetProviderInfo#WIDGET_CATEGORY_RECENTS}. + * AppWidgetProviderInfo#WIDGET_CATEGORY_SEARCHBOX}. */ public static final String OPTION_APPWIDGET_HOST_CATEGORY = "appWidgetCategory"; diff --git a/core/java/android/appwidget/AppWidgetProviderInfo.java b/core/java/android/appwidget/AppWidgetProviderInfo.java index 02f70c8a6809..b4d79b484c89 100644 --- a/core/java/android/appwidget/AppWidgetProviderInfo.java +++ b/core/java/android/appwidget/AppWidgetProviderInfo.java @@ -61,9 +61,9 @@ public class AppWidgetProviderInfo implements Parcelable { public static final int WIDGET_CATEGORY_KEYGUARD = 2; /** - * Indicates that the widget can be displayed within recents. + * Indicates that the widget can be displayed within a space reserved for the search box. */ - public static final int WIDGET_CATEGORY_RECENTS = 4; + public static final int WIDGET_CATEGORY_SEARCHBOX = 4; /** * Identity of this AppWidget component. This component should be a {@link diff --git a/core/java/android/bluetooth/le/AdvertiseData.java b/core/java/android/bluetooth/le/AdvertiseData.java index c7bfae96ad2c..ff0db9aeb610 100644 --- a/core/java/android/bluetooth/le/AdvertiseData.java +++ b/core/java/android/bluetooth/le/AdvertiseData.java @@ -119,8 +119,8 @@ public final class AdvertiseData implements Parcelable { } AdvertiseData other = (AdvertiseData) obj; return Objects.equals(mServiceUuids, other.mServiceUuids) && - Utils.equals(mManufacturerSpecificData, other.mManufacturerSpecificData) && - Utils.equals(mServiceData, other.mServiceData) && + BluetoothLeUtils.equals(mManufacturerSpecificData, other.mManufacturerSpecificData) && + BluetoothLeUtils.equals(mServiceData, other.mServiceData) && mIncludeDeviceName == other.mIncludeDeviceName && mIncludeTxPowerLevel == other.mIncludeTxPowerLevel; } @@ -128,8 +128,8 @@ public final class AdvertiseData implements Parcelable { @Override public String toString() { return "AdvertiseData [mServiceUuids=" + mServiceUuids + ", mManufacturerSpecificData=" - + Utils.toString(mManufacturerSpecificData) + ", mServiceData=" - + Utils.toString(mServiceData) + + BluetoothLeUtils.toString(mManufacturerSpecificData) + ", mServiceData=" + + BluetoothLeUtils.toString(mServiceData) + ", mIncludeTxPowerLevel=" + mIncludeTxPowerLevel + ", mIncludeDeviceName=" + mIncludeDeviceName + "]"; } diff --git a/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java b/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java index 3568f2624659..d46850843f6a 100644 --- a/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java +++ b/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java @@ -107,7 +107,7 @@ public final class BluetoothLeAdvertiser { AdvertiseData advertiseData, AdvertiseData scanResponse, final AdvertiseCallback callback) { synchronized (mLeAdvertisers) { - checkAdapterState(); + BluetoothLeUtils.checkAdapterStateOn(mBluetoothAdapter); if (callback == null) { throw new IllegalArgumentException("callback cannot be null"); } @@ -150,7 +150,7 @@ public final class BluetoothLeAdvertiser { */ public void stopAdvertising(final AdvertiseCallback callback) { synchronized (mLeAdvertisers) { - checkAdapterState(); + BluetoothLeUtils.checkAdapterStateOn(mBluetoothAdapter); if (callback == null) { throw new IllegalArgumentException("callback cannot be null"); } @@ -265,9 +265,18 @@ public final class BluetoothLeAdvertiser { } if (mClientIf > 0 && mIsAdvertising) { mLeAdvertisers.put(mAdvertiseCallback, this); - } else { + } else if (mClientIf <= 0) { + // Post internal error if registration failed. postStartFailure(mAdvertiseCallback, AdvertiseCallback.ADVERTISE_FAILED_INTERNAL_ERROR); + } else { + // Unregister application if it's already registered but advertise failed. + try { + mBluetoothGatt.unregisterClient(mClientIf); + mClientIf = -1; + } catch (RemoteException e) { + Log.e(TAG, "remote exception when unregistering", e); + } } } } @@ -342,13 +351,6 @@ public final class BluetoothLeAdvertiser { } } - // TODO: move this api to a common util class. - private void checkAdapterState() { - if (mBluetoothAdapter.getState() != mBluetoothAdapter.STATE_ON) { - throw new IllegalStateException("BT Adapter is not turned ON"); - } - } - private void postStartFailure(final AdvertiseCallback callback, final int error) { mHandler.post(new Runnable() { @Override diff --git a/core/java/android/bluetooth/le/BluetoothLeScanner.java b/core/java/android/bluetooth/le/BluetoothLeScanner.java index e1d4bbd2b57e..a57c3ca25a9b 100644 --- a/core/java/android/bluetooth/le/BluetoothLeScanner.java +++ b/core/java/android/bluetooth/le/BluetoothLeScanner.java @@ -80,11 +80,10 @@ public final class BluetoothLeScanner { * @throws IllegalArgumentException If {@code callback} is null. */ public void startScan(final ScanCallback callback) { - checkAdapterState(); if (callback == null) { throw new IllegalArgumentException("callback is null"); } - this.startScan(null, new ScanSettings.Builder().build(), callback); + startScan(null, new ScanSettings.Builder().build(), callback); } /** @@ -104,7 +103,7 @@ public final class BluetoothLeScanner { private void startScan(List<ScanFilter> filters, ScanSettings settings, final ScanCallback callback, List<List<ResultStorageDescriptor>> resultStorages) { - checkAdapterState(); + BluetoothLeUtils.checkAdapterStateOn(mBluetoothAdapter); if (settings == null || callback == null) { throw new IllegalArgumentException("settings or callback is null"); } @@ -142,7 +141,7 @@ public final class BluetoothLeScanner { * @param callback */ public void stopScan(ScanCallback callback) { - checkAdapterState(); + BluetoothLeUtils.checkAdapterStateOn(mBluetoothAdapter); synchronized (mLeScanClients) { BleScanCallbackWrapper wrapper = mLeScanClients.remove(callback); if (wrapper == null) { @@ -162,7 +161,7 @@ public final class BluetoothLeScanner { * used to start scan. */ public void flushPendingScanResults(ScanCallback callback) { - checkAdapterState(); + BluetoothLeUtils.checkAdapterStateOn(mBluetoothAdapter); if (callback == null) { throw new IllegalArgumentException("callback cannot be null!"); } @@ -373,13 +372,6 @@ public final class BluetoothLeScanner { } } - // TODO: move this api to a common util class. - private void checkAdapterState() { - if (mBluetoothAdapter.getState() != mBluetoothAdapter.STATE_ON) { - throw new IllegalStateException("BT Adapter is not turned ON"); - } - } - private void postCallbackError(final ScanCallback callback, final int errorCode) { mHandler.post(new Runnable() { @Override diff --git a/core/java/android/bluetooth/le/Utils.java b/core/java/android/bluetooth/le/BluetoothLeUtils.java index ccdae6964697..4916bd9cebfa 100644 --- a/core/java/android/bluetooth/le/Utils.java +++ b/core/java/android/bluetooth/le/BluetoothLeUtils.java @@ -16,6 +16,7 @@ package android.bluetooth.le; +import android.bluetooth.BluetoothAdapter; import android.util.SparseArray; import java.util.Arrays; @@ -29,7 +30,7 @@ import java.util.Set; * * @hide */ -public class Utils { +public class BluetoothLeUtils { /** * Returns a string composed from a {@link SparseArray}. @@ -123,4 +124,17 @@ public class Utils { } return true; } + + /** + * Ensure Bluetooth is turned on. + * + * @throws IllegalStateException If {@code adapter} is null or Bluetooth state is not + * {@link BluetoothAdapter#STATE_ON}. + */ + static void checkAdapterStateOn(BluetoothAdapter adapter) { + if (adapter == null || adapter.getState() != BluetoothAdapter.STATE_ON) { + throw new IllegalStateException("BT Adapter is not turned ON"); + } + } + } diff --git a/core/java/android/bluetooth/le/ScanRecord.java b/core/java/android/bluetooth/le/ScanRecord.java index 2f3d06fc4bcf..f802e8d1295e 100644 --- a/core/java/android/bluetooth/le/ScanRecord.java +++ b/core/java/android/bluetooth/le/ScanRecord.java @@ -268,8 +268,8 @@ public final class ScanRecord { @Override public String toString() { return "ScanRecord [mAdvertiseFlags=" + mAdvertiseFlags + ", mServiceUuids=" + mServiceUuids - + ", mManufacturerSpecificData=" + Utils.toString(mManufacturerSpecificData) - + ", mServiceData=" + Utils.toString(mServiceData) + + ", mManufacturerSpecificData=" + BluetoothLeUtils.toString(mManufacturerSpecificData) + + ", mServiceData=" + BluetoothLeUtils.toString(mServiceData) + ", mTxPowerLevel=" + mTxPowerLevel + ", mDeviceName=" + mDeviceName + "]"; } diff --git a/core/java/android/content/AbstractRestrictionsProvider.java b/core/java/android/content/AbstractRestrictionsProvider.java deleted file mode 100644 index 262980e2f4aa..000000000000 --- a/core/java/android/content/AbstractRestrictionsProvider.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (C) 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. - */ - -package android.content; - -import android.app.admin.DevicePolicyManager; -import android.os.IBinder; -import android.os.PersistableBundle; - -/** - * @hide - * Abstract implementation of a Restrictions Provider BroadcastReceiver. To implement a - * Restrictions Provider, extend from this class and implement the abstract methods. - * Export this receiver in the manifest. A profile owner device admin can then register this - * component as a Restrictions Provider using - * {@link DevicePolicyManager#setRestrictionsProvider(ComponentName, ComponentName)}. - * <p> - * The function of a Restrictions Provider is to transport permission requests from apps on this - * device to an administrator (most likely on a remote device or computer) and deliver back - * responses. The response should be sent back to the app via - * {@link RestrictionsManager#notifyPermissionResponse(String, PersistableBundle)}. - * - * @see RestrictionsManager - * TODO: STOPSHIP: Remove before L ships, after clients have switched over - * to android.service.restrictions.RestrictionsReceiver. Bug: 17006805 - */ -public abstract class AbstractRestrictionsProvider extends BroadcastReceiver { - - private static final String TAG = "AbstractRestrictionsProvider"; - - /** - * An asynchronous permission request made by an application for an operation that requires - * authorization by a local or remote administrator other than the user. The Restrictions - * Provider should transfer the request to the administrator and deliver back a response, when - * available. The calling application is aware that the response could take an indefinite - * amount of time. - * <p> - * If the request bundle contains the key {@link RestrictionsManager#REQUEST_KEY_NEW_REQUEST}, - * then a new request must be sent. Otherwise the provider can look up any previous response - * to the same requestId and return the cached response. - * - * @param packageName the application requesting permission. - * @param requestType the type of request, which determines the content and presentation of - * the request data. - * @param request the request data bundle containing at a minimum a request id. - * - * @see RestrictionsManager#REQUEST_TYPE_APPROVAL - * @see RestrictionsManager#REQUEST_TYPE_LOCAL_APPROVAL - * @see RestrictionsManager#REQUEST_KEY_ID - */ - public abstract void requestPermission(Context context, - String packageName, String requestType, String requestId, PersistableBundle request); - - /** - * Intercept standard Restrictions Provider broadcasts. Implementations - * should not override this method; it is better to implement the - * convenience callbacks for each action. - */ - @Override - public void onReceive(Context context, Intent intent) { - String action = intent.getAction(); - - if (RestrictionsManager.ACTION_REQUEST_PERMISSION.equals(action)) { - String packageName = intent.getStringExtra(RestrictionsManager.EXTRA_PACKAGE_NAME); - String requestType = intent.getStringExtra(RestrictionsManager.EXTRA_REQUEST_TYPE); - String requestId = intent.getStringExtra(RestrictionsManager.EXTRA_REQUEST_ID); - PersistableBundle request = (PersistableBundle) - intent.getParcelableExtra(RestrictionsManager.EXTRA_REQUEST_BUNDLE); - requestPermission(context, packageName, requestType, requestId, request); - } - } -} diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index b825c94d7564..51a58d11ef12 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -3363,7 +3363,7 @@ public class Intent implements Parcelable, Cloneable { * profiles - {@link #ACTION_MANAGED_PROFILE_ADDED} and {@link #ACTION_MANAGED_PROFILE_REMOVED}. */ public static final String EXTRA_USER = - "android.intent.extra.user"; + "android.intent.extra.USER"; /** * Extra used in the response from a BroadcastReceiver that handles diff --git a/core/java/android/content/pm/IPackageInstaller.aidl b/core/java/android/content/pm/IPackageInstaller.aidl index c6c0ff6163d3..6daefc8b6350 100644 --- a/core/java/android/content/pm/IPackageInstaller.aidl +++ b/core/java/android/content/pm/IPackageInstaller.aidl @@ -22,14 +22,21 @@ import android.content.pm.IPackageInstallerSession; import android.content.pm.PackageInstaller; import android.content.IntentSender; +import android.graphics.Bitmap; + /** {@hide} */ interface IPackageInstaller { int createSession(in PackageInstaller.SessionParams params, String installerPackageName, int userId); + + void updateSessionAppIcon(int sessionId, in Bitmap appIcon); + void updateSessionAppLabel(int sessionId, String appLabel); + void abandonSession(int sessionId); IPackageInstallerSession openSession(int sessionId); PackageInstaller.SessionInfo getSessionInfo(int sessionId); + List<PackageInstaller.SessionInfo> getAllSessions(int userId); List<PackageInstaller.SessionInfo> getMySessions(String installerPackageName, int userId); diff --git a/core/java/android/content/pm/IPackageInstallerCallback.aidl b/core/java/android/content/pm/IPackageInstallerCallback.aidl index 39ae1a050c3e..fe98ee77d159 100644 --- a/core/java/android/content/pm/IPackageInstallerCallback.aidl +++ b/core/java/android/content/pm/IPackageInstallerCallback.aidl @@ -19,6 +19,7 @@ package android.content.pm; /** {@hide} */ oneway interface IPackageInstallerCallback { void onSessionCreated(int sessionId); + void onSessionBadgingChanged(int sessionId); void onSessionOpened(int sessionId); void onSessionProgressChanged(int sessionId, float progress); void onSessionClosed(int sessionId); diff --git a/core/java/android/content/pm/LauncherActivityInfo.java b/core/java/android/content/pm/LauncherActivityInfo.java index 0cff08b35266..ee23fcd33437 100644 --- a/core/java/android/content/pm/LauncherActivityInfo.java +++ b/core/java/android/content/pm/LauncherActivityInfo.java @@ -18,16 +18,10 @@ package android.content.pm; import android.content.ComponentName; import android.content.Context; -import android.content.Intent; import android.content.pm.PackageManager.NameNotFoundException; import android.content.res.Resources; -import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.graphics.Bitmap.Config; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; -import android.os.Bundle; -import android.os.RemoteException; import android.os.UserHandle; import android.os.UserManager; import android.util.DisplayMetrics; @@ -39,11 +33,9 @@ import android.util.Log; * and badged icon for the activity. */ public class LauncherActivityInfo { - private static final boolean DEBUG = false; private static final String TAG = "LauncherActivityInfo"; private final PackageManager mPm; - private final UserManager mUm; private ActivityInfo mActivityInfo; private ComponentName mComponentName; @@ -68,7 +60,6 @@ public class LauncherActivityInfo { LauncherActivityInfo(Context context) { mPm = context.getPackageManager(); - mUm = UserManager.get(context); } /** @@ -179,7 +170,7 @@ public class LauncherActivityInfo { } if (originalIcon instanceof BitmapDrawable) { - return mUm.getBadgedIconForUser(originalIcon, mUser); + return mPm.getUserBadgedIcon(originalIcon, mUser); } else { Log.e(TAG, "Unable to create badged icon for " + mActivityInfo); } diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java index 44e24b14e158..7c34a6512b8e 100644 --- a/core/java/android/content/pm/PackageInstaller.java +++ b/core/java/android/content/pm/PackageInstaller.java @@ -312,6 +312,32 @@ public class PackageInstaller { } } + /** + * Update the icon representing the app being installed in a specific + * session. This should be roughly + * {@link ActivityManager#getLauncherLargeIconSize()} in both dimensions. + */ + public void updateSessionAppIcon(int sessionId, @Nullable Bitmap appIcon) { + try { + mInstaller.updateSessionAppIcon(sessionId, appIcon); + } catch (RemoteException e) { + throw e.rethrowAsRuntimeException(); + } + } + + /** + * Update the label representing the app being installed in a specific + * session. + */ + public void updateSessionAppLabel(int sessionId, @Nullable CharSequence appLabel) { + try { + final String val = (appLabel != null) ? appLabel.toString() : null; + mInstaller.updateSessionAppLabel(sessionId, val); + } catch (RemoteException e) { + throw e.rethrowAsRuntimeException(); + } + } + public void abandonSession(int sessionId) { try { mInstaller.abandonSession(sessionId); @@ -321,8 +347,7 @@ public class PackageInstaller { } /** - * Return details for a specific session. To succeed, the caller must either - * own this session, or be the current home app. + * Return details for a specific session. */ public @Nullable SessionInfo getSessionInfo(int sessionId) { try { @@ -334,7 +359,6 @@ public class PackageInstaller { /** * Return list of all active install sessions, regardless of the installer. - * To succeed, the caller must be the current home app. */ public @NonNull List<SessionInfo> getAllSessions() { final ApplicationInfo info = mContext.getApplicationInfo(); @@ -406,6 +430,12 @@ public class PackageInstaller { public abstract void onCreated(int sessionId); /** + * Badging details for an existing session has changed. For example, the + * app icon or label has been updated. + */ + public abstract void onBadgingChanged(int sessionId); + + /** * Session has been opened. A session is usually opened when the * installer is actively writing data. */ @@ -436,10 +466,11 @@ public class PackageInstaller { private static class SessionCallbackDelegate extends IPackageInstallerCallback.Stub implements Handler.Callback { private static final int MSG_SESSION_CREATED = 1; - private static final int MSG_SESSION_OPENED = 2; - private static final int MSG_SESSION_PROGRESS_CHANGED = 3; - private static final int MSG_SESSION_CLOSED = 4; - private static final int MSG_SESSION_FINISHED = 5; + private static final int MSG_SESSION_BADGING_CHANGED = 2; + private static final int MSG_SESSION_OPENED = 3; + private static final int MSG_SESSION_PROGRESS_CHANGED = 4; + private static final int MSG_SESSION_CLOSED = 5; + private static final int MSG_SESSION_FINISHED = 6; final SessionCallback mCallback; final Handler mHandler; @@ -455,6 +486,9 @@ public class PackageInstaller { case MSG_SESSION_CREATED: mCallback.onCreated(msg.arg1); return true; + case MSG_SESSION_BADGING_CHANGED: + mCallback.onBadgingChanged(msg.arg1); + return true; case MSG_SESSION_OPENED: mCallback.onOpened(msg.arg1); return true; @@ -477,6 +511,11 @@ public class PackageInstaller { } @Override + public void onSessionBadgingChanged(int sessionId) { + mHandler.obtainMessage(MSG_SESSION_BADGING_CHANGED, sessionId, 0).sendToTarget(); + } + + @Override public void onSessionOpened(int sessionId) { mHandler.obtainMessage(MSG_SESSION_OPENED, sessionId, 0).sendToTarget(); } @@ -499,22 +538,32 @@ public class PackageInstaller { } } + /** {@hide} */ + @Deprecated + public void addSessionCallback(@NonNull SessionCallback callback) { + registerSessionCallback(callback); + } + /** - * Register to watch for session lifecycle events. To succeed, the caller - * must be the current home app. + * Register to watch for session lifecycle events. */ - public void addSessionCallback(@NonNull SessionCallback callback) { - addSessionCallback(callback, new Handler()); + public void registerSessionCallback(@NonNull SessionCallback callback) { + registerSessionCallback(callback, new Handler()); + } + + /** {@hide} */ + @Deprecated + public void addSessionCallback(@NonNull SessionCallback callback, @NonNull Handler handler) { + registerSessionCallback(callback, handler); } /** - * Register to watch for session lifecycle events. To succeed, the caller - * must be the current home app. + * Register to watch for session lifecycle events. * * @param handler to dispatch callback events through, otherwise uses * calling thread. */ - public void addSessionCallback(@NonNull SessionCallback callback, @NonNull Handler handler) { + public void registerSessionCallback(@NonNull SessionCallback callback, @NonNull Handler handler) { // TODO: remove this temporary guard once we have new prebuilts final ApplicationInfo info = mContext.getApplicationInfo(); if ("com.google.android.googlequicksearchbox".equals(info.packageName) @@ -535,10 +584,16 @@ public class PackageInstaller { } } + /** {@hide} */ + @Deprecated + public void removeSessionCallback(@NonNull SessionCallback callback) { + unregisterSessionCallback(callback); + } + /** * Unregister an existing callback. */ - public void removeSessionCallback(@NonNull SessionCallback callback) { + public void unregisterSessionCallback(@NonNull SessionCallback callback) { synchronized (mDelegates) { for (Iterator<SessionCallbackDelegate> i = mDelegates.iterator(); i.hasNext();) { final SessionCallbackDelegate delegate = i.next(); diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 1b15ff5262ff..e87adda50745 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -31,6 +31,7 @@ import android.content.IntentSender; import android.content.pm.PackageParser.PackageParserException; import android.content.res.Resources; import android.content.res.XmlResourceParser; +import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.Bundle; @@ -2882,6 +2883,79 @@ public abstract class PackageManager { throws NameNotFoundException; /** + * If the target user is a managed profile of the calling user or the caller + * is itself a managed profile, then this returns a badged copy of the given + * icon to be able to distinguish it from the original icon. For badging an + * arbitrary drawable use {@link #getUserBadgedDrawableForDensity( + * android.graphics.drawable.Drawable, UserHandle, android.graphics.Rect, int)}. + * <p> + * If the original drawable is a BitmapDrawable and the backing bitmap is + * mutable as per {@link android.graphics.Bitmap#isMutable()}, the badging + * is performed in place and the original drawable is returned. + * </p> + * + * @param icon The icon to badge. + * @param user The target user. + * @return A drawable that combines the original icon and a badge as + * determined by the system. + */ + public abstract Drawable getUserBadgedIcon(Drawable icon, UserHandle user); + + /** + * If the target user is a managed profile of the calling user or the caller + * is itself a managed profile, then this returns a badged copy of the given + * drawable allowing the user to distinguish it from the original drawable. + * The caller can specify the location in the bounds of the drawable to be + * badged where the badge should be applied as well as the density of the + * badge to be used. + * <p> + * If the original drawable is a BitmapDrawable and the backing bitmap is + * mutable as per {@link android.graphics.Bitmap#isMutable()}, the bading + * is performed in place and the original drawable is returned. + * </p> + * + * @param drawable The drawable to badge. + * @param user The target user. + * @param badgeLocation Where in the bounds of the badged drawable to place + * the badge. If not provided, the badge is applied on top of the entire + * drawable being badged. + * @param badgeDensity The optional desired density for the badge as per + * {@link android.util.DisplayMetrics#densityDpi}. If not provided, + * the density of the display is used. + * @return A drawable that combines the original drawable and a badge as + * determined by the system. + */ + public abstract Drawable getUserBadgedDrawableForDensity(Drawable drawable, + UserHandle user, Rect badgeLocation, int badgeDensity); + + /** + * If the target user is a managed profile of the calling user or the caller + * is itself a managed profile, then this returns a drawable to use as a small + * icon to include in a view to distinguish it from the original icon. + * + * @param user The target user. + * @param density The optional desired density for the badge as per + * {@link android.util.DisplayMetrics#densityDpi}. If not provided + * the density of the current display is used. + * @return the drawable or null if no drawable is required. + * @hide + */ + public abstract Drawable getUserBadgeForDensity(UserHandle user, int density); + + /** + * If the target user is a managed profile of the calling user or the caller + * is itself a managed profile, then this returns a copy of the label with + * badging for accessibility services like talkback. E.g. passing in "Email" + * and it might return "Work Email" for Email in the work profile. + * + * @param label The label to change. + * @param user The target user. + * @return A label that combines the original label and a badge as + * determined by the system. + */ + public abstract CharSequence getUserBadgedLabel(CharSequence label, UserHandle user); + + /** * Retrieve text from a package. This is a low-level API used by * the various package manager info structures (such as * {@link ComponentInfo} to implement retrieval of their associated diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java index e63fd0703339..27bbb242f575 100644 --- a/core/java/android/content/res/Configuration.java +++ b/core/java/android/content/res/Configuration.java @@ -16,6 +16,12 @@ package android.content.res; +import com.android.internal.util.XmlUtils; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; +import org.xmlpull.v1.XmlSerializer; + import android.content.pm.ActivityInfo; import android.os.Build; import android.os.Parcel; @@ -23,7 +29,7 @@ import android.os.Parcelable; import android.text.TextUtils; import android.view.View; -import java.text.Format; +import java.io.IOException; import java.util.ArrayList; import java.util.Locale; @@ -1353,8 +1359,6 @@ public final class Configuration implements Parcelable, Comparable<Configuration * Returns a string representation of the configuration that can be parsed * by build tools (like AAPT). * - * - * * @hide */ public static String resourceQualifierString(Configuration config) { @@ -1568,4 +1572,229 @@ public final class Configuration implements Parcelable, Comparable<Configuration parts.add("v" + Build.VERSION.RESOURCES_SDK_INT); return TextUtils.join("-", parts); } + + /** + * Generate a delta Configuration between <code>base</code> and <code>change</code>. The + * resulting delta can be used with {@link #updateFrom(Configuration)}. + * <p /> + * Caveat: If the any of the Configuration's members becomes undefined, then + * {@link #updateFrom(Configuration)} will treat it as a no-op and not update that member. + * + * This is fine for device configurations as no member is ever undefined. + * {@hide} + */ + public static Configuration generateDelta(Configuration base, Configuration change) { + final Configuration delta = new Configuration(); + if (base.fontScale != change.fontScale) { + delta.fontScale = change.fontScale; + } + + if (base.mcc != change.mcc) { + delta.mcc = change.mcc; + } + + if (base.mnc != change.mnc) { + delta.mnc = change.mnc; + } + + if ((base.locale == null && change.locale != null) || + (base.locale != null && !base.locale.equals(change.locale))) { + delta.locale = change.locale; + } + + if (base.touchscreen != change.touchscreen) { + delta.touchscreen = change.touchscreen; + } + + if (base.keyboard != change.keyboard) { + delta.keyboard = change.keyboard; + } + + if (base.keyboardHidden != change.keyboardHidden) { + delta.keyboardHidden = change.keyboardHidden; + } + + if (base.navigation != change.navigation) { + delta.navigation = change.navigation; + } + + if (base.navigationHidden != change.navigationHidden) { + delta.navigationHidden = change.navigationHidden; + } + + if (base.orientation != change.orientation) { + delta.orientation = change.orientation; + } + + if ((base.screenLayout & SCREENLAYOUT_SIZE_MASK) != + (change.screenLayout & SCREENLAYOUT_SIZE_MASK)) { + delta.screenLayout |= change.screenLayout & SCREENLAYOUT_SIZE_MASK; + } + + if ((base.screenLayout & SCREENLAYOUT_LAYOUTDIR_MASK) != + (change.screenLayout & SCREENLAYOUT_LAYOUTDIR_MASK)) { + delta.screenLayout |= change.screenLayout & SCREENLAYOUT_LAYOUTDIR_MASK; + } + + if ((base.screenLayout & SCREENLAYOUT_LONG_MASK) != + (change.screenLayout & SCREENLAYOUT_LONG_MASK)) { + delta.screenLayout |= change.screenLayout & SCREENLAYOUT_LONG_MASK; + } + + if ((base.uiMode & UI_MODE_TYPE_MASK) != (change.uiMode & UI_MODE_TYPE_MASK)) { + delta.uiMode |= change.uiMode & UI_MODE_TYPE_MASK; + } + + if ((base.uiMode & UI_MODE_NIGHT_MASK) != (change.uiMode & UI_MODE_NIGHT_MASK)) { + delta.uiMode |= change.uiMode & UI_MODE_NIGHT_MASK; + } + + if (base.screenWidthDp != change.screenWidthDp) { + delta.screenWidthDp = change.screenWidthDp; + } + + if (base.screenHeightDp != change.screenHeightDp) { + delta.screenHeightDp = change.screenHeightDp; + } + + if (base.smallestScreenWidthDp != change.smallestScreenWidthDp) { + delta.smallestScreenWidthDp = change.smallestScreenWidthDp; + } + + if (base.densityDpi != change.densityDpi) { + delta.densityDpi = change.densityDpi; + } + return delta; + } + + private static final String XML_ATTR_FONT_SCALE = "fs"; + private static final String XML_ATTR_MCC = "mcc"; + private static final String XML_ATTR_MNC = "mnc"; + private static final String XML_ATTR_LOCALE = "locale"; + private static final String XML_ATTR_TOUCHSCREEN = "touch"; + private static final String XML_ATTR_KEYBOARD = "key"; + private static final String XML_ATTR_KEYBOARD_HIDDEN = "keyHid"; + private static final String XML_ATTR_HARD_KEYBOARD_HIDDEN = "hardKeyHid"; + private static final String XML_ATTR_NAVIGATION = "nav"; + private static final String XML_ATTR_NAVIGATION_HIDDEN = "navHid"; + private static final String XML_ATTR_ORIENTATION = "ori"; + private static final String XML_ATTR_SCREEN_LAYOUT = "scrLay"; + private static final String XML_ATTR_UI_MODE = "ui"; + private static final String XML_ATTR_SCREEN_WIDTH = "width"; + private static final String XML_ATTR_SCREEN_HEIGHT = "height"; + private static final String XML_ATTR_SMALLEST_WIDTH = "sw"; + private static final String XML_ATTR_DENSITY = "density"; + + /** + * Reads the attributes corresponding to Configuration member fields from the Xml parser. + * The parser is expected to be on a tag which has Configuration attributes. + * + * @param parser The Xml parser from which to read attributes. + * @param configOut The Configuration to populate from the Xml attributes. + * {@hide} + */ + public static void readXmlAttrs(XmlPullParser parser, Configuration configOut) + throws XmlPullParserException, IOException { + configOut.fontScale = Float.intBitsToFloat( + XmlUtils.readIntAttribute(parser, XML_ATTR_FONT_SCALE, 0)); + configOut.mcc = XmlUtils.readIntAttribute(parser, XML_ATTR_MCC, 0); + configOut.mnc = XmlUtils.readIntAttribute(parser, XML_ATTR_MNC, 0); + + final String localeStr = XmlUtils.readStringAttribute(parser, XML_ATTR_LOCALE); + if (localeStr != null) { + configOut.locale = Locale.forLanguageTag(localeStr); + } + + configOut.touchscreen = XmlUtils.readIntAttribute(parser, XML_ATTR_TOUCHSCREEN, + TOUCHSCREEN_UNDEFINED); + configOut.keyboard = XmlUtils.readIntAttribute(parser, XML_ATTR_KEYBOARD, + KEYBOARD_UNDEFINED); + configOut.keyboardHidden = XmlUtils.readIntAttribute(parser, XML_ATTR_KEYBOARD_HIDDEN, + KEYBOARDHIDDEN_UNDEFINED); + configOut.hardKeyboardHidden = + XmlUtils.readIntAttribute(parser, XML_ATTR_HARD_KEYBOARD_HIDDEN, + HARDKEYBOARDHIDDEN_UNDEFINED); + configOut.navigation = XmlUtils.readIntAttribute(parser, XML_ATTR_NAVIGATION, + NAVIGATION_UNDEFINED); + configOut.navigationHidden = XmlUtils.readIntAttribute(parser, XML_ATTR_NAVIGATION_HIDDEN, + NAVIGATIONHIDDEN_UNDEFINED); + configOut.orientation = XmlUtils.readIntAttribute(parser, XML_ATTR_ORIENTATION, + ORIENTATION_UNDEFINED); + configOut.screenLayout = XmlUtils.readIntAttribute(parser, XML_ATTR_SCREEN_LAYOUT, + SCREENLAYOUT_UNDEFINED); + configOut.uiMode = XmlUtils.readIntAttribute(parser, XML_ATTR_UI_MODE, 0); + configOut.screenWidthDp = XmlUtils.readIntAttribute(parser, XML_ATTR_SCREEN_WIDTH, + SCREEN_WIDTH_DP_UNDEFINED); + configOut.screenHeightDp = XmlUtils.readIntAttribute(parser, XML_ATTR_SCREEN_HEIGHT, + SCREEN_HEIGHT_DP_UNDEFINED); + configOut.smallestScreenWidthDp = + XmlUtils.readIntAttribute(parser, XML_ATTR_SMALLEST_WIDTH, + SMALLEST_SCREEN_WIDTH_DP_UNDEFINED); + configOut.densityDpi = XmlUtils.readIntAttribute(parser, XML_ATTR_DENSITY, + DENSITY_DPI_UNDEFINED); + } + + + /** + * Writes the Configuration's member fields as attributes into the XmlSerializer. + * The serializer is expected to have already started a tag so that attributes can be + * immediately written. + * + * @param xml The serializer to which to write the attributes. + * @param config The Configuration whose member fields to write. + * {@hide} + */ + public static void writeXmlAttrs(XmlSerializer xml, Configuration config) throws IOException { + XmlUtils.writeIntAttribute(xml, XML_ATTR_FONT_SCALE, + Float.floatToIntBits(config.fontScale)); + if (config.mcc != 0) { + XmlUtils.writeIntAttribute(xml, XML_ATTR_MCC, config.mcc); + } + if (config.mnc != 0) { + XmlUtils.writeIntAttribute(xml, XML_ATTR_MNC, config.mnc); + } + if (config.locale != null) { + XmlUtils.writeStringAttribute(xml, XML_ATTR_LOCALE, config.locale.toLanguageTag()); + } + if (config.touchscreen != TOUCHSCREEN_UNDEFINED) { + XmlUtils.writeIntAttribute(xml, XML_ATTR_TOUCHSCREEN, config.touchscreen); + } + if (config.keyboard != KEYBOARD_UNDEFINED) { + XmlUtils.writeIntAttribute(xml, XML_ATTR_KEYBOARD, config.keyboard); + } + if (config.keyboardHidden != KEYBOARDHIDDEN_UNDEFINED) { + XmlUtils.writeIntAttribute(xml, XML_ATTR_KEYBOARD_HIDDEN, config.keyboardHidden); + } + if (config.hardKeyboardHidden != HARDKEYBOARDHIDDEN_UNDEFINED) { + XmlUtils.writeIntAttribute(xml, XML_ATTR_HARD_KEYBOARD_HIDDEN, + config.hardKeyboardHidden); + } + if (config.navigation != NAVIGATION_UNDEFINED) { + XmlUtils.writeIntAttribute(xml, XML_ATTR_NAVIGATION, config.navigation); + } + if (config.navigationHidden != NAVIGATIONHIDDEN_UNDEFINED) { + XmlUtils.writeIntAttribute(xml, XML_ATTR_NAVIGATION_HIDDEN, config.navigationHidden); + } + if (config.orientation != ORIENTATION_UNDEFINED) { + XmlUtils.writeIntAttribute(xml, XML_ATTR_ORIENTATION, config.orientation); + } + if (config.screenLayout != SCREENLAYOUT_UNDEFINED) { + XmlUtils.writeIntAttribute(xml, XML_ATTR_SCREEN_LAYOUT, config.screenLayout); + } + if (config.uiMode != 0) { + XmlUtils.writeIntAttribute(xml, XML_ATTR_UI_MODE, config.uiMode); + } + if (config.screenWidthDp != SCREEN_WIDTH_DP_UNDEFINED) { + XmlUtils.writeIntAttribute(xml, XML_ATTR_SCREEN_WIDTH, config.screenWidthDp); + } + if (config.screenHeightDp != SCREEN_HEIGHT_DP_UNDEFINED) { + XmlUtils.writeIntAttribute(xml, XML_ATTR_SCREEN_HEIGHT, config.screenHeightDp); + } + if (config.smallestScreenWidthDp != SMALLEST_SCREEN_WIDTH_DP_UNDEFINED) { + XmlUtils.writeIntAttribute(xml, XML_ATTR_SMALLEST_WIDTH, config.smallestScreenWidthDp); + } + if (config.densityDpi != DENSITY_DPI_UNDEFINED) { + XmlUtils.writeIntAttribute(xml, XML_ATTR_DENSITY, config.densityDpi); + } + } } diff --git a/core/java/android/hardware/camera2/CameraDevice.java b/core/java/android/hardware/camera2/CameraDevice.java index 6a9d56544184..097b430e3d99 100644 --- a/core/java/android/hardware/camera2/CameraDevice.java +++ b/core/java/android/hardware/camera2/CameraDevice.java @@ -216,6 +216,128 @@ public abstract class CameraDevice implements AutoCloseable { * <p>Configuring a session with an empty or null list will close the current session, if * any. This can be used to release the current session's target surfaces for another use.</p> * + * <p>While any of the sizes from {@link StreamConfigurationMap#getOutputSizes} can be used when + * a single output stream is configured, a given camera device may not be able to support all + * combination of sizes, formats, and targets when multiple outputs are configured at once. The + * tables below list the maximum guaranteed resolutions for combinations of streams and targets, + * given the capabilities of the camera device.</p> + * + * <p>If an application tries to create a session using a set of targets that exceed the limits + * described in the below tables, one of three possibilities may occur. First, the session may + * be successfully created and work normally. Second, the session may be successfully created, + * but the camera device won't meet the frame rate guarantees as described in + * {@link StreamConfigurationMap#getOutputMinFrameDuration}. Or third, if the output set + * cannot be used at all, session creation will fail entirely, with + * {@link CameraCaptureSession.StateListener#onConfigureFailed} being invoked.</p> + * + * <p>For the type column, {@code PRIV} refers to any target whose available sizes are found + * using {@link StreamConfigurationMap#getOutputSizes(Class)} with no direct application-visible + * format, {@code YUV} refers to a target Surface using the + * {@link android.graphics.ImageFormat#YUV_420_888} format, {@code JPEG} refers to the + * {@link android.graphics.ImageFormat#JPEG} format, and {@code RAW} refers to the + * {@link android.graphics.ImageFormat#RAW_SENSOR} format.</p> + * + * <p>For the maximum size column, {@code PREVIEW} refers to the best size match to the + * device's screen resolution, or to 1080p ({@code 1920x1080}), whichever is + * smaller. {@code RECORD} refers to the camera device's maximum supported recording resolution, + * as determined by {@link android.media.CamcorderProfile}. And {@code MAXIMUM} refers to the + * camera device's maximum output resolution for that format or target from + * {@link StreamConfigurationMap#getOutputSizes}.</p> + * + * <p>To use these tables, determine the number and the formats/targets of outputs needed, and + * find the row(s) of the table with those targets. The sizes indicate the maximum set of sizes + * that can be used; it is guaranteed that for those targets, the listed sizes and anything + * smaller from the list given by {@link StreamConfigurationMap#getOutputSizes} can be + * successfully used to create a session. For example, if a row indicates that a 8 megapixel + * (MP) YUV_420_888 output can be used together with a 2 MP {@code PRIV} output, then a session + * can be created with targets {@code [8 MP YUV, 2 MP PRIV]} or targets {@code [2 MP YUV, 2 MP + * PRIV]}; but a session with targets {@code [8 MP YUV, 4 MP PRIV]}, targets {@code [4 MP YUV, 4 + * MP PRIV]}, or targets {@code [8 MP PRIV, 2 MP YUV]} would not be guaranteed to work, unless + * some other row of the table lists such a combination.</p> + * + * <style scoped> + * #rb { border-right-width: thick; } + * </style> + * <p>Legacy devices ({@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL} + * {@code == }{@link CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY LEGACY}) support at + * least the following stream combinations: + * + * <table> + * <tr><th colspan="7">LEGACY-level guaranteed configurations</th></tr> + * <tr> <th colspan="2" id="rb">Target 1</th> <th colspan="2" id="rb">Target 2</th> <th colspan="2" id="rb">Target 3</th> <th rowspan="2">Sample use case(s)</th> </tr> + * <tr> <th>Type</th><th id="rb">Max size</th> <th>Type</th><th id="rb">Max size</th> <th>Type</th><th id="rb">Max size</th></tr> + * <tr> <td>{@code PRIV}</td><td id="rb">{@code MAXIMUM}</td> <td colspan="2" id="rb"></td> <td colspan="2" id="rb"></td> <td>Simple preview, GPU video processing, or no-preview video recording.</td> </tr> + * <tr> <td>{@code JPEG}</td><td id="rb">{@code MAXIMUM}</td> <td colspan="2" id="rb"></td> <td colspan="2" id="rb"></td> <td>No-viewfinder still image capture.</td> </tr> + * <tr> <td>{@code YUV }</td><td id="rb">{@code MAXIMUM}</td> <td colspan="2" id="rb"></td> <td colspan="2" id="rb"></td> <td>In-application video/image processing.</td> </tr> + * <tr> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code JPEG}</td><td id="rb">{@code MAXIMUM}</td> <td colspan="2" id="rb"></td> <td>Standard still imaging.</td> </tr> + * <tr> <td>{@code YUV }</td><td id="rb">{@code PREVIEW}</td> <td>{@code JPEG}</td><td id="rb">{@code MAXIMUM}</td> <td colspan="2" id="rb"></td> <td>In-app processing plus still capture.</td> </tr> + * <tr> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td> <td colspan="2" id="rb"></td> <td>Standard recording.</td> </tr> + * <tr> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code YUV }</td><td id="rb">{@code PREVIEW}</td> <td colspan="2" id="rb"></td> <td>Preview plus in-app processing.</td> </tr> + * <tr> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code YUV }</td><td id="rb">{@code PREVIEW}</td> <td>{@code JPEG}</td><td id="rb">{@code MAXIMUM}</td> <td>Still capture plus in-app processing.</td> </tr> + * </table><br> + * </p> + * + * <p>Limited-capability ({@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL} + * {@code == }{@link CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED LIMITED}) devices + * support at least the following stream combinations in addition to those for + * {@link CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY LEGACY} devices: + * + * <table> + * <tr><th colspan="7">LIMITED-level additional guaranteed configurations</th></tr> + * <tr><th colspan="2" id="rb">Target 1</th><th colspan="2" id="rb">Target 2</th><th colspan="2" id="rb">Target 3</th> <th rowspan="2">Sample use case(s)</th> </tr> + * <tr><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th></tr> + * <tr> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code PRIV}</td><td id="rb">{@code RECORD }</td> <td colspan="2" id="rb"></td> <td>High-resolution video recording with preview.</td> </tr> + * <tr> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code YUV }</td><td id="rb">{@code RECORD }</td> <td colspan="2" id="rb"></td> <td>High-resolution in-app video processing with preview.</td> </tr> + * <tr> <td>{@code YUV }</td><td id="rb">{@code PREVIEW}</td> <td>{@code YUV }</td><td id="rb">{@code RECORD }</td> <td colspan="2" id="rb"></td> <td>Two-input in-app video processing.</td> </tr> + * <tr> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code PRIV}</td><td id="rb">{@code RECORD }</td> <td>{@code JPEG}</td><td id="rb">{@code RECORD }</td> <td>High-resolution recording with video snapshot.</td> </tr> + * <tr> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code YUV }</td><td id="rb">{@code RECORD }</td> <td>{@code JPEG}</td><td id="rb">{@code RECORD }</td> <td>High-resolution in-app processing with video snapshot.</td> </tr> + * <tr> <td>{@code YUV }</td><td id="rb">{@code PREVIEW}</td> <td>{@code YUV }</td><td id="rb">{@code PREVIEW}</td> <td>{@code JPEG}</td><td id="rb">{@code MAXIMUM}</td> <td>Two-input in-app processing with still capture.</td> </tr> + * </table><br> + * </p> + * + * <p>FULL-capability ({@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL} + * {@code == }{@link CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_FULL FULL}) devices + * support at least the following stream combinations in addition to those for + * {@link CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED LIMITED} devices: + * + * <table> + * <tr><th colspan="7">FULL-capability additional guaranteed configurations</th></tr> + * <tr><th colspan="2" id="rb">Target 1</th><th colspan="2" id="rb">Target 2</th><th colspan="2" id="rb">Target 3</th> <th rowspan="2">Sample use case(s)</th> </tr> + * <tr><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th> </tr> + * <tr> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code PRIV}</td><td id="rb">{@code MAXIMUM}</td> <td colspan="2" id="rb"></td> <td>Maximum-resolution GPU processing with preview.</td> </tr> + * <tr> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code YUV }</td><td id="rb">{@code MAXIMUM}</td> <td colspan="2" id="rb"></td> <td>Maximum-resolution in-app processing with preview.</td> </tr> + * <tr> <td>{@code YUV }</td><td id="rb">{@code PREVIEW}</td> <td>{@code YUV }</td><td id="rb">{@code MAXIMUM}</td> <td colspan="2" id="rb"></td> <td>Maximum-resolution two-input in-app processsing.</td> </tr> + * <tr> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code JPEG}</td><td id="rb">{@code MAXIMUM}</td> <td>Video recording with maximum-size video snapshot</td> </tr> + * <tr> <td>{@code YUV }</td><td id="rb">{@code 640x480}</td> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code YUV }</td><td id="rb">{@code MAXIMUM}</td> <td>Standard video recording plus maximum-resolution in-app processing.</td> </tr> + * <tr> <td>{@code YUV }</td><td id="rb">{@code 640x480}</td> <td>{@code YUV }</td><td id="rb">{@code PREVIEW}</td> <td>{@code YUV }</td><td id="rb">{@code MAXIMUM}</td> <td>Preview plus two-input maximum-resolution in-app processing.</td> </tr> + * </table><br> + * </p> + * + * <p>RAW-capability ({@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES} includes + * {@link CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_RAW RAW}) devices additionally support + * at least the following stream combinations on both + * {@link CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_FULL FULL} and + * {@link CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED LIMITED} devices: + * + * <table> + * <tr><th colspan="7">RAW-capability additional guaranteed configurations</th></tr> + * <tr><th colspan="2" id="rb">Target 1</th><th colspan="2" id="rb">Target 2</th><th colspan="2" id="rb">Target 3</th> <th rowspan="2">Sample use case(s)</th> </tr> + * <tr><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th> </tr> + * <tr> <td>{@code RAW }</td><td id="rb">{@code MAXIMUM}</td> <td colspan="2" id="rb"></td> <td colspan="2" id="rb"></td> <td>No-preview DNG capture.</td> </tr> + * <tr> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code RAW }</td><td id="rb">{@code MAXIMUM}</td> <td colspan="2" id="rb"></td> <td>Standard DNG capture.</td> </tr> + * <tr> <td>{@code YUV }</td><td id="rb">{@code PREVIEW}</td> <td>{@code RAW }</td><td id="rb">{@code MAXIMUM}</td> <td colspan="2" id="rb"></td> <td>In-app processing plus DNG capture.</td> </tr> + * <tr> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code RAW }</td><td id="rb">{@code MAXIMUM}</td> <td>Video recording with DNG capture.</td> </tr> + * <tr> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code YUV }</td><td id="rb">{@code PREVIEW}</td> <td>{@code RAW }</td><td id="rb">{@code MAXIMUM}</td> <td>Preview with in-app processing and DNG capture.</td> </tr> + * <tr> <td>{@code YUV }</td><td id="rb">{@code PREVIEW}</td> <td>{@code YUV }</td><td id="rb">{@code PREVIEW}</td> <td>{@code RAW }</td><td id="rb">{@code MAXIMUM}</td> <td>Two-input in-app processing plus DNG capture.</td> </tr> + * <tr> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code JPEG}</td><td id="rb">{@code MAXIMUM}</td> <td>{@code RAW }</td><td id="rb">{@code MAXIMUM}</td> <td>Still capture with simultaneous JPEG and DNG.</td> </tr> + * <tr> <td>{@code YUV }</td><td id="rb">{@code PREVIEW}</td> <td>{@code JPEG}</td><td id="rb">{@code MAXIMUM}</td> <td>{@code RAW }</td><td id="rb">{@code MAXIMUM}</td> <td>In-app processing with simultaneous JPEG and DNG.</td> </tr> + * </table><br> + * </p> + * + * <p>Since the capabilities of camera devices vary greatly, a given camera device may support + * target combinations with sizes outside of these guarantees, but this can only be tested for + * by attempting to create a session with such targets.</p> + * * @param outputs The new set of Surfaces that should be made available as * targets for captured image data. * @param listener The listener to notify about the status of the new capture session. diff --git a/core/java/android/hardware/camera2/legacy/GLThreadManager.java b/core/java/android/hardware/camera2/legacy/GLThreadManager.java index 06521cf16f59..2c584ef7752c 100644 --- a/core/java/android/hardware/camera2/legacy/GLThreadManager.java +++ b/core/java/android/hardware/camera2/legacy/GLThreadManager.java @@ -121,9 +121,10 @@ public class GLThreadManager { * Create a new GL thread and renderer. * * @param cameraId the camera id for this thread. + * @param facing direction the camera is facing. */ - public GLThreadManager(int cameraId) { - mTextureRenderer = new SurfaceTextureRenderer(); + public GLThreadManager(int cameraId, int facing) { + mTextureRenderer = new SurfaceTextureRenderer(facing); TAG = String.format("CameraDeviceGLThread-%d", cameraId); mGLHandlerThread = new RequestHandlerThread(TAG, mGLHandlerCb); } diff --git a/core/java/android/hardware/camera2/legacy/RequestThreadManager.java b/core/java/android/hardware/camera2/legacy/RequestThreadManager.java index eb8debba0c9e..e6ff17b86455 100644 --- a/core/java/android/hardware/camera2/legacy/RequestThreadManager.java +++ b/core/java/android/hardware/camera2/legacy/RequestThreadManager.java @@ -399,7 +399,7 @@ public class RequestThreadManager { // TODO: Detect and optimize single-output paths here to skip stream teeing. if (mGLThreadManager == null) { - mGLThreadManager = new GLThreadManager(mCameraId); + mGLThreadManager = new GLThreadManager(mCameraId, facing); mGLThreadManager.start(); } mGLThreadManager.waitUntilStarted(); diff --git a/core/java/android/hardware/camera2/legacy/SurfaceTextureRenderer.java b/core/java/android/hardware/camera2/legacy/SurfaceTextureRenderer.java index b1b0f9b485f3..a35883c00070 100644 --- a/core/java/android/hardware/camera2/legacy/SurfaceTextureRenderer.java +++ b/core/java/android/hardware/camera2/legacy/SurfaceTextureRenderer.java @@ -18,6 +18,7 @@ package android.hardware.camera2.legacy; import android.graphics.ImageFormat; import android.graphics.RectF; import android.graphics.SurfaceTexture; +import android.hardware.camera2.CameraCharacteristics; import android.os.Environment; import android.opengl.EGL14; import android.opengl.EGLConfig; @@ -80,7 +81,18 @@ public class SurfaceTextureRenderer { private static final int TRIANGLE_VERTICES_DATA_STRIDE_BYTES = 5 * FLOAT_SIZE_BYTES; private static final int TRIANGLE_VERTICES_DATA_POS_OFFSET = 0; private static final int TRIANGLE_VERTICES_DATA_UV_OFFSET = 3; - private final float[] mTriangleVerticesData = { + + // Sampling is mirrored across the vertical axis to undo horizontal flip from the front camera + private static final float[] sFrontCameraTriangleVertices = { + // X, Y, Z, U, V + -1.0f, -1.0f, 0, 1.f, 0.f, + 1.0f, -1.0f, 0, 0.f, 0.f, + -1.0f, 1.0f, 0, 1.f, 1.f, + 1.0f, 1.0f, 0, 0.f, 1.f, + }; + + // Sampling is 1:1 for a straight copy for the back camera + private static final float[] sBackCameraTriangleVertices = { // X, Y, Z, U, V -1.0f, -1.0f, 0, 0.f, 0.f, 1.0f, -1.0f, 0, 1.f, 0.f, @@ -135,10 +147,16 @@ public class SurfaceTextureRenderer { private PerfMeasurement mPerfMeasurer = null; private static final String LEGACY_PERF_PROPERTY = "persist.camera.legacy_perf"; - public SurfaceTextureRenderer() { - mTriangleVertices = ByteBuffer.allocateDirect(mTriangleVerticesData.length * - FLOAT_SIZE_BYTES).order(ByteOrder.nativeOrder()).asFloatBuffer(); - mTriangleVertices.put(mTriangleVerticesData).position(0); + public SurfaceTextureRenderer(int facing) { + if (facing == CameraCharacteristics.LENS_FACING_BACK) { + mTriangleVertices = ByteBuffer.allocateDirect(sBackCameraTriangleVertices.length * + FLOAT_SIZE_BYTES).order(ByteOrder.nativeOrder()).asFloatBuffer(); + mTriangleVertices.put(sBackCameraTriangleVertices).position(0); + } else { + mTriangleVertices = ByteBuffer.allocateDirect(sFrontCameraTriangleVertices.length * + FLOAT_SIZE_BYTES).order(ByteOrder.nativeOrder()).asFloatBuffer(); + mTriangleVertices.put(sFrontCameraTriangleVertices).position(0); + } Matrix.setIdentityM(mSTMatrix, 0); } diff --git a/core/java/android/hardware/camera2/params/StreamConfigurationMap.java b/core/java/android/hardware/camera2/params/StreamConfigurationMap.java index c0b79678c63c..5d226e393f9f 100644 --- a/core/java/android/hardware/camera2/params/StreamConfigurationMap.java +++ b/core/java/android/hardware/camera2/params/StreamConfigurationMap.java @@ -142,7 +142,7 @@ public final class StreamConfigurationMap { * or in {@link PixelFormat} (and there is no possibility of collision).</p> * * <p>Formats listed in this array are guaranteed to return true if queried with - * {@link #isOutputSupportedFor(int).</p> + * {@link #isOutputSupportedFor(int)}.</p> * * @return an array of integer format * diff --git a/core/java/android/hardware/hdmi/HdmiControlManager.java b/core/java/android/hardware/hdmi/HdmiControlManager.java index 4b5ced99a250..30f3576648c1 100644 --- a/core/java/android/hardware/hdmi/HdmiControlManager.java +++ b/core/java/android/hardware/hdmi/HdmiControlManager.java @@ -55,10 +55,29 @@ public final class HdmiControlManager { public static final int OSD_MESSAGE_ARC_CONNECTED_INVALID_PORT = 1; /** + * Message used by TV to receive volume status from Audio Receiver. It should check volume value + * that is retrieved from extra value with the key {@link #EXTRA_MESSAGE_EXTRAM_PARAM1}. If the + * value is in range of [0,100], it is current volume of Audio Receiver. And there is another + * value, {@link #AVR_VOLUME_MUTED}, which is used to inform volume mute. + */ + public static final int OSD_MESSAGE_AVR_VOLUME_CHANGED = 2; + + /** * Used as an extra field in the intent {@link #ACTION_OSD_MESSAGE}. Contains the ID of * the message to display on screen. */ public static final String EXTRA_MESSAGE_ID = "android.hardware.hdmi.extra.MESSAGE_ID"; + /** + * Used as an extra field in the intent {@link #ACTION_OSD_MESSAGE}. Contains the extra value + * of the message. + */ + public static final String EXTRA_MESSAGE_EXTRAM_PARAM1 = + "android.hardware.hdmi.extra.MESSAGE_EXTRA_PARAM1"; + + /** + * Volume value for mute state. + */ + public static final int AVR_VOLUME_MUTED = 101; public static final int POWER_STATUS_UNKNOWN = -1; public static final int POWER_STATUS_ON = 0; diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 3c219fd5ed37..70b402d8fcf6 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -1298,7 +1298,7 @@ public class ConnectivityManager { } /** - * Callback for use with {@link ConnectivityManager#registerDefaultNetworkActiveListener} + * Callback for use with {@link ConnectivityManager#addDefaultNetworkActiveListener} * to find out when the system default network has gone in to a high power state. */ public interface OnNetworkActiveListener { @@ -1340,7 +1340,7 @@ public class ConnectivityManager { * * @param l The listener to be told when the network is active. */ - public void registerDefaultNetworkActiveListener(final OnNetworkActiveListener l) { + public void addDefaultNetworkActiveListener(final OnNetworkActiveListener l) { INetworkActivityListener rl = new INetworkActivityListener.Stub() { @Override public void onNetworkActive() throws RemoteException { @@ -1357,11 +1357,11 @@ public class ConnectivityManager { /** * Remove network active listener previously registered with - * {@link #registerDefaultNetworkActiveListener}. + * {@link #addDefaultNetworkActiveListener}. * * @param l Previously registered listener. */ - public void unregisterDefaultNetworkActiveListener(OnNetworkActiveListener l) { + public void removeDefaultNetworkActiveListener(OnNetworkActiveListener l) { INetworkActivityListener rl = mNetworkActivityListeners.get(l); if (rl == null) { throw new IllegalArgumentException("Listener not registered: " + l); diff --git a/core/java/android/net/LinkAddress.java b/core/java/android/net/LinkAddress.java index f9a25f9ed265..c387055741f4 100644 --- a/core/java/android/net/LinkAddress.java +++ b/core/java/android/net/LinkAddress.java @@ -274,7 +274,6 @@ public class LinkAddress implements Parcelable { /** * Implement the Parcelable interface. - * @hide */ public int describeContents() { return 0; @@ -282,7 +281,6 @@ public class LinkAddress implements Parcelable { /** * Implement the Parcelable interface. - * @hide */ public void writeToParcel(Parcel dest, int flags) { dest.writeByteArray(address.getAddress()); @@ -293,7 +291,6 @@ public class LinkAddress implements Parcelable { /** * Implement the Parcelable interface. - * @hide */ public static final Creator<LinkAddress> CREATOR = new Creator<LinkAddress>() { diff --git a/core/java/android/net/NetworkRequest.java b/core/java/android/net/NetworkRequest.java index 83bdfaab0286..5a09b460b6a8 100644 --- a/core/java/android/net/NetworkRequest.java +++ b/core/java/android/net/NetworkRequest.java @@ -52,6 +52,9 @@ public class NetworkRequest implements Parcelable { * @hide */ public NetworkRequest(NetworkCapabilities nc, int legacyType, int rId) { + if (nc == null) { + throw new NullPointerException(); + } requestId = rId; networkCapabilities = nc; this.legacyType = legacyType; diff --git a/core/java/android/net/ProxyInfo.java b/core/java/android/net/ProxyInfo.java index 7ea6bae83d2c..1534e2c7f4b1 100644 --- a/core/java/android/net/ProxyInfo.java +++ b/core/java/android/net/ProxyInfo.java @@ -334,10 +334,6 @@ public class ProxyInfo implements Parcelable { dest.writeStringArray(mParsedExclusionList); } - /** - * Implement the Parcelable interface. - * @hide - */ public static final Creator<ProxyInfo> CREATOR = new Creator<ProxyInfo>() { public ProxyInfo createFromParcel(Parcel in) { diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java index b0e0b4972a58..1e0dc53e1286 100644 --- a/core/java/android/os/Build.java +++ b/core/java/android/os/Build.java @@ -541,7 +541,7 @@ public class Build { * Intent.</li> * </ul> */ - public static final int L = CUR_DEVELOPMENT; + public static final int L = 21; } /** The type of build, like "user" or "eng". */ diff --git a/core/java/android/os/Bundle.java b/core/java/android/os/Bundle.java index 3252d195ae2b..a9aa570dd5fd 100644 --- a/core/java/android/os/Bundle.java +++ b/core/java/android/os/Bundle.java @@ -17,6 +17,8 @@ package android.os; import android.util.ArrayMap; +import android.util.Size; +import android.util.SizeF; import android.util.SparseArray; import java.io.Serializable; @@ -335,6 +337,30 @@ public final class Bundle extends BaseBundle implements Cloneable, Parcelable { } /** + * Inserts a Size value into the mapping of this Bundle, replacing + * any existing value for the given key. Either key or value may be null. + * + * @param key a String, or null + * @param value a Size object, or null + */ + public void putSize(String key, Size value) { + unparcel(); + mMap.put(key, value); + } + + /** + * Inserts a SizeF value into the mapping of this Bundle, replacing + * any existing value for the given key. Either key or value may be null. + * + * @param key a String, or null + * @param value a SizeF object, or null + */ + public void putSizeF(String key, SizeF value) { + unparcel(); + mMap.put(key, value); + } + + /** * Inserts an array of Parcelable values into the mapping of this Bundle, * replacing any existing value for the given key. Either key or value may * be null. @@ -712,6 +738,44 @@ public final class Bundle extends BaseBundle implements Cloneable, Parcelable { * value is explicitly associated with the key. * * @param key a String, or null + * @return a Size value, or null + */ + public Size getSize(String key) { + unparcel(); + final Object o = mMap.get(key); + try { + return (Size) o; + } catch (ClassCastException e) { + typeWarning(key, o, "Size", e); + return null; + } + } + + /** + * Returns the value associated with the given key, or null if + * no mapping of the desired type exists for the given key or a null + * value is explicitly associated with the key. + * + * @param key a String, or null + * @return a Size value, or null + */ + public SizeF getSizeF(String key) { + unparcel(); + final Object o = mMap.get(key); + try { + return (SizeF) o; + } catch (ClassCastException e) { + typeWarning(key, o, "SizeF", e); + return null; + } + } + + /** + * Returns the value associated with the given key, or null if + * no mapping of the desired type exists for the given key or a null + * value is explicitly associated with the key. + * + * @param key a String, or null * @return a Bundle value, or null */ public Bundle getBundle(String key) { diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java index 645d510b45c1..d1ad0ad41941 100644 --- a/core/java/android/os/Parcel.java +++ b/core/java/android/os/Parcel.java @@ -19,6 +19,8 @@ package android.os; import android.text.TextUtils; import android.util.ArrayMap; import android.util.Log; +import android.util.Size; +import android.util.SizeF; import android.util.SparseArray; import android.util.SparseBooleanArray; @@ -224,6 +226,8 @@ public final class Parcel { private static final int VAL_BOOLEANARRAY = 23; private static final int VAL_CHARSEQUENCEARRAY = 24; private static final int VAL_PERSISTABLEBUNDLE = 25; + private static final int VAL_SIZE = 26; + private static final int VAL_SIZEF = 27; // The initial int32 in a Binder call's reply Parcel header: private static final int EX_SECURITY = -1; @@ -672,6 +676,24 @@ public final class Parcel { } /** + * Flatten a Size into the parcel at the current dataPosition(), + * growing dataCapacity() if needed. + */ + public final void writeSize(Size val) { + writeInt(val.getWidth()); + writeInt(val.getHeight()); + } + + /** + * Flatten a SizeF into the parcel at the current dataPosition(), + * growing dataCapacity() if needed. + */ + public final void writeSizeF(SizeF val) { + writeFloat(val.getWidth()); + writeFloat(val.getHeight()); + } + + /** * Flatten a List into the parcel at the current dataPosition(), growing * dataCapacity() if needed. The List values are written using * {@link #writeValue} and must follow the specification there. @@ -1293,6 +1315,12 @@ public final class Parcel { } else if (v instanceof PersistableBundle) { writeInt(VAL_PERSISTABLEBUNDLE); writePersistableBundle((PersistableBundle) v); + } else if (v instanceof Size) { + writeInt(VAL_SIZE); + writeSize((Size) v); + } else if (v instanceof SizeF) { + writeInt(VAL_SIZEF); + writeSizeF((SizeF) v); } else { Class<?> clazz = v.getClass(); if (clazz.isArray() && clazz.getComponentType() == Object.class) { @@ -1699,6 +1727,24 @@ public final class Parcel { } /** + * Read a Size from the parcel at the current dataPosition(). + */ + public final Size readSize() { + final int width = readInt(); + final int height = readInt(); + return new Size(width, height); + } + + /** + * Read a SizeF from the parcel at the current dataPosition(). + */ + public final SizeF readSizeF() { + final float width = readFloat(); + final float height = readFloat(); + return new SizeF(width, height); + } + + /** * Read and return a byte[] object from the parcel. */ public final byte[] createByteArray() { @@ -2160,6 +2206,12 @@ public final class Parcel { case VAL_PERSISTABLEBUNDLE: return readPersistableBundle(loader); + case VAL_SIZE: + return readSize(); + + case VAL_SIZEF: + return readSizeF(); + default: int off = dataPosition() - 4; throw new RuntimeException( diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java index 59220e1d0a37..ec77a5e21ceb 100644 --- a/core/java/android/os/UserManager.java +++ b/core/java/android/os/UserManager.java @@ -22,10 +22,7 @@ import android.content.Context; import android.content.pm.UserInfo; import android.content.res.Resources; import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.graphics.Bitmap.Config; import android.graphics.Rect; -import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.provider.Settings; import android.util.Log; @@ -660,6 +657,7 @@ public class UserManager { try { Bundle guestRestrictions = mService.getDefaultGuestRestrictions(); guestRestrictions.putBoolean(DISALLOW_SMS, true); + guestRestrictions.putBoolean(DISALLOW_INSTALL_UNKNOWN_SOURCES, true); mService.setUserRestrictions(guestRestrictions, guest.id); } catch (RemoteException re) { Log.w(TAG, "Could not update guest restrictions"); @@ -837,46 +835,10 @@ public class UserManager { * @param user The target user. * @return A drawable that combines the original icon and a badge as * determined by the system. + * @removed */ public Drawable getBadgedIconForUser(Drawable icon, UserHandle user) { - final int badgeResId = getBadgeResIdForUser(user.getIdentifier()); - if (badgeResId == 0) { - return icon; - } - Drawable badgeIcon = mContext.getPackageManager() - .getDrawable("system", badgeResId, null); - return getBadgedDrawable(icon, badgeIcon, null, true); - } - - /** - * If the target user is a managed profile of the calling user or the caller - * is itself a managed profile, then this returns a badged copy of the given - * icon to be able to distinguish it from the original icon. - * <p> - * If the original drawable is not a BitmapDrawable, then the original - * drawable is returned. - * </p> - * - * @param icon The icon to badge. - * @param user The target user. - * @return A drawable that combines the original icon and a badge as - * determined by the system. - * - * @deprecation Use {@link #getBadgedIconForUser( - * android.graphics.drawable.Drawable, UserHandle)} - * - * @hide - */ - @Deprecated - public Drawable getBadgedDrawableForUser(Drawable icon, UserHandle user) { - int badgeResId = getBadgeResIdForUser(user.getIdentifier()); - if (badgeResId == 0) { - return icon; - } else { - Drawable badgeIcon = mContext.getPackageManager() - .getDrawable("system", badgeResId, null); - return getBadgedDrawable(icon, badgeIcon, null, false); - } + return mContext.getPackageManager().getUserBadgedIcon(icon, user); } /** @@ -902,14 +864,12 @@ public class UserManager { * the density of the display is used. * @return A drawable that combines the original drawable and a badge as * determined by the system. + * @removed */ public Drawable getBadgedDrawableForUser(Drawable badgedDrawable, UserHandle user, Rect badgeLocation, int badgeDensity) { - Drawable badgeDrawable = getBadgeForUser(user, badgeDensity); - if (badgeDrawable == null) { - return badgedDrawable; - } - return getBadgedDrawable(badgedDrawable, badgeDrawable, badgeLocation, true); + return mContext.getPackageManager().getUserBadgedDrawableForDensity(badgedDrawable, user, + badgeLocation, badgeDensity); } /** @@ -922,114 +882,10 @@ public class UserManager { * @param user The target user. * @return A label that combines the original label and a badge as * determined by the system. + * @removed */ public CharSequence getBadgedLabelForUser(CharSequence label, UserHandle user) { - UserInfo userInfo = getUserIfProfile(user.getIdentifier()); - if (userInfo != null && userInfo.isManagedProfile()) { - return Resources.getSystem().getString( - R.string.managed_profile_label_badge, label); - } - return label; - } - - /** - * If the target user is a managed profile of the calling user or the caller - * is itself a managed profile, then this returns a drawable to use as a small - * icon to include in a view to distinguish it from the original icon. - * - * @param user The target user. - * @param density The optional desired density for the badge as per - * {@link android.util.DisplayMetrics#densityDpi}. If not provided - * the density of the current display is used. - * @return the drawable or null if no drawable is required. - * @hide - */ - public Drawable getBadgeForUser(UserHandle user, int density) { - UserInfo userInfo = getUserIfProfile(user.getIdentifier()); - if (userInfo != null && userInfo.isManagedProfile()) { - if (density <= 0) { - density = mContext.getResources().getDisplayMetrics().densityDpi; - } - return Resources.getSystem().getDrawableForDensity( - com.android.internal.R.drawable.ic_corp_badge, density); - } - return null; - } - - private int getBadgeResIdForUser(int userHandle) { - // Return the framework-provided badge. - UserInfo userInfo = getUserIfProfile(userHandle); - if (userInfo != null && userInfo.isManagedProfile()) { - return com.android.internal.R.drawable.ic_corp_icon_badge; - } - return 0; - } - - /** - * @return UserInfo for userHandle if it exists and is a profile of the current - * user or null. - */ - private UserInfo getUserIfProfile(int userHandle) { - List<UserInfo> userProfiles = getProfiles(getUserHandle()); - for (UserInfo user : userProfiles) { - if (user.id == userHandle) { - return user; - } - } - return null; - } - - private Drawable getBadgedDrawable(Drawable badgedDrawable, Drawable badgeDrawable, - Rect badgeLocation, boolean tryBadgeInPlace) { - final int badgedWidth = badgedDrawable.getIntrinsicWidth(); - final int badgedHeight = badgedDrawable.getIntrinsicHeight(); - final boolean canBadgeInPlace = tryBadgeInPlace - && (badgedDrawable instanceof BitmapDrawable) - && ((BitmapDrawable) badgedDrawable).getBitmap().isMutable(); - - final Bitmap bitmap; - if (canBadgeInPlace) { - bitmap = ((BitmapDrawable) badgedDrawable).getBitmap(); - } else { - bitmap = Bitmap.createBitmap(badgedWidth, badgedHeight, Config.ARGB_8888); - } - Canvas canvas = new Canvas(bitmap); - - if (!canBadgeInPlace) { - badgedDrawable.setBounds(0, 0, badgedWidth, badgedHeight); - badgedDrawable.draw(canvas); - } - - if (badgeLocation != null) { - if (badgeLocation.left < 0 || badgeLocation.top < 0 - || badgeLocation.width() > badgedWidth || badgeLocation.height() > badgedHeight) { - throw new IllegalArgumentException("Badge location " + badgeLocation - + " not in badged drawable bounds " - + new Rect(0, 0, badgedWidth, badgedHeight)); - } - badgeDrawable.setBounds(0, 0, badgeLocation.width(), badgeLocation.height()); - - canvas.save(); - canvas.translate(badgeLocation.left, badgeLocation.top); - badgeDrawable.draw(canvas); - canvas.restore(); - } else { - badgeDrawable.setBounds(0, 0, badgedWidth, badgedHeight); - badgeDrawable.draw(canvas); - } - - if (!canBadgeInPlace) { - BitmapDrawable mergedDrawable = new BitmapDrawable(mContext.getResources(), bitmap); - - if (badgedDrawable instanceof BitmapDrawable) { - BitmapDrawable bitmapDrawable = (BitmapDrawable) badgedDrawable; - mergedDrawable.setTargetDensity(bitmapDrawable.getBitmap().getDensity()); - } - - return mergedDrawable; - } - - return badgedDrawable; + return mContext.getPackageManager().getUserBadgedLabel(label, user); } /** diff --git a/core/java/android/provider/CallLog.java b/core/java/android/provider/CallLog.java index 0202f91fbded..5fa1cc95d43b 100644 --- a/core/java/android/provider/CallLog.java +++ b/core/java/android/provider/CallLog.java @@ -116,8 +116,8 @@ public class CallLog { * </pre> * </p> */ - public static final String EXTRA_CALL_TYPE_FILTER - = "android.provider.extra.call_type_filter"; + public static final String EXTRA_CALL_TYPE_FILTER = + "android.provider.extra.CALL_TYPE_FILTER"; /** * Content uri used to access call log entries, including voicemail records. You must have diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java index 27473e393b06..18a9eb1d0e8b 100644 --- a/core/java/android/provider/ContactsContract.java +++ b/core/java/android/provider/ContactsContract.java @@ -1125,7 +1125,7 @@ public final class ContactsContract { * import android.provider.ContactsContract.Contacts; * * Uri uri = Contacts.CONTENT_URI.buildUpon() - * .appendQueryParameter(Contacts.ADDRESS_BOOK_INDEX_EXTRAS, "true") + * .appendQueryParameter(Contacts.EXTRA_ADDRESS_BOOK_INDEX, "true") * .build(); * Cursor cursor = getContentResolver().query(uri, * new String[] {Contacts.DISPLAY_NAME}, @@ -1140,21 +1140,24 @@ public final class ContactsContract { * </pre> * </p> */ - public static final String ADDRESS_BOOK_INDEX_EXTRAS = "address_book_index_extras"; + public static final String EXTRA_ADDRESS_BOOK_INDEX = + "android.provider.extra.ADDRESS_BOOK_INDEX"; /** * The array of address book index titles, which are returned in the * same order as the data in the cursor. * <p>TYPE: String[]</p> */ - public static final String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "address_book_index_titles"; + public static final String EXTRA_ADDRESS_BOOK_INDEX_TITLES = + "android.provider.extra.ADDRESS_BOOK_INDEX_TITLES"; /** * The array of group counts for the corresponding group. Contains the same number * of elements as the EXTRA_ADDRESS_BOOK_INDEX_TITLES array. * <p>TYPE: int[]</p> */ - public static final String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "address_book_index_counts"; + public static final String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = + "android.provider.extra.ADDRESS_BOOK_INDEX_COUNTS"; } /** @@ -8111,7 +8114,7 @@ public final class ContactsContract { * for the provided {@link Contacts} entry. */ public static final String ACTION_QUICK_CONTACT = - "com.android.contacts.action.QUICK_CONTACT"; + "android.provider.action.QUICK_CONTACT"; /** * Extra used to specify pivot dialog location in screen coordinates. diff --git a/core/java/android/service/voice/AlwaysOnHotwordDetector.java b/core/java/android/service/voice/AlwaysOnHotwordDetector.java index 519bc282a8fa..4de5f41e308d 100644 --- a/core/java/android/service/voice/AlwaysOnHotwordDetector.java +++ b/core/java/android/service/voice/AlwaysOnHotwordDetector.java @@ -450,7 +450,7 @@ public class AlwaysOnHotwordDetector { * This intent must be invoked using {@link Activity#startActivityForResult(Intent, int)}. * Starting re-enrollment is only valid if the keyphrase is un-enrolled, * i.e. {@link #STATE_KEYPHRASE_UNENROLLED}, - * otherwise {@link #createIntentToReEnroll()} should be preferred. + * otherwise {@link #createReEnrollIntent()} should be preferred. * * @return An {@link Intent} to start enrollment for the given keyphrase. * @throws UnsupportedOperationException if managing they keyphrase isn't supported. @@ -460,6 +460,19 @@ public class AlwaysOnHotwordDetector { * This may happen if another detector has been instantiated or the * {@link VoiceInteractionService} hosting this detector has been shut down. */ + public Intent createEnrollIntent() { + if (DBG) Slog.d(TAG, "createEnrollIntent"); + synchronized (mLock) { + return getManageIntentLocked(MANAGE_ACTION_ENROLL); + } + } + + /** + * FIXME: Remove once the prebuilts are updated. + * + * @hide + */ + @Deprecated public Intent createIntentToEnroll() { if (DBG) Slog.d(TAG, "createIntentToEnroll"); synchronized (mLock) { @@ -481,6 +494,19 @@ public class AlwaysOnHotwordDetector { * This may happen if another detector has been instantiated or the * {@link VoiceInteractionService} hosting this detector has been shut down. */ + public Intent createUnEnrollIntent() { + if (DBG) Slog.d(TAG, "createUnEnrollIntent"); + synchronized (mLock) { + return getManageIntentLocked(MANAGE_ACTION_UN_ENROLL); + } + } + + /** + * FIXME: Remove once the prebuilts are updated. + * + * @hide + */ + @Deprecated public Intent createIntentToUnEnroll() { if (DBG) Slog.d(TAG, "createIntentToUnEnroll"); synchronized (mLock) { @@ -502,6 +528,19 @@ public class AlwaysOnHotwordDetector { * This may happen if another detector has been instantiated or the * {@link VoiceInteractionService} hosting this detector has been shut down. */ + public Intent createReEnrollIntent() { + if (DBG) Slog.d(TAG, "createReEnrollIntent"); + synchronized (mLock) { + return getManageIntentLocked(MANAGE_ACTION_RE_ENROLL); + } + } + + /** + * FIXME: Remove once the prebuilts are updated. + * + * @hide + */ + @Deprecated public Intent createIntentToReEnroll() { if (DBG) Slog.d(TAG, "createIntentToReEnroll"); synchronized (mLock) { diff --git a/core/java/android/text/Layout.java b/core/java/android/text/Layout.java index 7dce34875d49..2b53c4862d44 100644 --- a/core/java/android/text/Layout.java +++ b/core/java/android/text/Layout.java @@ -727,10 +727,9 @@ public abstract class Layout { int[] runs = dirs.mDirections; int lineStart = getLineStart(line); for (int i = 0; i < runs.length; i += 2) { - int start = lineStart + (runs[i] & RUN_LENGTH_MASK); - // No need to test the end as an offset after the last run should return the value - // corresponding of the last run - if (offset >= start) { + int start = lineStart + runs[i]; + int limit = start + (runs[i+1] & RUN_LENGTH_MASK); + if (offset >= start && offset < limit) { int level = (runs[i+1] >>> RUN_LEVEL_SHIFT) & RUN_LEVEL_MASK; return ((level & 1) != 0); } diff --git a/core/java/android/text/Selection.java b/core/java/android/text/Selection.java index 679e2ccfa91f..3222dbf8718e 100644 --- a/core/java/android/text/Selection.java +++ b/core/java/android/text/Selection.java @@ -116,7 +116,8 @@ public class Selection { /** * Move the cursor to the buffer offset physically above the current - * offset, or return false if the cursor is already on the top line. + * offset, to the beginning if it is on the top line but not at the + * start, or return false if the cursor is already on the top line. */ public static boolean moveUp(Spannable text, Layout layout) { int start = getSelectionStart(text); @@ -149,6 +150,9 @@ public class Selection { setSelection(text, move); return true; + } else if (end != 0) { + setSelection(text, 0); + return true; } } @@ -157,7 +161,9 @@ public class Selection { /** * Move the cursor to the buffer offset physically below the current - * offset, or return false if the cursor is already on the bottom line. + * offset, to the end of the buffer if it is on the bottom line but + * not at the end, or return false if the cursor is already at the + * end of the buffer. */ public static boolean moveDown(Spannable text, Layout layout) { int start = getSelectionStart(text); @@ -190,6 +196,9 @@ public class Selection { setSelection(text, move); return true; + } else if (end != text.length()) { + setSelection(text, text.length()); + return true; } } diff --git a/core/java/android/text/format/DateFormat.java b/core/java/android/text/format/DateFormat.java index 1e411b45b6cb..9fec9a1f5a31 100755 --- a/core/java/android/text/format/DateFormat.java +++ b/core/java/android/text/format/DateFormat.java @@ -17,7 +17,6 @@ package android.text.format; import android.content.Context; -import android.os.UserHandle; import android.provider.Settings; import android.text.SpannableStringBuilder; import android.text.Spanned; @@ -129,14 +128,8 @@ public class DateFormat { * @return true if 24 hour time format is selected, false otherwise. */ public static boolean is24HourFormat(Context context) { - // This method is called by View classes that can be used by RemoteViews - // and rendered in another user. The context therefore may reference - // a user that would require interact accross users to access. So - // use the user id we are running as. - // This is the case when we have widgets from a user profile added - // to the homescreen. - String value = Settings.System.getStringForUser(context.getContentResolver(), - Settings.System.TIME_12_24, UserHandle.myUserId()); + String value = Settings.System.getString(context.getContentResolver(), + Settings.System.TIME_12_24); if (value == null) { Locale locale = context.getResources().getConfiguration().locale; @@ -234,14 +227,8 @@ public class DateFormat { * @return the {@link java.text.DateFormat} object that properly formats the date. */ public static java.text.DateFormat getDateFormat(Context context) { - // This method is called by View classes that can be used by RemoteViews - // and rendered in another user. The context therefore may reference - // a user that would require interact accross users to access. So - // use the user id we are running as. - // This is the case when we have widgets from a user profile added - // to the homescreen. - String value = Settings.System.getStringForUser(context.getContentResolver(), - Settings.System.DATE_FORMAT, UserHandle.myUserId()); + String value = Settings.System.getString(context.getContentResolver(), + Settings.System.DATE_FORMAT); return getDateFormatForSetting(context, value); } diff --git a/core/java/android/transition/ArcMotion.java b/core/java/android/transition/ArcMotion.java index a27063d26a1c..f95fb491ea1a 100644 --- a/core/java/android/transition/ArcMotion.java +++ b/core/java/android/transition/ArcMotion.java @@ -41,9 +41,9 @@ import android.util.FloatMath; * {@code * <changeBounds> * <arcMotion android:minimumHorizontalAngle="15" - * android:minimumVerticalAngle="0" android:maximumAngle="90"/> - * </changeBounds> - * } + * android:minimumVerticalAngle="0" + * android:maximumAngle="90"/> + * </changeBounds>} * </pre> */ public class ArcMotion extends PathMotion { diff --git a/core/java/android/transition/ChangeTransform.java b/core/java/android/transition/ChangeTransform.java index cb0a8758b840..1b8d57c59dd0 100644 --- a/core/java/android/transition/ChangeTransform.java +++ b/core/java/android/transition/ChangeTransform.java @@ -99,6 +99,7 @@ public class ChangeTransform extends Transition { * @return <code>true</code> when a changed parent should execute the transition * inside the scene root's overlay or <code>false</code> if a parent change only * affects the transform of the transitioning view. + * @attr ref android.R.styleable#ChangeTransform_reparentWithOverlay */ public boolean getReparentWithOverlay() { return mUseOverlay; @@ -120,6 +121,7 @@ public class ChangeTransform extends Transition { * @return <code>true</code> when a changed parent should execute the transition * inside the scene root's overlay or <code>false</code> if a parent change only * affects the transform of the transitioning view. + * @attr ref android.R.styleable#ChangeTransform_reparentWithOverlay */ public void setReparentWithOverlay(boolean reparentWithOverlay) { mUseOverlay = reparentWithOverlay; @@ -132,6 +134,7 @@ public class ChangeTransform extends Transition { * view will be tracked. Default is true. * * @return whether parent changes will be tracked by the ChangeTransform. + * @attr ref android.R.styleable#ChangeTransform_reparent */ public boolean getReparent() { return mReparent; @@ -145,6 +148,7 @@ public class ChangeTransform extends Transition { * * @param reparent Set to true to track parent changes or false to only track changes * of the transitioning view without considering the parent change. + * @attr ref android.R.styleable#ChangeTransform_reparent */ public void setReparent(boolean reparent) { mReparent = reparent; diff --git a/core/java/android/transition/PatternMotion.java b/core/java/android/transition/PatternPathMotion.java index e4045b40576a..a609df6a0a39 100644 --- a/core/java/android/transition/PatternMotion.java +++ b/core/java/android/transition/PatternPathMotion.java @@ -34,36 +34,35 @@ import android.util.PathParser; * <pre> * {@code * <changeBounds> - * <patternMotion android:pathData="M0 0 L0 100 L100 100"/> - * </changeBounds> - * } + * <patternPathMotion android:patternPathData="M0 0 L0 100 L100 100"/> + * </changeBounds>} * </pre> */ -public class PatternMotion extends PathMotion { +public class PatternPathMotion extends PathMotion { - private Path mOriginalPattern; + private Path mOriginalPatternPath; - private final Path mPattern = new Path(); + private final Path mPatternPath = new Path(); private final Matrix mTempMatrix = new Matrix(); /** - * Constructs a PatternMotion with a straight-line pattern. + * Constructs a PatternPathMotion with a straight-line pattern. */ - public PatternMotion() { - mPattern.lineTo(1, 0); - mOriginalPattern = mPattern; + public PatternPathMotion() { + mPatternPath.lineTo(1, 0); + mOriginalPatternPath = mPatternPath; } - public PatternMotion(Context context, AttributeSet attrs) { - TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.PatternMotion); + public PatternPathMotion(Context context, AttributeSet attrs) { + TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.PatternPathMotion); try { - String pathData = a.getString(R.styleable.PatternMotion_pathData); + String pathData = a.getString(R.styleable.PatternPathMotion_patternPathData); if (pathData == null) { - throw new RuntimeException("pathData must be supplied for patternMotion"); + throw new RuntimeException("pathData must be supplied for patternPathMotion"); } Path pattern = PathParser.createPathFromPathData(pathData); - setPattern(pattern); + setPatternPath(pattern); } finally { a.recycle(); } @@ -71,14 +70,15 @@ public class PatternMotion extends PathMotion { } /** - * Creates a PatternMotion with the Path defining a pattern of motion between two coordinates. - * The pattern will be translated, rotated, and scaled to fit between the start and end points. - * The pattern must not be empty and must have the end point differ from the start point. + * Creates a PatternPathMotion with the Path defining a pattern of motion between two + * coordinates. The pattern will be translated, rotated, and scaled to fit between the start + * and end points. The pattern must not be empty and must have the end point differ from the + * start point. * - * @param pattern A Path to be used as a pattern for two-dimensional motion. + * @param patternPath A Path to be used as a pattern for two-dimensional motion. */ - public PatternMotion(Path pattern) { - setPattern(pattern); + public PatternPathMotion(Path patternPath) { + setPatternPath(patternPath); } /** @@ -87,10 +87,10 @@ public class PatternMotion extends PathMotion { * The pattern must not be empty and must have the end point differ from the start point. * * @return the Path defining a pattern of motion between two coordinates. - * @attr ref android.R.styleable#PatternMotion_pathData + * @attr ref android.R.styleable#PatternPathMotion_patternPathData */ - public Path getPattern() { - return mOriginalPattern; + public Path getPatternPath() { + return mOriginalPatternPath; } /** @@ -98,11 +98,11 @@ public class PatternMotion extends PathMotion { * The pattern will be translated, rotated, and scaled to fit between the start and end points. * The pattern must not be empty and must have the end point differ from the start point. * - * @param pattern A Path to be used as a pattern for two-dimensional motion. - * @attr ref android.R.styleable#PatternMotion_pathData + * @param patternPath A Path to be used as a pattern for two-dimensional motion. + * @attr ref android.R.styleable#PatternPathMotion_patternPathData */ - public void setPattern(Path pattern) { - PathMeasure pathMeasure = new PathMeasure(pattern, false); + public void setPatternPath(Path patternPath) { + PathMeasure pathMeasure = new PathMeasure(patternPath, false); float length = pathMeasure.getLength(); float[] pos = new float[2]; pathMeasure.getPosTan(length, pos, null); @@ -124,8 +124,8 @@ public class PatternMotion extends PathMotion { mTempMatrix.postScale(scale, scale); double angle = Math.atan2(dy, dx); mTempMatrix.postRotate((float) Math.toDegrees(-angle)); - pattern.transform(mTempMatrix, mPattern); - mOriginalPattern = pattern; + patternPath.transform(mTempMatrix, mPatternPath); + mOriginalPatternPath = patternPath; } @Override @@ -139,7 +139,7 @@ public class PatternMotion extends PathMotion { mTempMatrix.postRotate((float) Math.toDegrees(angle)); mTempMatrix.postTranslate(startX, startY); Path path = new Path(); - mPattern.transform(mTempMatrix, path); + mPatternPath.transform(mTempMatrix, path); return path; } diff --git a/core/java/android/transition/Transition.java b/core/java/android/transition/Transition.java index bd52e714a025..0d1b56814ca6 100644 --- a/core/java/android/transition/Transition.java +++ b/core/java/android/transition/Transition.java @@ -1989,8 +1989,33 @@ public abstract class Transition implements Cloneable { * by extending PathMotion and implementing * {@link android.transition.PathMotion#getPath(float, float, float, float)}. * </p> + * <p> + * When describing in XML, use a nested XML tag for the path motion. It can be one of + * the built-in tags <code>arcMotion</code> or <code>patternPathMotion</code> or it can + * be a custom PathMotion using <code>pathMotion</code> with the <code>class</code> + * attributed with the fully-described class name. For example:</p> + * <pre> + * {@code + * <changeBounds> + * <pathMotion class="my.app.transition.MyPathMotion"/> + * </changeBounds> + * } + * </pre> + * <p>or</p> + * <pre> + * {@code + * <changeBounds> + * <arcMotion android:minimumHorizontalAngle="15" + * android:minimumVerticalAngle="0" android:maximumAngle="90"/> + * </changeBounds> + * } + * </pre> + * * @param pathMotion Algorithm object to use for determining how to interpolate in two * dimensions. If null, a straight-path algorithm will be used. + * @see android.transition.ArcMotion + * @see PatternPathMotion + * @see android.transition.PathMotion */ public void setPathMotion(PathMotion pathMotion) { if (pathMotion == null) { @@ -2004,7 +2029,31 @@ public abstract class Transition implements Cloneable { * Returns the algorithm object used to interpolate along two dimensions. This is typically * used to determine the View motion between two points. * + * <p> + * When describing in XML, use a nested XML tag for the path motion. It can be one of + * the built-in tags <code>arcMotion</code> or <code>patternPathMotion</code> or it can + * be a custom PathMotion using <code>pathMotion</code> with the <code>class</code> + * attributed with the fully-described class name. For example:</p> + * <pre> + * {@code + * <changeBounds> + * <pathMotion class="my.app.transition.MyPathMotion"/> + * </changeBounds>} + * </pre> + * <p>or</p> + * <pre> + * {@code + * <changeBounds> + * <arcMotion android:minimumHorizontalAngle="15" + * android:minimumVerticalAngle="0" + * android:maximumAngle="90"/> + * </changeBounds>} + * </pre> + * * @return The algorithm object used to interpolate along two dimensions. + * @see android.transition.ArcMotion + * @see PatternPathMotion + * @see android.transition.PathMotion */ public PathMotion getPathMotion() { return mPathMotion; diff --git a/core/java/android/transition/TransitionInflater.java b/core/java/android/transition/TransitionInflater.java index 760ffe1814b9..9009d6ab08d5 100644 --- a/core/java/android/transition/TransitionInflater.java +++ b/core/java/android/transition/TransitionInflater.java @@ -171,8 +171,8 @@ public class TransitionInflater { parent.setPathMotion(new ArcMotion(mContext, attrs)); } else if ("pathMotion".equals(name)) { parent.setPathMotion((PathMotion)createCustom(attrs, PathMotion.class, "pathMotion")); - } else if ("patternMotion".equals(name)) { - parent.setPathMotion(new PatternMotion(mContext, attrs)); + } else if ("patternPathMotion".equals(name)) { + parent.setPathMotion(new PatternPathMotion(mContext, attrs)); } else { throw new RuntimeException("Unknown scene name: " + parser.getName()); } diff --git a/core/java/android/util/Size.java b/core/java/android/util/Size.java index 64243440868a..62df5647cdaa 100644 --- a/core/java/android/util/Size.java +++ b/core/java/android/util/Size.java @@ -18,13 +18,10 @@ package android.util; import static com.android.internal.util.Preconditions.checkNotNull; -import android.os.Parcel; -import android.os.Parcelable; - /** * Immutable class for describing width and height dimensions in pixels. */ -public final class Size implements Parcelable { +public final class Size { /** * Create a new immutable Size instance. * @@ -36,11 +33,6 @@ public final class Size implements Parcelable { mHeight = height; } - private Size(Parcel in) { - mWidth = in.readInt(); - mHeight = in.readInt(); - } - /** * Get the width of the size (in pixels). * @return width @@ -155,29 +147,6 @@ public final class Size implements Parcelable { return mHeight ^ ((mWidth << (Integer.SIZE / 2)) | (mWidth >>> (Integer.SIZE / 2))); } - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel out, int flags) { - out.writeInt(mWidth); - out.writeInt(mHeight); - } - - public static final Parcelable.Creator<Size> CREATOR = new Parcelable.Creator<Size>() { - @Override - public Size createFromParcel(Parcel in) { - return new Size(in); - } - - @Override - public Size[] newArray(int size) { - return new Size[size]; - } - }; - private final int mWidth; private final int mHeight; } diff --git a/core/java/android/util/SizeF.java b/core/java/android/util/SizeF.java index 88bb43936518..ac4f18765a59 100644 --- a/core/java/android/util/SizeF.java +++ b/core/java/android/util/SizeF.java @@ -18,9 +18,6 @@ package android.util; import static com.android.internal.util.Preconditions.checkArgumentFinite; -import android.os.Parcel; -import android.os.Parcelable; - /** * Immutable class for describing width and height dimensions in some arbitrary * unit. @@ -28,7 +25,7 @@ import android.os.Parcelable; * Width and height are finite values stored as a floating point representation. * </p> */ -public final class SizeF implements Parcelable { +public final class SizeF { /** * Create a new immutable SizeF instance. * @@ -46,11 +43,6 @@ public final class SizeF implements Parcelable { mHeight = checkArgumentFinite(height, "height"); } - private SizeF(Parcel in) { - mWidth = in.readFloat(); - mHeight = in.readFloat(); - } - /** * Get the width of the size (as an arbitrary unit). * @return width @@ -111,29 +103,6 @@ public final class SizeF implements Parcelable { return Float.floatToIntBits(mWidth) ^ Float.floatToIntBits(mHeight); } - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel out, int flags) { - out.writeFloat(mWidth); - out.writeFloat(mHeight); - } - - public static final Parcelable.Creator<SizeF> CREATOR = new Parcelable.Creator<SizeF>() { - @Override - public SizeF createFromParcel(Parcel in) { - return new SizeF(in); - } - - @Override - public SizeF[] newArray(int size) { - return new SizeF[size]; - } - }; - private final float mWidth; private final float mHeight; } diff --git a/core/java/android/view/FrameStats.java b/core/java/android/view/FrameStats.java index 541b3365f73b..b3ac1db2b1df 100644 --- a/core/java/android/view/FrameStats.java +++ b/core/java/android/view/FrameStats.java @@ -28,7 +28,10 @@ public abstract class FrameStats { */ public static final long UNDEFINED_TIME_NANO = -1; + /** @hide */ protected long mRefreshPeriodNano; + + /** @hide */ protected long[] mFramesPresentedTimeNano; /** diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java index ceea9f8f0234..076f1e29fd32 100644 --- a/core/java/android/view/GLES20Canvas.java +++ b/core/java/android/view/GLES20Canvas.java @@ -800,28 +800,6 @@ class GLES20Canvas extends HardwareCanvas { } @Override - public void drawPicture(Picture picture, Rect dst) { - save(); - translate(dst.left, dst.top); - if (picture.getWidth() > 0 && picture.getHeight() > 0) { - scale(dst.width() / picture.getWidth(), dst.height() / picture.getHeight()); - } - drawPicture(picture); - restore(); - } - - @Override - public void drawPicture(Picture picture, RectF dst) { - save(); - translate(dst.left, dst.top); - if (picture.getWidth() > 0 && picture.getHeight() > 0) { - scale(dst.width() / picture.getWidth(), dst.height() / picture.getHeight()); - } - drawPicture(picture); - restore(); - } - - @Override public void drawPoint(float x, float y, Paint paint) { float[] point = getPointStorage(); point[0] = x; diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 21e7c6b3c220..92ad4e83349e 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -444,16 +444,19 @@ import java.util.concurrent.atomic.AtomicInteger; * <a name="Drawing"></a> * <h3>Drawing</h3> * <p> - * Drawing is handled by walking the tree and rendering each view that - * intersects the invalid region. Because the tree is traversed in-order, - * this means that parents will draw before (i.e., behind) their children, with - * siblings drawn in the order they appear in the tree. - * If you set a background drawable for a View, then the View will draw it for you - * before calling back to its <code>onDraw()</code> method. + * Drawing is handled by walking the tree and recording the drawing commands of + * any View that needs to update. After this, the drawing commands of the + * entire tree are issued to screen, clipped to the newly damaged area. * </p> * * <p> - * Note that the framework will not draw views that are not in the invalid region. + * The tree is largely recorded and drawn in order, with parents drawn before + * (i.e., behind) their children, with siblings drawn in the order they appear + * in the tree. If you set a background drawable for a View, then the View will + * draw it before calling back to its <code>onDraw()</code> method. The child + * drawing order can be overridden with + * {@link ViewGroup#setChildrenDrawingOrderEnabled(boolean) custom child drawing order} + * in a ViewGroup, and with {@link #setZ(float)} custom Z values} set on Views. * </p> * * <p> @@ -10825,6 +10828,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback, /** * Sets whether the View's Outline should be used to clip the contents of the View. * <p> + * Only a single non-rectangular clip can be applied on a View at any time. + * Circular clips from a {@link ViewAnimationUtils#createCircularReveal(View, int, int, float, float) + * circular reveal} animation take priority over Outline clipping, and + * child Outline clipping takes priority over Outline clipping done by a + * parent. + * <p> * Note that this flag will only be respected if the View's Outline returns true from * {@link Outline#canClip()}. * @@ -15091,10 +15100,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback, bounds.set(0, 0, mRight - mLeft, mBottom - mTop); } + canvas.save(); canvas.translate(mScrollX, mScrollY); + canvas.clipRect(bounds, Region.Op.REPLACE); drawable.setBounds(bounds); drawable.draw(canvas); - canvas.translate(-mScrollX, -mScrollY); + canvas.restore(); } /** diff --git a/core/java/android/view/ViewAnimationUtils.java b/core/java/android/view/ViewAnimationUtils.java index 7ced0889cdd5..001cd01646a9 100644 --- a/core/java/android/view/ViewAnimationUtils.java +++ b/core/java/android/view/ViewAnimationUtils.java @@ -27,9 +27,13 @@ public final class ViewAnimationUtils { private ViewAnimationUtils() {} /** * Returns an Animator which can animate a clipping circle. - * + * <p> * Any shadow cast by the View will respect the circular clip from this animator. - * + * <p> + * Only a single non-rectangular clip can be applied on a View at any time. + * Views clipped by a circular reveal animation take priority over + * {@link View#setClipToOutline(boolean) View Outline clipping}. + * <p> * Note that the animation returned here is a one-shot animation. It cannot * be re-used, and once started it cannot be paused or resumed. * @@ -39,7 +43,7 @@ public final class ViewAnimationUtils { * @param startRadius The starting radius of the animating circle. * @param endRadius The ending radius of the animating circle. */ - public static final Animator createCircularReveal(View view, + public static Animator createCircularReveal(View view, int centerX, int centerY, float startRadius, float endRadius) { return new RevealAnimator(view, centerX, centerY, startRadius, endRadius); } diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java index adad08242e62..974fe4e0c89f 100644 --- a/core/java/android/view/ViewGroup.java +++ b/core/java/android/view/ViewGroup.java @@ -5034,6 +5034,9 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager /** * Tells the ViewGroup whether to draw its children in the order defined by the method * {@link #getChildDrawingOrder(int, int)}. + * <p> + * Note that {@link View#getZ() Z} reordering, done by {@link #dispatchDraw(Canvas)}, + * will override custom child ordering done via this method. * * @param enabled true if the order of the children when drawing is determined by * {@link #getChildDrawingOrder(int, int)}, false otherwise diff --git a/core/java/android/webkit/WebResourceRequest.java b/core/java/android/webkit/WebResourceRequest.java index dc7c808d266c..b46ac9a54223 100644 --- a/core/java/android/webkit/WebResourceRequest.java +++ b/core/java/android/webkit/WebResourceRequest.java @@ -41,7 +41,7 @@ public interface WebResourceRequest { boolean isForMainFrame(); /** - * Gets whether a gesture was associated with the request. + * Gets whether a gesture (such as a link click) was associated with the request. * <p> * <strong>IMPORTANT:</strong> * This should not be used to implement any form of security. It is possible for the content @@ -49,6 +49,11 @@ public interface WebResourceRequest { * * @return whether a gesture was associated with the request. */ + boolean hasGesture(); + + /* + * @removed + */ boolean hasUserGestureInsecure(); /** diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java index edfa7af3e69d..081bfdf92d12 100644 --- a/core/java/android/webkit/WebView.java +++ b/core/java/android/webkit/WebView.java @@ -1939,16 +1939,14 @@ public class WebView extends AbsoluteLayout * * @param zoomFactor the zoom factor to apply. The zoom factor will be clamped to the Webview's * zoom limits. This value must be in the range 0.01 to 100.0 inclusive. - * - * @return false if no zoom changes, true otherwise. */ - public boolean zoomBy(float zoomFactor) { + public void zoomBy(float zoomFactor) { checkThread(); if (zoomFactor < 0.01) throw new IllegalArgumentException("zoomFactor must be greater than 0.01."); if (zoomFactor > 100.0) throw new IllegalArgumentException("zoomFactor must be less than 100."); - return mProvider.zoomBy(zoomFactor); + mProvider.zoomBy(zoomFactor); } /** diff --git a/core/java/android/widget/ActionMenuView.java b/core/java/android/widget/ActionMenuView.java index 96abf519d933..6ca4a9e10db2 100644 --- a/core/java/android/widget/ActionMenuView.java +++ b/core/java/android/widget/ActionMenuView.java @@ -29,6 +29,7 @@ import android.view.accessibility.AccessibilityEvent; import com.android.internal.view.menu.ActionMenuItemView; import com.android.internal.view.menu.MenuBuilder; import com.android.internal.view.menu.MenuItemImpl; +import com.android.internal.view.menu.MenuPresenter; import com.android.internal.view.menu.MenuView; /** @@ -53,6 +54,8 @@ public class ActionMenuView extends LinearLayout implements MenuBuilder.ItemInvo private boolean mReserveOverflow; private ActionMenuPresenter mPresenter; + private MenuPresenter.Callback mActionMenuPresenterCallback; + private MenuBuilder.Callback mMenuBuilderCallback; private boolean mFormatItems; private int mFormatItemsWidth; private int mMinCellSize; @@ -608,7 +611,8 @@ public class ActionMenuView extends LinearLayout implements MenuBuilder.ItemInvo mMenu = new MenuBuilder(context); mMenu.setCallback(new MenuBuilderCallback()); mPresenter = new ActionMenuPresenter(context); - mPresenter.setCallback(new ActionMenuPresenterCallback()); + mPresenter.setCallback(mActionMenuPresenterCallback != null + ? mActionMenuPresenterCallback : new ActionMenuPresenterCallback()); mMenu.addMenuPresenter(mPresenter, mPopupContext); mPresenter.setMenuView(this); } @@ -617,6 +621,15 @@ public class ActionMenuView extends LinearLayout implements MenuBuilder.ItemInvo } /** + * Must be called before the first call to getMenu() + * @hide + */ + public void setMenuCallbacks(MenuPresenter.Callback pcb, MenuBuilder.Callback mcb) { + mActionMenuPresenterCallback = pcb; + mMenuBuilderCallback = mcb; + } + + /** * Returns the current menu or null if one has not yet been configured. * @hide Internal use only for action bar integration */ @@ -719,6 +732,9 @@ public class ActionMenuView extends LinearLayout implements MenuBuilder.ItemInvo @Override public void onMenuModeChange(MenuBuilder menu) { + if (mMenuBuilderCallback != null) { + mMenuBuilderCallback.onMenuModeChange(menu); + } } } diff --git a/core/java/android/widget/DatePicker.java b/core/java/android/widget/DatePicker.java index 26c1f960ff57..2729bd084a55 100644 --- a/core/java/android/widget/DatePicker.java +++ b/core/java/android/widget/DatePicker.java @@ -71,9 +71,9 @@ import libcore.icu.ICU; * @attr ref android.R.styleable#DatePicker_minDate * @attr ref android.R.styleable#DatePicker_spinnersShown * @attr ref android.R.styleable#DatePicker_calendarViewShown - * @attr ref android.R.styleable#DatePicker_dayOfWeekBackgroundColor + * @attr ref android.R.styleable#DatePicker_dayOfWeekBackground * @attr ref android.R.styleable#DatePicker_dayOfWeekTextAppearance - * @attr ref android.R.styleable#DatePicker_headerBackgroundColor + * @attr ref android.R.styleable#DatePicker_headerBackground * @attr ref android.R.styleable#DatePicker_headerMonthTextAppearance * @attr ref android.R.styleable#DatePicker_headerDayOfMonthTextAppearance * @attr ref android.R.styleable#DatePicker_headerYearTextAppearance diff --git a/core/java/android/widget/DatePickerCalendarDelegate.java b/core/java/android/widget/DatePickerCalendarDelegate.java index 7df1fa3398f7..eed49bf21ea5 100644 --- a/core/java/android/widget/DatePickerCalendarDelegate.java +++ b/core/java/android/widget/DatePickerCalendarDelegate.java @@ -21,7 +21,7 @@ import android.content.res.ColorStateList; import android.content.res.Configuration; import android.content.res.Resources; import android.content.res.TypedArray; -import android.graphics.Color; +import android.graphics.drawable.Drawable; import android.os.Parcel; import android.os.Parcelable; import android.text.format.DateFormat; @@ -149,16 +149,12 @@ class DatePickerCalendarDelegate extends DatePicker.AbstractDatePickerDelegate i mDayOfWeekView.setTextAppearance(context, dayOfWeekTextAppearanceResId); } - final int dayOfWeekBackgroundColor = a.getColor( - R.styleable.DatePicker_dayOfWeekBackgroundColor, Color.TRANSPARENT); - mDayOfWeekView.setBackgroundColor(dayOfWeekBackgroundColor); + mDayOfWeekView.setBackground(a.getDrawable(R.styleable.DatePicker_dayOfWeekBackground)); + + dateLayout.setBackground(a.getDrawable(R.styleable.DatePicker_headerBackground)); final int headerSelectedTextColor = a.getColor( R.styleable.DatePicker_headerSelectedTextColor, defaultHighlightColor); - final int headerBackgroundColor = a.getColor(R.styleable.DatePicker_headerBackgroundColor, - Color.TRANSPARENT); - dateLayout.setBackgroundColor(headerBackgroundColor); - final int monthTextAppearanceResId = a.getResourceId( R.styleable.DatePicker_headerMonthTextAppearance, -1); if (monthTextAppearanceResId != -1) { diff --git a/core/java/android/widget/DateTimeView.java b/core/java/android/widget/DateTimeView.java index b3ff88b3dabf..45d1403bc598 100644 --- a/core/java/android/widget/DateTimeView.java +++ b/core/java/android/widget/DateTimeView.java @@ -29,7 +29,6 @@ import android.util.Log; import android.provider.Settings; import android.widget.TextView; import android.widget.RemoteViews.RemoteView; -import android.os.UserHandle; import java.text.DateFormat; import java.text.SimpleDateFormat; @@ -191,15 +190,8 @@ public class DateTimeView extends TextView { } private DateFormat getDateFormat() { - // OK, this is gross but needed. This class is supported by the - // remote views mechanism and as a part of that the remote views - // can be inflated by a context for another user without the app - // having interact users permission - just for loading resources. - // For example, when adding widgets from a user profile to the - // home screen. Therefore, we access settings as the user the app - // is running as not the one the context is for. - String format = Settings.System.getStringForUser(getContext().getContentResolver(), - Settings.System.DATE_FORMAT, UserHandle.myUserId()); + String format = Settings.System.getString(getContext().getContentResolver(), + Settings.System.DATE_FORMAT); if (format == null || "".equals(format)) { return DateFormat.getDateInstance(DateFormat.SHORT); } else { @@ -220,20 +212,10 @@ public class DateTimeView extends TextView { filter.addAction(Intent.ACTION_TIME_CHANGED); filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED); filter.addAction(Intent.ACTION_TIMEZONE_CHANGED); - - // OK, this is gross but needed. This class is supported by the - // remote views mechanism and as a part of that the remote views - // can be inflated by a context for another user without the app - // having interact users permission - just for loading resources. - // For example, when adding widgets from a user profile to the - // home screen. Therefore, we register the receiver and content - // observer as the user the app is running as not the one the context is for. - context.registerReceiverAsUser(mBroadcastReceiver, android.os.Process.myUserHandle(), - filter, null, null); + context.registerReceiver(mBroadcastReceiver, filter); Uri uri = Settings.System.getUriFor(Settings.System.DATE_FORMAT); - context.getContentResolver().registerContentObserver(uri, true, mContentObserver, - UserHandle.myUserId()); + context.getContentResolver().registerContentObserver(uri, true, mContentObserver); } private void unregisterReceivers() { diff --git a/core/java/android/widget/EdgeEffect.java b/core/java/android/widget/EdgeEffect.java index 57b8dcb9e763..033b99a22d51 100644 --- a/core/java/android/widget/EdgeEffect.java +++ b/core/java/android/widget/EdgeEffect.java @@ -52,12 +52,15 @@ public class EdgeEffect { private static final String TAG = "EdgeEffect"; // Time it will take the effect to fully recede in ms - private static final int RECEDE_TIME = 1000; + private static final int RECEDE_TIME = 600; // Time it will take before a pulled glow begins receding in ms private static final int PULL_TIME = 167; - private static final float MAX_ALPHA = 1.f; + // Time it will take in ms for a pulled glow to decay to partial strength before release + private static final int PULL_DECAY_TIME = 2000; + + private static final float MAX_ALPHA = 0.5f; private static final float MAX_GLOW_SCALE = 2.f; @@ -93,12 +96,9 @@ public class EdgeEffect { private static final int STATE_RECEDE = 3; private static final int STATE_PULL_DECAY = 4; - // How much dragging should effect the height of the glow image. - // Number determined by user testing. - private static final int PULL_DISTANCE_GLOW_FACTOR = 7; - private static final float PULL_DISTANCE_ALPHA_GLOW_FACTOR = 1.1f; + private static final float PULL_DISTANCE_ALPHA_GLOW_FACTOR = 0.8f; - private static final int VELOCITY_GLOW_FACTOR = 12; + private static final int VELOCITY_GLOW_FACTOR = 6; private int mState = STATE_IDLE; @@ -107,7 +107,7 @@ public class EdgeEffect { private final Rect mBounds = new Rect(); private final Paint mPaint = new Paint(); private float mRadius; - private float mBaseGlowHeight; + private float mBaseGlowScale; private float mDisplacement = 0.5f; private float mTargetDisplacement = 0.5f; @@ -138,8 +138,12 @@ public class EdgeEffect { final float r = width * 0.75f / SIN; final float y = COS * r; final float h = r - y; + final float or = height * 0.75f / SIN; + final float oy = COS * or; + final float oh = or - oy; + mRadius = r; - mBaseGlowHeight = h; + mBaseGlowScale = h > 0 ? Math.min(oh / h, 1.f) : 1.f; mBounds.set(mBounds.left, mBounds.top, width, (int) Math.min(height, h)); } @@ -319,13 +323,14 @@ public class EdgeEffect { final float centerX = mBounds.centerX(); final float centerY = mBounds.height() - mRadius; - canvas.scale(1.f, Math.min(mGlowScaleY, 1.f), centerX, 0); + canvas.scale(1.f, Math.min(mGlowScaleY, 1.f) * mBaseGlowScale, centerX, 0); final float displacement = Math.max(0, Math.min(mDisplacement, 1.f)) - 0.5f; float translateX = mBounds.width() * displacement / 2; canvas.clipRect(mBounds); canvas.translate(translateX, 0); + mPaint.setAlpha((int) (0xff * mGlowAlpha)); canvas.drawCircle(centerX, centerY, mRadius, mPaint); canvas.restoreToCount(count); @@ -372,7 +377,16 @@ public class EdgeEffect { mGlowScaleYFinish = 0.f; break; case STATE_PULL: - // Hold in this state until explicitly released. + mState = STATE_PULL_DECAY; + mStartTime = AnimationUtils.currentAnimationTimeMillis(); + mDuration = PULL_DECAY_TIME; + + mGlowAlphaStart = mGlowAlpha; + mGlowScaleYStart = mGlowScaleY; + + // After pull, the glow should fade to nothing. + mGlowAlphaFinish = 0.f; + mGlowScaleYFinish = 0.f; break; case STATE_PULL_DECAY: mState = STATE_RECEDE; diff --git a/core/java/android/widget/RadialTimePickerView.java b/core/java/android/widget/RadialTimePickerView.java index adca4ccdaaed..d2f68d07fbbd 100644 --- a/core/java/android/widget/RadialTimePickerView.java +++ b/core/java/android/widget/RadialTimePickerView.java @@ -458,6 +458,7 @@ public class RadialTimePickerView extends View implements View.OnTouchListener { a.recycle(); setOnTouchListener(this); + setClickable(true); // Initial values final Calendar calendar = Calendar.getInstance(Locale.getDefault()); @@ -612,9 +613,9 @@ public class RadialTimePickerView extends View implements View.OnTouchListener { mMinutesTexts[i] = String.format("%02d", MINUTES_NUMBERS[i]); } - String[] amPmTexts = new DateFormatSymbols().getAmPmStrings(); - mAmPmText[AM] = amPmTexts[0]; - mAmPmText[PM] = amPmTexts[1]; + String[] amPmStrings = TimePickerClockDelegate.getAmPmStrings(mContext); + mAmPmText[AM] = amPmStrings[0]; + mAmPmText[PM] = amPmStrings[1]; } private void initData() { diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java index 9de69f24d079..90e9c69913e9 100644 --- a/core/java/android/widget/RemoteViews.java +++ b/core/java/android/widget/RemoteViews.java @@ -22,11 +22,13 @@ import android.app.Application; import android.app.PendingIntent; import android.appwidget.AppWidgetHostView; import android.content.Context; +import android.content.ContextWrapper; import android.content.Intent; import android.content.IntentSender; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager.NameNotFoundException; import android.content.res.Configuration; +import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.PorterDuff; import android.graphics.Rect; @@ -2517,15 +2519,29 @@ public class RemoteViews implements Parcelable, Filter { RemoteViews rvToApply = getRemoteViewsToApply(context); View result; - - Context c = prepareContext(context); + // RemoteViews may be built by an application installed in another + // user. So build a context that loads resources from that user but + // still returns the current users userId so settings like data / time formats + // are loaded without requiring cross user persmissions. + final Context contextForResources = getContextForResources(context); + Context inflationContext = new ContextWrapper(context) { + @Override + public Resources getResources() { + return contextForResources.getResources(); + } + @Override + public Resources.Theme getTheme() { + return contextForResources.getTheme(); + } + }; LayoutInflater inflater = (LayoutInflater) - c.getSystemService(Context.LAYOUT_INFLATER_SERVICE); + context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); - inflater = inflater.cloneInContext(c); + // Clone inflater so we load resources from correct context and + // we don't add a filter to the static version returned by getSystemService. + inflater = inflater.cloneInContext(inflationContext); inflater.setFilter(this); - result = inflater.inflate(rvToApply.getLayoutId(), parent, false); rvToApply.performApply(result, parent, handler); @@ -2559,7 +2575,6 @@ public class RemoteViews implements Parcelable, Filter { } } - prepareContext(context); rvToApply.performApply(v, (ViewGroup) v.getParent(), handler); } @@ -2574,7 +2589,7 @@ public class RemoteViews implements Parcelable, Filter { } } - private Context prepareContext(Context context) { + private Context getContextForResources(Context context) { if (mApplication != null) { if (context.getUserId() == UserHandle.getUserId(mApplication.uid) && context.getPackageName().equals(mApplication.packageName)) { diff --git a/core/java/android/widget/TextClock.java b/core/java/android/widget/TextClock.java index acfc5431182d..4c5c71ded991 100644 --- a/core/java/android/widget/TextClock.java +++ b/core/java/android/widget/TextClock.java @@ -26,7 +26,6 @@ import android.database.ContentObserver; import android.net.Uri; import android.os.Handler; import android.os.SystemClock; -import android.os.UserHandle; import android.provider.Settings; import android.text.format.DateFormat; import android.util.AttributeSet; @@ -496,28 +495,12 @@ public class TextClock extends TextView { filter.addAction(Intent.ACTION_TIME_CHANGED); filter.addAction(Intent.ACTION_TIMEZONE_CHANGED); - // OK, this is gross but needed. This class is supported by the - // remote views mechanism and as a part of that the remote views - // can be inflated by a context for another user without the app - // having interact users permission - just for loading resources. - // For example, when adding widgets from a user profile to the - // home screen. Therefore, we register the receiver as the user - // the app is running as not the one the context is for. - getContext().registerReceiverAsUser(mIntentReceiver, android.os.Process.myUserHandle(), - filter, null, getHandler()); + getContext().registerReceiver(mIntentReceiver, filter, null, getHandler()); } private void registerObserver() { final ContentResolver resolver = getContext().getContentResolver(); - // OK, this is gross but needed. This class is supported by the - // remote views mechanism and as a part of that the remote views - // can be inflated by a context for another user without the app - // having interact users permission - just for loading resources. - // For example, when adding widgets from a user profile to the - // home screen. Therefore, we register the content observer - // as the user the app is running as not the one the context is for. - resolver.registerContentObserver(Settings.System.CONTENT_URI, true, - mFormatChangeObserver, UserHandle.myUserId()); + resolver.registerContentObserver(Settings.System.CONTENT_URI, true, mFormatChangeObserver); } private void unregisterReceiver() { diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index 188a3e9970e2..3e1b674892a1 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -41,7 +41,6 @@ import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; import android.os.SystemClock; -import android.os.UserHandle; import android.provider.Settings; import android.text.BoringLayout; import android.text.DynamicLayout; @@ -8338,15 +8337,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener * to speak passwords. */ private boolean shouldSpeakPasswordsForAccessibility() { - // OK, this is gross but needed. This class is supported by the - // remote views mechanism and as a part of that the remote views - // can be inflated by a context for another user without the app - // having interact users permission - just for loading resources. - // For example, when adding widgets from a user profile to the - // home screen. Therefore, we access settings as user the app is - // running as not the one the context is for. - return (Settings.Secure.getIntForUser(mContext.getContentResolver(), - Settings.Secure.ACCESSIBILITY_SPEAK_PASSWORD, 0, UserHandle.myUserId()) == 1); + return (Settings.Secure.getInt(mContext.getContentResolver(), + Settings.Secure.ACCESSIBILITY_SPEAK_PASSWORD, 0) == 1); } @Override diff --git a/core/java/android/widget/TimePickerSpinnerDelegate.java b/core/java/android/widget/TimePickerSpinnerDelegate.java index 6169d2e49cdc..73e05e8d4932 100644 --- a/core/java/android/widget/TimePickerSpinnerDelegate.java +++ b/core/java/android/widget/TimePickerSpinnerDelegate.java @@ -21,7 +21,6 @@ import android.content.res.ColorStateList; import android.content.res.Configuration; import android.content.res.Resources; import android.content.res.TypedArray; -import android.graphics.Color; import android.os.Parcel; import android.os.Parcelable; import android.text.TextUtils; @@ -40,7 +39,6 @@ import android.view.accessibility.AccessibilityNodeInfo; import com.android.internal.R; -import java.text.DateFormatSymbols; import java.util.ArrayList; import java.util.Calendar; import java.util.Locale; @@ -71,6 +69,7 @@ class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate im private static final int HOURS_IN_HALF_DAY = 12; + private View mHeaderView; private TextView mHourView; private TextView mMinuteView; private TextView mAmPmTextView; @@ -156,11 +155,8 @@ class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate im mAmPmTextView.setTextAppearance(context, headerAmPmTextAppearance); } - final int headerBackgroundColor = a.getColor( - R.styleable.TimePicker_headerBackgroundColor, Color.TRANSPARENT); - if (headerBackgroundColor != Color.TRANSPARENT) { - mainView.findViewById(R.id.time_header).setBackgroundColor(headerBackgroundColor); - } + mHeaderView = mainView.findViewById(R.id.time_header); + mHeaderView.setBackground(a.getDrawable(R.styleable.TimePicker_headerBackground)); a.recycle(); @@ -194,14 +190,11 @@ class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate im } private void setupListeners() { - KeyboardListener keyboardListener = new KeyboardListener(); - mDelegator.setOnKeyListener(keyboardListener); + mHeaderView.setOnKeyListener(mKeyListener); + mHeaderView.setOnFocusChangeListener(mFocusListener); + mHeaderView.setFocusable(true); - mHourView.setOnKeyListener(keyboardListener); - mMinuteView.setOnKeyListener(keyboardListener); - mAmPmTextView.setOnKeyListener(keyboardListener); mRadialTimePickerView.setOnValueSelectedListener(this); - mRadialTimePickerView.setOnKeyListener(keyboardListener); mHourView.setOnClickListener(new View.OnClickListener() { @Override @@ -641,7 +634,7 @@ class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate im if (!isTypedTimeFullyLegal()) { mTypedTimes.clear(); } - finishKbMode(true); + finishKbMode(); } } @@ -776,27 +769,7 @@ class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate im * @return true if the key was successfully processed, false otherwise. */ private boolean processKeyUp(int keyCode) { - if (keyCode == KeyEvent.KEYCODE_ESCAPE || keyCode == KeyEvent.KEYCODE_TAB) { - if(mInKbMode) { - if (isTypedTimeFullyLegal()) { - finishKbMode(true); - } - return true; - } - } else if (keyCode == KeyEvent.KEYCODE_ENTER) { - if (mInKbMode) { - if (!isTypedTimeFullyLegal()) { - return true; - } - finishKbMode(false); - } - if (mOnTimeChangedListener != null) { - mOnTimeChangedListener.onTimeChanged(mDelegator, - mRadialTimePickerView.getCurrentHour(), - mRadialTimePickerView.getCurrentMinute()); - } - return true; - } else if (keyCode == KeyEvent.KEYCODE_DEL) { + if (keyCode == KeyEvent.KEYCODE_DEL) { if (mInKbMode) { if (!mTypedTimes.isEmpty()) { int deleted = deleteLastTypedKey(); @@ -925,9 +898,8 @@ class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate im /** * Get out of keyboard mode. If there is nothing in typedTimes, revert to TimePicker's time. - * @param updateDisplays If true, update the displays with the relevant time. */ - private void finishKbMode(boolean updateDisplays) { + private void finishKbMode() { mInKbMode = false; if (!mTypedTimes.isEmpty()) { int values[] = getEnteredTime(null); @@ -938,10 +910,8 @@ class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate im } mTypedTimes.clear(); } - if (updateDisplays) { - updateDisplay(false); - mRadialTimePickerView.setInputEnabled(true); - } + updateDisplay(false); + mRadialTimePickerView.setInputEnabled(true); } /** @@ -1261,7 +1231,7 @@ class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate im } } - private class KeyboardListener implements View.OnKeyListener { + private final View.OnKeyListener mKeyListener = new View.OnKeyListener() { @Override public boolean onKey(View v, int keyCode, KeyEvent event) { if (event.getAction() == KeyEvent.ACTION_UP) { @@ -1269,5 +1239,20 @@ class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate im } return false; } - } + }; + + private final View.OnFocusChangeListener mFocusListener = new View.OnFocusChangeListener() { + @Override + public void onFocusChange(View v, boolean hasFocus) { + if (!hasFocus && mInKbMode && isTypedTimeFullyLegal()) { + finishKbMode(); + + if (mOnTimeChangedListener != null) { + mOnTimeChangedListener.onTimeChanged(mDelegator, + mRadialTimePickerView.getCurrentHour(), + mRadialTimePickerView.getCurrentMinute()); + } + } + } + }; } diff --git a/core/java/android/widget/Toolbar.java b/core/java/android/widget/Toolbar.java index 3ba03b808dcd..be28199b3636 100644 --- a/core/java/android/widget/Toolbar.java +++ b/core/java/android/widget/Toolbar.java @@ -37,6 +37,7 @@ import android.view.View; import android.view.ViewGroup; import com.android.internal.R; +import com.android.internal.app.ToolbarActionBar; import com.android.internal.view.menu.MenuBuilder; import com.android.internal.view.menu.MenuItemImpl; import com.android.internal.view.menu.MenuPresenter; @@ -153,6 +154,8 @@ public class Toolbar extends ViewGroup { private ToolbarWidgetWrapper mWrapper; private ActionMenuPresenter mOuterActionMenuPresenter; private ExpandedActionViewMenuPresenter mExpandedMenuPresenter; + private MenuPresenter.Callback mActionMenuPresenterCallback; + private MenuBuilder.Callback mMenuBuilderCallback; private boolean mCollapsible; @@ -825,6 +828,7 @@ public class Toolbar extends ViewGroup { mMenuView = new ActionMenuView(getContext()); mMenuView.setPopupTheme(mPopupTheme); mMenuView.setOnMenuItemClickListener(mMenuViewItemClickListener); + mMenuView.setMenuCallbacks(mActionMenuPresenterCallback, mMenuBuilderCallback); final LayoutParams lp = generateDefaultLayoutParams(); lp.gravity = Gravity.END | (mButtonGravity & Gravity.VERTICAL_GRAVITY_MASK); mMenuView.setLayoutParams(lp); @@ -1678,6 +1682,15 @@ public class Toolbar extends ViewGroup { } /** + * Must be called before the menu is accessed + * @hide + */ + public void setMenuCallbacks(MenuPresenter.Callback pcb, MenuBuilder.Callback mcb) { + mActionMenuPresenterCallback = pcb; + mMenuBuilderCallback = mcb; + } + + /** * Interface responsible for receiving menu item click events if the items themselves * do not have individual item click listeners. */ diff --git a/core/java/com/android/internal/app/ToolbarActionBar.java b/core/java/com/android/internal/app/ToolbarActionBar.java index 6f1c7ecbc7dc..99c87eabf5a0 100644 --- a/core/java/com/android/internal/app/ToolbarActionBar.java +++ b/core/java/com/android/internal/app/ToolbarActionBar.java @@ -35,6 +35,7 @@ import android.widget.SpinnerAdapter; import android.widget.Toolbar; import com.android.internal.R; import com.android.internal.view.menu.MenuBuilder; +import com.android.internal.view.menu.MenuPresenter; import com.android.internal.widget.DecorToolbar; import com.android.internal.widget.ToolbarWidgetWrapper; @@ -45,6 +46,7 @@ public class ToolbarActionBar extends ActionBar { private DecorToolbar mDecorToolbar; private boolean mToolbarMenuPrepared; private Window.Callback mWindowCallback; + private boolean mMenuCallbackSet; private CharSequence mHomeDescription; @@ -453,6 +455,10 @@ public class ToolbarActionBar extends ActionBar { } void populateOptionsMenu() { + if (!mMenuCallbackSet) { + mToolbar.setMenuCallbacks(new ActionMenuPresenterCallback(), new MenuBuilderCallback()); + mMenuCallbackSet = true; + } final Menu menu = mToolbar.getMenu(); final MenuBuilder mb = menu instanceof MenuBuilder ? (MenuBuilder) menu : null; if (mb != null) { @@ -514,4 +520,51 @@ public class ToolbarActionBar extends ActionBar { return result; } } + + private final class ActionMenuPresenterCallback implements MenuPresenter.Callback { + private boolean mClosingActionMenu; + + @Override + public boolean onOpenSubMenu(MenuBuilder subMenu) { + if (mWindowCallback != null) { + mWindowCallback.onMenuOpened(Window.FEATURE_ACTION_BAR, subMenu); + return true; + } + return false; + } + + @Override + public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) { + if (mClosingActionMenu) { + return; + } + + mClosingActionMenu = true; + mToolbar.dismissPopupMenus(); + if (mWindowCallback != null) { + mWindowCallback.onPanelClosed(Window.FEATURE_ACTION_BAR, menu); + } + mClosingActionMenu = false; + } + } + + private final class MenuBuilderCallback implements MenuBuilder.Callback { + + @Override + public boolean onMenuItemSelected(MenuBuilder menu, MenuItem item) { + return false; + } + + @Override + public void onMenuModeChange(MenuBuilder menu) { + if (mWindowCallback != null) { + if (mToolbar.isOverflowMenuShowing()) { + mWindowCallback.onPanelClosed(Window.FEATURE_ACTION_BAR, menu); + } else if (mWindowCallback.onPreparePanel(Window.FEATURE_OPTIONS_PANEL, + null, menu)) { + mWindowCallback.onMenuOpened(Window.FEATURE_ACTION_BAR, menu); + } + } + } + } } diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java index 54c532abd090..c5211bb23872 100644 --- a/core/java/com/android/internal/os/Zygote.java +++ b/core/java/com/android/internal/os/Zygote.java @@ -20,9 +20,12 @@ package com.android.internal.os; import dalvik.system.ZygoteHooks; import android.system.ErrnoException; import android.system.Os; +import android.os.SystemClock; +import android.util.Slog; /** @hide */ public final class Zygote { + private static final String TAG = "Zygote"; /* * Bit values for "debugFlags" argument. The definitions are duplicated * in the native code. @@ -81,10 +84,14 @@ public final class Zygote { */ public static int forkAndSpecialize(int uid, int gid, int[] gids, int debugFlags, int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose) { + long startTime = SystemClock.elapsedRealtime(); VM_HOOKS.preFork(); + checkTime(startTime, "Zygote.preFork"); int pid = nativeForkAndSpecialize( uid, gid, gids, debugFlags, rlimits, mountExternal, seInfo, niceName, fdsToClose); + checkTime(startTime, "Zygote.nativeForkAndSpecialize"); VM_HOOKS.postForkCommon(); + checkTime(startTime, "Zygote.postForkCommon"); return pid; } @@ -92,6 +99,18 @@ public final class Zygote { int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose); /** + * Temporary hack: check time since start time and log if over a fixed threshold. + * + */ + private static void checkTime(long startTime, String where) { + long now = SystemClock.elapsedRealtime(); + if ((now-startTime) > 1000) { + // If we are taking more than a second, log about it. + Slog.w(TAG, "Slow operation: " + (now-startTime) + "ms so far, now at " + where); + } + } + + /** * Special method to start the system server process. In addition to the * common actions performed in forkAndSpecialize, the pid of the child * process is recorded such that the death of the child process will cause @@ -127,7 +146,9 @@ public final class Zygote { int[][] rlimits, long permittedCapabilities, long effectiveCapabilities); private static void callPostForkChildHooks(int debugFlags) { + long startTime = SystemClock.elapsedRealtime(); VM_HOOKS.postForkChild(debugFlags); + checkTime(startTime, "Zygote.callPostForkChildHooks"); } diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java index 43ebb3d10912..b4c4da655b05 100644 --- a/core/java/com/android/internal/os/ZygoteConnection.java +++ b/core/java/com/android/internal/os/ZygoteConnection.java @@ -37,6 +37,8 @@ import java.io.PrintStream; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import libcore.io.IoUtils; +import android.os.SystemClock; +import android.util.Slog; /** * A connection that can make spawn requests. @@ -103,11 +105,23 @@ class ZygoteConnection { } /** + * Temporary hack: check time since start time and log if over a fixed threshold. + * + */ + private void checkTime(long startTime, String where) { + long now = SystemClock.elapsedRealtime(); + if ((now-startTime) > 1000) { + // If we are taking more than a second, log about it. + Slog.w(TAG, "Slow operation: " + (now-startTime) + "ms so far, now at " + where); + } + } + + /** * Returns the file descriptor of the associated socket. * * @return null-ok; file descriptor */ - FileDescriptor getFileDesciptor() { + FileDescriptor getFileDescriptor() { return mSocket.getFileDescriptor(); } @@ -131,6 +145,8 @@ class ZygoteConnection { Arguments parsedArgs = null; FileDescriptor[] descriptors; + long startTime = SystemClock.elapsedRealtime(); + try { args = readArgumentList(); descriptors = mSocket.getAncillaryFileDescriptors(); @@ -140,6 +156,7 @@ class ZygoteConnection { return true; } + checkTime(startTime, "zygoteConnection.runOnce: readArgumentList"); if (args == null) { // EOF reached. closeSocket(); @@ -171,14 +188,19 @@ class ZygoteConnection { ", effective=0x" + Long.toHexString(parsedArgs.effectiveCapabilities)); } + applyUidSecurityPolicy(parsedArgs, peer, peerSecurityContext); applyRlimitSecurityPolicy(parsedArgs, peer, peerSecurityContext); applyInvokeWithSecurityPolicy(parsedArgs, peer, peerSecurityContext); applyseInfoSecurityPolicy(parsedArgs, peer, peerSecurityContext); + checkTime(startTime, "zygoteConnection.runOnce: apply security policies"); + applyDebuggerSystemProperty(parsedArgs); applyInvokeWithSystemProperty(parsedArgs); + checkTime(startTime, "zygoteConnection.runOnce: apply security policies"); + int[][] rlimits = null; if (parsedArgs.rlimits != null) { @@ -220,9 +242,11 @@ class ZygoteConnection { fd = null; + checkTime(startTime, "zygoteConnection.runOnce: preForkAndSpecialize"); pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids, parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo, parsedArgs.niceName, fdsToClose); + checkTime(startTime, "zygoteConnection.runOnce: postForkAndSpecialize"); } catch (IOException ex) { logAndPrintError(newStderr, "Exception creating pipe", ex); } catch (ErrnoException ex) { diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java index 051de6e5d1f8..0aee0e385d2a 100644 --- a/core/java/com/android/internal/os/ZygoteInit.java +++ b/core/java/com/android/internal/os/ZygoteInit.java @@ -770,7 +770,7 @@ public class ZygoteInit { } else if (index == 0) { ZygoteConnection newPeer = acceptCommandPeer(abiList); peers.add(newPeer); - fds.add(newPeer.getFileDesciptor()); + fds.add(newPeer.getFileDescriptor()); } else { boolean done; done = peers.get(index).runOnce(); diff --git a/core/jni/android_ddm_DdmHandleNativeHeap.cpp b/core/jni/android_ddm_DdmHandleNativeHeap.cpp index f5eaf94b15d2..9b963209f892 100644 --- a/core/jni/android_ddm_DdmHandleNativeHeap.cpp +++ b/core/jni/android_ddm_DdmHandleNativeHeap.cpp @@ -35,7 +35,15 @@ extern "C" void get_malloc_leak_info(uint8_t** info, size_t* overallSize, extern "C" void free_malloc_leak_info(uint8_t* info); +#define DDMS_HEADER_SIGNATURE 0x812345dd +#define DDMS_VERSION 2 + struct Header { +#if defined(__LP64__) + uint32_t signature; + uint16_t version; + uint16_t pointerSize; +#endif size_t mapSize; size_t allocSize; size_t allocInfoSize; @@ -77,6 +85,12 @@ static jbyteArray DdmHandleNativeHeap_getLeakInfo(JNIEnv* env, jobject) { ALOGD("*** mapSize: %d allocSize: %d allocInfoSize: %d totalMemory: %d", header.mapSize, header.allocSize, header.allocInfoSize, header.totalMemory); +#if defined(__LP64__) + header.signature = DDMS_HEADER_SIGNATURE; + header.version = DDMS_VERSION; + header.pointerSize = sizeof(void*); +#endif + jbyteArray array = env->NewByteArray(sizeof(Header) + header.mapSize + header.allocSize); if (array != NULL) { env->SetByteArrayRegion(array, 0, diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp index 1f7acecb927c..3d2d47196f60 100644 --- a/core/jni/com_android_internal_os_Zygote.cpp +++ b/core/jni/com_android_internal_os_Zygote.cpp @@ -43,6 +43,7 @@ #include <utils/String8.h> #include <selinux/android.h> #include <processgroup/processgroup.h> +#include <inttypes.h> #include "android_runtime/AndroidRuntime.h" #include "JNIHelp.h" @@ -398,6 +399,22 @@ void SetThreadName(const char* thread_name) { } } + // Temporary timing check. +uint64_t MsTime() { + timespec now; + clock_gettime(CLOCK_MONOTONIC, &now); + return static_cast<uint64_t>(now.tv_sec) * UINT64_C(1000) + now.tv_nsec / UINT64_C(1000000); +} + + +void ckTime(uint64_t start, const char* where) { + uint64_t now = MsTime(); + if ((now-start) > 1000) { + // If we are taking more than a second, log about it. + ALOGW("Slow operation: %"PRIu64" ms in %s", (uint64_t)(now-start), where); + } +} + // Utility routine to fork zygote and specialize the child process. static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray javaGids, jint debug_flags, jobjectArray javaRlimits, @@ -405,7 +422,9 @@ static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArra jint mount_external, jstring java_se_info, jstring java_se_name, bool is_system_server, jintArray fdsToClose) { + uint64_t start = MsTime(); SetSigChldHandler(); + ckTime(start, "ForkAndSpecializeCommon:SetSigChldHandler"); pid_t pid = fork(); @@ -413,9 +432,12 @@ static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArra // The child process. gMallocLeakZygoteChild = 1; + // Clean up any descriptors which must be closed immediately DetachDescriptors(env, fdsToClose); + ckTime(start, "ForkAndSpecializeCommon:Fork and detach"); + // Keep capabilities across UID change, unless we're staying root. if (uid != 0) { EnableKeepCapabilities(env); @@ -518,7 +540,10 @@ static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArra UnsetSigChldHandler(); + ckTime(start, "ForkAndSpecializeCommon:child process setup"); + env->CallStaticVoidMethod(gZygoteClass, gCallPostForkChildHooks, debug_flags); + ckTime(start, "ForkAndSpecializeCommon:PostForkChildHooks returns"); if (env->ExceptionCheck()) { ALOGE("Error calling post fork hooks."); RuntimeAbort(env); diff --git a/core/res/res/drawable/time_picker_header_material.xml b/core/res/res/drawable/time_picker_header_material.xml new file mode 100644 index 000000000000..cdb92b646a92 --- /dev/null +++ b/core/res/res/drawable/time_picker_header_material.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 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. +--> + +<ripple xmlns:android="http://schemas.android.com/apk/res/android" + android:color="?attr/colorControlHighlight"> + <item> + <color android:color="?attr/colorAccent" /> + </item> +</ripple> diff --git a/core/res/res/layout-land/time_picker_holo.xml b/core/res/res/layout-land/time_picker_holo.xml index f316f1b48de2..ce90a5b5ddbc 100644 --- a/core/res/res/layout-land/time_picker_holo.xml +++ b/core/res/res/layout-land/time_picker_holo.xml @@ -21,7 +21,6 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal" - android:focusable="true" android:layout_marginLeft="@dimen/timepicker_minimum_margin_sides" android:layout_marginRight="@dimen/timepicker_minimum_margin_sides" android:layout_marginTop="@dimen/timepicker_minimum_margin_top_bottom" @@ -42,7 +41,5 @@ android:id="@+id/radial_picker" android:layout_width="@dimen/timepicker_radial_picker_dimen" android:layout_height="match_parent" - android:layout_gravity="center" - android:focusable="true" - android:focusableInTouchMode="true" /> + android:layout_gravity="center" /> </LinearLayout> diff --git a/core/res/res/layout/time_picker_holo.xml b/core/res/res/layout/time_picker_holo.xml index 483eb6db9f8d..08d221149cbb 100644 --- a/core/res/res/layout/time_picker_holo.xml +++ b/core/res/res/layout/time_picker_holo.xml @@ -18,20 +18,17 @@ --> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="wrap_content" - android:layout_height="match_parent" - android:orientation="vertical" - android:focusable="true" > + android:layout_width="wrap_content" + android:layout_height="match_parent" + android:orientation="vertical"> <include - layout="@layout/time_header_label" - android:layout_width="match_parent" - android:layout_height="@dimen/timepicker_header_height" - android:layout_gravity="center" /> + layout="@layout/time_header_label" + android:layout_width="match_parent" + android:layout_height="@dimen/timepicker_header_height" + android:layout_gravity="center" /> <android.widget.RadialTimePickerView - android:id="@+id/radial_picker" - android:layout_width="wrap_content" - android:layout_height="@dimen/timepicker_radial_picker_dimen" - android:layout_gravity="center" - android:focusable="true" - android:focusableInTouchMode="true" /> + android:id="@+id/radial_picker" + android:layout_width="wrap_content" + android:layout_height="@dimen/timepicker_radial_picker_dimen" + android:layout_gravity="center" /> </LinearLayout> diff --git a/core/res/res/values-mcc310-mnc410/config.xml b/core/res/res/values-mcc310-mnc410/config.xml index 8069d13fa09d..edf6d9f4f859 100644 --- a/core/res/res/values-mcc310-mnc410/config.xml +++ b/core/res/res/values-mcc310-mnc410/config.xml @@ -46,4 +46,9 @@ <item>GPS_LOCK=1</item> <item>LPP_PROFILE=3</item> </string-array> + <!-- Do not translate. Defines the slots is Two Digit Number for dialing normally not USSD --> + <string-array name="config_twoDigitNumberPattern"> + <item>"0"</item> + <item>"00"</item> + </string-array> </resources> diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index 46229959b106..d1cc1fd7a314 100644 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -4346,7 +4346,7 @@ <!-- @hide The layout of the legacy DatePicker. --> <attr name="legacyLayout" /> <!-- The background color for the date selector 's day of week. --> - <attr name="dayOfWeekBackgroundColor" format="color" /> + <attr name="dayOfWeekBackground" format="color|reference" /> <!-- The text color for the date selector's day of week. --> <attr name="dayOfWeekTextAppearance" format="reference" /> <!-- The month's text appearance in the date selector. --> @@ -4355,8 +4355,8 @@ <attr name="headerDayOfMonthTextAppearance" format="reference" /> <!-- The year's text appearance in the date selector. --> <attr name="headerYearTextAppearance" format="reference" /> - <!-- The background color for the date selector. --> - <attr name="headerBackgroundColor" /> + <!-- The background for the date selector. --> + <attr name="headerBackground" /> <!-- @hide The selected text color for the date selector. Used as a backup if the text appearance does not explicitly have a color set for the selected state. --> @@ -4653,29 +4653,29 @@ <attr name="legacyLayout" format="reference" /> <!-- @hide The layout of the time picker. --> <attr name="internalLayout" /> - <!-- The text appearance for the AM/PM header of the TimePicker. --> + <!-- The text appearance for the AM/PM header. --> <attr name="headerAmPmTextAppearance" format="reference" /> - <!-- The text appearance for the time header of the TimePicker. --> + <!-- The text appearance for the time header. --> <attr name="headerTimeTextAppearance" format="reference" /> <!-- @hide The text color for selected time header of the TimePicker. This will override the value from the text appearance if it does not explicitly have a color set for the selected state. --> <attr name="headerSelectedTextColor" format="color" /> - <!-- The background color for the header of the TimePicker. --> - <attr name="headerBackgroundColor" format="color" /> - <!-- The color for the hours/minutes numbers of the TimePicker. --> + <!-- The background for the header containing the currently selected time. --> + <attr name="headerBackground" /> + <!-- The color for the hours/minutes numbers. --> <attr name="numbersTextColor" format="color" /> - <!-- The background color for the hours/minutes numbers of the TimePicker. --> + <!-- The background color for the hours/minutes numbers. --> <attr name="numbersBackgroundColor" format="color" /> - <!-- The color for the AM/PM selectors of the TimePicker. --> + <!-- The color for the AM/PM selectors. --> <attr name="amPmTextColor" format="color" /> - <!-- The background color state list for the AM/PM selectors of the TimePicker. --> + <!-- The background color state list for the AM/PM selectors. --> <attr name="amPmBackgroundColor" format="color" /> <!-- @hide The background color for the AM/PM selectors of the TimePicker when selected. Used if the background color does not explicitly have a color set for the selected state. --> <attr name="amPmSelectedBackgroundColor" format="color" /> - <!-- The color for the hours/minutes selector of the TimePicker. --> + <!-- The color for the hours/minutes selector. --> <attr name="numbersSelectorColor" format="color" /> <!-- Defines the look of the widget. Prior to the L release, the only choice was spinner. As of L, with the Material theme selected, the default layout is clock, @@ -5686,12 +5686,12 @@ <attr name="maximumAngle" format="float" /> </declare-styleable> - <!-- Use <code>patternMotion</code> as the root tag of the XML resource that - describes a {@link android.transition.PatternMotion}. This must be used + <!-- Use <code>patternPathMotion</code> as the root tag of the XML resource that + describes a {@link android.transition.PatternPathMotion}. This must be used within a transition with which the PathMotion should be associated. --> - <declare-styleable name="PatternMotion"> - <!-- The path string describing the pattern to use for the PathMotion. --> - <attr name="pathData" /> + <declare-styleable name="PatternPathMotion"> + <!-- The path string describing the pattern to use for the PathPathMotion. --> + <attr name="patternPathData" format="string" /> </declare-styleable> <!-- ========================== --> @@ -6600,12 +6600,12 @@ <flag name="vertical" value="0x2" /> </attr> <!-- Optional parameter which indicates where this widget can be shown, - ie. home screen, keyguard, recents or any combination thereof. + ie. home screen, keyguard, search bar or any combination thereof. Supports combined values using | operator. --> <attr name="widgetCategory" format="integer"> <flag name="home_screen" value="0x1" /> <flag name="keyguard" value="0x2" /> - <flag name="recents" value="0x4" /> + <flag name="searchbox" value="0x4" /> </attr> </declare-styleable> @@ -7435,6 +7435,9 @@ <!-- @removed --> <attr name="__removed1" format="reference" /> + <!-- TODO: Spacer to be removed from here and public.xml --> + <attr name="__removed2" format="reference" /> + <!-- Attributes that can be used with <code>rating-system-definition</code> tags inside of the XML resource that describes TV content rating of a {@link android.media.tv.TvInputService}, which is referenced from its diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index d68d12a899d7..b63b91d88908 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -374,7 +374,7 @@ <bool name="config_useAttentionLight">false</bool> <!-- If this is true, the screen will fade off. --> - <bool name="config_animateScreenLights">true</bool> + <bool name="config_animateScreenLights">false</bool> <!-- If this is true, key chords can be used to take a screenshot on the device. --> <bool name="config_enableScreenshotChord">true</bool> diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml index 75c0e2ccf8c9..a4c347453e94 100644 --- a/core/res/res/values/public.xml +++ b/core/res/res/values/public.xml @@ -2235,7 +2235,7 @@ <public type="attr" name="launchTaskBehindTargetAnimation" /> <public type="attr" name="launchTaskBehindSourceAnimation" /> <public type="attr" name="restrictionType" /> - <public type="attr" name="dayOfWeekBackgroundColor" /> + <public type="attr" name="dayOfWeekBackground" /> <public type="attr" name="dayOfWeekTextAppearance" /> <public type="attr" name="headerMonthTextAppearance" /> <public type="attr" name="headerDayOfMonthTextAppearance" /> @@ -2248,7 +2248,7 @@ <public type="attr" name="timePickerDialogTheme" /> <public type="attr" name="headerTimeTextAppearance" /> <public type="attr" name="headerAmPmTextAppearance" /> - <public type="attr" name="headerBackgroundColor" /> + <public type="attr" name="__removed2" /> <public type="attr" name="numbersTextColor" /> <public type="attr" name="numbersBackgroundColor" /> <public type="attr" name="numbersSelectorColor" /> @@ -2290,6 +2290,7 @@ <public type="attr" name="fragmentReenterTransition" /> <public type="attr" name="fragmentAllowEnterTransitionOverlap" /> <public type="attr" name="fragmentAllowReturnTransitionOverlap" /> + <public type="attr" name="patternPathData" /> <public-padding type="dimen" name="l_resource_pad" end="0x01050010" /> diff --git a/core/res/res/values/styles_holo.xml b/core/res/res/values/styles_holo.xml index 2a54ccff7f73..c7d2db1f754a 100644 --- a/core/res/res/values/styles_holo.xml +++ b/core/res/res/values/styles_holo.xml @@ -468,7 +468,7 @@ please see styles_device_defaults.xml. <item name="internalLayout">@layout/time_picker_holo</item> <item name="headerTimeTextAppearance">@style/TextAppearance.Holo.TimePicker.TimeLabel</item> <item name="headerAmPmTextAppearance">@style/TextAppearance.Holo.TimePicker.AmPmLabel</item> - <item name="headerBackgroundColor">@color/timepicker_default_background_holo_dark</item> + <item name="headerBackground">@color/timepicker_default_background_holo_dark</item> <item name="headerSelectedTextColor">@color/holo_blue_light</item> <item name="numbersTextColor">@color/timepicker_default_text_color_holo_dark</item> <item name="numbersBackgroundColor">@color/timepicker_default_background_holo_dark</item> @@ -484,9 +484,9 @@ please see styles_device_defaults.xml. <item name="internalLayout">@layout/date_picker_holo</item> <item name="calendarViewShown">true</item> <!-- New-style date picker attributes. --> - <item name="dayOfWeekBackgroundColor">@color/datepicker_default_header_dayofweek_background_color_holo_dark</item> + <item name="dayOfWeekBackground">@color/datepicker_default_header_dayofweek_background_color_holo_dark</item> <item name="dayOfWeekTextAppearance">@style/TextAppearance.Holo.DatePicker.DayOfWeekLabel</item> - <item name="headerBackgroundColor">@color/datepicker_default_header_selector_background_holo_dark</item> + <item name="headerBackground">@color/datepicker_default_header_selector_background_holo_dark</item> <item name="headerMonthTextAppearance">@style/TextAppearance.Holo.DatePicker.Selector.MonthLabel</item> <item name="headerDayOfMonthTextAppearance">@style/TextAppearance.Holo.DatePicker.Selector.DayOfMonthLabel</item> <item name="headerYearTextAppearance">@style/TextAppearance.Holo.DatePicker.Selector.YearLabel</item> @@ -892,7 +892,7 @@ please see styles_device_defaults.xml. <item name="internalLayout">@layout/time_picker_holo</item> <item name="headerTimeTextAppearance">@style/TextAppearance.Holo.Light.TimePicker.TimeLabel</item> <item name="headerAmPmTextAppearance">@style/TextAppearance.Holo.Light.TimePicker.AmPmLabel</item> - <item name="headerBackgroundColor">@color/timepicker_default_background_holo_light</item> + <item name="headerBackground">@color/timepicker_default_background_holo_light</item> <item name="headerSelectedTextColor">@color/holo_blue_light</item> <item name="numbersTextColor">@color/timepicker_default_text_color_holo_light</item> <item name="numbersBackgroundColor">@color/timepicker_default_background_holo_light</item> @@ -908,12 +908,12 @@ please see styles_device_defaults.xml. <item name="internalLayout">@layout/date_picker_holo</item> <item name="calendarViewShown">true</item> <!-- New-style date picker attributes. --> - <item name="dayOfWeekBackgroundColor">@color/datepicker_default_header_dayofweek_background_color_holo_light</item> + <item name="dayOfWeekBackground">@color/datepicker_default_header_dayofweek_background_color_holo_light</item> <item name="dayOfWeekTextAppearance">@style/TextAppearance.Holo.Light.DatePicker.DayOfWeekLabel</item> <item name="headerMonthTextAppearance">@style/TextAppearance.Holo.Light.DatePicker.Selector.MonthLabel</item> <item name="headerDayOfMonthTextAppearance">@style/TextAppearance.Holo.Light.DatePicker.Selector.DayOfMonthLabel</item> <item name="headerYearTextAppearance">@style/TextAppearance.Holo.Light.DatePicker.Selector.YearLabel</item> - <item name="headerBackgroundColor">@color/datepicker_default_header_selector_background_holo_light</item> + <item name="headerBackground">@color/datepicker_default_header_selector_background_holo_light</item> <item name="headerSelectedTextColor">@color/holo_blue_light</item> <item name="yearListItemTextAppearance">@style/TextAppearance.Holo.Light.DatePicker.List.YearLabel</item> <item name="yearListSelectorColor">@color/datepicker_default_circle_background_color_holo_light</item> diff --git a/core/res/res/values/styles_material.xml b/core/res/res/values/styles_material.xml index 77484e6e119c..a7335af11087 100644 --- a/core/res/res/values/styles_material.xml +++ b/core/res/res/values/styles_material.xml @@ -619,7 +619,7 @@ please see styles_device_defaults.xml. <item name="headerTimeTextAppearance">@style/TextAppearance.Material.TimePicker.TimeLabel</item> <item name="headerAmPmTextAppearance">@style/TextAppearance.Material.TimePicker.AmPmLabel</item> <item name="headerSelectedTextColor">?attr/textColorPrimaryInverse</item> - <item name="headerBackgroundColor">?attr/colorAccent</item> + <item name="headerBackground">@drawable/time_picker_header_material</item> <item name="numbersTextColor">?attr/textColorSecondary</item> <item name="numbersBackgroundColor">#10ffffff</item> <item name="amPmTextColor">?attr/textColorSecondary</item> @@ -634,13 +634,13 @@ please see styles_device_defaults.xml. <!-- Attributes for new-style DatePicker. --> <item name="internalLayout">@layout/date_picker_holo</item> <item name="calendarViewShown">true</item> - <item name="dayOfWeekBackgroundColor">#10000000</item> + <item name="dayOfWeekBackground">#10000000</item> <item name="dayOfWeekTextAppearance">@style/TextAppearance.Material.DatePicker.DayOfWeekLabel</item> <item name="headerMonthTextAppearance">@style/TextAppearance.Material.DatePicker.MonthLabel</item> <item name="headerDayOfMonthTextAppearance">@style/TextAppearance.Material.DatePicker.DayOfMonthLabel</item> <item name="headerYearTextAppearance">@style/TextAppearance.Material.DatePicker.YearLabel</item> <item name="headerSelectedTextColor">?attr/textColorPrimaryInverse</item> - <item name="headerBackgroundColor">?attr/colorAccent</item> + <item name="headerBackground">?attr/colorAccent</item> <item name="yearListItemTextAppearance">@style/TextAppearance.Material.DatePicker.List.YearLabel</item> <item name="yearListSelectorColor">?attr/colorControlActivated</item> <item name="calendarTextColor">?attr/textColorSecondary</item> diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java index f18694b07e59..0927ffd548cf 100644 --- a/graphics/java/android/graphics/Canvas.java +++ b/graphics/java/android/graphics/Canvas.java @@ -203,7 +203,7 @@ public class Canvas { */ public void setBitmap(@Nullable Bitmap bitmap) { if (isHardwareAccelerated()) { - throw new RuntimeException("Can't set a bitmap device on a GL canvas"); + throw new RuntimeException("Can't set a bitmap device on a HW accelerated canvas"); } if (bitmap == null) { diff --git a/graphics/java/android/graphics/Picture.java b/graphics/java/android/graphics/Picture.java index 5aa7c6a8df52..d28c3d574d05 100644 --- a/graphics/java/android/graphics/Picture.java +++ b/graphics/java/android/graphics/Picture.java @@ -122,6 +122,11 @@ public class Picture { * @param canvas The picture is drawn to this canvas */ public void draw(Canvas canvas) { + if (canvas.isHardwareAccelerated()) { + throw new IllegalArgumentException( + "Picture playback is only supported on software canvas."); + } + if (mRecordingCanvas != null) { endRecording(); } diff --git a/graphics/java/android/graphics/PorterDuffColorFilter.java b/graphics/java/android/graphics/PorterDuffColorFilter.java index c078c1c05642..705f5e6cf5be 100644 --- a/graphics/java/android/graphics/PorterDuffColorFilter.java +++ b/graphics/java/android/graphics/PorterDuffColorFilter.java @@ -60,6 +60,8 @@ public class PorterDuffColorFilter extends ColorFilter { * @see Color * @see #getColor() * @see #getMode() + * + * @hide */ public void setColor(int color) { mColor = color; @@ -84,6 +86,8 @@ public class PorterDuffColorFilter extends ColorFilter { * @see PorterDuff * @see #getMode() * @see #getColor() + * + * @hide */ public void setMode(PorterDuff.Mode mode) { mMode = mode; diff --git a/graphics/java/android/graphics/drawable/Ripple.java b/graphics/java/android/graphics/drawable/Ripple.java index cd919a627f35..43922b8e3f6a 100644 --- a/graphics/java/android/graphics/drawable/Ripple.java +++ b/graphics/java/android/graphics/drawable/Ripple.java @@ -419,18 +419,22 @@ class Ripple { private void endSoftwareAnimations() { if (mAnimRadius != null) { mAnimRadius.end(); + mAnimRadius = null; } if (mAnimOpacity != null) { mAnimOpacity.end(); + mAnimOpacity = null; } if (mAnimX != null) { mAnimX.end(); + mAnimX = null; } if (mAnimY != null) { mAnimY.end(); + mAnimY = null; } } @@ -506,18 +510,22 @@ class Ripple { private void cancelSoftwareAnimations() { if (mAnimRadius != null) { mAnimRadius.cancel(); + mAnimRadius = null; } if (mAnimOpacity != null) { mAnimOpacity.cancel(); + mAnimOpacity = null; } if (mAnimX != null) { mAnimX.cancel(); + mAnimX = null; } if (mAnimY != null) { mAnimY.cancel(); + mAnimY = null; } } diff --git a/graphics/java/android/graphics/drawable/RippleBackground.java b/graphics/java/android/graphics/drawable/RippleBackground.java index 4e68a60f36a4..80ecea32749b 100644 --- a/graphics/java/android/graphics/drawable/RippleBackground.java +++ b/graphics/java/android/graphics/drawable/RippleBackground.java @@ -326,6 +326,7 @@ class RippleBackground { private void endSoftwareAnimations() { if (mAnimOuterOpacity != null) { mAnimOuterOpacity.end(); + mAnimOuterOpacity = null; } } @@ -413,6 +414,7 @@ class RippleBackground { private void cancelSoftwareAnimations() { if (mAnimOuterOpacity != null) { mAnimOuterOpacity.cancel(); + mAnimOuterOpacity = null; } } diff --git a/libs/hwui/Layer.cpp b/libs/hwui/Layer.cpp index e6bc4db5a323..25caae3a9e0c 100644 --- a/libs/hwui/Layer.cpp +++ b/libs/hwui/Layer.cpp @@ -54,6 +54,7 @@ Layer::Layer(RenderState& renderState, const uint32_t layerWidth, const uint32_t convexMask = NULL; caches.resourceCache.incrementRefcount(this); rendererLightPosDirty = true; + wasBuildLayered = false; renderState.registerLayer(this); } diff --git a/libs/hwui/Layer.h b/libs/hwui/Layer.h index 38c29c7796b7..911b99880334 100644 --- a/libs/hwui/Layer.h +++ b/libs/hwui/Layer.h @@ -306,6 +306,7 @@ public: Rect dirtyRect; bool debugDrawUpdate; bool hasDrawnSinceUpdate; + bool wasBuildLayered; private: void requireRenderer(); diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp index 0f36c0658dd0..dbd273d037d2 100755 --- a/libs/hwui/OpenGLRenderer.cpp +++ b/libs/hwui/OpenGLRenderer.cpp @@ -605,6 +605,12 @@ void OpenGLRenderer::flushLayerUpdates() { AutoFence fence; } +void OpenGLRenderer::markLayersAsBuildLayers() { + for (size_t i = 0; i < mLayerUpdates.size(); i++) { + mLayerUpdates[i]->wasBuildLayered = true; + } +} + /////////////////////////////////////////////////////////////////////////////// // State management /////////////////////////////////////////////////////////////////////////////// diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h index e9ca5d9c839c..e295b1a8659b 100755 --- a/libs/hwui/OpenGLRenderer.h +++ b/libs/hwui/OpenGLRenderer.h @@ -150,6 +150,7 @@ public: void cancelLayerUpdate(Layer* layer); void clearLayerUpdates(); void flushLayerUpdates(); + void markLayersAsBuildLayers(); virtual int saveLayer(float left, float top, float right, float bottom, const SkPaint* paint, int flags) { diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp index 6a92a6e4f35e..a10e70f493c3 100644 --- a/libs/hwui/RenderNode.cpp +++ b/libs/hwui/RenderNode.cpp @@ -58,6 +58,19 @@ void RenderNode::outputLogBuffer(int fd) { fflush(file); } +void RenderNode::debugDumpLayers(const char* prefix) { + if (mLayer) { + ALOGD("%sNode %p (%s) has layer %p (fbo = %u, wasBuildLayered = %s)", + prefix, this, getName(), mLayer, mLayer->getFbo(), + mLayer->wasBuildLayered ? "true" : "false"); + } + if (mDisplayListData) { + for (size_t i = 0; i < mDisplayListData->children().size(); i++) { + mDisplayListData->children()[i]->mRenderNode->debugDumpLayers(prefix); + } + } +} + RenderNode::RenderNode() : mDirtyPropertyFields(0) , mNeedsDisplayListDataSync(false) @@ -413,7 +426,7 @@ void RenderNode::setViewProperties(OpenGLRenderer& renderer, T& handler) { handler(op, PROPERTY_SAVECOUNT, properties().getClipToBounds()); } - // TODO: support both reveal clip and outline clip simultaneously + // TODO: support nesting round rect clips if (mProperties.getRevealClip().willClip()) { Rect bounds; mProperties.getRevealClip().getBounds(&bounds); @@ -421,7 +434,6 @@ void RenderNode::setViewProperties(OpenGLRenderer& renderer, T& handler) { } else if (mProperties.getOutline().willClip()) { renderer.setClippingOutline(handler.allocator(), &(mProperties.getOutline())); } - } /** diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h index d8979977bf09..f32928301fc4 100644 --- a/libs/hwui/RenderNode.h +++ b/libs/hwui/RenderNode.h @@ -102,6 +102,7 @@ public: }; ANDROID_API static void outputLogBuffer(int fd); + void debugDumpLayers(const char* prefix); ANDROID_API void setStagingDisplayList(DisplayListData* newData); diff --git a/libs/hwui/RenderState.cpp b/libs/hwui/RenderState.cpp index 9948b44ac703..a7c5e85d9123 100644 --- a/libs/hwui/RenderState.cpp +++ b/libs/hwui/RenderState.cpp @@ -15,6 +15,8 @@ */ #include "RenderState.h" +#include "renderthread/CanvasContext.h" + namespace android { namespace uirenderer { @@ -38,6 +40,17 @@ void RenderState::onGLContextCreated() { void RenderState::onGLContextDestroyed() { if (CC_UNLIKELY(!mActiveLayers.empty())) { mCaches->dumpMemoryUsage(); + for (std::set<renderthread::CanvasContext*>::iterator cit = mRegisteredContexts.begin(); + cit != mRegisteredContexts.end(); cit++) { + renderthread::CanvasContext* context = *cit; + ALOGD("Context: %p (root = %p)", context, context->mRootRenderNode.get()); + ALOGD(" Prefeteched layers: %zu", context->mPrefetechedLayers.size()); + for (std::set<RenderNode*>::iterator pit = context->mPrefetechedLayers.begin(); + pit != context->mPrefetechedLayers.end(); pit++) { + (*pit)->debugDumpLayers(" "); + } + context->mRootRenderNode->debugDumpLayers(" "); + } LOG_ALWAYS_FATAL("layers have survived gl context destruction"); } } diff --git a/libs/hwui/RenderState.h b/libs/hwui/RenderState.h index 3915fb5f3f83..c7ab197c4fb2 100644 --- a/libs/hwui/RenderState.h +++ b/libs/hwui/RenderState.h @@ -29,6 +29,7 @@ namespace android { namespace uirenderer { namespace renderthread { +class CanvasContext; class RenderThread; } @@ -57,6 +58,14 @@ public: mActiveLayers.erase(layer); } + void registerCanvasContext(renderthread::CanvasContext* context) { + mRegisteredContexts.insert(context); + } + + void unregisterCanvasContext(renderthread::CanvasContext* context) { + mRegisteredContexts.erase(context); + } + private: friend class renderthread::RenderThread; friend class Caches; @@ -69,6 +78,7 @@ private: Caches* mCaches; std::set<const Layer*> mActiveLayers; + std::set<renderthread::CanvasContext*> mRegisteredContexts; GLsizei mViewportWidth; GLsizei mViewportHeight; diff --git a/libs/hwui/Snapshot.cpp b/libs/hwui/Snapshot.cpp index ecc47d29a647..cf8229fdffb9 100644 --- a/libs/hwui/Snapshot.cpp +++ b/libs/hwui/Snapshot.cpp @@ -216,14 +216,22 @@ void Snapshot::resetTransform(float x, float y, float z) { // Clipping round rect /////////////////////////////////////////////////////////////////////////////// -void Snapshot::setClippingRoundRect(LinearAllocator& allocator, const Rect& bounds, float radius) { +void Snapshot::setClippingRoundRect(LinearAllocator& allocator, const Rect& bounds, + float radius, bool highPriority) { if (bounds.isEmpty()) { clipRect->setEmpty(); return; } + if (roundRectClipState && roundRectClipState->highPriority) { + // ignore, don't replace, already have a high priority clip + return; + } + RoundRectClipState* state = new (allocator) RoundRectClipState; + state->highPriority = highPriority; + // store the inverse drawing matrix Matrix4 roundRectDrawingMatrix; roundRectDrawingMatrix.load(getOrthoMatrix()); diff --git a/libs/hwui/Snapshot.h b/libs/hwui/Snapshot.h index ad4ee9dee6a0..549de9baa21b 100644 --- a/libs/hwui/Snapshot.h +++ b/libs/hwui/Snapshot.h @@ -55,6 +55,7 @@ public: || rect.intersects(dangerRects[3]); } + bool highPriority; Matrix4 matrix; Rect dangerRects[4]; Rect innerRect; @@ -166,8 +167,11 @@ public: /** * Sets (and replaces) the current clipping outline + * + * If the current round rect clip is high priority, the incoming clip is ignored. */ - void setClippingRoundRect(LinearAllocator& allocator, const Rect& bounds, float radius); + void setClippingRoundRect(LinearAllocator& allocator, const Rect& bounds, + float radius, bool highPriority); /** * Indicates whether this snapshot should be ignored. A snapshot diff --git a/libs/hwui/StatefulBaseRenderer.cpp b/libs/hwui/StatefulBaseRenderer.cpp index 3e1aed3dfa01..12b8c8db28ea 100644 --- a/libs/hwui/StatefulBaseRenderer.cpp +++ b/libs/hwui/StatefulBaseRenderer.cpp @@ -198,13 +198,13 @@ void StatefulBaseRenderer::setClippingOutline(LinearAllocator& allocator, const clipRect(bounds.left, bounds.top, bounds.right, bounds.bottom, SkRegion::kIntersect_Op); } if (outlineIsRounded) { - setClippingRoundRect(allocator, bounds, radius); + setClippingRoundRect(allocator, bounds, radius, false); } } void StatefulBaseRenderer::setClippingRoundRect(LinearAllocator& allocator, - const Rect& rect, float radius) { - mSnapshot->setClippingRoundRect(allocator, rect, radius); + const Rect& rect, float radius, bool highPriority) { + mSnapshot->setClippingRoundRect(allocator, rect, radius, highPriority); } diff --git a/libs/hwui/StatefulBaseRenderer.h b/libs/hwui/StatefulBaseRenderer.h index c6974b4d39de..745e48a8759f 100644 --- a/libs/hwui/StatefulBaseRenderer.h +++ b/libs/hwui/StatefulBaseRenderer.h @@ -97,7 +97,7 @@ public: */ void setClippingOutline(LinearAllocator& allocator, const Outline* outline); void setClippingRoundRect(LinearAllocator& allocator, - const Rect& rect, float radius); + const Rect& rect, float radius, bool highPriority = true); inline const mat4* currentTransform() const { return mSnapshot->transform; diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp index 428e42605107..4129a89b6ef8 100644 --- a/libs/hwui/renderthread/CanvasContext.cpp +++ b/libs/hwui/renderthread/CanvasContext.cpp @@ -48,11 +48,13 @@ CanvasContext::CanvasContext(RenderThread& thread, bool translucent, , mHaveNewSurface(false) , mRootRenderNode(rootRenderNode) { mAnimationContext = contextFactory->createAnimationContext(mRenderThread.timeLord()); + mRenderThread.renderState().registerCanvasContext(this); } CanvasContext::~CanvasContext() { destroy(); delete mAnimationContext; + mRenderThread.renderState().unregisterCanvasContext(this); } void CanvasContext::destroy() { @@ -299,6 +301,7 @@ void CanvasContext::buildLayer(RenderNode* node) { // purposes when the frame is actually drawn node->setPropertyFieldsDirty(RenderNode::GENERIC); + mCanvas->markLayersAsBuildLayers(); mCanvas->flushLayerUpdates(); node->incStrong(0); diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h index 5984fd0950a2..2460f6b845b2 100644 --- a/libs/hwui/renderthread/CanvasContext.h +++ b/libs/hwui/renderthread/CanvasContext.h @@ -42,6 +42,7 @@ class DeferredLayerUpdater; class OpenGLRenderer; class Rect; class Layer; +class RenderState; namespace renderthread { @@ -95,6 +96,9 @@ public: private: friend class RegisterFrameCallbackTask; + // TODO: Replace with something better for layer & other GL object + // lifecycle tracking + friend class android::uirenderer::RenderState; void setSurface(ANativeWindow* window); void swapBuffers(); diff --git a/libs/hwui/renderthread/RenderThread.h b/libs/hwui/renderthread/RenderThread.h index 0b91e9dd97aa..c461f3a25859 100644 --- a/libs/hwui/renderthread/RenderThread.h +++ b/libs/hwui/renderthread/RenderThread.h @@ -40,6 +40,7 @@ class RenderState; namespace renderthread { +class CanvasContext; class DispatchFrameCallbacks; class EglManager; class RenderProxy; diff --git a/location/java/android/location/Location.java b/location/java/android/location/Location.java index bdd119582add..fcf222b01267 100644 --- a/location/java/android/location/Location.java +++ b/location/java/android/location/Location.java @@ -16,6 +16,7 @@ package android.location; +import android.annotation.SystemApi; import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; @@ -771,6 +772,7 @@ public class Location implements Parcelable { * @see #makeComplete * @hide */ + @SystemApi public boolean isComplete() { if (mProvider == null) return false; if (!mHasAccuracy) return false; @@ -788,6 +790,7 @@ public class Location implements Parcelable { * @see #isComplete * @hide */ + @SystemApi public void makeComplete() { if (mProvider == null) mProvider = "?"; if (!mHasAccuracy) { @@ -957,6 +960,7 @@ public class Location implements Parcelable { * @param isFromMockProvider true if this Location came from a mock provider, false otherwise * @hide */ + @SystemApi public void setIsFromMockProvider(boolean isFromMockProvider) { mIsFromMockProvider = isFromMockProvider; } diff --git a/location/java/android/location/LocationRequest.java b/location/java/android/location/LocationRequest.java index c9162fe1892f..271f2bbe3ae1 100644 --- a/location/java/android/location/LocationRequest.java +++ b/location/java/android/location/LocationRequest.java @@ -16,6 +16,7 @@ package android.location; +import android.annotation.SystemApi; import android.os.Parcel; import android.os.Parcelable; import android.os.SystemClock; @@ -84,6 +85,7 @@ import android.util.TimeUtils; * * @hide */ +@SystemApi public final class LocationRequest implements Parcelable { /** * Used with {@link #setQuality} to request the most accurate locations available. @@ -166,6 +168,7 @@ public final class LocationRequest implements Parcelable { } /** @hide */ + @SystemApi public static LocationRequest createFromDeprecatedProvider(String provider, long minTime, float minDistance, boolean singleShot) { if (minTime < 0) minTime = 0; @@ -191,6 +194,7 @@ public final class LocationRequest implements Parcelable { } /** @hide */ + @SystemApi public static LocationRequest createFromDeprecatedCriteria(Criteria criteria, long minTime, float minDistance, boolean singleShot) { if (minTime < 0) minTime = 0; @@ -475,6 +479,7 @@ public final class LocationRequest implements Parcelable { /** @hide */ + @SystemApi public LocationRequest setProvider(String provider) { checkProvider(provider); mProvider = provider; @@ -482,11 +487,13 @@ public final class LocationRequest implements Parcelable { } /** @hide */ + @SystemApi public String getProvider() { return mProvider; } /** @hide */ + @SystemApi public LocationRequest setSmallestDisplacement(float meters) { checkDisplacement(meters); mSmallestDisplacement = meters; @@ -494,6 +501,7 @@ public final class LocationRequest implements Parcelable { } /** @hide */ + @SystemApi public float getSmallestDisplacement() { return mSmallestDisplacement; } @@ -508,11 +516,13 @@ public final class LocationRequest implements Parcelable { * @param workSource WorkSource defining power blame for this location request. * @hide */ + @SystemApi public void setWorkSource(WorkSource workSource) { mWorkSource = workSource; } /** @hide */ + @SystemApi public WorkSource getWorkSource() { return mWorkSource; } @@ -531,11 +541,13 @@ public final class LocationRequest implements Parcelable { * @see android.app.AppOpsManager * @hide */ + @SystemApi public void setHideFromAppOps(boolean hideFromAppOps) { mHideFromAppOps = hideFromAppOps; } /** @hide */ + @SystemApi public boolean getHideFromAppOps() { return mHideFromAppOps; } diff --git a/location/java/android/location/SettingInjectorService.java b/location/java/android/location/SettingInjectorService.java index 98c78647185e..fcd2cdec904f 100644 --- a/location/java/android/location/SettingInjectorService.java +++ b/location/java/android/location/SettingInjectorService.java @@ -196,10 +196,7 @@ public abstract class SettingInjectorService extends Service { * @deprecated not called any more */ @Deprecated - protected String onGetSummary() { - // Do not delete until no callers have @Override annotations for this method - return null; - } + protected abstract String onGetSummary(); /** * Returns the {@link android.preference.Preference#isEnabled()} value. Should not perform diff --git a/media/java/android/media/AudioPortEventHandler.java b/media/java/android/media/AudioPortEventHandler.java index 8d2c17251fa7..9db49949baf9 100644 --- a/media/java/android/media/AudioPortEventHandler.java +++ b/media/java/android/media/AudioPortEventHandler.java @@ -47,10 +47,7 @@ class AudioPortEventHandler { mListeners = new ArrayList<AudioManager.OnAudioPortUpdateListener>(); // find the looper for our new event handler - Looper looper = Looper.myLooper(); - if (looper == null) { - looper = Looper.getMainLooper(); - } + Looper looper = Looper.getMainLooper(); if (looper != null) { mHandler = new Handler(looper) { diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java index 329033cf8b4f..1d16793ec03a 100644 --- a/media/java/android/media/AudioService.java +++ b/media/java/android/media/AudioService.java @@ -1777,6 +1777,15 @@ public class AudioService extends IAudioService.Stub { return; } + if ( (mode == AudioSystem.MODE_IN_CALL) && + (mContext.checkCallingOrSelfPermission( + android.Manifest.permission.MODIFY_PHONE_STATE) + != PackageManager.PERMISSION_GRANTED)) { + Log.w(TAG, "MODIFY_PHONE_STATE Permission Denial: setMode(MODE_IN_CALL) from pid=" + + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()); + return; + } + if (mode < AudioSystem.MODE_CURRENT || mode >= AudioSystem.NUM_MODES) { return; } @@ -1798,7 +1807,7 @@ public class AudioService extends IAudioService.Stub { // must be called synchronized on mSetModeDeathHandlers // setModeInt() returns a valid PID if the audio mode was successfully set to // any mode other than NORMAL. - int setModeInt(int mode, IBinder cb, int pid) { + private int setModeInt(int mode, IBinder cb, int pid) { if (DEBUG_MODE) { Log.v(TAG, "setModeInt(mode=" + mode + ", pid=" + pid + ")"); } int newModeOwnerPid = 0; if (cb == null) { @@ -3058,7 +3067,7 @@ public class AudioService extends IAudioService.Stub { } boolean checkAudioSettingsPermission(String method) { - if (mContext.checkCallingOrSelfPermission("android.permission.MODIFY_AUDIO_SETTINGS") + if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.MODIFY_AUDIO_SETTINGS) == PackageManager.PERMISSION_GRANTED) { return true; } diff --git a/media/java/android/media/RemoteController.java b/media/java/android/media/RemoteController.java index f378cef7803e..fbfac89fb08c 100644 --- a/media/java/android/media/RemoteController.java +++ b/media/java/android/media/RemoteController.java @@ -789,8 +789,12 @@ import java.util.List; void startListeningToSessions() { final ComponentName listenerComponent = new ComponentName(mContext, mOnClientUpdateListener.getClass()); + Handler handler = null; + if (Looper.myLooper() == null) { + handler = new Handler(Looper.getMainLooper()); + } mSessionManager.addOnActiveSessionsChangedListener(mSessionListener, listenerComponent, - UserHandle.myUserId(), null); + UserHandle.myUserId(), handler); mSessionListener.onActiveSessionsChanged(mSessionManager .getActiveSessions(listenerComponent)); if (DEBUG) { diff --git a/packages/Keyguard/res/layout/keyguard_emergency_carrier_area.xml b/packages/Keyguard/res/layout/keyguard_emergency_carrier_area.xml index 78b57462f463..a083f89d42fa 100644 --- a/packages/Keyguard/res/layout/keyguard_emergency_carrier_area.xml +++ b/packages/Keyguard/res/layout/keyguard_emergency_carrier_area.xml @@ -40,39 +40,19 @@ android:visibility="gone" androidprv:allCaps="@bool/kg_use_all_caps" /> - <LinearLayout - android:layout_width="match_parent" + <com.android.keyguard.EmergencyButton + android:id="@+id/emergency_call_button" + android:layout_width="wrap_content" android:layout_height="wrap_content" + android:layout_weight="1" android:layout_marginTop="@dimen/eca_overlap" - style="?android:attr/buttonBarStyle" - android:orientation="horizontal" - android:gravity="center" - android:weightSum="2"> - - <com.android.keyguard.EmergencyButton - android:id="@+id/emergency_call_button" - android:layout_width="0dip" - android:layout_height="wrap_content" - android:layout_weight="1" - android:drawableLeft="@drawable/lockscreen_emergency_button" - android:text="@string/kg_emergency_call_label" - style="?android:attr/buttonBarButtonStyle" - android:textAppearance="?android:attr/textAppearanceMedium" - android:textSize="@dimen/kg_status_line_font_size" - android:textColor="?android:attr/textColorSecondary" - android:drawablePadding="8dip" - android:textAllCaps="@bool/kg_use_all_caps" /> - - <Button android:id="@+id/forgot_password_button" - android:layout_width="0dip" - android:layout_height="wrap_content" - android:layout_weight="1" - style="?android:attr/buttonBarButtonStyle" - android:textSize="@dimen/kg_status_line_font_size" - android:textColor="?android:attr/textColorSecondary" - android:textAppearance="?android:attr/textAppearanceMedium" - android:visibility="gone" - android:textAllCaps="@bool/kg_use_all_caps" /> - </LinearLayout> + android:drawableLeft="@drawable/lockscreen_emergency_button" + android:text="@string/kg_emergency_call_label" + style="?android:attr/buttonBarButtonStyle" + android:textAppearance="?android:attr/textAppearanceMedium" + android:textSize="@dimen/kg_status_line_font_size" + android:textColor="?android:attr/textColorSecondary" + android:drawablePadding="8dip" + android:textAllCaps="@bool/kg_use_all_caps" /> </com.android.keyguard.EmergencyCarrierArea> diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java index 65c4ce299fd6..0e01a2756c47 100644 --- a/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java +++ b/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java @@ -15,38 +15,27 @@ */ package com.android.keyguard; -import android.accounts.Account; -import android.accounts.AccountManager; -import android.accounts.AccountManagerCallback; -import android.accounts.AccountManagerFuture; -import android.accounts.AuthenticatorException; -import android.accounts.OperationCanceledException; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ValueAnimator; import android.content.Context; import android.graphics.Rect; import android.graphics.drawable.Drawable; -import android.os.Bundle; import android.os.CountDownTimer; import android.os.SystemClock; -import android.os.UserHandle; import android.text.TextUtils; import android.util.AttributeSet; import android.util.Log; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; -import android.view.animation.AccelerateInterpolator; import android.view.animation.AnimationUtils; import android.view.animation.Interpolator; -import android.widget.Button; import android.widget.LinearLayout; import com.android.internal.widget.LockPatternUtils; import com.android.internal.widget.LockPatternView; -import java.io.IOException; import java.util.List; public class KeyguardPatternView extends LinearLayout implements KeyguardSecurityView, @@ -70,9 +59,7 @@ public class KeyguardPatternView extends LinearLayout implements KeyguardSecurit private CountDownTimer mCountdownTimer = null; private LockPatternUtils mLockPatternUtils; private LockPatternView mLockPatternView; - private Button mForgotPatternButton; private KeyguardSecurityCallback mCallback; - private boolean mEnableFallback; /** * Keeps track of the last time we poked the wake lock during dispatching of the touch event. @@ -144,20 +131,8 @@ public class KeyguardPatternView extends LinearLayout implements KeyguardSecurit // vibrate mode will be the same for the life of this screen mLockPatternView.setTactileFeedbackEnabled(mLockPatternUtils.isTactileFeedbackEnabled()); - mForgotPatternButton = (Button) findViewById(R.id.forgot_password_button); - // note: some configurations don't have an emergency call area - if (mForgotPatternButton != null) { - mForgotPatternButton.setText(R.string.kg_forgot_pattern_button_text); - mForgotPatternButton.setOnClickListener(new OnClickListener() { - public void onClick(View v) { - mCallback.showBackupSecurity(); - } - }); - } - setFocusableInTouchMode(true); - maybeEnableFallback(mContext); mSecurityMessageDisplay = new KeyguardMessageArea.Helper(this); mEcaView = findViewById(R.id.keyguard_selector_fade_container); View bouncerFrameView = findViewById(R.id.keyguard_bouncer_frame); @@ -169,24 +144,6 @@ public class KeyguardPatternView extends LinearLayout implements KeyguardSecurit mHelpMessage = (KeyguardMessageArea) findViewById(R.id.keyguard_message_area); } - private void updateFooter(FooterMode mode) { - if (mForgotPatternButton == null) return; // no ECA? no footer - - switch (mode) { - case Normal: - if (DEBUG) Log.d(TAG, "mode normal"); - mForgotPatternButton.setVisibility(View.GONE); - break; - case ForgotLockPattern: - if (DEBUG) Log.d(TAG, "mode ForgotLockPattern"); - mForgotPatternButton.setVisibility(View.VISIBLE); - break; - case VerifyUnlocked: - if (DEBUG) Log.d(TAG, "mode VerifyUnlocked"); - mForgotPatternButton.setVisibility(View.GONE); - } - } - @Override public boolean onTouchEvent(MotionEvent ev) { boolean result = super.onTouchEvent(ev); @@ -217,18 +174,6 @@ public class KeyguardPatternView extends LinearLayout implements KeyguardSecurit } else { displayDefaultSecurityMessage(); } - - // the footer depends on how many total attempts the user has failed - if (mCallback.isVerifyUnlockOnly()) { - updateFooter(FooterMode.VerifyUnlocked); - } else if (mEnableFallback && - (mKeyguardUpdateMonitor.getFailedUnlockAttempts() - >= LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT)) { - updateFooter(FooterMode.ForgotLockPattern); - } else { - updateFooter(FooterMode.Normal); - } - } private void displayDefaultSecurityMessage() { @@ -291,68 +236,10 @@ public class KeyguardPatternView extends LinearLayout implements KeyguardSecurit } } - private void maybeEnableFallback(Context context) { - // Ask the account manager if we have an account that can be used as a - // fallback in case the user forgets his pattern. - AccountAnalyzer accountAnalyzer = new AccountAnalyzer(AccountManager.get(context)); - accountAnalyzer.start(); - } - - private class AccountAnalyzer implements AccountManagerCallback<Bundle> { - private final AccountManager mAccountManager; - private final Account[] mAccounts; - private int mAccountIndex; - - private AccountAnalyzer(AccountManager accountManager) { - mAccountManager = accountManager; - mAccounts = accountManager.getAccountsByTypeAsUser("com.google", - new UserHandle(mLockPatternUtils.getCurrentUser())); - } - - private void next() { - // if we are ready to enable the fallback or if we depleted the list of accounts - // then finish and get out - if (mEnableFallback || mAccountIndex >= mAccounts.length) { - return; - } - - // lookup the confirmCredentials intent for the current account - mAccountManager.confirmCredentialsAsUser(mAccounts[mAccountIndex], null, null, this, - null, new UserHandle(mLockPatternUtils.getCurrentUser())); - } - - public void start() { - mEnableFallback = false; - mAccountIndex = 0; - next(); - } - - public void run(AccountManagerFuture<Bundle> future) { - try { - Bundle result = future.getResult(); - if (result.getParcelable(AccountManager.KEY_INTENT) != null) { - mEnableFallback = true; - } - } catch (OperationCanceledException e) { - // just skip the account if we are unable to query it - } catch (IOException e) { - // just skip the account if we are unable to query it - } catch (AuthenticatorException e) { - // just skip the account if we are unable to query it - } finally { - mAccountIndex++; - next(); - } - } - } - private void handleAttemptLockout(long elapsedRealtimeDeadline) { mLockPatternView.clearPattern(); mLockPatternView.setEnabled(false); final long elapsedRealtime = SystemClock.elapsedRealtime(); - if (mEnableFallback) { - updateFooter(FooterMode.ForgotLockPattern); - } mCountdownTimer = new CountDownTimer(elapsedRealtimeDeadline - elapsedRealtime, 1000) { @@ -367,12 +254,6 @@ public class KeyguardPatternView extends LinearLayout implements KeyguardSecurit public void onFinish() { mLockPatternView.setEnabled(true); displayDefaultSecurityMessage(); - // TODO mUnlockIcon.setVisibility(View.VISIBLE); - if (mEnableFallback) { - updateFooter(FooterMode.ForgotLockPattern); - } else { - updateFooter(FooterMode.Normal); - } } }.start(); @@ -489,13 +370,6 @@ public class KeyguardPatternView extends LinearLayout implements KeyguardSecurit // Also animate the Emergency call mAppearAnimationUtils.createAnimation(mEcaView, delay, duration, startTranslationY, interpolator, null); - - // And the forgot pattern button - if (mForgotPatternButton != null - && mForgotPatternButton.getVisibility() == View.VISIBLE) { - mAppearAnimationUtils.createAnimation(mForgotPatternButton, delay, duration, - startTranslationY, interpolator, null); - } } animator.start(); mLockPatternView.invalidate(); diff --git a/packages/PrintSpooler/Android.mk b/packages/PrintSpooler/Android.mk index 6e1402c4b2fd..c4a55d1e4eb9 100644 --- a/packages/PrintSpooler/Android.mk +++ b/packages/PrintSpooler/Android.mk @@ -23,6 +23,7 @@ LOCAL_SRC_FILES += src/com/android/printspooler/renderer/IPdfRenderer.aidl LOCAL_PACKAGE_NAME := PrintSpooler +LOCAL_JNI_SHARED_LIBRARIES := libprintspooler_jni LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4 android-support-v7-recyclerview include $(BUILD_PACKAGE) diff --git a/packages/SystemUI/res/layout/status_bar_notification_keyguard_overflow.xml b/packages/SystemUI/res/layout/status_bar_notification_keyguard_overflow.xml index 351177b21687..ef8584752fc1 100644 --- a/packages/SystemUI/res/layout/status_bar_notification_keyguard_overflow.xml +++ b/packages/SystemUI/res/layout/status_bar_notification_keyguard_overflow.xml @@ -64,9 +64,4 @@ /> </LinearLayout> - <com.android.systemui.statusbar.NotificationScrimView - android:id="@+id/scrim_view" - android:layout_width="match_parent" - android:layout_height="match_parent" /> - </com.android.systemui.statusbar.NotificationOverflowContainer> diff --git a/packages/SystemUI/res/layout/status_bar_notification_row.xml b/packages/SystemUI/res/layout/status_bar_notification_row.xml index ef4e27ce3243..6b829e56b94a 100644 --- a/packages/SystemUI/res/layout/status_bar_notification_row.xml +++ b/packages/SystemUI/res/layout/status_bar_notification_row.xml @@ -59,9 +59,4 @@ android:layout_height="match_parent" /> - <com.android.systemui.statusbar.NotificationScrimView - android:id="@+id/scrim_view" - android:layout_width="match_parent" - android:layout_height="match_parent" /> - </com.android.systemui.statusbar.ExpandableNotificationRow> diff --git a/packages/SystemUI/res/layout/super_status_bar.xml b/packages/SystemUI/res/layout/super_status_bar.xml index 09e541fa1650..29fec416c656 100644 --- a/packages/SystemUI/res/layout/super_status_bar.xml +++ b/packages/SystemUI/res/layout/super_status_bar.xml @@ -26,24 +26,6 @@ android:fitsSystemWindows="true" android:descendantFocusability="afterDescendants"> - <FrameLayout android:id="@+id/brightness_mirror" - android:layout_width="@dimen/notification_panel_width" - android:layout_height="wrap_content" - android:layout_gravity="@integer/notification_panel_layout_gravity" - android:paddingLeft="@dimen/notification_side_padding" - android:paddingRight="@dimen/notification_side_padding" - android:visibility="gone"> - <FrameLayout - android:layout_width="match_parent" - android:layout_height="match_parent" - android:elevation="2dp" - android:background="@drawable/brightness_mirror_background"> - <include layout="@layout/quick_settings_brightness_dialog" - android:layout_width="match_parent" - android:layout_height="wrap_content" /> - </FrameLayout> - </FrameLayout> - <com.android.systemui.statusbar.AlphaOptimizedFrameLayout android:id="@+id/backdrop" android:layout_width="match_parent" @@ -69,6 +51,24 @@ android:layout_width="match_parent" android:layout_height="@dimen/status_bar_height" /> + <FrameLayout android:id="@+id/brightness_mirror" + android:layout_width="@dimen/notification_panel_width" + android:layout_height="wrap_content" + android:layout_gravity="@integer/notification_panel_layout_gravity" + android:paddingLeft="@dimen/notification_side_padding" + android:paddingRight="@dimen/notification_side_padding" + android:visibility="gone"> + <FrameLayout + android:layout_width="match_parent" + android:layout_height="match_parent" + android:elevation="2dp" + android:background="@drawable/brightness_mirror_background"> + <include layout="@layout/quick_settings_brightness_dialog" + android:layout_width="match_parent" + android:layout_height="wrap_content" /> + </FrameLayout> + </FrameLayout> + <com.android.systemui.statusbar.phone.PanelHolder android:id="@+id/panel_holder" android:layout_width="match_parent" diff --git a/packages/SystemUI/res/values-sw600dp/dimens.xml b/packages/SystemUI/res/values-sw600dp/dimens.xml index 74a98fc2243f..d3b5580d309b 100644 --- a/packages/SystemUI/res/values-sw600dp/dimens.xml +++ b/packages/SystemUI/res/values-sw600dp/dimens.xml @@ -46,6 +46,9 @@ <!-- The side padding for the task stack as a percentage of the width. --> <item name="recents_stack_width_padding_percentage" format="float" type="dimen">0.075</item> + <!-- The height of the search bar space. --> + <dimen name="recents_search_bar_space_height">72dp</dimen> + <!-- The fraction of the screen height where the clock on the Keyguard has its center. The max value is used when no notifications are displaying, and the min value is when the highest possible number of notifications are showing. --> diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index c7a91afc8da3..23d9748ddd09 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -756,6 +756,9 @@ <!-- Accessibility label for the button that opens the user switcher. --> <string name="accessibility_multi_user_switch_switcher">Switch user</string> + <!-- Accessibility label for the button that opens the user switcher and announces the current user. --> + <string name="accessibility_multi_user_switch_switcher_with_current">Switch user, current user <xliff:g id="current_user_name" example="John Doe">%s</xliff:g></string> + <!-- Accessibility label for the button that opens the quick contact of the user. --> <string name="accessibility_multi_user_switch_quick_contact">Show profile</string> diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java index f8d0d9e59c26..8d35eb0f3d4b 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java @@ -1142,7 +1142,6 @@ public class KeyguardViewMediator extends SystemUI { } handleHide(); - sendUserPresentBroadcast(); } private void sendUserPresentBroadcast() { @@ -1313,6 +1312,7 @@ public class KeyguardViewMediator extends SystemUI { mHideAnimationRun = false; updateActivityLockScreenState(); adjustStatusBarLocked(); + sendUserPresentBroadcast(); } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java index 46d8a9b6fd82..d1dc5d2b00e7 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java @@ -60,7 +60,11 @@ public class LocationTile extends QSTile<QSTile.BooleanState> { @Override protected void handleUpdateState(BooleanState state, Object arg) { final boolean locationEnabled = mController.isLocationEnabled(); - state.visible = !(mKeyguard.isSecure() && mKeyguard.isShowing()); + + // Work around for bug 15916487: don't show location tile on top of lock screen. After the + // bug is fixed, this should be reverted to only hiding it on secure lock screens: + // state.visible = !(mKeyguard.isSecure() && mKeyguard.isShowing()); + state.visible = !mKeyguard.isShowing(); state.value = locationEnabled; if (locationEnabled) { state.iconId = R.drawable.ic_qs_location_on; diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java b/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java index 3e2ef94e9e1c..b7434fdd3858 100644 --- a/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java +++ b/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java @@ -34,14 +34,12 @@ import android.os.Handler; import android.os.Process; import android.os.RemoteException; import android.os.UserHandle; -import android.os.UserManager; import android.util.Log; import android.view.MotionEvent; import android.view.View; import com.android.systemui.R; import com.android.systemui.recents.misc.SystemServicesProxy; -import com.android.systemui.recents.misc.Utilities; import com.android.systemui.statusbar.phone.PhoneStatusBar; import java.util.ArrayList; @@ -205,8 +203,8 @@ public class RecentTasksLoader implements View.OnTouchListener { Drawable icon = getFullResIcon(td.resolveInfo, pm); if (td.userId != UserHandle.myUserId()) { // Need to badge the icon - final UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE); - icon = um.getBadgedDrawableForUser(icon, new UserHandle(td.userId)); + icon = mContext.getPackageManager().getUserBadgedDrawableForDensity(icon, + new UserHandle(td.userId), null, 0); } if (DEBUG) Log.v(TAG, "Loaded bitmap for task " + td + ": " + thumbnail); diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java index 082dde6cbb95..ec7799a0bddb 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java @@ -296,7 +296,7 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView mSearchAppWidgetInfo); Bundle opts = new Bundle(); opts.putInt(AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY, - AppWidgetProviderInfo.WIDGET_CATEGORY_RECENTS); + AppWidgetProviderInfo.WIDGET_CATEGORY_SEARCHBOX); mSearchAppWidgetHostView.updateAppWidgetOptions(opts); // Set the padding to 0 for this search widget mSearchAppWidgetHostView.setPadding(0, 0, 0, 0); diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java index e27c0ac788c4..07a42bd3544e 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java +++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java @@ -49,7 +49,6 @@ import android.os.Bundle; import android.os.ParcelFileDescriptor; import android.os.RemoteException; import android.os.UserHandle; -import android.os.UserManager; import android.provider.Settings; import android.util.Log; import android.util.Pair; @@ -79,7 +78,6 @@ public class SystemServicesProxy { AppWidgetManager mAwm; PackageManager mPm; IPackageManager mIpm; - UserManager mUm; SearchManager mSm; WindowManager mWm; Display mDisplay; @@ -103,7 +101,6 @@ public class SystemServicesProxy { mIam = ActivityManagerNative.getDefault(); mAwm = AppWidgetManager.getInstance(context); mPm = context.getPackageManager(); - mUm = (UserManager) context.getSystemService(Context.USER_SERVICE); mIpm = AppGlobals.getPackageManager(); mSm = (SearchManager) context.getSystemService(Context.SEARCH_SERVICE); mWm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); @@ -343,7 +340,7 @@ public class SystemServicesProxy { * necessary. */ public Drawable getActivityIcon(ActivityInfo info, int userId) { - if (mPm == null || mUm == null) return null; + if (mPm == null) return null; // If we are mocking, then return a mock label if (Constants.DebugFlags.App.EnableSystemServicesProxy) { @@ -359,7 +356,7 @@ public class SystemServicesProxy { */ public Drawable getBadgedIcon(Drawable icon, int userId) { if (userId != UserHandle.myUserId()) { - icon = mUm.getBadgedDrawableForUser(icon, new UserHandle(userId)); + icon = mPm.getUserBadgedDrawableForDensity(icon, new UserHandle(userId), null, 0); } return icon; } @@ -392,7 +389,7 @@ public class SystemServicesProxy { // Find the first Recents widget from the same package as the global assist activity List<AppWidgetProviderInfo> widgets = mAwm.getInstalledProviders( - AppWidgetProviderInfo.WIDGET_CATEGORY_RECENTS); + AppWidgetProviderInfo.WIDGET_CATEGORY_SEARCHBOX); for (AppWidgetProviderInfo info : widgets) { if (info.provider.getPackageName().equals(mAssistComponent.getPackageName())) { return info; @@ -418,7 +415,7 @@ public class SystemServicesProxy { int searchWidgetId = host.allocateAppWidgetId(); Bundle opts = new Bundle(); opts.putInt(AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY, - AppWidgetProviderInfo.WIDGET_CATEGORY_RECENTS); + AppWidgetProviderInfo.WIDGET_CATEGORY_SEARCHBOX); if (!mAwm.bindAppWidgetIdIfAllowed(searchWidgetId, searchWidgetInfo.provider, opts)) { return null; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java index e6984b2bd6d1..c869ba48eb67 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java @@ -121,7 +121,6 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView private NotificationBackgroundView mBackgroundNormal; private NotificationBackgroundView mBackgroundDimmed; - private NotificationScrimView mScrimView; private ObjectAnimator mBackgroundAnimator; private RectF mAppearAnimationRect = new RectF(); private PorterDuffColorFilter mAppearAnimationFilter; @@ -173,8 +172,6 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView mBackgroundDimmed.setCustomBackground(R.drawable.notification_material_bg_dim); updateBackground(); updateBackgroundTint(); - mScrimView = (NotificationScrimView) findViewById(R.id.scrim_view); - setScrimAmount(0); } private final Runnable mTapTimeoutRunnable = new Runnable() { @@ -465,7 +462,6 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView setPivotY(actualHeight / 2); mBackgroundNormal.setActualHeight(actualHeight); mBackgroundDimmed.setActualHeight(actualHeight); - mScrimView.setActualHeight(actualHeight); } @Override @@ -473,7 +469,6 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView super.setClipTopAmount(clipTopAmount); mBackgroundNormal.setClipTopAmount(clipTopAmount); mBackgroundDimmed.setClipTopAmount(clipTopAmount); - mScrimView.setClipTopAmount(clipTopAmount); } @Override @@ -496,11 +491,6 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView } } - @Override - public void setScrimAmount(float scrimAmount) { - mScrimView.setAlpha(scrimAmount); - } - private void startAppearAnimation(boolean isAppearing, float translationDirection, long delay, long duration, final Runnable onFinishedRunnable) { if (mAppearAnimator != null) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java index 2c1d70db5233..1c4556f7c2aa 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java @@ -558,6 +558,8 @@ public abstract class BaseStatusBar extends SystemUI implements // disable lockscreen notifications until user acts on the banner. Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, 0); + Settings.Secure.putInt(mContext.getContentResolver(), + Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, 0); final String packageName = mContext.getPackageName(); PendingIntent cancelIntent = PendingIntent.getBroadcast(mContext, 0, @@ -1356,8 +1358,8 @@ public abstract class BaseStatusBar extends SystemUI implements } if (profileBadge != null) { - Drawable profileDrawable - = mUserManager.getBadgeForUser(entry.notification.getUser(), 0); + Drawable profileDrawable = mContext.getPackageManager().getUserBadgeForDensity( + entry.notification.getUser(), 0); if (profileDrawable != null) { profileBadge.setImageDrawable(profileDrawable); profileBadge.setVisibility(View.VISIBLE); @@ -1623,10 +1625,11 @@ public abstract class BaseStatusBar extends SystemUI implements } } boolean showOnKeyguard = shouldShowOnKeyguard(entry.notification); - if (onKeyguard && (visibleNotifications >= maxKeyguardNotifications - || !showOnKeyguard)) { + if ((isLockscreenPublicMode() && !showOnKeyguard) || + (onKeyguard && (visibleNotifications >= maxKeyguardNotifications + || !showOnKeyguard))) { entry.row.setVisibility(View.GONE); - if (showOnKeyguard) { + if (onKeyguard && showOnKeyguard) { mKeyguardIconOverflowContainer.getIconsView().addNotification(entry); } } else { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java index e3a0b1855f0d..c13593a204d7 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java @@ -147,6 +147,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView { mMaxExpandHeight = 0; mWasReset = true; onHeightReset(); + requestLayout(); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java index 28387479b13a..c8f756e906c0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java @@ -255,8 +255,6 @@ public abstract class ExpandableView extends FrameLayout { public abstract void performAddAnimation(long delay, long duration); - public abstract void setScrimAmount(float scrimAmount); - public void setBelowSpeedBump(boolean below) { } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java index 0905fe797d04..ca1fbe0e8221 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java @@ -100,15 +100,26 @@ public class NotificationData { @Override public int compare(Entry a, Entry b) { - String mediaNotification = mEnvironment.getCurrentMediaNotificationKey(); - // Upsort current media notification. + String mediaNotification = mEnvironment.getCurrentMediaNotificationKey(); boolean aMedia = a.key.equals(mediaNotification); boolean bMedia = b.key.equals(mediaNotification); if (aMedia != bMedia) { return aMedia ? -1 : 1; } + final StatusBarNotification na = a.notification; + final StatusBarNotification nb = b.notification; + + // Upsort PRIORITY_MAX system notifications + boolean aSystemMax = na.getNotification().priority >= Notification.PRIORITY_MAX && + isSystemNotification(na); + boolean bSystemMax = nb.getNotification().priority >= Notification.PRIORITY_MAX && + isSystemNotification(nb); + if (aSystemMax != bSystemMax) { + return aSystemMax ? -1 : 1; + } + // RankingMap as received from NoMan. if (mRankingMap != null) { mRankingMap.getRanking(a.key, mRankingA); @@ -116,8 +127,6 @@ public class NotificationData { return mRankingA.getRank() - mRankingB.getRank(); } - final StatusBarNotification na = a.notification; - final StatusBarNotification nb = b.notification; int d = nb.getScore() - na.getScore(); if (a.interruption != b.interruption) { return a.interruption ? -1 : 1; @@ -305,6 +314,11 @@ public class NotificationData { pw.println(" tickerText=\"" + n.getNotification().tickerText + "\""); } + private static boolean isSystemNotification(StatusBarNotification sbn) { + String sbnPackage = sbn.getPackageName(); + return "android".equals(sbnPackage) || "com.android.systemui".equals(sbnPackage); + } + /** * Provides access to keyguard state and user settings dependent data. */ diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationScrimView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationScrimView.java deleted file mode 100644 index 440b2c1df871..000000000000 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationScrimView.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (C) 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 - */ - -package com.android.systemui.statusbar; - -import android.content.Context; -import android.graphics.Canvas; -import android.graphics.PorterDuff; -import android.graphics.drawable.Drawable; -import android.util.AttributeSet; -import android.view.View; - -import com.android.keyguard.R; - -/** - * A view that can be used for both the dimmed and normal background of an notification. - */ -public class NotificationScrimView extends View { - - private Drawable mBackground; - private int mClipTopAmount; - private int mActualHeight; - - public NotificationScrimView(Context context, AttributeSet attrs) { - super(context, attrs); - mBackground = getResources().getDrawable(R.drawable.notification_scrim); - } - - @Override - protected void onDraw(Canvas canvas) { - draw(canvas, mBackground); - } - - private void draw(Canvas canvas, Drawable drawable) { - if (drawable != null) { - drawable.setBounds(0, mClipTopAmount, getWidth(), mActualHeight); - drawable.draw(canvas); - } - } - - @Override - protected boolean verifyDrawable(Drawable who) { - return super.verifyDrawable(who) || who == mBackground; - } - - public void setActualHeight(int actualHeight) { - mActualHeight = actualHeight; - invalidate(); - } - - public int getActualHeight() { - return mActualHeight; - } - - public void setClipTopAmount(int clipTopAmount) { - mClipTopAmount = clipTopAmount; - invalidate(); - } - - @Override - public boolean hasOverlappingRendering() { - - // Prevents this view from creating a layer when alpha is animating. - return false; - } -} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpView.java b/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpView.java index 816612b79dda..1fc874479f72 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpView.java @@ -126,9 +126,4 @@ public class SpeedBumpView extends ExpandableView { // TODO: Use duration performVisibilityAnimation(true, delay); } - - @Override - public void setScrimAmount(float scrimAmount) { - // We don't need to scrim the speedbumps - } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StackScrollerDecorView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StackScrollerDecorView.java index 62a492e1ff07..c620046d4c47 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/StackScrollerDecorView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/StackScrollerDecorView.java @@ -127,11 +127,6 @@ public abstract class StackScrollerDecorView extends ExpandableView { } @Override - public void setScrimAmount(float scrimAmount) { - // We don't need to scrim the dismissView - } - - @Override public boolean hasOverlappingRendering() { return false; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java index d7144dadcd9e..dc491183b4f0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java @@ -30,6 +30,7 @@ import android.widget.FrameLayout; import com.android.systemui.R; import com.android.systemui.qs.QSPanel; import com.android.systemui.statusbar.policy.KeyguardUserSwitcher; +import com.android.systemui.statusbar.policy.UserSwitcherController; /** * Container for image of the multi user switcher (tappable). @@ -90,9 +91,21 @@ public class MultiUserSwitch extends FrameLayout implements View.OnClickListener if (isClickable()) { final UserManager um = UserManager.get(getContext()); - String text = mContext.getString(um.isUserSwitcherEnabled() - ? R.string.accessibility_multi_user_switch_switcher - : R.string.accessibility_multi_user_switch_quick_contact); + String text; + if (um.isUserSwitcherEnabled()) { + UserSwitcherController controller = mQsPanel.getHost() + .getUserSwitcherController(); + String currentUser = controller.getCurrentUserName(mContext); + if (TextUtils.isEmpty(currentUser)) { + text = mContext.getString(R.string.accessibility_multi_user_switch_switcher); + } else { + text = mContext.getString( + R.string.accessibility_multi_user_switch_switcher_with_current, + currentUser); + } + } else { + text = mContext.getString(R.string.accessibility_multi_user_switch_quick_contact); + } if (!TextUtils.isEmpty(text)) { event.getText().add(text); } 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 bae18646f600..cf5aebc9780a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java @@ -1047,7 +1047,6 @@ public class NotificationPanelView extends PanelView implements int startDistance = mQsMinExpansionHeight + mNotificationScrimWaitDistance; float progress = (height - startDistance) / (mQsMaxExpansionHeight - startDistance); progress = Math.max(0.0f, Math.min(progress, 1.0f)); - mNotificationStackScroller.setScrimAlpha(progress); } private float getHeaderExpansionFraction() { @@ -1279,7 +1278,7 @@ public class NotificationPanelView extends PanelView implements private void updateNotificationTranslucency() { float alpha = (getNotificationsTopY() + mNotificationStackScroller.getItemHeight()) / (mQsMinExpansionHeight + mNotificationStackScroller.getBottomStackPeekSize() - + mNotificationStackScroller.getCollapseSecondCardPadding()); + - mNotificationStackScroller.getCollapseSecondCardPadding()); alpha = Math.max(0, Math.min(alpha, 1)); alpha = (float) Math.pow(alpha, 0.75); if (alpha != 1f && mNotificationStackScroller.getLayerType() != LAYER_TYPE_HARDWARE) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java index ddd03d69e22e..271371a6d397 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java @@ -1559,8 +1559,9 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, } } - for (View remove : toRemove) { - mNotificationIcons.removeView(remove); + final int toRemoveCount = toRemove.size(); + for (int i = 0; i < toRemoveCount; i++) { + mNotificationIcons.removeView(toRemove.get(i)); } for (int i=0; i<toShow.size(); i++) { @@ -1569,6 +1570,18 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, mNotificationIcons.addView(v, i, params); } } + + // Resort notification icons + final int childCount = mNotificationIcons.getChildCount(); + for (int i = 0; i < childCount; i++) { + View actual = mNotificationIcons.getChildAt(i); + StatusBarIconView expected = toShow.get(i); + if (actual == expected) { + continue; + } + mNotificationIcons.removeView(expected); + mNotificationIcons.addView(expected, i); + } } @Override @@ -3774,7 +3787,9 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, row = (ExpandableNotificationRow) expandView; row.setUserExpanded(true); } - if (isLockscreenPublicMode() && !userAllowsPrivateNotificationsInPublic(mCurrentUserId)) { + boolean fullShadeNeedsBouncer = !userAllowsPrivateNotificationsInPublic(mCurrentUserId) + || !mShowLockscreenNotifications; + if (isLockscreenPublicMode() && fullShadeNeedsBouncer) { mLeaveOpenOnKeyguardHide = true; showBouncer(); mDraggedDownRow = row; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java index e4b1945fc37c..52fa621dc5cc 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java @@ -334,6 +334,14 @@ public class UserSwitcherController { } } + public String getCurrentUserName(Context context) { + if (mUsers.isEmpty()) return null; + UserRecord item = mUsers.get(0); + if (item == null || item.info == null) return null; + if (item.isGuest) return context.getString(R.string.guest_nickname); + return item.info.name; + } + public static abstract class BaseUserAdapter extends BaseAdapter { final UserSwitcherController mController; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java index ddb5cb8cdd6a..8e677f1e68d2 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java @@ -32,7 +32,6 @@ public class AmbientState { private float mOverScrollTopAmount; private float mOverScrollBottomAmount; private int mSpeedBumpIndex = -1; - private float mScrimAmount; private boolean mDark; private boolean mHideSensitive; @@ -105,14 +104,6 @@ public class AmbientState { } } - public void setScrimAmount(float scrimAmount) { - mScrimAmount = scrimAmount; - } - - public float getScrimAmount() { - return mScrimAmount; - } - public float getOverScrollAmount(boolean top) { return top ? mOverScrollTopAmount : mOverScrollBottomAmount; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java index fed579cb39ee..6f477ef278f8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java @@ -2094,13 +2094,6 @@ public class NotificationStackScrollLayout extends ViewGroup return true; } - public void setScrimAlpha(float progress) { - if (progress != mAmbientState.getScrimAmount()) { - mAmbientState.setScrimAmount(progress); - requestChildrenUpdate(); - } - } - /** * See {@link AmbientState#setDark}. */ diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java index fe855d92e6cd..7c4c0e8b9db6 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java @@ -172,7 +172,6 @@ public class StackScrollAlgorithm { handleDraggedViews(ambientState, resultState, algorithmState); updateDimmedActivatedHideSensitive(ambientState, resultState, algorithmState); updateClipping(resultState, algorithmState); - updateScrimAmount(resultState, algorithmState, ambientState.getScrimAmount()); updateSpeedBumpState(resultState, algorithmState, ambientState.getSpeedBumpIndex()); } @@ -189,16 +188,6 @@ public class StackScrollAlgorithm { } } - private void updateScrimAmount(StackScrollState resultState, - StackScrollAlgorithmState algorithmState, float scrimAmount) { - int childCount = algorithmState.visibleChildren.size(); - for (int i = 0; i < childCount; i++) { - View child = algorithmState.visibleChildren.get(i); - StackScrollState.ViewState childViewState = resultState.getViewStateForView(child); - childViewState.scrimAmount = scrimAmount; - } - } - private void updateClipping(StackScrollState resultState, StackScrollAlgorithmState algorithmState) { float previousNotificationEnd = 0; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java index f7a28247de4b..0967ecd06a52 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java @@ -165,9 +165,6 @@ public class StackScrollState { // apply speed bump state child.setBelowSpeedBump(state.belowSpeedBump); - // apply scrimming - child.setScrimAmount(state.scrimAmount); - // apply clipping float oldClipTopAmount = child.getClipTopAmount(); if (oldClipTopAmount != state.clipTopAmount) { @@ -252,12 +249,6 @@ public class StackScrollState { boolean belowSpeedBump; /** - * A value between 0 and 1 indicating how much the view should be scrimmed. - * 1 means that the notifications will be darkened as much as possible. - */ - float scrimAmount; - - /** * The amount which the view should be clipped from the top. This is calculated to * perceive consistent shadows. */ diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java index 58d58135c0a7..ece82a1cc8d4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java @@ -251,9 +251,6 @@ public class StackStateAnimator { child.setHideSensitive(viewState.hideSensitive, mAnimationFilter.animateHideSensitive && !wasAdded && !noAnimation, delay, duration); - // apply scrimming - child.setScrimAmount(viewState.scrimAmount); - if (wasAdded) { child.performAddAnimation(delay, mCurrentLength); } diff --git a/policy/src/com/android/internal/policy/impl/GlobalActions.java b/policy/src/com/android/internal/policy/impl/GlobalActions.java index 41695c11bfca..7b4139182afd 100644 --- a/policy/src/com/android/internal/policy/impl/GlobalActions.java +++ b/policy/src/com/android/internal/policy/impl/GlobalActions.java @@ -413,7 +413,7 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac @Override public void onPress() { Intent intent = new Intent(Settings.ACTION_SETTINGS); - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP); mContext.startActivity(intent); } diff --git a/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java b/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java index af5c13dee0db..ac0ca0afe6b0 100644 --- a/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java +++ b/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java @@ -708,7 +708,6 @@ class TouchExplorer implements EventStreamTransformation { // Send an event to the end of the drag gesture. sendMotionEvent(event, MotionEvent.ACTION_UP, pointerIdBits, policyFlags); } - mCurrentState = STATE_TOUCH_EXPLORING; } break; case MotionEvent.ACTION_UP: { mAms.onTouchInteractionEnd(); diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java index 2ef806f1babf..d05de697d40f 100644 --- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java +++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java @@ -440,12 +440,10 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku @Override public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) - != PackageManager.PERMISSION_GRANTED) { - throw new SecurityException("Permission Denial: can't dump from from pid=" - + Binder.getCallingPid() - + ", uid=" + Binder.getCallingUid()); - } + mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, + "Permission Denial: can't dump from from pid=" + + Binder.getCallingPid() + + ", uid=" + Binder.getCallingUid()); synchronized (mLock) { int N = mProviders.size(); @@ -4038,4 +4036,4 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku } } } -}
\ No newline at end of file +} diff --git a/services/core/java/com/android/server/MmsServiceBroker.java b/services/core/java/com/android/server/MmsServiceBroker.java index 65ad1ceb9eac..b452a380703f 100644 --- a/services/core/java/com/android/server/MmsServiceBroker.java +++ b/services/core/java/com/android/server/MmsServiceBroker.java @@ -193,7 +193,7 @@ public class MmsServiceBroker extends SystemService { private final class BinderService extends IMms.Stub { @Override public void sendMessage(long subId, String callingPkg, Uri contentUri, - String locationUrl, ContentValues configOverrides, PendingIntent sentIntent) + String locationUrl, Bundle configOverrides, PendingIntent sentIntent) throws RemoteException { mContext.enforceCallingPermission(Manifest.permission.SEND_SMS, "Send MMS message"); if (getAppOpsManager().noteOp(AppOpsManager.OP_SEND_SMS, Binder.getCallingUid(), @@ -206,7 +206,7 @@ public class MmsServiceBroker extends SystemService { @Override public void downloadMessage(long subId, String callingPkg, String locationUrl, - Uri contentUri, ContentValues configOverrides, + Uri contentUri, Bundle configOverrides, PendingIntent downloadedIntent) throws RemoteException { mContext.enforceCallingPermission(Manifest.permission.RECEIVE_MMS, "Download MMS message"); @@ -333,7 +333,7 @@ public class MmsServiceBroker extends SystemService { @Override public void sendStoredMessage(long subId, String callingPkg, Uri messageUri, - ContentValues configOverrides, PendingIntent sentIntent) throws RemoteException { + Bundle configOverrides, PendingIntent sentIntent) throws RemoteException { mContext.enforceCallingPermission(Manifest.permission.SEND_SMS, "Send stored MMS message"); if (getAppOpsManager().noteOp(AppOpsManager.OP_SEND_SMS, Binder.getCallingUid(), diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index b116d762867c..023f627c55db 100755 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -3215,7 +3215,6 @@ public final class ActivityManagerService extends ActivityManagerNative if (resumed) { if (mUsageStatsService != null) { mUsageStatsService.reportEvent(component.realActivity, component.userId, - System.currentTimeMillis(), UsageEvents.Event.MOVE_TO_FOREGROUND); } synchronized (stats) { @@ -3224,7 +3223,6 @@ public final class ActivityManagerService extends ActivityManagerNative } else { if (mUsageStatsService != null) { mUsageStatsService.reportEvent(component.realActivity, component.userId, - System.currentTimeMillis(), UsageEvents.Event.MOVE_TO_BACKGROUND); } synchronized (stats) { @@ -15936,6 +15934,7 @@ public final class ActivityManagerService extends ActivityManagerNative newConfig.seq = mConfigurationSeq; mConfiguration = newConfig; Slog.i(TAG, "Config changes=" + Integer.toHexString(changes) + " " + newConfig); + mUsageStatsService.reportConfigurationChange(newConfig, mCurrentUserId); //mUsageStatsService.noteStartConfig(newConfig); final Configuration configCopy = new Configuration(mConfiguration); diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java index 3efd049f8171..81c379a744b9 100755 --- a/services/core/java/com/android/server/am/ActivityStack.java +++ b/services/core/java/com/android/server/am/ActivityStack.java @@ -241,6 +241,9 @@ final class ActivityStack { /** Run all ActivityStacks through this */ final ActivityStackSupervisor mStackSupervisor; + /** Used to keep resumeTopActivityLocked() from being entered recursively */ + private boolean inResumeTopActivity; + static final int PAUSE_TIMEOUT_MSG = ActivityManagerService.FIRST_ACTIVITY_STACK_MSG + 1; static final int DESTROY_TIMEOUT_MSG = ActivityManagerService.FIRST_ACTIVITY_STACK_MSG + 2; static final int LAUNCH_TICK_MSG = ActivityManagerService.FIRST_ACTIVITY_STACK_MSG + 3; @@ -456,7 +459,7 @@ final class ActivityStack { final ActivityRecord r = ActivityRecord.forToken(token); if (r != null) { final TaskRecord task = r.task; - if (task.mActivities.contains(r) && mTaskHistory.contains(task)) { + if (task != null && task.mActivities.contains(r) && mTaskHistory.contains(task)) { if (task.stack != this) Slog.w(TAG, "Illegal state! task does not point to stack it is in."); return r; @@ -1439,6 +1442,23 @@ final class ActivityStack { } final boolean resumeTopActivityLocked(ActivityRecord prev, Bundle options) { + if (inResumeTopActivity) { + // Don't even start recursing. + return false; + } + + boolean result = false; + try { + // Protect against recursion. + inResumeTopActivity = true; + result = resumeTopActivityInnerLocked(prev, options); + } finally { + inResumeTopActivity = false; + } + return result; + } + + final boolean resumeTopActivityInnerLocked(ActivityRecord prev, Bundle options) { if (ActivityManagerService.DEBUG_LOCKSCREEN) mService.logLockScreen(""); ActivityRecord parent = mActivityContainer.mParentActivity; diff --git a/services/core/java/com/android/server/hdmi/Constants.java b/services/core/java/com/android/server/hdmi/Constants.java index aa1310dd14c5..6ce235b7badd 100644 --- a/services/core/java/com/android/server/hdmi/Constants.java +++ b/services/core/java/com/android/server/hdmi/Constants.java @@ -159,6 +159,8 @@ final class Constants { static final int TRUE = 1; static final int FALSE = 0; + // Internal abort error code. It's the same as success. + static final int ABORT_NO_ERROR = -1; // Constants related to operands of HDMI CEC commands. // Refer to CEC Table 29 in HDMI Spec v1.4b. // [Abort Reason] diff --git a/services/core/java/com/android/server/hdmi/HdmiCecController.java b/services/core/java/com/android/server/hdmi/HdmiCecController.java index bb22b4dde105..c5a6dbd788b7 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecController.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecController.java @@ -31,8 +31,6 @@ import com.android.server.hdmi.HdmiControlService.DevicePollingCallback; import libcore.util.EmptyArray; -import java.io.FileDescriptor; -import java.io.PrintWriter; import java.util.ArrayList; import java.util.List; @@ -102,11 +100,6 @@ final class HdmiCecController { // Stores the local CEC devices in the system. Device type is used for key. private final SparseArray<HdmiCecLocalDevice> mLocalDevices = new SparseArray<>(); - @IoThreadOnly - private final HdmiLogger mIoThreadLogger = new HdmiLogger(TAG); - @ServiceThreadOnly - private final HdmiLogger mServiceThreadLogger = new HdmiLogger(TAG); - // Private constructor. Use HdmiCecController.create(). private HdmiCecController(HdmiControlService service) { mService = service; @@ -210,9 +203,8 @@ final class HdmiCecController { } final int assignedAddress = logicalAddress; - mIoThreadLogger.debug( - String.format("New logical address for device [%d]: [preferred:%d, assigned:%d]", - deviceType, preferredAddress, assignedAddress)); + HdmiLogger.debug("New logical address for device [%d]: [preferred:%d, assigned:%d]", + deviceType, preferredAddress, assignedAddress); if (callback != null) { runOnServiceThread(new Runnable() { @Override @@ -449,7 +441,7 @@ final class HdmiCecController { allocated.add(address); } } - mIoThreadLogger.debug("[P]:Allocated Address=" + allocated); + HdmiLogger.debug("[P]:Allocated Address=" + allocated); if (callback != null) { runOnServiceThread(new Runnable() { @Override @@ -551,7 +543,7 @@ final class HdmiCecController { runOnIoThread(new Runnable() { @Override public void run() { - mIoThreadLogger.debug("[S]:" + cecMessage); + HdmiLogger.debug("[S]:" + cecMessage); byte[] body = buildBody(cecMessage.getOpcode(), cecMessage.getParams()); int i = 0; int errorCode = Constants.SEND_RESULT_SUCCESS; @@ -586,7 +578,7 @@ final class HdmiCecController { private void handleIncomingCecCommand(int srcAddress, int dstAddress, byte[] body) { assertRunOnServiceThread(); HdmiCecMessage command = HdmiCecMessageBuilder.of(srcAddress, dstAddress, body); - mServiceThreadLogger.debug("[R]:" + command); + HdmiLogger.debug("[R]:" + command); onReceiveCommand(command); } @@ -596,8 +588,7 @@ final class HdmiCecController { @ServiceThreadOnly private void handleHotplug(int port, boolean connected) { assertRunOnServiceThread(); - mServiceThreadLogger.debug( - "Hotplug event:[port:" + port + " , connected:" + connected + "]"); + HdmiLogger.debug("Hotplug event:[port:%d, connected:%b]", port, connected); mService.onHotplug(port, connected); } diff --git a/services/core/java/com/android/server/hdmi/HdmiCecFeatureAction.java b/services/core/java/com/android/server/hdmi/HdmiCecFeatureAction.java index 85f5be2143d5..b2300a6f50c0 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecFeatureAction.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecFeatureAction.java @@ -43,9 +43,6 @@ import java.util.List; */ abstract class HdmiCecFeatureAction { private static final String TAG = "HdmiCecFeatureAction"; - // As all actions run in the same thread (service thread), it's fine to have single logger. - // TODO: create global logger for each threads and use them. - protected static final HdmiLogger DLOGGER = new HdmiLogger(TAG); // Timer handler message used for timeout event protected static final int MSG_TIMEOUT = 100; @@ -264,10 +261,7 @@ abstract class HdmiCecFeatureAction { } protected final void sendUserControlPressedAndReleased(int targetAddress, int uiCommand) { - sendCommand(HdmiCecMessageBuilder.buildUserControlPressed( - getSourceAddress(), targetAddress, uiCommand)); - sendCommand(HdmiCecMessageBuilder.buildUserControlReleased( - getSourceAddress(), targetAddress)); + mSource.sendUserControlPressedAndReleased(targetAddress, uiCommand); } protected final void addOnFinishedCallback(HdmiCecFeatureAction action, Runnable runnable) { diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java index bc6a299bbb49..c00c5d009f09 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java @@ -274,6 +274,12 @@ abstract class HdmiCecLocalDevice { return handleRecordTvScreen(message); case Constants.MESSAGE_TIMER_CLEARED_STATUS: return handleTimerClearedStatus(message); + case Constants.MESSAGE_REPORT_POWER_STATUS: + return handleReportPowerStatus(message); + case Constants.MESSAGE_TIMER_STATUS: + return handleTimerStatus(message); + case Constants.MESSAGE_RECORD_STATUS: + return handleRecordStatus(message); default: return false; } @@ -541,6 +547,18 @@ abstract class HdmiCecLocalDevice { return false; } + protected boolean handleReportPowerStatus(HdmiCecMessage message) { + return false; + } + + protected boolean handleTimerStatus(HdmiCecMessage message) { + return false; + } + + protected boolean handleRecordStatus(HdmiCecMessage message) { + return false; + } + @ServiceThreadOnly final void handleAddressAllocated(int logicalAddress, int reason) { assertRunOnServiceThread(); @@ -810,6 +828,13 @@ abstract class HdmiCecLocalDevice { Slog.w(TAG, "sendKeyEvent not implemented"); } + void sendUserControlPressedAndReleased(int targetAddress, int cecKeycode) { + mService.sendCecCommand(HdmiCecMessageBuilder.buildUserControlPressed( + mAddress, targetAddress, cecKeycode)); + mService.sendCecCommand(HdmiCecMessageBuilder.buildUserControlReleased( + mAddress, targetAddress)); + } + /** * Dump internal status of HdmiCecLocalDevice object. */ diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java index 7ae2198c8d0d..58ccbdb91a6e 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java @@ -120,8 +120,6 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { // other CEC devices since they might not have logical address. private final ArraySet<Integer> mCecSwitches = new ArraySet<Integer>(); - private final HdmiLogger mSafeLogger = new HdmiLogger(TAG); - HdmiCecLocalDeviceTv(HdmiControlService service) { super(service, HdmiDeviceInfo.DEVICE_TV); mPrevPortId = Constants.INVALID_PORT_ID; @@ -476,6 +474,25 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { return true; } + @Override + protected boolean handleReportPowerStatus(HdmiCecMessage command) { + int newStatus = command.getParams()[0] & 0xFF; + updateDevicePowerStatus(command.getSource(), newStatus); + return true; + } + + @Override + protected boolean handleTimerStatus(HdmiCecMessage message) { + // Do nothing. + return true; + } + + @Override + protected boolean handleRecordStatus(HdmiCecMessage message) { + // Do nothing. + return true; + } + boolean updateCecSwitchInfo(int address, int type, int path) { if (address == Constants.ADDR_UNREGISTERED && type == HdmiDeviceInfo.DEVICE_PURE_CEC_SWITCH) { @@ -700,8 +717,7 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { // # Seq 25 void setSystemAudioMode(boolean on, boolean updateSetting) { - mSafeLogger.debug(String.format("System Audio Mode change[old:%b new:%b]", - mSystemAudioActivated, on)); + HdmiLogger.debug("System Audio Mode change[old:%b new:%b]", mSystemAudioActivated, on); if (updateSetting) { mService.writeBooleanSetting(Global.HDMI_SYSTEM_AUDIO_ENABLED, on); @@ -832,6 +848,8 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { AudioManager.STREAM_MUSIC); mService.setAudioStatus(mute, VolumeControlAction.scaleToCustomVolume(volume, maxVolume)); + displayOsd(HdmiControlManager.OSD_MESSAGE_AVR_VOLUME_CHANGED, + mute ? HdmiControlManager.AVR_VOLUME_MUTED : volume); } } @@ -855,12 +873,13 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { } } - // Remove existing volume action. - removeAction(VolumeControlAction.class); - - HdmiDeviceInfo avr = getAvrDeviceInfo(); - addAndStartAction(VolumeControlAction.ofVolumeChange(this, avr.getLogicalAddress(), - cecVolume, delta > 0)); + List<VolumeControlAction> actions = getActions(VolumeControlAction.class); + if (actions.isEmpty()) { + addAndStartAction(new VolumeControlAction(this, + getAvrDeviceInfo().getLogicalAddress(), delta > 0)); + } else { + actions.get(0).handleVolumeChange(delta > 0); + } } @ServiceThreadOnly @@ -872,8 +891,9 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { // Remove existing volume action. removeAction(VolumeControlAction.class); - HdmiDeviceInfo avr = getAvrDeviceInfo(); - addAndStartAction(VolumeControlAction.ofMute(this, avr.getLogicalAddress(), mute)); + sendUserControlPressedAndReleased(getAvrDeviceInfo().getLogicalAddress(), + mute ? HdmiCecKeycode.CEC_KEYCODE_MUTE_FUNCTION : + HdmiCecKeycode.CEC_KEYCODE_RESTORE_VOLUME_FUNCTION); } @Override @@ -935,8 +955,9 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { protected boolean handleSetSystemAudioMode(HdmiCecMessage message) { assertRunOnServiceThread(); if (!isMessageForSystemAudio(message)) { - mSafeLogger.warning("Invalid <Set System Audio Mode> message:" + message); - return false; + HdmiLogger.warning("Invalid <Set System Audio Mode> message:" + message); + mService.maySendFeatureAbortCommand(message, Constants.ABORT_REFUSED); + return true; } SystemAudioActionFromAvr action = new SystemAudioActionFromAvr(this, message.getSource(), HdmiUtils.parseCommandParamSystemAudioStatus(message), null); @@ -949,8 +970,9 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { protected boolean handleSystemAudioModeStatus(HdmiCecMessage message) { assertRunOnServiceThread(); if (!isMessageForSystemAudio(message)) { - mSafeLogger.warning("Invalid <System Audio Mode Status> message:" + message); - return false; + HdmiLogger.warning("Invalid <System Audio Mode Status> message:" + message); + // Ignore this message. + return true; } setSystemAudioMode(HdmiUtils.parseCommandParamSystemAudioStatus(message), true); return true; @@ -973,7 +995,10 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { int recorderAddress = message.getSource(); byte[] recordSource = mService.invokeRecordRequestListener(recorderAddress); - startOneTouchRecord(recorderAddress, recordSource); + int reason = startOneTouchRecord(recorderAddress, recordSource); + if (reason != Constants.ABORT_NO_ERROR) { + mService.maySendFeatureAbortCommand(message, reason); + } return true; } @@ -998,7 +1023,8 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { } private boolean isMessageForSystemAudio(HdmiCecMessage message) { - return message.getSource() == Constants.ADDR_AUDIO_SYSTEM + return mService.isControlEnabled() + && message.getSource() == Constants.ADDR_AUDIO_SYSTEM && (message.getDestination() == Constants.ADDR_TV || message.getDestination() == Constants.ADDR_BROADCAST) && getAvrDeviceInfo() != null; @@ -1445,31 +1471,38 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { mService.displayOsd(messageId); } + @ServiceThreadOnly + void displayOsd(int messageId, int extra) { + assertRunOnServiceThread(); + mService.displayOsd(messageId, extra); + } + // Seq #54 and #55 @ServiceThreadOnly - void startOneTouchRecord(int recorderAddress, byte[] recordSource) { + int startOneTouchRecord(int recorderAddress, byte[] recordSource) { assertRunOnServiceThread(); if (!mService.isControlEnabled()) { Slog.w(TAG, "Can not start one touch record. CEC control is disabled."); announceOneTouchRecordResult(ONE_TOUCH_RECORD_CEC_DISABLED); - return; + return Constants.ABORT_NOT_IN_CORRECT_MODE; } if (!checkRecorder(recorderAddress)) { Slog.w(TAG, "Invalid recorder address:" + recorderAddress); announceOneTouchRecordResult(ONE_TOUCH_RECORD_CHECK_RECORDER_CONNECTION); - return; + return Constants.ABORT_NOT_IN_CORRECT_MODE; } if (!checkRecordSource(recordSource)) { Slog.w(TAG, "Invalid record source." + Arrays.toString(recordSource)); announceOneTouchRecordResult(ONE_TOUCH_RECORD_FAIL_TO_RECORD_DISPLAYED_SCREEN); - return; + return Constants.ABORT_UNABLE_TO_DETERMINE; } addAndStartAction(new OneTouchRecordAction(this, recorderAddress, recordSource)); Slog.i(TAG, "Start new [One Touch Record]-Target:" + recorderAddress + ", recordSource:" + Arrays.toString(recordSource)); + return Constants.ABORT_NO_ERROR; } @ServiceThreadOnly diff --git a/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java b/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java index 8b345cfc675d..0b3d9fb5df68 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java @@ -51,7 +51,6 @@ public final class HdmiCecMessageValidator { } final SparseArray<ValidationInfo> mValidationInfo = new SparseArray<>(); - private final HdmiLogger mSpamSafeLogger = new HdmiLogger(TAG); public HdmiCecMessageValidator(HdmiControlService service) { mService = service; @@ -183,32 +182,32 @@ public final class HdmiCecMessageValidator { int opcode = message.getOpcode(); ValidationInfo info = mValidationInfo.get(opcode); if (info == null) { - mSpamSafeLogger.warning("No validation information for the message: " + message); + HdmiLogger.warning("No validation information for the message: " + message); return true; } // Check the source field. if (message.getSource() == Constants.ADDR_UNREGISTERED && (info.addressType & SRC_UNREGISTERED) == 0) { - mSpamSafeLogger.warning("Unexpected source: " + message); + HdmiLogger.warning("Unexpected source: " + message); return false; } // Check the destination field. if (message.getDestination() == Constants.ADDR_BROADCAST) { if ((info.addressType & DEST_BROADCAST) == 0) { - mSpamSafeLogger.warning("Unexpected broadcast message: " + message); + HdmiLogger.warning("Unexpected broadcast message: " + message); return false; } } else { // Direct addressing. if ((info.addressType & DEST_DIRECT) == 0) { - mSpamSafeLogger.warning("Unexpected direct message: " + message); + HdmiLogger.warning("Unexpected direct message: " + message); return false; } } // Check the parameter type. if (!info.parameterValidator.isValid(message.getParams())) { - mSpamSafeLogger.warning("Unexpected parameters: " + message); + HdmiLogger.warning("Unexpected parameters: " + message); return false; } return true; diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java index 9314cf86a84e..38c6fb3e4f76 100644 --- a/services/core/java/com/android/server/hdmi/HdmiControlService.java +++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java @@ -166,8 +166,6 @@ public final class HdmiControlService extends SystemService { // Type of logical devices hosted in the system. Stored in the unmodifiable list. private final List<Integer> mLocalDevices; - private final HdmiLogger mSpamSafeLogger = new HdmiLogger(TAG); - // List of records for hotplug event listener to handle the the caller killed in action. @GuardedBy("mLock") private final ArrayList<HotplugEventListenerRecord> mHotplugEventListenerRecords = @@ -656,7 +654,7 @@ public final class HdmiControlService extends SystemService { if (mMessageValidator.isValid(command)) { mCecController.sendCommand(command, callback); } else { - mSpamSafeLogger.error("Invalid message type:" + command); + HdmiLogger.error("Invalid message type:" + command); if (callback != null) { callback.onSendCompleted(Constants.SEND_RESULT_FAILURE); } @@ -705,7 +703,7 @@ public final class HdmiControlService extends SystemService { } if (message.getDestination() != Constants.ADDR_BROADCAST) { - mSpamSafeLogger.warning("Unhandled cec command:" + message); + HdmiLogger.warning("Unhandled cec command:" + message); } return false; } @@ -794,7 +792,6 @@ public final class HdmiControlService extends SystemService { // FLAG_HDMI_SYSTEM_AUDIO_VOLUME prevents audio manager from announcing // volume change notification back to hdmi control service. audioManager.setStreamVolume(AudioManager.STREAM_MUSIC, volume, - AudioManager.FLAG_SHOW_UI | AudioManager.FLAG_HDMI_SYSTEM_AUDIO_VOLUME); } } @@ -2033,4 +2030,14 @@ public final class HdmiControlService extends SystemService { getContext().sendBroadcastAsUser(intent, UserHandle.ALL, HdmiControlService.PERMISSION); } + + @ServiceThreadOnly + void displayOsd(int messageId, int extra) { + assertRunOnServiceThread(); + Intent intent = new Intent(HdmiControlManager.ACTION_OSD_MESSAGE); + intent.putExtra(HdmiControlManager.EXTRA_MESSAGE_ID, messageId); + intent.putExtra(HdmiControlManager.EXTRA_MESSAGE_EXTRAM_PARAM1, extra); + getContext().sendBroadcastAsUser(intent, UserHandle.ALL, + HdmiControlService.PERMISSION); + } } diff --git a/services/core/java/com/android/server/hdmi/HdmiLogger.java b/services/core/java/com/android/server/hdmi/HdmiLogger.java index c7add75d346b..2562ffc7898a 100644 --- a/services/core/java/com/android/server/hdmi/HdmiLogger.java +++ b/services/core/java/com/android/server/hdmi/HdmiLogger.java @@ -26,44 +26,83 @@ import java.util.HashMap; /** * A logger that prevents spammy log. For the same log message, it logs once every 20seconds. * This class is not thread-safe. + * <p> + * For convenience, use single character prefix for all messages. + * Here are common acronyms + * <ul> + * <li>[T]: Timout + * <li>[R]: Received message + * <li>[S]: Sent message + * <li>[P]: Device polling result + * </ul> */ final class HdmiLogger { + private static final String TAG = "HDMI"; // Logging duration for same error message. private static final long ERROR_LOG_DURATTION_MILLIS = 20 * 1000; // 20s private static final boolean DEBUG = false; + private static final ThreadLocal<HdmiLogger> sLogger = new ThreadLocal<>(); + // Key (String): log message. // Value (Pair(Long, Integer)): a pair of last log time millis and the number of logMessage. // Cache for warning. private final HashMap<String, Pair<Long, Integer>> mWarningTimingCache = new HashMap<>(); // Cache for error. private final HashMap<String, Pair<Long, Integer>> mErrorTimingCache = new HashMap<>(); - private final String mTag; - HdmiLogger(String tag) { - mTag = "HDMI:" + tag; + private HdmiLogger() { + } + + static final void warning(String logMessage, Object... objs) { + getLogger().warningInternal(toLogString(logMessage, objs)); } - void warning(String logMessage) { + private void warningInternal(String logMessage) { String log = updateLog(mWarningTimingCache, logMessage); if (!log.isEmpty()) { - Slog.w(mTag, log); + Slog.w(TAG, log); } } - void error(String logMessage) { + static final void error(String logMessage, Object... objs) { + getLogger().errorInternal(toLogString(logMessage, objs)); + } + + private void errorInternal(String logMessage) { String log = updateLog(mErrorTimingCache, logMessage); if (!log.isEmpty()) { - Slog.e(mTag, log); + Slog.e(TAG, log); } } - void debug(String logMessage) { + static final void debug(String logMessage, Object... objs) { + getLogger().debugInternal(toLogString(logMessage, objs)); + } + + private void debugInternal(String logMessage) { if (!DEBUG) { return; } - Slog.d(mTag, logMessage); + Slog.d(TAG, logMessage); + } + + private static final String toLogString(String logMessage, Object[] objs) { + if (objs.length > 0) { + return String.format(logMessage, objs); + } else { + return logMessage; + } + } + + private static HdmiLogger getLogger() { + HdmiLogger logger = sLogger.get(); + if (logger == null) { + logger = new HdmiLogger(); + sLogger.set(logger); + } + return logger; } private static String updateLog(HashMap<String, Pair<Long, Integer>> cache, String logMessage) { diff --git a/services/core/java/com/android/server/hdmi/PowerStatusMonitorAction.java b/services/core/java/com/android/server/hdmi/PowerStatusMonitorAction.java index 03fbb9562420..1e29fd6e4ff4 100644 --- a/services/core/java/com/android/server/hdmi/PowerStatusMonitorAction.java +++ b/services/core/java/com/android/server/hdmi/PowerStatusMonitorAction.java @@ -77,7 +77,7 @@ public class PowerStatusMonitorAction extends HdmiCecFeatureAction { // if no device exists for incoming message, hands it over to other actions. return false; } - int newStatus = cmd.getParams()[0]; + int newStatus = cmd.getParams()[0] & 0xFF; updatePowerStatus(sourceAddress, newStatus, true); return true; } diff --git a/services/core/java/com/android/server/hdmi/RequestArcAction.java b/services/core/java/com/android/server/hdmi/RequestArcAction.java index 17c2d6cc1f1a..3fb450f2dbf8 100644 --- a/services/core/java/com/android/server/hdmi/RequestArcAction.java +++ b/services/core/java/com/android/server/hdmi/RequestArcAction.java @@ -85,6 +85,7 @@ abstract class RequestArcAction extends HdmiCecFeatureAction { if (mState != state || state != STATE_WATING_FOR_REQUEST_ARC_REQUEST_RESPONSE) { return; } + HdmiLogger.debug("[T]RequestArcAction."); disableArcTransmission(); finish(); } diff --git a/services/core/java/com/android/server/hdmi/RequestArcInitiationAction.java b/services/core/java/com/android/server/hdmi/RequestArcInitiationAction.java index f25363d4fccd..d9e1f24d95e9 100644 --- a/services/core/java/com/android/server/hdmi/RequestArcInitiationAction.java +++ b/services/core/java/com/android/server/hdmi/RequestArcInitiationAction.java @@ -35,15 +35,15 @@ final class RequestArcInitiationAction extends RequestArcAction { @Override boolean start() { + mState = STATE_WATING_FOR_REQUEST_ARC_REQUEST_RESPONSE; + addTimer(mState, HdmiConfig.TIMEOUT_MS); + HdmiCecMessage command = HdmiCecMessageBuilder.buildRequestArcInitiation( getSourceAddress(), mAvrAddress); sendCommand(command, new HdmiControlService.SendMessageCallback() { @Override public void onSendCompleted(int error) { - if (error == Constants.SEND_RESULT_SUCCESS) { - mState = STATE_WATING_FOR_REQUEST_ARC_REQUEST_RESPONSE; - addTimer(mState, HdmiConfig.TIMEOUT_MS); - } else { + if (error != Constants.SEND_RESULT_SUCCESS) { // If failed to send <Request ARC Initiation>, start "Disabled" // ARC transmission action. disableArcTransmission(); diff --git a/services/core/java/com/android/server/hdmi/RequestArcTerminationAction.java b/services/core/java/com/android/server/hdmi/RequestArcTerminationAction.java index 1491c724ce97..f5a01156cc92 100644 --- a/services/core/java/com/android/server/hdmi/RequestArcTerminationAction.java +++ b/services/core/java/com/android/server/hdmi/RequestArcTerminationAction.java @@ -35,15 +35,15 @@ final class RequestArcTerminationAction extends RequestArcAction { @Override boolean start() { + mState = STATE_WATING_FOR_REQUEST_ARC_REQUEST_RESPONSE; + addTimer(mState, HdmiConfig.TIMEOUT_MS); + HdmiCecMessage command = HdmiCecMessageBuilder.buildRequestArcTermination(getSourceAddress(), mAvrAddress); sendCommand(command, new HdmiControlService.SendMessageCallback() { @Override public void onSendCompleted(int error) { - if (error == Constants.SEND_RESULT_SUCCESS) { - mState = STATE_WATING_FOR_REQUEST_ARC_REQUEST_RESPONSE; - addTimer(mState, HdmiConfig.TIMEOUT_MS); - } else { + if (error != Constants.SEND_RESULT_SUCCESS) { // If failed to send <Request ARC Termination>, start "Disabled" ARC // transmission action. disableArcTransmission(); diff --git a/services/core/java/com/android/server/hdmi/SetArcTransmissionStateAction.java b/services/core/java/com/android/server/hdmi/SetArcTransmissionStateAction.java index 30519f36d8d3..bffa854b79e5 100644 --- a/services/core/java/com/android/server/hdmi/SetArcTransmissionStateAction.java +++ b/services/core/java/com/android/server/hdmi/SetArcTransmissionStateAction.java @@ -53,6 +53,18 @@ final class SetArcTransmissionStateAction extends HdmiCecFeatureAction { @Override boolean start() { if (mEnabled) { + // Enable ARC status immediately after sending <Report Arc Initiated>. + // If AVR responds with <Feature Abort>, disable ARC status again. + // This is different from spec that says that turns ARC status to + // "Enabled" if <Report ARC Initiated> is acknowledged and no + // <Feature Abort> is received. + // But implemented this way to save the time having to wait for + // <Feature Abort>. + setArcStatus(true); + // If succeeds to send <Report ARC Initiated>, wait general timeout + // to check whether there is no <Feature Abort> for <Report ARC Initiated>. + mState = STATE_WAITING_TIMEOUT; + addTimer(mState, HdmiConfig.TIMEOUT_MS); sendReportArcInitiated(); } else { setArcStatus(false); @@ -67,23 +79,11 @@ final class SetArcTransmissionStateAction extends HdmiCecFeatureAction { sendCommand(command, new HdmiControlService.SendMessageCallback() { @Override public void onSendCompleted(int error) { - if (error == Constants.SEND_RESULT_SUCCESS) { - // Enable ARC status immediately after sending <Report Arc Initiated>. - // If AVR responds with <Feature Abort>, disable ARC status again. - // This is different from spec that says that turns ARC status to - // "Enabled" if <Report ARC Initiated> is acknowledged and no - // <Feature Abort> is received. - // But implemented this way to save the time having to wait for - // <Feature Abort>. - setArcStatus(true); - // If succeeds to send <Report ARC Initiated>, wait general timeout - // to check whether there is no <Feature Abort> for <Report ARC Initiated>. - mState = STATE_WAITING_TIMEOUT; - addTimer(mState, HdmiConfig.TIMEOUT_MS); - } else { + if (error != Constants.SEND_RESULT_SUCCESS) { // If fails to send <Report ARC Initiated>, disable ARC and // send <Report ARC Terminated> directly. setArcStatus(false); + HdmiLogger.debug("Failed to send <Report Arc Initiated>."); finish(); } } @@ -112,6 +112,7 @@ final class SetArcTransmissionStateAction extends HdmiCecFeatureAction { if (opcode == Constants.MESSAGE_FEATURE_ABORT) { int originalOpcode = cmd.getParams()[0] & 0xFF; if (originalOpcode == Constants.MESSAGE_REPORT_ARC_INITIATED) { + HdmiLogger.debug("Feature aborted for <Report Arc Initiated>"); setArcStatus(false); finish(); return true; diff --git a/services/core/java/com/android/server/hdmi/SystemAudioAction.java b/services/core/java/com/android/server/hdmi/SystemAudioAction.java index d15ffb0db1a1..0871194b268f 100644 --- a/services/core/java/com/android/server/hdmi/SystemAudioAction.java +++ b/services/core/java/com/android/server/hdmi/SystemAudioAction.java @@ -98,7 +98,7 @@ abstract class SystemAudioAction extends HdmiCecFeatureAction { @Override public void onSendCompleted(int error) { if (error != Constants.SEND_RESULT_SUCCESS) { - DLOGGER.debug("Failed to send <System Audio Mode Request>:" + error); + HdmiLogger.debug("Failed to send <System Audio Mode Request>:" + error); setSystemAudioMode(false); finishWithCallback(HdmiControlManager.RESULT_COMMUNICATION_FAILED); } @@ -111,7 +111,7 @@ abstract class SystemAudioAction extends HdmiCecFeatureAction { private void handleSendSystemAudioModeRequestTimeout() { if (!mTargetAudioStatus // Don't retry for Off case. || mSendRetryCount++ >= MAX_SEND_RETRY_COUNT) { - DLOGGER.debug("[T]:wait for <Set System Audio Mode>."); + HdmiLogger.debug("[T]:wait for <Set System Audio Mode>."); setSystemAudioMode(false); finishWithCallback(HdmiControlManager.RESULT_TIMEOUT); return; @@ -130,7 +130,7 @@ abstract class SystemAudioAction extends HdmiCecFeatureAction { if (cmd.getOpcode() == Constants.MESSAGE_FEATURE_ABORT && (cmd.getParams()[0] & 0xFF) == Constants.MESSAGE_SYSTEM_AUDIO_MODE_REQUEST) { - DLOGGER.debug("Failed to start system audio mode request."); + HdmiLogger.debug("Failed to start system audio mode request."); setSystemAudioMode(false); finishWithCallback(HdmiControlManager.RESULT_EXCEPTION); return true; @@ -145,7 +145,7 @@ abstract class SystemAudioAction extends HdmiCecFeatureAction { startAudioStatusAction(); return true; } else { - DLOGGER.debug("Unexpected system audio mode request:" + receivedStatus); + HdmiLogger.debug("Unexpected system audio mode request:" + receivedStatus); // Unexpected response, consider the request is newly initiated by AVR. // To return 'false' will initiate new SystemAudioActionFromAvr by the control // service. diff --git a/services/core/java/com/android/server/hdmi/VolumeControlAction.java b/services/core/java/com/android/server/hdmi/VolumeControlAction.java index ddc267a5e2b6..4338fc7dd673 100644 --- a/services/core/java/com/android/server/hdmi/VolumeControlAction.java +++ b/services/core/java/com/android/server/hdmi/VolumeControlAction.java @@ -17,66 +17,35 @@ package com.android.server.hdmi; import static com.android.server.hdmi.Constants.IRT_MS; +import static com.android.server.hdmi.Constants.MESSAGE_FEATURE_ABORT; +import static com.android.server.hdmi.Constants.MESSAGE_REPORT_AUDIO_STATUS; +import static com.android.server.hdmi.Constants.MESSAGE_USER_CONTROL_PRESSED; -import com.android.internal.util.Preconditions; +import android.media.AudioManager; /** * Feature action that transmits volume change to Audio Receiver. * <p> - * This action is created when a user pressed volume up/down. However, Since Android only provides a - * listener for delta of some volume change, we will set a target volume, and check reported volume - * from Audio Receiver(AVR). If TV receives no <Report Audio Status> from AVR, this action - * will be finished in {@link #IRT_MS} * {@link #VOLUME_CHANGE_TIMEOUT_MAX_COUNT} (ms). + * This action is created when a user pressed volume up/down. However, Android only provides a + * listener for delta of some volume change instead of individual key event. Also it's hard to know + * Audio Receiver's number of volume steps for a single volume control key. Because of this, it + * sends key-down event until IRT timeout happens, and it will send key-up event if no additional + * volume change happens; otherwise, it will send again key-down as press and hold feature does. */ final class VolumeControlAction extends HdmiCecFeatureAction { private static final String TAG = "VolumeControlAction"; - private static final int VOLUME_MUTE = 101; - private static final int VOLUME_RESTORE = 102; + // State that wait for next volume press. + private static final int STATE_WAIT_FOR_NEXT_VOLUME_PRESS = 1; private static final int MAX_VOLUME = 100; - private static final int MIN_VOLUME = 0; - // State where to wait for <Report Audio Status> - private static final int STATE_WAIT_FOR_REPORT_VOLUME_STATUS = 1; - - // Maximum count of time out used to finish volume action. - private static final int VOLUME_CHANGE_TIMEOUT_MAX_COUNT = 2; + private static final int UNKNOWN_AVR_VOLUME = -1; private final int mAvrAddress; - private final int mTargetVolume; - private final boolean mIsVolumeUp; - private int mTimeoutCount; - - /** - * Create a {@link VolumeControlAction} for mute/restore change - * - * @param source source device sending volume change - * @param avrAddress address of audio receiver - * @param mute whether to mute sound or not. {@code true} for mute on; {@code false} for mute - * off, i.e restore volume - * @return newly created {@link VolumeControlAction} - */ - public static VolumeControlAction ofMute(HdmiCecLocalDevice source, int avrAddress, - boolean mute) { - return new VolumeControlAction(source, avrAddress, mute ? VOLUME_MUTE : VOLUME_RESTORE, - false); - } - - /** - * Create a {@link VolumeControlAction} for volume up/down change - * - * @param source source device sending volume change - * @param avrAddress address of audio receiver - * @param targetVolume target volume to be set to AVR. It should be in range of [0-100] - * @param isVolumeUp whether to volume up or not. {@code true} for volume up; {@code false} for - * volume down - * @return newly created {@link VolumeControlAction} - */ - public static VolumeControlAction ofVolumeChange(HdmiCecLocalDevice source, int avrAddress, - int targetVolume, boolean isVolumeUp) { - Preconditions.checkArgumentInRange(targetVolume, MIN_VOLUME, MAX_VOLUME, "volume"); - return new VolumeControlAction(source, avrAddress, targetVolume, isVolumeUp); - } + private boolean mIsVolumeUp; + private long mLastKeyUpdateTime; + private int mLastAvrVolume; + private boolean mSentKeyPressed; /** * Scale a custom volume value to cec volume scale. @@ -94,123 +63,141 @@ final class VolumeControlAction extends HdmiCecFeatureAction { * * @param cecVolume volume value in cec volume scale. It should be in a range of [0-100] * @param scale scale of custom volume (max volume) - * @return a volume value scaled to custom volume range + * @return a volume scaled to custom volume range */ public static int scaleToCustomVolume(int cecVolume, int scale) { return (cecVolume * scale) / MAX_VOLUME; } - private VolumeControlAction(HdmiCecLocalDevice source, int avrAddress, int targetVolume, - boolean isVolumeUp) { + VolumeControlAction(HdmiCecLocalDevice source, int avrAddress, boolean isVolumeUp) { super(source); - mAvrAddress = avrAddress; - mTargetVolume = targetVolume; mIsVolumeUp = isVolumeUp; + mLastAvrVolume = UNKNOWN_AVR_VOLUME; + mSentKeyPressed = false; + + updateLastKeyUpdateTime(); + } + + private void updateLastKeyUpdateTime() { + mLastKeyUpdateTime = System.currentTimeMillis(); } @Override boolean start() { - if (isForMute()) { - sendMuteChange(mTargetVolume == VOLUME_MUTE); - finish(); - return true; - } - - startVolumeChange(); + mState = STATE_WAIT_FOR_NEXT_VOLUME_PRESS; + sendVolumeKeyPressed(); + resetTimer(); return true; } - - private boolean isForMute() { - return mTargetVolume == VOLUME_MUTE || mTargetVolume == VOLUME_RESTORE; + private void sendVolumeKeyPressed() { + sendCommand(HdmiCecMessageBuilder.buildUserControlPressed(getSourceAddress(), mAvrAddress, + mIsVolumeUp ? HdmiCecKeycode.CEC_KEYCODE_VOLUME_UP + : HdmiCecKeycode.CEC_KEYCODE_VOLUME_DOWN)); + mSentKeyPressed = true; } - private void startVolumeChange() { - mTimeoutCount = 0; - sendVolumeChange(mIsVolumeUp); - mState = STATE_WAIT_FOR_REPORT_VOLUME_STATUS; - addTimer(mState, IRT_MS); + private void resetTimer() { + mActionTimer.clearTimerMessage(); + addTimer(STATE_WAIT_FOR_NEXT_VOLUME_PRESS, IRT_MS); } - private void sendVolumeChange(boolean up) { - sendCommand(HdmiCecMessageBuilder.buildUserControlPressed(getSourceAddress(), mAvrAddress, - up ? HdmiCecKeycode.CEC_KEYCODE_VOLUME_UP - : HdmiCecKeycode.CEC_KEYCODE_VOLUME_DOWN)); + void handleVolumeChange(boolean isVolumeUp) { + if (mIsVolumeUp != isVolumeUp) { + HdmiLogger.debug("Volume Key Status Changed[old:%b new:%b]", mIsVolumeUp, isVolumeUp); + sendVolumeKeyReleased(); + mIsVolumeUp = isVolumeUp; + } + updateLastKeyUpdateTime(); } - private void sendMuteChange(boolean mute) { - sendUserControlPressedAndReleased(mAvrAddress, - mute ? HdmiCecKeycode.CEC_KEYCODE_MUTE_FUNCTION : - HdmiCecKeycode.CEC_KEYCODE_RESTORE_VOLUME_FUNCTION); + private void sendVolumeKeyReleased() { + sendCommand(HdmiCecMessageBuilder.buildUserControlReleased( + getSourceAddress(), mAvrAddress)); + mSentKeyPressed = false; } @Override boolean processCommand(HdmiCecMessage cmd) { - if (mState != STATE_WAIT_FOR_REPORT_VOLUME_STATUS) { + if (mState != STATE_WAIT_FOR_NEXT_VOLUME_PRESS || cmd.getSource() != mAvrAddress) { return false; } switch (cmd.getOpcode()) { - case Constants.MESSAGE_REPORT_AUDIO_STATUS: - handleReportAudioStatus(cmd); - return true; - case Constants.MESSAGE_FEATURE_ABORT: - int originalOpcode = cmd.getParams()[0] & 0xFF; - if (originalOpcode == Constants.MESSAGE_USER_CONTROL_PRESSED - || originalOpcode == Constants.MESSAGE_USER_CONTROL_RELEASED) { - // TODO: handle feature abort. - finish(); - return true; - } - default: // fall through + case MESSAGE_REPORT_AUDIO_STATUS: + return handleReportAudioStatus(cmd); + case MESSAGE_FEATURE_ABORT: + return handleFeatureAbort(cmd); + default: return false; } } - private void handleReportAudioStatus(HdmiCecMessage cmd) { - byte[] params = cmd.getParams(); + private boolean handleReportAudioStatus(HdmiCecMessage cmd) { + byte params[] = cmd.getParams(); + boolean mute = (params[0] & 0x80) == 0x80; int volume = params[0] & 0x7F; - // Update volume with new value. - // Note that it will affect system volume change. - tv().setAudioStatus(false, volume); + mLastAvrVolume = volume; + if (shouldUpdateAudioVolume(mute)) { + HdmiLogger.debug("Force volume change[mute:%b, volume=%d]", mute, volume); + tv().setAudioStatus(mute, volume); + } + return true; + } + + private boolean shouldUpdateAudioVolume(boolean mute) { + // Do nothing if in mute. + if (mute) { + return true; + } + + // Update audio status if current volume position is edge of volume bar, + // i.e max or min volume. + AudioManager audioManager = tv().getService().getAudioManager(); + int currentVolume = audioManager.getStreamVolume(AudioManager.STREAM_MUSIC); if (mIsVolumeUp) { - if (mTargetVolume <= volume) { - finishWithVolumeChangeRelease(); - return; - } + int maxVolume = audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC); + return currentVolume == maxVolume; } else { - if (mTargetVolume >= volume) { - finishWithVolumeChangeRelease(); - return; - } + return currentVolume == 0; } + } - // Clear action status and send another volume change command. - clear(); - startVolumeChange(); + private boolean handleFeatureAbort(HdmiCecMessage cmd) { + int originalOpcode = cmd.getParams()[0] & 0xFF; + // Since it sends <User Control Released> only when it finishes this action, + // it takes care of <User Control Pressed> only here. + if (originalOpcode == MESSAGE_USER_CONTROL_PRESSED) { + finish(); + return true; + } + return false; } - private void finishWithVolumeChangeRelease() { - sendCommand(HdmiCecMessageBuilder.buildUserControlReleased( - getSourceAddress(), mAvrAddress)); - finish(); + @Override + protected void clear() { + super.clear(); + if (mSentKeyPressed) { + sendVolumeKeyReleased(); + } + if (mLastAvrVolume != UNKNOWN_AVR_VOLUME) { + tv().setAudioStatus(false, mLastAvrVolume); + mLastAvrVolume = UNKNOWN_AVR_VOLUME; + } } @Override void handleTimerEvent(int state) { - if (mState != STATE_WAIT_FOR_REPORT_VOLUME_STATUS) { + if (state != STATE_WAIT_FOR_NEXT_VOLUME_PRESS) { return; } - // If no report volume action after IRT * VOLUME_CHANGE_TIMEOUT_MAX_COUNT just stop volume - // action. - if (++mTimeoutCount == VOLUME_CHANGE_TIMEOUT_MAX_COUNT) { - finishWithVolumeChangeRelease(); - return; + if (System.currentTimeMillis() - mLastKeyUpdateTime >= IRT_MS) { + finish(); + } else { + sendVolumeKeyPressed(); + resetTimer(); } - - sendVolumeChange(mIsVolumeUp); - addTimer(mState, IRT_MS); } } diff --git a/services/core/java/com/android/server/notification/ConditionProviders.java b/services/core/java/com/android/server/notification/ConditionProviders.java index 189131c557f4..05ad1fe5ac08 100644 --- a/services/core/java/com/android/server/notification/ConditionProviders.java +++ b/services/core/java/com/android/server/notification/ConditionProviders.java @@ -545,8 +545,9 @@ public class ConditionProviders extends ManagedServices { setZenModeCondition(condition, "downtime"); } // exit downtime - if (!inDowntime && mode == Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS - && mDowntime.isDowntimeCondition(mExitCondition)) { + if (!inDowntime && mDowntime.isDowntimeCondition(mExitCondition) + && (mode == Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS + || mode == Global.ZEN_MODE_NO_INTERRUPTIONS)) { mZenModeHelper.setZenMode(Global.ZEN_MODE_OFF, "downtimeExit"); } } diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 0794edf40e1b..bc538ed14417 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -1470,7 +1470,14 @@ public class NotificationManagerService extends SystemService { @Override public boolean matchesCallFilter(Bundle extras) { enforceSystemOrSystemUI("INotificationManager.matchesCallFilter"); - return mZenModeHelper.matchesCallFilter(extras, + return matchesCallFilterAsUser(extras, Binder.getCallingUid()); + } + + @Override + public boolean matchesCallFilterAsUser(Bundle extras, int userId) { + enforceSystemOrSystemUI("INotificationManager.matchesCallFilter"); + UserHandle userHandle = new UserHandle(userId); + return mZenModeHelper.matchesCallFilter(userHandle, extras, mRankingHelper.findExtractor(ValidateNotificationPeople.class)); } }; @@ -2636,7 +2643,10 @@ public class NotificationManagerService extends SystemService { visibilityOverrides.putInt(record.sbn.getKey(), record.getPackageVisibilityOverride()); } + // Find first min-prio notification for speedbump placement. if (speedBumpIndex == -1 && + // Intrusiveness trumps priority, hence ignore intrusives. + !record.isRecentlyIntrusive() && record.sbn.getNotification().priority == Notification.PRIORITY_MIN) { speedBumpIndex = keys.size() - 1; } diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java index 84b4d9754448..fd34aa5fbcb3 100644 --- a/services/core/java/com/android/server/notification/NotificationRecord.java +++ b/services/core/java/com/android/server/notification/NotificationRecord.java @@ -21,6 +21,7 @@ import android.content.pm.PackageManager.NameNotFoundException; import android.content.res.Resources; import android.graphics.Bitmap; import android.media.AudioAttributes; +import android.os.UserHandle; import android.service.notification.StatusBarNotification; import com.android.internal.annotations.VisibleForTesting; @@ -88,8 +89,10 @@ public final class NotificationRecord { public Notification getNotification() { return sbn.getNotification(); } public int getFlags() { return sbn.getNotification().flags; } - public int getUserId() { return sbn.getUserId(); } + public UserHandle getUser() { return sbn.getUser(); } public String getKey() { return sbn.getKey(); } + /** @deprecated Use {@link #getUser()} instead. */ + public int getUserId() { return sbn.getUserId(); } void dump(PrintWriter pw, String prefix, Context baseContext) { final Notification notification = sbn.getNotification(); diff --git a/services/core/java/com/android/server/notification/ValidateNotificationPeople.java b/services/core/java/com/android/server/notification/ValidateNotificationPeople.java index aa47858f913b..f266916d3646 100644 --- a/services/core/java/com/android/server/notification/ValidateNotificationPeople.java +++ b/services/core/java/com/android/server/notification/ValidateNotificationPeople.java @@ -18,18 +18,23 @@ package com.android.server.notification; import android.app.Notification; import android.content.Context; +import android.content.pm.PackageManager; import android.database.Cursor; import android.net.Uri; import android.os.Bundle; +import android.os.UserHandle; import android.provider.ContactsContract; import android.provider.ContactsContract.Contacts; import android.provider.Settings; import android.text.TextUtils; +import android.util.ArrayMap; +import android.util.Log; import android.util.LruCache; import android.util.Slog; import java.util.ArrayList; import java.util.LinkedList; +import java.util.Map; /** * This {@link NotificationSignalExtractor} attempts to validate @@ -65,21 +70,88 @@ public class ValidateNotificationPeople implements NotificationSignalExtractor { static final float STARRED_CONTACT = 1f; protected boolean mEnabled; - private Context mContext; + private Context mBaseContext; // maps raw person handle to resolved person object private LruCache<String, LookupResult> mPeopleCache; + private Map<Integer, Context> mUserToContextMap; - private RankingReconsideration validatePeople(final NotificationRecord record) { + public void initialize(Context context) { + if (DEBUG) Slog.d(TAG, "Initializing " + getClass().getSimpleName() + "."); + mUserToContextMap = new ArrayMap<>(); + mBaseContext = context; + mPeopleCache = new LruCache<String, LookupResult>(PEOPLE_CACHE_SIZE); + mEnabled = ENABLE_PEOPLE_VALIDATOR && 1 == Settings.Global.getInt( + mBaseContext.getContentResolver(), SETTING_ENABLE_PEOPLE_VALIDATOR, 1); + } + + public RankingReconsideration process(NotificationRecord record) { + if (!mEnabled) { + if (INFO) Slog.i(TAG, "disabled"); + return null; + } + if (record == null || record.getNotification() == null) { + if (INFO) Slog.i(TAG, "skipping empty notification"); + return null; + } + if (record.getUserId() == UserHandle.USER_ALL) { + if (INFO) Slog.i(TAG, "skipping global notification"); + return null; + } + Context context = getContextAsUser(record.getUser()); + if (context == null) { + if (INFO) Slog.i(TAG, "skipping notification that lacks a context"); + return null; + } + return validatePeople(context, record); + } + + @Override + public void setConfig(RankingConfig config) { + // ignore: config has no relevant information yet. + } + + public float getContactAffinity(UserHandle userHandle, Bundle extras) { + if (extras == null) return NONE; + final String key = Long.toString(System.nanoTime()); + final float[] affinityOut = new float[1]; + Context context = getContextAsUser(userHandle); + if (context == null) { + return NONE; + } + final PeopleRankingReconsideration prr = validatePeople(context, key, extras, affinityOut); + float affinity = affinityOut[0]; + if (prr != null) { + prr.work(); + affinity = Math.max(prr.getContactAffinity(), affinity); + } + return affinity; + } + + private Context getContextAsUser(UserHandle userHandle) { + Context context = mUserToContextMap.get(userHandle.getIdentifier()); + if (context == null) { + try { + context = mBaseContext.createPackageContextAsUser("android", 0, userHandle); + mUserToContextMap.put(userHandle.getIdentifier(), context); + } catch (PackageManager.NameNotFoundException e) { + Log.e(TAG, "failed to create package context for lookups", e); + } + } + return context; + } + + private RankingReconsideration validatePeople(Context context, + final NotificationRecord record) { final String key = record.getKey(); final Bundle extras = record.getNotification().extras; final float[] affinityOut = new float[1]; - final RankingReconsideration rr = validatePeople(key, extras, affinityOut); + final RankingReconsideration rr = validatePeople(context, key, extras, affinityOut); record.setContactAffinity(affinityOut[0]); return rr; } - private PeopleRankingReconsideration validatePeople(String key, Bundle extras, + private PeopleRankingReconsideration validatePeople(Context context, String key, Bundle extras, float[] affinityOut) { float affinity = NONE; if (extras == null) { @@ -98,7 +170,8 @@ public class ValidateNotificationPeople implements NotificationSignalExtractor { if (TextUtils.isEmpty(handle)) continue; synchronized (mPeopleCache) { - LookupResult lookupResult = mPeopleCache.get(handle); + final String cacheKey = getCacheKey(context.getUserId(), handle); + LookupResult lookupResult = mPeopleCache.get(cacheKey); if (lookupResult == null || lookupResult.isExpired()) { pendingLookups.add(handle); } else { @@ -119,7 +192,11 @@ public class ValidateNotificationPeople implements NotificationSignalExtractor { } if (DEBUG) Slog.d(TAG, "Pending: future work scheduled for: " + key); - return new PeopleRankingReconsideration(key, pendingLookups); + return new PeopleRankingReconsideration(context, key, pendingLookups); + } + + private String getCacheKey(int userId, String handle) { + return Integer.toString(userId) + ":" + handle; } // VisibleForTesting @@ -185,24 +262,24 @@ public class ValidateNotificationPeople implements NotificationSignalExtractor { return null; } - private LookupResult resolvePhoneContact(final String number) { + private LookupResult resolvePhoneContact(Context context, final String number) { Uri phoneUri = Uri.withAppendedPath(ContactsContract.PhoneLookup.CONTENT_FILTER_URI, Uri.encode(number)); - return searchContacts(phoneUri); + return searchContacts(context, phoneUri); } - private LookupResult resolveEmailContact(final String email) { + private LookupResult resolveEmailContact(Context context, final String email) { Uri numberUri = Uri.withAppendedPath( ContactsContract.CommonDataKinds.Email.CONTENT_LOOKUP_URI, Uri.encode(email)); - return searchContacts(numberUri); + return searchContacts(context, numberUri); } - private LookupResult searchContacts(Uri lookupUri) { + private LookupResult searchContacts(Context context, Uri lookupUri) { LookupResult lookupResult = new LookupResult(); Cursor c = null; try { - c = mContext.getContentResolver().query(lookupUri, LOOKUP_PROJECTION, null, null, null); + c = context.getContentResolver().query(lookupUri, LOOKUP_PROJECTION, null, null, null); if (c != null && c.getCount() > 0) { c.moveToFirst(); lookupResult.readContact(c); @@ -217,44 +294,6 @@ public class ValidateNotificationPeople implements NotificationSignalExtractor { return lookupResult; } - public void initialize(Context context) { - if (DEBUG) Slog.d(TAG, "Initializing " + getClass().getSimpleName() + "."); - mContext = context; - mPeopleCache = new LruCache<String, LookupResult>(PEOPLE_CACHE_SIZE); - mEnabled = ENABLE_PEOPLE_VALIDATOR && 1 == Settings.Global.getInt( - mContext.getContentResolver(), SETTING_ENABLE_PEOPLE_VALIDATOR, 1); - } - - public RankingReconsideration process(NotificationRecord record) { - if (!mEnabled) { - if (INFO) Slog.i(TAG, "disabled"); - return null; - } - if (record == null || record.getNotification() == null) { - if (INFO) Slog.i(TAG, "skipping empty notification"); - return null; - } - return validatePeople(record); - } - - @Override - public void setConfig(RankingConfig config) { - // ignore: config has no relevant information yet. - } - - public float getContactAffinity(Bundle extras) { - if (extras == null) return NONE; - final String key = Long.toString(System.nanoTime()); - final float[] affinityOut = new float[1]; - final PeopleRankingReconsideration prr = validatePeople(key, extras, affinityOut); - float affinity = affinityOut[0]; - if (prr != null) { - prr.work(); - affinity = Math.max(prr.getContactAffinity(), affinity); - } - return affinity; - } - private static class LookupResult { private static final long CONTACT_REFRESH_MILLIS = 60 * 60 * 1000; // 1hr public static final int INVALID_ID = -1; @@ -317,11 +356,13 @@ public class ValidateNotificationPeople implements NotificationSignalExtractor { private class PeopleRankingReconsideration extends RankingReconsideration { private final LinkedList<String> mPendingLookups; + private final Context mContext; private float mContactAffinity = NONE; - private PeopleRankingReconsideration(String key, LinkedList<String> pendingLookups) { + private PeopleRankingReconsideration(Context context, String key, LinkedList<String> pendingLookups) { super(key); + mContext = context; mPendingLookups = pendingLookups; } @@ -333,20 +374,21 @@ public class ValidateNotificationPeople implements NotificationSignalExtractor { final Uri uri = Uri.parse(handle); if ("tel".equals(uri.getScheme())) { if (DEBUG) Slog.d(TAG, "checking telephone URI: " + handle); - lookupResult = resolvePhoneContact(uri.getSchemeSpecificPart()); + lookupResult = resolvePhoneContact(mContext, uri.getSchemeSpecificPart()); } else if ("mailto".equals(uri.getScheme())) { if (DEBUG) Slog.d(TAG, "checking mailto URI: " + handle); - lookupResult = resolveEmailContact(uri.getSchemeSpecificPart()); + lookupResult = resolveEmailContact(mContext, uri.getSchemeSpecificPart()); } else if (handle.startsWith(Contacts.CONTENT_LOOKUP_URI.toString())) { if (DEBUG) Slog.d(TAG, "checking lookup URI: " + handle); - lookupResult = searchContacts(uri); + lookupResult = searchContacts(mContext, uri); } else { lookupResult = new LookupResult(); // invalid person for the cache Slog.w(TAG, "unsupported URI " + handle); } if (lookupResult != null) { synchronized (mPeopleCache) { - mPeopleCache.put(handle, lookupResult); + final String cacheKey = getCacheKey(mContext.getUserId(), handle); + mPeopleCache.put(cacheKey, lookupResult); } mContactAffinity = Math.max(mContactAffinity, lookupResult.getAffinity()); } diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java index fd35eded8dde..168328fd5976 100644 --- a/services/core/java/com/android/server/notification/ZenModeHelper.java +++ b/services/core/java/com/android/server/notification/ZenModeHelper.java @@ -373,13 +373,14 @@ public class ZenModeHelper { return record.isCategory(Notification.CATEGORY_MESSAGE) || isDefaultMessagingApp(record); } - public boolean matchesCallFilter(Bundle extras, ValidateNotificationPeople validator) { + public boolean matchesCallFilter(UserHandle userHandle, Bundle extras, + ValidateNotificationPeople validator) { final int zen = mZenMode; if (zen == Global.ZEN_MODE_NO_INTERRUPTIONS) return false; // nothing gets through if (zen == Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS) { if (!mConfig.allowCalls) return false; // no calls get through if (validator != null) { - final float contactAffinity = validator.getContactAffinity(extras); + final float contactAffinity = validator.getContactAffinity(userHandle, extras); return audienceMatches(contactAffinity); } } diff --git a/services/core/java/com/android/server/pm/BackgroundDexOptService.java b/services/core/java/com/android/server/pm/BackgroundDexOptService.java index 355f34fe9e43..a7eebf832f09 100644 --- a/services/core/java/com/android/server/pm/BackgroundDexOptService.java +++ b/services/core/java/com/android/server/pm/BackgroundDexOptService.java @@ -75,7 +75,7 @@ public class BackgroundDexOptService extends JobService { schedule(BackgroundDexOptService.this); return; } - pm.performDexOpt(pkg, null /* instruction set */, false); + pm.performDexOpt(pkg, null /* instruction set */, true); } // ran to completion, so we abandon our timeslice and do not reschedule jobFinished(jobParams, false); diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java index 3f7a607efce3..9a00923effcb 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerService.java +++ b/services/core/java/com/android/server/pm/PackageInstallerService.java @@ -47,12 +47,12 @@ import android.content.pm.IPackageInstaller; import android.content.pm.IPackageInstallerCallback; import android.content.pm.IPackageInstallerSession; import android.content.pm.PackageInstaller; -import android.content.pm.PackageParser; import android.content.pm.PackageInstaller.SessionInfo; import android.content.pm.PackageInstaller.SessionParams; +import android.content.pm.PackageManager; +import android.content.pm.PackageParser; import android.content.pm.PackageParser.PackageLite; import android.content.pm.PackageParser.PackageParserException; -import android.content.pm.PackageManager; import android.graphics.Bitmap; import android.net.Uri; import android.os.Binder; @@ -581,6 +581,30 @@ public class PackageInstallerService extends IPackageInstaller.Stub { } @Override + public void updateSessionAppIcon(int sessionId, Bitmap appIcon) { + synchronized (mSessions) { + final PackageInstallerSession session = mSessions.get(sessionId); + if (session == null || !isCallingUidOwner(session)) { + throw new SecurityException("Caller has no access to session " + sessionId); + } + session.params.appIcon = appIcon; + mInternalCallback.onSessionBadgingChanged(session); + } + } + + @Override + public void updateSessionAppLabel(int sessionId, String appLabel) { + synchronized (mSessions) { + final PackageInstallerSession session = mSessions.get(sessionId); + if (session == null || !isCallingUidOwner(session)) { + throw new SecurityException("Caller has no access to session " + sessionId); + } + session.params.appLabel = appLabel; + mInternalCallback.onSessionBadgingChanged(session); + } + } + + @Override public void abandonSession(int sessionId) { synchronized (mSessions) { final PackageInstallerSession session = mSessions.get(sessionId); @@ -681,9 +705,6 @@ public class PackageInstallerService extends IPackageInstaller.Stub { public SessionInfo getSessionInfo(int sessionId) { synchronized (mSessions) { final PackageInstallerSession session = mSessions.get(sessionId); - if (!isCallingUidOwner(session)) { - enforceCallerCanReadSessions(); - } return session != null ? session.generateInfo() : null; } } @@ -691,7 +712,6 @@ public class PackageInstallerService extends IPackageInstaller.Stub { @Override public List<SessionInfo> getAllSessions(int userId) { mPm.enforceCrossUserPermission(Binder.getCallingUid(), userId, true, "getAllSessions"); - enforceCallerCanReadSessions(); final List<SessionInfo> result = new ArrayList<>(); synchronized (mSessions) { @@ -755,8 +775,6 @@ public class PackageInstallerService extends IPackageInstaller.Stub { @Override public void registerCallback(IPackageInstallerCallback callback, int userId) { mPm.enforceCrossUserPermission(Binder.getCallingUid(), userId, true, "registerCallback"); - enforceCallerCanReadSessions(); - mCallbacks.register(callback, userId); } @@ -787,21 +805,6 @@ public class PackageInstallerService extends IPackageInstaller.Stub { } } - /** - * We allow those with permission, or the current home app. - */ - private void enforceCallerCanReadSessions() { - final boolean hasPermission = (mContext.checkCallingOrSelfPermission( - android.Manifest.permission.READ_INSTALL_SESSIONS) - == PackageManager.PERMISSION_GRANTED); - final boolean isHomeApp = mPm.checkCallerIsHomeApp(); - if (hasPermission || isHomeApp) { - return; - } else { - throw new SecurityException("Caller must be current home app to read install sessions"); - } - } - static class PackageDeleteObserverAdapter extends PackageDeleteObserver { private final Context mContext; private final IntentSender mTarget; @@ -893,10 +896,11 @@ public class PackageInstallerService extends IPackageInstaller.Stub { private static class Callbacks extends Handler { private static final int MSG_SESSION_CREATED = 1; - private static final int MSG_SESSION_OPENED = 2; - private static final int MSG_SESSION_PROGRESS_CHANGED = 3; - private static final int MSG_SESSION_CLOSED = 4; - private static final int MSG_SESSION_FINISHED = 5; + private static final int MSG_SESSION_BADGING_CHANGED = 2; + private static final int MSG_SESSION_OPENED = 3; + private static final int MSG_SESSION_PROGRESS_CHANGED = 4; + private static final int MSG_SESSION_CLOSED = 5; + private static final int MSG_SESSION_FINISHED = 6; private final RemoteCallbackList<IPackageInstallerCallback> mCallbacks = new RemoteCallbackList<>(); @@ -938,6 +942,9 @@ public class PackageInstallerService extends IPackageInstaller.Stub { case MSG_SESSION_CREATED: callback.onSessionCreated(sessionId); break; + case MSG_SESSION_BADGING_CHANGED: + callback.onSessionBadgingChanged(sessionId); + break; case MSG_SESSION_OPENED: callback.onSessionOpened(sessionId); break; @@ -957,6 +964,10 @@ public class PackageInstallerService extends IPackageInstaller.Stub { obtainMessage(MSG_SESSION_CREATED, sessionId, userId).sendToTarget(); } + private void notifySessionBadgingChanged(int sessionId, int userId) { + obtainMessage(MSG_SESSION_BADGING_CHANGED, sessionId, userId).sendToTarget(); + } + private void notifySessionOpened(int sessionId, int userId) { obtainMessage(MSG_SESSION_OPENED, sessionId, userId).sendToTarget(); } @@ -1006,14 +1017,19 @@ public class PackageInstallerService extends IPackageInstaller.Stub { } class InternalCallback { - public void onSessionProgressChanged(PackageInstallerSession session, float progress) { - mCallbacks.notifySessionProgressChanged(session.sessionId, session.userId, progress); + public void onSessionBadgingChanged(PackageInstallerSession session) { + mCallbacks.notifySessionBadgingChanged(session.sessionId, session.userId); + writeSessionsAsync(); } public void onSessionOpened(PackageInstallerSession session) { mCallbacks.notifySessionOpened(session.sessionId, session.userId); } + public void onSessionProgressChanged(PackageInstallerSession session, float progress) { + mCallbacks.notifySessionProgressChanged(session.sessionId, session.userId, progress); + } + public void onSessionClosed(PackageInstallerSession session) { mCallbacks.notifySessionClosed(session.sessionId, session.userId); } diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java index 5264fc4b13fd..85ff54e444c2 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerSession.java +++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java @@ -294,7 +294,9 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } private void computeProgressLocked() { - mProgress = MathUtils.constrain(mClientProgress * 0.8f, 0f, 0.8f); + if (mProgress <= 0.8f) { + mProgress = MathUtils.constrain(mClientProgress * 0.8f, 0f, 0.8f); + } } private void maybePublishProgress() { @@ -485,7 +487,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } // TODO: surface more granular state from dexopt - mCallback.onSessionProgressChanged(this, 0.9f); + mProgress = 0.9f; + maybePublishProgress(); // Unpack native libraries extractNativeLibraries(mResolvedStageDir, params.abiOverride); diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 846efc075d5d..d2a627e32137 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -312,6 +312,12 @@ public class PackageManagerService extends IPackageManager.Stub { final PackageHandler mHandler; + /** + * Messages for {@link #mHandler} that need to wait for system ready before + * being dispatched. + */ + private ArrayList<Message> mPostSystemReadyMessages; + final int mSdkVersion = Build.VERSION.SDK_INT; final Context mContext; @@ -446,9 +452,9 @@ public class PackageManagerService extends IPackageManager.Stub { /** Token for keys in mPendingVerification. */ private int mPendingVerificationToken = 0; - boolean mSystemReady; - boolean mSafeMode; - boolean mHasSystemUidErrors; + volatile boolean mSystemReady; + volatile boolean mSafeMode; + volatile boolean mHasSystemUidErrors; ApplicationInfo mAndroidApplication; final ActivityInfo mResolveActivity = new ActivityInfo(); @@ -4512,7 +4518,7 @@ public class PackageManagerService extends IPackageManager.Stub { @Override public boolean performDexOptIfNeeded(String packageName, String instructionSet) { - return performDexOpt(packageName, instructionSet, true); + return performDexOpt(packageName, instructionSet, false); } private static String getPrimaryInstructionSet(ApplicationInfo info) { @@ -7685,16 +7691,18 @@ public class PackageManagerService extends IPackageManager.Stub { } void schedulePackageCleaning(String packageName, int userId, boolean andCode) { - if (false) { - RuntimeException here = new RuntimeException("here"); - here.fillInStackTrace(); - Slog.d(TAG, "Schedule cleaning " + packageName + " user=" + userId - + " andCode=" + andCode, here); + final Message msg = mHandler.obtainMessage(START_CLEANING_PACKAGE, + userId, andCode ? 1 : 0, packageName); + if (mSystemReady) { + msg.sendToTarget(); + } else { + if (mPostSystemReadyMessages == null) { + mPostSystemReadyMessages = new ArrayList<>(); + } + mPostSystemReadyMessages.add(msg); } - mHandler.sendMessage(mHandler.obtainMessage(START_CLEANING_PACKAGE, - userId, andCode ? 1 : 0, packageName)); } - + void startCleaningPackages() { // reader synchronized (mPackages) { @@ -11738,47 +11746,6 @@ public class PackageManagerService extends IPackageManager.Stub { preferred.activityInfo.name); } - /** - * Check if calling UID is the current home app. This handles both the case - * where the user has selected a specific home app, and where there is only - * one home app. - */ - public boolean checkCallerIsHomeApp() { - final Intent intent = new Intent(Intent.ACTION_MAIN); - intent.addCategory(Intent.CATEGORY_HOME); - - final int callingUid = Binder.getCallingUid(); - final int callingUserId = UserHandle.getCallingUserId(); - final List<ResolveInfo> allHomes = queryIntentActivities(intent, null, 0, callingUserId); - final ResolveInfo preferredHome = findPreferredActivity(intent, null, 0, allHomes, 0, true, - false, false, callingUserId); - - if (preferredHome != null) { - if (callingUid == preferredHome.activityInfo.applicationInfo.uid) { - return true; - } - } else { - for (ResolveInfo info : allHomes) { - if (callingUid == info.activityInfo.applicationInfo.uid) { - return true; - } - } - } - - return false; - } - - /** - * Enforce that calling UID is the current home app. This handles both the - * case where the user has selected a specific home app, and where there is - * only one home app. - */ - public void enforceCallerIsHomeApp() { - if (!checkCallerIsHomeApp()) { - throw new SecurityException("Caller is not currently selected home app"); - } - } - @Override public void setApplicationEnabledSetting(String appPackageName, int newState, int flags, int userId, String callingPackage) { @@ -12038,6 +12005,14 @@ public class PackageManagerService extends IPackageManager.Stub { } } sUserManager.systemReady(); + + // Kick off any messages waiting for system ready + if (mPostSystemReadyMessages != null) { + for (Message msg : mPostSystemReadyMessages) { + msg.sendToTarget(); + } + mPostSystemReadyMessages = null; + } } @Override @@ -13035,6 +13010,9 @@ public class PackageManagerService extends IPackageManager.Stub { Iterator<PackageSetting> psit = mSettings.mPackages.values().iterator(); while (psit.hasNext()) { PackageSetting ps = psit.next(); + if (ps.pkg == null) { + continue; + } final String packageName = ps.pkg.packageName; // Skip over if system app if ((ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) != 0) { diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index cad277200730..09584f463ce6 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -2996,10 +2996,12 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { mContext.enforceCallingOrSelfPermission( android.Manifest.permission.BIND_DEVICE_ADMIN, null); - synchronized (this) { - DevicePolicyData policy = getUserData(userHandle); - long ident = Binder.clearCallingIdentity(); - try { + long ident = Binder.clearCallingIdentity(); + try { + boolean wipeData = false; + int identifier = 0; + synchronized (this) { + DevicePolicyData policy = getUserData(userHandle); policy.mFailedPasswordAttempts++; saveSettingsLocked(userHandle); if (mHasFeature) { @@ -3011,15 +3013,20 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { // Wipe the user/profile associated with the policy that was violated. This // is not necessarily calling user: if the policy that fired was from a // managed profile rather than the main user profile, we wipe former only. - wipeDeviceOrUserLocked(0, strictestAdmin.getUserHandle().getIdentifier()); + wipeData = true; + identifier = strictestAdmin.getUserHandle().getIdentifier(); } sendAdminCommandToSelfAndProfilesLocked( DeviceAdminReceiver.ACTION_PASSWORD_FAILED, DeviceAdminInfo.USES_POLICY_WATCH_LOGIN, userHandle); } - } finally { - Binder.restoreCallingIdentity(ident); } + if (wipeData) { + // Call without holding lock. + wipeDeviceOrUserLocked(0, identifier); + } + } finally { + Binder.restoreCallingIdentity(ident); } } @@ -3654,11 +3661,15 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USERS, null); - if (mUserManager.getUserInfo(userHandle) == null) { + UserInfo info = mUserManager.getUserInfo(userHandle); + if (info == null) { // User doesn't exist. throw new IllegalArgumentException( "Attempted to set profile owner for invalid userId: " + userHandle); } + if (info.isGuest()) { + throw new IllegalStateException("Cannot set a profile owner on a guest"); + } if (who == null || !DeviceOwner.isInstalledForUser(who.getPackageName(), userHandle)) { diff --git a/services/print/java/com/android/server/print/PrintManagerService.java b/services/print/java/com/android/server/print/PrintManagerService.java index 64242ba7e0a0..6785cb8df220 100644 --- a/services/print/java/com/android/server/print/PrintManagerService.java +++ b/services/print/java/com/android/server/print/PrintManagerService.java @@ -627,26 +627,40 @@ public final class PrintManagerService extends SystemService { return userState; } - private void handleUserStarted(int userId) { - UserState userState; - synchronized (mLock) { - userState = getOrCreateUserStateLocked(userId); - userState.updateIfNeededLocked(); - } - // This is the first time we switch to this user after boot, so - // now is the time to remove obsolete print jobs since they - // are from the last boot and no application would query them. - userState.removeObsoletePrintJobs(); + private void handleUserStarted(final int userId) { + // This code will touch the remote print spooler which + // must be called off the main thread, so post the work. + BackgroundThread.getHandler().post(new Runnable() { + @Override + public void run() { + UserState userState; + synchronized (mLock) { + userState = getOrCreateUserStateLocked(userId); + userState.updateIfNeededLocked(); + } + // This is the first time we switch to this user after boot, so + // now is the time to remove obsolete print jobs since they + // are from the last boot and no application would query them. + userState.removeObsoletePrintJobs(); + } + }); } - private void handleUserStopped(int userId) { - synchronized (mLock) { - UserState userState = mUserStates.get(userId); - if (userState != null) { - userState.destroyLocked(); - mUserStates.remove(userId); + private void handleUserStopped(final int userId) { + // This code will touch the remote print spooler which + // must be called off the main thread, so post the work. + BackgroundThread.getHandler().post(new Runnable() { + @Override + public void run() { + synchronized (mLock) { + UserState userState = mUserStates.get(userId); + if (userState != null) { + userState.destroyLocked(); + mUserStates.remove(userId); + } + } } - } + }); } private int resolveCallingProfileParentLocked(int userId) { diff --git a/services/usage/java/com/android/server/usage/IntervalStats.java b/services/usage/java/com/android/server/usage/IntervalStats.java index dc036e251878..6c80a65ff007 100644 --- a/services/usage/java/com/android/server/usage/IntervalStats.java +++ b/services/usage/java/com/android/server/usage/IntervalStats.java @@ -15,17 +15,23 @@ */ package com.android.server.usage; +import android.app.usage.ConfigurationStats; import android.app.usage.TimeSparseArray; import android.app.usage.UsageEvents; import android.app.usage.UsageStats; +import android.content.res.Configuration; import android.util.ArrayMap; import android.util.ArraySet; +import java.util.ArrayList; + class IntervalStats { public long beginTime; public long endTime; public long lastTimeSaved; public final ArrayMap<String, UsageStats> stats = new ArrayMap<>(); + public final ArrayMap<Configuration, ConfigurationStats> configurations = new ArrayMap<>(); + public Configuration activeConfiguration; public TimeSparseArray<UsageEvents.Event> events; // A string cache. This is important as when we're parsing XML files, we don't want to @@ -34,18 +40,49 @@ class IntervalStats { // strings that had identical copies in the cache. private final ArraySet<String> mStringCache = new ArraySet<>(); + /** + * Gets the UsageStats object for the given package, or creates one and adds it internally. + */ UsageStats getOrCreateUsageStats(String packageName) { UsageStats usageStats = stats.get(packageName); if (usageStats == null) { usageStats = new UsageStats(); - usageStats.mPackageName = packageName; + usageStats.mPackageName = getCachedStringRef(packageName); usageStats.mBeginTimeStamp = beginTime; usageStats.mEndTimeStamp = endTime; - stats.put(packageName, usageStats); + stats.put(usageStats.mPackageName, usageStats); } return usageStats; } + /** + * Gets the ConfigurationStats object for the given configuration, or creates one and adds it + * internally. + */ + ConfigurationStats getOrCreateConfigurationStats(Configuration config) { + ConfigurationStats configStats = configurations.get(config); + if (configStats == null) { + configStats = new ConfigurationStats(); + configStats.mBeginTimeStamp = beginTime; + configStats.mEndTimeStamp = endTime; + configStats.mConfiguration = config; + configurations.put(config, configStats); + } + return configStats; + } + + /** + * Builds a UsageEvents.Event, but does not add it internally. + */ + UsageEvents.Event buildEvent(String packageName, String className) { + UsageEvents.Event event = new UsageEvents.Event(); + event.mPackage = getCachedStringRef(packageName); + if (className != null) { + event.mClass = getCachedStringRef(className); + } + return event; + } + void update(String packageName, long timeStamp, int eventType) { UsageStats usageStats = getOrCreateUsageStats(packageName); @@ -61,6 +98,28 @@ class IntervalStats { usageStats.mLastEvent = eventType; usageStats.mLastTimeUsed = timeStamp; usageStats.mEndTimeStamp = timeStamp; + + if (eventType == UsageEvents.Event.MOVE_TO_FOREGROUND) { + usageStats.mLaunchCount += 1; + } + + endTime = timeStamp; + } + + void updateConfigurationStats(Configuration config, long timeStamp) { + if (activeConfiguration != null) { + ConfigurationStats activeStats = configurations.get(activeConfiguration); + activeStats.mTotalTimeActive += timeStamp - activeStats.mLastTimeActive; + activeStats.mLastTimeActive = timeStamp - 1; + } + + if (config != null) { + ConfigurationStats configStats = getOrCreateConfigurationStats(config); + configStats.mLastTimeActive = timeStamp; + configStats.mActivationCount += 1; + activeConfiguration = configStats.mConfiguration; + } + endTime = timeStamp; } @@ -72,13 +131,4 @@ class IntervalStats { } return mStringCache.valueAt(index); } - - UsageEvents.Event buildEvent(String packageName, String className) { - UsageEvents.Event event = new UsageEvents.Event(); - event.mPackage = getCachedStringRef(packageName); - if (className != null) { - event.mClass = getCachedStringRef(className); - } - return event; - } } diff --git a/services/usage/java/com/android/server/usage/UsageStatsDatabase.java b/services/usage/java/com/android/server/usage/UsageStatsDatabase.java index e6ce0fe0b45b..37340a4e194c 100644 --- a/services/usage/java/com/android/server/usage/UsageStatsDatabase.java +++ b/services/usage/java/com/android/server/usage/UsageStatsDatabase.java @@ -17,7 +17,6 @@ package com.android.server.usage; import android.app.usage.TimeSparseArray; -import android.app.usage.UsageStats; import android.app.usage.UsageStatsManager; import android.util.AtomicFile; import android.util.Slog; @@ -133,9 +132,30 @@ class UsageStatsDatabase { } /** - * Find all {@link UsageStats} for the given range and interval type. + * Figures out what to extract from the given IntervalStats object. */ - public List<UsageStats> queryUsageStats(int intervalType, long beginTime, long endTime) { + interface StatCombiner<T> { + + /** + * Implementations should extract interesting from <code>stats</code> and add it + * to the <code>accumulatedResult</code> list. + * + * If the <code>stats</code> object is mutable, <code>mutable</code> will be true, + * which means you should make a copy of the data before adding it to the + * <code>accumulatedResult</code> list. + * + * @param stats The {@link IntervalStats} object selected. + * @param mutable Whether or not the data inside the stats object is mutable. + * @param accumulatedResult The list to which to add extracted data. + */ + void combine(IntervalStats stats, boolean mutable, List<T> accumulatedResult); + } + + /** + * Find all {@link IntervalStats} for the given range and interval type. + */ + public <T> List<T> queryUsageStats(int intervalType, long beginTime, long endTime, + StatCombiner<T> combiner) { synchronized (mLock) { if (intervalType < 0 || intervalType >= mIntervalDirs.length) { throw new IllegalArgumentException("Bad interval type " + intervalType); @@ -157,7 +177,7 @@ class UsageStatsDatabase { try { IntervalStats stats = new IntervalStats(); - ArrayList<UsageStats> results = new ArrayList<>(); + ArrayList<T> results = new ArrayList<>(); for (int i = startIndex; i <= endIndex; i++) { final AtomicFile f = mSortedStatFiles[intervalType].valueAt(i); @@ -167,7 +187,7 @@ class UsageStatsDatabase { UsageStatsXml.read(f, stats); if (beginTime < stats.endTime) { - results.addAll(stats.stats.values()); + combiner.combine(stats, false, results); } } return results; @@ -209,6 +229,10 @@ class UsageStatsDatabase { public void prune() { synchronized (mLock) { long timeNow = System.currentTimeMillis(); + mCal.setTimeInMillis(timeNow); + mCal.add(Calendar.YEAR, -3); + pruneFilesOlderThan(mIntervalDirs[UsageStatsManager.INTERVAL_YEARLY], + mCal.getTimeInMillis()); mCal.setTimeInMillis(timeNow); mCal.add(Calendar.MONTH, -6); diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java index 0e8b427bfb2c..e77bf86e6764 100644 --- a/services/usage/java/com/android/server/usage/UsageStatsService.java +++ b/services/usage/java/com/android/server/usage/UsageStatsService.java @@ -18,6 +18,7 @@ package com.android.server.usage; import android.Manifest; import android.app.AppOpsManager; +import android.app.usage.ConfigurationStats; import android.app.usage.IUsageStatsManager; import android.app.usage.UsageEvents; import android.app.usage.UsageStats; @@ -30,11 +31,13 @@ import android.content.IntentFilter; import android.content.pm.PackageManager; import android.content.pm.ParceledListSlice; import android.content.pm.UserInfo; +import android.content.res.Configuration; import android.os.Binder; import android.os.Environment; import android.os.Handler; import android.os.Looper; import android.os.Message; +import android.os.RemoteException; import android.os.UserHandle; import android.os.UserManager; import android.util.ArraySet; @@ -218,8 +221,7 @@ public class UsageStatsService extends SystemService implements * Called by the Binder stub. */ List<UsageStats> queryUsageStats(int userId, int bucketType, long beginTime, long endTime) { - final long timeNow = System.currentTimeMillis(); - if (beginTime > timeNow) { + if (!validRange(beginTime, endTime)) { return null; } @@ -232,15 +234,23 @@ public class UsageStatsService extends SystemService implements /** * Called by the Binder stub. */ - UsageEvents queryEvents(int userId, long beginTime, long endTime) { - final long timeNow = System.currentTimeMillis(); + List<ConfigurationStats> queryConfigurationStats(int userId, int bucketType, long beginTime, + long endTime) { + if (!validRange(beginTime, endTime)) { + return null; + } - // Adjust the endTime so that we don't query for the latest events. - // This is to prevent apps from making decision based on what app launched them, - // etc. - endTime = Math.min(endTime, timeNow - END_TIME_DELAY); + synchronized (mLock) { + UserUsageStatsService service = getUserDataAndInitializeIfNeededLocked(userId); + return service.queryConfigurationStats(bucketType, beginTime, endTime); + } + } - if (beginTime > endTime) { + /** + * Called by the Binder stub. + */ + UsageEvents queryEvents(int userId, long beginTime, long endTime) { + if (!validRange(beginTime, endTime)) { return null; } @@ -250,6 +260,11 @@ public class UsageStatsService extends SystemService implements } } + private static boolean validRange(long beginTime, long endTime) { + final long timeNow = System.currentTimeMillis(); + return beginTime <= timeNow && beginTime < endTime; + } + private void flushToDiskLocked() { final int userCount = mUserState.size(); for (int i = 0; i < userCount; i++) { @@ -323,6 +338,28 @@ public class UsageStatsService extends SystemService implements } @Override + public ParceledListSlice<ConfigurationStats> queryConfigurationStats(int bucketType, + long beginTime, long endTime, String callingPackage) throws RemoteException { + if (!hasPermission(callingPackage)) { + return null; + } + + final int userId = UserHandle.getCallingUserId(); + final long token = Binder.clearCallingIdentity(); + try { + final List<ConfigurationStats> results = + UsageStatsService.this.queryConfigurationStats(userId, bucketType, + beginTime, endTime); + if (results != null) { + return new ParceledListSlice<>(results); + } + } finally { + Binder.restoreCallingIdentity(token); + } + return null; + } + + @Override public UsageEvents queryEvents(long beginTime, long endTime, String callingPackage) { if (!hasPermission(callingPackage)) { return null; @@ -346,8 +383,7 @@ public class UsageStatsService extends SystemService implements private class LocalService extends UsageStatsManagerInternal { @Override - public void reportEvent(ComponentName component, int userId, - long timeStamp, int eventType) { + public void reportEvent(ComponentName component, int userId, int eventType) { if (component == null) { Slog.w(TAG, "Event reported without a component name"); return; @@ -356,12 +392,27 @@ public class UsageStatsService extends SystemService implements UsageEvents.Event event = new UsageEvents.Event(); event.mPackage = component.getPackageName(); event.mClass = component.getClassName(); - event.mTimeStamp = timeStamp; + event.mTimeStamp = System.currentTimeMillis(); event.mEventType = eventType; mHandler.obtainMessage(MSG_REPORT_EVENT, userId, 0, event).sendToTarget(); } @Override + public void reportConfigurationChange(Configuration config, int userId) { + if (config == null) { + Slog.w(TAG, "Configuration event reported with a null config"); + return; + } + + UsageEvents.Event event = new UsageEvents.Event(); + event.mPackage = "android"; + event.mTimeStamp = System.currentTimeMillis(); + event.mEventType = UsageEvents.Event.CONFIGURATION_CHANGE; + event.mConfiguration = new Configuration(config); + mHandler.obtainMessage(MSG_REPORT_EVENT, userId, 0, event).sendToTarget(); + } + + @Override public void prepareShutdown() { // This method *WILL* do IO work, but we must block until it is finished or else // we might not shutdown cleanly. This is ok to do with the 'am' lock held, because diff --git a/services/usage/java/com/android/server/usage/UsageStatsXmlV1.java b/services/usage/java/com/android/server/usage/UsageStatsXmlV1.java index 374429a8c01b..65299507d852 100644 --- a/services/usage/java/com/android/server/usage/UsageStatsXmlV1.java +++ b/services/usage/java/com/android/server/usage/UsageStatsXmlV1.java @@ -20,68 +20,69 @@ import com.android.internal.util.XmlUtils; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; +import org.xmlpull.v1.XmlSerializer; +import android.app.usage.ConfigurationStats; import android.app.usage.TimeSparseArray; import android.app.usage.UsageEvents; import android.app.usage.UsageStats; import android.content.ComponentName; +import android.content.res.Configuration; import java.io.IOException; import java.net.ProtocolException; +import java.util.Locale; /** * UsageStats reader/writer for version 1 of the XML format. */ final class UsageStatsXmlV1 { + private static final String PACKAGE_TAG = "package"; + private static final String CONFIGURATION_TAG = "config"; + private static final String EVENT_LOG_TAG = "event-log"; + private static final String BEGIN_TIME_ATTR = "beginTime"; private static final String END_TIME_ATTR = "endTime"; - private static final String PACKAGE_TAG = "package"; private static final String NAME_ATTR = "name"; private static final String PACKAGE_ATTR = "package"; private static final String CLASS_ATTR = "class"; private static final String TOTAL_TIME_ACTIVE_ATTR = "totalTimeActive"; private static final String LAST_TIME_ACTIVE_ATTR = "lastTimeActive"; + private static final String COUNT_ATTR = "count"; + private static final String ACTIVE_ATTR = "active"; private static final String LAST_EVENT_ATTR = "lastEvent"; - private static final String EVENT_LOG_TAG = "event-log"; private static final String TYPE_ATTR = "type"; private static final String TIME_ATTR = "time"; - private static UsageStats readNextUsageStats(XmlPullParser parser) + private static void loadUsageStats(XmlPullParser parser, IntervalStats statsOut) throws XmlPullParserException, IOException { - if (parser.getEventType() != XmlPullParser.START_TAG) { - XmlUtils.nextElement(parser); - } - - if (parser.getEventType() != XmlPullParser.START_TAG || - !parser.getName().equals(PACKAGE_TAG)) { - return null; - } - final String name = parser.getAttributeValue(null, NAME_ATTR); if (name == null) { throw new ProtocolException("no " + NAME_ATTR + " attribute present"); } - UsageStats stats = new UsageStats(); - stats.mPackageName = name; + UsageStats stats = statsOut.getOrCreateUsageStats(name); stats.mTotalTimeInForeground = XmlUtils.readLongAttribute(parser, TOTAL_TIME_ACTIVE_ATTR); stats.mLastTimeUsed = XmlUtils.readLongAttribute(parser, LAST_TIME_ACTIVE_ATTR); stats.mLastEvent = XmlUtils.readIntAttribute(parser, LAST_EVENT_ATTR); - XmlUtils.skipCurrentTag(parser); - return stats; } - private static UsageEvents.Event readNextEvent(XmlPullParser parser, IntervalStats statsOut) + private static void loadConfigStats(XmlPullParser parser, IntervalStats statsOut) throws XmlPullParserException, IOException { - if (parser.getEventType() != XmlPullParser.START_TAG) { - XmlUtils.nextElement(parser); - } - - if (parser.getEventType() != XmlPullParser.START_TAG || - !parser.getName().equals(EVENT_LOG_TAG)) { - return null; + final Configuration config = new Configuration(); + Configuration.readXmlAttrs(parser, config); + + ConfigurationStats configStats = statsOut.getOrCreateConfigurationStats(config); + configStats.mLastTimeActive = XmlUtils.readLongAttribute(parser, LAST_TIME_ACTIVE_ATTR); + configStats.mTotalTimeActive = XmlUtils.readLongAttribute(parser, TOTAL_TIME_ACTIVE_ATTR); + configStats.mActivationCount = XmlUtils.readIntAttribute(parser, COUNT_ATTR); + if (XmlUtils.readBooleanAttribute(parser, ACTIVE_ATTR)) { + statsOut.activeConfiguration = configStats.mConfiguration; } + } + private static void loadEvent(XmlPullParser parser, IntervalStats statsOut) + throws XmlPullParserException, IOException { String packageName = XmlUtils.readStringAttribute(parser, PACKAGE_ATTR); String className; if (packageName == null) { @@ -105,31 +106,60 @@ final class UsageStatsXmlV1 { UsageEvents.Event event = statsOut.buildEvent(packageName, className); event.mEventType = XmlUtils.readIntAttribute(parser, TYPE_ATTR); event.mTimeStamp = XmlUtils.readLongAttribute(parser, TIME_ATTR); - XmlUtils.skipCurrentTag(parser); - return event; + + if (event.mEventType == UsageEvents.Event.CONFIGURATION_CHANGE) { + event.mConfiguration = new Configuration(); + Configuration.readXmlAttrs(parser, event.mConfiguration); + } + + if (statsOut.events == null) { + statsOut.events = new TimeSparseArray<>(); + } + statsOut.events.put(event.mTimeStamp, event); } - private static void writeUsageStats(FastXmlSerializer serializer, UsageStats stats) + private static void writeUsageStats(XmlSerializer xml, final UsageStats stats) throws IOException { - serializer.startTag(null, PACKAGE_TAG); - serializer.attribute(null, NAME_ATTR, stats.mPackageName); - serializer.attribute(null, TOTAL_TIME_ACTIVE_ATTR, - Long.toString(stats.mTotalTimeInForeground)); - serializer.attribute(null, LAST_TIME_ACTIVE_ATTR, Long.toString(stats.mLastTimeUsed)); - serializer.attribute(null, LAST_EVENT_ATTR, Integer.toString(stats.mLastEvent)); - serializer.endTag(null, PACKAGE_TAG); + xml.startTag(null, PACKAGE_TAG); + XmlUtils.writeStringAttribute(xml, NAME_ATTR, stats.mPackageName); + XmlUtils.writeLongAttribute(xml, TOTAL_TIME_ACTIVE_ATTR, stats.mTotalTimeInForeground); + XmlUtils.writeLongAttribute(xml, LAST_TIME_ACTIVE_ATTR, stats.mLastTimeUsed); + XmlUtils.writeIntAttribute(xml, LAST_EVENT_ATTR, stats.mLastEvent); + xml.endTag(null, PACKAGE_TAG); + } + + private static void writeConfigStats(XmlSerializer xml, final ConfigurationStats stats, + boolean isActive) throws IOException { + xml.startTag(null, CONFIGURATION_TAG); + XmlUtils.writeLongAttribute(xml, LAST_TIME_ACTIVE_ATTR, stats.mLastTimeActive); + XmlUtils.writeLongAttribute(xml, TOTAL_TIME_ACTIVE_ATTR, stats.mTotalTimeActive); + XmlUtils.writeIntAttribute(xml, COUNT_ATTR, stats.mActivationCount); + if (isActive) { + XmlUtils.writeBooleanAttribute(xml, ACTIVE_ATTR, true); + } + + // Now write the attributes representing the configuration object. + Configuration.writeXmlAttrs(xml, stats.mConfiguration); + + xml.endTag(null, CONFIGURATION_TAG); } - private static void writeEvent(FastXmlSerializer serializer, UsageEvents.Event event) + private static void writeEvent(XmlSerializer xml, final UsageEvents.Event event) throws IOException { - serializer.startTag(null, EVENT_LOG_TAG); - serializer.attribute(null, PACKAGE_ATTR, event.mPackage); + xml.startTag(null, EVENT_LOG_TAG); + XmlUtils.writeStringAttribute(xml, PACKAGE_ATTR, event.mPackage); if (event.mClass != null) { - serializer.attribute(null, CLASS_ATTR, event.mClass); + XmlUtils.writeStringAttribute(xml, CLASS_ATTR, event.mClass); + } + XmlUtils.writeIntAttribute(xml, TYPE_ATTR, event.mEventType); + XmlUtils.writeLongAttribute(xml, TIME_ATTR, event.mTimeStamp); + + if (event.mEventType == UsageEvents.Event.CONFIGURATION_CHANGE + && event.mConfiguration != null) { + Configuration.writeXmlAttrs(xml, event.mConfiguration); } - serializer.attribute(null, TYPE_ATTR, Integer.toString(event.getEventType())); - serializer.attribute(null, TIME_ATTR, Long.toString(event.getTimeStamp())); - serializer.endTag(null, EVENT_LOG_TAG); + + xml.endTag(null, EVENT_LOG_TAG); } /** @@ -142,6 +172,8 @@ final class UsageStatsXmlV1 { public static void read(XmlPullParser parser, IntervalStats statsOut) throws XmlPullParserException, IOException { statsOut.stats.clear(); + statsOut.configurations.clear(); + statsOut.activeConfiguration = null; if (statsOut.events != null) { statsOut.events.clear(); @@ -149,21 +181,29 @@ final class UsageStatsXmlV1 { statsOut.beginTime = XmlUtils.readLongAttribute(parser, BEGIN_TIME_ATTR); statsOut.endTime = XmlUtils.readLongAttribute(parser, END_TIME_ATTR); - XmlUtils.nextElement(parser); - UsageStats pkgStats; - while ((pkgStats = readNextUsageStats(parser)) != null) { - pkgStats.mBeginTimeStamp = statsOut.beginTime; - pkgStats.mEndTimeStamp = statsOut.endTime; - statsOut.stats.put(pkgStats.mPackageName, pkgStats); - } + int eventCode; + int outerDepth = parser.getDepth(); + while ((eventCode = parser.next()) != XmlPullParser.END_DOCUMENT + && (eventCode != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { + if (eventCode != XmlPullParser.START_TAG) { + continue; + } + + final String tag = parser.getName(); + switch (tag) { + case PACKAGE_TAG: + loadUsageStats(parser, statsOut); + break; - UsageEvents.Event event; - while ((event = readNextEvent(parser, statsOut)) != null) { - if (statsOut.events == null) { - statsOut.events = new TimeSparseArray<>(); + case CONFIGURATION_TAG: + loadConfigStats(parser, statsOut); + break; + + case EVENT_LOG_TAG: + loadEvent(parser, statsOut); + break; } - statsOut.events.put(event.getTimeStamp(), event); } } @@ -184,11 +224,15 @@ final class UsageStatsXmlV1 { writeUsageStats(serializer, stats.stats.valueAt(i)); } - if (stats.events != null) { - final int eventCount = stats.events.size(); - for (int i = 0; i < eventCount; i++) { - writeEvent(serializer, stats.events.valueAt(i)); - } + final int configCount = stats.configurations.size(); + for (int i = 0; i < configCount; i++) { + boolean active = stats.activeConfiguration.equals(stats.configurations.keyAt(i)); + writeConfigStats(serializer, stats.configurations.valueAt(i), active); + } + + final int eventCount = stats.events != null ? stats.events.size() : 0; + for (int i = 0; i < eventCount; i++) { + writeEvent(serializer, stats.events.valueAt(i)); } } diff --git a/services/usage/java/com/android/server/usage/UserUsageStatsService.java b/services/usage/java/com/android/server/usage/UserUsageStatsService.java index 6951590f19da..7142a9999dda 100644 --- a/services/usage/java/com/android/server/usage/UserUsageStatsService.java +++ b/services/usage/java/com/android/server/usage/UserUsageStatsService.java @@ -16,13 +16,17 @@ package com.android.server.usage; +import android.app.usage.ConfigurationStats; import android.app.usage.TimeSparseArray; import android.app.usage.UsageEvents; import android.app.usage.UsageStats; import android.app.usage.UsageStatsManager; +import android.content.res.Configuration; import android.util.ArraySet; import android.util.Slog; +import com.android.server.usage.UsageStatsDatabase.StatCombiner; + import java.io.File; import java.io.IOException; import java.text.SimpleDateFormat; @@ -108,35 +112,91 @@ class UserUsageStatsService { notifyStatsChanged(); } } + + stat.updateConfigurationStats(null, stat.lastTimeSaved); } } void reportEvent(UsageEvents.Event event) { if (DEBUG) { Slog.d(TAG, mLogPrefix + "Got usage event for " + event.mPackage - + "[" + event.getTimeStamp() + "]: " - + eventToString(event.getEventType())); + + "[" + event.mTimeStamp + "]: " + + eventToString(event.mEventType)); } - if (event.getTimeStamp() >= mDailyExpiryDate.getTimeInMillis()) { + if (event.mTimeStamp >= mDailyExpiryDate.getTimeInMillis()) { // Need to rollover rolloverStats(); } - if (mCurrentStats[UsageStatsManager.INTERVAL_DAILY].events == null) { - mCurrentStats[UsageStatsManager.INTERVAL_DAILY].events = new TimeSparseArray<>(); + final IntervalStats currentDailyStats = mCurrentStats[UsageStatsManager.INTERVAL_DAILY]; + + final Configuration newFullConfig = event.mConfiguration; + if (event.mEventType == UsageEvents.Event.CONFIGURATION_CHANGE && + currentDailyStats.activeConfiguration != null) { + // Make the event configuration a delta. + event.mConfiguration = Configuration.generateDelta( + currentDailyStats.activeConfiguration, newFullConfig); + } + + // Add the event to the daily list. + if (currentDailyStats.events == null) { + currentDailyStats.events = new TimeSparseArray<>(); } - mCurrentStats[UsageStatsManager.INTERVAL_DAILY].events.put(event.getTimeStamp(), event); + currentDailyStats.events.put(event.mTimeStamp, event); for (IntervalStats stats : mCurrentStats) { - stats.update(event.mPackage, event.getTimeStamp(), - event.getEventType()); + if (event.mEventType == UsageEvents.Event.CONFIGURATION_CHANGE) { + stats.updateConfigurationStats(newFullConfig, event.mTimeStamp); + } else { + stats.update(event.mPackage, event.mTimeStamp, event.mEventType); + } } notifyStatsChanged(); } - List<UsageStats> queryUsageStats(int bucketType, long beginTime, long endTime) { + private static final StatCombiner<UsageStats> sUsageStatsCombiner = + new StatCombiner<UsageStats>() { + @Override + public void combine(IntervalStats stats, boolean mutable, + List<UsageStats> accResult) { + if (!mutable) { + accResult.addAll(stats.stats.values()); + return; + } + + final int statCount = stats.stats.size(); + for (int i = 0; i < statCount; i++) { + accResult.add(new UsageStats(stats.stats.valueAt(i))); + } + } + }; + + private static final StatCombiner<ConfigurationStats> sConfigStatsCombiner = + new StatCombiner<ConfigurationStats>() { + @Override + public void combine(IntervalStats stats, boolean mutable, + List<ConfigurationStats> accResult) { + if (!mutable) { + accResult.addAll(stats.configurations.values()); + return; + } + + final int configCount = stats.configurations.size(); + for (int i = 0; i < configCount; i++) { + accResult.add(new ConfigurationStats(stats.configurations.valueAt(i))); + } + } + }; + + /** + * Generic query method that selects the appropriate IntervalStats for the specified time range + * and bucket, then calls the {@link com.android.server.usage.UsageStatsDatabase.StatCombiner} + * provided to select the stats to use from the IntervalStats object. + */ + private <T> List<T> queryStats(int bucketType, long beginTime, long endTime, + StatCombiner<T> combiner) { if (bucketType == UsageStatsManager.INTERVAL_BEST) { bucketType = mDatabase.findBestFitBucket(beginTime, endTime); } @@ -161,11 +221,8 @@ class UserUsageStatsService { Slog.d(TAG, mLogPrefix + "Returning in-memory stats for bucket " + bucketType); } // Fast path for retrieving in-memory state. - ArrayList<UsageStats> results = new ArrayList<>(); - final int packageCount = mCurrentStats[bucketType].stats.size(); - for (int i = 0; i < packageCount; i++) { - results.add(new UsageStats(mCurrentStats[bucketType].stats.valueAt(i))); - } + ArrayList<T> results = new ArrayList<>(); + combiner.combine(mCurrentStats[bucketType], true, results); return results; } @@ -178,13 +235,21 @@ class UserUsageStatsService { + beginTime + " AND endTime < " + endTime); } - final List<UsageStats> results = mDatabase.queryUsageStats(bucketType, beginTime, endTime); + final List<T> results = mDatabase.queryUsageStats(bucketType, beginTime, endTime, combiner); if (DEBUG) { Slog.d(TAG, mLogPrefix + "Results: " + (results == null ? 0 : results.size())); } return results; } + List<UsageStats> queryUsageStats(int bucketType, long beginTime, long endTime) { + return queryStats(bucketType, beginTime, endTime, sUsageStatsCombiner); + } + + List<ConfigurationStats> queryConfigurationStats(int bucketType, long beginTime, long endTime) { + return queryStats(bucketType, beginTime, endTime, sConfigStatsCombiner); + } + UsageEvents queryEvents(long beginTime, long endTime) { if (endTime > mCurrentStats[UsageStatsManager.INTERVAL_DAILY].beginTime) { if (beginTime > mCurrentStats[UsageStatsManager.INTERVAL_DAILY].endTime) { @@ -245,6 +310,8 @@ class UserUsageStatsService { // Finish any ongoing events with an END_OF_DAY event. Make a note of which components // need a new CONTINUE_PREVIOUS_DAY entry. + final Configuration previousConfig = + mCurrentStats[UsageStatsManager.INTERVAL_DAILY].activeConfiguration; ArraySet<String> continuePreviousDay = new ArraySet<>(); for (IntervalStats stat : mCurrentStats) { final int pkgCount = stat.stats.size(); @@ -253,11 +320,13 @@ class UserUsageStatsService { if (pkgStats.mLastEvent == UsageEvents.Event.MOVE_TO_FOREGROUND || pkgStats.mLastEvent == UsageEvents.Event.CONTINUE_PREVIOUS_DAY) { continuePreviousDay.add(pkgStats.mPackageName); - stat.update(pkgStats.mPackageName, - mDailyExpiryDate.getTimeInMillis() - 1, UsageEvents.Event.END_OF_DAY); + stat.update(pkgStats.mPackageName, mDailyExpiryDate.getTimeInMillis() - 1, + UsageEvents.Event.END_OF_DAY); mStatsChanged = true; } } + + stat.updateConfigurationStats(null, mDailyExpiryDate.getTimeInMillis() - 1); } persistActiveStats(); @@ -267,9 +336,10 @@ class UserUsageStatsService { final int continueCount = continuePreviousDay.size(); for (int i = 0; i < continueCount; i++) { String name = continuePreviousDay.valueAt(i); + final long beginTime = mCurrentStats[UsageStatsManager.INTERVAL_DAILY].beginTime; for (IntervalStats stat : mCurrentStats) { - stat.update(name, mCurrentStats[UsageStatsManager.INTERVAL_DAILY].beginTime, - UsageEvents.Event.CONTINUE_PREVIOUS_DAY); + stat.update(name, beginTime, UsageEvents.Event.CONTINUE_PREVIOUS_DAY); + stat.updateConfigurationStats(previousConfig, beginTime); mStatsChanged = true; } } @@ -353,6 +423,8 @@ class UserUsageStatsService { return "END_OF_DAY"; case UsageEvents.Event.CONTINUE_PREVIOUS_DAY: return "CONTINUE_PREVIOUS_DAY"; + case UsageEvents.Event.CONFIGURATION_CHANGE: + return "CONFIGURATION_CHANGE"; default: return "UNKNOWN"; } diff --git a/telecomm/java/android/telecomm/Log.java b/telecomm/java/android/telecomm/Log.java index b8dfb11146f0..446ae7560600 100644 --- a/telecomm/java/android/telecomm/Log.java +++ b/telecomm/java/android/telecomm/Log.java @@ -31,7 +31,7 @@ final public class Log { // Generic tag for all Telecomm Framework logging private static final String TAG = "TelecommFramework"; - public static final boolean FORCE_LOGGING = true; /* STOP SHIP if true */ + public static final boolean FORCE_LOGGING = false; /* STOP SHIP if true */ public static final boolean DEBUG = isLoggable(android.util.Log.DEBUG); public static final boolean INFO = isLoggable(android.util.Log.INFO); public static final boolean VERBOSE = isLoggable(android.util.Log.VERBOSE); diff --git a/telecomm/java/android/telecomm/TelecommManager.java b/telecomm/java/android/telecomm/TelecommManager.java index 071b719fba1f..b8f6964a7eaf 100644 --- a/telecomm/java/android/telecomm/TelecommManager.java +++ b/telecomm/java/android/telecomm/TelecommManager.java @@ -62,6 +62,13 @@ public class TelecommManager { "android.telecomm.intent.action.SHOW_CALL_SETTINGS"; /** + * The {@link android.content.Intent} action used to show the settings page used to configure + * {@link PhoneAccount} preferences. + */ + public static final String ACTION_CHANGE_PHONE_ACCOUNTS = + "android.telecomm.intent.action.CHANGE_PHONE_ACCOUNTS"; + + /** * Optional extra for {@link android.content.Intent#ACTION_CALL} containing a boolean that * determines whether the speakerphone should be automatically turned on for an outgoing call. */ @@ -287,16 +294,38 @@ public class TelecommManager { } /** + * Return the {@link PhoneAccount} which is the user-chosen default for making outgoing phone + * calls. This {@code PhoneAccount} will always be a member of the list which is returned from + * calling {@link #getEnabledPhoneAccounts()} + * + * Apps must be prepared for this method to return {@code null}, indicating that there currently + * exists no user-chosen default {@code PhoneAccount}. + * + * @return The user outgoing phone account selected by the user. + * @hide + */ + public PhoneAccountHandle getUserSelectedOutgoingPhoneAccount() { + try { + if (isServiceConnected()) { + return getTelecommService().getUserSelectedOutgoingPhoneAccount(); + } + } catch (RemoteException e) { + Log.e(TAG, "Error calling ITelecommService#getUserSelectedOutgoingPhoneAccount", e); + } + return null; + } + + /** * Sets the default account for making outgoing phone calls. * @hide */ - public void setDefaultOutgoingPhoneAccount(PhoneAccountHandle accountHandle) { + public void setUserSelectedOutgoingPhoneAccount(PhoneAccountHandle accountHandle) { try { if (isServiceConnected()) { - getTelecommService().setDefaultOutgoingPhoneAccount(accountHandle); + getTelecommService().setUserSelectedOutgoingPhoneAccount(accountHandle); } } catch (RemoteException e) { - Log.e(TAG, "Error calling ITelecommService#setDefaultOutgoingPhoneAccount"); + Log.e(TAG, "Error calling ITelecommService#setUserSelectedOutgoingPhoneAccount"); } } @@ -368,6 +397,17 @@ public class TelecommManager { } /** + * Returns the current connection manager. Apps must be prepared for this method to return + * {@code null}, indicating that there currently exists no user-chosen default + * {@code PhoneAccount}. + * + * @return The phone account handle of the current connection manager. + */ + public PhoneAccountHandle getConnectionManager() { + return getSimCallManager(); + } + + /** * Returns a list of {@link PhoneAccountHandle}s which can be used to make and receive phone * calls which support the specified URI scheme. * <P> @@ -702,4 +742,4 @@ public class TelecommManager { } return isConnected; } -}
\ No newline at end of file +} diff --git a/telecomm/java/com/android/internal/telecomm/ITelecommService.aidl b/telecomm/java/com/android/internal/telecomm/ITelecommService.aidl index a6ab3ac03e2d..6ab78c40cb99 100644 --- a/telecomm/java/com/android/internal/telecomm/ITelecommService.aidl +++ b/telecomm/java/com/android/internal/telecomm/ITelecommService.aidl @@ -40,9 +40,14 @@ interface ITelecommService { PhoneAccountHandle getDefaultOutgoingPhoneAccount(in String uriScheme); /** - * @see TelecommServiceImpl#setDefaultOutgoingPhoneAccount + * @see TelecommServiceImpl#getUserSelectedOutgoingPhoneAccount */ - void setDefaultOutgoingPhoneAccount(in PhoneAccountHandle account); + PhoneAccountHandle getUserSelectedOutgoingPhoneAccount(); + + /** + * @see TelecommServiceImpl#setUserSelectedOutgoingPhoneAccount + */ + void setUserSelectedOutgoingPhoneAccount(in PhoneAccountHandle account); /** * @see TelecommServiceImpl#getOutgoingPhoneAccounts diff --git a/telephony/java/android/telephony/IccOpenLogicalChannelResponse.java b/telephony/java/android/telephony/IccOpenLogicalChannelResponse.java index dbe38eabbff6..4621f9175969 100644 --- a/telephony/java/android/telephony/IccOpenLogicalChannelResponse.java +++ b/telephony/java/android/telephony/IccOpenLogicalChannelResponse.java @@ -27,7 +27,7 @@ public class IccOpenLogicalChannelResponse implements Parcelable { /** * Indicates an invalid channel. */ - public static int INVALID_CHANNEL = -1; + public static final int INVALID_CHANNEL = -1; /** * Possible status values returned by open channel command. @@ -37,10 +37,10 @@ public class IccOpenLogicalChannelResponse implements Parcelable { * STATUS_NO_SUCH_ELEMENT: AID not found on UICC. * STATUS_UNKNOWN_ERROR: Unknown error in open channel command. */ - public static int STATUS_NO_ERROR = 1; - public static int STATUS_MISSING_RESOURCE = 2; - public static int STATUS_NO_SUCH_ELEMENT = 3; - public static int STATUS_UNKNOWN_ERROR = 4; + public static final int STATUS_NO_ERROR = 1; + public static final int STATUS_MISSING_RESOURCE = 2; + public static final int STATUS_NO_SUCH_ELEMENT = 3; + public static final int STATUS_UNKNOWN_ERROR = 4; private final int mChannel; private final int mStatus; diff --git a/telephony/java/android/telephony/PhoneNumberUtils.java b/telephony/java/android/telephony/PhoneNumberUtils.java index acb97a047bf2..8af5e98dd7fc 100644 --- a/telephony/java/android/telephony/PhoneNumberUtils.java +++ b/telephony/java/android/telephony/PhoneNumberUtils.java @@ -164,14 +164,6 @@ public class PhoneNumberUtils return uri.getSchemeSpecificPart(); } - // TODO: We don't check for SecurityException here (requires - // CALL_PRIVILEGED permission). - if (scheme.equals("voicemail")) { - long subId = intent.getLongExtra(SUBSCRIPTION_KEY, - SubscriptionManager.getDefaultVoiceSubId()); - return TelephonyManager.getDefault().getCompleteVoiceMailNumber(subId); - } - if (context == null) { return null; } diff --git a/telephony/java/android/telephony/SubInfoRecord.java b/telephony/java/android/telephony/SubInfoRecord.java index 55781fa5aacc..805f787c33c8 100644 --- a/telephony/java/android/telephony/SubInfoRecord.java +++ b/telephony/java/android/telephony/SubInfoRecord.java @@ -1,18 +1,18 @@ /* -* Copyright (C) 2011-2014 MediaTek Inc. -* -* 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. -*/ + * Copyright (C) 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. + */ package android.telephony; @@ -20,95 +20,148 @@ import android.os.Parcel; import android.os.Parcelable; /** - * A parcelable holder class of byte[] for ISms aidl implementation - * @hide + * A Parcelable class for Subscription Information. + * @hide - to be unhidden */ - public class SubInfoRecord implements Parcelable { - public long mSubId; - public String mIccId; - public int mSlotId; - public String mDisplayName; - public int mNameSource; - public int mColor; - public String mNumber; - public int mDisplayNumberFormat; - public int mDataRoaming; - public int[] mSimIconRes; + /** + * Subscription Identifier, this is a device unique number + * and not an index into an array + */ + public long subId; + /** The GID for a SIM that maybe associated with this subscription, empty if unknown */ + public String iccId; + /** + * The slot identifier for that currently contains the subscription + * and not necessarily unique and maybe INVALID_SLOT_ID if unknown + */ + public int slotId; + /** + * The string displayed to the user that identifies this subscription + */ + public String displayName; + /** + * The source of the name, NAME_SOURCE_UNDEFINED, NAME_SOURCE_DEFAULT_SOURCE, + * NAME_SOURCE_SIM_SOURCE or NAME_SOURCE_USER_INPUT. + */ + public int nameSource; + /** + * The color to be used for when displaying to the user + */ + public int color; + /** + * A number presented to the user identify this subscription + */ + public String number; + /** + * How to display the phone number, DISPLAY_NUMBER_NONE, DISPLAY_NUMBER_FIRST, + * DISPLAY_NUMBER_LAST + */ + public int displayNumberFormat; + /** + * Data roaming state, DATA_RAOMING_ENABLE, DATA_RAOMING_DISABLE + */ + public int dataRoaming; + /** + * SIM Icon resource identifiers. FIXME: Check with MTK what it really is + */ + public int[] simIconRes; + /** + * Mobile Country Code + */ + public int mcc; + /** + * Mobile Network Code + */ + public int mnc; public SubInfoRecord() { - this.mSubId = SubscriptionManager.INVALID_SUB_ID; - this.mIccId = ""; - this.mSlotId = SubscriptionManager.INVALID_SLOT_ID; - this.mDisplayName = ""; - this.mNameSource = 0; - this.mColor = 0; - this.mNumber = ""; - this.mDisplayNumberFormat = 0; - this.mDataRoaming = 0; - this.mSimIconRes = new int[2]; + this.subId = SubscriptionManager.INVALID_SUB_ID; + this.iccId = ""; + this.slotId = SubscriptionManager.INVALID_SLOT_ID; + this.displayName = ""; + this.nameSource = 0; + this.color = 0; + this.number = ""; + this.displayNumberFormat = 0; + this.dataRoaming = 0; + this.simIconRes = new int[2]; + this.mcc = 0; + this.mnc = 0; } - public SubInfoRecord(long subId, String iccId, int slotId, String displayName, - int nameSource, int mColor, String mNumber, int displayFormat, int roaming, int[] iconRes) { - this.mSubId = subId; - this.mIccId = iccId; - this.mSlotId = slotId; - this.mDisplayName = displayName; - this.mNameSource = nameSource; - this.mColor = mColor; - this.mNumber = mNumber; - this.mDisplayNumberFormat = displayFormat; - this.mDataRoaming = roaming; - this.mSimIconRes = iconRes; + public SubInfoRecord(long subId, String iccId, int slotId, String displayName, int nameSource, + int color, String number, int displayFormat, int roaming, int[] iconRes, + int mcc, int mnc) { + this.subId = subId; + this.iccId = iccId; + this.slotId = slotId; + this.displayName = displayName; + this.nameSource = nameSource; + this.color = color; + this.number = number; + this.displayNumberFormat = displayFormat; + this.dataRoaming = roaming; + this.simIconRes = iconRes; + this.mcc = mcc; + this.mnc = mnc; } public static final Parcelable.Creator<SubInfoRecord> CREATOR = new Parcelable.Creator<SubInfoRecord>() { + @Override public SubInfoRecord createFromParcel(Parcel source) { - long mSubId = source.readLong(); - String mIccId = source.readString(); - int mSlotId = source.readInt(); - String mDisplayName = source.readString(); - int mNameSource = source.readInt(); - int mColor = source.readInt(); - String mNumber = source.readString(); - int mDisplayNumberFormat = source.readInt(); - int mDataRoaming = source.readInt(); + long subId = source.readLong(); + String iccId = source.readString(); + int slotId = source.readInt(); + String displayName = source.readString(); + int nameSource = source.readInt(); + int color = source.readInt(); + String number = source.readString(); + int displayNumberFormat = source.readInt(); + int dataRoaming = source.readInt(); int[] iconRes = new int[2]; source.readIntArray(iconRes); + int mcc = source.readInt(); + int mnc = source.readInt(); - return new SubInfoRecord(mSubId, mIccId, mSlotId, mDisplayName, mNameSource, mColor, mNumber, - mDisplayNumberFormat, mDataRoaming, iconRes); + return new SubInfoRecord(subId, iccId, slotId, displayName, nameSource, color, number, + displayNumberFormat, dataRoaming, iconRes, mcc, mnc); } + @Override public SubInfoRecord[] newArray(int size) { return new SubInfoRecord[size]; } }; + @Override public void writeToParcel(Parcel dest, int flags) { - dest.writeLong(mSubId); - dest.writeString(mIccId); - dest.writeInt(mSlotId); - dest.writeString(mDisplayName); - dest.writeInt(mNameSource); - dest.writeInt(mColor); - dest.writeString(mNumber); - dest.writeInt(mDisplayNumberFormat); - dest.writeInt(mDataRoaming); - dest.writeIntArray(mSimIconRes); + dest.writeLong(subId); + dest.writeString(iccId); + dest.writeInt(slotId); + dest.writeString(displayName); + dest.writeInt(nameSource); + dest.writeInt(color); + dest.writeString(number); + dest.writeInt(displayNumberFormat); + dest.writeInt(dataRoaming); + dest.writeIntArray(simIconRes); + dest.writeInt(mcc); + dest.writeInt(mnc); } + @Override public int describeContents() { return 0; } + @Override public String toString() { - return "{mSubId=" + mSubId + ", mIccId=" + mIccId + " mSlotId=" + mSlotId - + " mDisplayName=" + mDisplayName + " mNameSource=" + mNameSource - + " mColor=" + mColor + " mNumber=" + mNumber - + " mDisplayNumberFormat=" + mDisplayNumberFormat + " mDataRoaming=" + mDataRoaming - + " mSimIconRes=" + mSimIconRes + "}"; + return "{mSubId=" + subId + ", mIccId=" + iccId + " mSlotId=" + slotId + + " mDisplayName=" + displayName + " mNameSource=" + nameSource + + " mColor=" + color + " mNumber=" + number + + " mDisplayNumberFormat=" + displayNumberFormat + " mDataRoaming=" + dataRoaming + + " mSimIconRes=" + simIconRes + " mMcc " + mcc + " mMnc " + mnc + "}"; } } diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java index 2bb24044a496..58d30f1561df 100644 --- a/telephony/java/android/telephony/SubscriptionManager.java +++ b/telephony/java/android/telephony/SubscriptionManager.java @@ -27,45 +27,49 @@ import android.os.RemoteException; import com.android.internal.telephony.ISub; import com.android.internal.telephony.PhoneConstants; + +import java.util.ArrayList; import java.util.List; /** * SubscriptionManager is the application interface to SubscriptionController * and provides information about the current Telephony Subscriptions. * - * @hide + * The android.Manifest.permission.READ_PHONE_STATE to retrieve the information, except + * getActiveSubIdList and getActiveSubIdCount for which no permission is needed. + * + * @hide - to be unhidden */ public class SubscriptionManager implements BaseColumns { private static final String LOG_TAG = "SUB"; private static final boolean DBG = true; private static final boolean VDBG = false; - // An invalid phone identifier - /** @hide */ + /** An invalid phone identifier */ + /** @hide - to be unhidden */ public static final int INVALID_PHONE_ID = -1000; - // Indicates the caller wants the default phone id. - /** @hide */ + /** Indicates the caller wants the default phone id. */ + /** @hide - to be unhidden */ public static final int DEFAULT_PHONE_ID = Integer.MAX_VALUE; - // An invalid slot identifier - /** @hide */ + /** An invalid slot identifier */ + /** @hide - to be unhidden */ public static final int INVALID_SLOT_ID = -1000; - // Indicates the caller wants the default slot id. + /** Indicates the caller wants the default slot id. */ /** @hide */ public static final int DEFAULT_SLOT_ID = Integer.MAX_VALUE; - // An invalid subscription identifier - /** @hide */ - public static final long INVALID_SUB_ID = -1000; - - // Indicates the user should be asked which sub to use. + /** Indicates the user should be asked which sub to use. */ /** @hide */ public static final long ASK_USER_SUB_ID = -1001; - // Indicates the caller wants the default sub id. - /** @hide */ + /** An invalid subscription identifier */ + public static final long INVALID_SUB_ID = -1000; + + /** Indicates the caller wants the default sub id. */ + /** @hide - to be unhidden */ public static final long DEFAULT_SUB_ID = Long.MAX_VALUE; /** @hide */ @@ -108,40 +112,58 @@ public class SubscriptionManager implements BaseColumns { */ /** @hide */ public static final String SIM_ID = "sim_id"; - /** @hide */ + + /** SIM is not inserted */ + /** @hide - to be unhidden */ public static final int SIM_NOT_INSERTED = -1; /** - * The display name of a SIM. + * TelephonyProvider column name for user displayed name. * <P>Type: TEXT (String)</P> */ /** @hide */ public static final String DISPLAY_NAME = "display_name"; - /** @hide */ + /** + * Default name resource + * @hide + */ public static final int DEFAULT_NAME_RES = com.android.internal.R.string.unknownName; /** - * The display name source of a SIM. - * <P>Type: INT (int)</P> + * TelephonyProvider column name for source of the user displayed name. + * <P>Type: INT (int)</P> with one of the NAME_SOURCE_XXXX values below + * + * @hide */ - /** @hide */ public static final String NAME_SOURCE = "name_source"; - /** @hide */ + /** + * The name_source is undefined + * @hide + */ public static final int NAME_SOURCE_UNDEFINDED = -1; - /** @hide */ + /** + * The name_source is the default + * @hide + */ public static final int NAME_SOURCE_DEFAULT_SOURCE = 0; - /** @hide */ + /** + * The name_source is from the SIM + * @hide + */ public static final int NAME_SOURCE_SIM_SOURCE = 1; - /** @hide */ + /** + * The name_source is from the user + * @hide + */ public static final int NAME_SOURCE_USER_INPUT = 2; /** - * The color of a SIM. + * TelephonyProvider column name for the color of a SIM. * <P>Type: INTEGER (int)</P> */ /** @hide */ @@ -163,14 +185,14 @@ public class SubscriptionManager implements BaseColumns { public static final int COLOR_DEFAULT = COLOR_1; /** - * The phone number of a SIM. + * TelephonyProvider column name for the phone number of a SIM. * <P>Type: TEXT (String)</P> */ /** @hide */ public static final String NUMBER = "number"; /** - * The number display format of a SIM. + * TelephonyProvider column name for the number display format of a SIM. * <P>Type: INTEGER (int)</P> */ /** @hide */ @@ -189,7 +211,7 @@ public class SubscriptionManager implements BaseColumns { public static final int DISLPAY_NUMBER_DEFAULT = DISPLAY_NUMBER_FIRST; /** - * Permission for data roaming of a SIM. + * TelephonyProvider column name for permission for data roaming of a SIM. * <P>Type: INTEGER (int)</P> */ /** @hide */ @@ -204,6 +226,19 @@ public class SubscriptionManager implements BaseColumns { /** @hide */ public static final int DATA_ROAMING_DEFAULT = DATA_ROAMING_DISABLE; + /** + * TelephonyProvider column name for the MCC associated with a SIM. + * <P>Type: INTEGER (int)</P> + */ + public static final String MCC = "mcc"; + + /** + * TelephonyProvider column name for the MNC associated with a SIM. + * <P>Type: INTEGER (int)</P> + */ + public static final String MNC = "mnc"; + + private static final int RES_TYPE_BACKGROUND_DARK = 0; private static final int RES_TYPE_BACKGROUND_LIGHT = 1; @@ -225,10 +260,10 @@ public class SubscriptionManager implements BaseColumns { } /** - * Get the SubInfoRecord according to an index + * Get the SubInfoRecord associated with the subId * @param subId The unique SubInfoRecord index in database * @return SubInfoRecord, maybe null - * @hide + * @hide - to be unhidden */ public static SubInfoRecord getSubInfoUsingSubId(long subId) { if (!isValidSubId(subId)) { @@ -254,7 +289,7 @@ public class SubscriptionManager implements BaseColumns { /** * Get the SubInfoRecord according to an IccId * @param iccId the IccId of SIM card - * @return SubInfoRecord, maybe null + * @return SubInfoRecord List, maybe empty but not null * @hide */ public static List<SubInfoRecord> getSubInfoUsingIccId(String iccId) { @@ -275,14 +310,18 @@ public class SubscriptionManager implements BaseColumns { // ignore it } + + if (result == null) { + result = new ArrayList<SubInfoRecord>(); + } return result; } /** * Get the SubInfoRecord according to slotId * @param slotId the slot which the SIM is inserted - * @return SubInfoRecord, maybe null - * @hide + * @return SubInfoRecord list, maybe empty but not null + * @hide - to be unhidden */ public static List<SubInfoRecord> getSubInfoUsingSlotId(int slotId) { // FIXME: Consider never returning null @@ -302,12 +341,17 @@ public class SubscriptionManager implements BaseColumns { // ignore it } + + if (result == null) { + result = new ArrayList<SubInfoRecord>(); + } return result; } /** - * Get all the SubInfoRecord(s) in subinfo database - * @return Array list of all SubInfoRecords in database, include thsoe that were inserted before + * Get all the SubInfoRecord(s) in subInfo database + * @return List of all SubInfoRecords in database, include those that were inserted before + * maybe empty but not null. * @hide */ public static List<SubInfoRecord> getAllSubInfoList() { @@ -324,13 +368,16 @@ public class SubscriptionManager implements BaseColumns { // ignore it } + if (result == null) { + result = new ArrayList<SubInfoRecord>(); + } return result; } /** * Get the SubInfoRecord(s) of the currently inserted SIM(s) - * @return Array list of currently inserted SubInfoRecord(s) - * @hide + * @return Array list of currently inserted SubInfoRecord(s) maybe empty but not null + * @hide - to be unhidden */ public static List<SubInfoRecord> getActiveSubInfoList() { List<SubInfoRecord> result = null; @@ -344,6 +391,9 @@ public class SubscriptionManager implements BaseColumns { // ignore it } + if (result == null) { + result = new ArrayList<SubInfoRecord>(); + } return result; } @@ -580,7 +630,12 @@ public class SubscriptionManager implements BaseColumns { return result; } - /** @hide */ + /** + * Get slotId associated with the subscription. + * @return slotId as a positive integer or a negative value if an error either + * SIM_NOT_INSERTED or INVALID_SLOT_ID. + * @hide - to be unhidden + */ public static int getSlotId(long subId) { if (!isValidSubId(subId)) { logd("[getSlotId]- fail"); @@ -736,7 +791,10 @@ public class SubscriptionManager implements BaseColumns { return getPhoneId(getDefaultVoiceSubId()); } - /** @hide */ + /** + * @return subId of the DefaultSms subscription or the value INVALID_SUB_ID if an error. + * @hide - to be unhidden + */ public static long getDefaultSmsSubId() { long subId = INVALID_SUB_ID; @@ -862,7 +920,10 @@ public class SubscriptionManager implements BaseColumns { } } - /** @hide */ + /** + * @return true if a valid subId else false + * @hide - to be unhidden + */ public static boolean isValidSubId(long subId) { return subId > INVALID_SUB_ID ; } diff --git a/telephony/java/com/android/internal/telephony/IMms.aidl b/telephony/java/com/android/internal/telephony/IMms.aidl index 63b7a537fb26..433701278de0 100644 --- a/telephony/java/com/android/internal/telephony/IMms.aidl +++ b/telephony/java/com/android/internal/telephony/IMms.aidl @@ -40,7 +40,7 @@ interface IMms { * broadcast when the message is successfully sent, or failed */ void sendMessage(long subId, String callingPkg, in Uri contentUri, - String locationUrl, in ContentValues configOverrides, in PendingIntent sentIntent); + String locationUrl, in Bundle configOverrides, in PendingIntent sentIntent); /** * Download an MMS message using known location and transaction id @@ -57,7 +57,7 @@ interface IMms { * broadcast when the message is downloaded, or the download is failed */ void downloadMessage(long subId, String callingPkg, String locationUrl, - in Uri contentUri, in ContentValues configOverrides, + in Uri contentUri, in Bundle configOverrides, in PendingIntent downloadedIntent); /** @@ -192,7 +192,7 @@ interface IMms { * broadcast when the message is successfully sent, or failed */ void sendStoredMessage(long subId, String callingPkg, in Uri messageUri, - in ContentValues configOverrides, in PendingIntent sentIntent); + in Bundle configOverrides, in PendingIntent sentIntent); /** * Turns on/off the flag to automatically write sent/received SMS/MMS messages into system diff --git a/test-runner/src/android/test/ProviderTestCase.java b/test-runner/src/android/test/ProviderTestCase.java index 1b323cf2dd38..4108f34fa0d4 100644 --- a/test-runner/src/android/test/ProviderTestCase.java +++ b/test-runner/src/android/test/ProviderTestCase.java @@ -67,9 +67,8 @@ public abstract class ProviderTestCase<T extends ContentProvider> filenamePrefix); mProviderContext = new IsolatedContext(mResolver, targetContextWrapper); - mProvider = mProviderClass.newInstance(); - mProvider.attachInfoForTesting(mProviderContext, null); - assertNotNull(mProvider); + mProvider = ProviderTestCase2.createProviderForTest( + mProviderContext, mProviderClass, mProviderAuthority); mResolver.addProvider(mProviderAuthority, getProvider()); } @@ -107,8 +106,7 @@ public abstract class ProviderTestCase<T extends ContentProvider> resolver, targetContextWrapper); DatabaseUtils.createDbFromSqlStatements(context, databaseName, databaseVersion, sql); - T provider = providerClass.newInstance(); - provider.attachInfoForTesting(context, null); + T provider = ProviderTestCase2.createProviderForTest(context, providerClass, authority); resolver.addProvider(authority, provider); return resolver; diff --git a/test-runner/src/android/test/ProviderTestCase2.java b/test-runner/src/android/test/ProviderTestCase2.java index dcd089dab90f..1fa633e26961 100644 --- a/test-runner/src/android/test/ProviderTestCase2.java +++ b/test-runner/src/android/test/ProviderTestCase2.java @@ -19,6 +19,7 @@ package android.test; import android.content.ContentProvider; import android.content.ContentResolver; import android.content.Context; +import android.content.pm.ProviderInfo; import android.content.res.Resources; import android.test.mock.MockContext; import android.test.mock.MockContentResolver; @@ -138,14 +139,24 @@ public abstract class ProviderTestCase2<T extends ContentProvider> extends Andro getContext(), // The context that file methods are delegated to filenamePrefix); mProviderContext = new IsolatedContext(mResolver, targetContextWrapper); - - mProvider = mProviderClass.newInstance(); - mProvider.attachInfoForTesting(mProviderContext, null); - assertNotNull(mProvider); + mProvider = createProviderForTest(mProviderContext, mProviderClass, mProviderAuthority); mResolver.addProvider(mProviderAuthority, getProvider()); } /** + * Creates and sets up a new instance of the provider. + */ + static <T extends ContentProvider> T createProviderForTest( + Context context, Class<T> providerClass, String authority) + throws IllegalAccessException, InstantiationException { + T instance = providerClass.newInstance(); + ProviderInfo providerInfo = new ProviderInfo(); + providerInfo.authority = authority; + instance.attachInfoForTesting(context, providerInfo); + return instance; + } + + /** * Tears down the environment for the test fixture. * <p> * Calls {@link android.content.ContentProvider#shutdown()} on the @@ -218,8 +229,7 @@ public abstract class ProviderTestCase2<T extends ContentProvider> extends Andro Context context = new IsolatedContext(resolver, targetContextWrapper); DatabaseUtils.createDbFromSqlStatements(context, databaseName, databaseVersion, sql); - T provider = providerClass.newInstance(); - provider.attachInfoForTesting(context, null); + T provider = createProviderForTest(context, providerClass, authority); resolver.addProvider(authority, provider); return resolver; diff --git a/test-runner/src/android/test/mock/MockPackageManager.java b/test-runner/src/android/test/mock/MockPackageManager.java index cd7d178f569c..5a4e0eb79668 100644 --- a/test-runner/src/android/test/mock/MockPackageManager.java +++ b/test-runner/src/android/test/mock/MockPackageManager.java @@ -46,7 +46,7 @@ import android.content.pm.VerificationParams; import android.content.pm.VerifierDeviceIdentity; import android.content.res.Resources; import android.content.res.XmlResourceParser; -import android.graphics.Bitmap; +import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.UserHandle; @@ -403,6 +403,29 @@ public class MockPackageManager extends PackageManager { } @Override + public Drawable getUserBadgedIcon(Drawable icon, UserHandle user) { + throw new UnsupportedOperationException(); + } + + @Override + public Drawable getUserBadgedDrawableForDensity(Drawable drawable, UserHandle user, + Rect badgeLocation, + int badgeDensity) { + throw new UnsupportedOperationException(); + } + + /** @hide */ + @Override + public Drawable getUserBadgeForDensity(UserHandle user, int density) { + throw new UnsupportedOperationException(); + } + + @Override + public CharSequence getUserBadgedLabel(CharSequence label, UserHandle user) { + throw new UnsupportedOperationException(); + } + + @Override public CharSequence getText(String packageName, int resid, ApplicationInfo appInfo) { throw new UnsupportedOperationException(); } diff --git a/tests/UsageStatsTest/Android.mk b/tests/UsageStatsTest/Android.mk index 69fefeb5bddf..5f7467a301d2 100644 --- a/tests/UsageStatsTest/Android.mk +++ b/tests/UsageStatsTest/Android.mk @@ -6,6 +6,8 @@ LOCAL_MODULE_TAGS := tests # Only compile source java files in this apk. LOCAL_SRC_FILES := $(call all-java-files-under, src) +LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4 + LOCAL_PACKAGE_NAME := UsageStatsTest include $(BUILD_PACKAGE) diff --git a/tests/UsageStatsTest/res/layout/config_row_item.xml b/tests/UsageStatsTest/res/layout/config_row_item.xml new file mode 100644 index 000000000000..547de04ad728 --- /dev/null +++ b/tests/UsageStatsTest/res/layout/config_row_item.xml @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="utf-8"?> +<TextView xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@android:id/text1" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:paddingLeft="16dp" + android:paddingRight="16dp"/> diff --git a/tests/UsageStatsTest/res/layout/row_item.xml b/tests/UsageStatsTest/res/layout/row_item.xml index da50163c94ab..4f2bfe4222fb 100644 --- a/tests/UsageStatsTest/res/layout/row_item.xml +++ b/tests/UsageStatsTest/res/layout/row_item.xml @@ -1,5 +1,6 @@ <?xml version="1.0" encoding="utf-8"?> -<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingLeft="16dp" @@ -8,13 +9,10 @@ <TextView android:id="@android:id/text1" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_alignParentLeft="true" - android:layout_centerVertical="true" + android:layout_weight="1" android:textStyle="bold"/> <TextView android:id="@android:id/text2" android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_alignParentRight="true" - android:layout_alignBaseline="@android:id/text1"/> -</RelativeLayout> + android:layout_height="wrap_content"/> +</LinearLayout> diff --git a/tests/UsageStatsTest/src/com/android/tests/usagestats/UsageLogActivity.java b/tests/UsageStatsTest/src/com/android/tests/usagestats/UsageLogActivity.java index 5f62ad8032e7..31e7c38d3a03 100644 --- a/tests/UsageStatsTest/src/com/android/tests/usagestats/UsageLogActivity.java +++ b/tests/UsageStatsTest/src/com/android/tests/usagestats/UsageLogActivity.java @@ -21,6 +21,7 @@ import android.app.usage.UsageStatsManager; import android.content.Context; import android.os.Bundle; import android.os.Handler; +import android.support.v4.util.CircularArray; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -35,11 +36,14 @@ public class UsageLogActivity extends ListActivity implements Runnable { private UsageStatsManager mUsageStatsManager; private Adapter mAdapter; private Handler mHandler = new Handler(); + private long mLastTime; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mUsageStatsManager = (UsageStatsManager) getSystemService(Context.USAGE_STATS_SERVICE); + mLastTime = System.currentTimeMillis() - USAGE_STATS_PERIOD; + mAdapter = new Adapter(); setListAdapter(mAdapter); } @@ -59,24 +63,31 @@ public class UsageLogActivity extends ListActivity implements Runnable { @Override public void run() { long now = System.currentTimeMillis(); - long beginTime = now - USAGE_STATS_PERIOD; - UsageEvents events = mUsageStatsManager.queryEvents(beginTime, now); - mAdapter.update(events); + UsageEvents events = mUsageStatsManager.queryEvents(mLastTime, now); + long lastEventTime = mAdapter.update(events); + if (lastEventTime >= 0) { + mLastTime = lastEventTime + 1; + } mHandler.postDelayed(this, 1000 * 5); } private class Adapter extends BaseAdapter { + private static final int MAX_EVENTS = 50; + private final CircularArray<UsageEvents.Event> mEvents = new CircularArray<>(MAX_EVENTS); - private final ArrayList<UsageEvents.Event> mEvents = new ArrayList<>(); - - public void update(UsageEvents results) { - mEvents.clear(); + public long update(UsageEvents results) { + long lastTimeStamp = -1; while (results.hasNextEvent()) { UsageEvents.Event event = new UsageEvents.Event(); results.getNextEvent(event); - mEvents.add(event); + lastTimeStamp = event.getTimeStamp(); + if (mEvents.size() == MAX_EVENTS) { + mEvents.popLast(); + } + mEvents.addFirst(event); } notifyDataSetChanged(); + return lastTimeStamp; } @Override @@ -85,7 +96,7 @@ public class UsageLogActivity extends ListActivity implements Runnable { } @Override - public Object getItem(int position) { + public UsageEvents.Event getItem(int position) { return mEvents.get(position); } @@ -95,41 +106,72 @@ public class UsageLogActivity extends ListActivity implements Runnable { } @Override + public int getItemViewType(int position) { + final int eventType = getItem(position).getEventType(); + if (eventType == UsageEvents.Event.CONFIGURATION_CHANGE) { + return 1; + } + return 0; + } + + @Override public View getView(int position, View convertView, ViewGroup parent) { + final UsageEvents.Event event = getItem(position); + final ViewHolder holder; if (convertView == null) { - convertView = LayoutInflater.from(UsageLogActivity.this) - .inflate(R.layout.row_item, parent, false); holder = new ViewHolder(); - holder.packageName = (TextView) convertView.findViewById(android.R.id.text1); - holder.state = (TextView) convertView.findViewById(android.R.id.text2); + + if (event.getEventType() == UsageEvents.Event.CONFIGURATION_CHANGE) { + convertView = LayoutInflater.from(UsageLogActivity.this) + .inflate(R.layout.config_row_item, parent, false); + holder.config = (TextView) convertView.findViewById(android.R.id.text1); + } else { + convertView = LayoutInflater.from(UsageLogActivity.this) + .inflate(R.layout.row_item, parent, false); + holder.packageName = (TextView) convertView.findViewById(android.R.id.text1); + holder.state = (TextView) convertView.findViewById(android.R.id.text2); + } convertView.setTag(holder); } else { holder = (ViewHolder) convertView.getTag(); } - holder.packageName.setText(mEvents.get(position).getPackageName()); - String state; - switch (mEvents.get(position).getEventType()) { + if (holder.packageName != null) { + holder.packageName.setText(event.getPackageName()); + } + + if (holder.state != null) { + holder.state.setText(eventToString(event.getEventType())); + } + + if (holder.config != null && + event.getEventType() == UsageEvents.Event.CONFIGURATION_CHANGE) { + holder.config.setText(event.getConfiguration().toString()); + } + return convertView; + } + + private String eventToString(int eventType) { + switch (eventType) { case UsageEvents.Event.MOVE_TO_FOREGROUND: - state = "Foreground"; - break; + return "Foreground"; case UsageEvents.Event.MOVE_TO_BACKGROUND: - state = "Background"; - break; + return "Background"; + + case UsageEvents.Event.CONFIGURATION_CHANGE: + return "Config change"; default: - state = "Unknown: " + mEvents.get(position).getEventType(); - break; + return "Unknown: " + eventType; } - holder.state.setText(state); - return convertView; } } static class ViewHolder { public TextView packageName; public TextView state; + public TextView config; } } diff --git a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionService.java b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionService.java index 1f014615dc66..46391149b262 100644 --- a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionService.java +++ b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionService.java @@ -92,7 +92,7 @@ public class MainInteractionService extends VoiceInteractionService { break; case AlwaysOnHotwordDetector.STATE_KEYPHRASE_UNENROLLED: Log.i(TAG, "STATE_KEYPHRASE_UNENROLLED"); - Intent enroll = mHotwordDetector.createIntentToEnroll(); + Intent enroll = mHotwordDetector.createEnrollIntent(); Log.i(TAG, "Need to enroll with " + enroll); break; case AlwaysOnHotwordDetector.STATE_KEYPHRASE_ENROLLED: diff --git a/tools/apilint/apilint.py b/tools/apilint/apilint.py index 6bb28e15fea7..393d2ec5d012 100644 --- a/tools/apilint/apilint.py +++ b/tools/apilint/apilint.py @@ -20,15 +20,20 @@ a previous API level, if provided. Usage: apilint.py current.txt Usage: apilint.py current.txt previous.txt + +You can also splice in blame details like this: +$ git blame api/current.txt -t -e > /tmp/currentblame.txt +$ apilint.py /tmp/currentblame.txt previous.txt --no-color """ -import re, sys, collections +import re, sys, collections, traceback BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE = range(8) def format(fg=None, bg=None, bright=False, bold=False, dim=False, reset=False): # manually derived from http://en.wikipedia.org/wiki/ANSI_escape_code#Codes + if "--no-color" in sys.argv: return "" codes = [] if reset: codes.append("0") else: @@ -43,9 +48,10 @@ def format(fg=None, bg=None, bright=False, bold=False, dim=False, reset=False): class Field(): - def __init__(self, clazz, raw): + def __init__(self, clazz, raw, blame): self.clazz = clazz self.raw = raw.strip(" {;") + self.blame = blame raw = raw.split() self.split = list(raw) @@ -60,14 +66,20 @@ class Field(): else: self.value = None + self.ident = self.raw.replace(" deprecated ", " ") + def __repr__(self): return self.raw class Method(): - def __init__(self, clazz, raw): + def __init__(self, clazz, raw, blame): self.clazz = clazz self.raw = raw.strip(" {;") + self.blame = blame + + # drop generics for now + raw = re.sub("<.+?>", "", raw) raw = re.split("[\s(),;]+", raw) for r in ["", ";"]: @@ -84,14 +96,24 @@ class Method(): if r == "throws": break self.args.append(r) + # identity for compat purposes + ident = self.raw + ident = ident.replace(" deprecated ", " ") + ident = ident.replace(" synchronized ", " ") + ident = re.sub("<.+?>", "", ident) + if " throws " in ident: + ident = ident[:ident.index(" throws ")] + self.ident = ident + def __repr__(self): return self.raw class Class(): - def __init__(self, pkg, raw): + def __init__(self, pkg, raw, blame): self.pkg = pkg self.raw = raw.strip(" {;") + self.blame = blame self.ctors = [] self.fields = [] self.methods = [] @@ -102,19 +124,25 @@ class Class(): self.fullname = raw[raw.index("class")+1] elif "interface" in raw: self.fullname = raw[raw.index("interface")+1] + else: + raise ValueError("Funky class type %s" % (self.raw)) - if "." in self.fullname: - self.name = self.fullname[self.fullname.rindex(".")+1:] + if "extends" in raw: + self.extends = raw[raw.index("extends")+1] else: - self.name = self.fullname + self.extends = None + + self.fullname = self.pkg.name + "." + self.fullname + self.name = self.fullname[self.fullname.rindex(".")+1:] def __repr__(self): return self.raw class Package(): - def __init__(self, raw): + def __init__(self, raw, blame): self.raw = raw.strip(" {;") + self.blame = blame raw = raw.split() self.name = raw[raw.index("package")+1] @@ -124,55 +152,68 @@ class Package(): def parse_api(fn): - api = [] + api = {} pkg = None clazz = None + blame = None + + re_blame = re.compile("^([a-z0-9]{7,}) \(<([^>]+)>.+?\) (.+?)$") with open(fn) as f: for raw in f.readlines(): raw = raw.rstrip() + match = re_blame.match(raw) + if match is not None: + blame = match.groups()[0:2] + raw = match.groups()[2] + else: + blame = None if raw.startswith("package"): - pkg = Package(raw) + pkg = Package(raw, blame) elif raw.startswith(" ") and raw.endswith("{"): - clazz = Class(pkg, raw) - api.append(clazz) + clazz = Class(pkg, raw, blame) + api[clazz.fullname] = clazz elif raw.startswith(" ctor"): - clazz.ctors.append(Method(clazz, raw)) + clazz.ctors.append(Method(clazz, raw, blame)) elif raw.startswith(" method"): - clazz.methods.append(Method(clazz, raw)) + clazz.methods.append(Method(clazz, raw, blame)) elif raw.startswith(" field"): - clazz.fields.append(Field(clazz, raw)) + clazz.fields.append(Field(clazz, raw, blame)) return api -failures = [] - -def filter_dupe(s): - return s.replace(" deprecated ", " ") +failures = {} def _fail(clazz, detail, msg): """Records an API failure to be processed later.""" global failures + sig = "%s-%s-%s" % (clazz.fullname, repr(detail), msg) + sig = sig.replace(" deprecated ", " ") + res = msg + blame = clazz.blame if detail is not None: res += "\n in " + repr(detail) + blame = detail.blame res += "\n in " + repr(clazz) res += "\n in " + repr(clazz.pkg) - failures.append(filter_dupe(res)) + if blame is not None: + res += "\n last modified by %s in %s" % (blame[1], blame[0]) + failures[sig] = res def warn(clazz, detail, msg): - _fail(clazz, detail, "%sWarning:%s %s" % (format(fg=YELLOW, bg=BLACK), format(reset=True), msg)) + _fail(clazz, detail, "%sWarning:%s %s" % (format(fg=YELLOW, bg=BLACK, bold=True), format(reset=True), msg)) def error(clazz, detail, msg): - _fail(clazz, detail, "%sError:%s %s" % (format(fg=RED, bg=BLACK), format(reset=True), msg)) + _fail(clazz, detail, "%sError:%s %s" % (format(fg=RED, bg=BLACK, bold=True), format(reset=True), msg)) def verify_constants(clazz): """All static final constants must be FOO_NAME style.""" - if re.match("R\.[a-z]+", clazz.fullname): return + if re.match("android\.R\.[a-z]+", clazz.fullname): return for f in clazz.fields: if "static" in f.split and "final" in f.split: @@ -188,6 +229,10 @@ def verify_enums(clazz): def verify_class_names(clazz): """Try catching malformed class names like myMtp or MTPUser.""" + if clazz.fullname.startswith("android.opengl"): return + if clazz.fullname.startswith("android.renderscript"): return + if re.match("android\.R\.[a-z]+", clazz.fullname): return + if re.search("[A-Z]{2,}", clazz.name) is not None: warn(clazz, None, "Class name style should be Mtp not MTP") if re.match("[^A-Z]", clazz.name): @@ -196,32 +241,35 @@ def verify_class_names(clazz): def verify_method_names(clazz): """Try catching malformed method names, like Foo() or getMTU().""" - if clazz.pkg.name == "android.opengl": return + if clazz.fullname.startswith("android.opengl"): return + if clazz.fullname.startswith("android.renderscript"): return + if clazz.fullname == "android.system.OsConstants": return for m in clazz.methods: if re.search("[A-Z]{2,}", m.name) is not None: warn(clazz, m, "Method name style should be getMtu() instead of getMTU()") if re.match("[^a-z]", m.name): - error(clazz, None, "Method name must start with lowercase char") + error(clazz, m, "Method name must start with lowercase char") def verify_callbacks(clazz): """Verify Callback classes. All callback classes must be abstract. All methods must follow onFoo() naming style.""" + if clazz.fullname == "android.speech.tts.SynthesisCallback": return if clazz.name.endswith("Callbacks"): - error(clazz, None, "Class must be named exactly Callback") + error(clazz, None, "Class name must not be plural") if clazz.name.endswith("Observer"): - warn(clazz, None, "Class should be named Callback") + warn(clazz, None, "Class should be named FooCallback") if clazz.name.endswith("Callback"): if "interface" in clazz.split: - error(clazz, None, "Callback must be abstract class") + error(clazz, None, "Callback must be abstract class to enable extension in future API levels") for m in clazz.methods: if not re.match("on[A-Z][a-z]*", m.name): - error(clazz, m, "Callback method names must be onFoo style") + error(clazz, m, "Callback method names must be onFoo() style") def verify_listeners(clazz): @@ -233,16 +281,16 @@ def verify_listeners(clazz): if clazz.name.endswith("Listener"): if " abstract class " in clazz.raw: - error(clazz, None, "Listener should be interface") + error(clazz, None, "Listener should be an interface, otherwise renamed Callback") for m in clazz.methods: if not re.match("on[A-Z][a-z]*", m.name): - error(clazz, m, "Listener method names must be onFoo style") + error(clazz, m, "Listener method names must be onFoo() style") if len(clazz.methods) == 1 and clazz.name.startswith("On"): m = clazz.methods[0] if (m.name + "Listener").lower() != clazz.name.lower(): - error(clazz, m, "Single method name should match class name") + error(clazz, m, "Single listener method name should match class name") def verify_actions(clazz): @@ -255,21 +303,24 @@ def verify_actions(clazz): for f in clazz.fields: if f.value is None: continue if f.name.startswith("EXTRA_"): continue + if f.name == "SERVICE_INTERFACE" or f.name == "PROVIDER_INTERFACE": continue if "static" in f.split and "final" in f.split and f.typ == "java.lang.String": if "_ACTION" in f.name or "ACTION_" in f.name or ".action." in f.value.lower(): if not f.name.startswith("ACTION_"): - error(clazz, f, "Intent action must be ACTION_FOO") + error(clazz, f, "Intent action constant name must be ACTION_FOO") else: - if clazz.name == "Intent": + if clazz.fullname == "android.content.Intent": prefix = "android.intent.action" - elif clazz.name == "Settings": + elif clazz.fullname == "android.provider.Settings": prefix = "android.settings" + elif clazz.fullname == "android.app.admin.DevicePolicyManager" or clazz.fullname == "android.app.admin.DeviceAdminReceiver": + prefix = "android.app.action" else: prefix = clazz.pkg.name + ".action" expected = prefix + "." + f.name[7:] if f.value != expected: - error(clazz, f, "Inconsistent action value") + error(clazz, f, "Inconsistent action value; expected %s" % (expected)) def verify_extras(clazz): @@ -279,6 +330,9 @@ def verify_extras(clazz): package android.foo { String EXTRA_BAR = "android.foo.extra.BAR"; }""" + if clazz.fullname == "android.app.Notification": return + if clazz.fullname == "android.appwidget.AppWidgetManager": return + for f in clazz.fields: if f.value is None: continue if f.name.startswith("ACTION_"): continue @@ -288,13 +342,15 @@ def verify_extras(clazz): if not f.name.startswith("EXTRA_"): error(clazz, f, "Intent extra must be EXTRA_FOO") else: - if clazz.name == "Intent": + if clazz.pkg.name == "android.content" and clazz.name == "Intent": prefix = "android.intent.extra" + elif clazz.pkg.name == "android.app.admin": + prefix = "android.app.extra" else: prefix = clazz.pkg.name + ".extra" expected = prefix + "." + f.name[6:] if f.value != expected: - error(clazz, f, "Inconsistent extra value") + error(clazz, f, "Inconsistent extra value; expected %s" % (expected)) def verify_equals(clazz): @@ -303,7 +359,7 @@ def verify_equals(clazz): eq = "equals" in methods hc = "hashCode" in methods if eq != hc: - error(clazz, None, "Must override both equals and hashCode") + error(clazz, None, "Must override both equals and hashCode; missing one") def verify_parcelable(clazz): @@ -314,34 +370,59 @@ def verify_parcelable(clazz): describe = [ i for i in clazz.methods if i.name == "describeContents" ] if len(creator) == 0 or len(write) == 0 or len(describe) == 0: - error(clazz, None, "Parcelable requires CREATOR, writeToParcel, and describeContents") + error(clazz, None, "Parcelable requires CREATOR, writeToParcel, and describeContents; missing one") def verify_protected(clazz): """Verify that no protected methods are allowed.""" for m in clazz.methods: if "protected" in m.split: - error(clazz, m, "Protected method") + error(clazz, m, "No protected methods; must be public") for f in clazz.fields: if "protected" in f.split: - error(clazz, f, "Protected field") + error(clazz, f, "No protected fields; must be public") def verify_fields(clazz): """Verify that all exposed fields are final. Exposed fields must follow myName style. Catch internal mFoo objects being exposed.""" + + IGNORE_BARE_FIELDS = [ + "android.app.ActivityManager.RecentTaskInfo", + "android.app.Notification", + "android.content.pm.ActivityInfo", + "android.content.pm.ApplicationInfo", + "android.content.pm.FeatureGroupInfo", + "android.content.pm.InstrumentationInfo", + "android.content.pm.PackageInfo", + "android.content.pm.PackageItemInfo", + "android.os.Message", + "android.system.StructPollfd", + ] + for f in clazz.fields: if not "final" in f.split: - error(clazz, f, "Bare fields must be final; consider adding accessors") + if clazz.fullname in IGNORE_BARE_FIELDS: + pass + elif clazz.fullname.endswith("LayoutParams"): + pass + elif clazz.fullname.startswith("android.util.Mutable"): + pass + else: + error(clazz, f, "Bare fields must be marked final; consider adding accessors") if not "static" in f.split: if not re.match("[a-z]([a-zA-Z]+)?", f.name): - error(clazz, f, "Non-static fields must be myName") + error(clazz, f, "Non-static fields must be named with myField style") - if re.match("[m][A-Z]", f.name): + if re.match("[ms][A-Z]", f.name): error(clazz, f, "Don't expose your internal objects") + if re.match("[A-Z_]+", f.name): + if "static" not in f.split or "final" not in f.split: + error(clazz, f, "Constants must be marked static final") + def verify_register(clazz): """Verify parity of registration methods. @@ -353,34 +434,34 @@ def verify_register(clazz): if m.name.startswith("register"): other = "unregister" + m.name[8:] if other not in methods: - error(clazz, m, "Missing unregister") + error(clazz, m, "Missing unregister method") if m.name.startswith("unregister"): other = "register" + m.name[10:] if other not in methods: - error(clazz, m, "Missing register") + error(clazz, m, "Missing register method") if m.name.startswith("add") or m.name.startswith("remove"): - error(clazz, m, "Callback should be register/unregister") + error(clazz, m, "Callback methods should be named register/unregister") if "Listener" in m.raw: if m.name.startswith("add"): other = "remove" + m.name[3:] if other not in methods: - error(clazz, m, "Missing remove") + error(clazz, m, "Missing remove method") if m.name.startswith("remove") and not m.name.startswith("removeAll"): other = "add" + m.name[6:] if other not in methods: - error(clazz, m, "Missing add") + error(clazz, m, "Missing add method") if m.name.startswith("register") or m.name.startswith("unregister"): - error(clazz, m, "Listener should be add/remove") + error(clazz, m, "Listener methods should be named add/remove") def verify_sync(clazz): """Verify synchronized methods aren't exposed.""" for m in clazz.methods: if "synchronized" in m.split: - error(clazz, m, "Lock exposed") + error(clazz, m, "Internal lock exposed") def verify_intent_builder(clazz): @@ -392,7 +473,7 @@ def verify_intent_builder(clazz): if m.name.startswith("create") and m.name.endswith("Intent"): pass else: - warn(clazz, m, "Should be createFooIntent()") + error(clazz, m, "Methods creating an Intent should be named createFooIntent()") def verify_helper_classes(clazz): @@ -402,25 +483,57 @@ def verify_helper_classes(clazz): if "extends android.app.Service" in clazz.raw: test_methods = True if not clazz.name.endswith("Service"): - error(clazz, None, "Inconsistent class name") + error(clazz, None, "Inconsistent class name; should be FooService") + + found = False + for f in clazz.fields: + if f.name == "SERVICE_INTERFACE": + found = True + if f.value != clazz.fullname: + error(clazz, f, "Inconsistent interface constant; expected %s" % (clazz.fullname)) + + if not found: + warn(clazz, None, "Missing SERVICE_INTERFACE constant") + + if "abstract" in clazz.split and not clazz.fullname.startswith("android.service."): + warn(clazz, None, "Services extended by developers should be under android.service") + if "extends android.content.ContentProvider" in clazz.raw: test_methods = True if not clazz.name.endswith("Provider"): - error(clazz, None, "Inconsistent class name") + error(clazz, None, "Inconsistent class name; should be FooProvider") + + found = False + for f in clazz.fields: + if f.name == "PROVIDER_INTERFACE": + found = True + if f.value != clazz.fullname: + error(clazz, f, "Inconsistent interface name; expected %s" % (clazz.fullname)) + + if not found: + warn(clazz, None, "Missing PROVIDER_INTERFACE constant") + + if "abstract" in clazz.split and not clazz.fullname.startswith("android.provider."): + warn(clazz, None, "Providers extended by developers should be under android.provider") + if "extends android.content.BroadcastReceiver" in clazz.raw: test_methods = True if not clazz.name.endswith("Receiver"): - error(clazz, None, "Inconsistent class name") + error(clazz, None, "Inconsistent class name; should be FooReceiver") + if "extends android.app.Activity" in clazz.raw: test_methods = True if not clazz.name.endswith("Activity"): - error(clazz, None, "Inconsistent class name") + error(clazz, None, "Inconsistent class name; should be FooActivity") if test_methods: for m in clazz.methods: if "final" in m.split: continue if not re.match("on[A-Z]", m.name): - error(clazz, m, "Extendable methods should be onFoo() style, otherwise final") + if "abstract" in m.split: + error(clazz, m, "Methods implemented by developers must be named onFoo()") + else: + warn(clazz, m, "If implemented by developer, should be named onFoo(); otherwise consider marking final") def verify_builder(clazz): @@ -430,7 +543,7 @@ def verify_builder(clazz): if not clazz.name.endswith("Builder"): return if clazz.name != "Builder": - warn(clazz, None, "Should be standalone Builder class") + warn(clazz, None, "Builder should be defined as inner class") has_build = False for m in clazz.methods: @@ -442,11 +555,11 @@ def verify_builder(clazz): if m.name.startswith("clear"): continue if m.name.startswith("with"): - error(clazz, m, "Builder methods must be setFoo()") + error(clazz, m, "Builder methods names must follow setFoo() style") if m.name.startswith("set"): if not m.typ.endswith(clazz.fullname): - warn(clazz, m, "Should return the builder") + warn(clazz, m, "Methods should return the builder") if not has_build: warn(clazz, None, "Missing build() method") @@ -474,7 +587,7 @@ def verify_layering(clazz): "android.view", "android.animation", "android.provider", - "android.content", + ["android.content","android.graphics.drawable"], "android.database", "android.graphics", "android.text", @@ -508,29 +621,40 @@ def verify_layering(clazz): warn(clazz, m, "Method argument type violates package layering") -def verify_boolean(clazz): +def verify_boolean(clazz, api): """Catches people returning boolean from getFoo() style methods. Ignores when matching setFoo() is present.""" + methods = [ m.name for m in clazz.methods ] + + builder = clazz.fullname + ".Builder" + builder_methods = [] + if builder in api: + builder_methods = [ m.name for m in api[builder].methods ] + for m in clazz.methods: if m.typ == "boolean" and m.name.startswith("get") and m.name != "get" and len(m.args) == 0: setter = "set" + m.name[3:] - if setter not in methods: - error(clazz, m, "Methods returning boolean should be isFoo or hasFoo") + if setter in methods: + pass + elif builder is not None and setter in builder_methods: + pass + else: + warn(clazz, m, "Methods returning boolean should be named isFoo, hasFoo, areFoo") def verify_collections(clazz): """Verifies that collection types are interfaces.""" + if clazz.fullname == "android.os.Bundle": return + bad = ["java.util.Vector", "java.util.LinkedList", "java.util.ArrayList", "java.util.Stack", "java.util.HashMap", "java.util.HashSet", "android.util.ArraySet", "android.util.ArrayMap"] for m in clazz.methods: - filt = re.sub("<.+>", "", m.typ) - if filt in bad: - error(clazz, m, "Return type is concrete collection") + if m.typ in bad: + error(clazz, m, "Return type is concrete collection; should be interface") for arg in m.args: - filt = re.sub("<.+>", "", arg) - if filt in bad: - error(clazz, m, "Argument is concrete collection") + if arg in bad: + error(clazz, m, "Argument is concrete collection; should be interface") def verify_flags(clazz): @@ -545,15 +669,18 @@ def verify_flags(clazz): scope = f.name[0:f.name.index("FLAG_")] if val & known[scope]: - warn(clazz, f, "Found overlapping flag") + warn(clazz, f, "Found overlapping flag constant value") known[scope] |= val -def verify_all(api): +def verify_style(api): + """Find all style issues in the given API level.""" global failures - failures = [] - for clazz in api: + failures = {} + for key in sorted(api.keys()): + clazz = api[key] + if clazz.pkg.name.startswith("java"): continue if clazz.pkg.name.startswith("junit"): continue if clazz.pkg.name.startswith("org.apache"): continue @@ -581,26 +708,90 @@ def verify_all(api): verify_aidl(clazz) verify_internal(clazz) verify_layering(clazz) - verify_boolean(clazz) + verify_boolean(clazz, api) verify_collections(clazz) verify_flags(clazz) return failures +def verify_compat(cur, prev): + """Find any incompatible API changes between two levels.""" + global failures + + def class_exists(api, test): + return test.fullname in api + + def ctor_exists(api, clazz, test): + for m in clazz.ctors: + if m.ident == test.ident: return True + return False + + def all_methods(api, clazz): + methods = list(clazz.methods) + if clazz.extends is not None: + methods.extend(all_methods(api, api[clazz.extends])) + return methods + + def method_exists(api, clazz, test): + methods = all_methods(api, clazz) + for m in methods: + if m.ident == test.ident: return True + return False + + def field_exists(api, clazz, test): + for f in clazz.fields: + if f.ident == test.ident: return True + return False + + failures = {} + for key in sorted(prev.keys()): + prev_clazz = prev[key] + + if not class_exists(cur, prev_clazz): + error(prev_clazz, None, "Class removed or incompatible change") + continue + + cur_clazz = cur[key] + + for test in prev_clazz.ctors: + if not ctor_exists(cur, cur_clazz, test): + error(prev_clazz, prev_ctor, "Constructor removed or incompatible change") + + methods = all_methods(prev, prev_clazz) + for test in methods: + if not method_exists(cur, cur_clazz, test): + error(prev_clazz, test, "Method removed or incompatible change") + + for test in prev_clazz.fields: + if not field_exists(cur, cur_clazz, test): + error(prev_clazz, test, "Field removed or incompatible change") + + return failures + + cur = parse_api(sys.argv[1]) -cur_fail = verify_all(cur) +cur_fail = verify_style(cur) if len(sys.argv) > 2: prev = parse_api(sys.argv[2]) - prev_fail = verify_all(prev) + prev_fail = verify_style(prev) # ignore errors from previous API level for p in prev_fail: if p in cur_fail: - cur_fail.remove(p) + del cur_fail[p] + + # look for compatibility issues + compat_fail = verify_compat(cur, prev) + + print "%s API compatibility issues %s\n" % ((format(fg=WHITE, bg=BLUE, bold=True), format(reset=True))) + for f in sorted(compat_fail): + print compat_fail[f] + print -for f in cur_fail: - print f +print "%s API style issues %s\n" % ((format(fg=WHITE, bg=BLUE, bold=True), format(reset=True))) +for f in sorted(cur_fail): + print cur_fail[f] print diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java index 74f2f651873f..1393bcef1867 100644 --- a/wifi/java/android/net/wifi/WifiManager.java +++ b/wifi/java/android/net/wifi/WifiManager.java @@ -1000,6 +1000,7 @@ public class WifiManager { } /** @hide */ + @SystemApi public boolean startScan(WorkSource workSource) { try { mService.startScan(null, workSource); @@ -1073,6 +1074,7 @@ public class WifiManager { * @return false if not supported. * @hide */ + @SystemApi public boolean isBatchedScanSupported() { try { return mService.isBatchedScanSupported(); @@ -1099,6 +1101,7 @@ public class WifiManager { * {@link BATCHED_SCAN_RESULTS_AVAILABLE_ACTION} is received. * @hide */ + @SystemApi public List<BatchedScanResult> getBatchedScanResults() { try { return mService.getBatchedScanResults(mContext.getOpPackageName()); |