Merge "Revert to save-layer based alpha if layer would be too large" into mnc-dev
diff --git a/Android.mk b/Android.mk
index 1752caf..e96a932 100644
--- a/Android.mk
+++ b/Android.mk
@@ -142,6 +142,7 @@
core/java/android/content/pm/IPackageManager.aidl \
core/java/android/content/pm/IPackageMoveObserver.aidl \
core/java/android/content/pm/IPackageStatsObserver.aidl \
+ core/java/android/content/pm/IOnPermissionsChangeListener.aidl \
core/java/android/database/IContentObserver.aidl \
core/java/android/hardware/ICameraService.aidl \
core/java/android/hardware/ICameraServiceListener.aidl \
diff --git a/CleanSpec.mk b/CleanSpec.mk
index 667ed02..48be749 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -234,6 +234,7 @@
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/lib/libinputflingerhost.so $(PRODUCT_OUT)/obj_arm/lib/libinputflingerhost.so)
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libinputflingerhost_intermediates $(PRODUCT_OUT)/obj_arm/SHARED_LIBRARIES/libinputflingerhost_intermediates)
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/target/common/obj/framework.aidl)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates)
# ******************************************************************
# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST ABOVE THIS BANNER
diff --git a/api/current.txt b/api/current.txt
index 049d790..3e0a1b3 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -17,7 +17,6 @@
field public static final java.lang.String ACCESS_WIFI_STATE = "android.permission.ACCESS_WIFI_STATE";
field public static final java.lang.String ACCOUNT_MANAGER = "android.permission.ACCOUNT_MANAGER";
field public static final java.lang.String ADD_VOICEMAIL = "com.android.voicemail.permission.ADD_VOICEMAIL";
- field public static final java.lang.String AUTHENTICATE_ACCOUNTS = "android.permission.AUTHENTICATE_ACCOUNTS";
field public static final java.lang.String BATTERY_STATS = "android.permission.BATTERY_STATS";
field public static final java.lang.String BIND_ACCESSIBILITY_SERVICE = "android.permission.BIND_ACCESSIBILITY_SERVICE";
field public static final java.lang.String BIND_APPWIDGET = "android.permission.BIND_APPWIDGET";
@@ -86,7 +85,6 @@
field public static final java.lang.String INTERNET = "android.permission.INTERNET";
field public static final java.lang.String KILL_BACKGROUND_PROCESSES = "android.permission.KILL_BACKGROUND_PROCESSES";
field public static final java.lang.String LOCATION_HARDWARE = "android.permission.LOCATION_HARDWARE";
- field public static final java.lang.String MANAGE_ACCOUNTS = "android.permission.MANAGE_ACCOUNTS";
field public static final java.lang.String MANAGE_APP_TOKENS = "android.permission.MANAGE_APP_TOKENS";
field public static final java.lang.String MANAGE_DOCUMENTS = "android.permission.MANAGE_DOCUMENTS";
field public static final java.lang.String MASTER_CLEAR = "android.permission.MASTER_CLEAR";
@@ -145,7 +143,6 @@
field public static final java.lang.String TRANSMIT_IR = "android.permission.TRANSMIT_IR";
field public static final java.lang.String UNINSTALL_SHORTCUT = "com.android.launcher.permission.UNINSTALL_SHORTCUT";
field public static final java.lang.String UPDATE_DEVICE_STATS = "android.permission.UPDATE_DEVICE_STATS";
- field public static final java.lang.String USE_CREDENTIALS = "android.permission.USE_CREDENTIALS";
field public static final java.lang.String USE_FINGERPRINT = "android.permission.USE_FINGERPRINT";
field public static final java.lang.String USE_SIP = "android.permission.USE_SIP";
field public static final java.lang.String VIBRATE = "android.permission.VIBRATE";
@@ -179,6 +176,7 @@
field public static final java.lang.String SENSORS = "android.permission-group.SENSORS";
field public static final java.lang.String SMS = "android.permission-group.SMS";
field public static final java.lang.String SOCIAL_INFO = "android.permission-group.SOCIAL_INFO";
+ field public static final java.lang.String STORAGE = "android.permission-group.STORAGE";
field public static final java.lang.String USER_DICTIONARY = "android.permission-group.USER_DICTIONARY";
}
@@ -222,6 +220,12 @@
ctor public R.attr();
field public static final int __reserved0 = 16844020; // 0x10104f4
field public static final int __reserved1 = 16844019; // 0x10104f3
+ field public static final int __reserved2 = 16843999; // 0x10104df
+ field public static final int __reserved3 = 16844000; // 0x10104e0
+ field public static final int __reserved4 = 16844001; // 0x10104e1
+ field public static final int __reserved5 = 16844002; // 0x10104e2
+ field public static final int __reserved6 = 16844003; // 0x10104e3
+ field public static final int __reserved7 = 16844004; // 0x10104e4
field public static final int absListViewStyle = 16842858; // 0x101006a
field public static final int accessibilityEventTypes = 16843648; // 0x1010380
field public static final int accessibilityFeedbackType = 16843650; // 0x1010382
@@ -570,7 +574,7 @@
field public static final int fillViewport = 16843130; // 0x101017a
field public static final int filter = 16843035; // 0x101011b
field public static final int filterTouchesWhenObscured = 16843460; // 0x10102c4
- field public static final int fingerprintDrawable = 16844025; // 0x10104f9
+ field public static final int fingerprintAuthDrawable = 16844025; // 0x10104f9
field public static final int finishOnCloseSystemDialogs = 16843431; // 0x10102a7
field public static final int finishOnTaskLaunch = 16842772; // 0x1010014
field public static final int firstDayOfWeek = 16843581; // 0x101033d
@@ -661,8 +665,6 @@
field public static final int hyphenationFrequency = 16844024; // 0x10104f8
field public static final int icon = 16842754; // 0x1010002
field public static final int iconPreview = 16843337; // 0x1010249
- field public static final int iconTint = 16843999; // 0x10104df
- field public static final int iconTintMode = 16844000; // 0x10104e0
field public static final int iconifiedByDefault = 16843514; // 0x10102fa
field public static final int id = 16842960; // 0x10100d0
field public static final int ignoreGravity = 16843263; // 0x10101ff
@@ -874,8 +876,6 @@
field public static final int navigationContentDescription = 16843969; // 0x10104c1
field public static final int navigationIcon = 16843968; // 0x10104c0
field public static final int navigationMode = 16843471; // 0x10102cf
- field public static final int navigationTint = 16844003; // 0x10104e3
- field public static final int navigationTintMode = 16844004; // 0x10104e4
field public static final int negativeButtonText = 16843254; // 0x10101f6
field public static final int nestedScrollingEnabled = 16843830; // 0x1010436
field public static final int nextFocusDown = 16842980; // 0x10100e4
@@ -907,8 +907,6 @@
field public static final int overScrollFooter = 16843459; // 0x10102c3
field public static final int overScrollHeader = 16843458; // 0x10102c2
field public static final int overScrollMode = 16843457; // 0x10102c1
- field public static final int overflowTint = 16844001; // 0x10104e1
- field public static final int overflowTintMode = 16844002; // 0x10104e2
field public static final int overlapAnchor = 16843874; // 0x1010462
field public static final int overridesImplicitlyEnabledSubtype = 16843682; // 0x10103a2
field public static final int packageNames = 16843649; // 0x1010381
@@ -4002,6 +4000,7 @@
public deprecated class AssistContent {
ctor public AssistContent();
method public android.content.ClipData getClipData();
+ method public android.os.Bundle getExtras();
method public android.net.Uri getWebUri();
method public boolean isAppProvidedIntent();
method public void setClipData(android.content.ClipData);
@@ -4060,6 +4059,7 @@
}
public static class AssistStructure.WindowNode {
+ method public int getDisplayId();
method public int getHeight();
method public int getLeft();
method public android.app.AssistStructure.ViewNode getRootViewNode();
@@ -5681,23 +5681,6 @@
field public static final java.lang.String EXTRA_LOCK_TASK_PACKAGE = "android.app.extra.LOCK_TASK_PACKAGE";
}
- public class DeviceInitializerStatus {
- field public static final int FLAG_STATUS_CUSTOM = 33554432; // 0x2000000
- field public static final int FLAG_STATUS_ERROR = 16777216; // 0x1000000
- field public static final int FLAG_STATUS_HIGH_PRIORITY = 134217728; // 0x8000000
- field public static final int FLAG_STATUS_RESERVED = 67108864; // 0x4000000
- field public static final int STATUS_ERROR_CONNECT_WIFI = 16777237; // 0x1000015
- field public static final int STATUS_ERROR_DELETE_APPS = 16777242; // 0x100001a
- field public static final int STATUS_ERROR_DOUBLE_BUMP = 16777246; // 0x100001e
- field public static final int STATUS_ERROR_DOWNLOAD_PACKAGE = 16777239; // 0x1000017
- field public static final int STATUS_ERROR_INSTALL_PACKAGE = 16777240; // 0x1000018
- field public static final int STATUS_ERROR_RESET_PROTECTION_BLOCKING_PROVISIONING = 16777238; // 0x1000016
- field public static final int STATUS_ERROR_SET_DEVICE_POLICY = 16777241; // 0x1000019
- field public static final int STATUS_STATE_CONNECTING_BLUETOOTH_PROXY = 134217736; // 0x8000008
- field public static final int STATUS_STATE_DEVICE_PROVISIONED = 134217738; // 0x800000a
- field public static final int STATUS_STATE_DISCONNECTING_BLUETOOTH_PROXY = 134217737; // 0x8000009
- }
-
public class DevicePolicyManager {
method public void addCrossProfileIntentFilter(android.content.ComponentName, android.content.IntentFilter, int);
method public boolean addCrossProfileWidgetProvider(android.content.ComponentName, java.lang.String);
@@ -5765,7 +5748,6 @@
method public boolean removeCrossProfileWidgetProvider(android.content.ComponentName, java.lang.String);
method public boolean removeUser(android.content.ComponentName, android.os.UserHandle);
method public boolean resetPassword(java.lang.String, int);
- method public void sendDeviceInitializerStatus(int, java.lang.String);
method public void setAccountManagementDisabled(android.content.ComponentName, java.lang.String, boolean);
method public boolean setApplicationHidden(android.content.ComponentName, java.lang.String, boolean);
method public void setApplicationRestrictions(android.content.ComponentName, java.lang.String, android.os.Bundle);
@@ -5829,23 +5811,19 @@
field public static final java.lang.String EXTRA_DEVICE_ADMIN = "android.app.extra.DEVICE_ADMIN";
field public static final java.lang.String EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE = "android.app.extra.PROVISIONING_ACCOUNT_TO_MIGRATE";
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_BT_DEVICE_ID = "android.app.extra.PROVISIONING_BT_DEVICE_ID";
- field public static final java.lang.String EXTRA_PROVISIONING_BT_MAC_ADDRESS = "android.app.extra.PROVISIONING_BT_MAC_ADDRESS";
- field public static final java.lang.String EXTRA_PROVISIONING_BT_USE_PROXY = "android.app.extra.PROVISIONING_BT_USE_PROXY";
- field public static final java.lang.String EXTRA_PROVISIONING_BT_UUID = "android.app.extra.PROVISIONING_BT_UUID";
- field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_CERTIFICATE_CHECKSUM = "android.app.extra.PROVISIONING_DEVICE_ADMIN_CERTIFICATE_CHECKSUM";
field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME = "android.app.extra.PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME";
field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_MINIMUM_VERSION_CODE = "android.app.extra.PROVISIONING_DEVICE_ADMIN_MINIMUM_VERSION_CODE";
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 deprecated java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME";
- field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_INITIALIZER_CERTIFICATE_CHECKSUM = "android.app.extra.PROVISIONING_DEVICE_INITIALIZER_CERTIFICATE_CHECKSUM";
+ field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_SIGNATURE_CHECKSUM = "android.app.extra.PROVISIONING_DEVICE_ADMIN_SIGNATURE_CHECKSUM";
field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_INITIALIZER_COMPONENT_NAME = "android.app.extra.PROVISIONING_DEVICE_INITIALIZER_COMPONENT_NAME";
field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_INITIALIZER_MINIMUM_VERSION_CODE = "android.app.extra.PROVISIONING_DEVICE_INITIALIZER_MINIMUM_VERSION_CODE";
field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_INITIALIZER_PACKAGE_CHECKSUM = "android.app.extra.PROVISIONING_DEVICE_INITIALIZER_PACKAGE_CHECKSUM";
field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_INITIALIZER_PACKAGE_DOWNLOAD_COOKIE_HEADER = "android.app.extra.PROVISIONING_DEVICE_INITIALIZER_PACKAGE_DOWNLOAD_COOKIE_HEADER";
field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_INITIALIZER_PACKAGE_DOWNLOAD_LOCATION = "android.app.extra.PROVISIONING_DEVICE_INITIALIZER_PACKAGE_DOWNLOAD_LOCATION";
+ field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_INITIALIZER_SIGNATURE_CHECKSUM = "android.app.extra.PROVISIONING_DEVICE_INITIALIZER_SIGNATURE_CHECKSUM";
field public static final java.lang.String EXTRA_PROVISIONING_EMAIL_ADDRESS = "android.app.extra.PROVISIONING_EMAIL_ADDRESS";
field public static final java.lang.String EXTRA_PROVISIONING_LEAVE_ALL_SYSTEM_APPS_ENABLED = "android.app.extra.PROVISIONING_LEAVE_ALL_SYSTEM_APPS_ENABLED";
field public static final java.lang.String EXTRA_PROVISIONING_LOCALE = "android.app.extra.PROVISIONING_LOCALE";
@@ -6148,10 +6126,10 @@
method public java.lang.String getPackageName();
method public long getTimeStamp();
field public static final int CONFIGURATION_CHANGE = 5; // 0x5
- field public static final int INTERACTION = 6; // 0x6
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
+ field public static final int USER_INTERACTION = 7; // 0x7
}
public final class UsageStats implements android.os.Parcelable {
@@ -7721,6 +7699,7 @@
method public final java.lang.String getString(int, java.lang.Object...);
method public abstract java.lang.Object getSystemService(java.lang.String);
method public final T getSystemService(java.lang.Class<T>);
+ method public abstract java.lang.String getSystemServiceName(java.lang.Class<?>);
method public final java.lang.CharSequence getText(int);
method public abstract android.content.res.Resources.Theme getTheme();
method public abstract deprecated android.graphics.drawable.Drawable getWallpaper();
@@ -8480,8 +8459,6 @@
field public static final int NO_MATCH_CATEGORY = -4; // 0xfffffffc
field public static final int NO_MATCH_DATA = -2; // 0xfffffffe
field public static final int NO_MATCH_TYPE = -1; // 0xffffffff
- field public static final java.lang.String SCHEME_HTTP = "http";
- field public static final java.lang.String SCHEME_HTTPS = "https";
field public static final int SYSTEM_HIGH_PRIORITY = 1000; // 0x3e8
field public static final int SYSTEM_LOW_PRIORITY = -1000; // 0xfffffc18
}
@@ -17210,7 +17187,7 @@
method public void connect();
method public void disconnect();
method public android.os.Bundle getExtras();
- method public void getMediaItem(java.lang.String, android.media.browse.MediaBrowser.MediaItemCallback);
+ method public void getItem(java.lang.String, android.media.browse.MediaBrowser.ItemCallback);
method public java.lang.String getRoot();
method public android.content.ComponentName getServiceComponent();
method public android.media.session.MediaSession.Token getSessionToken();
@@ -17226,6 +17203,12 @@
method public void onConnectionSuspended();
}
+ public static abstract class MediaBrowser.ItemCallback {
+ ctor public MediaBrowser.ItemCallback();
+ method public void onError(java.lang.String);
+ method public void onItemLoaded(android.media.browse.MediaBrowser.MediaItem);
+ }
+
public static class MediaBrowser.MediaItem implements android.os.Parcelable {
ctor public MediaBrowser.MediaItem(android.media.MediaDescription, int);
method public int describeContents();
@@ -17240,12 +17223,6 @@
field public static final int FLAG_PLAYABLE = 2; // 0x2
}
- public static abstract class MediaBrowser.MediaItemCallback {
- ctor public MediaBrowser.MediaItemCallback();
- method public void onError();
- method public void onMediaItemLoaded(android.media.browse.MediaBrowser.MediaItem);
- }
-
public static abstract class MediaBrowser.SubscriptionCallback {
ctor public MediaBrowser.SubscriptionCallback();
method public void onChildrenLoaded(java.lang.String, java.util.List<android.media.browse.MediaBrowser.MediaItem>);
@@ -24476,6 +24453,7 @@
method protected abstract void onPrintJobQueued(android.printservice.PrintJob);
method protected abstract void onRequestCancelPrintJob(android.printservice.PrintJob);
field public static final java.lang.String EXTRA_PRINTER_INFO = "android.intent.extra.print.EXTRA_PRINTER_INFO";
+ field public static final java.lang.String EXTRA_PRINT_DOCUMENT_INFO = "android.printservice.extra.PRINT_DOCUMENT_INFO";
field public static final java.lang.String EXTRA_PRINT_JOB_INFO = "android.intent.extra.print.PRINT_JOB_INFO";
field public static final java.lang.String SERVICE_INTERFACE = "android.printservice.PrintService";
field public static final java.lang.String SERVICE_META_DATA = "android.printservice";
@@ -26099,6 +26077,7 @@
method public static boolean isDocumentUri(android.content.Context, android.net.Uri);
method public static android.net.Uri renameDocument(android.content.ContentResolver, android.net.Uri, java.lang.String);
field public static final java.lang.String EXTRA_ERROR = "error";
+ field public static final java.lang.String EXTRA_EXCLUDE_SELF = "android.provider.extra.EXCLUDE_SELF";
field public static final java.lang.String EXTRA_INFO = "info";
field public static final java.lang.String EXTRA_LOADING = "loading";
field public static final java.lang.String PROVIDER_INTERFACE = "android.content.action.DOCUMENTS_PROVIDER";
@@ -26536,6 +26515,7 @@
field public static final java.lang.String ACTION_DISPLAY_SETTINGS = "android.settings.DISPLAY_SETTINGS";
field public static final java.lang.String ACTION_DREAM_SETTINGS = "android.settings.DREAM_SETTINGS";
field public static final java.lang.String ACTION_HOME_SETTINGS = "android.settings.HOME_SETTINGS";
+ field public static final java.lang.String ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS = "android.settings.IGNORE_BATTERY_OPTIMIZATION_SETTINGS";
field public static final java.lang.String ACTION_INPUT_METHOD_SETTINGS = "android.settings.INPUT_METHOD_SETTINGS";
field public static final java.lang.String ACTION_INPUT_METHOD_SUBTYPE_SETTINGS = "android.settings.INPUT_METHOD_SUBTYPE_SETTINGS";
field public static final java.lang.String ACTION_INTERNAL_STORAGE_SETTINGS = "android.settings.INTERNAL_STORAGE_SETTINGS";
@@ -28785,12 +28765,12 @@
public abstract class MediaBrowserService extends android.app.Service {
ctor public MediaBrowserService();
method public void dump(java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
- method public void getMediaItem(java.lang.String, android.service.media.MediaBrowserService.Result<android.media.browse.MediaBrowser.MediaItem>) throws java.lang.UnsupportedOperationException;
method public android.media.session.MediaSession.Token getSessionToken();
method public void notifyChildrenChanged(java.lang.String);
method public android.os.IBinder onBind(android.content.Intent);
method public abstract android.service.media.MediaBrowserService.BrowserRoot onGetRoot(java.lang.String, int, android.os.Bundle);
method public abstract void onLoadChildren(java.lang.String, android.service.media.MediaBrowserService.Result<java.util.List<android.media.browse.MediaBrowser.MediaItem>>);
+ method public void onLoadItem(java.lang.String, android.service.media.MediaBrowserService.Result<android.media.browse.MediaBrowser.MediaItem>);
method public void setSessionToken(android.media.session.MediaSession.Token);
field public static final java.lang.String SERVICE_INTERFACE = "android.media.browse.MediaBrowserService";
}
@@ -30733,7 +30713,7 @@
field public static final java.lang.String KEY_USE_HFA_FOR_PROVISIONING_BOOL = "use_hfa_for_provisioning_bool";
field public static final java.lang.String KEY_USE_OTASP_FOR_PROVISIONING_BOOL = "use_otasp_for_provisioning_bool";
field public static final java.lang.String KEY_VOICEMAIL_NOTIFICATION_PERSISTENT_BOOL = "voicemail_notification_persistent_bool";
- field public static final java.lang.String KEY_VOICE_PRIVACY_DISABLE_BOOL = "voice_privacy_disable_bool";
+ field public static final java.lang.String KEY_VOICE_PRIVACY_DISABLE_UI_BOOL = "voice_privacy_disable_ui_bool";
field public static final java.lang.String KEY_VOLTE_REPLACEMENT_RAT_INT = "volte_replacement_rat_int";
field public static final java.lang.String KEY_WORLD_PHONE_BOOL = "world_phone_bool";
}
@@ -33927,7 +33907,7 @@
public final class ArrayMap implements java.util.Map {
ctor public ArrayMap();
ctor public ArrayMap(int);
- ctor public ArrayMap(android.util.ArrayMap);
+ ctor public ArrayMap(android.util.ArrayMap<K, V>);
method public void clear();
method public boolean containsAll(java.util.Collection<?>);
method public boolean containsKey(java.lang.Object);
@@ -33952,6 +33932,31 @@
method public java.util.Collection<V> values();
}
+ public final class ArraySet implements java.util.Collection java.util.Set {
+ ctor public ArraySet();
+ ctor public ArraySet(int);
+ ctor public ArraySet(android.util.ArraySet<E>);
+ method public boolean add(E);
+ method public void addAll(android.util.ArraySet<? extends E>);
+ method public boolean addAll(java.util.Collection<? extends E>);
+ method public void clear();
+ method public boolean contains(java.lang.Object);
+ method public boolean containsAll(java.util.Collection<?>);
+ method public void ensureCapacity(int);
+ method public int indexOf(java.lang.Object);
+ method public boolean isEmpty();
+ method public java.util.Iterator<E> iterator();
+ method public boolean remove(java.lang.Object);
+ method public boolean removeAll(android.util.ArraySet<? extends E>);
+ method public boolean removeAll(java.util.Collection<?>);
+ method public E removeAt(int);
+ method public boolean retainAll(java.util.Collection<?>);
+ method public int size();
+ method public java.lang.Object[] toArray();
+ method public T[] toArray(T[]);
+ method public E valueAt(int);
+ }
+
public class AtomicFile {
ctor public AtomicFile(java.io.File);
method public void delete();
@@ -35489,8 +35494,6 @@
method public abstract android.view.MenuItem setEnabled(boolean);
method public abstract android.view.MenuItem setIcon(android.graphics.drawable.Drawable);
method public abstract android.view.MenuItem setIcon(int);
- method public abstract android.view.MenuItem setIconTintList(android.content.res.ColorStateList);
- method public abstract android.view.MenuItem setIconTintMode(android.graphics.PorterDuff.Mode);
method public abstract android.view.MenuItem setIntent(android.content.Intent);
method public abstract android.view.MenuItem setNumericShortcut(char);
method public abstract android.view.MenuItem setOnActionExpandListener(android.view.MenuItem.OnActionExpandListener);
@@ -37051,6 +37054,7 @@
public abstract class ViewStructure {
ctor public ViewStructure();
+ method public abstract int addChildCount(int);
method public abstract void asyncCommit();
method public abstract android.view.ViewAssistStructure asyncNewChild(int);
method public abstract int getChildCount();
@@ -39551,14 +39555,14 @@
ctor public ActionMenuView(android.content.Context, android.util.AttributeSet);
method public void dismissPopupMenus();
method public android.view.Menu getMenu();
+ method public android.graphics.drawable.Drawable getOverflowIcon();
method public int getPopupTheme();
method public boolean hideOverflowMenu();
method public boolean isOverflowMenuShowing();
method public void onConfigurationChanged(android.content.res.Configuration);
method public void onDetachedFromWindow();
method public void setOnMenuItemClickListener(android.widget.ActionMenuView.OnMenuItemClickListener);
- method public void setOverflowTintList(android.content.res.ColorStateList);
- method public void setOverflowTintMode(android.graphics.PorterDuff.Mode);
+ method public void setOverflowIcon(android.graphics.drawable.Drawable);
method public void setPopupTheme(int);
method public boolean showOverflowMenu();
}
@@ -41848,6 +41852,7 @@
method public android.view.Menu getMenu();
method public java.lang.CharSequence getNavigationContentDescription();
method public android.graphics.drawable.Drawable getNavigationIcon();
+ method public android.graphics.drawable.Drawable getOverflowIcon();
method public int getPopupTheme();
method public java.lang.CharSequence getSubtitle();
method public java.lang.CharSequence getTitle();
@@ -41867,11 +41872,8 @@
method public void setNavigationIcon(int);
method public void setNavigationIcon(android.graphics.drawable.Drawable);
method public void setNavigationOnClickListener(android.view.View.OnClickListener);
- method public void setNavigationTintList(android.content.res.ColorStateList);
- method public void setNavigationTintMode(android.graphics.PorterDuff.Mode);
method public void setOnMenuItemClickListener(android.widget.Toolbar.OnMenuItemClickListener);
- method public void setOverflowTintList(android.content.res.ColorStateList);
- method public void setOverflowTintMode(android.graphics.PorterDuff.Mode);
+ method public void setOverflowIcon(android.graphics.drawable.Drawable);
method public void setPopupTheme(int);
method public void setSubtitle(int);
method public void setSubtitle(java.lang.CharSequence);
diff --git a/api/removed.txt b/api/removed.txt
index 0046a70..f6ad27b 100644
--- a/api/removed.txt
+++ b/api/removed.txt
@@ -1,12 +1,3 @@
-package android {
-
- public static final class Manifest.permission {
- field public static final java.lang.String SUBSCRIBED_FEEDS_READ = "android.permission.SUBSCRIBED_FEEDS_READ";
- field public static final java.lang.String SUBSCRIBED_FEEDS_WRITE = "android.permission.SUBSCRIBED_FEEDS_WRITE";
- }
-
-}
-
package android.content.pm {
public class PackageInfo implements android.os.Parcelable {
diff --git a/api/system-current.txt b/api/system-current.txt
index 8b3c181..a61b9fb53 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -24,7 +24,6 @@
field public static final java.lang.String ACCOUNT_MANAGER = "android.permission.ACCOUNT_MANAGER";
field public static final java.lang.String ADD_VOICEMAIL = "com.android.voicemail.permission.ADD_VOICEMAIL";
field public static final java.lang.String ALLOW_ANY_CODEC_FOR_PLAYBACK = "android.permission.ALLOW_ANY_CODEC_FOR_PLAYBACK";
- field public static final java.lang.String AUTHENTICATE_ACCOUNTS = "android.permission.AUTHENTICATE_ACCOUNTS";
field public static final java.lang.String BACKUP = "android.permission.BACKUP";
field public static final java.lang.String BATTERY_STATS = "android.permission.BATTERY_STATS";
field public static final java.lang.String BIND_ACCESSIBILITY_SERVICE = "android.permission.BIND_ACCESSIBILITY_SERVICE";
@@ -117,7 +116,6 @@
field public static final java.lang.String LOCAL_MAC_ADDRESS = "android.permission.LOCAL_MAC_ADDRESS";
field public static final java.lang.String LOCATION_HARDWARE = "android.permission.LOCATION_HARDWARE";
field public static final java.lang.String LOOP_RADIO = "android.permission.LOOP_RADIO";
- field public static final java.lang.String MANAGE_ACCOUNTS = "android.permission.MANAGE_ACCOUNTS";
field public static final java.lang.String MANAGE_ACTIVITY_STACKS = "android.permission.MANAGE_ACTIVITY_STACKS";
field public static final java.lang.String MANAGE_APP_TOKENS = "android.permission.MANAGE_APP_TOKENS";
field public static final java.lang.String MANAGE_CA_CERTIFICATES = "android.permission.MANAGE_CA_CERTIFICATES";
@@ -217,7 +215,6 @@
field public static final java.lang.String UPDATE_DEVICE_STATS = "android.permission.UPDATE_DEVICE_STATS";
field public static final java.lang.String UPDATE_LOCK = "android.permission.UPDATE_LOCK";
field public static final java.lang.String USER_ACTIVITY = "android.permission.USER_ACTIVITY";
- field public static final java.lang.String USE_CREDENTIALS = "android.permission.USE_CREDENTIALS";
field public static final java.lang.String USE_FINGERPRINT = "android.permission.USE_FINGERPRINT";
field public static final java.lang.String USE_SIP = "android.permission.USE_SIP";
field public static final java.lang.String VIBRATE = "android.permission.VIBRATE";
@@ -253,6 +250,7 @@
field public static final java.lang.String SENSORS = "android.permission-group.SENSORS";
field public static final java.lang.String SMS = "android.permission-group.SMS";
field public static final java.lang.String SOCIAL_INFO = "android.permission-group.SOCIAL_INFO";
+ field public static final java.lang.String STORAGE = "android.permission-group.STORAGE";
field public static final java.lang.String USER_DICTIONARY = "android.permission-group.USER_DICTIONARY";
}
@@ -297,6 +295,12 @@
ctor public R.attr();
field public static final int __reserved0 = 16844020; // 0x10104f4
field public static final int __reserved1 = 16844019; // 0x10104f3
+ field public static final int __reserved2 = 16843999; // 0x10104df
+ field public static final int __reserved3 = 16844000; // 0x10104e0
+ field public static final int __reserved4 = 16844001; // 0x10104e1
+ field public static final int __reserved5 = 16844002; // 0x10104e2
+ field public static final int __reserved6 = 16844003; // 0x10104e3
+ field public static final int __reserved7 = 16844004; // 0x10104e4
field public static final int absListViewStyle = 16842858; // 0x101006a
field public static final int accessibilityEventTypes = 16843648; // 0x1010380
field public static final int accessibilityFeedbackType = 16843650; // 0x1010382
@@ -645,7 +649,7 @@
field public static final int fillViewport = 16843130; // 0x101017a
field public static final int filter = 16843035; // 0x101011b
field public static final int filterTouchesWhenObscured = 16843460; // 0x10102c4
- field public static final int fingerprintDrawable = 16844025; // 0x10104f9
+ field public static final int fingerprintAuthDrawable = 16844025; // 0x10104f9
field public static final int finishOnCloseSystemDialogs = 16843431; // 0x10102a7
field public static final int finishOnTaskLaunch = 16842772; // 0x1010014
field public static final int firstDayOfWeek = 16843581; // 0x101033d
@@ -736,8 +740,6 @@
field public static final int hyphenationFrequency = 16844024; // 0x10104f8
field public static final int icon = 16842754; // 0x1010002
field public static final int iconPreview = 16843337; // 0x1010249
- field public static final int iconTint = 16843999; // 0x10104df
- field public static final int iconTintMode = 16844000; // 0x10104e0
field public static final int iconifiedByDefault = 16843514; // 0x10102fa
field public static final int id = 16842960; // 0x10100d0
field public static final int ignoreGravity = 16843263; // 0x10101ff
@@ -949,8 +951,6 @@
field public static final int navigationContentDescription = 16843969; // 0x10104c1
field public static final int navigationIcon = 16843968; // 0x10104c0
field public static final int navigationMode = 16843471; // 0x10102cf
- field public static final int navigationTint = 16844003; // 0x10104e3
- field public static final int navigationTintMode = 16844004; // 0x10104e4
field public static final int negativeButtonText = 16843254; // 0x10101f6
field public static final int nestedScrollingEnabled = 16843830; // 0x1010436
field public static final int nextFocusDown = 16842980; // 0x10100e4
@@ -982,8 +982,6 @@
field public static final int overScrollFooter = 16843459; // 0x10102c3
field public static final int overScrollHeader = 16843458; // 0x10102c2
field public static final int overScrollMode = 16843457; // 0x10102c1
- field public static final int overflowTint = 16844001; // 0x10104e1
- field public static final int overflowTintMode = 16844002; // 0x10104e2
field public static final int overlapAnchor = 16843874; // 0x1010462
field public static final int overridesImplicitlyEnabledSubtype = 16843682; // 0x10103a2
field public static final int packageNames = 16843649; // 0x1010381
@@ -4098,6 +4096,7 @@
public deprecated class AssistContent {
ctor public AssistContent();
method public android.content.ClipData getClipData();
+ method public android.os.Bundle getExtras();
method public android.net.Uri getWebUri();
method public boolean isAppProvidedIntent();
method public void setClipData(android.content.ClipData);
@@ -4156,6 +4155,7 @@
}
public static class AssistStructure.WindowNode {
+ method public int getDisplayId();
method public int getHeight();
method public int getLeft();
method public android.app.AssistStructure.ViewNode getRootViewNode();
@@ -5781,23 +5781,6 @@
field public static final java.lang.String EXTRA_LOCK_TASK_PACKAGE = "android.app.extra.LOCK_TASK_PACKAGE";
}
- public class DeviceInitializerStatus {
- field public static final int FLAG_STATUS_CUSTOM = 33554432; // 0x2000000
- field public static final int FLAG_STATUS_ERROR = 16777216; // 0x1000000
- field public static final int FLAG_STATUS_HIGH_PRIORITY = 134217728; // 0x8000000
- field public static final int FLAG_STATUS_RESERVED = 67108864; // 0x4000000
- field public static final int STATUS_ERROR_CONNECT_WIFI = 16777237; // 0x1000015
- field public static final int STATUS_ERROR_DELETE_APPS = 16777242; // 0x100001a
- field public static final int STATUS_ERROR_DOUBLE_BUMP = 16777246; // 0x100001e
- field public static final int STATUS_ERROR_DOWNLOAD_PACKAGE = 16777239; // 0x1000017
- field public static final int STATUS_ERROR_INSTALL_PACKAGE = 16777240; // 0x1000018
- field public static final int STATUS_ERROR_RESET_PROTECTION_BLOCKING_PROVISIONING = 16777238; // 0x1000016
- field public static final int STATUS_ERROR_SET_DEVICE_POLICY = 16777241; // 0x1000019
- field public static final int STATUS_STATE_CONNECTING_BLUETOOTH_PROXY = 134217736; // 0x8000008
- field public static final int STATUS_STATE_DEVICE_PROVISIONED = 134217738; // 0x800000a
- field public static final int STATUS_STATE_DISCONNECTING_BLUETOOTH_PROXY = 134217737; // 0x8000009
- }
-
public class DevicePolicyManager {
method public void addCrossProfileIntentFilter(android.content.ComponentName, android.content.IntentFilter, int);
method public boolean addCrossProfileWidgetProvider(android.content.ComponentName, java.lang.String);
@@ -5874,7 +5857,6 @@
method public boolean removeCrossProfileWidgetProvider(android.content.ComponentName, java.lang.String);
method public boolean removeUser(android.content.ComponentName, android.os.UserHandle);
method public boolean resetPassword(java.lang.String, int);
- method public void sendDeviceInitializerStatus(int, java.lang.String);
method public void setAccountManagementDisabled(android.content.ComponentName, java.lang.String, boolean);
method public deprecated boolean setActiveProfileOwner(android.content.ComponentName, java.lang.String) throws java.lang.IllegalArgumentException;
method public boolean setApplicationHidden(android.content.ComponentName, java.lang.String, boolean);
@@ -5927,7 +5909,6 @@
field public static final java.lang.String ACTION_MANAGED_PROFILE_PROVISIONED = "android.app.action.MANAGED_PROFILE_PROVISIONED";
field public static final java.lang.String ACTION_PROVISION_MANAGED_DEVICE = "android.app.action.PROVISION_MANAGED_DEVICE";
field public static final java.lang.String ACTION_PROVISION_MANAGED_PROFILE = "android.app.action.PROVISION_MANAGED_PROFILE";
- field public static final java.lang.String ACTION_SEND_DEVICE_INITIALIZER_STATUS = "android.app.action.SEND_DEVICE_INITIALIZER_STATUS";
field public static final java.lang.String ACTION_SET_NEW_PASSWORD = "android.app.action.SET_NEW_PASSWORD";
field public static final java.lang.String ACTION_SET_PROFILE_OWNER = "android.app.action.SET_PROFILE_OWNER";
field public static final java.lang.String ACTION_START_ENCRYPTION = "android.app.action.START_ENCRYPTION";
@@ -5939,28 +5920,22 @@
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_DEVICE_INITIALIZER_STATUS_CODE = "android.app.extra.DEVICE_INITIALIZER_STATUS_CODE";
- field public static final java.lang.String EXTRA_DEVICE_INITIALIZER_STATUS_DESCRIPTION = "android.app.extra.DEVICE_INITIALIZER_STATUS_DESCRIPTION";
field public static final java.lang.String EXTRA_PROFILE_OWNER_NAME = "android.app.extra.PROFILE_OWNER_NAME";
field public static final java.lang.String EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE = "android.app.extra.PROVISIONING_ACCOUNT_TO_MIGRATE";
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_BT_DEVICE_ID = "android.app.extra.PROVISIONING_BT_DEVICE_ID";
- field public static final java.lang.String EXTRA_PROVISIONING_BT_MAC_ADDRESS = "android.app.extra.PROVISIONING_BT_MAC_ADDRESS";
- field public static final java.lang.String EXTRA_PROVISIONING_BT_USE_PROXY = "android.app.extra.PROVISIONING_BT_USE_PROXY";
- field public static final java.lang.String EXTRA_PROVISIONING_BT_UUID = "android.app.extra.PROVISIONING_BT_UUID";
- field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_CERTIFICATE_CHECKSUM = "android.app.extra.PROVISIONING_DEVICE_ADMIN_CERTIFICATE_CHECKSUM";
field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME = "android.app.extra.PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME";
field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_MINIMUM_VERSION_CODE = "android.app.extra.PROVISIONING_DEVICE_ADMIN_MINIMUM_VERSION_CODE";
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 deprecated java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME";
- field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_INITIALIZER_CERTIFICATE_CHECKSUM = "android.app.extra.PROVISIONING_DEVICE_INITIALIZER_CERTIFICATE_CHECKSUM";
+ field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_SIGNATURE_CHECKSUM = "android.app.extra.PROVISIONING_DEVICE_ADMIN_SIGNATURE_CHECKSUM";
field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_INITIALIZER_COMPONENT_NAME = "android.app.extra.PROVISIONING_DEVICE_INITIALIZER_COMPONENT_NAME";
field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_INITIALIZER_MINIMUM_VERSION_CODE = "android.app.extra.PROVISIONING_DEVICE_INITIALIZER_MINIMUM_VERSION_CODE";
field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_INITIALIZER_PACKAGE_CHECKSUM = "android.app.extra.PROVISIONING_DEVICE_INITIALIZER_PACKAGE_CHECKSUM";
field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_INITIALIZER_PACKAGE_DOWNLOAD_COOKIE_HEADER = "android.app.extra.PROVISIONING_DEVICE_INITIALIZER_PACKAGE_DOWNLOAD_COOKIE_HEADER";
field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_INITIALIZER_PACKAGE_DOWNLOAD_LOCATION = "android.app.extra.PROVISIONING_DEVICE_INITIALIZER_PACKAGE_DOWNLOAD_LOCATION";
+ field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_INITIALIZER_SIGNATURE_CHECKSUM = "android.app.extra.PROVISIONING_DEVICE_INITIALIZER_SIGNATURE_CHECKSUM";
field public static final java.lang.String EXTRA_PROVISIONING_EMAIL_ADDRESS = "android.app.extra.PROVISIONING_EMAIL_ADDRESS";
field public static final java.lang.String EXTRA_PROVISIONING_LEAVE_ALL_SYSTEM_APPS_ENABLED = "android.app.extra.PROVISIONING_LEAVE_ALL_SYSTEM_APPS_ENABLED";
field public static final java.lang.String EXTRA_PROVISIONING_LOCALE = "android.app.extra.PROVISIONING_LOCALE";
@@ -6341,10 +6316,10 @@
method public java.lang.String getPackageName();
method public long getTimeStamp();
field public static final int CONFIGURATION_CHANGE = 5; // 0x5
- field public static final int INTERACTION = 6; // 0x6
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
+ field public static final int USER_INTERACTION = 7; // 0x7
}
public final class UsageStats implements android.os.Parcelable {
@@ -7944,6 +7919,7 @@
method public final java.lang.String getString(int, java.lang.Object...);
method public abstract java.lang.Object getSystemService(java.lang.String);
method public final T getSystemService(java.lang.Class<T>);
+ method public abstract java.lang.String getSystemServiceName(java.lang.Class<?>);
method public final java.lang.CharSequence getText(int);
method public abstract android.content.res.Resources.Theme getTheme();
method public abstract deprecated android.graphics.drawable.Drawable getWallpaper();
@@ -8715,8 +8691,6 @@
field public static final int NO_MATCH_CATEGORY = -4; // 0xfffffffc
field public static final int NO_MATCH_DATA = -2; // 0xfffffffe
field public static final int NO_MATCH_TYPE = -1; // 0xffffffff
- field public static final java.lang.String SCHEME_HTTP = "http";
- field public static final java.lang.String SCHEME_HTTPS = "https";
field public static final int SYSTEM_HIGH_PRIORITY = 1000; // 0x3e8
field public static final int SYSTEM_LOW_PRIORITY = -1000; // 0xfffffc18
}
@@ -9521,6 +9495,7 @@
public abstract class PackageManager {
ctor public PackageManager();
+ method public abstract void addOnPermissionsChangeListener(android.content.pm.PackageManager.OnPermissionsChangedListener);
method public abstract deprecated void addPackageToPreferred(java.lang.String);
method public abstract boolean addPermission(android.content.pm.PermissionInfo);
method public abstract boolean addPermissionAsync(android.content.pm.PermissionInfo);
@@ -9594,6 +9569,7 @@
method public abstract java.util.List<android.content.pm.ResolveInfo> queryIntentContentProviders(android.content.Intent, int);
method public abstract java.util.List<android.content.pm.ResolveInfo> queryIntentServices(android.content.Intent, int);
method public abstract java.util.List<android.content.pm.PermissionInfo> queryPermissionsByGroup(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
+ method public abstract void removeOnPermissionsChangeListener(android.content.pm.PackageManager.OnPermissionsChangedListener);
method public abstract deprecated void removePackageFromPreferred(java.lang.String);
method public abstract void removePermission(java.lang.String);
method public abstract android.content.pm.ResolveInfo resolveActivity(android.content.Intent, int);
@@ -9769,6 +9745,10 @@
ctor public PackageManager.NameNotFoundException(java.lang.String);
}
+ public static abstract interface PackageManager.OnPermissionsChangedListener {
+ method public abstract void onPermissionsChanged(int);
+ }
+
public static abstract class PackageManager.PermissionFlags implements java.lang.annotation.Annotation {
}
@@ -18522,7 +18502,7 @@
method public void connect();
method public void disconnect();
method public android.os.Bundle getExtras();
- method public void getMediaItem(java.lang.String, android.media.browse.MediaBrowser.MediaItemCallback);
+ method public void getItem(java.lang.String, android.media.browse.MediaBrowser.ItemCallback);
method public java.lang.String getRoot();
method public android.content.ComponentName getServiceComponent();
method public android.media.session.MediaSession.Token getSessionToken();
@@ -18538,6 +18518,12 @@
method public void onConnectionSuspended();
}
+ public static abstract class MediaBrowser.ItemCallback {
+ ctor public MediaBrowser.ItemCallback();
+ method public void onError(java.lang.String);
+ method public void onItemLoaded(android.media.browse.MediaBrowser.MediaItem);
+ }
+
public static class MediaBrowser.MediaItem implements android.os.Parcelable {
ctor public MediaBrowser.MediaItem(android.media.MediaDescription, int);
method public int describeContents();
@@ -18552,12 +18538,6 @@
field public static final int FLAG_PLAYABLE = 2; // 0x2
}
- public static abstract class MediaBrowser.MediaItemCallback {
- ctor public MediaBrowser.MediaItemCallback();
- method public void onError();
- method public void onMediaItemLoaded(android.media.browse.MediaBrowser.MediaItem);
- }
-
public static abstract class MediaBrowser.SubscriptionCallback {
ctor public MediaBrowser.SubscriptionCallback();
method public void onChildrenLoaded(java.lang.String, java.util.List<android.media.browse.MediaBrowser.MediaItem>);
@@ -19194,7 +19174,9 @@
method public android.content.Intent createSettingsIntent();
method public android.content.Intent createSetupIntent();
method public static android.media.tv.TvInputInfo createTvInputInfo(android.content.Context, android.content.pm.ResolveInfo, android.hardware.hdmi.HdmiDeviceInfo, java.lang.String, java.lang.String, android.net.Uri) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+ method public static android.media.tv.TvInputInfo createTvInputInfo(android.content.Context, android.content.pm.ResolveInfo, android.hardware.hdmi.HdmiDeviceInfo, java.lang.String, int, android.graphics.drawable.Icon) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
method public static android.media.tv.TvInputInfo createTvInputInfo(android.content.Context, android.content.pm.ResolveInfo, android.media.tv.TvInputHardwareInfo, java.lang.String, android.net.Uri) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+ method public static android.media.tv.TvInputInfo createTvInputInfo(android.content.Context, android.content.pm.ResolveInfo, android.media.tv.TvInputHardwareInfo, int, android.graphics.drawable.Icon) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
method public int describeContents();
method public android.hardware.hdmi.HdmiDeviceInfo getHdmiDeviceInfo();
method public java.lang.String getId();
@@ -26406,6 +26388,7 @@
method protected abstract void onPrintJobQueued(android.printservice.PrintJob);
method protected abstract void onRequestCancelPrintJob(android.printservice.PrintJob);
field public static final java.lang.String EXTRA_PRINTER_INFO = "android.intent.extra.print.EXTRA_PRINTER_INFO";
+ field public static final java.lang.String EXTRA_PRINT_DOCUMENT_INFO = "android.printservice.extra.PRINT_DOCUMENT_INFO";
field public static final java.lang.String EXTRA_PRINT_JOB_INFO = "android.intent.extra.print.PRINT_JOB_INFO";
field public static final java.lang.String SERVICE_INTERFACE = "android.printservice.PrintService";
field public static final java.lang.String SERVICE_META_DATA = "android.printservice";
@@ -28029,6 +28012,7 @@
method public static boolean isDocumentUri(android.content.Context, android.net.Uri);
method public static android.net.Uri renameDocument(android.content.ContentResolver, android.net.Uri, java.lang.String);
field public static final java.lang.String EXTRA_ERROR = "error";
+ field public static final java.lang.String EXTRA_EXCLUDE_SELF = "android.provider.extra.EXCLUDE_SELF";
field public static final java.lang.String EXTRA_INFO = "info";
field public static final java.lang.String EXTRA_LOADING = "loading";
field public static final java.lang.String PROVIDER_INTERFACE = "android.content.action.DOCUMENTS_PROVIDER";
@@ -28568,6 +28552,7 @@
field public static final java.lang.String ACTION_DISPLAY_SETTINGS = "android.settings.DISPLAY_SETTINGS";
field public static final java.lang.String ACTION_DREAM_SETTINGS = "android.settings.DREAM_SETTINGS";
field public static final java.lang.String ACTION_HOME_SETTINGS = "android.settings.HOME_SETTINGS";
+ field public static final java.lang.String ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS = "android.settings.IGNORE_BATTERY_OPTIMIZATION_SETTINGS";
field public static final java.lang.String ACTION_INPUT_METHOD_SETTINGS = "android.settings.INPUT_METHOD_SETTINGS";
field public static final java.lang.String ACTION_INPUT_METHOD_SUBTYPE_SETTINGS = "android.settings.INPUT_METHOD_SUBTYPE_SETTINGS";
field public static final java.lang.String ACTION_INTERNAL_STORAGE_SETTINGS = "android.settings.INTERNAL_STORAGE_SETTINGS";
@@ -30818,12 +30803,12 @@
public abstract class MediaBrowserService extends android.app.Service {
ctor public MediaBrowserService();
method public void dump(java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
- method public void getMediaItem(java.lang.String, android.service.media.MediaBrowserService.Result<android.media.browse.MediaBrowser.MediaItem>) throws java.lang.UnsupportedOperationException;
method public android.media.session.MediaSession.Token getSessionToken();
method public void notifyChildrenChanged(java.lang.String);
method public android.os.IBinder onBind(android.content.Intent);
method public abstract android.service.media.MediaBrowserService.BrowserRoot onGetRoot(java.lang.String, int, android.os.Bundle);
method public abstract void onLoadChildren(java.lang.String, android.service.media.MediaBrowserService.Result<java.util.List<android.media.browse.MediaBrowser.MediaItem>>);
+ method public void onLoadItem(java.lang.String, android.service.media.MediaBrowserService.Result<android.media.browse.MediaBrowser.MediaItem>);
method public void setSessionToken(android.media.session.MediaSession.Token);
field public static final java.lang.String SERVICE_INTERFACE = "android.media.browse.MediaBrowserService";
}
@@ -32949,7 +32934,7 @@
field public static final java.lang.String KEY_USE_HFA_FOR_PROVISIONING_BOOL = "use_hfa_for_provisioning_bool";
field public static final java.lang.String KEY_USE_OTASP_FOR_PROVISIONING_BOOL = "use_otasp_for_provisioning_bool";
field public static final java.lang.String KEY_VOICEMAIL_NOTIFICATION_PERSISTENT_BOOL = "voicemail_notification_persistent_bool";
- field public static final java.lang.String KEY_VOICE_PRIVACY_DISABLE_BOOL = "voice_privacy_disable_bool";
+ field public static final java.lang.String KEY_VOICE_PRIVACY_DISABLE_UI_BOOL = "voice_privacy_disable_ui_bool";
field public static final java.lang.String KEY_VOLTE_REPLACEMENT_RAT_INT = "volte_replacement_rat_int";
field public static final java.lang.String KEY_WORLD_PHONE_BOOL = "world_phone_bool";
}
@@ -33514,6 +33499,10 @@
field public static final int CALL_STATE_IDLE = 0; // 0x0
field public static final int CALL_STATE_OFFHOOK = 2; // 0x2
field public static final int CALL_STATE_RINGING = 1; // 0x1
+ field public static final int CARRIER_PRIVILEGE_STATUS_ERROR_LOADING_RULES = -2; // 0xfffffffe
+ field public static final int CARRIER_PRIVILEGE_STATUS_HAS_ACCESS = 1; // 0x1
+ field public static final int CARRIER_PRIVILEGE_STATUS_NO_ACCESS = 0; // 0x0
+ field public static final int CARRIER_PRIVILEGE_STATUS_RULES_NOT_LOADED = -1; // 0xffffffff
field public static final int DATA_ACTIVITY_DORMANT = 4; // 0x4
field public static final int DATA_ACTIVITY_IN = 1; // 0x1
field public static final int DATA_ACTIVITY_INOUT = 3; // 0x3
@@ -34151,6 +34140,7 @@
public class MockPackageManager extends android.content.pm.PackageManager {
ctor public MockPackageManager();
+ method public void addOnPermissionsChangeListener(android.content.pm.PackageManager.OnPermissionsChangedListener);
method public void addPackageToPreferred(java.lang.String);
method public boolean addPermission(android.content.pm.PermissionInfo);
method public boolean addPermissionAsync(android.content.pm.PermissionInfo);
@@ -34225,6 +34215,7 @@
method public java.util.List<android.content.pm.ResolveInfo> queryIntentContentProviders(android.content.Intent, int);
method public java.util.List<android.content.pm.ResolveInfo> queryIntentServices(android.content.Intent, int);
method public java.util.List<android.content.pm.PermissionInfo> queryPermissionsByGroup(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
+ method public void removeOnPermissionsChangeListener(android.content.pm.PackageManager.OnPermissionsChangedListener);
method public void removePackageFromPreferred(java.lang.String);
method public void removePermission(java.lang.String);
method public android.content.pm.ResolveInfo resolveActivity(android.content.Intent, int);
@@ -36193,7 +36184,7 @@
public final class ArrayMap implements java.util.Map {
ctor public ArrayMap();
ctor public ArrayMap(int);
- ctor public ArrayMap(android.util.ArrayMap);
+ ctor public ArrayMap(android.util.ArrayMap<K, V>);
method public void clear();
method public boolean containsAll(java.util.Collection<?>);
method public boolean containsKey(java.lang.Object);
@@ -36218,6 +36209,31 @@
method public java.util.Collection<V> values();
}
+ public final class ArraySet implements java.util.Collection java.util.Set {
+ ctor public ArraySet();
+ ctor public ArraySet(int);
+ ctor public ArraySet(android.util.ArraySet<E>);
+ method public boolean add(E);
+ method public void addAll(android.util.ArraySet<? extends E>);
+ method public boolean addAll(java.util.Collection<? extends E>);
+ method public void clear();
+ method public boolean contains(java.lang.Object);
+ method public boolean containsAll(java.util.Collection<?>);
+ method public void ensureCapacity(int);
+ method public int indexOf(java.lang.Object);
+ method public boolean isEmpty();
+ method public java.util.Iterator<E> iterator();
+ method public boolean remove(java.lang.Object);
+ method public boolean removeAll(android.util.ArraySet<? extends E>);
+ method public boolean removeAll(java.util.Collection<?>);
+ method public E removeAt(int);
+ method public boolean retainAll(java.util.Collection<?>);
+ method public int size();
+ method public java.lang.Object[] toArray();
+ method public T[] toArray(T[]);
+ method public E valueAt(int);
+ }
+
public class AtomicFile {
ctor public AtomicFile(java.io.File);
method public void delete();
@@ -37755,8 +37771,6 @@
method public abstract android.view.MenuItem setEnabled(boolean);
method public abstract android.view.MenuItem setIcon(android.graphics.drawable.Drawable);
method public abstract android.view.MenuItem setIcon(int);
- method public abstract android.view.MenuItem setIconTintList(android.content.res.ColorStateList);
- method public abstract android.view.MenuItem setIconTintMode(android.graphics.PorterDuff.Mode);
method public abstract android.view.MenuItem setIntent(android.content.Intent);
method public abstract android.view.MenuItem setNumericShortcut(char);
method public abstract android.view.MenuItem setOnActionExpandListener(android.view.MenuItem.OnActionExpandListener);
@@ -39317,6 +39331,7 @@
public abstract class ViewStructure {
ctor public ViewStructure();
+ method public abstract int addChildCount(int);
method public abstract void asyncCommit();
method public abstract android.view.ViewAssistStructure asyncNewChild(int);
method public abstract int getChildCount();
@@ -42131,14 +42146,14 @@
ctor public ActionMenuView(android.content.Context, android.util.AttributeSet);
method public void dismissPopupMenus();
method public android.view.Menu getMenu();
+ method public android.graphics.drawable.Drawable getOverflowIcon();
method public int getPopupTheme();
method public boolean hideOverflowMenu();
method public boolean isOverflowMenuShowing();
method public void onConfigurationChanged(android.content.res.Configuration);
method public void onDetachedFromWindow();
method public void setOnMenuItemClickListener(android.widget.ActionMenuView.OnMenuItemClickListener);
- method public void setOverflowTintList(android.content.res.ColorStateList);
- method public void setOverflowTintMode(android.graphics.PorterDuff.Mode);
+ method public void setOverflowIcon(android.graphics.drawable.Drawable);
method public void setPopupTheme(int);
method public boolean showOverflowMenu();
}
@@ -44428,6 +44443,7 @@
method public android.view.Menu getMenu();
method public java.lang.CharSequence getNavigationContentDescription();
method public android.graphics.drawable.Drawable getNavigationIcon();
+ method public android.graphics.drawable.Drawable getOverflowIcon();
method public int getPopupTheme();
method public java.lang.CharSequence getSubtitle();
method public java.lang.CharSequence getTitle();
@@ -44447,11 +44463,8 @@
method public void setNavigationIcon(int);
method public void setNavigationIcon(android.graphics.drawable.Drawable);
method public void setNavigationOnClickListener(android.view.View.OnClickListener);
- method public void setNavigationTintList(android.content.res.ColorStateList);
- method public void setNavigationTintMode(android.graphics.PorterDuff.Mode);
method public void setOnMenuItemClickListener(android.widget.Toolbar.OnMenuItemClickListener);
- method public void setOverflowTintList(android.content.res.ColorStateList);
- method public void setOverflowTintMode(android.graphics.PorterDuff.Mode);
+ method public void setOverflowIcon(android.graphics.drawable.Drawable);
method public void setPopupTheme(int);
method public void setSubtitle(int);
method public void setSubtitle(java.lang.CharSequence);
diff --git a/api/system-removed.txt b/api/system-removed.txt
index 0046a70..f6ad27b 100644
--- a/api/system-removed.txt
+++ b/api/system-removed.txt
@@ -1,12 +1,3 @@
-package android {
-
- public static final class Manifest.permission {
- field public static final java.lang.String SUBSCRIBED_FEEDS_READ = "android.permission.SUBSCRIBED_FEEDS_READ";
- field public static final java.lang.String SUBSCRIBED_FEEDS_WRITE = "android.permission.SUBSCRIBED_FEEDS_WRITE";
- }
-
-}
-
package android.content.pm {
public class PackageInfo implements android.os.Parcelable {
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index b0a7dc7..bf3b4559 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -305,11 +305,23 @@
" [--eu <EXTRA_KEY> <EXTRA_URI_VALUE> ...]\n" +
" [--ecn <EXTRA_KEY> <EXTRA_COMPONENT_NAME_VALUE>]\n" +
" [--eia <EXTRA_KEY> <EXTRA_INT_VALUE>[,<EXTRA_INT_VALUE...]]\n" +
+ " (mutiple extras passed as Integer[])\n" +
+ " [--eial <EXTRA_KEY> <EXTRA_INT_VALUE>[,<EXTRA_INT_VALUE...]]\n" +
+ " (mutiple extras passed as List<Integer>)\n" +
" [--ela <EXTRA_KEY> <EXTRA_LONG_VALUE>[,<EXTRA_LONG_VALUE...]]\n" +
+ " (mutiple extras passed as Long[])\n" +
+ " [--elal <EXTRA_KEY> <EXTRA_LONG_VALUE>[,<EXTRA_LONG_VALUE...]]\n" +
+ " (mutiple extras passed as List<Long>)\n" +
" [--efa <EXTRA_KEY> <EXTRA_FLOAT_VALUE>[,<EXTRA_FLOAT_VALUE...]]\n" +
+ " (mutiple extras passed as Float[])\n" +
+ " [--efal <EXTRA_KEY> <EXTRA_FLOAT_VALUE>[,<EXTRA_FLOAT_VALUE...]]\n" +
+ " (mutiple extras passed as List<Float>)\n" +
" [--esa <EXTRA_KEY> <EXTRA_STRING_VALUE>[,<EXTRA_STRING_VALUE...]]\n" +
- " (to embed a comma into a string escape it using \"\\,\")\n" +
- " [-n <COMPONENT>] [-p <PACKAGE>] [-f <FLAGS>]\n" +
+ " (mutiple extras passed as String[]; to embed a comma into a string,\n" +
+ " escape it using \"\\,\")\n" +
+ " [--esal <EXTRA_KEY> <EXTRA_STRING_VALUE>[,<EXTRA_STRING_VALUE...]]\n" +
+ " (mutiple extras passed as List<String>; to embed a comma into a string,\n" +
+ " escape it using \"\\,\")\n" +
" [--grant-read-uri-permission] [--grant-write-uri-permission]\n" +
" [--grant-persistable-uri-permission] [--grant-prefix-uri-permission]\n" +
" [--debug-log-resolution] [--exclude-stopped-packages]\n" +
@@ -490,6 +502,15 @@
list[i] = Integer.decode(strings[i]);
}
intent.putExtra(key, list);
+ } else if (opt.equals("--eial")) {
+ String key = nextArgRequired();
+ String value = nextArgRequired();
+ String[] strings = value.split(",");
+ ArrayList<Integer> list = new ArrayList<>(strings.length);
+ for (int i = 0; i < strings.length; i++) {
+ list.add(Integer.decode(strings[i]));
+ }
+ intent.putExtra(key, list);
} else if (opt.equals("--el")) {
String key = nextArgRequired();
String value = nextArgRequired();
@@ -504,6 +525,16 @@
}
intent.putExtra(key, list);
hasIntentInfo = true;
+ } else if (opt.equals("--elal")) {
+ String key = nextArgRequired();
+ String value = nextArgRequired();
+ String[] strings = value.split(",");
+ ArrayList<Long> list = new ArrayList<>(strings.length);
+ for (int i = 0; i < strings.length; i++) {
+ list.add(Long.valueOf(strings[i]));
+ }
+ intent.putExtra(key, list);
+ hasIntentInfo = true;
} else if (opt.equals("--ef")) {
String key = nextArgRequired();
String value = nextArgRequired();
@@ -519,6 +550,16 @@
}
intent.putExtra(key, list);
hasIntentInfo = true;
+ } else if (opt.equals("--efal")) {
+ String key = nextArgRequired();
+ String value = nextArgRequired();
+ String[] strings = value.split(",");
+ ArrayList<Float> list = new ArrayList<>(strings.length);
+ for (int i = 0; i < strings.length; i++) {
+ list.add(Float.valueOf(strings[i]));
+ }
+ intent.putExtra(key, list);
+ hasIntentInfo = true;
} else if (opt.equals("--esa")) {
String key = nextArgRequired();
String value = nextArgRequired();
@@ -528,6 +569,19 @@
String[] strings = value.split("(?<!\\\\),");
intent.putExtra(key, strings);
hasIntentInfo = true;
+ } else if (opt.equals("--esal")) {
+ String key = nextArgRequired();
+ String value = nextArgRequired();
+ // Split on commas unless they are preceeded by an escape.
+ // The escape character must be escaped for the string and
+ // again for the regex, thus four escape characters become one.
+ String[] strings = value.split("(?<!\\\\),");
+ ArrayList<String> list = new ArrayList<>(strings.length);
+ for (int i = 0; i < strings.length; i++) {
+ list.add(strings[i]);
+ }
+ intent.putExtra(key, list);
+ hasIntentInfo = true;
} else if (opt.equals("--ez")) {
String key = nextArgRequired();
String value = nextArgRequired().toLowerCase();
diff --git a/cmds/screencap/screencap.cpp b/cmds/screencap/screencap.cpp
index dbc35af..c469ae4 100644
--- a/cmds/screencap/screencap.cpp
+++ b/cmds/screencap/screencap.cpp
@@ -30,6 +30,7 @@
#include <gui/SurfaceComposerClient.h>
#include <gui/ISurfaceComposer.h>
+#include <ui/DisplayInfo.h>
#include <ui/PixelFormat.h>
// TODO: Fix Skia.
@@ -159,9 +160,35 @@
uint32_t w, s, h, f;
size_t size = 0;
+ // Maps orientations from DisplayInfo to ISurfaceComposer
+ static const uint32_t ORIENTATION_MAP[] = {
+ ISurfaceComposer::eRotateNone, // 0 == DISPLAY_ORIENTATION_0
+ ISurfaceComposer::eRotate270, // 1 == DISPLAY_ORIENTATION_90
+ ISurfaceComposer::eRotate180, // 2 == DISPLAY_ORIENTATION_180
+ ISurfaceComposer::eRotate90, // 3 == DISPLAY_ORIENTATION_270
+ };
+
ScreenshotClient screenshot;
sp<IBinder> display = SurfaceComposerClient::getBuiltInDisplay(displayId);
- if (display != NULL && screenshot.update(display, Rect(), false) == NO_ERROR) {
+ if (display == NULL) {
+ fprintf(stderr, "Unable to get handle for display %d\n", displayId);
+ return 1;
+ }
+
+ Vector<DisplayInfo> configs;
+ SurfaceComposerClient::getDisplayConfigs(display, &configs);
+ int activeConfig = SurfaceComposerClient::getActiveConfig(display);
+ if (static_cast<size_t>(activeConfig) >= configs.size()) {
+ fprintf(stderr, "Active config %d not inside configs (size %zu)\n",
+ activeConfig, configs.size());
+ return 1;
+ }
+ uint8_t displayOrientation = configs[activeConfig].orientation;
+ uint32_t captureOrientation = ORIENTATION_MAP[displayOrientation];
+
+ status_t result = screenshot.update(display, Rect(), 0, 0, 0, -1U,
+ false, captureOrientation);
+ if (result == NO_ERROR) {
base = screenshot.getPixels();
w = screenshot.getWidth();
h = screenshot.getHeight();
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java
index 31e129b..993b53d 100644
--- a/core/java/android/accounts/AccountManager.java
+++ b/core/java/android/accounts/AccountManager.java
@@ -51,10 +51,7 @@
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
-import static android.Manifest.permission.AUTHENTICATE_ACCOUNTS;
import static android.Manifest.permission.GET_ACCOUNTS;
-import static android.Manifest.permission.MANAGE_ACCOUNTS;
-import static android.Manifest.permission.USE_CREDENTIALS;
/**
* This class provides access to a centralized registry of the user's
@@ -319,14 +316,12 @@
*
* <p>It is safe to call this method from the main thread.
*
- * <p>This method requires the caller to hold the permission
- * {@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS}
- * and to have the same UID as the account's authenticator.
+ * <p>This method requires the caller to have a signature match with the
+ * authenticator that owns the specified account.
*
- * @param account The account to query for a password
+ * @param account The account to query for a password. Must not be {@code null}.
* @return The account's password, null if none or if the account doesn't exist
*/
- @RequiresPermission(AUTHENTICATE_ACCOUNTS)
public String getPassword(final Account account) {
if (account == null) throw new IllegalArgumentException("account is null");
try {
@@ -345,14 +340,12 @@
*
* <p>It is safe to call this method from the main thread.
*
- * <p>This method requires the caller to hold the permission
- * {@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS}
- * and to have the same UID as the account's authenticator.
+ * <p>This method requires the caller to have a signature match with the
+ * authenticator that owns the specified account.
*
* @param account The account to query for user data
* @return The user data, null if the account or key doesn't exist
*/
- @RequiresPermission(AUTHENTICATE_ACCOUNTS)
public String getUserData(final Account account, final String key) {
if (account == null) throw new IllegalArgumentException("account is null");
if (key == null) throw new IllegalArgumentException("key is null");
@@ -662,10 +655,8 @@
* wizards associated with authenticators, not directly by applications.
*
* <p>It is safe to call this method from the main thread.
- *
- * <p>This method requires the caller to hold the permission
- * {@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS}
- * and to have the same UID as the added account's authenticator.
+ * <p>This method requires the caller to have a signature match with the
+ * authenticator that owns the specified account.
*
* @param account The {@link Account} to add
* @param password The password to associate with the account, null for none
@@ -673,7 +664,6 @@
* @return True if the account was successfully added, false if the account
* already exists, the account is null, or another error occurs.
*/
- @RequiresPermission(AUTHENTICATE_ACCOUNTS)
public boolean addAccountExplicitly(Account account, String password, Bundle userdata) {
if (account == null) throw new IllegalArgumentException("account is null");
try {
@@ -692,14 +682,13 @@
* <p>
* It is not safe to call this method from the main thread. As such, call it
* from another thread.
- * <p>
- * This method requires the caller to hold the permission
- * {@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS} and should be
- * called from the account's authenticator.
+ * <p>This method requires the caller to have a signature match with the
+ * authenticator that owns the specified account.
*
* @param account The {@link Account} to be updated.
+ * @return boolean {@code true} if the authentication of the account has been successfully
+ * acknowledged. Otherwise {@code false}.
*/
- @RequiresPermission(AUTHENTICATE_ACCOUNTS)
public boolean notifyAccountAuthenticated(Account account) {
if (account == null)
throw new IllegalArgumentException("account is null");
@@ -717,9 +706,8 @@
*
* <p>It is safe to call this method from the main thread.
*
- * <p>This method requires the caller to hold the permission
- * {@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS}
- * and have the same UID as the account's authenticator.
+ * <p>This method requires the caller to have a signature match with the
+ * authenticator that manages the specified account.
*
* @param account The {@link Account} to rename
* @param newName String name to be associated with the account.
@@ -731,7 +719,6 @@
* after the name change. If successful the account's name will be the
* specified new name.
*/
- @RequiresPermission(AUTHENTICATE_ACCOUNTS)
public AccountManagerFuture<Account> renameAccount(
final Account account,
@Size(min = 1) final String newName,
@@ -783,11 +770,8 @@
* The authenticator may have its own policies preventing account
* deletion, in which case the account will not be deleted.
*
- * <p>This method may be called from any thread, but the returned
- * {@link AccountManagerFuture} must not be used on the main thread.
- *
- * <p>This method requires the caller to hold the permission
- * {@link android.Manifest.permission#MANAGE_ACCOUNTS}.
+ * <p>This method requires the caller to have a signature match with the
+ * authenticator that manages the specified account.
*
* @param account The {@link Account} to remove
* @param callback Callback to invoke when the request completes,
@@ -800,15 +784,16 @@
* {@link #removeAccount(Account, Activity, AccountManagerCallback, Handler)}
* instead
*/
- @RequiresPermission(MANAGE_ACCOUNTS)
@Deprecated
public AccountManagerFuture<Boolean> removeAccount(final Account account,
AccountManagerCallback<Boolean> callback, Handler handler) {
if (account == null) throw new IllegalArgumentException("account is null");
return new Future2Task<Boolean>(handler, callback) {
+ @Override
public void doWork() throws RemoteException {
mService.removeAccount(mResponse, account, false);
}
+ @Override
public Boolean bundleToResult(Bundle bundle) throws AuthenticatorException {
if (!bundle.containsKey(KEY_BOOLEAN_RESULT)) {
throw new AuthenticatorException("no result in response");
@@ -827,8 +812,8 @@
* <p>This method may be called from any thread, but the returned
* {@link AccountManagerFuture} must not be used on the main thread.
*
- * <p>This method requires the caller to hold the permission
- * {@link android.Manifest.permission#MANAGE_ACCOUNTS}.
+ * <p>This method requires the caller to have a signature match with the
+ * authenticator that manages the specified account.
*
* @param account The {@link Account} to remove
* @param activity The {@link Activity} context to use for launching a new
@@ -855,11 +840,11 @@
* adding accounts (of this type) has been disabled by policy
* </ul>
*/
- @RequiresPermission(MANAGE_ACCOUNTS)
public AccountManagerFuture<Bundle> removeAccount(final Account account,
final Activity activity, AccountManagerCallback<Bundle> callback, Handler handler) {
if (account == null) throw new IllegalArgumentException("account is null");
return new AmsTask(activity, handler, callback) {
+ @Override
public void doWork() throws RemoteException {
mService.removeAccount(mResponse, account, activity != null);
}
@@ -880,9 +865,11 @@
if (account == null) throw new IllegalArgumentException("account is null");
if (userHandle == null) throw new IllegalArgumentException("userHandle is null");
return new Future2Task<Boolean>(handler, callback) {
+ @Override
public void doWork() throws RemoteException {
mService.removeAccountAsUser(mResponse, account, false, userHandle.getIdentifier());
}
+ @Override
public Boolean bundleToResult(Bundle bundle) throws AuthenticatorException {
if (!bundle.containsKey(KEY_BOOLEAN_RESULT)) {
throw new AuthenticatorException("no result in response");
@@ -918,17 +905,14 @@
* in which case the account will not be deleted.
* <p>
* It is safe to call this method from the main thread.
- * <p>
- * This method requires the caller to hold the permission
- * {@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS} and to have the
- * same UID or signature as the account's authenticator.
+ * <p>This method requires the caller to have a signature match with the
+ * authenticator that manages the specified account.
*
* @param account The {@link Account} to delete.
* @return True if the account was successfully deleted, false if the
* account did not exist, the account is null, or another error
* occurs.
*/
- @RequiresPermission(AUTHENTICATE_ACCOUNTS)
public boolean removeAccountExplicitly(Account account) {
if (account == null) throw new IllegalArgumentException("account is null");
try {
@@ -948,14 +932,9 @@
*
* <p>It is safe to call this method from the main thread.
*
- * <p>This method requires the caller to hold the permission
- * {@link android.Manifest.permission#MANAGE_ACCOUNTS} or
- * {@link android.Manifest.permission#USE_CREDENTIALS}
- *
* @param accountType The account type of the auth token to invalidate, must not be null
* @param authToken The auth token to invalidate, may be null
*/
- @RequiresPermission(anyOf = {MANAGE_ACCOUNTS, USE_CREDENTIALS})
public void invalidateAuthToken(final String accountType, final String authToken) {
if (accountType == null) throw new IllegalArgumentException("accountType is null");
try {
@@ -976,16 +955,15 @@
*
* <p>It is safe to call this method from the main thread.
*
- * <p>This method requires the caller to hold the permission
- * {@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS}
- * and to have the same UID as the account's authenticator.
+ * <p>This method requires the caller to have a signature match with the
+ * authenticator that manages the specified account.
*
- * @param account The account to fetch an auth token for
- * @param authTokenType The type of auth token to fetch, see {#getAuthToken}
+ * @param account The account for which an auth token is to be fetched. Cannot be {@code null}.
+ * @param authTokenType The type of auth token to fetch. Cannot be {@code null}.
* @return The cached auth token for this account and type, or null if
* no auth token is cached or the account does not exist.
+ * @see #getAuthToken
*/
- @RequiresPermission(AUTHENTICATE_ACCOUNTS)
public String peekAuthToken(final Account account, final String authTokenType) {
if (account == null) throw new IllegalArgumentException("account is null");
if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
@@ -1005,14 +983,12 @@
*
* <p>It is safe to call this method from the main thread.
*
- * <p>This method requires the caller to hold the permission
- * {@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS}
- * and have the same UID as the account's authenticator.
+ * <p>This method requires the caller to have a signature match with the
+ * authenticator that manages the specified account.
*
- * @param account The account to set a password for
+ * @param account The account whose password is to be set. Cannot be {@code null}.
* @param password The password to set, null to clear the password
*/
- @RequiresPermission(AUTHENTICATE_ACCOUNTS)
public void setPassword(final Account account, final String password) {
if (account == null) throw new IllegalArgumentException("account is null");
try {
@@ -1030,14 +1006,14 @@
* permissions, and may be used by applications or management interfaces
* to "sign out" from an account.
*
- * <p>It is safe to call this method from the main thread.
+ * <p>This method only successfully clear the account's password when the
+ * caller has the same signature as the authenticator that owns the
+ * specified account. Otherwise, this method will silently fail.
*
- * <p>This method requires the caller to hold the permission
- * {@link android.Manifest.permission#MANAGE_ACCOUNTS}
+ * <p>It is safe to call this method from the main thread.
*
* @param account The account whose password to clear
*/
- @RequiresPermission(MANAGE_ACCOUNTS)
public void clearPassword(final Account account) {
if (account == null) throw new IllegalArgumentException("account is null");
try {
@@ -1055,15 +1031,13 @@
*
* <p>It is safe to call this method from the main thread.
*
- * <p>This method requires the caller to hold the permission
- * {@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS}
- * and to have the same UID as the account's authenticator.
+ * <p>This method requires the caller to have a signature match with the
+ * authenticator that manages the specified account.
*
- * @param account The account to set the userdata for
- * @param key The userdata key to set. Must not be null
- * @param value The value to set, null to clear this userdata key
+ * @param account Account whose user data is to be set. Must not be {@code null}.
+ * @param key String user data key to set. Must not be null
+ * @param value String value to set, {@code null} to clear this user data key
*/
- @RequiresPermission(AUTHENTICATE_ACCOUNTS)
public void setUserData(final Account account, final String key, final String value) {
if (account == null) throw new IllegalArgumentException("account is null");
if (key == null) throw new IllegalArgumentException("key is null");
@@ -1083,15 +1057,13 @@
*
* <p>It is safe to call this method from the main thread.
*
- * <p>This method requires the caller to hold the permission
- * {@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS}
- * and to have the same UID as the account's authenticator.
+ * <p>This method requires the caller to have a signature match with the
+ * authenticator that manages the specified account.
*
* @param account The account to set an auth token for
* @param authTokenType The type of the auth token, see {#getAuthToken}
* @param authToken The auth token to add to the cache
*/
- @RequiresPermission(AUTHENTICATE_ACCOUNTS)
public void setAuthToken(Account account, final String authTokenType, final String authToken) {
if (account == null) throw new IllegalArgumentException("account is null");
if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
@@ -1110,9 +1082,6 @@
* <p>This method may block while a network request completes, and must
* never be made from the main thread.
*
- * <p>This method requires the caller to hold the permission
- * {@link android.Manifest.permission#USE_CREDENTIALS}.
- *
* @param account The account to fetch an auth token for
* @param authTokenType The auth token type, see {@link #getAuthToken getAuthToken()}
* @param notifyAuthFailure If true, display a notification and return null
@@ -1126,7 +1095,6 @@
* @throws java.io.IOException if the authenticator experienced an I/O problem
* creating a new auth token, usually because of network trouble
*/
- @RequiresPermission(USE_CREDENTIALS)
public String blockingGetAuthToken(Account account, String authTokenType,
boolean notifyAuthFailure)
throws OperationCanceledException, IOException, AuthenticatorException {
@@ -1165,9 +1133,6 @@
* <p>This method may be called from any thread, but the returned
* {@link AccountManagerFuture} must not be used on the main thread.
*
- * <p>This method requires the caller to hold the permission
- * {@link android.Manifest.permission#USE_CREDENTIALS}.
- *
* @param account The account to fetch an auth token for
* @param authTokenType The auth token type, an authenticator-dependent
* string token, must not be null
@@ -1201,7 +1166,6 @@
* authenticator-dependent. The caller should verify the validity of the
* account before requesting an auth token.
*/
- @RequiresPermission(USE_CREDENTIALS)
public AccountManagerFuture<Bundle> getAuthToken(
final Account account, final String authTokenType, final Bundle options,
final Activity activity, AccountManagerCallback<Bundle> callback, Handler handler) {
@@ -1253,9 +1217,6 @@
* <p>This method may be called from any thread, but the returned
* {@link AccountManagerFuture} must not be used on the main thread.
*
- * <p>This method requires the caller to hold the permission
- * {@link android.Manifest.permission#USE_CREDENTIALS}.
- *
* @param account The account to fetch an auth token for
* @param authTokenType The auth token type, an authenticator-dependent
* string token, must not be null
@@ -1292,7 +1253,6 @@
* boolean, AccountManagerCallback, android.os.Handler)} instead
*/
@Deprecated
- @RequiresPermission(USE_CREDENTIALS)
public AccountManagerFuture<Bundle> getAuthToken(
final Account account, final String authTokenType,
final boolean notifyAuthFailure,
@@ -1333,9 +1293,6 @@
* <p>This method may be called from any thread, but the returned
* {@link AccountManagerFuture} must not be used on the main thread.
*
- * <p>This method requires the caller to hold the permission
- * {@link android.Manifest.permission#USE_CREDENTIALS}.
- *
* @param account The account to fetch an auth token for
* @param authTokenType The auth token type, an authenticator-dependent
* string token, must not be null
@@ -1371,7 +1328,6 @@
* authenticator-dependent. The caller should verify the validity of the
* account before requesting an auth token.
*/
- @RequiresPermission(USE_CREDENTIALS)
public AccountManagerFuture<Bundle> getAuthToken(
final Account account, final String authTokenType, final Bundle options,
final boolean notifyAuthFailure,
@@ -1401,9 +1357,6 @@
* <p>This method may be called from any thread, but the returned
* {@link AccountManagerFuture} must not be used on the main thread.
*
- * <p>This method requires the caller to hold the permission
- * {@link android.Manifest.permission#MANAGE_ACCOUNTS}.
- *
* @param accountType The type of account to add; must not be null
* @param authTokenType The type of auth token (see {@link #getAuthToken})
* this account will need to be able to generate, null for none
@@ -1441,7 +1394,6 @@
* creating a new account, usually because of network trouble
* </ul>
*/
- @RequiresPermission(MANAGE_ACCOUNTS)
public AccountManagerFuture<Bundle> addAccount(final String accountType,
final String authTokenType, final String[] requiredFeatures,
final Bundle addAccountOptions,
@@ -1586,9 +1538,6 @@
* <p>This method may be called from any thread, but the returned
* {@link AccountManagerFuture} must not be used on the main thread.
*
- * <p>This method requires the caller to hold the permission
- * {@link android.Manifest.permission#MANAGE_ACCOUNTS}.
- *
* @param account The account to confirm password knowledge for
* @param options Authenticator-specific options for the request;
* if the {@link #KEY_PASSWORD} string field is present, the
@@ -1615,11 +1564,11 @@
* If no activity or password was specified, the returned Bundle contains
* {@link #KEY_INTENT} with the {@link Intent} needed to launch the
* password prompt.
- *
+ *
* <p>Also the returning Bundle may contain {@link
* #KEY_LAST_AUTHENTICATED_TIME} indicating the last time the
* credential was validated/created.
- *
+ *
* If an error occurred,{@link AccountManagerFuture#getResult()} throws:
* <ul>
* <li> {@link AuthenticatorException} if the authenticator failed to respond
@@ -1629,7 +1578,6 @@
* verifying the password, usually because of network trouble
* </ul>
*/
- @RequiresPermission(MANAGE_ACCOUNTS)
public AccountManagerFuture<Bundle> confirmCredentials(final Account account,
final Bundle options,
final Activity activity,
@@ -1668,9 +1616,6 @@
* <p>This method may be called from any thread, but the returned
* {@link AccountManagerFuture} must not be used on the main thread.
*
- * <p>This method requires the caller to hold the permission
- * {@link android.Manifest.permission#MANAGE_ACCOUNTS}.
- *
* @param account The account to update credentials for
* @param authTokenType The credentials entered must allow an auth token
* of this type to be created (but no actual auth token is returned);
@@ -1706,7 +1651,6 @@
* verifying the password, usually because of network trouble
* </ul>
*/
- @RequiresPermission(MANAGE_ACCOUNTS)
public AccountManagerFuture<Bundle> updateCredentials(final Account account,
final String authTokenType,
final Bundle options, final Activity activity,
@@ -1729,8 +1673,8 @@
* <p>This method may be called from any thread, but the returned
* {@link AccountManagerFuture} must not be used on the main thread.
*
- * <p>This method requires the caller to hold the permission
- * {@link android.Manifest.permission#MANAGE_ACCOUNTS}.
+ * <p>This method requires the caller to have the same signature as the
+ * authenticator associated with the specified account type.
*
* @param accountType The account type associated with the authenticator
* to adjust
@@ -1758,7 +1702,6 @@
* updating settings, usually because of network trouble
* </ul>
*/
- @RequiresPermission(MANAGE_ACCOUNTS)
public AccountManagerFuture<Bundle> editProperties(final String accountType,
final Activity activity, final AccountManagerCallback<Bundle> callback,
final Handler handler) {
@@ -2253,9 +2196,6 @@
* <p>This method may be called from any thread, but the returned
* {@link AccountManagerFuture} must not be used on the main thread.
*
- * <p>This method requires the caller to hold the permission
- * {@link android.Manifest.permission#MANAGE_ACCOUNTS}.
- *
* @param accountType The account type required
* (see {@link #getAccountsByType}), must not be null
* @param authTokenType The desired auth token type
@@ -2292,7 +2232,6 @@
* updating settings, usually because of network trouble
* </ul>
*/
- @RequiresPermission(MANAGE_ACCOUNTS)
public AccountManagerFuture<Bundle> getAuthTokenByFeatures(
final String accountType, final String authTokenType, final String[] features,
final Activity activity, final Bundle addAccountOptions,
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index da345a6..b65593d 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -2812,7 +2812,9 @@
* continues running even if the process is killed and restarted. To remove the watch,
* use {@link #clearWatchHeapLimit()}.
*
- * <p>This API only work if running on a debuggable (userdebug or eng) build.</p>
+ * <p>This API only work if the calling process has been marked as
+ * {@link ApplicationInfo#FLAG_DEBUGGABLE} or this is running on a debuggable
+ * (userdebug or eng) build.</p>
*
* <p>Callers can optionally implement {@link #ACTION_REPORT_HEAP_LIMIT} to directly
* handle heap limit reports themselves.</p>
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 41e3db8..cb1e7aa 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -31,6 +31,7 @@
import android.content.pm.ComponentInfo;
import android.content.pm.ContainerEncryptionParams;
import android.content.pm.FeatureInfo;
+import android.content.pm.IOnPermissionsChangeListener;
import android.content.pm.IPackageDataObserver;
import android.content.pm.IPackageDeleteObserver;
import android.content.pm.IPackageInstallObserver;
@@ -88,6 +89,7 @@
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
+import java.util.Map;
import java.util.Objects;
/*package*/
@@ -1048,6 +1050,38 @@
}
}
+ @Override
+ public void addOnPermissionsChangeListener(OnPermissionsChangedListener listener) {
+ synchronized (mPermissionListeners) {
+ if (mPermissionListeners.get(listener) != null) {
+ return;
+ }
+ OnPermissionsChangeListenerDelegate delegate =
+ new OnPermissionsChangeListenerDelegate(listener, Looper.getMainLooper());
+ try {
+ mPM.addOnPermissionsChangeListener(delegate);
+ mPermissionListeners.put(listener, delegate);
+ } catch (RemoteException e) {
+ throw new RuntimeException("Package manager has died", e);
+ }
+ }
+ }
+
+ @Override
+ public void removeOnPermissionsChangeListener(OnPermissionsChangedListener listener) {
+ synchronized (mPermissionListeners) {
+ IOnPermissionsChangeListener delegate = mPermissionListeners.get(listener);
+ if (delegate != null) {
+ try {
+ mPM.removeOnPermissionsChangeListener(delegate);
+ mPermissionListeners.remove(listener);
+ } catch (RemoteException e) {
+ throw new RuntimeException("Package manager has died", e);
+ }
+ }
+ }
+ }
+
static void configurationChanged() {
synchronized (sSync) {
sIconCache.clear();
@@ -2139,4 +2173,39 @@
= new ArrayMap<ResourceName, WeakReference<Drawable.ConstantState>>();
private static ArrayMap<ResourceName, WeakReference<CharSequence>> sStringCache
= new ArrayMap<ResourceName, WeakReference<CharSequence>>();
+
+ private final Map<OnPermissionsChangedListener, IOnPermissionsChangeListener>
+ mPermissionListeners = new ArrayMap<>();
+
+ public class OnPermissionsChangeListenerDelegate extends IOnPermissionsChangeListener.Stub
+ implements Handler.Callback{
+ private static final int MSG_PERMISSIONS_CHANGED = 1;
+
+ private final OnPermissionsChangedListener mListener;
+ private final Handler mHandler;
+
+
+ public OnPermissionsChangeListenerDelegate(OnPermissionsChangedListener listener,
+ Looper looper) {
+ mListener = listener;
+ mHandler = new Handler(looper, this);
+ }
+
+ @Override
+ public void onPermissionsChanged(int uid) {
+ mHandler.obtainMessage(MSG_PERMISSIONS_CHANGED, uid, 0).sendToTarget();
+ }
+
+ @Override
+ public boolean handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_PERMISSIONS_CHANGED: {
+ final int uid = msg.arg1;
+ mListener.onPermissionsChanged(uid);
+ return true;
+ }
+ }
+ return false;
+ }
+ }
}
diff --git a/core/java/android/app/AssistContent.java b/core/java/android/app/AssistContent.java
index 173b237..0df9ce5 100644
--- a/core/java/android/app/AssistContent.java
+++ b/core/java/android/app/AssistContent.java
@@ -35,6 +35,7 @@
private Intent mIntent;
private ClipData mClipData;
private Uri mUri;
+ private final Bundle mExtras;
/**
* @hide
@@ -53,6 +54,7 @@
}
public AssistContent() {
+ mExtras = new Bundle();
}
/**
@@ -143,6 +145,13 @@
return mUri;
}
+ /**
+ * Return Bundle for extra vendor-specific data that can be modified and examined.
+ */
+ public Bundle getExtras() {
+ return mExtras;
+ }
+
/** @hide */
public AssistContent(Parcel in) {
if (in.readInt() != 0) {
@@ -155,6 +164,7 @@
mUri = Uri.CREATOR.createFromParcel(in);
}
mIsAppProvidedIntent = in.readInt() == 1;
+ mExtras = in.readBundle();
}
/** @hide */
@@ -178,5 +188,6 @@
dest.writeInt(0);
}
dest.writeInt(mIsAppProvidedIntent ? 1 : 0);
+ dest.writeBundle(mExtras);
}
}
diff --git a/core/java/android/app/AssistStructure.java b/core/java/android/app/AssistStructure.java
index 0f69817..7f6dae5 100644
--- a/core/java/android/app/AssistStructure.java
+++ b/core/java/android/app/AssistStructure.java
@@ -131,6 +131,7 @@
final int mWidth;
final int mHeight;
final CharSequence mTitle;
+ final int mDisplayId;
final ViewNode mRoot;
WindowNode(AssistStructure assist, ViewRootImpl root) {
@@ -142,6 +143,7 @@
mWidth = rect.width();
mHeight = rect.height();
mTitle = root.getTitle();
+ mDisplayId = root.getDisplayId();
mRoot = new ViewNode();
ViewNodeBuilder builder = new ViewNodeBuilder(assist, mRoot, false);
if ((root.getWindowFlags()&WindowManager.LayoutParams.FLAG_SECURE) != 0) {
@@ -160,6 +162,7 @@
mWidth = in.readInt();
mHeight = in.readInt();
mTitle = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
+ mDisplayId = in.readInt();
mRoot = new ViewNode(in, preader);
}
@@ -169,29 +172,58 @@
out.writeInt(mWidth);
out.writeInt(mHeight);
TextUtils.writeToParcel(mTitle, out, 0);
+ out.writeInt(mDisplayId);
mRoot.writeToParcel(out, pwriter);
}
+ /**
+ * Returns the left edge of the window, in pixels, relative to the left
+ * edge of the screen.
+ */
public int getLeft() {
return mX;
}
+ /**
+ * Returns the top edge of the window, in pixels, relative to the top
+ * edge of the screen.
+ */
public int getTop() {
return mY;
}
+ /**
+ * Returns the total width of the window in pixels.
+ */
public int getWidth() {
return mWidth;
}
+ /**
+ * Returns the total height of the window in pixels.
+ */
public int getHeight() {
return mHeight;
}
+ /**
+ * Returns the title associated with the window, if it has one.
+ */
public CharSequence getTitle() {
return mTitle;
}
+ /**
+ * Returns the ID of the display this window is on, for use with
+ * {@link android.hardware.display.DisplayManager#getDisplay DisplayManager.getDisplay()}.
+ */
+ public int getDisplayId() {
+ return mDisplayId;
+ }
+
+ /**
+ * Returns the {@link ViewNode} containing the root content of the window.
+ */
public ViewNode getRootViewNode() {
return mRoot;
}
@@ -325,146 +357,288 @@
}
}
+ /**
+ * Returns the ID associated with this view, as per {@link View#getId() View.getId()}.
+ */
public int getId() {
return mId;
}
+ /**
+ * If {@link #getId()} is a resource identifier, this is the package name of that
+ * identifier. See {@link android.view.ViewStructure#setId ViewStructure.setId}
+ * for more information.
+ */
public String getIdPackage() {
return mIdPackage;
}
+ /**
+ * If {@link #getId()} is a resource identifier, this is the type name of that
+ * identifier. See {@link android.view.ViewStructure#setId ViewStructure.setId}
+ * for more information.
+ */
public String getIdType() {
return mIdType;
}
+ /**
+ * If {@link #getId()} is a resource identifier, this is the entry name of that
+ * identifier. See {@link android.view.ViewStructure#setId ViewStructure.setId}
+ * for more information.
+ */
public String getIdEntry() {
return mIdEntry;
}
+ /**
+ * Returns the left edge of this view, in pixels, relative to the left edge of its parent.
+ */
public int getLeft() {
return mX;
}
+ /**
+ * Returns the top edge of this view, in pixels, relative to the top edge of its parent.
+ */
public int getTop() {
return mY;
}
+ /**
+ * Returns the current X scroll offset of this view, as per
+ * {@link android.view.View#getScrollX() View.getScrollX()}.
+ */
public int getScrollX() {
return mScrollX;
}
+ /**
+ * Returns the current Y scroll offset of this view, as per
+ * {@link android.view.View#getScrollX() View.getScrollY()}.
+ */
public int getScrollY() {
return mScrollY;
}
+ /**
+ * Returns the width of this view, in pixels.
+ */
public int getWidth() {
return mWidth;
}
+ /**
+ * Returns the height of this view, in pixels.
+ */
public int getHeight() {
return mHeight;
}
+ /**
+ * Returns the visibility mode of this view, as per
+ * {@link android.view.View#getVisibility() View.getVisibility()}.
+ */
public int getVisibility() {
return mFlags&ViewNode.FLAGS_VISIBILITY_MASK;
}
+ /**
+ * Returns true if assist data has been blocked starting at this node in the hierarchy.
+ */
public boolean isAssistBlocked() {
return (mFlags&ViewNode.FLAGS_ASSIST_BLOCKED) == 0;
}
+ /**
+ * Returns true if this node is in an enabled state.
+ */
public boolean isEnabled() {
return (mFlags&ViewNode.FLAGS_DISABLED) == 0;
}
+ /**
+ * Returns true if this node is clickable by the user.
+ */
public boolean isClickable() {
return (mFlags&ViewNode.FLAGS_CLICKABLE) != 0;
}
+ /**
+ * Returns true if this node can take input focus.
+ */
public boolean isFocusable() {
return (mFlags&ViewNode.FLAGS_FOCUSABLE) != 0;
}
+ /**
+ * Returns true if this node currently had input focus at the time that the
+ * structure was collected.
+ */
public boolean isFocused() {
return (mFlags&ViewNode.FLAGS_FOCUSED) != 0;
}
+ /**
+ * Returns true if this node currently had accessibility focus at the time that the
+ * structure was collected.
+ */
public boolean isAccessibilityFocused() {
return (mFlags&ViewNode.FLAGS_ACCESSIBILITY_FOCUSED) != 0;
}
+ /**
+ * Returns true if this node represents something that is checkable by the user.
+ */
public boolean isCheckable() {
return (mFlags&ViewNode.FLAGS_CHECKABLE) != 0;
}
+ /**
+ * Returns true if this node is currently in a checked state.
+ */
public boolean isChecked() {
return (mFlags&ViewNode.FLAGS_CHECKED) != 0;
}
+ /**
+ * Returns true if this node has currently been selected by the user.
+ */
public boolean isSelected() {
return (mFlags&ViewNode.FLAGS_SELECTED) != 0;
}
+ /**
+ * Returns true if this node has currently been activated by the user.
+ */
public boolean isActivated() {
return (mFlags&ViewNode.FLAGS_ACTIVATED) != 0;
}
+ /**
+ * Returns true if this node is something the user can perform a long click/press on.
+ */
public boolean isLongClickable() {
return (mFlags&ViewNode.FLAGS_LONG_CLICKABLE) != 0;
}
+ /**
+ * Returns true if this node is something the user can perform a context click on.
+ */
public boolean isContextClickable() {
return (mFlags&ViewNode.FLAGS_CONTEXT_CLICKABLE) != 0;
}
+ /**
+ * Returns the class name of the node's implementation, indicating its behavior.
+ * For example, a button will report "android.widget.Button" meaning it behaves
+ * like a {@link android.widget.Button}.
+ */
public String getClassName() {
return mClassName;
}
+ /**
+ * Returns any content description associated with the node, which semantically describes
+ * its purpose for accessibility and other uses.
+ */
public CharSequence getContentDescription() {
return mContentDescription;
}
+ /**
+ * Returns any text associated with the node that is displayed to the user, or null
+ * if there is none.
+ */
public CharSequence getText() {
return mText != null ? mText.mText : null;
}
+ /**
+ * If {@link #getText()} is non-null, this is where the current selection starts.
+ */
public int getTextSelectionStart() {
return mText != null ? mText.mTextSelectionStart : -1;
}
+ /**
+ * If {@link #getText()} is non-null, this is where the current selection starts.
+ * If there is no selection, returns the same value as {@link #getTextSelectionStart()},
+ * indicating the cursor position.
+ */
public int getTextSelectionEnd() {
return mText != null ? mText.mTextSelectionEnd : -1;
}
+ /**
+ * If {@link #getText()} is non-null, this is the main text color associated with it.
+ * If there is no text color, {@link #TEXT_COLOR_UNDEFINED} is returned.
+ * Note that the text may also contain style spans that modify the color of specific
+ * parts of the text.
+ */
public int getTextColor() {
return mText != null ? mText.mTextColor : TEXT_COLOR_UNDEFINED;
}
+ /**
+ * If {@link #getText()} is non-null, this is the main text background color associated
+ * with it.
+ * If there is no text background color, {@link #TEXT_COLOR_UNDEFINED} is returned.
+ * Note that the text may also contain style spans that modify the color of specific
+ * parts of the text.
+ */
public int getTextBackgroundColor() {
return mText != null ? mText.mTextBackgroundColor : TEXT_COLOR_UNDEFINED;
}
+ /**
+ * If {@link #getText()} is non-null, this is the main text size (in pixels) associated
+ * with it.
+ * Note that the text may also contain style spans that modify the size of specific
+ * parts of the text.
+ */
public float getTextSize() {
return mText != null ? mText.mTextSize : 0;
}
+ /**
+ * If {@link #getText()} is non-null, this is the main text style associated
+ * with it, containing a bit mask of {@link #TEXT_STYLE_BOLD},
+ * {@link #TEXT_STYLE_BOLD}, {@link #TEXT_STYLE_STRIKE_THRU}, and/or
+ * {@link #TEXT_STYLE_UNDERLINE}.
+ * Note that the text may also contain style spans that modify the style of specific
+ * parts of the text.
+ */
public int getTextStyle() {
return mText != null ? mText.mTextStyle : 0;
}
+ /**
+ * Return additional hint text associated with the node; this is typically used with
+ * a node that takes user input, describing to the user what the input means.
+ */
public String getHint() {
return mText != null ? mText.mHint : null;
}
+ /**
+ * Return a Bundle containing optional vendor-specific extension information.
+ */
public Bundle getExtras() {
return mExtras;
}
+ /**
+ * Return the number of children this node has.
+ */
public int getChildCount() {
return mChildren != null ? mChildren.length : 0;
}
+ /**
+ * Return a child of this node, given an index value from 0 to
+ * {@link #getChildCount()}-1.
+ */
public ViewNode getChildAt(int index) {
return mChildren[index];
}
@@ -663,6 +837,19 @@
}
@Override
+ public int addChildCount(int num) {
+ if (mNode.mChildren == null) {
+ setChildCount(num);
+ return 0;
+ }
+ final int start = mNode.mChildren.length;
+ ViewNode[] newArray = new ViewNode[start + num];
+ System.arraycopy(mNode.mChildren, 0, newArray, 0, start);
+ mNode.mChildren = newArray;
+ return start;
+ }
+
+ @Override
public int getChildCount() {
return mNode.mChildren != null ? mNode.mChildren.length : 0;
}
@@ -801,6 +988,9 @@
return assistBundle.getParcelable(ASSIST_KEY);
}
+ /**
+ * Return the activity this AssistStructure came from.
+ */
public ComponentName getActivityComponent() {
ensureData();
return mActivityComponent;
diff --git a/core/java/android/app/DownloadManager.java b/core/java/android/app/DownloadManager.java
index 2ed8b0f..5327646 100644
--- a/core/java/android/app/DownloadManager.java
+++ b/core/java/android/app/DownloadManager.java
@@ -418,7 +418,7 @@
private int mNotificationVisibility = VISIBILITY_VISIBLE;
/**
- * @param uri the HTTP URI to download.
+ * @param uri the HTTP or HTTPS URI to download.
*/
public Request(Uri uri) {
if (uri == null) {
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index 9604789..c2bf28a 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -55,6 +55,7 @@
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URL;
+import java.util.List;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
@@ -166,6 +167,7 @@
if (runtimeIsa.equals(secondaryIsa)) {
final ApplicationInfo modified = new ApplicationInfo(info);
modified.nativeLibraryDir = modified.secondaryNativeLibraryDir;
+ modified.primaryCpuAbi = modified.secondaryCpuAbi;
return modified;
}
}
@@ -272,8 +274,9 @@
}
}
- final ArrayList<String> zipPaths = new ArrayList<>();
- final ArrayList<String> libPaths = new ArrayList<>();
+ final List<String> zipPaths = new ArrayList<>();
+ final List<String> apkPaths = new ArrayList<>();
+ final List<String> libPaths = new ArrayList<>();
if (mRegisterPackage) {
try {
@@ -329,6 +332,8 @@
}
}
+ apkPaths.addAll(zipPaths);
+
if (mSharedLibraries != null) {
for (String lib : mSharedLibraries) {
if (!zipPaths.contains(lib)) {
@@ -346,6 +351,14 @@
}
final String zip = TextUtils.join(File.pathSeparator, zipPaths);
+
+ // Add path to libraries in apk for current abi
+ if (mApplicationInfo.primaryCpuAbi != null) {
+ for (String apk : apkPaths) {
+ libPaths.add(apk + "!/lib/" + mApplicationInfo.primaryCpuAbi);
+ }
+ }
+
final String lib = TextUtils.join(File.pathSeparator, libPaths);
/*
diff --git a/core/java/android/app/Presentation.java b/core/java/android/app/Presentation.java
index bb45abb4..e110dcb 100644
--- a/core/java/android/app/Presentation.java
+++ b/core/java/android/app/Presentation.java
@@ -213,7 +213,7 @@
// dismiss the presentation immediately. This case is expected
// to be rare but surprising, so we'll write a log message about it.
if (!isConfigurationStillValid()) {
- Log.i(TAG, "Presentation is being immediately dismissed because the "
+ Log.i(TAG, "Presentation is being dismissed because the "
+ "display metrics have changed since it was created.");
mHandler.sendEmptyMessage(MSG_CANCEL);
}
@@ -274,6 +274,8 @@
// is invalid and the application must recreate the presentation to get
// a new context.
if (!isConfigurationStillValid()) {
+ Log.i(TAG, "Presentation is being dismissed because the "
+ + "display metrics have changed since it was created.");
cancel();
}
}
diff --git a/core/java/android/app/admin/DeviceInitializerStatus.java b/core/java/android/app/admin/DeviceInitializerStatus.java
deleted file mode 100644
index 7de518b..0000000
--- a/core/java/android/app/admin/DeviceInitializerStatus.java
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.admin;
-
-/**
- * Defines constants designating device provisioning status used with {@link
- * android.app.admin.DevicePolicyManager#sendDeviceInitializerStatus(int,String)}.
- *
- * This class contains flag constants that define special status codes:
- * <ul>
- * <li>{@link #FLAG_STATUS_ERROR} is used to define provisioning error status codes
- * <li>{@link #FLAG_STATUS_CUSTOM} is used to define custom status codes
- * <li>{@link #FLAG_STATUS_HIGH_PRIORITY} is used to define high priority status codes
- * </ul>
- *
- * <p>Status codes used by ManagedProvisioning are also defined in this class. These status codes
- * include provisioning errors and status codes.
- * <ul>
- * <li>{@link #STATUS_ERROR_CONNECT_WIFI}
- * <li>{@link #STATUS_ERROR_RESET_PROTECTION_BLOCKING_PROVISIONING}
- * <li>{@link #STATUS_ERROR_DOWNLOAD_PACKAGE}
- * <li>{@link #STATUS_ERROR_INSTALL_PACKAGE}
- * <li>{@link #STATUS_ERROR_SET_DEVICE_POLICY}
- * <li>{@link #STATUS_ERROR_DELETE_APPS}
- * <li>{@link #STATUS_ERROR_DOUBLE_BUMP}
- * <li>{@link #STATUS_STATE_CONNECTING_BLUETOOTH_PROXY}
- * <li>{@link #STATUS_STATE_DISCONNECTING_BLUETOOTH_PROXY}
- * <li>{@link #STATUS_STATE_DEVICE_PROVISIONED}
- * </ul>
- */
-public class DeviceInitializerStatus {
- /**
- * A flag used to designate an error status.
- *
- * <p>This flag is used with {@code statusCode} values sent through
- * {@link android.app.admin.DevicePolicyManager#sendDeviceInitializerStatus(int,String)}
- * @see #isErrorStatus(int)
- */
- public static final int FLAG_STATUS_ERROR = 0x01000000;
-
- /**
- * A flag used to designate a custom status. Custom status codes will be defined by device
- * initializer agents.
- *
- * <p>This flag is used with {@code statusCode} values sent through
- * {@link android.app.admin.DevicePolicyManager#sendDeviceInitializerStatus(int,String)}
- * @see #isCustomStatus(int)
- */
- public static final int FLAG_STATUS_CUSTOM = 0x02000000;
-
- /**
- * A bit flag used to designate a reserved status. Reserved status codes will not be defined
- * in AOSP.
- *
- * <p>This flag is used with {@code statusCode} values sent through
- * {@link android.app.admin.DevicePolicyManager#sendDeviceInitializerStatus(int,String)}
- */
- public static final int FLAG_STATUS_RESERVED = 0x04000000;
-
- /**
- * A flag used to indicate that a status message is high priority.
- *
- * <p>This flag is used with {@code statusCode} values sent through
- * {@link android.app.admin.DevicePolicyManager#sendDeviceInitializerStatus(int,String)}
- * @see #isHighPriority(int)
- */
- public static final int FLAG_STATUS_HIGH_PRIORITY = 0x08000000;
-
- /**
- * Device provisioning status code that indicates that a device is connecting to establish
- * a Bluetooth network proxy.
- */
- public static final int STATUS_STATE_CONNECTING_BLUETOOTH_PROXY = FLAG_STATUS_HIGH_PRIORITY | 8;
-
- /**
- * Device provisioning status code that indicates that a connected Bluetooth network proxy
- * is being shut down.
- */
- public static final int STATUS_STATE_DISCONNECTING_BLUETOOTH_PROXY = FLAG_STATUS_HIGH_PRIORITY | 9;
-
- /**
- * Device provisioning status code that indicates that a device has been successfully
- * provisioned.
- */
- public static final int STATUS_STATE_DEVICE_PROVISIONED = FLAG_STATUS_HIGH_PRIORITY | 10;
-
- /**
- * Device provisioning error status code that indicates that a device could not connect to
- * a Wi-Fi network.
- */
- public static final int STATUS_ERROR_CONNECT_WIFI = FLAG_STATUS_ERROR | 21;
-
- /**
- * Device provisioning error status indicating that factory reset protection is enabled on
- * the provisioned device and cannot be disabled with the provided data.
- */
- public static final int STATUS_ERROR_RESET_PROTECTION_BLOCKING_PROVISIONING =
- FLAG_STATUS_ERROR | 22;
-
- /**
- * Device provisioning error status indicating that device administrator and device initializer
- * packages could not be downloaded and verified successfully.
- */
- public static final int STATUS_ERROR_DOWNLOAD_PACKAGE = FLAG_STATUS_ERROR | 23;
-
- /**
- * Device provisioning error status indicating that device owner and device initializer packages
- * could not be installed.
- */
- public static final int STATUS_ERROR_INSTALL_PACKAGE = FLAG_STATUS_ERROR | 24;
-
- /**
- * Device provisioning error status indicating that the device owner or device initializer
- * components could not be set.
- */
- public static final int STATUS_ERROR_SET_DEVICE_POLICY = FLAG_STATUS_ERROR | 25;
-
- /**
- * Device provisioning error status indicating that deleting non-required applications during
- * provisioning failed.
- */
- public static final int STATUS_ERROR_DELETE_APPS = FLAG_STATUS_ERROR | 26;
-
- /**
- * Device provisioning error status code that indicates that a provisioning attempt has failed
- * because the device has already been provisioned or that provisioning has already started.
- */
- public static final int STATUS_ERROR_DOUBLE_BUMP = FLAG_STATUS_ERROR | 30;
-
- private DeviceInitializerStatus() {}
-}
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 3ab0e01..42d0dcb 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -400,7 +400,7 @@
* A String extra holding the URL-safe base64 encoded SHA-1 checksum of the file at download
* location specified in {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION}.
*
- * <p>Either this extra or {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_CERTIFICATE_CHECKSUM} should be
+ * <p>Either this extra or {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_SIGNATURE_CHECKSUM} should be
* present. The provided checksum should match the checksum of the file at the download
* location. If the checksum doesn't match an error will be shown to the user and the user will
* be asked to factory reset the device.
@@ -412,24 +412,24 @@
= "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM";
/**
- * A String extra holding the URL-safe base64 encoded SHA-1 checksum of any certificate of the
+ * A String extra holding the URL-safe base64 encoded SHA-1 checksum of any signature of the
* android package archive at the download location specified in {@link
* #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION}.
*
- * <p>The certificates of an android package archive can be obtained using
+ * <p>The signatures of an android package archive can be obtained using
* {@link android.content.pm.PackageManager#getPackageArchiveInfo} with flag
* {@link android.content.pm.PackageManager#GET_SIGNATURES}.
*
* <p>Either this extra or {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM} should be
- * present. The provided checksum should match the checksum of any certificate of the file at
+ * present. The provided checksum should match the checksum of any signature of the file at
* the download location. If the checksum does not match an error will be shown to the user and
* the user will be asked to factory reset the device.
*
* <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC} that starts device owner
* provisioning via an NFC bump.
*/
- public static final String EXTRA_PROVISIONING_DEVICE_ADMIN_CERTIFICATE_CHECKSUM
- = "android.app.extra.PROVISIONING_DEVICE_ADMIN_CERTIFICATE_CHECKSUM";
+ public static final String EXTRA_PROVISIONING_DEVICE_ADMIN_SIGNATURE_CHECKSUM
+ = "android.app.extra.PROVISIONING_DEVICE_ADMIN_SIGNATURE_CHECKSUM";
/**
* Broadcast Action: This broadcast is sent to indicate that provisioning of a managed profile
@@ -508,7 +508,7 @@
* location specified in
* {@link #EXTRA_PROVISIONING_DEVICE_INITIALIZER_PACKAGE_DOWNLOAD_LOCATION}.
*
- * <p>Either this extra or {@link #EXTRA_PROVISIONING_DEVICE_INITIALIZER_CERTIFICATE_CHECKSUM}
+ * <p>Either this extra or {@link #EXTRA_PROVISIONING_DEVICE_INITIALIZER_SIGNATURE_CHECKSUM}
* should be present. The provided checksum should match the checksum of the file at the
* download location. If the checksum doesn't match an error will be shown to the user and the
* user will be asked to factory reset the device.
@@ -520,68 +520,24 @@
= "android.app.extra.PROVISIONING_DEVICE_INITIALIZER_PACKAGE_CHECKSUM";
/**
- * A String extra holding the URL-safe base64 encoded SHA-1 checksum of any certificate of the
+ * A String extra holding the URL-safe base64 encoded SHA-1 checksum of any signature of the
* android package archive at the download location specified in {@link
* #EXTRA_PROVISIONING_DEVICE_INITIALIZER_PACKAGE_DOWNLOAD_LOCATION}.
*
- * <p>The certificates of an android package archive can be obtained using
+ * <p>The signatures of an android package archive can be obtained using
* {@link android.content.pm.PackageManager#getPackageArchiveInfo} with flag
* {@link android.content.pm.PackageManager#GET_SIGNATURES}.
*
* <p>Either this extra or {@link #EXTRA_PROVISIONING_DEVICE_INITIALIZER_PACKAGE_CHECKSUM}
- * should be present. The provided checksum should match the checksum of any certificate of the
+ * should be present. The provided checksum should match the checksum of any signature of the
* file at the download location. If the checksum doesn't match an error will be shown to the
* user and the user will be asked to factory reset the device.
*
* <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC_V2} that starts device owner
* provisioning via an NFC bump.
*/
- public static final String EXTRA_PROVISIONING_DEVICE_INITIALIZER_CERTIFICATE_CHECKSUM
- = "android.app.extra.PROVISIONING_DEVICE_INITIALIZER_CERTIFICATE_CHECKSUM";
-
- /**
- * A String extra holding the MAC address of the Bluetooth device to connect to with status
- * updates during provisioning.
- *
- * <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC_V2} that starts device owner
- * provisioning via an NFC bump.
- */
- public static final String EXTRA_PROVISIONING_BT_MAC_ADDRESS
- = "android.app.extra.PROVISIONING_BT_MAC_ADDRESS";
-
- /**
- * A String extra holding the Bluetooth service UUID on the device to connect to with status
- * updates during provisioning.
- *
- * <p>This value must be specified when {@code #EXTRA_PROVISIONING_BT_MAC_ADDRESS} is present.
- *
- * <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC_V2} that starts device owner
- * provisioning via an NFC bump.
- */
- public static final String EXTRA_PROVISIONING_BT_UUID
- = "android.app.extra.PROVISIONING_BT_UUID";
-
- /**
- * A String extra holding a unique identifier used to identify the device connecting over
- * Bluetooth. This identifier will be part of every status message sent to the remote device.
- *
- * <p>This value must be specified when {@code #EXTRA_PROVISIONING_BT_MAC_ADDRESS} is present.
- *
- * <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC_V2} that starts device owner
- * provisioning via an NFC bump.
- */
- public static final String EXTRA_PROVISIONING_BT_DEVICE_ID
- = "android.app.extra.PROVISIONING_BT_DEVICE_ID";
-
- /**
- * A Boolean extra that that will cause a provisioned device to temporarily proxy network
- * traffic over Bluetooth. When a Wi-Fi network is available, the network proxy will stop.
- *
- * <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC_V2} that starts device owner
- * provisioning via an NFC bump.
- */
- public static final String EXTRA_PROVISIONING_BT_USE_PROXY
- = "android.app.extra.PROVISIONING_BT_USE_PROXY";
+ public static final String EXTRA_PROVISIONING_DEVICE_INITIALIZER_SIGNATURE_CHECKSUM
+ = "android.app.extra.PROVISIONING_DEVICE_INITIALIZER_SIGNATURE_CHECKSUM";
/**
* A {@link android.os.Parcelable} extra of type {@link android.os.PersistableBundle} that
@@ -665,11 +621,7 @@
* Replaces {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME}. The value of the property
* should be converted to a String via
* {@link android.content.ComponentName#flattenToString()}</li>
- * <li>{@link #EXTRA_PROVISIONING_DEVICE_ADMIN_MINIMUM_VERSION_CODE}, optional</li>
- * <li>{@link #EXTRA_PROVISIONING_BT_MAC_ADDRESS}, optional</li>
- * <li>{@link #EXTRA_PROVISIONING_BT_UUID}, optional</li>
- * <li>{@link #EXTRA_PROVISIONING_BT_DEVICE_ID}, optional</li>
- * <li>{@link #EXTRA_PROVISIONING_BT_USE_PROXY}, optional</li></ul>
+ * <li>{@link #EXTRA_PROVISIONING_DEVICE_ADMIN_MINIMUM_VERSION_CODE}, optional</li></ul>
*
* <p> When device owner provisioning has completed, an intent of the type
* {@link DeviceAdminReceiver#ACTION_PROFILE_PROVISIONING_COMPLETE} is broadcasted to the
@@ -727,45 +679,6 @@
= "android.app.action.SET_PROFILE_OWNER";
/**
- * Protected broadcast action that will be sent to managed provisioning to notify it that a
- * status update has been reported by the device initializer. The status update will be
- * reported to the remote setup device over Bluetooth.
- *
- * <p>Broadcasts with this action must supply a
- * {@linkplain DeviceInitializerStatus#FLAG_STATUS_CUSTOM custom} status code in the
- * {@link EXTRA_DEVICE_INITIALIZER_STATUS_CODE} extra.
- *
- * <p>Broadcasts may optionally contain a description in the
- * {@link EXTRA_DEVICE_INITIALIZER_STATUS_DESCRIPTION} extra.
- * @hide
- */
- @SystemApi
- public static final String ACTION_SEND_DEVICE_INITIALIZER_STATUS
- = "android.app.action.SEND_DEVICE_INITIALIZER_STATUS";
-
- /**
- * An integer extra that contains the status code that defines a status update. This extra must
- * sent as part of a broadcast with an action of {@code ACTION_SEND_DEVICE_INITIALIZER_STATUS}.
- *
- * <p>The status code sent with this extra must be a custom status code as defined by
- * {@link DeviceInitializerStatus#FLAG_STATUS_CUSTOM}.
- * @hide
- */
- @SystemApi
- public static final String EXTRA_DEVICE_INITIALIZER_STATUS_CODE
- = "android.app.extra.DEVICE_INITIALIZER_STATUS_CODE";
-
- /**
- * A {@code String} extra that contains an optional description accompanying a status update.
- * This extra my be sent as part of a broadcast with an action of
- * {@code ACTION_SEND_DEVICE_INITIALIZER_STATUS}.
- * @hide
- */
- @SystemApi
- public static final String EXTRA_DEVICE_INITIALIZER_STATUS_DESCRIPTION
- = "android.app.extra.DEVICE_INITIALIZER_STATUS_DESCRIPTION";
-
- /**
* @hide
* Name of the profile owner admin that controls the user.
*/
@@ -2275,7 +2188,7 @@
if (mService != null) {
try {
final String alias = getCaCertAlias(certBuffer);
- mService.uninstallCaCert(admin, alias);
+ mService.uninstallCaCerts(admin, new String[] {alias});
} catch (CertificateException e) {
Log.w(TAG, "Unable to parse certificate", e);
} catch (RemoteException e) {
@@ -2322,12 +2235,11 @@
*/
public void uninstallAllUserCaCerts(@Nullable ComponentName admin) {
if (mService != null) {
- for (String alias : new TrustedCertificateStore().userAliases()) {
- try {
- mService.uninstallCaCert(admin, alias);
- } catch (RemoteException re) {
- Log.w(TAG, "Failed talking with device policy service", re);
- }
+ try {
+ mService.uninstallCaCerts(admin, new TrustedCertificateStore().userAliases()
+ .toArray(new String[0]));
+ } catch (RemoteException re) {
+ Log.w(TAG, "Failed talking with device policy service", re);
}
}
}
@@ -3976,6 +3888,9 @@
* <p>Any packages that shares uid with an allowed package will also be allowed
* to activate lock task.
*
+ * From {@link android.os.Build.VERSION_CODES#MNC} removing packages from the lock task
+ * package list results in locked tasks belonging to those packages to be finished.
+ *
* This function can only be called by the device owner.
* @param packages The list of packages allowed to enter lock task mode
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
@@ -4289,21 +4204,6 @@
}
/**
- * Called by device initializer to send a provisioning status update to the remote setup device.
- *
- * @param statusCode a custom status code value as defined by
- * {@link DeviceInitializerStatus#FLAG_STATUS_CUSTOM}.
- * @param description custom description of the status code sent
- */
- public void sendDeviceInitializerStatus(int statusCode, String description) {
- try {
- mService.sendDeviceInitializerStatus(statusCode, description);
- } catch (RemoteException re) {
- Log.w(TAG, "Could not send device initializer status", re);
- }
- }
-
- /**
* Called by device owners to set a local system update policy. When a new policy is set,
* {@link #ACTION_SYSTEM_UPDATE_POLICY_CHANGED} is broadcasted.
*
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 8c7b20a..376a3d8 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -128,7 +128,7 @@
boolean hasUserSetupCompleted();
boolean installCaCert(in ComponentName admin, in byte[] certBuffer);
- void uninstallCaCert(in ComponentName admin, in String alias);
+ void uninstallCaCerts(in ComponentName admin, in String[] aliases);
void enforceCanManageCaCerts(in ComponentName admin);
boolean installKeyPair(in ComponentName who, in byte[] privKeyBuffer, in byte[] certBuffer, String alias);
@@ -220,7 +220,6 @@
void setUserIcon(in ComponentName admin, in Bitmap icon);
- void sendDeviceInitializerStatus(int statusCode, String description);
void setSystemUpdatePolicy(in ComponentName who, in SystemUpdatePolicy policy);
SystemUpdatePolicy getSystemUpdatePolicy();
diff --git a/core/java/android/app/usage/UsageEvents.java b/core/java/android/app/usage/UsageEvents.java
index 58279d7..369b692 100644
--- a/core/java/android/app/usage/UsageEvents.java
+++ b/core/java/android/app/usage/UsageEvents.java
@@ -68,9 +68,15 @@
public static final int CONFIGURATION_CHANGE = 5;
/**
- * An event type denoting that a package was interacted with in some way.
+ * An event type denoting that a package was interacted with in some way by the system.
+ * @hide
*/
- public static final int INTERACTION = 6;
+ public static final int SYSTEM_INTERACTION = 6;
+
+ /**
+ * An event type denoting that a package was interacted with in some way by the user.
+ */
+ public static final int USER_INTERACTION = 7;
/**
* {@hide}
diff --git a/core/java/android/app/usage/UsageStats.java b/core/java/android/app/usage/UsageStats.java
index 81c7422..0fce4e2 100644
--- a/core/java/android/app/usage/UsageStats.java
+++ b/core/java/android/app/usage/UsageStats.java
@@ -41,11 +41,19 @@
public long mEndTimeStamp;
/**
+ * Last time used by the user with an explicit action (notification, activity launch).
* {@hide}
*/
public long mLastTimeUsed;
/**
+ * The last time the package was used via implicit, non-user initiated actions (service
+ * was bound, etc).
+ * {@hide}
+ */
+ public long mLastTimeSystemUsed;
+
+ /**
* Last time the package was used and the beginning of the idle countdown.
* This uses a different timebase that is about how much the device has been in use in general.
* {@hide}
@@ -82,6 +90,7 @@
mLaunchCount = stats.mLaunchCount;
mLastEvent = stats.mLastEvent;
mBeginIdleTime = stats.mBeginIdleTime;
+ mLastTimeSystemUsed = stats.mLastTimeSystemUsed;
}
public String getPackageName() {
@@ -119,6 +128,16 @@
/**
* @hide
+ * Get the last time this package was used by the system (not the user). This can be different
+ * from {@link #getLastTimeUsed()} when the system binds to one of this package's services.
+ * See {@link System#currentTimeMillis()}.
+ */
+ public long getLastTimeSystemUsed() {
+ return mLastTimeSystemUsed;
+ }
+
+ /**
+ * @hide
* Get the last time this package was active, measured in milliseconds. This timestamp
* uses a timebase that represents how much the device was used and not wallclock time.
*/
@@ -151,6 +170,7 @@
mEndTimeStamp = right.mEndTimeStamp;
mLastTimeUsed = right.mLastTimeUsed;
mBeginIdleTime = right.mBeginIdleTime;
+ mLastTimeSystemUsed = right.mLastTimeSystemUsed;
}
mBeginTimeStamp = Math.min(mBeginTimeStamp, right.mBeginTimeStamp);
mTotalTimeInForeground += right.mTotalTimeInForeground;
@@ -172,6 +192,7 @@
dest.writeInt(mLaunchCount);
dest.writeInt(mLastEvent);
dest.writeLong(mBeginIdleTime);
+ dest.writeLong(mLastTimeSystemUsed);
}
public static final Creator<UsageStats> CREATOR = new Creator<UsageStats>() {
@@ -186,6 +207,7 @@
stats.mLaunchCount = in.readInt();
stats.mLastEvent = in.readInt();
stats.mBeginIdleTime = in.readLong();
+ stats.mLastTimeSystemUsed = in.readLong();
return stats;
}
diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java
index 72e701d..494f821 100644
--- a/core/java/android/content/ContentProvider.java
+++ b/core/java/android/content/ContentProvider.java
@@ -19,6 +19,7 @@
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.Manifest.permission.INTERACT_ACROSS_USERS;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.AppOpsManager;
import android.content.pm.PathPermission;
@@ -639,7 +640,7 @@
* {@link #onCreate} has been called -- this will return {@code null} in the
* constructor.
*/
- public final Context getContext() {
+ public final @Nullable Context getContext() {
return mContext;
}
@@ -667,7 +668,7 @@
* @throws SecurityException if the calling package doesn't belong to the
* calling UID.
*/
- public final String getCallingPackage() {
+ public final @Nullable String getCallingPackage() {
final String pkg = mCallingPackage.get();
if (pkg != null) {
mTransport.mAppOpsManager.checkPackage(Binder.getCallingUid(), pkg);
@@ -716,7 +717,7 @@
*
* @param permission Name of the permission required for read-only access.
*/
- protected final void setReadPermission(String permission) {
+ protected final void setReadPermission(@Nullable String permission) {
mReadPermission = permission;
}
@@ -727,7 +728,7 @@
* <a href="{@docRoot}guide/topics/fundamentals/processes-and-threads.html#Threads">Processes
* and Threads</a>.
*/
- public final String getReadPermission() {
+ public final @Nullable String getReadPermission() {
return mReadPermission;
}
@@ -738,7 +739,7 @@
*
* @param permission Name of the permission required for read/write access.
*/
- protected final void setWritePermission(String permission) {
+ protected final void setWritePermission(@Nullable String permission) {
mWritePermission = permission;
}
@@ -749,7 +750,7 @@
* <a href="{@docRoot}guide/topics/fundamentals/processes-and-threads.html#Threads">Processes
* and Threads</a>.
*/
- public final String getWritePermission() {
+ public final @Nullable String getWritePermission() {
return mWritePermission;
}
@@ -760,7 +761,7 @@
*
* @param permissions Array of path permission descriptions.
*/
- protected final void setPathPermissions(PathPermission[] permissions) {
+ protected final void setPathPermissions(@Nullable PathPermission[] permissions) {
mPathPermissions = permissions;
}
@@ -771,7 +772,7 @@
* <a href="{@docRoot}guide/topics/fundamentals/processes-and-threads.html#Threads">Processes
* and Threads</a>.
*/
- public final PathPermission[] getPathPermissions() {
+ public final @Nullable PathPermission[] getPathPermissions() {
return mPathPermissions;
}
@@ -897,8 +898,9 @@
* If {@code null} then the provider is free to define the sort order.
* @return a Cursor or {@code null}.
*/
- public abstract Cursor query(Uri uri, String[] projection,
- String selection, String[] selectionArgs, String sortOrder);
+ public abstract @Nullable Cursor query(@NonNull Uri uri, @Nullable String[] projection,
+ @Nullable String selection, @Nullable String[] selectionArgs,
+ @Nullable String sortOrder);
/**
* Implement this to handle query requests from clients with support for cancellation.
@@ -963,9 +965,9 @@
* when the query is executed.
* @return a Cursor or {@code null}.
*/
- public Cursor query(Uri uri, String[] projection,
- String selection, String[] selectionArgs, String sortOrder,
- CancellationSignal cancellationSignal) {
+ public @Nullable Cursor query(@NonNull Uri uri, @Nullable String[] projection,
+ @Nullable String selection, @Nullable String[] selectionArgs,
+ @Nullable String sortOrder, @Nullable CancellationSignal cancellationSignal) {
return query(uri, projection, selection, selectionArgs, sortOrder);
}
@@ -987,7 +989,7 @@
* @param uri the URI to query.
* @return a MIME type string, or {@code null} if there is no type.
*/
- public abstract String getType(Uri uri);
+ public abstract @Nullable String getType(@NonNull Uri uri);
/**
* Implement this to support canonicalization of URIs that refer to your
@@ -1019,7 +1021,7 @@
* @return Return the canonical representation of <var>url</var>, or null if
* canonicalization of that Uri is not supported.
*/
- public Uri canonicalize(Uri url) {
+ public @Nullable Uri canonicalize(@NonNull Uri url) {
return null;
}
@@ -1037,7 +1039,7 @@
* the data identified by the canonical representation can not be found in
* the current environment.
*/
- public Uri uncanonicalize(Uri url) {
+ public @Nullable Uri uncanonicalize(@NonNull Uri url) {
return url;
}
@@ -1070,7 +1072,7 @@
* This must not be {@code null}.
* @return The URI for the newly inserted item.
*/
- public abstract Uri insert(Uri uri, ContentValues values);
+ public abstract @Nullable Uri insert(@NonNull Uri uri, @Nullable ContentValues values);
/**
* Override this to handle requests to insert a set of new rows, or the
@@ -1087,7 +1089,7 @@
* This must not be {@code null}.
* @return The number of values that were inserted.
*/
- public int bulkInsert(Uri uri, ContentValues[] values) {
+ public int bulkInsert(@NonNull Uri uri, @NonNull ContentValues[] values) {
int numValues = values.length;
for (int i = 0; i < numValues; i++) {
insert(uri, values[i]);
@@ -1115,7 +1117,8 @@
* @return The number of rows affected.
* @throws SQLException
*/
- public abstract int delete(Uri uri, String selection, String[] selectionArgs);
+ public abstract int delete(@NonNull Uri uri, @Nullable String selection,
+ @Nullable String[] selectionArgs);
/**
* Implement this to handle requests to update one or more rows.
@@ -1134,8 +1137,8 @@
* @param selection An optional filter to match rows to update.
* @return the number of rows affected.
*/
- public abstract int update(Uri uri, ContentValues values, String selection,
- String[] selectionArgs);
+ public abstract int update(@NonNull Uri uri, @Nullable ContentValues values,
+ @Nullable String selection, @Nullable String[] selectionArgs);
/**
* Override this to handle requests to open a file blob.
@@ -1194,7 +1197,7 @@
* @see #getType(android.net.Uri)
* @see ParcelFileDescriptor#parseMode(String)
*/
- public ParcelFileDescriptor openFile(Uri uri, String mode)
+ public @Nullable ParcelFileDescriptor openFile(@NonNull Uri uri, @NonNull String mode)
throws FileNotFoundException {
throw new FileNotFoundException("No files supported by provider at "
+ uri);
@@ -1264,8 +1267,8 @@
* @see #getType(android.net.Uri)
* @see ParcelFileDescriptor#parseMode(String)
*/
- public ParcelFileDescriptor openFile(Uri uri, String mode, CancellationSignal signal)
- throws FileNotFoundException {
+ public @Nullable ParcelFileDescriptor openFile(@NonNull Uri uri, @NonNull String mode,
+ @Nullable CancellationSignal signal) throws FileNotFoundException {
return openFile(uri, mode);
}
@@ -1320,7 +1323,7 @@
* @see #openFileHelper(Uri, String)
* @see #getType(android.net.Uri)
*/
- public AssetFileDescriptor openAssetFile(Uri uri, String mode)
+ public @Nullable AssetFileDescriptor openAssetFile(@NonNull Uri uri, @NonNull String mode)
throws FileNotFoundException {
ParcelFileDescriptor fd = openFile(uri, mode);
return fd != null ? new AssetFileDescriptor(fd, 0, -1) : null;
@@ -1383,8 +1386,8 @@
* @see #openFileHelper(Uri, String)
* @see #getType(android.net.Uri)
*/
- public AssetFileDescriptor openAssetFile(Uri uri, String mode, CancellationSignal signal)
- throws FileNotFoundException {
+ public @Nullable AssetFileDescriptor openAssetFile(@NonNull Uri uri, @NonNull String mode,
+ @Nullable CancellationSignal signal) throws FileNotFoundException {
return openAssetFile(uri, mode);
}
@@ -1402,8 +1405,8 @@
* @return Returns a new ParcelFileDescriptor that can be used by the
* client to access the file.
*/
- protected final ParcelFileDescriptor openFileHelper(Uri uri,
- String mode) throws FileNotFoundException {
+ protected final @NonNull ParcelFileDescriptor openFileHelper(@NonNull Uri uri,
+ @NonNull String mode) throws FileNotFoundException {
Cursor c = query(uri, new String[]{"_data"}, null, null, null);
int count = (c != null) ? c.getCount() : 0;
if (count != 1) {
@@ -1449,7 +1452,7 @@
* @see #openTypedAssetFile(Uri, String, Bundle)
* @see ClipDescription#compareMimeTypes(String, String)
*/
- public String[] getStreamTypes(Uri uri, String mimeTypeFilter) {
+ public @Nullable String[] getStreamTypes(@NonNull Uri uri, @NonNull String mimeTypeFilter) {
return null;
}
@@ -1498,8 +1501,8 @@
* @see #openAssetFile(Uri, String)
* @see ClipDescription#compareMimeTypes(String, String)
*/
- public AssetFileDescriptor openTypedAssetFile(Uri uri, String mimeTypeFilter, Bundle opts)
- throws FileNotFoundException {
+ public @Nullable AssetFileDescriptor openTypedAssetFile(@NonNull Uri uri,
+ @NonNull String mimeTypeFilter, @Nullable Bundle opts) throws FileNotFoundException {
if ("*/*".equals(mimeTypeFilter)) {
// If they can take anything, the untyped open call is good enough.
return openAssetFile(uri, "r");
@@ -1565,9 +1568,9 @@
* @see #openAssetFile(Uri, String)
* @see ClipDescription#compareMimeTypes(String, String)
*/
- public AssetFileDescriptor openTypedAssetFile(
- Uri uri, String mimeTypeFilter, Bundle opts, CancellationSignal signal)
- throws FileNotFoundException {
+ public @Nullable AssetFileDescriptor openTypedAssetFile(@NonNull Uri uri,
+ @NonNull String mimeTypeFilter, @Nullable Bundle opts,
+ @Nullable CancellationSignal signal) throws FileNotFoundException {
return openTypedAssetFile(uri, mimeTypeFilter, opts);
}
@@ -1589,8 +1592,8 @@
* @param opts Options supplied by caller.
* @param args Your own custom arguments.
*/
- public void writeDataToPipe(ParcelFileDescriptor output, Uri uri, String mimeType,
- Bundle opts, T args);
+ public void writeDataToPipe(@NonNull ParcelFileDescriptor output, @NonNull Uri uri,
+ @NonNull String mimeType, @Nullable Bundle opts, @Nullable T args);
}
/**
@@ -1610,9 +1613,9 @@
* the pipe. This should be returned to the caller for reading; the caller
* is responsible for closing it when done.
*/
- public <T> ParcelFileDescriptor openPipeHelper(final Uri uri, final String mimeType,
- final Bundle opts, final T args, final PipeDataWriter<T> func)
- throws FileNotFoundException {
+ public @NonNull <T> ParcelFileDescriptor openPipeHelper(final @NonNull Uri uri,
+ final @NonNull String mimeType, final @Nullable Bundle opts, final @Nullable T args,
+ final @NonNull PipeDataWriter<T> func) throws FileNotFoundException {
try {
final ParcelFileDescriptor[] fds = ParcelFileDescriptor.createPipe();
@@ -1717,8 +1720,9 @@
* @throws OperationApplicationException thrown if any operation fails.
* @see ContentProviderOperation#apply
*/
- public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations)
- throws OperationApplicationException {
+ public @NonNull ContentProviderResult[] applyBatch(
+ @NonNull ArrayList<ContentProviderOperation> operations)
+ throws OperationApplicationException {
final int numOperations = operations.size();
final ContentProviderResult[] results = new ContentProviderResult[numOperations];
for (int i = 0; i < numOperations; i++) {
@@ -1745,7 +1749,8 @@
* @return provider-defined return value. May be {@code null}, which is also
* the default for providers which don't implement any call methods.
*/
- public Bundle call(String method, @Nullable String arg, @Nullable Bundle extras) {
+ public @Nullable Bundle call(@NonNull String method, @Nullable String arg,
+ @Nullable Bundle extras) {
return null;
}
diff --git a/core/java/android/content/ContentProviderClient.java b/core/java/android/content/ContentProviderClient.java
index e15ac94..d12595f 100644
--- a/core/java/android/content/ContentProviderClient.java
+++ b/core/java/android/content/ContentProviderClient.java
@@ -16,6 +16,8 @@
package android.content;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.content.res.AssetFileDescriptor;
import android.database.Cursor;
import android.net.Uri;
@@ -30,6 +32,7 @@
import android.util.Log;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.Preconditions;
import dalvik.system.CloseGuard;
@@ -109,14 +112,19 @@
}
/** See {@link ContentProvider#query ContentProvider.query} */
- public Cursor query(Uri url, String[] projection, String selection,
- String[] selectionArgs, String sortOrder) throws RemoteException {
+ public @Nullable Cursor query(@NonNull Uri url, @Nullable String[] projection,
+ @Nullable String selection, @Nullable String[] selectionArgs,
+ @Nullable String sortOrder) throws RemoteException {
return query(url, projection, selection, selectionArgs, sortOrder, null);
}
/** See {@link ContentProvider#query ContentProvider.query} */
- public Cursor query(Uri url, String[] projection, String selection, String[] selectionArgs,
- String sortOrder, CancellationSignal cancellationSignal) throws RemoteException {
+ public @Nullable Cursor query(@NonNull Uri url, @Nullable String[] projection,
+ @Nullable String selection, @Nullable String[] selectionArgs,
+ @Nullable String sortOrder, @Nullable CancellationSignal cancellationSignal)
+ throws RemoteException {
+ Preconditions.checkNotNull(url, "url");
+
beforeRemote();
try {
ICancellationSignal remoteCancellationSignal = null;
@@ -138,7 +146,9 @@
}
/** See {@link ContentProvider#getType ContentProvider.getType} */
- public String getType(Uri url) throws RemoteException {
+ public @Nullable String getType(@NonNull Uri url) throws RemoteException {
+ Preconditions.checkNotNull(url, "url");
+
beforeRemote();
try {
return mContentProvider.getType(url);
@@ -153,7 +163,11 @@
}
/** See {@link ContentProvider#getStreamTypes ContentProvider.getStreamTypes} */
- public String[] getStreamTypes(Uri url, String mimeTypeFilter) throws RemoteException {
+ public @Nullable String[] getStreamTypes(@NonNull Uri url, @NonNull String mimeTypeFilter)
+ throws RemoteException {
+ Preconditions.checkNotNull(url, "url");
+ Preconditions.checkNotNull(mimeTypeFilter, "mimeTypeFilter");
+
beforeRemote();
try {
return mContentProvider.getStreamTypes(url, mimeTypeFilter);
@@ -168,7 +182,9 @@
}
/** See {@link ContentProvider#canonicalize} */
- public final Uri canonicalize(Uri url) throws RemoteException {
+ public final @Nullable Uri canonicalize(@NonNull Uri url) throws RemoteException {
+ Preconditions.checkNotNull(url, "url");
+
beforeRemote();
try {
return mContentProvider.canonicalize(mPackageName, url);
@@ -183,7 +199,9 @@
}
/** See {@link ContentProvider#uncanonicalize} */
- public final Uri uncanonicalize(Uri url) throws RemoteException {
+ public final @Nullable Uri uncanonicalize(@NonNull Uri url) throws RemoteException {
+ Preconditions.checkNotNull(url, "url");
+
beforeRemote();
try {
return mContentProvider.uncanonicalize(mPackageName, url);
@@ -198,7 +216,10 @@
}
/** See {@link ContentProvider#insert ContentProvider.insert} */
- public Uri insert(Uri url, ContentValues initialValues) throws RemoteException {
+ public @Nullable Uri insert(@NonNull Uri url, @Nullable ContentValues initialValues)
+ throws RemoteException {
+ Preconditions.checkNotNull(url, "url");
+
beforeRemote();
try {
return mContentProvider.insert(mPackageName, url, initialValues);
@@ -213,7 +234,11 @@
}
/** See {@link ContentProvider#bulkInsert ContentProvider.bulkInsert} */
- public int bulkInsert(Uri url, ContentValues[] initialValues) throws RemoteException {
+ public int bulkInsert(@NonNull Uri url, @NonNull ContentValues[] initialValues)
+ throws RemoteException {
+ Preconditions.checkNotNull(url, "url");
+ Preconditions.checkNotNull(initialValues, "initialValues");
+
beforeRemote();
try {
return mContentProvider.bulkInsert(mPackageName, url, initialValues);
@@ -228,8 +253,10 @@
}
/** See {@link ContentProvider#delete ContentProvider.delete} */
- public int delete(Uri url, String selection, String[] selectionArgs)
- throws RemoteException {
+ public int delete(@NonNull Uri url, @Nullable String selection,
+ @Nullable String[] selectionArgs) throws RemoteException {
+ Preconditions.checkNotNull(url, "url");
+
beforeRemote();
try {
return mContentProvider.delete(mPackageName, url, selection, selectionArgs);
@@ -244,8 +271,10 @@
}
/** See {@link ContentProvider#update ContentProvider.update} */
- public int update(Uri url, ContentValues values, String selection,
- String[] selectionArgs) throws RemoteException {
+ public int update(@NonNull Uri url, @Nullable ContentValues values, @Nullable String selection,
+ @Nullable String[] selectionArgs) throws RemoteException {
+ Preconditions.checkNotNull(url, "url");
+
beforeRemote();
try {
return mContentProvider.update(mPackageName, url, values, selection, selectionArgs);
@@ -266,7 +295,7 @@
* you use the {@link ContentResolver#openFileDescriptor
* ContentResolver.openFileDescriptor} API instead.
*/
- public ParcelFileDescriptor openFile(Uri url, String mode)
+ public @Nullable ParcelFileDescriptor openFile(@NonNull Uri url, @NonNull String mode)
throws RemoteException, FileNotFoundException {
return openFile(url, mode, null);
}
@@ -278,8 +307,11 @@
* you use the {@link ContentResolver#openFileDescriptor
* ContentResolver.openFileDescriptor} API instead.
*/
- public ParcelFileDescriptor openFile(Uri url, String mode, CancellationSignal signal)
- throws RemoteException, FileNotFoundException {
+ public @Nullable ParcelFileDescriptor openFile(@NonNull Uri url, @NonNull String mode,
+ @Nullable CancellationSignal signal) throws RemoteException, FileNotFoundException {
+ Preconditions.checkNotNull(url, "url");
+ Preconditions.checkNotNull(mode, "mode");
+
beforeRemote();
try {
ICancellationSignal remoteSignal = null;
@@ -306,7 +338,7 @@
* you use the {@link ContentResolver#openAssetFileDescriptor
* ContentResolver.openAssetFileDescriptor} API instead.
*/
- public AssetFileDescriptor openAssetFile(Uri url, String mode)
+ public @Nullable AssetFileDescriptor openAssetFile(@NonNull Uri url, @NonNull String mode)
throws RemoteException, FileNotFoundException {
return openAssetFile(url, mode, null);
}
@@ -318,8 +350,11 @@
* you use the {@link ContentResolver#openAssetFileDescriptor
* ContentResolver.openAssetFileDescriptor} API instead.
*/
- public AssetFileDescriptor openAssetFile(Uri url, String mode, CancellationSignal signal)
- throws RemoteException, FileNotFoundException {
+ public @Nullable AssetFileDescriptor openAssetFile(@NonNull Uri url, @NonNull String mode,
+ @Nullable CancellationSignal signal) throws RemoteException, FileNotFoundException {
+ Preconditions.checkNotNull(url, "url");
+ Preconditions.checkNotNull(mode, "mode");
+
beforeRemote();
try {
ICancellationSignal remoteSignal = null;
@@ -340,15 +375,19 @@
}
/** See {@link ContentProvider#openTypedAssetFile ContentProvider.openTypedAssetFile} */
- public final AssetFileDescriptor openTypedAssetFileDescriptor(Uri uri,
- String mimeType, Bundle opts) throws RemoteException, FileNotFoundException {
+ public final @Nullable AssetFileDescriptor openTypedAssetFileDescriptor(@NonNull Uri uri,
+ @NonNull String mimeType, @Nullable Bundle opts)
+ throws RemoteException, FileNotFoundException {
return openTypedAssetFileDescriptor(uri, mimeType, opts, null);
}
/** See {@link ContentProvider#openTypedAssetFile ContentProvider.openTypedAssetFile} */
- public final AssetFileDescriptor openTypedAssetFileDescriptor(Uri uri,
- String mimeType, Bundle opts, CancellationSignal signal)
- throws RemoteException, FileNotFoundException {
+ public final @Nullable AssetFileDescriptor openTypedAssetFileDescriptor(@NonNull Uri uri,
+ @NonNull String mimeType, @Nullable Bundle opts, @Nullable CancellationSignal signal)
+ throws RemoteException, FileNotFoundException {
+ Preconditions.checkNotNull(uri, "uri");
+ Preconditions.checkNotNull(mimeType, "mimeType");
+
beforeRemote();
try {
ICancellationSignal remoteSignal = null;
@@ -370,8 +409,11 @@
}
/** See {@link ContentProvider#applyBatch ContentProvider.applyBatch} */
- public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations)
- throws RemoteException, OperationApplicationException {
+ public @NonNull ContentProviderResult[] applyBatch(
+ @NonNull ArrayList<ContentProviderOperation> operations)
+ throws RemoteException, OperationApplicationException {
+ Preconditions.checkNotNull(operations, "operations");
+
beforeRemote();
try {
return mContentProvider.applyBatch(mPackageName, operations);
@@ -386,7 +428,10 @@
}
/** See {@link ContentProvider#call(String, String, Bundle)} */
- public Bundle call(String method, String arg, Bundle extras) throws RemoteException {
+ public @Nullable Bundle call(@NonNull String method, @Nullable String arg,
+ @Nullable Bundle extras) throws RemoteException {
+ Preconditions.checkNotNull(method, "method");
+
beforeRemote();
try {
return mContentProvider.call(mPackageName, method, arg, extras);
@@ -436,7 +481,7 @@
* @return If the associated {@link ContentProvider} is local, returns it.
* Otherwise returns null.
*/
- public ContentProvider getLocalContentProvider() {
+ public @Nullable ContentProvider getLocalContentProvider() {
return ContentProvider.coerceToLocalContentProvider(mContentProvider);
}
diff --git a/core/java/android/content/ContentProviderOperation.java b/core/java/android/content/ContentProviderOperation.java
index 49ac062..fd1e24a 100644
--- a/core/java/android/content/ContentProviderOperation.java
+++ b/core/java/android/content/ContentProviderOperation.java
@@ -28,6 +28,11 @@
import java.util.HashMap;
import java.util.Map;
+/**
+ * Represents a single operation to be performed as part of a batch of operations.
+ *
+ * @see ContentProvider#applyBatch(ArrayList)
+ */
public class ContentProviderOperation implements Parcelable {
/** @hide exposed for unit tests */
public final static int TYPE_INSERT = 1;
@@ -195,10 +200,19 @@
return new Builder(TYPE_ASSERT, uri);
}
+ /**
+ * Gets the Uri for the target of the operation.
+ */
public Uri getUri() {
return mUri;
}
+ /**
+ * Returns true if the operation allows yielding the database to other transactions
+ * if the database is contended.
+ *
+ * @see android.database.sqlite.SQLiteDatabase#yieldIfContendedSafely()
+ */
public boolean isYieldAllowed() {
return mYieldAllowed;
}
@@ -208,26 +222,58 @@
return mType;
}
+ /**
+ * Returns true if the operation represents an insertion.
+ *
+ * @see #newInsert
+ */
public boolean isInsert() {
return mType == TYPE_INSERT;
}
+ /**
+ * Returns true if the operation represents a deletion.
+ *
+ * @see #newDelete
+ */
public boolean isDelete() {
return mType == TYPE_DELETE;
}
+ /**
+ * Returns true if the operation represents an update.
+ *
+ * @see #newUpdate
+ */
public boolean isUpdate() {
return mType == TYPE_UPDATE;
}
+ /**
+ * Returns true if the operation represents an assert query.
+ *
+ * @see #newAssertQuery
+ */
public boolean isAssertQuery() {
return mType == TYPE_ASSERT;
}
+ /**
+ * Returns true if the operation represents an insertion, deletion, or update.
+ *
+ * @see #isInsert
+ * @see #isDelete
+ * @see #isUpdate
+ */
public boolean isWriteOperation() {
return mType == TYPE_DELETE || mType == TYPE_INSERT || mType == TYPE_UPDATE;
}
+ /**
+ * Returns true if the operation represents an assert query.
+ *
+ * @see #isAssertQuery
+ */
public boolean isReadOperation() {
return mType == TYPE_ASSERT;
}
@@ -617,7 +663,7 @@
}
/**
- * If set then if the number of rows affected by this operation do not match
+ * If set then if the number of rows affected by this operation does not match
* this count {@link OperationApplicationException} will be throw.
* This can only be used with builders of type update, delete, or assert.
* @return this builder, to allow for chaining.
@@ -631,6 +677,12 @@
return this;
}
+ /**
+ * If set to true then the operation allows yielding the database to other transactions
+ * if the database is contended.
+ * @return this builder, to allow for chaining.
+ * @see android.database.sqlite.SQLiteDatabase#yieldIfContendedSafely()
+ */
public Builder withYieldAllowed(boolean yieldAllowed) {
mYieldAllowed = yieldAllowed;
return this;
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index 96a80e7..057001c 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -17,6 +17,7 @@
package android.content;
import android.accounts.Account;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManagerNative;
import android.app.ActivityThread;
@@ -47,6 +48,8 @@
import dalvik.system.CloseGuard;
+import com.android.internal.util.Preconditions;
+
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
@@ -320,7 +323,9 @@
* using the content:// scheme.
* @return A MIME type for the content, or null if the URL is invalid or the type is unknown
*/
- public final String getType(Uri url) {
+ public final @Nullable String getType(@NonNull Uri url) {
+ Preconditions.checkNotNull(url, "url");
+
// XXX would like to have an acquireExistingUnstableProvider for this.
IContentProvider provider = acquireExistingProvider(url);
if (provider != null) {
@@ -371,7 +376,10 @@
* data streams that match the given mimeTypeFilter. If there are none,
* null is returned.
*/
- public String[] getStreamTypes(Uri url, String mimeTypeFilter) {
+ public @Nullable String[] getStreamTypes(@NonNull Uri url, @NonNull String mimeTypeFilter) {
+ Preconditions.checkNotNull(url, "url");
+ Preconditions.checkNotNull(mimeTypeFilter, "mimeTypeFilter");
+
IContentProvider provider = acquireProvider(url);
if (provider == null) {
return null;
@@ -418,8 +426,9 @@
* @return A Cursor object, which is positioned before the first entry, or null
* @see Cursor
*/
- public final Cursor query(Uri uri, String[] projection,
- String selection, String[] selectionArgs, String sortOrder) {
+ public final @Nullable Cursor query(@NonNull Uri uri, @Nullable String[] projection,
+ @Nullable String selection, @Nullable String[] selectionArgs,
+ @Nullable String sortOrder) {
return query(uri, projection, selection, selectionArgs, sortOrder, null);
}
@@ -457,9 +466,10 @@
* @return A Cursor object, which is positioned before the first entry, or null
* @see Cursor
*/
- public final Cursor query(final Uri uri, String[] projection,
- String selection, String[] selectionArgs, String sortOrder,
- CancellationSignal cancellationSignal) {
+ public final @Nullable Cursor query(final @NonNull Uri uri, @Nullable String[] projection,
+ @Nullable String selection, @Nullable String[] selectionArgs,
+ @Nullable String sortOrder, @Nullable CancellationSignal cancellationSignal) {
+ Preconditions.checkNotNull(uri, "uri");
IContentProvider unstableProvider = acquireUnstableProvider(uri);
if (unstableProvider == null) {
return null;
@@ -555,7 +565,8 @@
*
* @see #uncanonicalize
*/
- public final Uri canonicalize(Uri url) {
+ public final @Nullable Uri canonicalize(@NonNull Uri url) {
+ Preconditions.checkNotNull(url, "url");
IContentProvider provider = acquireProvider(url);
if (provider == null) {
return null;
@@ -590,7 +601,8 @@
*
* @see #canonicalize
*/
- public final Uri uncanonicalize(Uri url) {
+ public final @Nullable Uri uncanonicalize(@NonNull Uri url) {
+ Preconditions.checkNotNull(url, "url");
IContentProvider provider = acquireProvider(url);
if (provider == null) {
return null;
@@ -626,8 +638,9 @@
* @throws FileNotFoundException if the provided URI could not be opened.
* @see #openAssetFileDescriptor(Uri, String)
*/
- public final InputStream openInputStream(Uri uri)
+ public final @Nullable InputStream openInputStream(@NonNull Uri uri)
throws FileNotFoundException {
+ Preconditions.checkNotNull(uri, "uri");
String scheme = uri.getScheme();
if (SCHEME_ANDROID_RESOURCE.equals(scheme)) {
// Note: left here to avoid breaking compatibility. May be removed
@@ -658,7 +671,7 @@
* openOutputStream(uri, "w")}.
* @throws FileNotFoundException if the provided URI could not be opened.
*/
- public final OutputStream openOutputStream(Uri uri)
+ public final @Nullable OutputStream openOutputStream(@NonNull Uri uri)
throws FileNotFoundException {
return openOutputStream(uri, "w");
}
@@ -682,7 +695,7 @@
* @throws FileNotFoundException if the provided URI could not be opened.
* @see #openAssetFileDescriptor(Uri, String)
*/
- public final OutputStream openOutputStream(Uri uri, String mode)
+ public final @Nullable OutputStream openOutputStream(@NonNull Uri uri, @NonNull String mode)
throws FileNotFoundException {
AssetFileDescriptor fd = openAssetFileDescriptor(uri, mode, null);
try {
@@ -729,8 +742,8 @@
* file exists under the URI or the mode is invalid.
* @see #openAssetFileDescriptor(Uri, String)
*/
- public final ParcelFileDescriptor openFileDescriptor(Uri uri, String mode)
- throws FileNotFoundException {
+ public final @Nullable ParcelFileDescriptor openFileDescriptor(@NonNull Uri uri,
+ @NonNull String mode) throws FileNotFoundException {
return openFileDescriptor(uri, mode, null);
}
@@ -774,8 +787,9 @@
* file exists under the URI or the mode is invalid.
* @see #openAssetFileDescriptor(Uri, String)
*/
- public final ParcelFileDescriptor openFileDescriptor(Uri uri,
- String mode, CancellationSignal cancellationSignal) throws FileNotFoundException {
+ public final @Nullable ParcelFileDescriptor openFileDescriptor(@NonNull Uri uri,
+ @NonNull String mode, @Nullable CancellationSignal cancellationSignal)
+ throws FileNotFoundException {
AssetFileDescriptor afd = openAssetFileDescriptor(uri, mode, cancellationSignal);
if (afd == null) {
return null;
@@ -844,8 +858,8 @@
* @throws FileNotFoundException Throws FileNotFoundException of no
* file exists under the URI or the mode is invalid.
*/
- public final AssetFileDescriptor openAssetFileDescriptor(Uri uri, String mode)
- throws FileNotFoundException {
+ public final @Nullable AssetFileDescriptor openAssetFileDescriptor(@NonNull Uri uri,
+ @NonNull String mode) throws FileNotFoundException {
return openAssetFileDescriptor(uri, mode, null);
}
@@ -900,8 +914,12 @@
* @throws FileNotFoundException Throws FileNotFoundException of no
* file exists under the URI or the mode is invalid.
*/
- public final AssetFileDescriptor openAssetFileDescriptor(Uri uri,
- String mode, CancellationSignal cancellationSignal) throws FileNotFoundException {
+ public final @Nullable AssetFileDescriptor openAssetFileDescriptor(@NonNull Uri uri,
+ @NonNull String mode, @Nullable CancellationSignal cancellationSignal)
+ throws FileNotFoundException {
+ Preconditions.checkNotNull(uri, "uri");
+ Preconditions.checkNotNull(mode, "mode");
+
String scheme = uri.getScheme();
if (SCHEME_ANDROID_RESOURCE.equals(scheme)) {
if (!"r".equals(mode)) {
@@ -1023,8 +1041,8 @@
* @throws FileNotFoundException Throws FileNotFoundException of no
* data of the desired type exists under the URI.
*/
- public final AssetFileDescriptor openTypedAssetFileDescriptor(
- Uri uri, String mimeType, Bundle opts) throws FileNotFoundException {
+ public final @Nullable AssetFileDescriptor openTypedAssetFileDescriptor(@NonNull Uri uri,
+ @NonNull String mimeType, @Nullable Bundle opts) throws FileNotFoundException {
return openTypedAssetFileDescriptor(uri, mimeType, opts, null);
}
@@ -1059,9 +1077,12 @@
* @throws FileNotFoundException Throws FileNotFoundException of no
* data of the desired type exists under the URI.
*/
- public final AssetFileDescriptor openTypedAssetFileDescriptor(Uri uri,
- String mimeType, Bundle opts, CancellationSignal cancellationSignal)
- throws FileNotFoundException {
+ public final @Nullable AssetFileDescriptor openTypedAssetFileDescriptor(@NonNull Uri uri,
+ @NonNull String mimeType, @Nullable Bundle opts,
+ @Nullable CancellationSignal cancellationSignal) throws FileNotFoundException {
+ Preconditions.checkNotNull(uri, "uri");
+ Preconditions.checkNotNull(mimeType, "mimeType");
+
IContentProvider unstableProvider = acquireUnstableProvider(uri);
if (unstableProvider == null) {
throw new FileNotFoundException("No content provider: " + uri);
@@ -1197,8 +1218,8 @@
* the field. Passing an empty ContentValues will create an empty row.
* @return the URL of the newly created row.
*/
- public final Uri insert(Uri url, ContentValues values)
- {
+ public final @Nullable Uri insert(@NonNull Uri url, @Nullable ContentValues values) {
+ Preconditions.checkNotNull(url, "url");
IContentProvider provider = acquireProvider(url);
if (provider == null) {
throw new IllegalArgumentException("Unknown URL " + url);
@@ -1234,9 +1255,11 @@
* @throws RemoteException thrown if a RemoteException is encountered while attempting
* to communicate with a remote provider.
*/
- public ContentProviderResult[] applyBatch(String authority,
- ArrayList<ContentProviderOperation> operations)
- throws RemoteException, OperationApplicationException {
+ public @NonNull ContentProviderResult[] applyBatch(@NonNull String authority,
+ @NonNull ArrayList<ContentProviderOperation> operations)
+ throws RemoteException, OperationApplicationException {
+ Preconditions.checkNotNull(authority, "authority");
+ Preconditions.checkNotNull(operations, "operations");
ContentProviderClient provider = acquireContentProviderClient(authority);
if (provider == null) {
throw new IllegalArgumentException("Unknown authority " + authority);
@@ -1258,8 +1281,9 @@
* the field. Passing null will create an empty row.
* @return the number of newly created rows.
*/
- public final int bulkInsert(Uri url, ContentValues[] values)
- {
+ public final int bulkInsert(@NonNull Uri url, @NonNull ContentValues[] values) {
+ Preconditions.checkNotNull(url, "url");
+ Preconditions.checkNotNull(values, "values");
IContentProvider provider = acquireProvider(url);
if (provider == null) {
throw new IllegalArgumentException("Unknown URL " + url);
@@ -1289,8 +1313,9 @@
(excluding the WHERE itself).
* @return The number of rows deleted.
*/
- public final int delete(Uri url, String where, String[] selectionArgs)
- {
+ public final int delete(@NonNull Uri url, @Nullable String where,
+ @Nullable String[] selectionArgs) {
+ Preconditions.checkNotNull(url, "url");
IContentProvider provider = acquireProvider(url);
if (provider == null) {
throw new IllegalArgumentException("Unknown URL " + url);
@@ -1323,8 +1348,9 @@
* @return the number of rows updated.
* @throws NullPointerException if uri or values are null
*/
- public final int update(Uri uri, ContentValues values, String where,
- String[] selectionArgs) {
+ public final int update(@NonNull Uri uri, @Nullable ContentValues values,
+ @Nullable String where, @Nullable String[] selectionArgs) {
+ Preconditions.checkNotNull(uri, "uri");
IContentProvider provider = acquireProvider(uri);
if (provider == null) {
throw new IllegalArgumentException("Unknown URI " + uri);
@@ -1358,14 +1384,10 @@
* @throws NullPointerException if uri or method is null
* @throws IllegalArgumentException if uri is not known
*/
- public final Bundle call(
- Uri uri, String method, @Nullable String arg, @Nullable Bundle extras) {
- if (uri == null) {
- throw new NullPointerException("uri == null");
- }
- if (method == null) {
- throw new NullPointerException("method == null");
- }
+ public final @Nullable Bundle call(@NonNull Uri uri, @NonNull String method,
+ @Nullable String arg, @Nullable Bundle extras) {
+ Preconditions.checkNotNull(uri, "uri");
+ Preconditions.checkNotNull(method, "method");
IContentProvider provider = acquireProvider(uri);
if (provider == null) {
throw new IllegalArgumentException("Unknown URI " + uri);
@@ -1467,12 +1489,12 @@
* @return a {@link ContentProviderClient} that is associated with the {@link ContentProvider}
* that services the content at uri or null if there isn't one.
*/
- public final ContentProviderClient acquireContentProviderClient(Uri uri) {
+ public final @Nullable ContentProviderClient acquireContentProviderClient(@NonNull Uri uri) {
+ Preconditions.checkNotNull(uri, "uri");
IContentProvider provider = acquireProvider(uri);
if (provider != null) {
return new ContentProviderClient(this, provider, true);
}
-
return null;
}
@@ -1487,7 +1509,9 @@
* @return a {@link ContentProviderClient} that is associated with the {@link ContentProvider}
* with the authority of name or null if there isn't one.
*/
- public final ContentProviderClient acquireContentProviderClient(String name) {
+ public final @Nullable ContentProviderClient acquireContentProviderClient(
+ @NonNull String name) {
+ Preconditions.checkNotNull(name, "name");
IContentProvider provider = acquireProvider(name);
if (provider != null) {
return new ContentProviderClient(this, provider, true);
@@ -1512,7 +1536,9 @@
* can acquire a new one if you would like to try to restart the provider
* and perform new operations on it.
*/
- public final ContentProviderClient acquireUnstableContentProviderClient(Uri uri) {
+ public final @Nullable ContentProviderClient acquireUnstableContentProviderClient(
+ @NonNull Uri uri) {
+ Preconditions.checkNotNull(uri, "uri");
IContentProvider provider = acquireUnstableProvider(uri);
if (provider != null) {
return new ContentProviderClient(this, provider, false);
@@ -1537,7 +1563,9 @@
* can acquire a new one if you would like to try to restart the provider
* and perform new operations on it.
*/
- public final ContentProviderClient acquireUnstableContentProviderClient(String name) {
+ public final @Nullable ContentProviderClient acquireUnstableContentProviderClient(
+ @NonNull String name) {
+ Preconditions.checkNotNull(name, "name");
IContentProvider provider = acquireUnstableProvider(name);
if (provider != null) {
return new ContentProviderClient(this, provider, false);
@@ -1559,8 +1587,10 @@
* @param observer The object that receives callbacks when changes occur.
* @see #unregisterContentObserver
*/
- public final void registerContentObserver(Uri uri, boolean notifyForDescendents,
- ContentObserver observer) {
+ public final void registerContentObserver(@NonNull Uri uri, boolean notifyForDescendents,
+ @NonNull ContentObserver observer) {
+ Preconditions.checkNotNull(uri, "uri");
+ Preconditions.checkNotNull(observer, "observer");
registerContentObserver(uri, notifyForDescendents, observer, UserHandle.myUserId());
}
@@ -1580,7 +1610,8 @@
* @param observer The previously registered observer that is no longer needed.
* @see #registerContentObserver
*/
- public final void unregisterContentObserver(ContentObserver observer) {
+ public final void unregisterContentObserver(@NonNull ContentObserver observer) {
+ Preconditions.checkNotNull(observer, "observer");
try {
IContentObserver contentObserver = observer.releaseContentObserver();
if (contentObserver != null) {
@@ -1603,7 +1634,7 @@
* has requested to receive self-change notifications by implementing
* {@link ContentObserver#deliverSelfNotifications()} to return true.
*/
- public void notifyChange(Uri uri, ContentObserver observer) {
+ public void notifyChange(@NonNull Uri uri, @Nullable ContentObserver observer) {
notifyChange(uri, observer, true /* sync to network */);
}
@@ -1623,7 +1654,9 @@
* @param syncToNetwork If true, attempt to sync the change to the network.
* @see #requestSync(android.accounts.Account, String, android.os.Bundle)
*/
- public void notifyChange(Uri uri, ContentObserver observer, boolean syncToNetwork) {
+ public void notifyChange(@NonNull Uri uri, @Nullable ContentObserver observer,
+ boolean syncToNetwork) {
+ Preconditions.checkNotNull(uri, "uri");
notifyChange(uri, observer, syncToNetwork, UserHandle.myUserId());
}
@@ -1653,7 +1686,9 @@
*
* @see #getPersistedUriPermissions()
*/
- public void takePersistableUriPermission(Uri uri, @Intent.AccessUriMode int modeFlags) {
+ public void takePersistableUriPermission(@NonNull Uri uri,
+ @Intent.AccessUriMode int modeFlags) {
+ Preconditions.checkNotNull(uri, "uri");
try {
ActivityManagerNative.getDefault().takePersistableUriPermission(
ContentProvider.getUriWithoutUserId(uri), modeFlags, resolveUserId(uri));
@@ -1669,7 +1704,9 @@
*
* @see #getPersistedUriPermissions()
*/
- public void releasePersistableUriPermission(Uri uri, @Intent.AccessUriMode int modeFlags) {
+ public void releasePersistableUriPermission(@NonNull Uri uri,
+ @Intent.AccessUriMode int modeFlags) {
+ Preconditions.checkNotNull(uri, "uri");
try {
ActivityManagerNative.getDefault().releasePersistableUriPermission(
ContentProvider.getUriWithoutUserId(uri), modeFlags, resolveUserId(uri));
@@ -1686,7 +1723,7 @@
* @see #takePersistableUriPermission(Uri, int)
* @see #releasePersistableUriPermission(Uri, int)
*/
- public List<UriPermission> getPersistedUriPermissions() {
+ public @NonNull List<UriPermission> getPersistedUriPermissions() {
try {
return ActivityManagerNative.getDefault()
.getPersistedUriPermissions(mPackageName, true).getList();
@@ -1701,7 +1738,7 @@
* <em>from</em> the calling app. Only grants taken with
* {@link #takePersistableUriPermission(Uri, int)} are returned.
*/
- public List<UriPermission> getOutgoingPersistedUriPermissions() {
+ public @NonNull List<UriPermission> getOutgoingPersistedUriPermissions() {
try {
return ActivityManagerNative.getDefault()
.getPersistedUriPermissions(mPackageName, false).getList();
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index a434c7b..970623a 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -1256,7 +1256,7 @@
* @param intent The description of the activity to start.
*
* @throws ActivityNotFoundException
- *
+ *`
* @see #startActivity(Intent, Bundle)
* @see PackageManager#resolveActivity
*/
@@ -2443,8 +2443,6 @@
*
* @param serviceClass The class of the desired service.
* @return The service name or null if the class is not a supported system service.
- *
- * @hide
*/
public abstract String getSystemServiceName(Class<?> serviceClass);
diff --git a/core/java/android/content/IntentFilter.java b/core/java/android/content/IntentFilter.java
index 33c0b87..08c5236 100644
--- a/core/java/android/content/IntentFilter.java
+++ b/core/java/android/content/IntentFilter.java
@@ -254,12 +254,14 @@
* HTTP scheme.
*
* @see #addDataScheme(String)
+ * @hide
*/
public static final String SCHEME_HTTP = "http";
/**
* HTTPS scheme.
*
* @see #addDataScheme(String)
+ * @hide
*/
public static final String SCHEME_HTTPS = "https";
diff --git a/core/java/android/content/pm/IOnPermissionsChangeListener.aidl b/core/java/android/content/pm/IOnPermissionsChangeListener.aidl
new file mode 100644
index 0000000..7791b50
--- /dev/null
+++ b/core/java/android/content/pm/IOnPermissionsChangeListener.aidl
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.pm;
+
+/**
+ * Listener for changes in the permissions for installed packages.
+ * {@hide}
+ */
+oneway interface IOnPermissionsChangeListener {
+ void onPermissionsChanged(int uid);
+}
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 00b8c71..0c07bc3 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -31,6 +31,7 @@
import android.content.pm.IPackageDataObserver;
import android.content.pm.IPackageMoveObserver;
import android.content.pm.IPackageStatsObserver;
+import android.content.pm.IOnPermissionsChangeListener;
import android.content.pm.IntentFilterVerificationInfo;
import android.content.pm.InstrumentationInfo;
import android.content.pm.KeySet;
@@ -490,4 +491,7 @@
KeySet getSigningKeySet(String packageName);
boolean isPackageSignedByKeySet(String packageName, in KeySet ks);
boolean isPackageSignedByKeySetExactly(String packageName, in KeySet ks);
+
+ void addOnPermissionsChangeListener(in IOnPermissionsChangeListener listener);
+ void removeOnPermissionsChangeListener(in IOnPermissionsChangeListener listener);
}
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 68092c8..bd50ca0 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -16,11 +16,13 @@
package android.content.pm;
+import android.Manifest;
import android.annotation.CheckResult;
import android.annotation.DrawableRes;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.annotation.StringRes;
@@ -78,6 +80,21 @@
}
/**
+ * Listener for changes in permissions granted to a UID.
+ *
+ * @hide
+ */
+ @SystemApi
+ public interface OnPermissionsChangedListener {
+
+ /**
+ * Called when the permissions for a UID change.
+ * @param uid The UID with a change.
+ */
+ public void onPermissionsChanged(int uid);
+ }
+
+ /**
* {@link PackageInfo} flag: return information about
* activities in the package in {@link PackageInfo#activities}.
*/
@@ -2636,7 +2653,7 @@
/**
* Retrieve the official name associated with a user id. This name is
- * guaranteed to never change, though it is possibly for the underlying
+ * guaranteed to never change, though it is possible for the underlying
* user id to be changed. That is, if you are storing information about
* user ids in persistent storage, you should use the string returned
* by this function instead of the raw user-id.
@@ -4295,6 +4312,27 @@
public abstract boolean isSafeMode();
/**
+ * Adds a listener for permission changes for installed packages.
+ *
+ * @param listener The listener to add.
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(Manifest.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS)
+ public abstract void addOnPermissionsChangeListener(OnPermissionsChangedListener listener);
+
+ /**
+ * Remvoes a listener for permission changes for installed packages.
+ *
+ * @param listener The listener to remove.
+ *
+ * @hide
+ */
+ @SystemApi
+ public abstract void removeOnPermissionsChangeListener(OnPermissionsChangedListener listener);
+
+ /**
* Return the {@link KeySet} associated with the String alias for this
* application.
*
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 83b0140..c92c256 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -36,6 +36,7 @@
import android.content.res.XmlResourceParser;
import android.os.Build;
import android.os.Bundle;
+import android.os.FileUtils;
import android.os.PatternMatcher;
import android.os.UserHandle;
import android.text.TextUtils;
@@ -1194,7 +1195,8 @@
}
}
- private static String validateName(String name, boolean requiresSeparator) {
+ private static String validateName(String name, boolean requireSeparator,
+ boolean requireFilename) {
final int N = name.length();
boolean hasSep = false;
boolean front = true;
@@ -1216,7 +1218,10 @@
}
return "bad character '" + c + "'";
}
- return hasSep || !requiresSeparator
+ if (requireFilename && !FileUtils.isValidExtFilename(name)) {
+ return "Invalid filename";
+ }
+ return hasSep || !requireSeparator
? null : "must have at least one '.' separator";
}
@@ -1240,7 +1245,7 @@
final String packageName = attrs.getAttributeValue(null, "package");
if (!"android".equals(packageName)) {
- final String error = validateName(packageName, true);
+ final String error = validateName(packageName, true, true);
if (error != null) {
throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME,
"Invalid manifest package: " + error);
@@ -1252,7 +1257,7 @@
if (splitName.length() == 0) {
splitName = null;
} else {
- final String error = validateName(splitName, false);
+ final String error = validateName(splitName, false, false);
if (error != null) {
throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME,
"Invalid manifest split: " + error);
@@ -1391,7 +1396,7 @@
String str = sa.getNonConfigurationString(
com.android.internal.R.styleable.AndroidManifest_sharedUserId, 0);
if (str != null && str.length() > 0) {
- String nameError = validateName(str, true);
+ String nameError = validateName(str, true, false);
if (nameError != null && !"android".equals(pkgName)) {
outError[0] = "<manifest> specifies bad sharedUserId name \""
+ str + "\": " + nameError;
@@ -1973,7 +1978,7 @@
return null;
}
String subName = proc.substring(1);
- String nameError = validateName(subName, false);
+ String nameError = validateName(subName, false, false);
if (nameError != null) {
outError[0] = "Invalid " + type + " name " + proc + " in package "
+ pkg + ": " + nameError;
@@ -1981,7 +1986,7 @@
}
return (pkg + proc).intern();
}
- String nameError = validateName(proc, true);
+ String nameError = validateName(proc, true, false);
if (nameError != null && !"system".equals(proc)) {
outError[0] = "Invalid " + type + " name " + proc + " in package "
+ pkg + ": " + nameError;
diff --git a/core/java/android/hardware/SensorManager.java b/core/java/android/hardware/SensorManager.java
index fda889f..d6b1142 100644
--- a/core/java/android/hardware/SensorManager.java
+++ b/core/java/android/hardware/SensorManager.java
@@ -1577,7 +1577,7 @@
* Significant Motion, Step Counter etc.
*
* The tests which call this API need to have {@code
- * android.permission.HARDWARE_TEST} permission which isn't
+ * android.permission.LOCATION_HADWARE} permission which isn't
* available for third party applications.
*
* @param enable True to set the HAL in DATA_INJECTION mode.
@@ -1607,7 +1607,7 @@
* the HAL is already in data injection mode.
*
* The tests which call this API need to have {@code
- * android.permission.HARDWARE_TEST} permission which isn't
+ * android.permission.LOCATION_HARDWARE} permission which isn't
* available for third party applications.
*
* @param sensor The sensor to inject.
diff --git a/core/java/android/hardware/SystemSensorManager.java b/core/java/android/hardware/SystemSensorManager.java
index 22a9e9c..d7960af 100644
--- a/core/java/android/hardware/SystemSensorManager.java
+++ b/core/java/android/hardware/SystemSensorManager.java
@@ -80,7 +80,7 @@
nativeClassInit();
}
mHasDataInjectionPermissions = context.checkSelfPermission(
- Manifest.permission.HARDWARE_TEST) == PackageManager.PERMISSION_GRANTED;
+ Manifest.permission.LOCATION_HARDWARE) == PackageManager.PERMISSION_GRANTED;
}
// initialize the sensor list
@@ -233,7 +233,7 @@
protected boolean enableDataInjectionImpl(boolean enable) {
if (!mHasDataInjectionPermissions) {
throw new SecurityException("Permission denial. Calling enableDataInjection without "
- + Manifest.permission.HARDWARE_TEST);
+ + Manifest.permission.LOCATION_HARDWARE);
}
synchronized (mLock) {
int ret = nativeEnableDataInjection(mNativeInstance, enable);
@@ -256,7 +256,7 @@
long timestamp) {
if (!mHasDataInjectionPermissions) {
throw new SecurityException("Permission denial. Calling injectSensorData without "
- + Manifest.permission.HARDWARE_TEST);
+ + Manifest.permission.LOCATION_HARDWARE);
}
synchronized (mLock) {
if (!mDataInjectionMode) {
diff --git a/core/java/android/hardware/camera2/CameraCaptureSession.java b/core/java/android/hardware/camera2/CameraCaptureSession.java
index 82d40d3..c547b06 100644
--- a/core/java/android/hardware/camera2/CameraCaptureSession.java
+++ b/core/java/android/hardware/camera2/CameraCaptureSession.java
@@ -150,9 +150,17 @@
* {@link CaptureRequest.Builder#addTarget}) must be a subset of the surfaces provided when this
* capture session was created.</p>
*
- * <p>Multiple requests can be in progress at once. They are processed in
- * first-in, first-out order, with minimal delays between each
- * capture. Requests submitted through this method have higher priority than
+ * <p>Multiple regular and reprocess requests can be in progress at once. If there are only
+ * regular requests or reprocess requests in progress, they are processed in first-in,
+ * first-out order. If there are both regular and reprocess requests in progress, regular
+ * requests are processed in first-in, first-out order and reprocess requests are processed in
+ * first-in, first-out order, respectively. However, the processing order of a regular request
+ * and a reprocess request in progress is not specified. In other words, a regular request
+ * will always be processed before regular requets that are submitted later. A reprocess request
+ * will always be processed before reprocess requests that are submitted later. However, a
+ * regular request may not be processed before reprocess requests that are submitted later.<p>
+ *
+ * <p>Requests submitted through this method have higher priority than
* those submitted through {@link #setRepeatingRequest} or
* {@link #setRepeatingBurst}, and will be processed as soon as the current
* repeat/repeatBurst processing completes.</p>
@@ -207,10 +215,13 @@
* not be interleaved with requests submitted by other capture or repeat
* calls.
*
- * <p>The requests will be captured in order, each capture producing one {@link CaptureResult}
- * and image buffers for one or more target {@link android.view.Surface surfaces}. The target
- * surfaces (set with {@link CaptureRequest.Builder#addTarget}) must be a subset of the surfaces
- * provided when this capture session was created.</p>
+ * <p>Regular and reprocess requests can be mixed together in a single burst. Regular requests
+ * will be captured in order and reprocess requests will be processed in order, respectively.
+ * However, the processing order between a regular request and a reprocess request is not
+ * specified. Each capture produces one {@link CaptureResult} and image buffers for one or more
+ * target {@link android.view.Surface surfaces}. The target surfaces (set with
+ * {@link CaptureRequest.Builder#addTarget}) must be a subset of the surfaces provided when
+ * this capture session was created.</p>
*
* <p>The main difference between this method and simply calling
* {@link #capture} repeatedly is that this method guarantees that no
diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
index c073ba5..8512b23 100644
--- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
@@ -52,6 +52,7 @@
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
+import java.util.concurrent.atomic.AtomicBoolean;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
@@ -79,7 +80,7 @@
private volatile StateCallbackKK mSessionStateCallback;
private final Handler mDeviceHandler;
- private volatile boolean mClosing = false;
+ private final AtomicBoolean mClosing = new AtomicBoolean();
private boolean mInError = false;
private boolean mIdle = true;
@@ -906,6 +907,10 @@
@Override
public void close() {
synchronized (mInterfaceLock) {
+ if (mClosing.getAndSet(true)) {
+ return;
+ }
+
try {
if (mRemoteDevice != null) {
mRemoteDevice.disconnect();
@@ -1917,13 +1922,35 @@
/** Whether the camera device has started to close (may not yet have finished) */
private boolean isClosed() {
- return mClosing;
+ return mClosing.get();
}
private CameraCharacteristics getCharacteristics() {
return mCharacteristics;
}
+ /**
+ * A high speed output surface can only be preview or hardware encoder surface.
+ *
+ * @param surface The high speed output surface to be checked.
+ */
+ private void checkHighSpeedSurfaceFormat(Surface surface) {
+ // TODO: remove this override since the default format should be
+ // ImageFormat.PRIVATE. b/9487482
+ final int HAL_FORMAT_RGB_START = 1; // HAL_PIXEL_FORMAT_RGBA_8888 from graphics.h
+ final int HAL_FORMAT_RGB_END = 5; // HAL_PIXEL_FORMAT_BGRA_8888 from graphics.h
+ int surfaceFormat = SurfaceUtils.getSurfaceFormat(surface);
+ if (surfaceFormat >= HAL_FORMAT_RGB_START &&
+ surfaceFormat <= HAL_FORMAT_RGB_END) {
+ surfaceFormat = ImageFormat.PRIVATE;
+ }
+
+ if (surfaceFormat != ImageFormat.PRIVATE) {
+ throw new IllegalArgumentException("Surface format(" + surfaceFormat + ") is not"
+ + " for preview or hardware video encoding!");
+ }
+ }
+
private void checkConstrainedHighSpeedSurfaces(Collection<Surface> surfaces,
Range<Integer> fpsRange) {
if (surfaces == null || surfaces.size() == 0 || surfaces.size() > 2) {
@@ -1948,15 +1975,10 @@
}
for (Surface surface : surfaces) {
+ checkHighSpeedSurfaceFormat(surface);
+
// Surface size must be supported high speed sizes.
Size surfaceSize = SurfaceUtils.getSurfaceSize(surface);
- int surfaceFormat = SurfaceUtils.getSurfaceFormat(surface);
-
- if (surfaceFormat != ImageFormat.PRIVATE) {
- throw new IllegalArgumentException("Surface format is not for preview or"
- + " hardware video encoding" + surfaceFormat);
- }
-
if (!highSpeedSizes.contains(surfaceSize)) {
throw new IllegalArgumentException("Surface size " + surfaceSize.toString() + " is"
+ " not part of the high speed supported size list " +
diff --git a/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java b/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java
index cc9d496..cc95c0e 100644
--- a/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java
+++ b/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java
@@ -87,6 +87,9 @@
public static final int MAX_DIMEN_FOR_ROUNDING = 1080; // maximum allowed width for rounding
+ // Keep up to date with values in system/core/include/system/window.h
+ public static final int NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW = 1;
+
private CaptureResultExtras getExtrasFromRequest(RequestHolder holder) {
if (holder == null) {
return new CaptureResultExtras(ILLEGAL_VALUE, ILLEGAL_VALUE, ILLEGAL_VALUE,
@@ -565,7 +568,7 @@
throw new IllegalArgumentException("Surface was abandoned", e);
}
- return previewConsumer && (surfaceFormat == ImageFormat.PRIVATE);
+ return previewConsumer;
}
public static boolean isVideoEncoderConsumer(Surface output) {
@@ -583,7 +586,7 @@
throw new IllegalArgumentException("Surface was abandoned", e);
}
- return videoEncoderConsumer && (surfaceFormat == ImageFormat.PRIVATE);
+ return videoEncoderConsumer;
}
/**
@@ -690,6 +693,13 @@
LegacyExceptionUtils.throwOnError(nativeSetNextTimestamp(surface, timestamp));
}
+ static void setScalingMode(Surface surface, int mode)
+ throws BufferQueueAbandonedException {
+ checkNotNull(surface);
+ LegacyExceptionUtils.throwOnError(nativeSetScalingMode(surface, mode));
+ }
+
+
private static native int nativeDetectSurfaceType(Surface surface);
private static native int nativeDetectSurfaceDimens(Surface surface,
@@ -717,5 +727,7 @@
private static native int nativeDetectSurfaceUsageFlags(Surface surface);
+ private static native int nativeSetScalingMode(Surface surface, int scalingMode);
+
static native int nativeGetJpegFooterSize();
}
diff --git a/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java b/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java
index 33a802b..8bdd42a 100644
--- a/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java
+++ b/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java
@@ -415,8 +415,9 @@
Range<Integer>[] ranges = new Range[rangesSize];
int i = 0;
for (int[] r : fpsRanges) {
- ranges[i++] = Range.create(r[Camera.Parameters.PREVIEW_FPS_MIN_INDEX],
- r[Camera.Parameters.PREVIEW_FPS_MAX_INDEX]);
+ ranges[i++] = Range.create(
+ (int) Math.floor(r[Camera.Parameters.PREVIEW_FPS_MIN_INDEX] / 1000.0),
+ (int) Math.ceil(r[Camera.Parameters.PREVIEW_FPS_MAX_INDEX] / 1000.0));
}
m.set(CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES, ranges);
}
diff --git a/core/java/android/hardware/camera2/legacy/LegacyRequestMapper.java b/core/java/android/hardware/camera2/legacy/LegacyRequestMapper.java
index d5d7f0d..6a44ac5 100644
--- a/core/java/android/hardware/camera2/legacy/LegacyRequestMapper.java
+++ b/core/java/android/hardware/camera2/legacy/LegacyRequestMapper.java
@@ -162,17 +162,19 @@
if (aeFpsRange != null) {
int[] legacyFps = convertAeFpsRangeToLegacy(aeFpsRange);
- // TODO - Should we enforce that all HAL1 devices must include (30, 30) FPS range?
- boolean supported = false;
+ int[] rangeToApply = null;
for(int[] range : params.getSupportedPreviewFpsRange()) {
- if (legacyFps[0] == range[0] && legacyFps[1] == range[1]) {
- supported = true;
+ // Round range up/down to integer FPS value
+ int intRangeLow = (int) Math.floor(range[0] / 1000.0) * 1000;
+ int intRangeHigh = (int) Math.ceil(range[1] / 1000.0) * 1000;
+ if (legacyFps[0] == intRangeLow && legacyFps[1] == intRangeHigh) {
+ rangeToApply = range;
break;
}
}
- if (supported) {
- params.setPreviewFpsRange(legacyFps[Camera.Parameters.PREVIEW_FPS_MIN_INDEX],
- legacyFps[Camera.Parameters.PREVIEW_FPS_MAX_INDEX]);
+ if (rangeToApply != null) {
+ params.setPreviewFpsRange(rangeToApply[Camera.Parameters.PREVIEW_FPS_MIN_INDEX],
+ rangeToApply[Camera.Parameters.PREVIEW_FPS_MAX_INDEX]);
} else {
Log.w(TAG, "Unsupported FPS range set [" + legacyFps[0] + "," + legacyFps[1] + "]");
}
@@ -626,8 +628,8 @@
private static int[] convertAeFpsRangeToLegacy(Range<Integer> fpsRange) {
int[] legacyFps = new int[2];
- legacyFps[Parameters.PREVIEW_FPS_MIN_INDEX] = fpsRange.getLower();
- legacyFps[Parameters.PREVIEW_FPS_MAX_INDEX] = fpsRange.getUpper();
+ legacyFps[Parameters.PREVIEW_FPS_MIN_INDEX] = fpsRange.getLower() * 1000;
+ legacyFps[Parameters.PREVIEW_FPS_MAX_INDEX] = fpsRange.getUpper() * 1000;
return legacyFps;
}
diff --git a/core/java/android/hardware/camera2/legacy/RequestThreadManager.java b/core/java/android/hardware/camera2/legacy/RequestThreadManager.java
index 5ea1ab8..348b14a 100644
--- a/core/java/android/hardware/camera2/legacy/RequestThreadManager.java
+++ b/core/java/android/hardware/camera2/legacy/RequestThreadManager.java
@@ -384,6 +384,8 @@
callbackOutputSizes.add(outSize);
break;
default:
+ LegacyCameraDevice.setScalingMode(s, LegacyCameraDevice.
+ NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
mPreviewOutputs.add(s);
previewOutputSizes.add(outSize);
break;
@@ -412,6 +414,9 @@
mParams.setPreviewFpsRange(bestRange[Camera.Parameters.PREVIEW_FPS_MIN_INDEX],
bestRange[Camera.Parameters.PREVIEW_FPS_MAX_INDEX]);
+ Size smallestSupportedJpegSize = calculatePictureSize(mCallbackOutputs,
+ callbackOutputSizes, mParams);
+
if (previewOutputSizes.size() > 0) {
Size largestOutput = SizeAreaComparator.findLargestByArea(previewOutputSizes);
@@ -419,6 +424,9 @@
// Find largest jpeg dimension - assume to have the same aspect ratio as sensor.
Size largestJpegDimen = ParameterUtils.getLargestSupportedJpegSizeByArea(mParams);
+ Size chosenJpegDimen = (smallestSupportedJpegSize != null) ? smallestSupportedJpegSize
+ : largestJpegDimen;
+
List<Size> supportedPreviewSizes = ParameterUtils.convertSizeList(
mParams.getSupportedPreviewSizes());
@@ -430,7 +438,7 @@
for (Size s : supportedPreviewSizes) {
long currArea = s.getWidth() * s.getHeight();
long bestArea = bestPreviewDimen.getWidth() * bestPreviewDimen.getHeight();
- if (checkAspectRatiosMatch(largestJpegDimen, s) && (currArea < bestArea &&
+ if (checkAspectRatiosMatch(chosenJpegDimen, s) && (currArea < bestArea &&
currArea >= largestOutputArea)) {
bestPreviewDimen = s;
}
@@ -451,8 +459,6 @@
}
}
- Size smallestSupportedJpegSize = calculatePictureSize(mCallbackOutputs,
- callbackOutputSizes, mParams);
if (smallestSupportedJpegSize != null) {
/*
* Set takePicture size to the smallest supported JPEG size large enough
diff --git a/core/java/android/hardware/camera2/utils/SurfaceUtils.java b/core/java/android/hardware/camera2/utils/SurfaceUtils.java
index 32e74e2..40005a5 100644
--- a/core/java/android/hardware/camera2/utils/SurfaceUtils.java
+++ b/core/java/android/hardware/camera2/utils/SurfaceUtils.java
@@ -16,6 +16,7 @@
package android.hardware.camera2.utils;
+import android.graphics.ImageFormat;
import android.hardware.camera2.legacy.LegacyCameraDevice;
import android.hardware.camera2.legacy.LegacyExceptionUtils.BufferQueueAbandonedException;
import android.util.Size;
@@ -27,7 +28,7 @@
public class SurfaceUtils {
/**
- * Check if a surface is for preview consumer.
+ * Check if a surface is for preview consumer based on consumer end point Gralloc usage flags.
*
* @param surface The surface to be checked.
* @return true if the surface is for preview consumer, false otherwise.
@@ -37,7 +38,8 @@
}
/**
- * Check if the surface is for hardware video encoder consumer.
+ * Check if the surface is for hardware video encoder consumer based on consumer end point
+ * Gralloc usage flags.
*
* @param surface The surface to be checked.
* @return true if the surface is for hardware video encoder consumer, false otherwise.
diff --git a/core/java/android/hardware/usb/IUsbManager.aidl b/core/java/android/hardware/usb/IUsbManager.aidl
index 881dc0f..31a6a962 100644
--- a/core/java/android/hardware/usb/IUsbManager.aidl
+++ b/core/java/android/hardware/usb/IUsbManager.aidl
@@ -85,6 +85,16 @@
/* Sets the current USB function. */
void setCurrentFunction(String function);
+ /* Sets whether USB data (for example, MTP exposed pictures) should be made
+ * available on the USB connection. Unlocking data should only be done with
+ * user involvement, since exposing pictures or other data could leak sensitive
+ * user information.
+ */
+ void setUsbDataUnlocked(boolean unlock);
+
+ /* Returns true iff sensitive user data is exposed on the USB connection. */
+ boolean isUsbDataUnlocked();
+
/* Allow USB debugging from the attached host. If alwaysAllow is true, add the
* the public key to list of host keys that the user has approved.
*/
diff --git a/core/java/android/hardware/usb/UsbManager.java b/core/java/android/hardware/usb/UsbManager.java
index 000d41f..c83f466 100644
--- a/core/java/android/hardware/usb/UsbManager.java
+++ b/core/java/android/hardware/usb/UsbManager.java
@@ -142,6 +142,16 @@
public static final String USB_CONFIGURED = "configured";
/**
+ * Boolean extra indicating whether confidential user data, such as photos, should be
+ * made available on the USB connection. This variable will only be set when the user
+ * has explicitly asked for this data to be unlocked.
+ * Used in extras for the {@link #ACTION_USB_STATE} broadcast.
+ *
+ * {@hide}
+ */
+ public static final String USB_DATA_UNLOCKED = "unlocked";
+
+ /**
* Name of the USB mass storage USB function.
* Used in extras for the {@link #ACTION_USB_STATE} broadcast
*
@@ -464,4 +474,34 @@
Log.e(TAG, "RemoteException in setCurrentFunction", e);
}
}
+
+ /**
+ * Sets whether USB data (for example, MTP exposed pictures) should be made available
+ * on the USB connection. Unlocking usb data should only be done with user involvement,
+ * since exposing pictures or other data could leak sensitive user information.
+ *
+ * {@hide}
+ */
+ public void setUsbDataUnlocked(boolean unlocked) {
+ try {
+ mService.setUsbDataUnlocked(unlocked);
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException in setUsbDataUnlocked", e);
+ }
+ }
+
+ /**
+ * Returns {@code true} iff access to sensitive USB data is currently allowed.
+ *
+ * {@hide}
+ */
+ public boolean isUsbDataUnlocked() {
+ try {
+ return mService.isUsbDataUnlocked();
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException in isUsbDataUnlocked", e);
+ }
+ return false;
+ }
+
}
diff --git a/core/java/android/inputmethodservice/Keyboard.java b/core/java/android/inputmethodservice/Keyboard.java
index 45f1889..a5490ef 100644
--- a/core/java/android/inputmethodservice/Keyboard.java
+++ b/core/java/android/inputmethodservice/Keyboard.java
@@ -400,16 +400,27 @@
public void onPressed() {
pressed = !pressed;
}
-
+
/**
- * Changes the pressed state of the key. If it is a sticky key, it will also change the
- * toggled state of the key if the finger was release inside.
- * @param inside whether the finger was released inside the key
+ * Changes the pressed state of the key.
+ *
+ * <p>Toggled state of the key will be flipped when all the following conditions are
+ * fulfilled:</p>
+ *
+ * <ul>
+ * <li>This is a sticky key, that is, {@link #sticky} is {@code true}.
+ * <li>The parameter {@code inside} is {@code true}.
+ * <li>{@link android.os.Build.VERSION#SDK_INT} is greater than
+ * {@link android.os.Build.VERSION_CODES#LOLLIPOP_MR1}.
+ * </ul>
+ *
+ * @param inside whether the finger was released inside the key. Works only on Android M and
+ * later. See the method document for details.
* @see #onPressed()
*/
public void onReleased(boolean inside) {
pressed = !pressed;
- if (sticky) {
+ if (sticky && inside) {
on = !on;
}
}
diff --git a/core/java/android/net/NetworkFactory.java b/core/java/android/net/NetworkFactory.java
index e47220b..5f46c73 100644
--- a/core/java/android/net/NetworkFactory.java
+++ b/core/java/android/net/NetworkFactory.java
@@ -24,8 +24,13 @@
import android.util.Log;
import android.util.SparseArray;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.Protocol;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
/**
* A NetworkFactory is an entity that creates NetworkAgent objects.
* The bearers register with ConnectivityService using {@link #register} and
@@ -157,6 +162,11 @@
this.score = score;
this.requested = false;
}
+
+ @Override
+ public String toString() {
+ return "{" + request + ", score=" + score + ", requested=" + requested + "}";
+ }
}
private void handleAddRequest(NetworkRequest request, int score) {
@@ -176,9 +186,9 @@
private void handleRemoveRequest(NetworkRequest request) {
NetworkRequestInfo n = mNetworkRequests.get(request.requestId);
- if (n != null && n.requested) {
+ if (n != null) {
mNetworkRequests.remove(request.requestId);
- releaseNetworkFor(n.request);
+ if (n.requested) releaseNetworkFor(n.request);
}
}
@@ -273,15 +283,31 @@
sendMessage(obtainMessage(CMD_SET_FILTER, new NetworkCapabilities(netCap)));
}
+ @VisibleForTesting
+ protected int getRequestCount() {
+ return mNetworkRequests.size();
+ }
+
protected void log(String s) {
Log.d(LOG_TAG, s);
}
+ public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
+ final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " ");
+ pw.println(toString());
+ pw.increaseIndent();
+ for (int i = 0; i < mNetworkRequests.size(); i++) {
+ pw.println(mNetworkRequests.valueAt(i));
+ }
+ pw.decreaseIndent();
+ }
+
@Override
public String toString() {
StringBuilder sb = new StringBuilder("{").append(LOG_TAG).append(" - ScoreFilter=").
append(mScore).append(", Filter=").append(mCapabilityFilter).append(", requests=").
- append(mNetworkRequests.size()).append("}");
+ append(mNetworkRequests.size()).append(", refCount=").append(mRefCount).
+ append("}");
return sb.toString();
}
}
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index c9609e5..f76192e 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -1177,8 +1177,13 @@
public static final int EVENT_ALARM = 0x000e;
// Record that we have decided we need to collect new stats data.
public static final int EVENT_COLLECT_EXTERNAL_STATS = 0x000f;
+ // Event for a package becoming inactive due to being unused for a period of time.
+ public static final int EVENT_PACKAGE_INACTIVE = 0x0010;
+ // Event for a package becoming active due to an interaction.
+ public static final int EVENT_PACKAGE_ACTIVE = 0x0011;
+
// Number of event types.
- public static final int EVENT_COUNT = 0x0010;
+ public static final int EVENT_COUNT = 0x0012;
// Mask to extract out only the type part of the event.
public static final int EVENT_TYPE_MASK = ~(EVENT_FLAG_START|EVENT_FLAG_FINISH);
@@ -1835,12 +1840,12 @@
public static final String[] HISTORY_EVENT_NAMES = new String[] {
"null", "proc", "fg", "top", "sync", "wake_lock_in", "job", "user", "userfg", "conn",
- "motion", "active", "pkginst", "pkgunin", "alarm", "stats"
+ "motion", "active", "pkginst", "pkgunin", "alarm", "stats", "inactive", "active"
};
public static final String[] HISTORY_EVENT_CHECKIN_NAMES = new String[] {
"Enl", "Epr", "Efg", "Etp", "Esy", "Ewl", "Ejb", "Eur", "Euf", "Ecn",
- "Esm", "Eac", "Epi", "Epu", "Eal", "Est"
+ "Esm", "Eac", "Epi", "Epu", "Eal", "Est", "Eai", "Eaa"
};
/**
@@ -3489,57 +3494,90 @@
pw.println();
for (int i=0; i<sippers.size(); i++) {
final BatterySipper bs = sippers.get(i);
+ pw.print(prefix);
switch (bs.drainType) {
case IDLE:
- pw.print(prefix); pw.print(" Idle: "); printmAh(pw, bs.totalPowerMah);
- pw.println();
+ pw.print(" Idle: ");
break;
case CELL:
- pw.print(prefix); pw.print(" Cell standby: "); printmAh(pw, bs.totalPowerMah);
- pw.println();
+ pw.print(" Cell standby: ");
break;
case PHONE:
- pw.print(prefix); pw.print(" Phone calls: "); printmAh(pw, bs.totalPowerMah);
- pw.println();
+ pw.print(" Phone calls: ");
break;
case WIFI:
- pw.print(prefix); pw.print(" Wifi: "); printmAh(pw, bs.totalPowerMah);
- pw.println();
+ pw.print(" Wifi: ");
break;
case BLUETOOTH:
- pw.print(prefix); pw.print(" Bluetooth: "); printmAh(pw, bs.totalPowerMah);
- pw.println();
+ pw.print(" Bluetooth: ");
break;
case SCREEN:
- pw.print(prefix); pw.print(" Screen: "); printmAh(pw, bs.totalPowerMah);
- pw.println();
+ pw.print(" Screen: ");
break;
case FLASHLIGHT:
- pw.print(prefix); pw.print(" Flashlight: "); printmAh(pw, bs.totalPowerMah);
- pw.println();
+ pw.print(" Flashlight: ");
break;
case APP:
- pw.print(prefix); pw.print(" Uid ");
+ pw.print(" Uid ");
UserHandle.formatUid(pw, bs.uidObj.getUid());
- pw.print(": "); printmAh(pw, bs.totalPowerMah); pw.println();
+ pw.print(": ");
break;
case USER:
- pw.print(prefix); pw.print(" User "); pw.print(bs.userId);
- pw.print(": "); printmAh(pw, bs.totalPowerMah); pw.println();
+ pw.print(" User "); pw.print(bs.userId);
+ pw.print(": ");
break;
case UNACCOUNTED:
- pw.print(prefix); pw.print(" Unaccounted: "); printmAh(pw, bs.totalPowerMah);
- pw.println();
+ pw.print(" Unaccounted: ");
break;
case OVERCOUNTED:
- pw.print(prefix); pw.print(" Over-counted: "); printmAh(pw, bs.totalPowerMah);
- pw.println();
+ pw.print(" Over-counted: ");
break;
case CAMERA:
- pw.print(prefix); pw.print(" Camera: "); printmAh(pw, bs.totalPowerMah);
- pw.println();
+ pw.print(" Camera: ");
+ break;
+ default:
+ pw.print(" ???: ");
break;
}
+ printmAh(pw, bs.totalPowerMah);
+
+ if (bs.drainType == BatterySipper.DrainType.APP) {
+ pw.print(" (");
+ if (bs.cpuPowerMah != 0) {
+ pw.print(" cpu=");
+ printmAh(pw, bs.cpuPowerMah);
+ }
+ if (bs.wakeLockPowerMah != 0) {
+ pw.print(" wake=");
+ printmAh(pw, bs.wakeLockPowerMah);
+ }
+ if (bs.mobileRadioPowerMah != 0) {
+ pw.print(" radio=");
+ printmAh(pw, bs.mobileRadioPowerMah);
+ }
+ if (bs.wifiPowerMah != 0) {
+ pw.print(" wifi=");
+ printmAh(pw, bs.wifiPowerMah);
+ }
+ if (bs.gpsPowerMah != 0) {
+ pw.print(" gps=");
+ printmAh(pw, bs.gpsPowerMah);
+ }
+ if (bs.sensorPowerMah != 0) {
+ pw.print(" sensor=");
+ printmAh(pw, bs.sensorPowerMah);
+ }
+ if (bs.cameraPowerMah != 0) {
+ pw.print(" camera=");
+ printmAh(pw, bs.cameraPowerMah);
+ }
+ if (bs.flashlightPowerMah != 0) {
+ pw.print(" flash=");
+ printmAh(pw, bs.flashlightPowerMah);
+ }
+ pw.print(" )");
+ }
+ pw.println();
}
pw.println();
}
diff --git a/core/java/android/os/FileUtils.java b/core/java/android/os/FileUtils.java
index 917271d..864225a 100644
--- a/core/java/android/os/FileUtils.java
+++ b/core/java/android/os/FileUtils.java
@@ -24,6 +24,8 @@
import android.util.Slog;
import android.webkit.MimeTypeMap;
+import com.android.internal.annotations.VisibleForTesting;
+
import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
@@ -34,6 +36,7 @@
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Objects;
@@ -456,6 +459,7 @@
res.append('_');
}
}
+ trimFilename(res, 255);
return res.toString();
}
@@ -504,9 +508,31 @@
res.append('_');
}
}
+ // Even though vfat allows 255 UCS-2 chars, we might eventually write to
+ // ext4 through a FUSE layer, so use that limit.
+ trimFilename(res, 255);
return res.toString();
}
+ @VisibleForTesting
+ public static String trimFilename(String str, int maxBytes) {
+ final StringBuilder res = new StringBuilder(str);
+ trimFilename(res, maxBytes);
+ return res.toString();
+ }
+
+ private static void trimFilename(StringBuilder res, int maxBytes) {
+ byte[] raw = res.toString().getBytes(StandardCharsets.UTF_8);
+ if (raw.length > maxBytes) {
+ maxBytes -= 3;
+ while (raw.length > maxBytes) {
+ res.deleteCharAt(res.length() / 2);
+ raw = res.toString().getBytes(StandardCharsets.UTF_8);
+ }
+ res.insert(res.length() / 2, "...");
+ }
+ }
+
public static String rewriteAfterRename(File beforeDir, File afterDir, String path) {
if (path == null) return null;
final File result = rewriteAfterRename(beforeDir, afterDir, new File(path));
diff --git a/core/java/android/os/ParcelFileDescriptor.java b/core/java/android/os/ParcelFileDescriptor.java
index 1c9c713..135f369 100644
--- a/core/java/android/os/ParcelFileDescriptor.java
+++ b/core/java/android/os/ParcelFileDescriptor.java
@@ -621,6 +621,9 @@
final int fd = getFd();
Parcel.clearFileDescriptor(mFd);
writeCommStatusAndClose(Status.DETACHED, null);
+ mClosed = true;
+ mGuard.close();
+ releaseResources();
return fd;
}
}
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index 8b18f32..7a1aa1e 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -878,7 +878,10 @@
* off network access to apps. You can monitor for changes to this state with
* {@link #ACTION_DEVICE_IDLE_MODE_CHANGED}.
*
- * @return Returns true if currently in low power mode, else false.
+ * @return Returns true if currently in active device idle mode, else false. This is
+ * when idle mode restrictions are being actively applied; it will return false if the
+ * device is in a long-term idle mode but currently running a maintenance window where
+ * restrictions have been lifted.
*/
public boolean isDeviceIdleMode() {
try {
diff --git a/core/java/android/os/RemoteCallbackList.java b/core/java/android/os/RemoteCallbackList.java
index d2a9cdc..5849350 100644
--- a/core/java/android/os/RemoteCallbackList.java
+++ b/core/java/android/os/RemoteCallbackList.java
@@ -77,7 +77,6 @@
public boolean register(E callback) {
return register(callback, null);
}
-
/**
* Add a new callback to the list. This callback will remain in the list
* until a corresponding call to {@link #unregister} or its hosting process
diff --git a/core/java/android/os/storage/DiskInfo.java b/core/java/android/os/storage/DiskInfo.java
index 04e54aa..5bc45d5 100644
--- a/core/java/android/os/storage/DiskInfo.java
+++ b/core/java/android/os/storage/DiskInfo.java
@@ -80,6 +80,12 @@
if (label.toLowerCase().contains("generic")) {
return false;
}
+ if (label.toLowerCase().startsWith("usb")) {
+ return false;
+ }
+ if (label.toLowerCase().startsWith("multiple")) {
+ return false;
+ }
return true;
}
diff --git a/core/java/android/os/storage/VolumeInfo.java b/core/java/android/os/storage/VolumeInfo.java
index 2622ee0..372725f 100644
--- a/core/java/android/os/storage/VolumeInfo.java
+++ b/core/java/android/os/storage/VolumeInfo.java
@@ -32,7 +32,9 @@
import android.util.ArrayMap;
import android.util.DebugUtils;
import android.util.SparseArray;
+import android.util.SparseIntArray;
+import com.android.internal.R;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.Preconditions;
@@ -80,6 +82,7 @@
private static SparseArray<String> sStateToEnvironment = new SparseArray<>();
private static ArrayMap<String, String> sEnvironmentToBroadcast = new ArrayMap<>();
+ private static SparseIntArray sStateToDescrip = new SparseIntArray();
private static final Comparator<VolumeInfo>
sDescriptionComparator = new Comparator<VolumeInfo>() {
@@ -116,6 +119,16 @@
sEnvironmentToBroadcast.put(Environment.MEDIA_UNMOUNTABLE, Intent.ACTION_MEDIA_UNMOUNTABLE);
sEnvironmentToBroadcast.put(Environment.MEDIA_REMOVED, Intent.ACTION_MEDIA_REMOVED);
sEnvironmentToBroadcast.put(Environment.MEDIA_BAD_REMOVAL, Intent.ACTION_MEDIA_BAD_REMOVAL);
+
+ sStateToDescrip.put(VolumeInfo.STATE_UNMOUNTED, R.string.ext_media_status_unmounted);
+ sStateToDescrip.put(VolumeInfo.STATE_CHECKING, R.string.ext_media_status_checking);
+ sStateToDescrip.put(VolumeInfo.STATE_MOUNTED, R.string.ext_media_status_mounted);
+ sStateToDescrip.put(VolumeInfo.STATE_MOUNTED_READ_ONLY, R.string.ext_media_status_mounted_ro);
+ sStateToDescrip.put(VolumeInfo.STATE_FORMATTING, R.string.ext_media_status_formatting);
+ sStateToDescrip.put(VolumeInfo.STATE_EJECTING, R.string.ext_media_status_ejecting);
+ sStateToDescrip.put(VolumeInfo.STATE_UNMOUNTABLE, R.string.ext_media_status_unmountable);
+ sStateToDescrip.put(VolumeInfo.STATE_REMOVED, R.string.ext_media_status_removed);
+ sStateToDescrip.put(VolumeInfo.STATE_BAD_REMOVAL, R.string.ext_media_status_bad_removal);
}
/** vold state */
@@ -201,6 +214,10 @@
return state;
}
+ public int getStateDescription() {
+ return sStateToDescrip.get(state, 0);
+ }
+
public @Nullable String getFsUuid() {
return fsUuid;
}
diff --git a/core/java/android/preference/SeekBarDialogPreference.java b/core/java/android/preference/SeekBarDialogPreference.java
index 9a08827..eeb69a3 100644
--- a/core/java/android/preference/SeekBarDialogPreference.java
+++ b/core/java/android/preference/SeekBarDialogPreference.java
@@ -18,29 +18,28 @@
import android.content.Context;
import android.graphics.drawable.Drawable;
-import android.preference.DialogPreference;
import android.util.AttributeSet;
import android.view.View;
import android.widget.ImageView;
import android.widget.SeekBar;
+import com.android.internal.R;
+
/**
* @hide
*/
public class SeekBarDialogPreference extends DialogPreference {
- private static final String TAG = "SeekBarDialogPreference";
-
- private Drawable mMyIcon;
+ private final Drawable mMyIcon;
public SeekBarDialogPreference(
Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
- setDialogLayoutResource(com.android.internal.R.layout.seekbar_dialog);
createActionButtons();
// Steal the XML dialogIcon attribute's value
mMyIcon = getDialogIcon();
+
setDialogIcon(null);
}
@@ -49,7 +48,7 @@
}
public SeekBarDialogPreference(Context context, AttributeSet attrs) {
- this(context, attrs, com.android.internal.R.attr.dialogPreferenceStyle);
+ this(context, attrs, R.attr.seekBarDialogPreferenceStyle);
}
public SeekBarDialogPreference(Context context) {
@@ -58,15 +57,15 @@
// Allow subclasses to override the action buttons
public void createActionButtons() {
- setPositiveButtonText(android.R.string.ok);
- setNegativeButtonText(android.R.string.cancel);
+ setPositiveButtonText(R.string.ok);
+ setNegativeButtonText(R.string.cancel);
}
@Override
protected void onBindDialogView(View view) {
super.onBindDialogView(view);
- final ImageView iconView = (ImageView) view.findViewById(android.R.id.icon);
+ final ImageView iconView = (ImageView) view.findViewById(R.id.icon);
if (mMyIcon != null) {
iconView.setImageDrawable(mMyIcon);
} else {
@@ -75,6 +74,6 @@
}
protected static SeekBar getSeekBar(View dialogView) {
- return (SeekBar) dialogView.findViewById(com.android.internal.R.id.seekbar);
+ return (SeekBar) dialogView.findViewById(R.id.seekbar);
}
}
diff --git a/core/java/android/preference/SeekBarVolumizer.java b/core/java/android/preference/SeekBarVolumizer.java
index 4bd085f..979c828 100644
--- a/core/java/android/preference/SeekBarVolumizer.java
+++ b/core/java/android/preference/SeekBarVolumizer.java
@@ -16,6 +16,7 @@
package android.preference;
+import android.app.NotificationManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -31,6 +32,7 @@
import android.os.Message;
import android.preference.VolumePreference.VolumeStore;
import android.provider.Settings;
+import android.provider.Settings.Global;
import android.provider.Settings.System;
import android.util.Log;
import android.widget.SeekBar;
@@ -46,7 +48,7 @@
public interface Callback {
void onSampleStarting(SeekBarVolumizer sbv);
void onProgressChanged(SeekBar seekBar, int progress, boolean fromTouch);
- void onMuted(boolean muted);
+ void onMuted(boolean muted, boolean zenMuted);
}
private final Context mContext;
@@ -54,6 +56,7 @@
private final Callback mCallback;
private final Uri mDefaultUri;
private final AudioManager mAudioManager;
+ private final NotificationManager mNotificationManager;
private final int mStreamType;
private final int mMaxStreamVolume;
private boolean mAffectedByRingerMode;
@@ -63,12 +66,14 @@
private Handler mHandler;
private Observer mVolumeObserver;
private int mOriginalStreamVolume;
+ private int mLastAudibleStreamVolume;
private Ringtone mRingtone;
private int mLastProgress = -1;
private boolean mMuted;
private SeekBar mSeekBar;
private int mVolumeBeforeMute = -1;
private int mRingerMode;
+ private int mZenMode;
private static final int MSG_SET_STREAM_VOLUME = 0;
private static final int MSG_START_SAMPLE = 1;
@@ -78,19 +83,22 @@
public SeekBarVolumizer(Context context, int streamType, Uri defaultUri, Callback callback) {
mContext = context;
- mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
+ mAudioManager = context.getSystemService(AudioManager.class);
+ mNotificationManager = context.getSystemService(NotificationManager.class);
mStreamType = streamType;
mAffectedByRingerMode = mAudioManager.isStreamAffectedByRingerMode(mStreamType);
mNotificationOrRing = isNotificationOrRing(mStreamType);
if (mNotificationOrRing) {
mRingerMode = mAudioManager.getRingerModeInternal();
}
+ mZenMode = mNotificationManager.getZenMode();
mMaxStreamVolume = mAudioManager.getStreamMaxVolume(mStreamType);
mCallback = callback;
mOriginalStreamVolume = mAudioManager.getStreamVolume(mStreamType);
+ mLastAudibleStreamVolume = mAudioManager.getLastAudibleStreamVolume(mStreamType);
mMuted = mAudioManager.isStreamMute(mStreamType);
if (mCallback != null) {
- mCallback.onMuted(mMuted);
+ mCallback.onMuted(mMuted, isZenMuted());
}
if (defaultUri == null) {
if (mStreamType == AudioManager.STREAM_RING) {
@@ -119,8 +127,17 @@
mSeekBar.setOnSeekBarChangeListener(this);
}
+ private boolean isZenMuted() {
+ return mNotificationOrRing && mZenMode == Global.ZEN_MODE_ALARMS
+ || mZenMode == Global.ZEN_MODE_NO_INTERRUPTIONS;
+ }
+
protected void updateSeekBar() {
- if (mNotificationOrRing && mRingerMode == AudioManager.RINGER_MODE_VIBRATE) {
+ final boolean zenMuted = isZenMuted();
+ mSeekBar.setEnabled(!zenMuted);
+ if (zenMuted) {
+ mSeekBar.setProgress(mLastAudibleStreamVolume);
+ } else if (mNotificationOrRing && mRingerMode == AudioManager.RINGER_MODE_VIBRATE) {
mSeekBar.setProgress(0);
} else if (mMuted) {
mSeekBar.setProgress(0);
@@ -316,11 +333,12 @@
if (msg.what == UPDATE_SLIDER) {
if (mSeekBar != null) {
mLastProgress = msg.arg1;
- final boolean muted = msg.arg2 != 0;
+ mLastAudibleStreamVolume = Math.abs(msg.arg2);
+ final boolean muted = msg.arg2 < 0;
if (muted != mMuted) {
mMuted = muted;
if (mCallback != null) {
- mCallback.onMuted(mMuted);
+ mCallback.onMuted(mMuted, isZenMuted());
}
}
updateSeekBar();
@@ -328,16 +346,18 @@
}
}
- public void postUpdateSlider(int volume, boolean mute) {
- obtainMessage(UPDATE_SLIDER, volume, mute ? 1 : 0).sendToTarget();
+ public void postUpdateSlider(int volume, int lastAudibleVolume, boolean mute) {
+ final int arg2 = lastAudibleVolume * (mute ? -1 : 1);
+ obtainMessage(UPDATE_SLIDER, volume, arg2).sendToTarget();
}
}
private void updateSlider() {
if (mSeekBar != null && mAudioManager != null) {
final int volume = mAudioManager.getStreamVolume(mStreamType);
+ final int lastAudibleVolume = mAudioManager.getLastAudibleStreamVolume(mStreamType);
final boolean mute = mAudioManager.isStreamMute(mStreamType);
- mUiHandler.postUpdateSlider(volume, mute);
+ mUiHandler.postUpdateSlider(volume, lastAudibleVolume, mute);
}
}
@@ -362,6 +382,7 @@
if (listening) {
final IntentFilter filter = new IntentFilter(AudioManager.VOLUME_CHANGED_ACTION);
filter.addAction(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION);
+ filter.addAction(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED);
mContext.registerReceiver(this, filter);
} else {
mContext.unregisterReceiver(this);
@@ -379,7 +400,7 @@
if (mSeekBar != null && streamMatch && streamValue != -1) {
final boolean muted = mAudioManager.isStreamMute(mStreamType)
|| streamValue == 0;
- mUiHandler.postUpdateSlider(streamValue, muted);
+ mUiHandler.postUpdateSlider(streamValue, mLastAudibleStreamVolume, muted);
}
} else if (AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION.equals(action)) {
if (mNotificationOrRing) {
@@ -388,6 +409,9 @@
if (mAffectedByRingerMode) {
updateSlider();
}
+ } else if (NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED.equals(action)) {
+ mZenMode = mNotificationManager.getZenMode();
+ updateSlider();
}
}
}
diff --git a/core/java/android/preference/VolumePreference.java b/core/java/android/preference/VolumePreference.java
index a2da01b..8a66c243b 100644
--- a/core/java/android/preference/VolumePreference.java
+++ b/core/java/android/preference/VolumePreference.java
@@ -26,14 +26,13 @@
import android.view.View;
import android.widget.SeekBar;
+import com.android.internal.R;
+
/**
* @hide
*/
public class VolumePreference extends SeekBarDialogPreference implements
PreferenceManager.OnActivityStopListener, View.OnKeyListener, SeekBarVolumizer.Callback {
-
- static final String TAG = "VolumePreference";
-
private int mStreamType;
/** May be null if the dialog isn't visible. */
@@ -44,7 +43,7 @@
super(context, attrs, defStyleAttr, defStyleRes);
final TypedArray a = context.obtainStyledAttributes(attrs,
- com.android.internal.R.styleable.VolumePreference, defStyleAttr, defStyleRes);
+ R.styleable.VolumePreference, defStyleAttr, defStyleRes);
mStreamType = a.getInt(android.R.styleable.VolumePreference_streamType, 0);
a.recycle();
}
@@ -54,7 +53,11 @@
}
public VolumePreference(Context context, AttributeSet attrs) {
- this(context, attrs, com.android.internal.R.attr.dialogPreferenceStyle);
+ this(context, attrs, R.attr.seekBarDialogPreferenceStyle);
+ }
+
+ public VolumePreference(Context context) {
+ this(context, null);
}
public void setStreamType(int streamType) {
@@ -65,7 +68,7 @@
protected void onBindDialogView(View view) {
super.onBindDialogView(view);
- final SeekBar seekBar = (SeekBar) view.findViewById(com.android.internal.R.id.seekbar);
+ final SeekBar seekBar = (SeekBar) view.findViewById(R.id.seekbar);
mSeekBarVolumizer = new SeekBarVolumizer(getContext(), mStreamType, null, this);
mSeekBarVolumizer.start();
mSeekBarVolumizer.setSeekBar(seekBar);
@@ -128,14 +131,17 @@
getPreferenceManager().unregisterOnActivityStopListener(this);
if (mSeekBarVolumizer != null) {
- Dialog dialog = getDialog();
+ final Dialog dialog = getDialog();
if (dialog != null && dialog.isShowing()) {
- View view = dialog.getWindow().getDecorView()
- .findViewById(com.android.internal.R.id.seekbar);
- if (view != null) view.setOnKeyListener(null);
+ final View view = dialog.getWindow().getDecorView().findViewById(R.id.seekbar);
+ if (view != null) {
+ view.setOnKeyListener(null);
+ }
+
// Stopped while dialog was showing, revert changes
mSeekBarVolumizer.revertVolume();
}
+
mSeekBarVolumizer.stop();
mSeekBarVolumizer = null;
}
@@ -155,7 +161,7 @@
}
@Override
- public void onMuted(boolean muted) {
+ public void onMuted(boolean muted, boolean zenMuted) {
// noop
}
diff --git a/core/java/android/printservice/PrintService.java b/core/java/android/printservice/PrintService.java
index 527c8ae..6295822 100644
--- a/core/java/android/printservice/PrintService.java
+++ b/core/java/android/printservice/PrintService.java
@@ -231,6 +231,19 @@
*/
public static final String EXTRA_PRINTER_INFO = "android.intent.extra.print.EXTRA_PRINTER_INFO";
+ /**
+ * If you declared an optional activity with advanced print options via the
+ * {@link android.R.attr#advancedPrintOptionsActivity advancedPrintOptionsActivity}
+ * attribute, this extra is used to pass in the meta-data for the currently printed
+ * document as a {@link android.print.PrintDocumentInfo} to your activity allowing
+ * you to inspect it.
+ *
+ * @see #EXTRA_PRINT_JOB_INFO
+ * @see #EXTRA_PRINTER_INFO
+ */
+ public static final String EXTRA_PRINT_DOCUMENT_INFO =
+ "android.printservice.extra.PRINT_DOCUMENT_INFO";
+
private Handler mHandler;
private IPrintServiceClient mClient;
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index d9c412b..aebe7f1 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -8931,157 +8931,4 @@
public static final String EXTRA_DATA_SET = "android.provider.extra.DATA_SET";
}
}
-
- /**
- * @hide
- */
- protected interface MetadataSyncColumns {
-
- /**
- * The raw contact backup id.
- * A reference to the {@link ContactsContract.RawContacts#BACKUP_ID} that save the
- * persistent unique id for each raw contact within its source system.
- *
- * @hide
- */
- public static final String RAW_CONTACT_BACKUP_ID = "raw_contact_backup_id";
-
- /**
- * The account type to which the raw_contact of this item is associated. See
- * {@link RawContacts#ACCOUNT_TYPE}
- *
- * @hide
- */
- public static final String ACCOUNT_TYPE = "account_type";
-
- /**
- * The account name to which the raw_contact of this item is associated. See
- * {@link RawContacts#ACCOUNT_NAME}
- *
- * @hide
- */
- public static final String ACCOUNT_NAME = "account_name";
-
- /**
- * The data set within the account that the raw_contact of this row belongs to. This allows
- * multiple sync adapters for the same account type to distinguish between
- * each others' data.
- * {@link RawContacts#DATA_SET}
- *
- * @hide
- */
- public static final String DATA_SET = "data_set";
-
- /**
- * A text column contains the Json string got from People API. The Json string contains
- * all the metadata related to the raw contact, i.e., all the data fields and
- * aggregation exceptions.
- *
- * Here is an example of the Json string got from the actual schema.
- * <pre>
- * {
- * "unique_contact_id": {
- * "account_type": "CUSTOM_ACCOUNT",
- * "custom_account_type": "facebook",
- * "account_name": "android-test",
- * "contact_id": "1111111",
- * "data_set": "FOCUS"
- * },
- * "contact_prefs": {
- * "send_to_voicemail": true,
- * "starred": false,
- * "pinned": 2
- * },
- * "aggregation_data": [
- * {
- * "type": "TOGETHER",
- * "contact_ids": [
- * {
- * "account_type": "GOOGLE_ACCOUNT",
- * "account_name": "android-test2",
- * "contact_id": "2222222",
- * "data_set": "GOOGLE_PLUS"
- * },
- * {
- * "account_type": "GOOGLE_ACCOUNT",
- * "account_name": "android-test3",
- * "contact_id": "3333333",
- * "data_set": "CUSTOM",
- * "custom_data_set": "custom type"
- * }
- * ]
- * }
- * ],
- * "field_data": [
- * {
- * "field_data_id": "1001",
- * "field_data_prefs": {
- * "is_primary": true,
- * "is_super_primary": true
- * },
- * "usage_stats": [
- * {
- * "usage_type": "CALL",
- * "last_time_used": 10000001,
- * "usage_count": 10
- * }
- * ]
- * }
- * ]
- * }
- * </pre>
- *
- * @hide
- */
- public static final String DATA = "data";
-
- /**
- * The "deleted" flag: "0" by default, "1" if the row has been marked
- * for deletion. When {@link android.content.ContentResolver#delete} is
- * called on a raw contact, updating MetadataSync table to set the flag of the raw contact
- * as "1", then metadata sync adapter deletes the raw contact metadata on the server.
- * <P>Type: INTEGER</P>
- *
- * @hide
- */
- public static final String DELETED = "deleted";
- }
-
- /**
- * Constants for the metadata sync table. This table is used to cache the metadata_sync data
- * from server before it is merged into other CP2 tables.
- *
- * @hide
- */
- public static final class MetadataSync implements BaseColumns, MetadataSyncColumns {
-
- /** The authority for the contacts metadata */
- public static final String METADATA_AUTHORITY = "com.android.contacts.metadata";
-
- /** A content:// style uri to the authority for the contacts metadata */
- public static final Uri METADATA_AUTHORITY_URI = Uri.parse(
- "content://" + METADATA_AUTHORITY);
-
- /**
- * This utility class cannot be instantiated
- */
- private MetadataSync() {
- }
-
- /**
- * The content:// style URI for this table.
- */
- public static final Uri CONTENT_URI = Uri.withAppendedPath(METADATA_AUTHORITY_URI,
- "metadata_sync");
-
- /**
- * The MIME type of {@link #CONTENT_URI} providing a directory of contact metadata
- */
- public static final String CONTENT_TYPE = "vnd.android.cursor.dir/contact_metadata";
-
- /**
- * The MIME type of a {@link #CONTENT_URI} subdirectory of a single contact metadata.
- */
- public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/contact_metadata";
- }
}
diff --git a/core/java/android/provider/DocumentsContract.java b/core/java/android/provider/DocumentsContract.java
index 69338b0..30535ff 100644
--- a/core/java/android/provider/DocumentsContract.java
+++ b/core/java/android/provider/DocumentsContract.java
@@ -93,6 +93,12 @@
public static final String EXTRA_SHOW_ADVANCED = "android.content.extra.SHOW_ADVANCED";
/**
+ * Set this in a DocumentsUI intent to cause a package's own roots to be
+ * excluded from the roots list.
+ */
+ public static final String EXTRA_EXCLUDE_SELF = "android.provider.extra.EXCLUDE_SELF";
+
+ /**
* Included in {@link AssetFileDescriptor#getExtras()} when returned
* thumbnail should be rotated.
*
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 640f434..f2d3e71 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -577,6 +577,21 @@
"android.settings.APPLICATION_DETAILS_SETTINGS";
/**
+ * Activity Action: Show screen for controlling which apps can ignore battery optimizations.
+ * <p>
+ * In some cases, a matching Activity may not exist, so ensure you
+ * safeguard against this.
+ * <p>
+ * Input: The Intent's data URI specifies the application package name
+ * to be shown, with the "package" scheme. That is "package:com.my.app".
+ * <p>
+ * Output: Nothing.
+ */
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS =
+ "android.settings.IGNORE_BATTERY_OPTIMIZATION_SETTINGS";
+
+ /**
* @hide
* Activity Action: Show the "app ops" settings screen.
* <p>
@@ -7072,6 +7087,36 @@
BLUETOOTH_SAP_PRIORITY_PREFIX = "bluetooth_sap_priority_";
/**
+ * Device Idle (Doze) specific settings.
+ * This is encoded as a key=value list, separated by commas. Ex:
+ *
+ * "inactive_timeout=60000,sensing_timeout=400000"
+ *
+ * The following keys are supported:
+ *
+ * <pre>
+ * inactive_to (long)
+ * sensing_to (long)
+ * motion_inactive_to (long)
+ * idle_after_inactive_to (long)
+ * idle_pending_to (long)
+ * max_idle_pending_to (long)
+ * idle_pending_factor (float)
+ * idle_to (long)
+ * max_idle_to (long)
+ * idle_factor (float)
+ * min_time_to_alarm (long)
+ * max_temp_app_whitelist_duration (long)
+ * </pre>
+ *
+ * <p>
+ * Type: string
+ * @hide
+ * @see com.android.server.DeviceIdleController.Constants
+ */
+ public static final String DEVICE_IDLE_CONSTANTS = "device_idle_constants";
+
+ /**
* Get the key that retrieves a bluetooth headset's priority.
* @hide
*/
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index b8493d4..8c6cd09 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -646,7 +646,7 @@
private void createLegacyIconExtras(Notification n) {
Icon smallIcon = n.getSmallIcon();
Icon largeIcon = n.getLargeIcon();
- if (smallIcon.getType() == Icon.TYPE_RESOURCE) {
+ if (smallIcon != null && smallIcon.getType() == Icon.TYPE_RESOURCE) {
n.extras.putInt(Notification.EXTRA_SMALL_ICON, smallIcon.getResId());
n.icon = smallIcon.getResId();
}
diff --git a/core/java/android/speech/tts/UtteranceProgressListener.java b/core/java/android/speech/tts/UtteranceProgressListener.java
index 9eb22ef..890ea3d 100644
--- a/core/java/android/speech/tts/UtteranceProgressListener.java
+++ b/core/java/android/speech/tts/UtteranceProgressListener.java
@@ -61,16 +61,16 @@
/**
* Called when an utterance has been stopped while in progress or flushed from the
- * synthesis queue. This can happen if client calls {@link TextToSpeech#stop()}
- * or use {@link TextToSpeech#QUEUE_FLUSH} as an argument in
+ * synthesis queue. This can happen if a client calls {@link TextToSpeech#stop()}
+ * or uses {@link TextToSpeech#QUEUE_FLUSH} as an argument with the
* {@link TextToSpeech#speak} or {@link TextToSpeech#synthesizeToFile} methods.
*
* @param utteranceId the utterance ID of the utterance.
- * @param isStarted If true, then utterance was interrupted while being synthesized
- * and it's output is incomplete. If it's false, then utterance was flushed
+ * @param interrupted If true, then the utterance was interrupted while being synthesized
+ * and its output is incomplete. If false, then the utterance was flushed
* before the synthesis started.
*/
- public void onStop(String utteranceId, boolean isStarted) {
+ public void onStop(String utteranceId, boolean interrupted) {
}
/**
@@ -99,7 +99,7 @@
}
@Override
- public void onStop(String utteranceId, boolean isStarted) {
+ public void onStop(String utteranceId, boolean interrupted) {
listener.onUtteranceCompleted(utteranceId);
}
};
diff --git a/core/java/android/text/Spanned.java b/core/java/android/text/Spanned.java
index b4622e0..a785d1b 100644
--- a/core/java/android/text/Spanned.java
+++ b/core/java/android/text/Spanned.java
@@ -187,12 +187,11 @@
public int getSpanFlags(Object tag);
/**
- * Return the first offset greater than or equal to <code>start</code>
- * where a markup object of class <code>type</code> begins or ends,
- * or <code>limit</code> if there are no starts or ends greater than or
- * equal to <code>start</code> but less than <code>limit</code>. Specify
- * <code>null</code> or Object.class for the type if you want every
- * transition regardless of type.
+ * Return the first offset greater than <code>start</code> where a markup
+ * object of class <code>type</code> begins or ends, or <code>limit</code>
+ * if there are no starts or ends greater than <code>start</code> but less
+ * than <code>limit</code>. Specify <code>null</code> or Object.class for
+ * the type if you want every transition regardless of type.
*/
public int nextSpanTransition(int start, int limit, Class type);
}
diff --git a/core/java/android/text/TextUtils.java b/core/java/android/text/TextUtils.java
index 6c4d8fd..d51aa79 100644
--- a/core/java/android/text/TextUtils.java
+++ b/core/java/android/text/TextUtils.java
@@ -1790,6 +1790,15 @@
}
}
+ /**
+ * Return localized string representing the given number of selected items.
+ *
+ * @hide
+ */
+ public static CharSequence formatSelectedCount(int count) {
+ return Resources.getSystem().getQuantityString(R.plurals.selected_count, count, count);
+ }
+
private static Object sLock = new Object();
private static char[] sTemp = null;
diff --git a/core/java/android/util/ArrayMap.java b/core/java/android/util/ArrayMap.java
index 6ed3885..4ee9807 100644
--- a/core/java/android/util/ArrayMap.java
+++ b/core/java/android/util/ArrayMap.java
@@ -266,7 +266,7 @@
/**
* Create a new ArrayMap with the mappings from the given ArrayMap.
*/
- public ArrayMap(ArrayMap map) {
+ public ArrayMap(ArrayMap<K, V> map) {
this();
if (map != null) {
putAll(map);
@@ -843,7 +843,8 @@
* in the array map.
*
* <p><b>Note:</b> this is a very inefficient way to access the array contents, it
- * requires generating a number of temporary objects.</p>
+ * requires generating a number of temporary objects and allocates additional state
+ * information associated with the container that will remain for the life of the container.</p>
*
* <p><b>Note:</b></p> the semantics of this
* Set are subtly different than that of a {@link java.util.HashMap}: most important,
@@ -861,7 +862,8 @@
* in the array map.
*
* <p><b>Note:</b> this is a fairly inefficient way to access the array contents, it
- * requires generating a number of temporary objects.</p>
+ * requires generating a number of temporary objects and allocates additional state
+ * information associated with the container that will remain for the life of the container.</p>
*/
@Override
public Set<K> keySet() {
@@ -873,7 +875,8 @@
* in the array map.
*
* <p><b>Note:</b> this is a fairly inefficient way to access the array contents, it
- * requires generating a number of temporary objects.</p>
+ * requires generating a number of temporary objects and allocates additional state
+ * information associated with the container that will remain for the life of the container.</p>
*/
@Override
public Collection<V> values() {
diff --git a/core/java/android/util/ArraySet.java b/core/java/android/util/ArraySet.java
index 7da3941..b7a3c42 100644
--- a/core/java/android/util/ArraySet.java
+++ b/core/java/android/util/ArraySet.java
@@ -42,8 +42,6 @@
* you have no control over this shrinking -- if you set a capacity and then remove an
* item, it may reduce the capacity to better match the current size. In the future an
* explicit call to set the capacity should turn off this aggressive shrinking behavior.</p>
- *
- * @hide
*/
public final class ArraySet<E> implements Collection<E>, Set<E> {
private static final boolean DEBUG = false;
@@ -660,11 +658,24 @@
return mCollections;
}
+ /**
+ * Return an {@link java.util.Iterator} over all values in the set.
+ *
+ * <p><b>Note:</b> this is a fairly inefficient way to access the array contents, it
+ * requires generating a number of temporary objects and allocates additional state
+ * information associated with the container that will remain for the life of the container.</p>
+ */
@Override
public Iterator<E> iterator() {
return getCollection().getKeySet().iterator();
}
+ /**
+ * Determine if the array set contains all of the values in the given collection.
+ * @param collection The collection whose contents are to be checked against.
+ * @return Returns true if this array set contains a value for every entry
+ * in <var>collection</var>, else returns false.
+ */
@Override
public boolean containsAll(Collection<?> collection) {
Iterator<?> it = collection.iterator();
@@ -676,6 +687,10 @@
return true;
}
+ /**
+ * Perform an {@link #add(Object)} of all values in <var>collection</var>
+ * @param collection The collection whose contents are to be retrieved.
+ */
@Override
public boolean addAll(Collection<? extends E> collection) {
ensureCapacity(mSize + collection.size());
@@ -686,6 +701,11 @@
return added;
}
+ /**
+ * Remove all values in the array set that exist in the given collection.
+ * @param collection The collection whose contents are to be used to remove values.
+ * @return Returns true if any values were removed from the array set, else false.
+ */
@Override
public boolean removeAll(Collection<?> collection) {
boolean removed = false;
@@ -695,6 +715,12 @@
return removed;
}
+ /**
+ * Remove all values in the array set that do <b>not</b> exist in the given collection.
+ * @param collection The collection whose contents are to be used to determine which
+ * values to keep.
+ * @return Returns true if any values were removed from the array set, else false.
+ */
@Override
public boolean retainAll(Collection<?> collection) {
boolean removed = false;
diff --git a/core/java/android/util/KeyValueListParser.java b/core/java/android/util/KeyValueListParser.java
new file mode 100644
index 0000000..4abdde0
--- /dev/null
+++ b/core/java/android/util/KeyValueListParser.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.util;
+
+import android.text.TextUtils;
+
+/**
+ * Parses a list of key=value pairs, separated by some delimiter, and puts the results in
+ * an internal Map. Values can be then queried by key, or if not found, a default value
+ * can be used.
+ * @hide
+ */
+public class KeyValueListParser {
+ private final ArrayMap<String, String> mValues = new ArrayMap<>();
+ private final TextUtils.StringSplitter mSplitter;
+
+ /**
+ * Constructs a new KeyValueListParser. This can be reused for different strings
+ * by calling {@link #setString(String)}.
+ * @param delim The delimiter that separates key=value pairs.
+ */
+ public KeyValueListParser(char delim) {
+ mSplitter = new TextUtils.SimpleStringSplitter(delim);
+ }
+
+ /**
+ * Resets the parser with a new string to parse. The string is expected to be in the following
+ * format:
+ * <pre>key1=value,key2=value,key3=value</pre>
+ *
+ * where the delimiter is a comma.
+ *
+ * @param str the string to parse.
+ * @throws IllegalArgumentException if the string is malformed.
+ */
+ public void setString(String str) throws IllegalArgumentException {
+ mValues.clear();
+ if (str != null) {
+ mSplitter.setString(str);
+ for (String pair : mSplitter) {
+ int sep = pair.indexOf('=');
+ if (sep < 0) {
+ mValues.clear();
+ throw new IllegalArgumentException(
+ "'" + pair + "' in '" + str + "' is not a valid key-value pair");
+ }
+ mValues.put(pair.substring(0, sep).trim(), pair.substring(sep + 1).trim());
+ }
+ }
+ }
+
+ /**
+ * Get the value for key as a long.
+ * @param key The key to lookup.
+ * @param def The value to return if the key was not found, or the value was not a long.
+ * @return the long value associated with the key.
+ */
+ public long getLong(String key, long def) {
+ String value = mValues.get(key);
+ if (value != null) {
+ try {
+ return Long.parseLong(value);
+ } catch (NumberFormatException e) {
+ // fallthrough
+ }
+ }
+ return def;
+ }
+
+ /**
+ * Get the value for key as a float.
+ * @param key The key to lookup.
+ * @param def The value to return if the key was not found, or the value was not a float.
+ * @return the float value associated with the key.
+ */
+ public float getFloat(String key, float def) {
+ String value = mValues.get(key);
+ if (value != null) {
+ try {
+ return Float.parseFloat(value);
+ } catch (NumberFormatException e) {
+ // fallthrough
+ }
+ }
+ return def;
+ }
+
+ /**
+ * Get the value for key as a string.
+ * @param key The key to lookup.
+ * @param def The value to return if the key was not found.
+ * @return the string value associated with the key.
+ */
+ public String getString(String key, String def) {
+ String value = mValues.get(key);
+ if (value != null) {
+ return value;
+ }
+ return def;
+ }
+}
diff --git a/core/java/android/view/Choreographer.java b/core/java/android/view/Choreographer.java
index d2b6533..a865307 100644
--- a/core/java/android/view/Choreographer.java
+++ b/core/java/android/view/Choreographer.java
@@ -22,6 +22,7 @@
import android.os.Message;
import android.os.SystemClock;
import android.os.SystemProperties;
+import android.os.Trace;
import android.util.Log;
import android.util.TimeUtils;
@@ -160,6 +161,14 @@
FrameInfo mFrameInfo = new FrameInfo();
/**
+ * Must be kept in sync with CALLBACK_* ints below, used to index into this array.
+ * @hide
+ */
+ private static final String[] CALLBACK_TRACE_TITLES = {
+ "input", "animation", "traversal", "commit"
+ };
+
+ /**
* Callback type: Input callback. Runs first.
* @hide
*/
@@ -584,16 +593,22 @@
mLastFrameTimeNanos = frameTimeNanos;
}
- mFrameInfo.markInputHandlingStart();
- doCallbacks(Choreographer.CALLBACK_INPUT, frameTimeNanos);
+ try {
+ Trace.traceBegin(Trace.TRACE_TAG_VIEW, "Choreographer#doFrame");
- mFrameInfo.markAnimationsStart();
- doCallbacks(Choreographer.CALLBACK_ANIMATION, frameTimeNanos);
+ mFrameInfo.markInputHandlingStart();
+ doCallbacks(Choreographer.CALLBACK_INPUT, frameTimeNanos);
- mFrameInfo.markPerformTraversalsStart();
- doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos);
+ mFrameInfo.markAnimationsStart();
+ doCallbacks(Choreographer.CALLBACK_ANIMATION, frameTimeNanos);
- doCallbacks(Choreographer.CALLBACK_COMMIT, frameTimeNanos);
+ mFrameInfo.markPerformTraversalsStart();
+ doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos);
+
+ doCallbacks(Choreographer.CALLBACK_COMMIT, frameTimeNanos);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIEW);
+ }
if (DEBUG_FRAMES) {
final long endNanos = System.nanoTime();
@@ -627,6 +642,7 @@
// safe by ensuring the commit time is always at least one frame behind.
if (callbackType == Choreographer.CALLBACK_COMMIT) {
final long jitterNanos = now - frameTimeNanos;
+ Trace.traceCounter(Trace.TRACE_TAG_VIEW, "jitterNanos", (int) jitterNanos);
if (jitterNanos >= 2 * mFrameIntervalNanos) {
final long lastFrameOffset = jitterNanos % mFrameIntervalNanos
+ mFrameIntervalNanos;
@@ -644,6 +660,7 @@
}
}
try {
+ Trace.traceBegin(Trace.TRACE_TAG_VIEW, CALLBACK_TRACE_TITLES[callbackType]);
for (CallbackRecord c = callbacks; c != null; c = c.next) {
if (DEBUG_FRAMES) {
Log.d(TAG, "RunCallback: type=" + callbackType
@@ -661,6 +678,7 @@
callbacks = next;
} while (callbacks != null);
}
+ Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
}
diff --git a/core/java/android/view/MenuInflater.java b/core/java/android/view/MenuInflater.java
index dc8cadf..1c67ba7 100644
--- a/core/java/android/view/MenuInflater.java
+++ b/core/java/android/view/MenuInflater.java
@@ -25,11 +25,8 @@
import android.app.Activity;
import android.content.Context;
import android.content.ContextWrapper;
-import android.content.res.ColorStateList;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
-import android.graphics.PorterDuff;
-import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.Log;
import android.util.Xml;
@@ -337,11 +334,6 @@
private ActionProvider itemActionProvider;
- private ColorStateList itemIconTintList;
- private boolean itemIconTintListSet;
- private PorterDuff.Mode itemIconTintMode;
- private boolean itemIconTintModeSet;
-
private static final int defaultGroupId = NO_ID;
private static final int defaultItemId = NO_ID;
private static final int defaultItemCategory = 0;
@@ -432,23 +424,6 @@
itemActionProvider = null;
}
- if (a.hasValueOrEmpty(com.android.internal.R.styleable.MenuItem_iconTint)) {
- itemIconTintList = a.getColorStateList(
- com.android.internal.R.styleable.MenuItem_iconTint);
- itemIconTintListSet = true;
- } else {
- itemIconTintList = null;
- itemIconTintListSet = false;
- }
- if (a.hasValueOrEmpty(com.android.internal.R.styleable.MenuItem_iconTintMode)) {
- itemIconTintMode = Drawable.parseTintMode(
- a.getInt(com.android.internal.R.styleable.MenuItem_iconTintMode, -1), null);
- itemIconTintModeSet = true;
- } else {
- itemIconTintMode = null;
- itemIconTintModeSet = false;
- }
-
a.recycle();
itemAdded = false;
@@ -511,13 +486,6 @@
if (itemActionProvider != null) {
item.setActionProvider(itemActionProvider);
}
-
- if (itemIconTintListSet) {
- item.setIconTintList(itemIconTintList);
- }
- if (itemIconTintModeSet) {
- item.setIconTintMode(itemIconTintMode);
- }
}
public MenuItem addItem() {
diff --git a/core/java/android/view/MenuItem.java b/core/java/android/view/MenuItem.java
index 2948007..9e8b97e 100644
--- a/core/java/android/view/MenuItem.java
+++ b/core/java/android/view/MenuItem.java
@@ -21,8 +21,6 @@
import android.annotation.StringRes;
import android.app.Activity;
import android.content.Intent;
-import android.content.res.ColorStateList;
-import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.View.OnCreateContextMenuListener;
@@ -601,26 +599,4 @@
* @return This menu item instance for call chaining
*/
public MenuItem setOnActionExpandListener(OnActionExpandListener listener);
-
- /**
- * Applies a tint to the icon drawable. Does not modify the current tint
- * mode, which is {@link PorterDuff.Mode#SRC_IN} by default.
- * <p>
- * Subsequent calls to {@link android.view.MenuItem#setIcon(android.graphics.drawable.Drawable)}
- * will automatically mutate the drawable and apply the specified tint and tint mode.
- *
- * @param tint the tint to apply, may be {@code null} to clear tint
- * @return This menu item instance for call chaining
- */
- public MenuItem setIconTintList(ColorStateList tint);
-
- /**
- * Specifies the blending mode used to apply the tint specified by {@link
- * #setIconTintList(ColorStateList)} to the icon drawable. The default mode is {@link
- * PorterDuff.Mode#SRC_IN}.
- *
- * @param tintMode the blending mode used to apply the tint, may be {@code null} to clear tint
- * @return This menu item instance for call chaining
- */
- public MenuItem setIconTintMode(PorterDuff.Mode tintMode);
}
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 160c662..7d48a9a 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -523,7 +523,7 @@
mVisibleInsets, mStableInsets, mOutsets, mConfiguration,
mNewSurface);
if ((relayoutResult & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) {
- mReportDrawNeeded = true;
+ reportDrawNeeded = true;
}
if (DEBUG) Log.i(TAG, "New surface: " + mNewSurface
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index be372d0..0df8ea9 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -741,6 +741,11 @@
private static boolean sUseBrokenMakeMeasureSpec = false;
/**
+ * Always return a size of 0 for MeasureSpec values with a mode of UNSPECIFIED
+ */
+ static boolean sUseZeroUnspecifiedMeasureSpec = false;
+
+ /**
* Ignore any optimizations using the measure cache.
*/
private static boolean sIgnoreMeasureCache = false;
@@ -3796,6 +3801,13 @@
Canvas.sCompatibilityRestore = targetSdkVersion < MNC;
+ // In MNC and newer, our widgets can pass a "hint" value in the size
+ // for UNSPECIFIED MeasureSpecs. This lets child views of scrolling containers
+ // know what the expected parent size is going to be, so e.g. list items can size
+ // themselves at 1/3 the size of their container. It breaks older apps though,
+ // specifically apps that use some popular open source libraries.
+ sUseZeroUnspecifiedMeasureSpec = targetSdkVersion < MNC;
+
sCompatibilityDone = true;
}
}
@@ -17163,21 +17175,6 @@
}
/**
- * If the view has a ColorDrawable background, returns the color of that
- * drawable.
- *
- * @return The color of the ColorDrawable background, if set, otherwise 0.
- * @hide
- */
- @ColorInt
- public int getBackgroundColor() {
- if (mBackground instanceof ColorDrawable) {
- return ((ColorDrawable) mBackground).getColor();
- }
- return 0;
- }
-
- /**
* Set the background to a given resource. The resource should refer to
* a Drawable object or 0 to remove the background.
* @param resid The identifier of the resource.
@@ -21032,6 +21029,19 @@
}
/**
+ * Like {@link #makeMeasureSpec(int, int)}, but any spec with a mode of UNSPECIFIED
+ * will automatically get a size of 0. Older apps expect this.
+ *
+ * @hide internal use only for compatibility with system widgets and older apps
+ */
+ public static int makeSafeMeasureSpec(int size, int mode) {
+ if (sUseZeroUnspecifiedMeasureSpec && mode == UNSPECIFIED) {
+ return 0;
+ }
+ return makeMeasureSpec(size, mode);
+ }
+
+ /**
* Extracts the mode from the supplied measure specification.
*
* @param measureSpec the measure specification to extract the mode from
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index dd32f85..89743e5 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -5963,12 +5963,12 @@
} else if (childDimension == LayoutParams.MATCH_PARENT) {
// Child wants to be our size... find out how big it should
// be
- resultSize = size;
+ resultSize = View.sUseZeroUnspecifiedMeasureSpec ? 0 : size;
resultMode = MeasureSpec.UNSPECIFIED;
} else if (childDimension == LayoutParams.WRAP_CONTENT) {
// Child wants to determine its own size.... find out how
// big it should be
- resultSize = size;
+ resultSize = View.sUseZeroUnspecifiedMeasureSpec ? 0 : size;
resultMode = MeasureSpec.UNSPECIFIED;
}
break;
diff --git a/core/java/android/view/ViewPropertyAnimator.java b/core/java/android/view/ViewPropertyAnimator.java
index f18b7ac..bd45007 100644
--- a/core/java/android/view/ViewPropertyAnimator.java
+++ b/core/java/android/view/ViewPropertyAnimator.java
@@ -80,18 +80,12 @@
/**
* The interpolator of the underlying Animator object. By default, we don't set the interpolator
- * on the Animator and just use its default interpolator. If the interpolator is ever set on
- * this Animator, then we use the interpolator that it was set to.
+ * on the Animator and just use its default interpolator. If the interpolator is set to a
+ * non-null value on this Animator, then we use the interpolator that it was set to.
*/
private TimeInterpolator mInterpolator;
/**
- * A flag indicating whether the interpolator has been set on this object. If not, we don't set
- * the interpolator on the underlying Animator, but instead just use its default interpolator.
- */
- private boolean mInterpolatorSet = false;
-
- /**
* Listener for the lifecycle events of the underlying ValueAnimator object.
*/
private Animator.AnimatorListener mListener = null;
@@ -338,7 +332,6 @@
* @return This object, allowing calls to methods in this class to be chained.
*/
public ViewPropertyAnimator setInterpolator(TimeInterpolator interpolator) {
- mInterpolatorSet = true;
mInterpolator = interpolator;
return this;
}
@@ -349,7 +342,7 @@
* @return The timing interpolator for this animation.
*/
public TimeInterpolator getInterpolator() {
- if (mInterpolatorSet) {
+ if (mInterpolator != null) {
return mInterpolator;
} else {
// Just return the default from ValueAnimator, since that's what we'd get if
@@ -897,7 +890,7 @@
if (mDurationSet) {
animator.setDuration(mDuration);
}
- if (mInterpolatorSet) {
+ if (mInterpolator != null) {
animator.setInterpolator(mInterpolator);
}
animator.start();
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index e1e0154..8b57d96 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -663,6 +663,10 @@
return mWindowAttributes.flags;
}
+ public int getDisplayId() {
+ return mDisplay.getDisplayId();
+ }
+
public CharSequence getTitle() {
return mWindowAttributes.getTitle();
}
@@ -1105,12 +1109,7 @@
Debug.startMethodTracing("ViewAncestor");
}
- Trace.traceBegin(Trace.TRACE_TAG_VIEW, "performTraversals");
- try {
- performTraversals();
- } finally {
- Trace.traceEnd(Trace.TRACE_TAG_VIEW);
- }
+ performTraversals();
if (mProfile) {
Debug.stopMethodTracing();
diff --git a/core/java/android/view/ViewStructure.java b/core/java/android/view/ViewStructure.java
index 8ceb166..d06cd83 100644
--- a/core/java/android/view/ViewStructure.java
+++ b/core/java/android/view/ViewStructure.java
@@ -201,6 +201,17 @@
public abstract void setChildCount(int num);
/**
+ * Add to this view's child count. This increases the current child count by
+ * <var>num</var> children beyond what was last set by {@link #setChildCount}
+ * or {@link #addChildCount}. The index at which the new child starts in the child
+ * array is returned.
+ *
+ * @param num The number of new children to add.
+ * @return Returns the index in the child array at which the new children start.
+ */
+ public abstract int addChildCount(int num);
+
+ /**
* Return the child count as set by {@link #setChildCount}.
*/
public abstract int getChildCount();
diff --git a/core/java/android/webkit/WebViewFactory.java b/core/java/android/webkit/WebViewFactory.java
index b7d529e..b4ef58a 100644
--- a/core/java/android/webkit/WebViewFactory.java
+++ b/core/java/android/webkit/WebViewFactory.java
@@ -333,8 +333,8 @@
newVmSize = Math.max(newVmSize, f.length());
continue;
}
- if (path.contains("!")) {
- String[] split = TextUtils.split(path, "!");
+ if (path.contains("!/")) {
+ String[] split = TextUtils.split(path, "!/");
if (split.length == 2) {
try {
ZipFile z = new ZipFile(split[0]);
@@ -384,7 +384,7 @@
ZipEntry e = z.getEntry(entry);
if (e != null && e.getMethod() == ZipEntry.STORED) {
// Return a path formatted for dlopen() load from APK.
- return apkPath + "!" + entry;
+ return apkPath + "!/" + entry;
}
}
} catch (IOException e) {
diff --git a/core/java/android/widget/ActionMenuPresenter.java b/core/java/android/widget/ActionMenuPresenter.java
index f08141c..a5696ee 100644
--- a/core/java/android/widget/ActionMenuPresenter.java
+++ b/core/java/android/widget/ActionMenuPresenter.java
@@ -21,10 +21,8 @@
import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
import android.content.Context;
-import android.content.res.ColorStateList;
import android.content.res.Configuration;
import android.content.res.Resources;
-import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
import android.os.Parcel;
import android.os.Parcelable;
@@ -64,6 +62,8 @@
private static final boolean ACTIONBAR_ANIMATIONS_ENABLED = false;
private OverflowMenuButton mOverflowButton;
+ private Drawable mPendingOverflowIcon;
+ private boolean mPendingOverflowIconSet;
private boolean mReserveOverflow;
private boolean mReserveOverflowSet;
private int mWidthLimit;
@@ -85,8 +85,6 @@
private OpenOverflowRunnable mPostedOpenRunnable;
private ActionMenuPopupCallback mPopupCallback;
- private TintInfo mOverflowTintInfo;
-
final PopupPresenterCallback mPopupPresenterCallback = new PopupPresenterCallback();
int mOpenSubMenuId;
@@ -154,9 +152,13 @@
if (mReserveOverflow) {
if (mOverflowButton == null) {
mOverflowButton = new OverflowMenuButton(mSystemContext);
+ if (mPendingOverflowIconSet) {
+ mOverflowButton.setImageDrawable(mPendingOverflowIcon);
+ mPendingOverflowIcon = null;
+ mPendingOverflowIconSet = false;
+ }
final int spec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
mOverflowButton.measure(spec, spec);
- applyOverflowTint();
}
width -= mOverflowButton.getMeasuredWidth();
} else {
@@ -198,6 +200,24 @@
mExpandedActionViewsExclusive = isExclusive;
}
+ public void setOverflowIcon(Drawable icon) {
+ if (mOverflowButton != null) {
+ mOverflowButton.setImageDrawable(icon);
+ } else {
+ mPendingOverflowIconSet = true;
+ mPendingOverflowIcon = icon;
+ }
+ }
+
+ public Drawable getOverflowIcon() {
+ if (mOverflowButton != null) {
+ return mOverflowButton.getDrawable();
+ } else if (mPendingOverflowIconSet) {
+ return mPendingOverflowIcon;
+ }
+ return null;
+ }
+
@Override
public MenuView getMenuView(ViewGroup root) {
MenuView oldMenuView = mMenuView;
@@ -449,7 +469,6 @@
if (hasOverflow) {
if (mOverflowButton == null) {
mOverflowButton = new OverflowMenuButton(mSystemContext);
- applyOverflowTint();
}
ViewGroup parent = (ViewGroup) mOverflowButton.getParent();
if (parent != mMenuView) {
@@ -764,40 +783,6 @@
}
}
- public void setOverflowTintList(ColorStateList tint) {
- if (mOverflowTintInfo == null) {
- mOverflowTintInfo = new TintInfo();
- }
- mOverflowTintInfo.mTintList = tint;
- mOverflowTintInfo.mHasTintList = true;
-
- applyOverflowTint();
- }
-
- public void setOverflowTintMode(PorterDuff.Mode tintMode) {
- if (mOverflowTintInfo == null) {
- mOverflowTintInfo = new TintInfo();
- }
- mOverflowTintInfo.mTintMode = tintMode;
- mOverflowTintInfo.mHasTintMode = true;
-
- applyOverflowTint();
- }
-
- private void applyOverflowTint() {
- final TintInfo tintInfo = mOverflowTintInfo;
- if (tintInfo != null && (tintInfo.mHasTintList || tintInfo.mHasTintMode)) {
- if (mOverflowButton != null) {
- if (tintInfo.mHasTintList) {
- mOverflowButton.setImageTintList(tintInfo.mTintList);
- }
- if (tintInfo.mHasTintMode) {
- mOverflowButton.setImageTintMode(tintInfo.mTintMode);
- }
- }
- }
- }
-
private static class SavedState implements Parcelable {
public int openSubMenuId;
@@ -1023,13 +1008,6 @@
}
}
- private static class TintInfo {
- ColorStateList mTintList;
- PorterDuff.Mode mTintMode;
- boolean mHasTintMode;
- boolean mHasTintList;
- }
-
/**
* This class holds layout information for a menu item. This is used to determine
* pre- and post-layout information about menu items, which will then be used to
@@ -1077,5 +1055,4 @@
this.animType = animType;
}
}
-
}
diff --git a/core/java/android/widget/ActionMenuView.java b/core/java/android/widget/ActionMenuView.java
index 278a8fb..1f02c3b 100644
--- a/core/java/android/widget/ActionMenuView.java
+++ b/core/java/android/widget/ActionMenuView.java
@@ -16,11 +16,11 @@
package android.widget;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.StyleRes;
import android.content.Context;
-import android.content.res.ColorStateList;
import android.content.res.Configuration;
-import android.graphics.PorterDuff;
+import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.ContextThemeWrapper;
import android.view.Gravity;
@@ -541,6 +541,27 @@
dismissPopupMenus();
}
+ /**
+ * Set the icon to use for the overflow button.
+ *
+ * @param icon Drawable to set, may be null to clear the icon
+ */
+ public void setOverflowIcon(@Nullable Drawable icon) {
+ getMenu();
+ mPresenter.setOverflowIcon(icon);
+ }
+
+ /**
+ * Return the current drawable used as the overflow icon.
+ *
+ * @return The overflow icon drawable
+ */
+ @Nullable
+ public Drawable getOverflowIcon() {
+ getMenu();
+ return mPresenter.getOverflowIcon();
+ }
+
/** @hide */
public boolean isOverflowReserved() {
return mReserveOverflow;
@@ -551,31 +572,6 @@
mReserveOverflow = reserveOverflow;
}
- /**
- * Applies a tint to the overflow drawable. Does not modify the current tint
- * mode, which is {@link PorterDuff.Mode#SRC_IN} by default.
- *
- * @param tint the tint to apply, may be {@code null} to clear tint
- */
- public void setOverflowTintList(ColorStateList tint) {
- if (mPresenter != null) {
- mPresenter.setOverflowTintList(tint);
- }
- }
-
- /**
- * Specifies the blending mode used to apply the tint specified by {@link
- * #setOverflowTintList(ColorStateList)} to the overflow drawable.
- * The default mode is {@link PorterDuff.Mode#SRC_IN}.
- *
- * @param tintMode the blending mode used to apply the tint, may be {@code null} to clear tint
- */
- public void setOverflowTintMode(PorterDuff.Mode tintMode) {
- if (mPresenter != null) {
- mPresenter.setOverflowTintMode(tintMode);
- }
- }
-
@Override
protected LayoutParams generateDefaultLayoutParams() {
LayoutParams params = new LayoutParams(LayoutParams.WRAP_CONTENT,
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index e43237a..cf6a018 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -1162,6 +1162,10 @@
// We do not hide the span controllers, since they can be added when a new text is
// inserted into the text view (voice IME).
hideCursorControllers();
+ // Reset drag accelerator.
+ if (mSelectionModifierCursorController != null) {
+ mSelectionModifierCursorController.resetTouchOffsets();
+ }
stopTextActionMode();
}
diff --git a/core/java/android/widget/FastScroller.java b/core/java/android/widget/FastScroller.java
index f06f3c21..11d7026 100644
--- a/core/java/android/widget/FastScroller.java
+++ b/core/java/android/widget/FastScroller.java
@@ -662,7 +662,7 @@
final int adjMaxWidth = maxWidth - marginLeft - marginRight;
final int widthMeasureSpec = MeasureSpec.makeMeasureSpec(adjMaxWidth, MeasureSpec.AT_MOST);
- final int heightMeasureSpec = MeasureSpec.makeMeasureSpec(container.height(),
+ final int heightMeasureSpec = MeasureSpec.makeSafeMeasureSpec(container.height(),
MeasureSpec.UNSPECIFIED);
view.measure(widthMeasureSpec, heightMeasureSpec);
@@ -702,7 +702,7 @@
final int containerWidth = container.width();
final int adjMaxWidth = containerWidth - marginLeft - marginRight;
final int widthMeasureSpec = MeasureSpec.makeMeasureSpec(adjMaxWidth, MeasureSpec.AT_MOST);
- final int heightMeasureSpec = MeasureSpec.makeMeasureSpec(container.height(),
+ final int heightMeasureSpec = MeasureSpec.makeSafeMeasureSpec(container.height(),
MeasureSpec.UNSPECIFIED);
preview.measure(widthMeasureSpec, heightMeasureSpec);
@@ -768,7 +768,7 @@
final Rect container = mContainerRect;
final int maxWidth = container.width();
final int widthMeasureSpec = MeasureSpec.makeMeasureSpec(maxWidth, MeasureSpec.AT_MOST);
- final int heightMeasureSpec = MeasureSpec.makeMeasureSpec(container.height(),
+ final int heightMeasureSpec = MeasureSpec.makeSafeMeasureSpec(container.height(),
MeasureSpec.UNSPECIFIED);
track.measure(widthMeasureSpec, heightMeasureSpec);
diff --git a/core/java/android/widget/GridView.java b/core/java/android/widget/GridView.java
index dcaafa5..f994d4a 100644
--- a/core/java/android/widget/GridView.java
+++ b/core/java/android/widget/GridView.java
@@ -1073,7 +1073,7 @@
p.forceAdd = true;
int childHeightSpec = getChildMeasureSpec(
- MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(heightMeasureSpec),
+ MeasureSpec.makeSafeMeasureSpec(MeasureSpec.getSize(heightMeasureSpec),
MeasureSpec.UNSPECIFIED), 0, p.height);
int childWidthSpec = getChildMeasureSpec(
MeasureSpec.makeMeasureSpec(mColumnWidth, MeasureSpec.EXACTLY), 0, p.width);
diff --git a/core/java/android/widget/LinearLayout.java b/core/java/android/widget/LinearLayout.java
index 9d14254..056323db 100644
--- a/core/java/android/widget/LinearLayout.java
+++ b/core/java/android/widget/LinearLayout.java
@@ -1062,9 +1062,9 @@
// use as much space as it wants because we can shrink things
// later (and re-measure).
if (baselineAligned) {
- final int freeWidthSpec = MeasureSpec.makeMeasureSpec(
+ final int freeWidthSpec = MeasureSpec.makeSafeMeasureSpec(
MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.UNSPECIFIED);
- final int freeHeightSpec = MeasureSpec.makeMeasureSpec(
+ final int freeHeightSpec = MeasureSpec.makeSafeMeasureSpec(
MeasureSpec.getSize(heightMeasureSpec), MeasureSpec.UNSPECIFIED);
child.measure(freeWidthSpec, freeHeightSpec);
} else {
diff --git a/core/java/android/widget/ListPopupWindow.java b/core/java/android/widget/ListPopupWindow.java
index 94b9416..afc683a 100644
--- a/core/java/android/widget/ListPopupWindow.java
+++ b/core/java/android/widget/ListPopupWindow.java
@@ -618,12 +618,11 @@
heightSpec = mDropDownHeight;
}
- mPopup.setWidth(widthSpec);
- mPopup.setHeight(heightSpec);
mPopup.setOutsideTouchable(!mForceIgnoreOutsideTouch && !mDropDownAlwaysVisible);
mPopup.update(getAnchorView(), mDropDownHorizontalOffset,
- mDropDownVerticalOffset, -1, -1);
+ mDropDownVerticalOffset, (widthSpec < 0)? -1 : widthSpec,
+ (heightSpec < 0)? -1 : heightSpec);
} else {
final int widthSpec;
if (mDropDownWidth == ViewGroup.LayoutParams.MATCH_PARENT) {
diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java
index f8b965f..fd0395a 100644
--- a/core/java/android/widget/ListView.java
+++ b/core/java/android/widget/ListView.java
@@ -1206,7 +1206,7 @@
if (lpHeight > 0) {
childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight, MeasureSpec.EXACTLY);
} else {
- childHeightSpec = MeasureSpec.makeMeasureSpec(heightHint, MeasureSpec.UNSPECIFIED);
+ childHeightSpec = MeasureSpec.makeSafeMeasureSpec(heightHint, MeasureSpec.UNSPECIFIED);
}
child.measure(childWidthSpec, childHeightSpec);
}
@@ -1943,7 +1943,7 @@
if (lpHeight > 0) {
childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight, MeasureSpec.EXACTLY);
} else {
- childHeightSpec = MeasureSpec.makeMeasureSpec(getMeasuredHeight(),
+ childHeightSpec = MeasureSpec.makeSafeMeasureSpec(getMeasuredHeight(),
MeasureSpec.UNSPECIFIED);
}
child.measure(childWidthSpec, childHeightSpec);
@@ -2698,7 +2698,7 @@
if (lpHeight > 0) {
childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight, MeasureSpec.EXACTLY);
} else {
- childHeightSpec = MeasureSpec.makeMeasureSpec(getMeasuredHeight(),
+ childHeightSpec = MeasureSpec.makeSafeMeasureSpec(getMeasuredHeight(),
MeasureSpec.UNSPECIFIED);
}
child.measure(childWidthSpec, childHeightSpec);
diff --git a/core/java/android/widget/ScrollView.java b/core/java/android/widget/ScrollView.java
index 11904e1..58a94b96 100644
--- a/core/java/android/widget/ScrollView.java
+++ b/core/java/android/widget/ScrollView.java
@@ -1263,7 +1263,7 @@
childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec, mPaddingLeft
+ mPaddingRight, lp.width);
- childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(
+ childHeightMeasureSpec = MeasureSpec.makeSafeMeasureSpec(
MeasureSpec.getSize(parentHeightMeasureSpec), MeasureSpec.UNSPECIFIED);
child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
@@ -1277,7 +1277,7 @@
final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec,
mPaddingLeft + mPaddingRight + lp.leftMargin + lp.rightMargin
+ widthUsed, lp.width);
- final int childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(
+ final int childHeightMeasureSpec = MeasureSpec.makeSafeMeasureSpec(
MeasureSpec.getSize(parentHeightMeasureSpec), MeasureSpec.UNSPECIFIED);
child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
diff --git a/core/java/android/widget/Spinner.java b/core/java/android/widget/Spinner.java
index 6fe34dd..fdabe91 100644
--- a/core/java/android/widget/Spinner.java
+++ b/core/java/android/widget/Spinner.java
@@ -812,9 +812,9 @@
View itemView = null;
int itemType = 0;
final int widthMeasureSpec =
- MeasureSpec.makeMeasureSpec(getMeasuredWidth(), MeasureSpec.UNSPECIFIED);
+ MeasureSpec.makeSafeMeasureSpec(getMeasuredWidth(), MeasureSpec.UNSPECIFIED);
final int heightMeasureSpec =
- MeasureSpec.makeMeasureSpec(getMeasuredHeight(), MeasureSpec.UNSPECIFIED);
+ MeasureSpec.makeSafeMeasureSpec(getMeasuredHeight(), MeasureSpec.UNSPECIFIED);
// Make sure the number of items we'll measure is capped. If it's a huge data set
// with wildly varying sizes, oh well.
diff --git a/core/java/android/widget/TabWidget.java b/core/java/android/widget/TabWidget.java
index aa7168c..d9cff4e 100644
--- a/core/java/android/widget/TabWidget.java
+++ b/core/java/android/widget/TabWidget.java
@@ -174,7 +174,8 @@
// First, measure with no constraint
final int width = MeasureSpec.getSize(widthMeasureSpec);
- final int unspecifiedWidth = MeasureSpec.makeMeasureSpec(width, MeasureSpec.UNSPECIFIED);
+ final int unspecifiedWidth = MeasureSpec.makeSafeMeasureSpec(width,
+ MeasureSpec.UNSPECIFIED);
mImposedTabsHeight = -1;
super.measureHorizontal(unspecifiedWidth, heightMeasureSpec);
diff --git a/core/java/android/widget/TableRow.java b/core/java/android/widget/TableRow.java
index d4288d6..f7f9c91 100644
--- a/core/java/android/widget/TableRow.java
+++ b/core/java/android/widget/TableRow.java
@@ -303,7 +303,7 @@
spec = getChildMeasureSpec(widthMeasureSpec, 0, LayoutParams.WRAP_CONTENT);
break;
case LayoutParams.MATCH_PARENT:
- spec = MeasureSpec.makeMeasureSpec(
+ spec = MeasureSpec.makeSafeMeasureSpec(
MeasureSpec.getSize(heightMeasureSpec),
MeasureSpec.UNSPECIFIED);
break;
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 353901c..78b5d5d 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -8790,7 +8790,8 @@
@Override
public void onProvideStructure(ViewStructure structure) {
super.onProvideStructure(structure);
- final boolean isPassword = hasPasswordTransformationMethod();
+ final boolean isPassword = hasPasswordTransformationMethod()
+ || isPasswordInputType(getInputType());
if (!isPassword) {
structure.setText(getText(), getSelectionStart(), getSelectionEnd());
@@ -9244,25 +9245,25 @@
/**
* If provided, this ActionMode.Callback will be used to create the ActionMode when text
* insertion is initiated in this View.
- *
* The standard implementation populates the menu with a subset of Select All,
* Paste and Replace actions, depending on what this View supports.
*
- * A custom implementation can add new entries in the default menu in its
- * {@link android.view.ActionMode.Callback#onPrepareActionMode(ActionMode, Menu)} method. The
- * default actions can also be removed from the menu using
+ * <p>A custom implementation can add new entries in the default menu in its
+ * {@link android.view.ActionMode.Callback#onPrepareActionMode(android.view.ActionMode,
+ * android.view.Menu)} method. The default actions can also be removed from the menu using
* {@link android.view.Menu#removeItem(int)} and passing {@link android.R.id#selectAll},
- * {@link android.R.id#paste} or {@link android.R.id#replaceText} ids as parameters.
+ * {@link android.R.id#paste} or {@link android.R.id#replaceText} ids as parameters.</p>
*
- * Returning false from
- * {@link android.view.ActionMode.Callback#onCreateActionMode(ActionMode, Menu)} will prevent
- * the action mode from being started.
+ * <p>Returning false from
+ * {@link android.view.ActionMode.Callback#onCreateActionMode(android.view.ActionMode,
+ * android.view.Menu)} will prevent the action mode from being started.</p>
*
- * Action click events should be handled by the custom implementation of
- * {@link android.view.ActionMode.Callback#onActionItemClicked(ActionMode, MenuItem)}.
+ * <p>Action click events should be handled by the custom implementation of
+ * {@link android.view.ActionMode.Callback#onActionItemClicked(android.view.ActionMode,
+ * android.view.MenuItem)}.</p>
*
- * Note that text insertion mode is not started when a TextView receives focus and the
- * {@link android.R.attr#selectAllOnFocus} flag has been set.
+ * <p>Note that text insertion mode is not started when a TextView receives focus and the
+ * {@link android.R.attr#selectAllOnFocus} flag has been set.</p>
*/
public void setCustomInsertionActionModeCallback(ActionMode.Callback actionModeCallback) {
createEditorIfNeeded();
diff --git a/core/java/android/widget/Toolbar.java b/core/java/android/widget/Toolbar.java
index 62d948d..8ace0f3 100644
--- a/core/java/android/widget/Toolbar.java
+++ b/core/java/android/widget/Toolbar.java
@@ -25,9 +25,8 @@
import android.annotation.StyleRes;
import android.app.ActionBar;
import android.content.Context;
-import android.content.res.ColorStateList;
import android.content.res.TypedArray;
-import android.graphics.PorterDuff;
+import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.os.Parcel;
import android.os.Parcelable;
@@ -110,9 +109,6 @@
private ImageButton mNavButtonView;
private ImageView mLogoView;
- private TintInfo mOverflowTintInfo;
- private TintInfo mNavTintInfo;
-
private Drawable mCollapseIcon;
private CharSequence mCollapseDescription;
private ImageButton mCollapseButtonView;
@@ -275,21 +271,6 @@
if (!TextUtils.isEmpty(navDesc)) {
setNavigationContentDescription(navDesc);
}
-
- if (a.hasValue(R.styleable.Toolbar_overflowTint)) {
- setOverflowTintList(a.getColorStateList(R.styleable.Toolbar_overflowTint));
- }
- if (a.hasValue(R.styleable.Toolbar_overflowTintMode)) {
- setOverflowTintMode(Drawable.parseTintMode(
- a.getInt(R.styleable.Toolbar_overflowTintMode, -1), null));
- }
- if (a.hasValue(R.styleable.Toolbar_navigationTint)) {
- setNavigationTintList(a.getColorStateList(R.styleable.Toolbar_navigationTint));
- }
- if (a.hasValue(R.styleable.Toolbar_navigationTintMode)) {
- setNavigationTintMode(Drawable.parseTintMode(
- a.getInt(R.styleable.Toolbar_navigationTintMode, -1), null));
- }
a.recycle();
}
@@ -830,91 +811,6 @@
}
/**
- * Applies a tint to the icon drawable. Does not modify the current tint
- * mode, which is {@link PorterDuff.Mode#SRC_IN} by default.
- * <p>
- * Subsequent calls to {@link #setNavigationIcon(Drawable)} will automatically mutate
- * the drawable and apply the specified tint and tint mode.
- *
- * @param tint the tint to apply, may be {@code null} to clear tint
- *
- * @attr ref android.R.styleable#Toolbar_navigationTint
- */
- public void setNavigationTintList(ColorStateList tint) {
- if (mNavTintInfo == null) {
- mNavTintInfo = new TintInfo();
- }
- mNavTintInfo.mTintList = tint;
- mNavTintInfo.mHasTintList = true;
-
- applyNavigationTint();
- }
-
- /**
- * Specifies the blending mode used to apply the tint specified by {@link
- * #setNavigationTintList(ColorStateList)} to the navigation drawable.
- * The default mode is {@link PorterDuff.Mode#SRC_IN}.
- *
- * @param tintMode the blending mode used to apply the tint, may be {@code null} to clear tint
- *
- * @attr ref android.R.styleable#Toolbar_navigationTintMode
- */
- public void setNavigationTintMode(PorterDuff.Mode tintMode) {
- if (mNavTintInfo == null) {
- mNavTintInfo = new TintInfo();
- }
- mNavTintInfo.mTintMode = tintMode;
- mNavTintInfo.mHasTintMode = true;
-
- applyNavigationTint();
- }
-
- /**
- * Applies a tint to the overflow drawable. Does not modify the current tint
- * mode, which is {@link PorterDuff.Mode#SRC_IN} by default.
- *
- * @param tint the tint to apply, may be {@code null} to clear tint
- *
- * @attr ref android.R.styleable#Toolbar_overflowTint
- */
- public void setOverflowTintList(ColorStateList tint) {
- if (mMenuView != null) {
- // If the menu view is available, directly set the tint
- mMenuView.setOverflowTintList(tint);
- } else {
- // Otherwise we will record the value
- if (mOverflowTintInfo == null) {
- mOverflowTintInfo = new TintInfo();
- }
- mOverflowTintInfo.mTintList = tint;
- mOverflowTintInfo.mHasTintList = true;
- }
- }
-
- /**
- * Specifies the blending mode used to apply the tint specified by {@link
- * #setOverflowTintList(ColorStateList)} to the overflow drawable.
- * The default mode is {@link PorterDuff.Mode#SRC_IN}.
- *
- * @param tintMode the blending mode used to apply the tint, may be {@code null} to clear tint
- *
- * @attr ref android.R.styleable#Toolbar_overflowTintMode
- */
- public void setOverflowTintMode(PorterDuff.Mode tintMode) {
- if (mMenuView != null) {
- // If the menu view is available, directly set the tint mode
- mMenuView.setOverflowTintMode(tintMode);
- } else {
- // Otherwise we will record the value
- if (mOverflowTintInfo == null) {
- mOverflowTintInfo = new TintInfo();
- }
- mOverflowTintInfo.mTintMode = tintMode;
- mOverflowTintInfo.mHasTintMode = true;
- }
- }
-
- /**
* Return the Menu shown in the toolbar.
*
* <p>Applications that wish to populate the toolbar's menu can do so from here. To use
@@ -927,6 +823,27 @@
return mMenuView.getMenu();
}
+ /**
+ * Set the icon to use for the overflow button.
+ *
+ * @param icon Drawable to set, may be null to clear the icon
+ */
+ public void setOverflowIcon(@Nullable Drawable icon) {
+ ensureMenu();
+ mMenuView.setOverflowIcon(icon);
+ }
+
+ /**
+ * Return the current drawable used as the overflow icon.
+ *
+ * @return The overflow icon drawable
+ */
+ @Nullable
+ public Drawable getOverflowIcon() {
+ ensureMenu();
+ return mMenuView.getOverflowIcon();
+ }
+
private void ensureMenu() {
ensureMenuView();
if (mMenuView.peekMenu() == null) {
@@ -950,17 +867,6 @@
lp.gravity = Gravity.END | (mButtonGravity & Gravity.VERTICAL_GRAVITY_MASK);
mMenuView.setLayoutParams(lp);
addSystemView(mMenuView);
-
- if (mOverflowTintInfo != null) {
- // If we have tint info for the overflow, set it on the menu view now
- if (mOverflowTintInfo.mHasTintList) {
- mMenuView.setOverflowTintList(mOverflowTintInfo.mTintList);
- }
- if (mOverflowTintInfo.mHasTintMode) {
- mMenuView.setOverflowTintMode(mOverflowTintInfo.mTintMode);
- }
- mOverflowTintInfo = null;
- }
}
}
@@ -1114,7 +1020,6 @@
final LayoutParams lp = generateDefaultLayoutParams();
lp.gravity = Gravity.START | (mButtonGravity & Gravity.VERTICAL_GRAVITY_MASK);
mNavButtonView.setLayoutParams(lp);
- applyNavigationTint();
}
}
@@ -1133,7 +1038,6 @@
collapseActionView();
}
});
- applyNavigationTint();
}
}
@@ -1885,30 +1789,6 @@
return mPopupContext;
}
- private void applyNavigationTint() {
- final TintInfo tintInfo = mNavTintInfo;
- if (tintInfo != null && (tintInfo.mHasTintList || tintInfo.mHasTintMode)) {
- if (mNavButtonView != null) {
- if (tintInfo.mHasTintList) {
- mNavButtonView.setImageTintList(tintInfo.mTintList);
- }
- if (tintInfo.mHasTintMode) {
- mNavButtonView.setImageTintMode(tintInfo.mTintMode);
- }
- }
-
- if (mCollapseButtonView != null) {
- // We will use the same tint for the collapse button
- if (tintInfo.mHasTintList) {
- mCollapseButtonView.setImageTintList(tintInfo.mTintList);
- }
- if (tintInfo.mHasTintMode) {
- mCollapseButtonView.setImageTintMode(tintInfo.mTintMode);
- }
- }
- }
- }
-
/**
* Interface responsible for receiving menu item click events if the items themselves
* do not have individual item click listeners.
@@ -2136,11 +2016,4 @@
public void onRestoreInstanceState(Parcelable state) {
}
}
-
- private static class TintInfo {
- ColorStateList mTintList;
- PorterDuff.Mode mTintMode;
- boolean mHasTintMode;
- boolean mHasTintList;
- }
}
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index ba4af89..39c86f9 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -18,8 +18,6 @@
import android.app.Activity;
import android.app.ActivityThread;
-import android.app.usage.UsageStats;
-import android.app.usage.UsageStatsManager;
import android.os.AsyncTask;
import android.provider.Settings;
import android.text.TextUtils;
@@ -64,14 +62,11 @@
import android.widget.Toast;
import com.android.internal.widget.ResolverDrawerLayout;
-import java.text.Collator;
import java.util.ArrayList;
import java.util.Collections;
-import java.util.Comparator;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
-import java.util.Map;
import java.util.Set;
import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
@@ -100,10 +95,7 @@
private boolean mResolvingHome = false;
private int mProfileSwitchMessageId = -1;
private final ArrayList<Intent> mIntents = new ArrayList<>();
-
- private UsageStatsManager mUsm;
- private Map<String, UsageStats> mStats;
- private static final long USAGE_STATS_PERIOD = 1000 * 60 * 60 * 24 * 14;
+ private ResolverComparator mResolverComparator;
private boolean mRegistered;
private final PackageMonitor mPackageMonitor = new PackageMonitor() {
@@ -222,10 +214,6 @@
}
mPm = getPackageManager();
- mUsm = (UsageStatsManager) getSystemService(Context.USAGE_STATS_SERVICE);
-
- final long sinceTime = System.currentTimeMillis() - USAGE_STATS_PERIOD;
- mStats = mUsm.queryAndAggregateUsageStats(sinceTime, System.currentTimeMillis());
mPackageMonitor.register(this, getMainLooper(), false);
mRegistered = true;
@@ -236,6 +224,10 @@
// Add our initial intent as the first item, regardless of what else has already been added.
mIntents.add(0, new Intent(intent));
+ final String referrerPackage = getReferrerPackageName();
+
+ mResolverComparator = new ResolverComparator(this, getTargetIntent(), referrerPackage);
+
configureContentView(mIntents, initialIntents, rList, alwaysUseOption);
// Prevent the Resolver window from becoming the top fullscreen window and thus from taking
@@ -265,7 +257,6 @@
// Try to initialize the title icon if we have a view for it and a title to match
final ImageView titleIcon = (ImageView) findViewById(R.id.title_icon);
if (titleIcon != null) {
- final String referrerPackage = getReferrerPackageName();
ApplicationInfo ai = null;
try {
if (!TextUtils.isEmpty(referrerPackage)) {
@@ -1175,8 +1166,8 @@
}
}
if (N > 1) {
- Collections.sort(currentResolveList,
- new ResolverComparator(ResolverActivity.this, getTargetIntent()));
+ mResolverComparator.compute(currentResolveList);
+ Collections.sort(currentResolveList, mResolverComparator);
}
// First put the initial items at the top.
if (mInitialIntents != null) {
@@ -1651,63 +1642,4 @@
&& match <= IntentFilter.MATCH_CATEGORY_PATH;
}
- class ResolverComparator implements Comparator<ResolvedComponentInfo> {
- private final Collator mCollator;
- private final boolean mHttp;
-
- public ResolverComparator(Context context, Intent intent) {
- mCollator = Collator.getInstance(context.getResources().getConfiguration().locale);
- String scheme = intent.getScheme();
- mHttp = "http".equals(scheme) || "https".equals(scheme);
- }
-
- @Override
- public int compare(ResolvedComponentInfo lhsp, ResolvedComponentInfo rhsp) {
- final ResolveInfo lhs = lhsp.getResolveInfoAt(0);
- final ResolveInfo rhs = rhsp.getResolveInfoAt(0);
-
- // We want to put the one targeted to another user at the end of the dialog.
- if (lhs.targetUserId != UserHandle.USER_CURRENT) {
- return 1;
- }
-
- if (mHttp) {
- // Special case: we want filters that match URI paths/schemes to be
- // ordered before others. This is for the case when opening URIs,
- // to make native apps go above browsers.
- final boolean lhsSpecific = isSpecificUriMatch(lhs.match);
- final boolean rhsSpecific = isSpecificUriMatch(rhs.match);
- if (lhsSpecific != rhsSpecific) {
- return lhsSpecific ? -1 : 1;
- }
- }
-
- if (mStats != null) {
- final long timeDiff =
- getPackageTimeSpent(rhs.activityInfo.packageName) -
- getPackageTimeSpent(lhs.activityInfo.packageName);
-
- if (timeDiff != 0) {
- return timeDiff > 0 ? 1 : -1;
- }
- }
-
- CharSequence sa = lhs.loadLabel(mPm);
- if (sa == null) sa = lhs.activityInfo.name;
- CharSequence sb = rhs.loadLabel(mPm);
- if (sb == null) sb = rhs.activityInfo.name;
-
- return mCollator.compare(sa.toString(), sb.toString());
- }
-
- private long getPackageTimeSpent(String packageName) {
- if (mStats != null) {
- final UsageStats stats = mStats.get(packageName);
- if (stats != null) {
- return stats.getTotalTimeInForeground();
- }
- }
- return 0;
- }
- }
}
diff --git a/core/java/com/android/internal/app/ResolverComparator.java b/core/java/com/android/internal/app/ResolverComparator.java
new file mode 100644
index 0000000..585cdf1
--- /dev/null
+++ b/core/java/com/android/internal/app/ResolverComparator.java
@@ -0,0 +1,215 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package com.android.internal.app;
+
+import android.app.usage.UsageStats;
+import android.app.usage.UsageStatsManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.ComponentInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.os.UserHandle;
+import android.text.TextUtils;
+import android.util.Log;
+import com.android.internal.app.ResolverActivity.ResolvedComponentInfo;
+
+import java.text.Collator;
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Ranks and compares packages based on usage stats.
+ */
+class ResolverComparator implements Comparator<ResolvedComponentInfo> {
+ private static final String TAG = "ResolverComparator";
+
+ private static final boolean DEBUG = false;
+
+ // Two weeks
+ private static final long USAGE_STATS_PERIOD = 1000 * 60 * 60 * 24 * 14;
+
+ private static final long RECENCY_TIME_PERIOD = 1000 * 60 * 60 * 12;
+
+ private static final float RECENCY_MULTIPLIER = 3.f;
+
+ private final Collator mCollator;
+ private final boolean mHttp;
+ private final PackageManager mPm;
+ private final UsageStatsManager mUsm;
+ private final Map<String, UsageStats> mStats;
+ private final long mCurrentTime;
+ private final long mSinceTime;
+ private final LinkedHashMap<ComponentName, ScoredTarget> mScoredTargets = new LinkedHashMap<>();
+ private final String mReferrerPackage;
+
+ public ResolverComparator(Context context, Intent intent, String referrerPackage) {
+ mCollator = Collator.getInstance(context.getResources().getConfiguration().locale);
+ String scheme = intent.getScheme();
+ mHttp = "http".equals(scheme) || "https".equals(scheme);
+ mReferrerPackage = referrerPackage;
+
+ mPm = context.getPackageManager();
+ mUsm = (UsageStatsManager) context.getSystemService(Context.USAGE_STATS_SERVICE);
+
+ mCurrentTime = System.currentTimeMillis();
+ mSinceTime = mCurrentTime - USAGE_STATS_PERIOD;
+ mStats = mUsm.queryAndAggregateUsageStats(mSinceTime, mCurrentTime);
+ }
+
+ public void compute(List<ResolvedComponentInfo> targets) {
+ mScoredTargets.clear();
+
+ final long recentSinceTime = mCurrentTime - RECENCY_TIME_PERIOD;
+
+ long mostRecentlyUsedTime = recentSinceTime + 1;
+ long mostTimeSpent = 1;
+ int mostLaunched = 1;
+
+ for (ResolvedComponentInfo target : targets) {
+ final ScoredTarget scoredTarget
+ = new ScoredTarget(target.getResolveInfoAt(0).activityInfo);
+ mScoredTargets.put(target.name, scoredTarget);
+ final UsageStats pkStats = mStats.get(target.name.getPackageName());
+ if (pkStats != null) {
+ // Only count recency for apps that weren't the caller
+ // since the caller is always the most recent.
+ // Persistent processes muck this up, so omit them too.
+ if (!target.name.getPackageName().equals(mReferrerPackage)
+ && !isPersistentProcess(target)) {
+ final long lastTimeUsed = pkStats.getLastTimeUsed();
+ scoredTarget.lastTimeUsed = lastTimeUsed;
+ if (lastTimeUsed > mostRecentlyUsedTime) {
+ mostRecentlyUsedTime = lastTimeUsed;
+ }
+ }
+ final long timeSpent = pkStats.getTotalTimeInForeground();
+ scoredTarget.timeSpent = timeSpent;
+ if (timeSpent > mostTimeSpent) {
+ mostTimeSpent = timeSpent;
+ }
+ final int launched = pkStats.mLaunchCount;
+ scoredTarget.launchCount = launched;
+ if (launched > mostLaunched) {
+ mostLaunched = launched;
+ }
+ }
+ }
+
+
+ if (DEBUG) {
+ Log.d(TAG, "compute - mostRecentlyUsedTime: " + mostRecentlyUsedTime
+ + " mostTimeSpent: " + mostTimeSpent
+ + " recentSinceTime: " + recentSinceTime
+ + " mostLaunched: " + mostLaunched);
+ }
+
+ for (ScoredTarget target : mScoredTargets.values()) {
+ final float recency = (float) Math.max(target.lastTimeUsed - recentSinceTime, 0)
+ / (mostRecentlyUsedTime - recentSinceTime);
+ final float recencyScore = recency * recency * RECENCY_MULTIPLIER;
+ final float usageTimeScore = (float) target.timeSpent / mostTimeSpent;
+ final float launchCountScore = (float) target.launchCount / mostLaunched;
+
+ target.score = recencyScore + usageTimeScore + launchCountScore;
+ if (DEBUG) {
+ Log.d(TAG, "Scores: recencyScore: " + recencyScore
+ + " usageTimeScore: " + usageTimeScore
+ + " launchCountScore: " + launchCountScore
+ + " - " + target);
+ }
+ }
+ }
+
+ static boolean isPersistentProcess(ResolvedComponentInfo rci) {
+ if (rci != null && rci.getCount() > 0) {
+ return (rci.getResolveInfoAt(0).activityInfo.applicationInfo.flags &
+ ApplicationInfo.FLAG_PERSISTENT) != 0;
+ }
+ return false;
+ }
+
+ @Override
+ public int compare(ResolvedComponentInfo lhsp, ResolvedComponentInfo rhsp) {
+ final ResolveInfo lhs = lhsp.getResolveInfoAt(0);
+ final ResolveInfo rhs = rhsp.getResolveInfoAt(0);
+
+ // We want to put the one targeted to another user at the end of the dialog.
+ if (lhs.targetUserId != UserHandle.USER_CURRENT) {
+ return 1;
+ }
+
+ if (mHttp) {
+ // Special case: we want filters that match URI paths/schemes to be
+ // ordered before others. This is for the case when opening URIs,
+ // to make native apps go above browsers.
+ final boolean lhsSpecific = ResolverActivity.isSpecificUriMatch(lhs.match);
+ final boolean rhsSpecific = ResolverActivity.isSpecificUriMatch(rhs.match);
+ if (lhsSpecific != rhsSpecific) {
+ return lhsSpecific ? -1 : 1;
+ }
+ }
+
+ if (mStats != null) {
+ final ScoredTarget lhsTarget = mScoredTargets.get(new ComponentName(
+ lhs.activityInfo.packageName, lhs.activityInfo.name));
+ final ScoredTarget rhsTarget = mScoredTargets.get(new ComponentName(
+ rhs.activityInfo.packageName, rhs.activityInfo.name));
+ final float diff = rhsTarget.score - lhsTarget.score;
+
+ if (diff != 0) {
+ return diff > 0 ? 1 : -1;
+ }
+ }
+
+ CharSequence sa = lhs.loadLabel(mPm);
+ if (sa == null) sa = lhs.activityInfo.name;
+ CharSequence sb = rhs.loadLabel(mPm);
+ if (sb == null) sb = rhs.activityInfo.name;
+
+ return mCollator.compare(sa.toString().trim(), sb.toString().trim());
+ }
+
+ static class ScoredTarget {
+ public final ComponentInfo componentInfo;
+ public float score;
+ public long lastTimeUsed;
+ public long timeSpent;
+ public long launchCount;
+
+ public ScoredTarget(ComponentInfo ci) {
+ componentInfo = ci;
+ }
+
+ @Override
+ public String toString() {
+ return "ScoredTarget{" + componentInfo
+ + " score: " + score
+ + " lastTimeUsed: " + lastTimeUsed
+ + " timeSpent: " + timeSpent
+ + " launchCount: " + launchCount
+ + "}";
+ }
+ }
+}
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 087db78..07d1fc8 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -4634,7 +4634,7 @@
@Override
public void noteWifiBatchedScanStartedLocked(int csph, long elapsedRealtimeMs) {
int bin = 0;
- while (csph > 8 && bin < NUM_WIFI_BATCHED_SCAN_BINS) {
+ while (csph > 8 && bin < NUM_WIFI_BATCHED_SCAN_BINS-1) {
csph = csph >> 3;
bin++;
}
diff --git a/core/java/com/android/internal/view/menu/ActionMenuItem.java b/core/java/com/android/internal/view/menu/ActionMenuItem.java
index 00af401..ed676bb 100644
--- a/core/java/com/android/internal/view/menu/ActionMenuItem.java
+++ b/core/java/com/android/internal/view/menu/ActionMenuItem.java
@@ -18,8 +18,6 @@
import android.content.Context;
import android.content.Intent;
-import android.content.res.ColorStateList;
-import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
import android.view.ActionProvider;
import android.view.ContextMenu.ContextMenuInfo;
@@ -44,7 +42,6 @@
private Drawable mIconDrawable;
private int mIconResId = NO_ICON;
- private TintInfo mIconTintInfo;
private Context mContext;
@@ -161,14 +158,12 @@
public MenuItem setIcon(Drawable icon) {
mIconDrawable = icon;
mIconResId = NO_ICON;
- applyIconTint();
return this;
}
public MenuItem setIcon(int iconRes) {
mIconResId = iconRes;
mIconDrawable = mContext.getDrawable(iconRes);
- applyIconTint();
return this;
}
@@ -279,48 +274,4 @@
// No need to save the listener; ActionMenuItem does not support collapsing items.
return this;
}
-
- @Override
- public MenuItem setIconTintList(ColorStateList tintList) {
- if (mIconTintInfo == null) {
- mIconTintInfo = new TintInfo();
- }
- mIconTintInfo.mTintList = tintList;
- mIconTintInfo.mHasTintList = true;
- applyIconTint();
- return this;
- }
-
- @Override
- public MenuItem setIconTintMode(PorterDuff.Mode tintMode) {
- if (mIconTintInfo == null) {
- mIconTintInfo = new TintInfo();
- }
- mIconTintInfo.mTintMode = tintMode;
- mIconTintInfo.mHasTintMode = true;
- applyIconTint();
- return this;
- }
-
- private void applyIconTint() {
- final TintInfo tintInfo = mIconTintInfo;
- if (mIconDrawable != null && tintInfo != null) {
- if (tintInfo.mHasTintList || tintInfo.mHasTintMode) {
- mIconDrawable = mIconDrawable.mutate();
- if (tintInfo.mHasTintList) {
- mIconDrawable.setTintList(tintInfo.mTintList);
- }
- if (tintInfo.mHasTintMode) {
- mIconDrawable.setTintMode(tintInfo.mTintMode);
- }
- }
- }
- }
-
- private static class TintInfo {
- ColorStateList mTintList;
- PorterDuff.Mode mTintMode;
- boolean mHasTintMode;
- boolean mHasTintList;
- }
}
diff --git a/core/java/com/android/internal/view/menu/MenuItemImpl.java b/core/java/com/android/internal/view/menu/MenuItemImpl.java
index ef4e546..3b1f20d 100644
--- a/core/java/com/android/internal/view/menu/MenuItemImpl.java
+++ b/core/java/com/android/internal/view/menu/MenuItemImpl.java
@@ -21,8 +21,6 @@
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
-import android.content.res.ColorStateList;
-import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
import android.util.Log;
import android.view.ActionProvider;
@@ -62,11 +60,6 @@
* needed).
*/
private int mIconResId = NO_ICON;
-
- /**
- * Tint info for the icon
- */
- private TintInfo mIconTintInfo;
/** The menu to which this item belongs */
private MenuBuilder mMenu;
@@ -392,10 +385,10 @@
}
if (mIconResId != NO_ICON) {
- mIconDrawable = mMenu.getContext().getDrawable(mIconResId);
+ Drawable icon = mMenu.getContext().getDrawable(mIconResId);
mIconResId = NO_ICON;
- applyIconTint();
- return mIconDrawable;
+ mIconDrawable = icon;
+ return icon;
}
return null;
@@ -404,7 +397,6 @@
public MenuItem setIcon(Drawable icon) {
mIconResId = NO_ICON;
mIconDrawable = icon;
- applyIconTint();
mMenu.onItemsChanged(false);
return this;
@@ -678,48 +670,4 @@
public boolean isActionViewExpanded() {
return mIsActionViewExpanded;
}
-
- @Override
- public MenuItem setIconTintList(ColorStateList tintList) {
- if (mIconTintInfo == null) {
- mIconTintInfo = new TintInfo();
- }
- mIconTintInfo.mTintList = tintList;
- mIconTintInfo.mHasTintList = true;
- applyIconTint();
- return this;
- }
-
- @Override
- public MenuItem setIconTintMode(PorterDuff.Mode tintMode) {
- if (mIconTintInfo == null) {
- mIconTintInfo = new TintInfo();
- }
- mIconTintInfo.mTintMode = tintMode;
- mIconTintInfo.mHasTintMode = true;
- applyIconTint();
- return this;
- }
-
- private void applyIconTint() {
- final TintInfo tintInfo = mIconTintInfo;
- if (mIconDrawable != null && tintInfo != null) {
- if (tintInfo.mHasTintList || tintInfo.mHasTintMode) {
- mIconDrawable = mIconDrawable.mutate();
- if (tintInfo.mHasTintList) {
- mIconDrawable.setTintList(tintInfo.mTintList);
- }
- if (tintInfo.mHasTintMode) {
- mIconDrawable.setTintMode(tintInfo.mTintMode);
- }
- }
- }
- }
-
- private static class TintInfo {
- ColorStateList mTintList;
- PorterDuff.Mode mTintMode;
- boolean mHasTintMode;
- boolean mHasTintList;
- }
}
diff --git a/core/java/com/android/internal/widget/ActionBarContextView.java b/core/java/com/android/internal/widget/ActionBarContextView.java
index 106272b..c5d3290 100644
--- a/core/java/com/android/internal/widget/ActionBarContextView.java
+++ b/core/java/com/android/internal/widget/ActionBarContextView.java
@@ -367,7 +367,7 @@
if (mTitleLayout != null && mCustomView == null) {
if (mTitleOptional) {
- final int titleWidthSpec = MeasureSpec.makeMeasureSpec(contentWidth,
+ final int titleWidthSpec = MeasureSpec.makeSafeMeasureSpec(contentWidth,
MeasureSpec.UNSPECIFIED);
mTitleLayout.measure(titleWidthSpec, childSpecHeight);
final int titleWidth = mTitleLayout.getMeasuredWidth();
diff --git a/core/java/com/android/internal/widget/FloatingToolbar.java b/core/java/com/android/internal/widget/FloatingToolbar.java
index c77d614..2d0989f 100644
--- a/core/java/com/android/internal/widget/FloatingToolbar.java
+++ b/core/java/com/android/internal/widget/FloatingToolbar.java
@@ -361,7 +361,7 @@
mParent = Preconditions.checkNotNull(parent);
mContentContainer = createContentContainer(parent.getContext());
mPopupWindow = createPopupWindow(mContentContainer);
- mDismissAnimation = createShrinkFadeOutFromBottomAnimation(
+ mDismissAnimation = createExitAnimation(
mContentContainer,
150, // startDelay
new AnimatorListenerAdapter() {
@@ -371,7 +371,7 @@
mContentContainer.removeAllViews();
}
});
- mHideAnimation = createShrinkFadeOutFromBottomAnimation(
+ mHideAnimation = createExitAnimation(
mContentContainer,
0, // startDelay
new AnimatorListenerAdapter() {
@@ -561,7 +561,7 @@
* Performs the "show" animation on the floating popup.
*/
private void runShowAnimation() {
- createGrowFadeInFromBottom(mContentContainer).start();
+ createEnterAnimation(mContentContainer).start();
}
/**
@@ -1369,38 +1369,35 @@
}
/**
- * Creates a "grow and fade in from the bottom" animation for the specified view.
+ * Creates an "appear" animation for the specified view.
*
* @param view The view to animate
*/
- private static AnimatorSet createGrowFadeInFromBottom(View view) {
- AnimatorSet growFadeInFromBottomAnimation = new AnimatorSet();
- growFadeInFromBottomAnimation.playTogether(
- ObjectAnimator.ofFloat(view, View.SCALE_X, 0.5f, 1).setDuration(125),
- ObjectAnimator.ofFloat(view, View.SCALE_Y, 0.5f, 1).setDuration(125),
- ObjectAnimator.ofFloat(view, View.ALPHA, 0, 1).setDuration(75),
+ private static AnimatorSet createEnterAnimation(View view) {
+ AnimatorSet animation = new AnimatorSet();
+ animation.playTogether(
+ ObjectAnimator.ofFloat(view, View.ALPHA, 0, 1).setDuration(200),
// Make sure that view.x is always fixed throughout the duration of this animation.
ObjectAnimator.ofFloat(view, View.X, view.getX(), view.getX()));
- growFadeInFromBottomAnimation.setStartDelay(50);
- return growFadeInFromBottomAnimation;
+ animation.setStartDelay(50);
+ return animation;
}
/**
- * Creates a "shrink and fade out from bottom" animation for the specified view.
+ * Creates a "disappear" animation for the specified view.
*
* @param view The view to animate
* @param startDelay The start delay of the animation
* @param listener The animation listener
*/
- private static AnimatorSet createShrinkFadeOutFromBottomAnimation(
+ private static AnimatorSet createExitAnimation(
View view, int startDelay, Animator.AnimatorListener listener) {
- AnimatorSet shrinkFadeOutFromBottomAnimation = new AnimatorSet();
- shrinkFadeOutFromBottomAnimation.playTogether(
- ObjectAnimator.ofFloat(view, View.SCALE_Y, 1, 0.5f).setDuration(125),
- ObjectAnimator.ofFloat(view, View.ALPHA, 1, 0).setDuration(75));
- shrinkFadeOutFromBottomAnimation.setStartDelay(startDelay);
- shrinkFadeOutFromBottomAnimation.addListener(listener);
- return shrinkFadeOutFromBottomAnimation;
+ AnimatorSet animation = new AnimatorSet();
+ animation.playTogether(
+ ObjectAnimator.ofFloat(view, View.ALPHA, 1, 0).setDuration(200));
+ animation.setStartDelay(startDelay);
+ animation.addListener(listener);
+ return animation;
}
private static int getEstimatedToolbarHeight(Context context) {
diff --git a/core/java/com/android/internal/widget/SlidingTab.java b/core/java/com/android/internal/widget/SlidingTab.java
index 0066ed0..79adada 100644
--- a/core/java/com/android/internal/widget/SlidingTab.java
+++ b/core/java/com/android/internal/widget/SlidingTab.java
@@ -403,10 +403,10 @@
public void measure(int widthMeasureSpec, int heightMeasureSpec) {
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
- tab.measure(View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.UNSPECIFIED),
- View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.UNSPECIFIED));
- text.measure(View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.UNSPECIFIED),
- View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.UNSPECIFIED));
+ tab.measure(View.MeasureSpec.makeSafeMeasureSpec(width, View.MeasureSpec.UNSPECIFIED),
+ View.MeasureSpec.makeSafeMeasureSpec(height, View.MeasureSpec.UNSPECIFIED));
+ text.measure(View.MeasureSpec.makeSafeMeasureSpec(width, View.MeasureSpec.UNSPECIFIED),
+ View.MeasureSpec.makeSafeMeasureSpec(height, View.MeasureSpec.UNSPECIFIED));
}
/**
diff --git a/core/jni/android/graphics/Shader.cpp b/core/jni/android/graphics/Shader.cpp
index d0f7591..ad3a5e2 100644
--- a/core/jni/android/graphics/Shader.cpp
+++ b/core/jni/android/graphics/Shader.cpp
@@ -84,7 +84,11 @@
jint tileModeX, jint tileModeY)
{
SkBitmap bitmap;
- GraphicsJNI::getSkBitmap(env, jbitmap, &bitmap);
+ if (jbitmap) {
+ // Only pass a valid SkBitmap object to the constructor if the Bitmap exists. Otherwise,
+ // we'll pass an empty SkBitmap to avoid crashing/excepting for compatibility.
+ GraphicsJNI::getSkBitmap(env, jbitmap, &bitmap);
+ }
SkShader* s = SkShader::CreateBitmapShader(bitmap,
(SkShader::TileMode)tileModeX,
(SkShader::TileMode)tileModeY);
diff --git a/core/jni/android/graphics/SurfaceTexture.cpp b/core/jni/android/graphics/SurfaceTexture.cpp
index 08d61d5..b9e48a0 100644
--- a/core/jni/android/graphics/SurfaceTexture.cpp
+++ b/core/jni/android/graphics/SurfaceTexture.cpp
@@ -49,6 +49,12 @@
};
static fields_t fields;
+// Get an ID that's unique within this process.
+static int32_t createProcessUniqueId() {
+ static volatile int32_t globalCounter = 0;
+ return android_atomic_inc(&globalCounter);
+}
+
// ----------------------------------------------------------------------------
static void SurfaceTexture_setSurfaceTexture(JNIEnv* env, jobject thiz,
@@ -253,6 +259,11 @@
"Unable to create native SurfaceTexture");
return;
}
+ surfaceTexture->setName(String8::format("SurfaceTexture-%d-%d-%d",
+ (isDetached ? 0 : texName),
+ getpid(),
+ createProcessUniqueId()));
+
SurfaceTexture_setSurfaceTexture(env, thiz, surfaceTexture);
SurfaceTexture_setProducer(env, thiz, producer);
diff --git a/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp b/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp
index afdfd8f..5bef653 100644
--- a/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp
+++ b/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp
@@ -689,6 +689,23 @@
return NO_ERROR;
}
+static jint LegacyCameraDevice_nativeSetScalingMode(JNIEnv* env, jobject thiz, jobject surface,
+ jint mode) {
+ ALOGV("nativeSetScalingMode");
+ sp<ANativeWindow> anw;
+ if ((anw = getNativeWindow(env, surface)) == NULL) {
+ ALOGE("%s: Could not retrieve native window from surface.", __FUNCTION__);
+ return BAD_VALUE;
+ }
+ status_t err = NO_ERROR;
+ if ((err = native_window_set_scaling_mode(anw.get(), static_cast<int>(mode))) != NO_ERROR) {
+ ALOGE("%s: Unable to set surface scaling mode, error %s (%d)", __FUNCTION__,
+ strerror(-err), err);
+ return err;
+ }
+ return NO_ERROR;
+}
+
static jint LegacyCameraDevice_nativeGetJpegFooterSize(JNIEnv* env, jobject thiz) {
ALOGV("nativeGetJpegFooterSize");
return static_cast<jint>(sizeof(struct camera3_jpeg_blob));
@@ -733,6 +750,9 @@
{ "nativeDetectSurfaceUsageFlags",
"(Landroid/view/Surface;)I",
(void *)LegacyCameraDevice_nativeDetectSurfaceUsageFlags },
+ { "nativeSetScalingMode",
+ "(Landroid/view/Surface;I)I",
+ (void *)LegacyCameraDevice_nativeSetScalingMode },
};
// Get all the required offsets in java class and register native functions
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 709de9e..8a79f5a 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -90,7 +90,6 @@
<protected-broadcast android:name="android.app.action.ENTER_DESK_MODE" />
<protected-broadcast android:name="android.app.action.EXIT_DESK_MODE" />
<protected-broadcast android:name="android.app.action.NEXT_ALARM_CLOCK_CHANGED" />
- <protected-broadcast android:name="android.app.action.SEND_DEVICE_INITIALIZER_STATUS" />
<protected-broadcast android:name="android.appwidget.action.APPWIDGET_UPDATE_OPTIONS" />
<protected-broadcast android:name="android.appwidget.action.APPWIDGET_DELETED" />
@@ -454,6 +453,63 @@
android:description="@string/permdesc_readCellBroadcasts"
android:protectionLevel="dangerous" />
+ <!-- ====================================================================== -->
+ <!-- Permissions for accessing external storage -->
+ <!-- ====================================================================== -->
+ <eat-comment />
+
+ <!-- Used for runtime permissions related to the shared external storage. -->
+ <permission-group android:name="android.permission-group.STORAGE"
+ android:icon="@drawable/perm_group_storage"
+ android:label="@string/permgrouplab_storage"
+ android:description="@string/permgroupdesc_storage"
+ android:priority="900" />
+
+ <!-- Allows an application to read from external storage.
+ <p>Any app that declares the {@link #WRITE_EXTERNAL_STORAGE} permission is implicitly
+ granted this permission.</p>
+ <p>This permission is enforced starting in API level 19. Before API level 19, this
+ permission is not enforced and all apps still have access to read from external storage.
+ You can test your app with the permission enforced by enabling <em>Protect USB
+ storage</em> under Developer options in the Settings app on a device running Android 4.1 or
+ higher.</p>
+ <p>Also starting in API level 19, this permission is <em>not</em> required to
+ read/write files in your application-specific directories returned by
+ {@link android.content.Context#getExternalFilesDir} and
+ {@link android.content.Context#getExternalCacheDir}.
+ <p class="note"><strong>Note:</strong> If <em>both</em> your <a
+ href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#min">{@code
+ minSdkVersion}</a> and <a
+ href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code
+ targetSdkVersion}</a> values are set to 3 or lower, the system implicitly
+ grants your app this permission. If you don't need this permission, be sure your <a
+ href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code
+ targetSdkVersion}</a> is 4 or higher.-->
+ <permission android:name="android.permission.READ_EXTERNAL_STORAGE"
+ android:permissionGroup="android.permission-group.STORAGE"
+ android:label="@string/permlab_sdcardRead"
+ android:description="@string/permdesc_sdcardRead"
+ android:protectionLevel="normal" />
+
+ <!-- Allows an application to write to external storage.
+ <p class="note"><strong>Note:</strong> If <em>both</em> your <a
+ href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#min">{@code
+ minSdkVersion}</a> and <a
+ href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code
+ targetSdkVersion}</a> values are set to 3 or lower, the system implicitly
+ grants your app this permission. If you don't need this permission, be sure your <a
+ href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code
+ targetSdkVersion}</a> is 4 or higher.
+ <p>Starting in API level 19, this permission is <em>not</em> required to
+ read/write files in your application-specific directories returned by
+ {@link android.content.Context#getExternalFilesDir} and
+ {@link android.content.Context#getExternalCacheDir}. -->
+ <permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
+ android:permissionGroup="android.permission-group.STORAGE"
+ android:label="@string/permlab_sdcardWrite"
+ android:description="@string/permdesc_sdcardWrite"
+ android:protectionLevel="dangerous" />
+
<!-- =============================================================== -->
<!-- Permissions for accessing social info -->
<!-- =============================================================== -->
@@ -866,7 +922,7 @@
<permission android:name="android.permission.CHANGE_WIFI_STATE"
android:description="@string/permdesc_changeWifiState"
android:label="@string/permlab_changeWifiState"
- android:protectionLevel="dangerous" />
+ android:protectionLevel="normal" />
<!-- @SystemApi @hide Allows applications to read Wi-Fi credential.
<p>Not for use by third-party applications. -->
@@ -896,7 +952,7 @@
<permission android:name="android.permission.CHANGE_WIMAX_STATE"
android:description="@string/permdesc_changeWimaxState"
android:label="@string/permlab_changeWimaxState"
- android:protectionLevel="dangerous" />
+ android:protectionLevel="normal" />
<!--@SystemApi Allows applications to the the local WiFi and Bluetooth MAC address.
@hide
@@ -913,13 +969,13 @@
<permission android:name="android.permission.BLUETOOTH"
android:description="@string/permdesc_bluetooth"
android:label="@string/permlab_bluetooth"
- android:protectionLevel="dangerous" />
+ android:protectionLevel="normal" />
<!-- Allows applications to discover and pair bluetooth devices -->
<permission android:name="android.permission.BLUETOOTH_ADMIN"
android:description="@string/permdesc_bluetoothAdmin"
android:label="@string/permlab_bluetoothAdmin"
- android:protectionLevel="dangerous" />
+ android:protectionLevel="normal" />
<!-- @SystemApi Allows applications to pair bluetooth devices without user interaction, and to
allow or disallow phonebook access or message access.
@@ -981,33 +1037,11 @@
<!-- Allows access to the list of accounts in the Accounts Service -->
<permission android:name="android.permission.GET_ACCOUNTS"
- android:permissionGroup="android.permission-group.ACCOUNTS"
+ android:permissionGroup="android.permission-group.CONTACTS"
android:protectionLevel="normal"
android:description="@string/permdesc_getAccounts"
android:label="@string/permlab_getAccounts" />
- <!-- Allows an application to act as an AccountAuthenticator for
- the AccountManager -->
- <permission android:name="android.permission.AUTHENTICATE_ACCOUNTS"
- android:permissionGroup="android.permission-group.ACCOUNTS"
- android:protectionLevel="dangerous"
- android:label="@string/permlab_authenticateAccounts"
- android:description="@string/permdesc_authenticateAccounts" />
-
- <!-- Allows an application to request authtokens from the AccountManager -->
- <permission android:name="android.permission.USE_CREDENTIALS"
- android:permissionGroup="android.permission-group.ACCOUNTS"
- android:protectionLevel="dangerous"
- android:label="@string/permlab_useCredentials"
- android:description="@string/permdesc_useCredentials" />
-
- <!-- Allows an application to manage the list of accounts in the AccountManager -->
- <permission android:name="android.permission.MANAGE_ACCOUNTS"
- android:permissionGroup="android.permission-group.ACCOUNTS"
- android:protectionLevel="dangerous"
- android:label="@string/permlab_manageAccounts"
- android:description="@string/permdesc_manageAccounts" />
-
<!-- @SystemApi Allows applications to call into AccountAuthenticators.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.ACCOUNT_MANAGER"
@@ -1023,7 +1057,7 @@
<permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE"
android:description="@string/permdesc_changeWifiMulticastState"
android:label="@string/permlab_changeWifiMulticastState"
- android:protectionLevel="dangerous" />
+ android:protectionLevel="normal" />
<!-- Allows access to the vibrator -->
<permission android:name="android.permission.VIBRATE"
@@ -1205,60 +1239,21 @@
<permission android:name="android.permission.BIND_TELECOM_CONNECTION_SERVICE"
android:protectionLevel="system|signature" />
-
<!-- @SystemApi Allows an application to control the in-call experience.
@hide -->
<permission android:name="android.permission.CONTROL_INCALL_EXPERIENCE"
android:protectionLevel="system|signature" />
+ <!-- Allows an application to receive STK related commands.
+ @hide -->
+ <permission android:name="android.permission.RECEIVE_STK_COMMANDS"
+ android:protectionLevel="system|signature" />
+
<!-- ================================== -->
<!-- Permissions for sdcard interaction -->
<!-- ================================== -->
<eat-comment />
- <!-- Allows an application to read from external storage.
- <p>Any app that declares the {@link #WRITE_EXTERNAL_STORAGE} permission is implicitly
- granted this permission.</p>
- <p>This permission is enforced starting in API level 19. Before API level 19, this
- permission is not enforced and all apps still have access to read from external storage.
- You can test your app with the permission enforced by enabling <em>Protect USB
- storage</em> under Developer options in the Settings app on a device running Android 4.1 or
- higher.</p>
- <p>Also starting in API level 19, this permission is <em>not</em> required to
- read/write files in your application-specific directories returned by
- {@link android.content.Context#getExternalFilesDir} and
- {@link android.content.Context#getExternalCacheDir}.
- <p class="note"><strong>Note:</strong> If <em>both</em> your <a
- href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#min">{@code
- minSdkVersion}</a> and <a
- href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code
- targetSdkVersion}</a> values are set to 3 or lower, the system implicitly
- grants your app this permission. If you don't need this permission, be sure your <a
- href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code
- targetSdkVersion}</a> is 4 or higher.-->
- <permission android:name="android.permission.READ_EXTERNAL_STORAGE"
- android:label="@string/permlab_sdcardRead"
- android:description="@string/permdesc_sdcardRead"
- android:protectionLevel="normal" />
-
- <!-- Allows an application to write to external storage.
- <p class="note"><strong>Note:</strong> If <em>both</em> your <a
- href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#min">{@code
- minSdkVersion}</a> and <a
- href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code
- targetSdkVersion}</a> values are set to 3 or lower, the system implicitly
- grants your app this permission. If you don't need this permission, be sure your <a
- href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code
- targetSdkVersion}</a> is 4 or higher.
- <p>Starting in API level 19, this permission is <em>not</em> required to
- read/write files in your application-specific directories returned by
- {@link android.content.Context#getExternalFilesDir} and
- {@link android.content.Context#getExternalCacheDir}. -->
- <permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
- android:label="@string/permlab_sdcardWrite"
- android:description="@string/permdesc_sdcardWrite"
- android:protectionLevel="normal" />
-
<!-- @SystemApi Allows an application to write to internal media storage
@hide -->
<permission android:name="android.permission.WRITE_MEDIA_STORAGE"
@@ -1496,7 +1491,7 @@
<permission android:name="android.permission.WRITE_SETTINGS"
android:label="@string/permlab_writeSettings"
android:description="@string/permdesc_writeSettings"
- android:protectionLevel="normal" />
+ android:protectionLevel="dangerous" />
<!-- @SystemApi Allows an application to modify the Google service map.
<p>Not for use by third-party applications. -->
@@ -1603,24 +1598,6 @@
<permission android:name="android.permission.WRITE_APN_SETTINGS"
android:protectionLevel="signature|system" />
- <!-- Allows an application to allow access the subscribed feeds ContentProvider.
- @hide
- @removed
- -->
- <permission android:name="android.permission.SUBSCRIBED_FEEDS_READ"
- android:label="@string/permlab_subscribedFeedsRead"
- android:description="@string/permdesc_subscribedFeedsRead"
- android:protectionLevel="normal" />
-
- <!--
- @hide
- @removed
- -->
- <permission android:name="android.permission.SUBSCRIBED_FEEDS_WRITE"
- android:label="@string/permlab_subscribedFeedsWrite"
- android:description="@string/permdesc_subscribedFeedsWrite"
- android:protectionLevel="dangerous" />
-
<!-- Allows applications to change network connectivity state -->
<permission android:name="android.permission.CHANGE_NETWORK_STATE"
android:description="@string/permdesc_changeNetworkState"
@@ -1630,7 +1607,7 @@
<!-- Allows an application to clear the caches of all installed
applications on the device. -->
<permission android:name="android.permission.CLEAR_APP_CACHE"
- android:protectionLevel="dangerous" />
+ android:protectionLevel="signatureOrSystem" />
<!-- @SystemApi Allows an application to use any media decoder when decoding for playback
@hide -->
@@ -1979,6 +1956,10 @@
<permission android:name="android.permission.GRANT_REVOKE_PERMISSIONS"
android:protectionLevel="signature" />
+ <!-- @hide Allows an application to observe permission changes. -->
+ <permission android:name="android.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS"
+ android:protectionLevel="signatureOrSystem" />
+
<!-- Allows an application to use SurfaceFlinger's low level features.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.ACCESS_SURFACE_FLINGER"
@@ -2446,11 +2427,6 @@
<permission android:name="android.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS"
android:protectionLevel="signature" />
- <!-- Allows receiving status updates from a device initializer.
- @hide Not for use by third-party applications. -->
- <permission android:name="android.permission.RECEIVE_DEVICE_INITIALIZER_STATUS"
- android:protectionLevel="signature" />
-
<!-- The system process that is allowed to bind to services in carrier apps will
have this permission. Carrier apps should use this permission to protect
their services that only the system is allowed to bind to. -->
diff --git a/core/res/res/drawable-hdpi/ic_fingerprint_light_overlay.png b/core/res/res/drawable-hdpi/ic_fingerprint_light_overlay.png
deleted file mode 100644
index 0253c77..0000000
--- a/core/res/res/drawable-hdpi/ic_fingerprint_light_overlay.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_fingerprint_light_overlay.png b/core/res/res/drawable-mdpi/ic_fingerprint_light_overlay.png
deleted file mode 100644
index 5a1c61e..0000000
--- a/core/res/res/drawable-mdpi/ic_fingerprint_light_overlay.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_fingerprint_light_overlay.png b/core/res/res/drawable-xhdpi/ic_fingerprint_light_overlay.png
deleted file mode 100644
index 5f0c362..0000000
--- a/core/res/res/drawable-xhdpi/ic_fingerprint_light_overlay.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_fingerprint_light_overlay.png b/core/res/res/drawable-xxhdpi/ic_fingerprint_light_overlay.png
deleted file mode 100644
index f4cf906..0000000
--- a/core/res/res/drawable-xxhdpi/ic_fingerprint_light_overlay.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_fingerprint_light_overlay.png b/core/res/res/drawable-xxxhdpi/ic_fingerprint_light_overlay.png
deleted file mode 100644
index dcdbed9..0000000
--- a/core/res/res/drawable-xxxhdpi/ic_fingerprint_light_overlay.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/floating_popup_background.xml b/core/res/res/drawable/floating_popup_background_dark.xml
similarity index 87%
copy from core/res/res/drawable/floating_popup_background.xml
copy to core/res/res/drawable/floating_popup_background_dark.xml
index b6700b3..ded1137 100644
--- a/core/res/res/drawable/floating_popup_background.xml
+++ b/core/res/res/drawable/floating_popup_background_dark.xml
@@ -16,8 +16,8 @@
*/
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
- android:shape="rectangle">
- <solid android:color="?attr/colorBackgroundFloating" />
+ android:shape="rectangle">
+ <solid android:color="@color/background_floating_material_dark" />
<corners android:radius="2dp" />
</shape>
diff --git a/core/res/res/drawable/floating_popup_background.xml b/core/res/res/drawable/floating_popup_background_light.xml
similarity index 91%
rename from core/res/res/drawable/floating_popup_background.xml
rename to core/res/res/drawable/floating_popup_background_light.xml
index b6700b3..9c7a886 100644
--- a/core/res/res/drawable/floating_popup_background.xml
+++ b/core/res/res/drawable/floating_popup_background_light.xml
@@ -17,7 +17,7 @@
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
- <solid android:color="?attr/colorBackgroundFloating" />
+ <solid android:color="@color/background_floating_material_light" />
<corners android:radius="2dp" />
</shape>
diff --git a/core/res/res/drawable/ic_ab_back_material_dark.xml b/core/res/res/drawable/ic_ab_back_material_dark.xml
new file mode 100644
index 0000000..7cdd139
--- /dev/null
+++ b/core/res/res/drawable/ic_ab_back_material_dark.xml
@@ -0,0 +1,27 @@
+<?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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"
+ android:autoMirrored="true"
+ android:tint="@color/secondary_text_material_dark">
+ <path
+ android:pathData="M20,11L7.8,11l5.6,-5.6L12,4l-8,8l8,8l1.4,-1.4L7.8,13L20,13L20,11z"
+ android:fillColor="@color/white"/>
+</vector>
diff --git a/core/res/res/drawable/ic_ab_back_material_light.xml b/core/res/res/drawable/ic_ab_back_material_light.xml
new file mode 100644
index 0000000..65dab81
--- /dev/null
+++ b/core/res/res/drawable/ic_ab_back_material_light.xml
@@ -0,0 +1,27 @@
+<?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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"
+ android:autoMirrored="true"
+ android:tint="@color/secondary_text_material_light">
+ <path
+ android:pathData="M20,11L7.8,11l5.6,-5.6L12,4l-8,8l8,8l1.4,-1.4L7.8,13L20,13L20,11z"
+ android:fillColor="@color/white"/>
+</vector>
diff --git a/core/res/res/drawable/ic_fingerprint.xml b/core/res/res/drawable/ic_fingerprint.xml
new file mode 100644
index 0000000..c19f00f
--- /dev/null
+++ b/core/res/res/drawable/ic_fingerprint.xml
@@ -0,0 +1,37 @@
+<!--
+ ~ Copyright (C) 2015 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24.0dp"
+ android:height="24.0dp"
+ android:tint="?attr/colorControlNormal"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#ffffff"
+ android:pathData="M17.5,4.47c-0.08,0.0 -0.16,-0.02 -0.24,-0.06C15.45,3.42 13.88,3.0 12.01,3.0c-1.87,0.0 -3.64,0.47 -5.25,1.4C6.52,4.54 6.22,4.46 6.08,4.22C5.94,3.98 6.02,3.67 6.26,3.54C8.03,2.52 9.96,2.0 12.01,2.0c2.02,0.0 3.79,0.47 5.73,1.53c0.24,0.13 0.33,0.44 0.2,0.68C17.85,4.38 17.68,4.47 17.5,4.47z"/>
+ <path
+ android:fillColor="#ffffff"
+ android:pathData="M3.95,9.72c-0.1,0.0 -0.19,-0.03 -0.28,-0.08C3.44,9.48 3.38,9.17 3.54,8.94c0.94,-1.4 2.14,-2.5 3.56,-3.28c2.99,-1.63 6.82,-1.63 9.81,-0.01c1.42,0.77 2.61,1.87 3.56,3.26c0.15,0.23 0.09,0.54 -0.13,0.69c-0.23,0.16 -0.54,0.09 -0.69,-0.13c-0.85,-1.26 -1.93,-2.24 -3.2,-2.94c-2.7,-1.47 -6.16,-1.46 -8.86,0.01C6.3,7.24 5.22,8.23 4.37,9.5C4.27,9.64 4.11,9.72 3.95,9.72z"/>
+ <path
+ android:fillColor="#ffffff"
+ android:pathData="M9.86,21.79c-0.13,0.0 -0.27,-0.05 -0.36,-0.16c-0.82,-0.87 -1.26,-1.43 -1.9,-2.63c-0.65,-1.23 -1.0,-2.73 -1.0,-4.33c0.0,-2.97 2.42,-5.39 5.39,-5.39s5.39,2.42 5.39,5.39c0.0,0.28 -0.22,0.5 -0.5,0.5s-0.5,-0.22 -0.5,-0.5c0.0,-2.42 -1.97,-4.39 -4.39,-4.39S7.6,12.24 7.6,14.66c0.0,1.44 0.3,2.78 0.88,3.86c0.61,1.15 1.02,1.64 1.75,2.42c0.19,0.2 0.18,0.52 -0.02,0.71C10.11,21.74 9.98,21.79 9.86,21.79z"/>
+ <path
+ android:fillColor="#ffffff"
+ android:pathData="M16.7,19.94c-1.14,0.0 -2.13,-0.3 -2.96,-0.89c-1.41,-1.01 -2.25,-2.65 -2.25,-4.38c0.0,-0.28 0.22,-0.5 0.5,-0.5s0.5,0.22 0.5,0.5c0.0,1.41 0.69,2.75 1.83,3.57c0.66,0.48 1.44,0.71 2.38,0.71c0.23,0.0 0.6,-0.02 0.98,-0.1c0.27,-0.05 0.53,0.13 0.58,0.4c0.05,0.27 -0.13,0.53 -0.4,0.58C17.3,19.93 16.83,19.94 16.7,19.94z"/>
+ <path
+ android:fillColor="#ffffff"
+ android:pathData="M14.76,22.0c-0.05,0.0 -0.09,-0.01 -0.14,-0.02c-1.51,-0.44 -2.51,-1.03 -3.53,-2.11c-1.32,-1.39 -2.05,-3.24 -2.05,-5.21c0.0,-1.62 1.32,-2.94 2.94,-2.94c1.62,0.0 2.94,1.32 2.94,2.94c0.0,1.07 0.87,1.94 1.94,1.94s1.94,-0.87 1.94,-1.94c0.0,-3.77 -3.07,-6.83 -6.83,-6.83c-2.68,0.0 -5.12,1.58 -6.23,4.02c-0.37,0.81 -0.56,1.76 -0.56,2.81c0.0,0.78 0.07,2.01 0.63,3.61c0.09,0.26 -0.04,0.55 -0.3,0.64c-0.26,0.09 -0.55,-0.04 -0.64,-0.3c-0.46,-1.31 -0.69,-2.6 -0.69,-3.95c0.0,-1.2 0.22,-2.28 0.65,-3.23c1.27,-2.8 4.07,-4.61 7.14,-4.61c4.32,0.0 7.83,3.51 7.83,7.83c0.0,1.62 -1.32,2.94 -2.94,2.94c-1.62,0.0 -2.94,-1.32 -2.94,-2.94c0.0,-1.07 -0.87,-1.94 -1.94,-1.94s-1.94,0.87 -1.94,1.94c0.0,1.71 0.63,3.32 1.77,4.52c0.9,0.95 1.74,1.45 3.08,1.84c0.27,0.08 0.42,0.35 0.34,0.62C15.18,21.86 14.98,22.0 14.76,22.0z"/>
+</vector>
diff --git a/core/res/res/drawable/ic_fingerprint_dark.xml b/core/res/res/drawable/ic_fingerprint_dark.xml
deleted file mode 100644
index 6eb6ada..0000000
--- a/core/res/res/drawable/ic_fingerprint_dark.xml
+++ /dev/null
@@ -1,37 +0,0 @@
-<!--
- ~ Copyright (C) 2015 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License
- -->
-
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="32.0dp"
- android:height="32.0dp"
- android:viewportWidth="32.0"
- android:viewportHeight="32.0">
- <path
- android:fillColor="?attr/colorControlNormal"
- android:pathData="M23.7,5.9c-0.1,0.0 -0.2,0.0 -0.3,-0.1C21.0,4.5 18.6,3.9 16.0,3.9c-2.5,0.0 -4.6,0.6 -6.9,1.9C8.8,6.0 8.3,5.9 8.1,5.5C7.9,5.2 8.0,4.7 8.4,4.5c2.5,-1.4 4.9,-2.1 7.7,-2.1c2.8,0.0 5.4,0.7 8.0,2.1c0.4,0.2 0.5,0.6 0.3,1.0C24.2,5.7 24.0,5.9 23.7,5.9z"/>
- <path
- android:fillColor="?attr/colorControlNormal"
- android:pathData="M5.3,13.2c-0.1,0.0 -0.3,0.0 -0.4,-0.1c-0.3,-0.2 -0.4,-0.7 -0.2,-1.0c1.3,-1.9 2.9,-3.4 4.9,-4.5c4.1,-2.2 9.3,-2.2 13.4,0.0c1.9,1.1 3.6,2.5 4.9,4.4c0.2,0.3 0.1,0.8 -0.2,1.0c-0.3,0.2 -0.8,0.1 -1.0,-0.2c-1.2,-1.7 -2.6,-3.0 -4.3,-4.0c-3.7,-2.0 -8.3,-2.0 -12.0,0.0c-1.7,0.9 -3.2,2.3 -4.3,4.0C5.7,13.1 5.5,13.2 5.3,13.2z"/>
- <path
- android:fillColor="?attr/colorControlNormal"
- android:pathData="M13.3,29.6c-0.2,0.0 -0.4,-0.1 -0.5,-0.2c-1.1,-1.2 -1.7,-2.0 -2.6,-3.6c-0.9,-1.7 -1.4,-3.7 -1.4,-5.9c0.0,-4.1 3.3,-7.4 7.4,-7.4c4.1,0.0 7.4,3.3 7.4,7.4c0.0,0.4 -0.3,0.7 -0.7,0.7s-0.7,-0.3 -0.7,-0.7c0.0,-3.3 -2.7,-5.9 -5.9,-5.9c-3.3,0.0 -5.9,2.7 -5.9,5.9c0.0,2.0 0.4,3.8 1.2,5.2c0.8,1.6 1.4,2.2 2.4,3.3c0.3,0.3 0.3,0.8 0.0,1.0C13.7,29.5 13.5,29.6 13.3,29.6z"/>
- <path
- android:fillColor="?attr/colorControlNormal"
- android:pathData="M22.6,27.1c-1.6,0.0 -2.9,-0.4 -4.1,-1.2c-1.9,-1.4 -3.1,-3.6 -3.1,-6.0c0.0,-0.4 0.3,-0.7 0.7,-0.7s0.7,0.3 0.7,0.7c0.0,1.9 0.9,3.7 2.5,4.8c0.9,0.6 1.9,1.0 3.2,1.0c0.3,0.0 0.8,0.0 1.3,-0.1c0.4,-0.1 0.8,0.2 0.8,0.6c0.1,0.4 -0.2,0.8 -0.6,0.8C23.4,27.1 22.8,27.1 22.6,27.1z"/>
- <path
- android:fillColor="?attr/colorControlNormal"
- android:pathData="M20.0,29.9c-0.1,0.0 -0.1,0.0 -0.2,0.0c-2.1,-0.6 -3.4,-1.4 -4.8,-2.9c-1.8,-1.9 -2.8,-4.4 -2.8,-7.1c0.0,-2.2 1.8,-4.1 4.1,-4.1c2.2,0.0 4.1,1.8 4.1,4.1c0.0,1.4 1.2,2.6 2.6,2.6c1.4,0.0 2.6,-1.2 2.6,-2.6c0.0,-5.1 -4.2,-9.3 -9.3,-9.3c-3.6,0.0 -6.9,2.1 -8.4,5.4C7.3,17.1 7.0,18.4 7.0,19.8c0.0,1.1 0.1,2.7 0.9,4.9c0.1,0.4 -0.1,0.8 -0.4,0.9c-0.4,0.1 -0.8,-0.1 -0.9,-0.4c-0.6,-1.8 -0.9,-3.6 -0.9,-5.4c0.0,-1.6 0.3,-3.1 0.9,-4.4c1.7,-3.8 5.6,-6.3 9.8,-6.3c5.9,0.0 10.7,4.8 10.7,10.7c0.0,2.2 -1.8,4.1 -4.1,4.1s-4.0,-1.8 -4.0,-4.1c0.0,-1.4 -1.2,-2.6 -2.6,-2.6c-1.4,0.0 -2.6,1.2 -2.6,2.6c0.0,2.3 0.9,4.5 2.4,6.1c1.2,1.3 2.4,2.0 4.2,2.5c0.4,0.1 0.6,0.5 0.5,0.9C20.6,29.7 20.3,29.9 20.0,29.9z"/>
-</vector>
diff --git a/core/res/res/drawable/ic_fingerprint_light.xml b/core/res/res/drawable/ic_fingerprint_light.xml
deleted file mode 100644
index 223d16b..0000000
--- a/core/res/res/drawable/ic_fingerprint_light.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<!--
- Copyright (C) 2015 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
- <item>
- <shape android:shape="oval">
- <solid android:color="?attr/colorAccent"/>
- <size
- android:width="40dp"
- android:height="40dp"/>
- </shape>
- </item>
- <item>
- <bitmap android:src="@drawable/ic_fingerprint_light_overlay"/>
- </item>
-</layer-list>
diff --git a/core/res/res/drawable/ic_menu_moreoverflow_material.xml b/core/res/res/drawable/ic_menu_moreoverflow_material.xml
index 502ad69..3f53451 100644
--- a/core/res/res/drawable/ic_menu_moreoverflow_material.xml
+++ b/core/res/res/drawable/ic_menu_moreoverflow_material.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2014 The Android Open Source Project
diff --git a/core/res/res/drawable/ic_menu_moreoverflow_material_dark.xml b/core/res/res/drawable/ic_menu_moreoverflow_material_dark.xml
new file mode 100644
index 0000000..fa350a6
--- /dev/null
+++ b/core/res/res/drawable/ic_menu_moreoverflow_material_dark.xml
@@ -0,0 +1,26 @@
+<?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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"
+ android:tint="@color/secondary_text_material_dark">
+ <path
+ android:pathData="M12,8c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2c-1.1,0 -2,0.9 -2,2S10.9,8 12,8zM12,10c-1.1,0 -2,0.9 -2,2s0.9,2 2,2c1.1,0 2,-0.9 2,-2S13.1,10 12,10zM12,16c-1.1,0 -2,0.9 -2,2s0.9,2 2,2c1.1,0 2,-0.9 2,-2S13.1,16 12,16z"
+ android:fillColor="@color/white"/>
+</vector>
diff --git a/core/res/res/drawable/ic_menu_moreoverflow_material_light.xml b/core/res/res/drawable/ic_menu_moreoverflow_material_light.xml
new file mode 100644
index 0000000..7af234f
--- /dev/null
+++ b/core/res/res/drawable/ic_menu_moreoverflow_material_light.xml
@@ -0,0 +1,26 @@
+<?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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"
+ android:tint="@color/secondary_text_material_light">
+ <path
+ android:pathData="M12,8c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2c-1.1,0 -2,0.9 -2,2S10.9,8 12,8zM12,10c-1.1,0 -2,0.9 -2,2s0.9,2 2,2c1.1,0 2,-0.9 2,-2S13.1,10 12,10zM12,16c-1.1,0 -2,0.9 -2,2s0.9,2 2,2c1.1,0 2,-0.9 2,-2S13.1,16 12,16z"
+ android:fillColor="@color/white"/>
+</vector>
diff --git a/core/res/res/drawable/item_background_borderless_material_dark.xml b/core/res/res/drawable/item_background_borderless_material_dark.xml
new file mode 100644
index 0000000..685c52a
--- /dev/null
+++ b/core/res/res/drawable/item_background_borderless_material_dark.xml
@@ -0,0 +1,18 @@
+<?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="@color/ripple_material_dark" />
diff --git a/core/res/res/drawable/item_background_borderless_material_light.xml b/core/res/res/drawable/item_background_borderless_material_light.xml
new file mode 100644
index 0000000..3ef6674
--- /dev/null
+++ b/core/res/res/drawable/item_background_borderless_material_light.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2015 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+ android:color="@color/ripple_material_light" />
diff --git a/core/res/res/drawable/item_background_material_dark.xml b/core/res/res/drawable/item_background_material_dark.xml
new file mode 100644
index 0000000..06eb531
--- /dev/null
+++ b/core/res/res/drawable/item_background_material_dark.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="@color/ripple_material_dark">
+ <item android:id="@id/mask">
+ <color android:color="@color/white" />
+ </item>
+</ripple>
diff --git a/core/res/res/drawable/item_background_material_light.xml b/core/res/res/drawable/item_background_material_light.xml
new file mode 100644
index 0000000..2f3d157
--- /dev/null
+++ b/core/res/res/drawable/item_background_material_light.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="@color/ripple_material_light">
+ <item android:id="@id/mask">
+ <color android:color="@color/white" />
+ </item>
+</ripple>
diff --git a/core/res/res/drawable/perm_group_storage.xml b/core/res/res/drawable/perm_group_storage.xml
new file mode 100644
index 0000000..11078d3
--- /dev/null
+++ b/core/res/res/drawable/perm_group_storage.xml
@@ -0,0 +1,24 @@
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="48dp"
+ android:height="48dp"
+ android:viewportWidth="48.0"
+ android:viewportHeight="48.0">
+ <path
+ android:pathData="M20,8H8c-2.2,0 -4,1.8 -4,4l0,24c0,2.2 1.8,4 4,4h32c2.2,0 4,-1.8 4,-4V16c0,-2.2 -1.8,-4 -4,-4H24L20,8z"
+ android:fillColor="#FFFFFF"/>
+</vector>
diff --git a/core/res/res/layout/floating_popup_close_overflow_button.xml b/core/res/res/layout/floating_popup_close_overflow_button.xml
index 0dbf7f7..4dae1ae 100644
--- a/core/res/res/layout/floating_popup_close_overflow_button.xml
+++ b/core/res/res/layout/floating_popup_close_overflow_button.xml
@@ -20,6 +20,6 @@
android:layout_height="match_parent"
android:minWidth="@dimen/floating_toolbar_menu_button_minimum_width"
android:minHeight="@dimen/floating_toolbar_height"
- android:src="?android:attr/actionModeCloseDrawable"
+ android:src="?attr/floatingToolbarCloseDrawable"
android:contentDescription="@string/floating_toolbar_close_overflow_description"
- android:background="?attr/selectableItemBackgroundBorderless" />
+ android:background="?attr/floatingToolbarItemBackgroundBorderlessDrawable" />
diff --git a/core/res/res/layout/floating_popup_container.xml b/core/res/res/layout/floating_popup_container.xml
index f37aee15..63dae44 100644
--- a/core/res/res/layout/floating_popup_container.xml
+++ b/core/res/res/layout/floating_popup_container.xml
@@ -24,4 +24,4 @@
android:elevation="2dp"
android:focusable="true"
android:focusableInTouchMode="true"
- android:background="@drawable/floating_popup_background"/>
+ android:background="?attr/floatingToolbarPopupBackgroundDrawable"/>
diff --git a/core/res/res/layout/floating_popup_menu_button.xml b/core/res/res/layout/floating_popup_menu_button.xml
index b549198..1b58ce5 100644
--- a/core/res/res/layout/floating_popup_menu_button.xml
+++ b/core/res/res/layout/floating_popup_menu_button.xml
@@ -30,5 +30,5 @@
android:fontFamily="sans-serif-medium"
android:textSize="@dimen/floating_toolbar_text_size"
android:textAllCaps="true"
- android:textColor="?attr/colorForeground"
- android:background="?attr/selectableItemBackground" />
+ android:textColor="?attr/floatingToolbarForegroundColor"
+ android:background="?attr/floatingToolbarItemBackgroundDrawable" />
diff --git a/core/res/res/layout/floating_popup_menu_image_button.xml b/core/res/res/layout/floating_popup_menu_image_button.xml
index 07eb7a3..1ba7848 100644
--- a/core/res/res/layout/floating_popup_menu_image_button.xml
+++ b/core/res/res/layout/floating_popup_menu_image_button.xml
@@ -32,5 +32,5 @@
android:paddingEnd="@dimen/floating_toolbar_menu_button_side_padding"
android:paddingBottom="@dimen/floating_toolbar_menu_image_button_vertical_padding"
android:scaleType="centerInside"
- android:background="?attr/selectableItemBackground" />
+ android:background="?attr/floatingToolbarItemBackgroundDrawable" />
</LinearLayout>
diff --git a/core/res/res/layout/floating_popup_open_overflow_button.xml b/core/res/res/layout/floating_popup_open_overflow_button.xml
index 3027565..f6a3e8d 100644
--- a/core/res/res/layout/floating_popup_open_overflow_button.xml
+++ b/core/res/res/layout/floating_popup_open_overflow_button.xml
@@ -24,6 +24,6 @@
android:paddingTop="0dp"
android:paddingBottom="0dp"
android:paddingEnd="4dp"
- android:src="@drawable/ic_menu_moreoverflow_material"
+ android:src="?attr/floatingToolbarOpenDrawable"
android:contentDescription="@string/floating_toolbar_open_overflow_description"
- android:background="?attr/selectableItemBackgroundBorderless" />
+ android:background="?attr/floatingToolbarItemBackgroundBorderlessDrawable" />
diff --git a/core/res/res/layout/floating_popup_overflow_list_item.xml b/core/res/res/layout/floating_popup_overflow_list_item.xml
index 2ff45bb..22f4e68 100644
--- a/core/res/res/layout/floating_popup_overflow_list_item.xml
+++ b/core/res/res/layout/floating_popup_overflow_list_item.xml
@@ -31,6 +31,6 @@
android:ellipsize="end"
android:fontFamily="sans-serif-medium"
android:textSize="@dimen/floating_toolbar_text_size"
- android:textColor="?attr/colorForeground"
+ android:textColor="?attr/floatingToolbarForegroundColor"
android:textAllCaps="true" />
diff --git a/core/res/res/layout/media_route_controller_dialog.xml b/core/res/res/layout/media_route_controller_dialog.xml
index 78287e0..0bf70da 100644
--- a/core/res/res/layout/media_route_controller_dialog.xml
+++ b/core/res/res/layout/media_route_controller_dialog.xml
@@ -14,47 +14,50 @@
limitations under the License.
-->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical"
- android:divider="?android:attr/dividerHorizontal"
- android:showDividers="middle">
- <!-- Optional volume slider section. -->
- <LinearLayout android:id="@+id/media_route_volume_layout"
- android:layout_width="match_parent"
- android:layout_height="64dp"
- android:gravity="center_vertical"
- android:padding="8dp"
- android:visibility="gone">
- <ImageView android:layout_width="48dp"
- android:layout_height="48dp"
- android:src="@drawable/ic_audio_vol"
- android:gravity="center"
- android:scaleType="center" />
- <SeekBar android:id="@+id/media_route_volume_slider"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:layout_marginLeft="8dp"
- android:layout_marginRight="8dp" />
- </LinearLayout>
-
- <!-- Optional content view section. -->
- <FrameLayout android:id="@+id/media_route_control_frame"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:visibility="gone" />
-
- <!-- Disconnect button. -->
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
<LinearLayout android:layout_width="match_parent"
android:layout_height="wrap_content"
- style="?attr/buttonBarStyle">
- <Button android:id="@+id/media_route_disconnect_button"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- style="?attr/buttonBarButtonStyle"
- android:gravity="center"
- android:text="@string/media_route_controller_disconnect" />
+ android:orientation="vertical"
+ android:divider="?android:attr/dividerHorizontal"
+ android:showDividers="middle">
+ <!-- Optional volume slider section. -->
+ <LinearLayout android:id="@+id/media_route_volume_layout"
+ android:layout_width="match_parent"
+ android:layout_height="64dp"
+ android:gravity="center_vertical"
+ android:padding="8dp"
+ android:visibility="gone">
+ <ImageView android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:src="@drawable/ic_audio_vol"
+ android:gravity="center"
+ android:scaleType="center" />
+ <SeekBar android:id="@+id/media_route_volume_slider"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:layout_marginLeft="8dp"
+ android:layout_marginRight="8dp" />
+ </LinearLayout>
+
+ <!-- Optional content view section. -->
+ <FrameLayout android:id="@+id/media_route_control_frame"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:visibility="gone" />
+
+ <!-- Disconnect button. -->
+ <LinearLayout android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ style="?attr/buttonBarStyle">
+ <Button android:id="@+id/media_route_disconnect_button"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ style="?attr/buttonBarButtonStyle"
+ android:gravity="center"
+ android:text="@string/media_route_controller_disconnect" />
+ </LinearLayout>
</LinearLayout>
-</LinearLayout>
+</ScrollView>
\ No newline at end of file
diff --git a/core/res/res/layout/preference_dialog_seekbar.xml b/core/res/res/layout/preference_dialog_seekbar.xml
new file mode 100644
index 0000000..4e366c4
--- /dev/null
+++ b/core/res/res/layout/preference_dialog_seekbar.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:gravity="center_horizontal"
+ android:orientation="vertical">
+
+ <ImageView
+ android:id="@+id/icon"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingTop="20dp" />
+
+ <SeekBar
+ android:id="@+id/seekbar"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:padding="20dp" />
+
+</LinearLayout>
diff --git a/core/res/res/layout/preference_dialog_seekbar_material.xml b/core/res/res/layout/preference_dialog_seekbar_material.xml
new file mode 100644
index 0000000..a98a995
--- /dev/null
+++ b/core/res/res/layout/preference_dialog_seekbar_material.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:gravity="center_horizontal"
+ android:orientation="vertical">
+
+ <ImageView
+ android:id="@+id/icon"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingTop="?attr/dialogPreferredPadding" />
+
+ <SeekBar
+ android:id="@+id/seekbar"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingTop="?attr/dialogPreferredPadding"
+ android:paddingStart="?attr/dialogPreferredPadding"
+ android:paddingEnd="?attr/dialogPreferredPadding" />
+
+</LinearLayout>
diff --git a/core/res/res/layout/seekbar_dialog.xml b/core/res/res/layout/seekbar_dialog.xml
deleted file mode 100644
index 84352a5..0000000
--- a/core/res/res/layout/seekbar_dialog.xml
+++ /dev/null
@@ -1,34 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2008 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.
--->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical"
- android:gravity="center_horizontal">
-
- <ImageView android:id="@+id/icon"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:paddingTop="20dip" />
-
- <SeekBar android:id="@+id/seekbar"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:padding="20dip" />
-
-</LinearLayout>
-
diff --git a/core/res/res/values/arrays.xml b/core/res/res/values/arrays.xml
index d5c2d19..a3cc4aed 100644
--- a/core/res/res/values/arrays.xml
+++ b/core/res/res/values/arrays.xml
@@ -310,7 +310,11 @@
<item>@drawable/fastscroll_label_right_material</item>
<item>@drawable/fastscroll_thumb_material</item>
<item>@drawable/fastscroll_track_material</item>
+ <item>@drawable/floating_popup_background_dark</item>
+ <item>@drawable/floating_popup_background_light</item>
<item>@drawable/ic_ab_back_material</item>
+ <item>@drawable/ic_ab_back_material_dark</item>
+ <item>@drawable/ic_ab_back_material_light</item>
<item>@drawable/ic_clear_material</item>
<item>@drawable/ic_commit_search_api_material</item>
<item>@drawable/ic_dialog_alert_material</item>
@@ -330,7 +334,11 @@
<item>@drawable/ic_search_api_material</item>
<item>@drawable/ic_voice_search_api_material</item>
<item>@drawable/item_background_borderless_material</item>
+ <item>@drawable/item_background_borderless_material_dark</item>
+ <item>@drawable/item_background_borderless_material_light</item>
<item>@drawable/item_background_material</item>
+ <item>@drawable/item_background_material_dark</item>
+ <item>@drawable/item_background_material_light</item>
<item>@drawable/list_divider_material</item>
<item>@drawable/list_section_divider_material</item>
<item>@drawable/notification_material_action_background</item>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index a13f494..c08d511 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -550,6 +550,17 @@
<attr name="windowTransitionBackgroundFadeDuration" format="integer"/>
<!-- ============ -->
+ <!-- Floating toolbar styles -->
+ <!-- ============ -->
+ <eat-comment />
+ <attr name="floatingToolbarCloseDrawable" format="reference" />
+ <attr name="floatingToolbarForegroundColor" format="reference|color" />
+ <attr name="floatingToolbarItemBackgroundBorderlessDrawable" format="reference" />
+ <attr name="floatingToolbarItemBackgroundDrawable" format="reference" />
+ <attr name="floatingToolbarOpenDrawable" format="reference" />
+ <attr name="floatingToolbarPopupBackgroundDrawable" format="reference" />
+
+ <!-- ============ -->
<!-- Alert Dialog styles -->
<!-- ============ -->
<eat-comment />
@@ -561,15 +572,18 @@
<!-- Image elements -->
<!-- ============== -->
<eat-comment />
-
+i
<!-- Background that can be used behind parts of a UI that provide
details on data the user is selecting. For example, this is
the background element of PreferenceActivity's embedded
preference fragment. -->
<attr name="detailsElementBackground" format="reference" />
- <!-- Drawable that should be used to indicate that an app is waiting for a fingerprint scan. -->
- <attr name="fingerprintDrawable" format="reference" />
+ <!-- Icon that should be used to indicate that an app is waiting for a fingerprint scan.
+ This should be used whenever an app is requesting the user to place a finger on the
+ fingerprint sensor. It can be combined with other drawables such as colored circles, so
+ the appearance matches the branding of the app requesting the fingerprint scan.-->
+ <attr name="fingerprintAuthDrawable" format="reference" />
<!-- ============ -->
<!-- Panel styles -->
@@ -868,6 +882,8 @@
<attr name="dialogPreferenceStyle" format="reference" />
<!-- Default style for EditTextPreference. -->
<attr name="editTextPreferenceStyle" format="reference" />
+ <!-- @hide Default style for SeekBarDialogPreference. -->
+ <attr name="seekBarDialogPreferenceStyle" format="reference" />
<!-- Default style for RingtonePreference. -->
<attr name="ringtonePreferenceStyle" format="reference" />
<!-- The preference layout that has the child/tabbed effect. -->
@@ -6646,33 +6662,6 @@
for more info. -->
<attr name="actionProviderClass" format="string" />
- <!-- An optional tint for the item's icon.
- See {@link android.view.MenuItem#setIconTintList(android.content.res.ColorStateList)}
- for more info. -->
- <attr name="iconTint" format="color" />
-
- <!-- The blending mode used for tinting the item's icon
- See {@link android.view.MenuItem#setIconTintMode(android.graphics.PorterDuff.Mode)}
- for more info. -->
- <attr name="iconTintMode">
- <!-- The tint is drawn on top of the drawable.
- [Sa + (1 - Sa)*Da, Rc = Sc + (1 - Sa)*Dc] -->
- <enum name="src_over" value="3" />
- <!-- The tint is masked by the alpha channel of the drawable. The drawable’s
- color channels are thrown out. [Sa * Da, Sc * Da] -->
- <enum name="src_in" value="5" />
- <!-- The tint is drawn above the drawable, but with the drawable’s alpha
- channel masking the result. [Da, Sc * Da + (1 - Sa) * Dc] -->
- <enum name="src_atop" value="9" />
- <!-- Multiplies the color and alpha channels of the drawable with those of
- the tint. [Sa * Da, Sc * Dc] -->
- <enum name="multiply" value="14" />
- <!-- [Sa + Da - Sa * Da, Sc + Dc - Sc * Dc] -->
- <enum name="screen" value="15" />
- <!-- Combines the tint and drawable color and alpha channels, clamping the
- result to valid color values. Saturate(S + D) -->
- <enum name="add" value="16" />
- </attr>
</declare-styleable>
<!-- Attrbitutes for a ActvityChooserView. -->
@@ -7786,52 +7775,6 @@
<!-- Text to set as the content description for the navigation button
located at the start of the toolbar. -->
<attr name="navigationContentDescription" format="string" />
-
- <!-- Tint used for the navigation button -->
- <attr name="navigationTint" format="color" />
- <!-- The blending mode used for tinting the navigation button -->
- <attr name="navigationTintMode">
- <!-- The tint is drawn on top of the drawable.
- [Sa + (1 - Sa)*Da, Rc = Sc + (1 - Sa)*Dc] -->
- <enum name="src_over" value="3" />
- <!-- The tint is masked by the alpha channel of the drawable. The drawable’s
- color channels are thrown out. [Sa * Da, Sc * Da] -->
- <enum name="src_in" value="5" />
- <!-- The tint is drawn above the drawable, but with the drawable’s alpha
- channel masking the result. [Da, Sc * Da + (1 - Sa) * Dc] -->
- <enum name="src_atop" value="9" />
- <!-- Multiplies the color and alpha channels of the drawable with those of
- the tint. [Sa * Da, Sc * Dc] -->
- <enum name="multiply" value="14" />
- <!-- [Sa + Da - Sa * Da, Sc + Dc - Sc * Dc] -->
- <enum name="screen" value="15" />
- <!-- Combines the tint and drawable color and alpha channels, clamping the
- result to valid color values. Saturate(S + D). Only works on APIv 11+ -->
- <enum name="add" value="16" />
- </attr>
-
- <!-- Tint used for the overflow button -->
- <attr name="overflowTint" format="color" />
- <!-- The blending mode used for tinting the overflow button -->
- <attr name="overflowTintMode">
- <!-- The tint is drawn on top of the drawable.
- [Sa + (1 - Sa)*Da, Rc = Sc + (1 - Sa)*Dc] -->
- <enum name="src_over" value="3" />
- <!-- The tint is masked by the alpha channel of the drawable. The drawable’s
- color channels are thrown out. [Sa * Da, Sc * Da] -->
- <enum name="src_in" value="5" />
- <!-- The tint is drawn above the drawable, but with the drawable’s alpha
- channel masking the result. [Da, Sc * Da + (1 - Sa) * Dc] -->
- <enum name="src_atop" value="9" />
- <!-- Multiplies the color and alpha channels of the drawable with those of
- the tint. [Sa * Da, Sc * Dc] -->
- <enum name="multiply" value="14" />
- <!-- [Sa + Da - Sa * Da, Sc + Dc - Sc * Dc] -->
- <enum name="screen" value="15" />
- <!-- Combines the tint and drawable color and alpha channels, clamping the
- result to valid color values. Saturate(S + D). Only works on APIv 11+ -->
- <enum name="add" value="16" />
- </attr>
</declare-styleable>
<declare-styleable name="Toolbar_LayoutParams">
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 470e345..f31c1d6 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -1058,18 +1058,20 @@
lockTask mode is disabled.
<p>While in lockTask mode with multiple permitted tasks running, each launched task is
permitted to finish, transitioning to the previous locked task, until there is only one
- task remaining. At that point the last task running is not permitted to finish. -->
+ task remaining. At that point the last task running is not permitted to finish, unless it
+ uses the value always. -->
<attr name="lockTaskMode">
<!-- This is the default value. Tasks will not launch into lockTask mode but can be
placed there by calling {@link android.app.Activity#startLockTask}. If a task with
this mode has been whitelisted using {@link
- android.app.admin.DevicePolicyManager#setLockTaskPackages} then calling startLockTask
- will enter lockTask mode immediately, otherwise the user will be presented with a
- dialog to approve entering lockTask mode.
+ android.app.admin.DevicePolicyManager#setLockTaskPackages} then calling
+ {@link android.app.Activity#startLockTask} will enter lockTask mode immediately,
+ otherwise the user will be presented with a dialog to approve entering pinned mode.
<p>If the system is already in lockTask mode when a new task rooted at this activity
is launched that task will or will not start depending on whether the package of this
activity has been whitelisted.
- <p>Tasks rooted at this activity can only exit lockTask mode using stopLockTask(). -->
+ <p>Tasks rooted at this activity can only exit lockTask mode using
+ {@link android.app.Activity#stopLockTask}. -->
<enum name="normal" value="0"/>
<!-- Tasks will not launch into lockTask mode and cannot be placed there using
{@link android.app.Activity#startLockTask} or be pinned from the Overview screen.
@@ -1082,16 +1084,17 @@
<!-- Tasks rooted at this activity will always launch into lockTask mode. If the system is
already in lockTask mode when this task is launched then the new task will be launched
on top of the current task. Tasks launched in this mode are capable of exiting
- lockTask mode using finish(), whereas tasks entering lockTask mode using
- startLockTask() must use stopLockTask() to exit.
+ lockTask mode using {@link android.app.Activity#finish()}.
<p>Note: This mode is only available to system and privileged applications.
Non-privileged apps with this value will be treated as normal.
-->
<enum name="always" value="2"/>
<!-- If the DevicePolicyManager (DPM) authorizes this package ({@link
android.app.admin.DevicePolicyManager#setLockTaskPackages}) then this mode is
- identical to always. If the DPM does not authorize this package then this
- mode is identical to normal. -->
+ identical to always, except that the activity needs to call
+ {@link android.app.Activity#stopLockTask} before being able to finish if it is the last
+ locked task.
+ If the DPM does not authorize this package then this mode is identical to normal. -->
<enum name="if_whitelisted" value="3"/>
</attr>
<!-- When set installer will extract native libraries. If set to false
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index db1ac44..e7811df 100755
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -572,6 +572,43 @@
true here reverses that logic. -->
<bool name="config_reverseDefaultRotation">false</bool>
+ <!-- Sets the minimum and maximum tilt tolerance for each possible rotation.
+ This array consists of 4 pairs of values which specify the minimum and maximum
+ tilt angle at which the device will transition into each rotation.
+
+ The tilt angle represents the direction in which the plane of the screen is facing;
+ it is also known as the angle of elevation.
+
+ -90 degree tilt means that the screen is facing straight down
+ (the device is being held overhead upside-down)
+ 0 degree tilt means that the screen is facing outwards
+ (the device is being held vertically)
+ 90 degree tilt means that the screen is facing straight up
+ (the device is resting on a flat table)
+
+ The default tolerances are set conservatively such that the device is more
+ likely to remain in its natural orientation than rotate into a counterclockwise,
+ clockwise, or reversed posture (with an especially strong bias against the latter)
+ to prevent accidental rotation while carrying the device in hand.
+
+ These thresholds may need to be tuned when the device is intended to be
+ mounted into a dock with a particularly shallow profile wherein rotation
+ would ordinarily have been suppressed.
+
+ It is helpful to consider the desired behavior both when the device is being
+ held at a positive tilt (typical case) vs. a negative tilt (reading overhead in
+ bed) since they are quite different. In the overhead case, we typically want
+ the device to more strongly prefer to retain its current configuration (in absence
+ of a clear indication that a rotation is desired) since the user's head and neck may
+ be held at an unusual angle.
+ -->
+ <integer-array name="config_autoRotationTiltTolerance">
+ <!-- rotation: 0 (natural) --> <item>-25</item> <item>70</item>
+ <!-- rotation: 90 (rotate CCW) --> <item>-25</item> <item>65</item>
+ <!-- rotation: 180 (reverse) --> <item>-25</item> <item>60</item>
+ <!-- rotation: 270 (rotate CW) --> <item>-25</item> <item>65</item>
+ </integer-array>
+
<!-- Lid switch behavior -->
<!-- The number of degrees to rotate the display when the keyboard is open.
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index bbf4005..bbe27a4 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2614,12 +2614,20 @@
<public type="attr" name="end" />
<public type="attr" name="windowLightStatusBar" />
<public type="attr" name="numbersInnerTextColor" />
- <public type="attr" name="iconTint" />
- <public type="attr" name="iconTintMode" />
- <public type="attr" name="overflowTint" />
- <public type="attr" name="overflowTintMode" />
- <public type="attr" name="navigationTint" />
- <public type="attr" name="navigationTintMode" />
+
+ <attr name="__reserved2" format="boolean" />
+ <public type="attr" name="__reserved2" />
+ <attr name="__reserved3" format="boolean" />
+ <public type="attr" name="__reserved3" />
+ <attr name="__reserved4" format="boolean" />
+ <public type="attr" name="__reserved4" />
+ <attr name="__reserved5" format="boolean" />
+ <public type="attr" name="__reserved5" />
+ <attr name="__reserved6" format="boolean" />
+ <public type="attr" name="__reserved6" />
+ <attr name="__reserved7" format="boolean" />
+ <public type="attr" name="__reserved7" />
+
<public type="attr" name="fullBackupContent" />
<public type="style" name="Widget.Material.Button.Colored" />
@@ -2690,5 +2698,5 @@
<public type="attr" name="supportsLaunchVoiceAssistFromKeyguard" />
<public type="attr" name="scrollIndicators" />
<public type="attr" name="hyphenationFrequency" />
- <public type="attr" name="fingerprintDrawable" />
+ <public type="attr" name="fingerprintAuthDrawable" />
</resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 2326968..a6b7e35 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -566,7 +566,12 @@
<!-- Title of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permgrouplab_sms">SMS</string>
<!-- Description of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
- <string name="permgroupdesc_sms">view and manage SMS messages</string>
+ <string name="permgroupdesc_sms">send and view SMS messages</string>
+
+ <!-- Title of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permgrouplab_storage">Storage</string>
+ <!-- Description of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permgroupdesc_storage">access photos, media, and files on your device</string>
<!-- Title of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permgrouplab_dictionary">User Dictionary</string>
@@ -596,7 +601,7 @@
<!-- Title of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permgrouplab_sensors">Sensors</string>
<!-- Description of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
- <string name="permgroupdesc_sensors">access data from sensors and wearable devices</string>
+ <string name="permgroupdesc_sensors">access information about your vital signs and physical activity</string>
<!-- Title for the capability of an accessibility service to retrieve window content. -->
<string name="capability_title_canRetrieveWindowContent">Retrieve window content</string>
@@ -1113,27 +1118,6 @@
the list of accounts known by the phone. This may include any accounts
created by applications you have installed.</string>
-
- <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
- <string name="permlab_authenticateAccounts">create accounts and set passwords</string>
- <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
- <string name="permdesc_authenticateAccounts">Allows the app
- to use the account authenticator capabilities of the
- AccountManager, including creating accounts and getting and
- setting their passwords.</string>
-
- <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
- <string name="permlab_manageAccounts">add or remove accounts</string>
- <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
- <string name="permdesc_manageAccounts">Allows the app to
- perform operations like adding and removing accounts, and deleting
- their password.</string>
-
- <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
- <string name="permlab_useCredentials">use accounts on the device</string>
- <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
- <string name="permdesc_useCredentials">Allows the app to request authentication tokens.</string>
-
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_accessNetworkState">view network connections</string>
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
@@ -1302,12 +1286,6 @@
<string name="permdesc_readSyncStats">Allows an app to read the sync stats for an account, including the history of sync events and how much data is synced. </string>
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
- <string name="permlab_subscribedFeedsWrite">write subscribed feeds</string>
- <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
- <string name="permdesc_subscribedFeedsWrite">Allows the app to modify
- your currently synced feeds. Malicious apps may change your synced feeds.</string>
-
- <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_readDictionary">read terms you added to the dictionary</string>
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permdesc_readDictionary">Allows the app to read all words,
@@ -1519,10 +1497,10 @@
<string name="policylab_disableCamera">Disable cameras</string>
<!-- Description of policy access to disable all device cameras [CHAR LIMIT=110]-->
<string name="policydesc_disableCamera">Prevent use of all device cameras.</string>
- <!-- Title of policy access to disable all device cameras [CHAR LIMIT=30]-->
- <string name="policylab_disableKeyguardFeatures">Disable features of screen lock</string>
- <!-- Description of policy access to disable all device cameras [CHAR LIMIT=110]-->
- <string name="policydesc_disableKeyguardFeatures">Prevent use of some features of screen lock.</string>
+ <!-- Title of policy access to disable keyguard features [CHAR LIMIT=30]-->
+ <string name="policylab_disableKeyguardFeatures">Disable some screen lock features</string>
+ <!-- Description of policy access to disable keyguard features. [CHAR LIMIT=110]-->
+ <string name="policydesc_disableKeyguardFeatures">Prevent use of some screen lock features.</string>
<!-- The order of these is important, don't reorder without changing Contacts.java --> <skip />
<!-- Phone number types from android.provider.Contacts. This could be used when adding a new phone number for a contact, for example. -->
@@ -3028,9 +3006,14 @@
<string name="ext_media_ready_notification_message">For transferring photos and media</string>
<!-- Notification title when external media is unmountable (corrupt) [CHAR LIMIT=30] -->
- <string name="ext_media_unmountable_notification_title">Damaged <xliff:g id="name" example="SD card">%s</xliff:g></string>
+ <string name="ext_media_unmountable_notification_title">Corrupted <xliff:g id="name" example="SD card">%s</xliff:g></string>
<!-- Notification body when external media is unmountable (corrupt) [CHAR LIMIT=NONE] -->
- <string name="ext_media_unmountable_notification_message"><xliff:g id="name" example="SD card">%s</xliff:g> is damaged; try reformatting it</string>
+ <string name="ext_media_unmountable_notification_message"><xliff:g id="name" example="SD card">%s</xliff:g> is corrupt. Touch to fix.</string>
+
+ <!-- Notification title when external media is unsupported [CHAR LIMIT=30] -->
+ <string name="ext_media_unsupported_notification_title">Unsupported <xliff:g id="name" example="SD card">%s</xliff:g></string>
+ <!-- Notification body when external media is unsupported [CHAR LIMIT=NONE] -->
+ <string name="ext_media_unsupported_notification_message">This device doesn\u2019t support this <xliff:g id="name" example="SD card">%s</xliff:g>. Touch to set up in a supported format.</string>
<!-- Notification title when external media is unsafely removed [CHAR LIMIT=30] -->
<string name="ext_media_badremoval_notification_title"><xliff:g id="name" example="SD card">%s</xliff:g> unexpectedly removed</string>
@@ -3048,7 +3031,7 @@
<string name="ext_media_unmounting_notification_message">Don\'t remove</string>
<!-- Notification action to setup external media [CHAR LIMIT=20] -->
- <string name="ext_media_init_action">Setup</string>
+ <string name="ext_media_init_action">Set up</string>
<!-- Notification action to unmount external media [CHAR LIMIT=20] -->
<string name="ext_media_unmount_action">Eject</string>
<!-- Notification action to browse external media [CHAR LIMIT=20] -->
@@ -3074,6 +3057,29 @@
<!-- Notification title when moving data to external storage failed [CHAR LIMIT=64] -->
<string name="ext_media_move_failure_message">Data left at original location</string>
+ <!-- Short summary of storage media status when removed [CHAR LIMIT=32] -->
+ <string name="ext_media_status_removed">Removed</string>
+ <!-- Short summary of storage media status when unmounted [CHAR LIMIT=32] -->
+ <string name="ext_media_status_unmounted">Ejected</string>
+ <!-- Short summary of storage media status when checking [CHAR LIMIT=32] -->
+ <string name="ext_media_status_checking">Checking\u2026</string>
+ <!-- Short summary of storage media status when mounted [CHAR LIMIT=32] -->
+ <string name="ext_media_status_mounted">Ready</string>
+ <!-- Short summary of storage media status when mounted read-only [CHAR LIMIT=32] -->
+ <string name="ext_media_status_mounted_ro">Read-only</string>
+ <!-- Short summary of storage media status when removed unsafely [CHAR LIMIT=32] -->
+ <string name="ext_media_status_bad_removal">Removed unsafely</string>
+ <!-- Short summary of storage media status when unmountable [CHAR LIMIT=32] -->
+ <string name="ext_media_status_unmountable">Corrupted</string>
+ <!-- Short summary of storage media status when unsupported [CHAR LIMIT=32] -->
+ <string name="ext_media_status_unsupported">Unsupported</string>
+ <!-- Short summary of storage media status when ejecting [CHAR LIMIT=32] -->
+ <string name="ext_media_status_ejecting">Ejecting\u2026</string>
+ <!-- Short summary of storage media status when formatting [CHAR LIMIT=32] -->
+ <string name="ext_media_status_formatting">Formatting\u2026</string>
+ <!-- Short summary of storage media status when missing [CHAR LIMIT=32] -->
+ <string name="ext_media_status_missing">Not inserted</string>
+
<!-- Shown in LauncherActivity when the requested target Intent didn't return any matching Activities, leaving the list empty. -->
<string name="activity_list_empty">No matching activities found.</string>
@@ -4179,4 +4185,9 @@
notification_template_material_inbox.xml.
DO NOT TRANSLATE -->
<string name="notification_inbox_ellipsis">\u2026</string>
+
+ <!-- Label describing the number of selected items [CHAR LIMIT=48] -->
+ <plurals name="selected_count">
+ <item quantity="other"><xliff:g id="count" example="3">%1$d</xliff:g> selected</item>
+ </plurals>
</resources>
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index 4eba117..4bad16d 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -1017,6 +1017,10 @@
<item name="negativeButtonText">@string/no</item>
</style>
+ <style name="Preference.DialogPreference.SeekBarPreference">
+ <item name="dialogLayout">@layout/preference_dialog_seekbar</item>
+ </style>
+
<style name="Preference.DialogPreference.EditTextPreference">
<item name="dialogLayout">@layout/preference_dialog_edittext</item>
</style>
diff --git a/core/res/res/values/styles_material.xml b/core/res/res/values/styles_material.xml
index df4106e..70f9c02 100644
--- a/core/res/res/values/styles_material.xml
+++ b/core/res/res/values/styles_material.xml
@@ -87,6 +87,10 @@
<item name="negativeButtonText">@string/no</item>
</style>
+ <style name="Preference.Material.DialogPreference.SeekBarPreference">
+ <item name="dialogLayout">@layout/preference_dialog_seekbar_material</item>
+ </style>
+
<style name="Preference.Material.DialogPreference.EditTextPreference">
<item name="dialogLayout">@layout/preference_dialog_edittext_material</item>
</style>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 15b253d..361c0bd 100755
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1341,7 +1341,6 @@
<java-symbol type="layout" name="preference_widget_seekbar" />
<java-symbol type="layout" name="progress_dialog" />
<java-symbol type="layout" name="resolve_list_item" />
- <java-symbol type="layout" name="seekbar_dialog" />
<java-symbol type="layout" name="select_dialog_singlechoice_holo" />
<java-symbol type="layout" name="ssl_certificate" />
<java-symbol type="layout" name="tab_content" />
@@ -1452,6 +1451,7 @@
<java-symbol type="anim" name="voice_activity_open_exit" />
<java-symbol type="anim" name="voice_activity_open_enter" />
+ <java-symbol type="array" name="config_autoRotationTiltTolerance" />
<java-symbol type="array" name="config_keyboardTapVibePattern" />
<java-symbol type="array" name="config_longPressVibePattern" />
<java-symbol type="array" name="config_safeModeDisabledVibePattern" />
@@ -2292,4 +2292,21 @@
<java-symbol type="string" name="config_radio_access_family" />
<java-symbol type="string" name="notification_inbox_ellipsis" />
<java-symbol type="bool" name="config_mainBuiltInDisplayIsRound" />
+
+ <java-symbol type="attr" name="seekBarDialogPreferenceStyle" />
+ <java-symbol type="string" name="ext_media_status_removed" />
+ <java-symbol type="string" name="ext_media_status_unmounted" />
+ <java-symbol type="string" name="ext_media_status_checking" />
+ <java-symbol type="string" name="ext_media_status_mounted" />
+ <java-symbol type="string" name="ext_media_status_mounted_ro" />
+ <java-symbol type="string" name="ext_media_status_bad_removal" />
+ <java-symbol type="string" name="ext_media_status_unmountable" />
+ <java-symbol type="string" name="ext_media_status_unsupported" />
+ <java-symbol type="string" name="ext_media_status_ejecting" />
+ <java-symbol type="string" name="ext_media_status_formatting" />
+ <java-symbol type="string" name="ext_media_status_missing" />
+ <java-symbol type="string" name="ext_media_unsupported_notification_message" />
+ <java-symbol type="string" name="ext_media_unsupported_notification_title" />
+ <java-symbol type="plurals" name="selected_count" />
+
</resources>
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index 9e87b4d..b7acdd4 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -331,6 +331,7 @@
<item name="seekBarPreferenceStyle">@style/Preference.SeekBarPreference</item>
<item name="yesNoPreferenceStyle">@style/Preference.DialogPreference.YesNoPreference</item>
<item name="dialogPreferenceStyle">@style/Preference.DialogPreference</item>
+ <item name="seekBarDialogPreferenceStyle">@style/Preference.DialogPreference.SeekBarPreference</item>
<item name="editTextPreferenceStyle">@style/Preference.DialogPreference.EditTextPreference</item>
<item name="ringtonePreferenceStyle">@style/Preference.RingtonePreference</item>
<item name="preferenceLayoutChild">@layout/preference_child</item>
@@ -386,6 +387,15 @@
<item name="buttonBarNegativeButtonStyle">?attr/buttonBarButtonStyle</item>
<item name="buttonBarNeutralButtonStyle">?attr/buttonBarButtonStyle</item>
<item name="segmentedButtonStyle">@style/SegmentedButton</item>
+ <item name="fingerprintAuthDrawable">@drawable/ic_fingerprint</item>
+
+ <!-- Floating toolbar styles -->
+ <item name="floatingToolbarCloseDrawable">@drawable/ic_ab_back_material_dark</item>
+ <item name="floatingToolbarForegroundColor">@color/foreground_material_dark</item>
+ <item name="floatingToolbarItemBackgroundBorderlessDrawable">@drawable/item_background_borderless_material_dark</item>
+ <item name="floatingToolbarItemBackgroundDrawable">@drawable/item_background_material_dark</item>
+ <item name="floatingToolbarOpenDrawable">@drawable/ic_menu_moreoverflow_material_dark</item>
+ <item name="floatingToolbarPopupBackgroundDrawable">@drawable/floating_popup_background_dark</item>
<!-- SearchView attributes -->
<item name="searchViewStyle">@style/Widget.Holo.SearchView</item>
@@ -536,6 +546,14 @@
<item name="mediaRouteButtonStyle">@style/Widget.DeviceDefault.Light.MediaRouteButton</item>
<item name="findOnPageNextDrawable">@drawable/ic_find_next_holo_light</item>
<item name="findOnPagePreviousDrawable">@drawable/ic_find_previous_holo_light</item>
+
+ <!-- Floating toolbar styles -->
+ <item name="floatingToolbarCloseDrawable">@drawable/ic_ab_back_material_light</item>
+ <item name="floatingToolbarForegroundColor">@color/foreground_material_light</item>
+ <item name="floatingToolbarItemBackgroundBorderlessDrawable">@drawable/item_background_borderless_material_light</item>
+ <item name="floatingToolbarItemBackgroundDrawable">@drawable/item_background_material_light</item>
+ <item name="floatingToolbarOpenDrawable">@drawable/ic_menu_moreoverflow_material_light</item>
+ <item name="floatingToolbarPopupBackgroundDrawable">@drawable/floating_popup_background_light</item>
</style>
<!-- Variant of {@link #Theme_Light} with no title bar -->
diff --git a/core/res/res/values/themes_material.xml b/core/res/res/values/themes_material.xml
index 9f3668d..295b453 100644
--- a/core/res/res/values/themes_material.xml
+++ b/core/res/res/values/themes_material.xml
@@ -295,6 +295,7 @@
<item name="seekBarPreferenceStyle">@style/Preference.Material.SeekBarPreference</item>
<item name="yesNoPreferenceStyle">@style/Preference.Material.DialogPreference.YesNoPreference</item>
<item name="dialogPreferenceStyle">@style/Preference.Material.DialogPreference</item>
+ <item name="seekBarDialogPreferenceStyle">@style/Preference.Material.DialogPreference.SeekBarPreference</item>
<item name="editTextPreferenceStyle">@style/Preference.Material.DialogPreference.EditTextPreference</item>
<item name="ringtonePreferenceStyle">@style/Preference.Material.RingtonePreference</item>
<item name="preferenceLayoutChild">@layout/preference_child_material</item>
@@ -304,7 +305,6 @@
<item name="preferenceFragmentListStyle">@style/PreferenceFragmentList.Material</item>
<item name="preferenceFragmentPaddingSide">@dimen/preference_fragment_padding_side_material</item>
<item name="detailsElementBackground">?attr/colorBackground</item>
- <item name="fingerprintDrawable">@drawable/ic_fingerprint_dark</item>
<!-- PreferenceFrameLayout attributes -->
<item name="preferenceFrameLayoutStyle">@style/Widget.Material.PreferenceFrameLayout</item>
@@ -651,6 +651,7 @@
<item name="seekBarPreferenceStyle">@style/Preference.Material.SeekBarPreference</item>
<item name="yesNoPreferenceStyle">@style/Preference.Material.DialogPreference.YesNoPreference</item>
<item name="dialogPreferenceStyle">@style/Preference.Material.DialogPreference</item>
+ <item name="seekBarDialogPreferenceStyle">@style/Preference.Material.DialogPreference.SeekBarPreference</item>
<item name="editTextPreferenceStyle">@style/Preference.Material.DialogPreference.EditTextPreference</item>
<item name="ringtonePreferenceStyle">@style/Preference.Material.RingtonePreference</item>
<item name="preferenceLayoutChild">@layout/preference_child_material</item>
@@ -660,7 +661,6 @@
<item name="preferenceFragmentListStyle">@style/PreferenceFragmentList.Material</item>
<item name="preferenceFragmentPaddingSide">@dimen/preference_fragment_padding_side_material</item>
<item name="detailsElementBackground">?attr/colorBackground</item>
- <item name="fingerprintDrawable">@drawable/ic_fingerprint_light</item>
<!-- PreferenceFrameLayout attributes -->
<item name="preferenceFrameLayoutStyle">@style/Widget.Material.PreferenceFrameLayout</item>
diff --git a/core/tests/coretests/src/android/os/FileUtilsTest.java b/core/tests/coretests/src/android/os/FileUtilsTest.java
index ee9e2e4..ac5abadc 100644
--- a/core/tests/coretests/src/android/os/FileUtilsTest.java
+++ b/core/tests/coretests/src/android/os/FileUtilsTest.java
@@ -232,6 +232,18 @@
assertEquals("foo_bar__baz", FileUtils.buildValidFatFilename("foo?bar**baz"));
}
+ public void testTrimFilename() throws Exception {
+ assertEquals("short.txt", FileUtils.trimFilename("short.txt", 16));
+ assertEquals("extrem...eme.txt", FileUtils.trimFilename("extremelylongfilename.txt", 16));
+
+ final String unicode = "a\u03C0\u03C0\u03C0\u03C0z";
+ assertEquals("a\u03C0\u03C0\u03C0\u03C0z", FileUtils.trimFilename(unicode, 10));
+ assertEquals("a\u03C0...\u03C0z", FileUtils.trimFilename(unicode, 9));
+ assertEquals("a...\u03C0z", FileUtils.trimFilename(unicode, 8));
+ assertEquals("a...\u03C0z", FileUtils.trimFilename(unicode, 7));
+ assertEquals("a...z", FileUtils.trimFilename(unicode, 6));
+ }
+
public void testBuildUniqueFile_normal() throws Exception {
assertNameEquals("test.jpg", FileUtils.buildUniqueFile(mTarget, "image/jpeg", "test"));
assertNameEquals("test.jpg", FileUtils.buildUniqueFile(mTarget, "image/jpeg", "test.jpg"));
diff --git a/data/fonts/Android.mk b/data/fonts/Android.mk
index 6d8d81f..3181017 100644
--- a/data/fonts/Android.mk
+++ b/data/fonts/Android.mk
@@ -17,8 +17,8 @@
LOCAL_PATH := $(call my-dir)
-# Use full Noto Sans Japanese font on extended footprint
-ifeq ($(EXTENDED_FONT_FOOTPRINT),true)
+# Use full Noto Sans Japanese font on non-smaller footprints
+ifneq ($(SMALLER_FONT_FOOTPRINT),true)
FONT_NOTOSANS_JP_FULL := true
endif
@@ -38,7 +38,7 @@
endef
##########################################
-# The following fonts are distributed as symlink only.
+# The following fonts are just symlinks, for backward compatibility.
##########################################
$(eval $(call create-font-symlink,DroidSans.ttf,Roboto-Regular.ttf))
$(eval $(call create-font-symlink,DroidSans-Bold.ttf,Roboto-Bold.ttf))
@@ -54,7 +54,7 @@
################################
# Do not include Motoya on space-constrained devices
ifneq ($(SMALLER_FONT_FOOTPRINT),true)
-# Do not include Motoya if we are including full NotoSans
+# Do not include Motoya if we are including Noto Sans Japanese
ifneq ($(FONT_NOTOSANS_JP_FULL),true)
include $(CLEAR_VARS)
@@ -82,26 +82,19 @@
extra_font_files :=
################################
-# Include DroidSansFallback only on non-EXTENDED_FONT_FOOTPRINT builds
-ifneq ($(EXTENDED_FONT_FOOTPRINT),true)
-
-# Include a subset of DroidSansFallback on SMALLER_FONT_FOOTPRINT build
+# Include the DroidSansFallback subset on SMALLER_FONT_FOOTPRINT build
ifeq ($(SMALLER_FONT_FOOTPRINT),true)
-droidsans_fallback_src := DroidSansFallback.ttf
-else # !SMALLER_FONT_FOOTPRINT
-droidsans_fallback_src := DroidSansFallbackFull.ttf
-endif # SMALLER_FONT_FOOTPRINT
include $(CLEAR_VARS)
LOCAL_MODULE := DroidSansFallback.ttf
-LOCAL_SRC_FILES := $(droidsans_fallback_src)
+LOCAL_SRC_FILES := $(LOCAL_MODULE)
LOCAL_MODULE_CLASS := ETC
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_PATH := $(TARGET_OUT)/fonts
include $(BUILD_PREBUILT)
droidsans_fallback_src :=
-endif # !EXTENDED_FONT_FOOTPRINT
+endif # SMALLER_FONT_FOOTPRINT
################################
# Build the rest of font files as prebuilt.
diff --git a/docs/html/distribute/engage/deep-linking.jd b/docs/html/distribute/engage/deep-linking.jd
index 701cb99..713bfbb 100644
--- a/docs/html/distribute/engage/deep-linking.jd
+++ b/docs/html/distribute/engage/deep-linking.jd
@@ -1,7 +1,7 @@
page.title=Increase Usage with Search
page.metaDescription=Use search to bring your existing users back into your app.
page.image=images/cards/google-search_2x.png
-page.tags=engagement, appindexing, search
+page.tags="engagement", "app indexing", "search", "deep linking"
@jd:body
<p>
@@ -69,7 +69,7 @@
<div class="resource-widget resource-flow-layout col-13"
data-query="collection:distribute/engage/appindexing"
data-sortOrder="-timestamp"
- data-cardSizes="6x2"
- data-maxResults="3"></div>
+ data-cardSizes="9x3"
+ data-maxResults="4"></div>
diff --git a/docs/html/distribute/googleplay/families/about.jd b/docs/html/distribute/googleplay/families/about.jd
index a3ef157..bec9b6a 100644
--- a/docs/html/distribute/googleplay/families/about.jd
+++ b/docs/html/distribute/googleplay/families/about.jd
@@ -154,6 +154,10 @@
for Families program requirements</a>.
</p>
+<h2 id="optin">
+ Opt-in and FAQs
+</h2>
+
<p>
To learn how to opt-in and find more details about the program, visit the
Google Play Developer <a href=
diff --git a/docs/html/distribute/users/appindexing.jd b/docs/html/distribute/users/appindexing.jd
index 6a3fec6..04114e3 100644
--- a/docs/html/distribute/users/appindexing.jd
+++ b/docs/html/distribute/users/appindexing.jd
@@ -1,6 +1,7 @@
page.title=Drive installs from Google Search
page.metaDescription=Surface the content of your apps in Google Search and link it to app installs.
meta.tags="getusers", "search", "appindexing"
+page.tags="app indexing", "search", "get users"
page.image=images/cards/google-search_2x.png
@jd:body
diff --git a/docs/html/guide/faq/commontasks.jd b/docs/html/guide/faq/commontasks.jd
deleted file mode 100644
index 2943aef..0000000
--- a/docs/html/guide/faq/commontasks.jd
+++ /dev/null
@@ -1,826 +0,0 @@
-page.title=Common Tasks and How to Do Them in Android
-excludeFromSuggestions=true
-@jd:body
-
-<ul>
- <li><a href="#neweclipseandroidproject">Creating an Android Application using
- the Eclipse plugin</a></li>
- <li><a href="#newandroidprojectnoeclipse">Creating an Android Application without
- the Eclipse plugin</a></li>
- <li><a href="#addexternallibrary">Adding an External Library (.jar) using Eclipse</a></li>
- <li><a href="#implementcallbacks">Implementing Activity callbacks</a> (Android
- calls your activity at various key moments in its life cycle. You must know
- how to handle each of these to draw your screen, initialize class members,
- and acquire data.)</li>
- <li><a href="#opennewscreen">Opening a new screen</a></li>
- <li><a href="#listening">Listening for button clicks </a></li>
- <li><a href="#configurewindowproperties">Configuring general window properties </a></li>
- <li><a href="#localhostalias">Referring to localhost from the emulated environment</a></li>
- <li><a href="#appstate">Storing and retrieving state</a></li>
- <li><a href="{@docRoot}guide/topics/data/data-storage.html#preferences">Storing and retrieving preferences</a></li>
- <li><a href="#storingandretrieving">Storing and retrieving larger or more complex
- persistent data</a> (files and data) </li>
- <li><a href="#playback">Playing audio, video, still, or other media files</a></li>
- <li><a href="#broadcastreceivers">Listening for and broadcasting global messages
- and setting alarms</a></li>
- <li><a href="#alerts">Displaying alerts </a></li>
- <li><a href="#progressbar">Displaying a progress bar</a> </li>
- <li><a href="#addmenuitems">Adding items to the screen menu</a> </li>
- <li><a href="#webpage">Display a web page</a> </li>
- <li><a href="#binding">Binding to data</a></li>
- <li><a href="#handle">Getting a Handle to a Screen Element</a></li>
- <li><a href="#captureimages">Capture images from the phone camera </a></li>
- <li><a href="#threading">Handling expensive operations in the UI thread</a></li>
- <li><a href="#selectingtext">Selecting, highlighting, or styling portions of
- text</a></li>
- <li><a href="#querymap">Utilizing attributes in a Map query</a></li>
- <li><a href="#filelist">List of files for an Android application</a></li>
- <li><a href="#logging">Print messages to a log file</a></li>
-</ul>
-<p>The ApiDemos sample application includes many, many examples of common
-tasks and UI features. See the code inside
-<code><sdk>samples/ApiDemos</code> and the other sample applications
-under the <code>samples/</code> folder in the SDK.</p>
-
-
-<h2 id="neweclipseandroidproject">Creating an Android Application using the Eclipse Plugin</h2>
-
-<p>Using the Android Eclipse plugin is the fastest and easiest way
-to start creating a new Android application. The plugin automatically generates
-the correct project structure for your application, and keeps the resources
-compiled for you automatically.</p>
-
-<p>It is still a good idea to know what is going on though. Take a look at <a
-href="{@docRoot}guide/topics/fundamentals.html">Application Fundamentals</a>
-to understand the basics of how an Android application works.</p>
-
-<p>You should also take a look at the ApiDemos application and the other sample
-applications included in the SDK, in the <code><sdk>/samples/</code>
-folder in the SDK.</p>
-
-<p>Finally, a great way to started with Android development in Eclipse is to
-follow both the <a href="{@docRoot}resources/tutorials/hello-world.html">Hello,
-World</a> and <a
-href="{@docRoot}training/notepad/index.html">Notepad</a> code
-tutorials. In particular, the start of the Hello Android tutorial is an
-excellent introduction to creating a new Android application in Eclipse.</p>
-
-<h2 id="newandroidprojectnoeclipse">Creating an Android Application without the Eclipse Plugin</h2>
-
-<p>This topic describes the manual steps in creating an Android application.
-Before reading this, you should read <a
-href="{@docRoot}guide/topics/fundamentals.html">Application Fundamentals</a>
-to understand the basics of how an Android application works. You might also
-want to look at the sample code included with the Android SDK, in the
-<code><sdk>/samples/</code> directory. </p>
-
-<p>Here is a list of the basic steps in building an application.</p>
-<ol>
- <li><strong>Create your required resource files</strong> This includes
- the AndroidManifest.xml global description file, string files that your application
- needs, and layout files describing your user interface. A full list of optional
- and required files and syntax details for each is given in <a href="#filelist">File
- List for an Android Application</a>. </li>
- <li><strong>Design your user interface</strong> See <a
- href="{@docRoot}guide/topics/ui/index.html">User Interface</a> for
- details on elements of the Android screen. </li>
- <li><strong>Implement your Activity </strong>(this page)<strong> </strong> You
- will create one class/file for each screen in your application. Screens will
- inherit from an {@link android.app android.app} class, typically {@link android.app.Activity
- android.app.Activity} for basic screens, {@link android.app.ListActivity
- android.app.ListActivity} for list screens, or {@link android.app.Dialog
- android.app.Dialog} for dialog boxes. You will implement the required callbacks
- that let you draw your screen, query data, and commit changes, and also perform
- any required tasks such as opening additional screens or reading data from
- the device. Common tasks, such as opening a new screen or reading data from
- the device, are described below.
- The list of files you'll need for your application are described in <a href="#filelist">List
- of Files for an Android Application</a>. </li>
- <li><strong><a href="{@docRoot}guide/developing/building/building-cmdline.html">Build and install your
- package</a>.</strong> The Android SDK has some nice tools for generating
- projects and debugging code. </li>
-</ol>
-
-<h2 id="addexternallibrary">Adding an External Library (.jar) using Eclipse</h2>
-<p>
-You can use a third party JAR in your application by adding it to your Eclipse project as follows:
-</p>
-<ol>
-<li>
-In the <strong>Package Explorer</strong> panel, right-click on your project and select <strong>Properties</strong>.
-<li>
-Select <strong>Java Build Path</strong>, then the tab <strong>Libraries</strong>.
-<li>
-Press the <strong>Add External JARs...</strong> button and select the JAR file.
-</ol>
-<p>
-Alternatively, if you want to include third party JARs with your package, create a new directory for them within your project and select <strong>Add Library...</strong> instead.</p>
-<p>
-It is not necessary to put external JARs in the assets folder.
-</p>
-
-<a name="implementcallbacks" id="implementcallbacks"></a>
-<h2>Implementing Activity Callbacks</h2>
-<p>Android calls a number of callbacks to let you draw your screen, store data before
- pausing, and refresh data after closing. You must implement at least some of
- these methods. Read the <a
-href="{@docRoot}guide/topics/fundamentals/activities.html#Lifecycle">Activities</a>
- document to learn when and in what order these methods
- are called. Here are some of the standard types of screen classes that Android provides:</p>
-<ul>
- <li>{@link android.app.Activity android.app.Activity} - This is a standard screen,
- with no specialization.</li>
- <li>{@link android.app.ListActivity android.app.ListActivity} - This is a screen
- that is used to display a list of something. It hosts a ListView object,
- and exposes methods to let you identify the selected item, receive callbacks
- when the selected item changes, and perform other list-related actions. </li>
- <li>{@link android.app.Dialog android.app.Dialog} - This is a small, popup dialog-style
- window that isn't intended to remain in the history stack. (It is not resizeable
- or moveable by the user.)</li>
-</ul>
-
-<a name="opennewscreen" id="opennewscreen"></a><h2>Opening a New Screen</h2>
-<p>Your Activity will often need to open another Activity screen as it progresses.
- This new screen can be part of the same application or part of another application,
- the new screen can be floating or full screen, it can return a result, and you
- can decide whether to close this screen and remove it from the history stack
- when you are done with it, or to keep the screen open in history. These next
- sections describe all these options. </p>
-<h3>Floating or full?<a name="floatingorfull" id="floatingorfull"></a></h3>
-<p>When you open a new screen you can decide whether to make it transparent or floating,
- or full-screen. The choice of new screen affects the event sequence of events
- in the old screen (if the new screen obscures the old screen, a different
- series of events is called in the old screen). See the <a
- href="{@docRoot}guide/topics/fundamentals/activities.html#Lifecycle">Activities</a> document for
-details. </p>
-<p>Transparent or floating windows are implemented in three
- standard ways: </p>
-<ul>
- <li>Create an {@link android.app.Dialog app.Dialog} class </li>
- <li>Create an {@link android.app.AlertDialog app.AlertDialog} class </li>
- <li>Set the {@link android.R.style#Theme_Dialog} <em>theme</em> attribute to <code>@android:style/Theme.Dialog</code>
- in your AndroidManifest.xml file. For example:
- <pre><activity class="AddRssItem" android:label="Add an item" android:theme="@android:style/Theme.Dialog"/></pre></li>
-</ul>
-
-<p>Calling startActivity() or startActivityForResult() will open a new screen in whatever
- way it defines itself (if it uses a floating theme it will be floating,
- otherwise it will be full screen). </p>
-<h3>Opening a Screen </h3>
-<p>When you want to open a new screen, you can either explicitly specify the activity
- class to open, or you can let the operating system decide which screen to open,
- based upon the data and various parameters you pass in. A screen is opened by
- calling {@link android.app.Activity#startActivity(android.content.Intent) startActivity}
- and passing in an {@link android.content.Intent Intent} object, which specifies
- the criteria for the handling screen. To specify a specific screen, call Intent.setClass
- or setClassName with the exact activity class to open. Otherwise, set a variety
- of values and data, and let Android decide which screen is appropriate to open.
- Android will find one or zero Activities that match the specified requirements;
- it will never open multiple activities for a single request. More information
- on Intents and how Android resolves them to a specific class is given in the
- {@link android.content.Intent Intent} topic. </p>
-<a name="intentexamples" id="intentexamples"></a><h3>Some Intent examples </h3>
-<p>The following snippet loads the com.android.samples.Animation1 class, and
- passes it some arbitrary data.:</p>
-<pre>Intent myIntent = new Intent();
-myIntent.setClassName("com.android.samples", "com.android.samples.Animation1");
-myIntent.putExtra("com.android.samples.SpecialValue", "Hello, Joe!"); // key/value pair, where key needs current package prefix.
-startActivity(myIntent); </pre>
-<p>The next snippet requests that a Web page be opened by specifying the VIEW action,
- and a URI data string starting with "http://" schema:</p>
-<pre>Intent myIntent = new Intent(Intent.VIEW_ACTION, Uri.parse("http://www.google.com"));</pre>
-<p>Here is the intent filter from the AndroidManifest.xml file for com.android.browser:</p>
-<pre><intent-filter>
- <action android:name="android.intent.action.VIEW" />
- <category android:name="android.intent.category.DEFAULT" />
- <scheme android:name="http" />
- <scheme android:name="https" />
- <scheme android:name="file" />
-</intent-filter> </pre>
-<p>Android defines a number of standard values, for instance the action constants
- defined by {@link android.content.Intent}. You can define custom values, but
- both the caller and handler must use them. See the <intent-filter>
- tag description in <a href="{@docRoot}guide/topics/manifest/manifest-intro.html">The AndroidManifest.xml
- File</a> for more information on the manifest syntax for the handling
- application. </p>
-<a name="returningaresult" id="returningaresult"></a><h3>Returning a Result from a Screen</h3>
-<p>A window can return a result after it closes. This result will be passed back
- into the calling Activity's {@link android.app.Activity#onActivityResult(int,int,android.content.Intent)
- onActivityResult()} method, which can supply an Intent containing arbitrary data, along with
- the request code passed to startActivityForResult(). Note that you must call the {@link
- android.app.Activity#startActivityForResult(android.content.Intent,int) startActivityForResult()}
- method that accepts a request code parameter to get this callback. The following
- code demonstrates opening a new screen and retrieving a result. </p>
-<pre>// Open the new screen.
-public void onClick(View v){
- // Start the activity whose result we want to retrieve. The
- // result will come back with request code GET_CODE.
- Intent intent = new Intent(this, com.example.app.ChooseYourBoxer.class);
- startActivityForResult(intent, CHOOSE_FIGHTER);
-}
-
-// Listen for results.
-protected void onActivityResult(int requestCode, int resultCode, Intent data){
- // See which child activity is calling us back.
- switch (requestCode) {
- case CHOOSE_FIGHTER:
- // This is the standard resultCode that is sent back if the
- // activity crashed or didn't doesn't supply an explicit result.
- if (resultCode == RESULT_CANCELED){
- myMessageboxFunction("Fight cancelled");
- }
- else {
- myFightFunction(data);
- }
- default:
- break;
- }
-}
-
-// Class SentResult
-// Temporary screen to let the user choose something.
- private OnClickListener mLincolnListener = new OnClickListener(){
- public void onClick(View v) {
- Bundle stats = new Bundle();
- stats.putString("height","6\'4\"");
- stats.putString("weight", "190 lbs");
- stats.putString("reach", "74\"");
- setResult(RESULT_OK, "Lincoln", stats);
- finish();
- }
- };
-
- private OnClickListener mWashingtonListener = new OnClickListener() {
- public void onClick(View v){
- Bundle stats = new Bundle();
- stats.putString("height","6\'2\"");
- stats.putString("weight", "190 lbs");
- stats.putString("reach", "73\"");
- setResult(RESULT_OK, "Washington", stats);
- finish();
- }
- };
- </pre>
-<h3>Lifetime of the new screen </h3>
-<p>An activity can remove itself from the history stack by calling {@link android.app.Activity#finish()
- Activity.finish()} on itself, or the activity that opened the screen can call
- {@link android.app.Activity#finishActivity(int) Activity.finishActivity()}
- on any screens that it opens to close them. </p>
-<a name="listening" id="listening"></a><h2>Listening for Button Clicks</h2>
-<p>Button click and other UI event capturing are covered in <a
-href="{@docRoot}guide/topics/ui/ui-events.html">Input Events</a>.</p>
-<a name="configurewindowproperties" id="configurewindowproperties"></a><h2>Configuring General Window Properties</h2>
-<p>You can set a number of general window properties, such as whether to display
- a title, whether the window is floating, and whether it displays an icon, by
- calling methods on the {@link android.view.Window Window} member
- of the underlying View object for the window. Examples include calling {@link
- android.app.Activity#getWindow() getWindow().requestFeature()} (or the convenience
- method {@link android.app.Activity#requestWindowFeature(int) requestWindowFeature(<em>some_feature</em>)})
- to hide the title. Here is an example of hiding the title bar:</p>
-<pre>//Hide the title bar
-requestWindowFeature(Window.FEATURE_NO_TITLE);
-</pre>
-<p>A better way to achieve the same end is to specify a theme in your Android
-Manifest file:</p>
-<pre><application android:icon="@drawable/icon" android:theme="@android:style/Theme.NoTitleBar">
-</pre>
-<p>This is preferable because it tells the system not to show a title bar while
-your application is starting up. With the explicit method call, your application
-will have a title bar visible to the user until <code>onCreate</code> runs.</p>
-<p>(Note that this can be applied to either the <code><application></code>
-tag or to individual <code><activity></code> tags.)</p>
-<p class="caution"><strong>Caution:</strong> This theme will also hide the Action Bar on Android
-3.0 and higher. If you want to keep the Action Bar, but hide the title bar, see how you can <a
-href="{@docRoot}guide/topics/ui/themes.html#SelectATheme">select a theme based on platform
-version</a>.</p>
-<a name="localhostalias" id="localhostalias"></a><h2>Referring to localhost from the emulated
-environment</h2>
-<p>
-If you need to refer to your host computer's <em>localhost</em>, such as when you
-want the emulator client to contact a server running on the same host, use the alias
-<code>10.0.2.2</code> to refer to the host computer's loopback interface.
-From the emulator's perspective, localhost (<code>127.0.0.1</code>) refers to its own
-loopback interface.
-</p>
-<a name="appstate" id="appstate"></a><h2>Storing and Retrieving State</h2>
-<p>If your application is dumped from memory because of space concerns, it will lose
- all user interface state information such as checkbox state and text box values
- as well as class member values. Android calls {@link android.app.Activity#onSaveInstanceState(android.os.Bundle)
- Activity.onSaveInstanceState} before it pauses the application. This method hands in a {@link
- android.os.Bundle Bundle} that can be used to store name/value pairs that will
- persist and be handed back to the application even if it is dropped from memory.
- Android will pass this Bundle back to you when it calls {@link android.app.Activity#onCreate(android.os.Bundle)
- onCreate()}. This Bundle only exists while the application is still in the history
- stack (whether or not it has been removed from memory) and will be lost when
- the application is finalized. See the topics for {@link android.app.Activity#onSaveInstanceState} and
- {@link android.app.Activity#onCreate} for
- examples of storing and retrieving state.</p>
-<p>Read more about the lifecycle of an activity in <a
-href="{@docRoot}guide/topics/fundamentals/activities.html">Activities</a> document.</p>
-<h3>Storing and Retrieving Larger or More Complex Persistent Data<a name="storingandretrieving" id="storingandretrieving"></a></h3>
-<p>Your application can store files or complex collection objects, and reserve them
- for private use by itself or other activities in the application, or it can expose
- its data to all other applications on the device. See <a href="{@docRoot}guide/topics/data/data-storage.html">Storing,
- Retrieving, and Exposing Data</a> to learn how to store and retrieve private data,
- how to store and retrieve common data from the device, and how to expose your
- private data to other applications.</p>
-<a name="playback" id="playback"></a><h2>Playing Media Files</h2>
-<p>Please see the document <a href="{@docRoot}guide/topics/media/index.html">Audio and Video</a> for more details.</p>
-<a name="broadcastreceivers" id="broadcastreceivers"></a><h2>Listening For and Broadcasting Global Messages, and Setting Alarms</h2>
-<p>You can create a listening class that can be notified or even instantiated whenever
- a specific type of system message is sent.
-</p>
-<p>The listening classes, called broadcast receivers, extend {@link android.content.BroadcastReceiver
- BroadcastReceiver}. If you want Android to instantiate the object whenever an appropriate
- intent notification is sent, define the receiver with a <code><receiver></code> element
- in the AndroidManifext.xml file. If the caller is expected to instantiate the
- object in preparation to receive a message, this is not required. The receiver
- will get a call to their {@link android.content.BroadcastReceiver#onReceive(android.content.Context,android.content.Intent)
- BroadcastReceiver.onReceive()} method. A receiver can define an <code><intent-filter></code> tag
- that describes the types of messages it will receive. Just as Android's IntentResolver
- will look for appropriate Activity matches for a startActivity() call, it will
- look for any matching Receivers (but it will send the message to all matching
- receivers, not to the "best" match). </p>
-<p>To send a notification, the caller creates an {@link android.content.Intent Intent}
- object and calls {@link android.app.Activity#sendBroadcast(android.content.Intent)
- Context.sendBroadcast()} with that Intent. Multiple recipients can receive
- the same message. You can broadcast an Intent message to an intent receiver in
- any application, not only your own. If the receiving class is not registered
- using <code><receiver></code> in its manifest, you can dynamically instantiate
- and register a receiver by calling {@link android.content.Context#registerReceiver(android.content.BroadcastReceiver,android.content.IntentFilter)
- Context.registerReceiver()}. </p>
-<p>Receivers can include intent filters to specify what kinds of intents they are
- listening for. Alternatively, if you expect a single known caller to contact
- a single known receiver, the receiver does not specify an intent filter, and
- the caller specifies the receiver's class name in the Intent by calling {@link
- android.content.Intent#setClassName(java.lang.String, java.lang.String) Intent.setClassName()}
- with the recipient's class name. The recipient receives a {@link android.content.Context
- Context} object that refers to its own package, not to the package of the sender.</p>
-<p><em><strong>Note:</strong></em> If a receiver or broadcaster
- enforces permissions, your application might need to request permission
- to send or receive messages from that object. You can request permission by using
- the <uses-permission> tag in the manifest. </p>
-<p>Here is a code snippet of a sender and receiver. This example does not demonstrate
- registering receivers dynamically. For a full code example, see the AlarmService
- class in the ApiDemos project.</p>
-<h3>Sending the message</h3>
-<pre>// We are sending this to a specific recipient, so we will
-// only specify the recipient class name.
-Intent intent = new Intent(this, AlarmReceiver.class);
-intent.putExtra("message","Wake up.");
-sendBroadcast(intent);
-</pre>
-<h3>Receiving the message</h3>
-<p><strong>Receiver AndroidManifest.xml </strong>(because there is no intent filter
- child, this class will only receive a broadcast when the receiver class is specified
- by name, as is done in this example):</p>
-<pre>
-<receiver class=".AlarmReceiver" /></pre>
-<p><strong>Receiver Java code: </strong></p>
-<pre>
-public class AlarmReceiver extends BroadcastReceiver{
- // Display an alert that we've received a message.
- @Override
- public void onReceive(Context context, Intent intent){
- // Send a text notification to the screen.
- NotificationManager nm = (NotificationManager)
- context.getSystemService(Context.NOTIFICATION_SERVICE);
- nm.notifyWithText(R.id.alarm,
- "Alarm!!!",
- NotificationManager.LENGTH_SHORT,
- null);
- }
-} </pre>
-<h3>Other system messages</h3>
-<p>You can listen for other system messages sent by Android as well, such as USB
- connection/removal messages, SMS arrival messages, and timezone changes. See
- {@link android.content.Intent} for a list of broadcast messages to listen for.
- Messages are marked "Broadcast Action" in the documentation. </p>
-<h3>Listening for phone events<a name="phoneevents" id="phoneevents"></a></h3>
-<p>The {@link android.telephony android.telephony} package overview page describes how to
- register to listen for phone events. </p>
-<a name="alarms" id="alarms"></a><h3>Setting Alarms </h3>
-<p>Android provides an {@link android.app.AlarmManager AlarmManager} service that
- will let you specify an Intent to send at a designated time. This intent is typically
- used to start an application at a preset time. (Note: If you want to send
- a notification to a sleeping or running application, use {@link android.os.Handler
- Handler} instead.)</p>
-<a name="alerts" id="alerts"></a><h2>Displaying Alerts</h2>
-<p>There are two major kinds of alerts that you may display to the user:
-(1) Normal alerts are displayed in response to a user action, such as
-trying to perform an action that is not allowed. (2) Out-of-band alerts,
-called notifications, are
-displayed as a result of something happening in the background, such as the
-user receiving new e-mail.</p>
-
-<a name="dialogsandalerts" id="dialogsandalerts"></a><h3>Normal Alerts</h3>
-
-<p>Android provides a number of ways for you to show popup notifications to your
- user as they interact with your application. </p>
-<table width="100%" border="1">
- <tr>
- <th scope="col">Class</th>
- <th scope="col">Description</th>
- </tr>
- <tr>
- <td>{@link android.app.Dialog app.Dialog}</td>
- <td>A generic floating dialog box with a layout that you design. </td>
- </tr>
- <tr>
- <td><p>{@link android.app.AlertDialog app.AlertDialog}</p></td>
- <td>A popup alert dialog with two buttons (typically OK and Cancel) that
- take callback handlers. See the section after this table for more details. </td>
- </tr>
- <tr>
- <td>{@link android.app.ProgressDialog ProgressDialog} </td>
- <td>A dialog box used to indicate progress of an operation with a known progress
- value or an indeterminate length (setProgress(bool)). See <strong>Views</strong> > <strong>Progress Bar</strong> in
- ApiDemos for examples. </td>
- </tr>
- <tr>
- <td>Activity</td>
- <td>By setting the theme of an activity to
- {@link android.R.style#Theme_Dialog
- android:theme="@android:style/Theme.Dialog"},
- your activity will take on
- the appearance of a normal dialog, floating on top of whatever was
- underneath it. You usually set the theme through the
- {@link android.R.attr#theme android:theme} attribute in your AndroidManifest.xml.
- The advantage of this
- over Dialog and AlertDialog is that Application has a much better managed
- life cycle than dialogs: if a dialog goes to the background and is killed,
- you cannot recapture state, whereas Application exposes a {@link android.os.Bundle
- Bundle} of saved values in <code>onCreate()</code> to help you maintain state.</td>
- </tr>
-</table>
-<h3>AlertDialog</h3>
-<p>This is a basic warning dialog box that lets you configure a message, button text,
- and callback. You can create one by calling using the {@link
- android.app.AlertDialog.Builder} class, as shown here. </p>
-<pre>private Handler mHandler = new Handler() {
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case ACCEPT_CALL:
- answer(msg.obj);
- break;
-
- case BOUNCE_TO_VOICEMAIL:
- voicemail(msg.obj);
- break;
-
- }
- }
-};
-
-
-private void IncomingMotherInlawCall(Connection c) {
- String Text;
-
- // "Answer" callback.
- Message acceptMsg = Message.obtain();
- acceptMsg.target = mHandler;
- acceptMsg.what = ACCEPT_CALL;
- acceptMsg.obj = c.getCall();
-
- // "Cancel" callback.
- final Message rejectMsg = Message.obtain();
- rejectMsg.target = mHandler;
- rejectMsg.what = BOUNCE_TO_VOICEMAIL;
- rejectMsg.obj = c.getCall();
-
- new AlertDialog.Builder(this)
- .setMessage("Phyllis is calling")
- .setPositiveButton("Answer", acceptMsg)
- .setOnCanceListener(new OnCancelListener() {
- public void onCancel(DialogInterface dialog) {
- rejectMsg.sendToTarget();
- }});
- .show();
-} </pre>
-
-<h3>Notifications</h3>
-
-<p>Out-of-band alerts should always be displayed using the
-{@link android.app.NotificationManager}, which allows you to tell the user
-about something they may be interested in without disrupting what they are
-currently doing. A notification can be anything from a brief pop-up box
-informing the user of the new information, through displaying a persistent
-icon in the status bar, to vibrating, playing sounds, or flashing lights to
-get the user's attention. In all cases, the user must explicitly shift their
-focus to the notification before they can interact with it.</p>
-
-<p>The following code demonstrates using NotificationManager to display a basic text
- popup when a new SMS message arrives in a listening service, and provides the
- current message count. You can see several more examples in the ApiDemos application,
- under app/ (named <em>notification</em>*.java).</p>
-<pre>static void setNewMessageIndicator(Context context, int messageCount){
- // Get the static global NotificationManager object.
- NotificationManager nm = NotificationManager.getDefault();</p>
-
- // If we're being called because a new message has been received,
- // then display an icon and a count. Otherwise, delete the persistent
- // message.
- if (messageCount > 0) {
- nm.notifyWithText(myApp.NOTIFICATION_GUID, // ID for this notification.
- messageCount + " new message" + messageCount > 1 ? "s":"", // Text to display.
- NotificationManager.LENGTH_SHORT); // Show it for a short time only.
- }
-}</pre>
-<p>To display a notification in the status bar and have it launch an intent when
- the user selects it (such as the new text message notification does), call {@link
- android.app.NotificationManager#notify(int, android.app.Notification) NotificationManager.notify()},
- and pass in vibration patterns, status bar icons, or Intents to associate with
- the notification. </p>
-<a name="progressbar" id="progressbar"></a><h2>Displaying a Progress Bar</h2>
-<p>An activity can display a progress bar to notify the user that something is happening.
- To display a progress bar in a screen, call {@link android.app.Activity#requestWindowFeature(int)
- Activity.requestWindowFeature(Window.FEATURE_PROGRESS)}. To set the value
- of the progress bar, call {@link android.view.Window#setFeatureInt(int,int)
- Activity.getWindow().setFeatureInt(Window.FEATURE_PROGRESS, <em>level</em>)}.
- Progress bar values are from 0 to 9,999, or set the value to 10,000 to make the
- progress bar invisible. </p>
-<p>You can also use the {@link android.app.ProgressDialog ProgressDialog} class,
- which enables a dialog box with an embedded progress bar to send a "I'm working
- on it" notification to the user. </p>
-<a name="addmenuitems" id="addmenuitems"></a><h2>Adding Items to the Screen Menu</h2>
-<p>See <a href="{@docRoot}guide/topics/ui/menus.html">Menus</a>.</p>
-
-<a name="webpage" id="webpage"></a><h2>Display a Web Page</h2>
-<p>Use the {@link android.webkit.WebView webkit.WebView} object. </p>
-<a name="binding" id="binding"></a><h2>Binding to Data</h2>
-<p>You can bind a ListView to a set of underlying data by using a shim class called
- {@link android.widget.ListAdapter ListAdapter} (or a subclass). ListAdapter subclasses
- bind to a variety of data sources, and expose a common set of methods such as
- getItem() and getView(), and uses them to pick View items to display in its list.
- You can extend ListAdapter and override getView() to create your own custom list
- items. There are essentially only two steps you need to perform to bind to data: </p>
-<ol>
- <li>Create a ListAdapter object and specify its data source</li>
- <li>Give the ListAdapter to your ListView object.</li>
-</ol>
-<p>That's it!</p>
-<p>Here's an example of binding a ListActivity screen to the results from a cursor
- query. (Note that the setListAdapter() method shown is a convenience method that
- gets the page's ListView object and calls setAdapter() on it.)</p>
-<pre>// Run a query and get a Cursor pointing to the results.
-Cursor c = People.query(this.getContentResolver(), null);
-startManagingCursor(c);
-
-// Create the ListAdapter. A SimpleCursorAdapter lets you specify two interesting things:
-// an XML template for your list item, and
-// The column to map to a specific item, by ID, in your template.
-ListAdapter adapter = new SimpleCursorAdapter(this,
- android.R.layout.simple_list_item_1, // Use a template that displays a text view
- c, // Give the cursor to the list adapter
- new String[] {People.NAME} , // Map the NAME column in the people database to...
- new String[] {"text1"}); // The "text1" view defined in the XML template
-setListAdapter(adapter);</pre>
-<p>See view/List4 in the ApiDemos project for an example of extending ListAdapter
- for a new data type. </p>
-
-<a name="handle"></a>
-
-<h2>Getting a Handle to a Screen Element</h2>
-<p>You can get a handle to a screen element by calling {@link
-android.app.Activity#findViewById(int) Activity.findViewById}. You can then use
-the handle to set or retrieve any values exposed by the object. </p>
-<a name="captureimages" id="captureimages"></a><h2>Capture Images from the Phone Camera</h2>
-<p>You can hook into the device's camera onto your own Canvas object by using the
- {@link android.hardware.Camera Camera} class. See that class's documentation,
- and the ApiDemos project's Camera Preview application (Graphics/Camera Preview)
- for example code. </p>
-
-
-<a name="threading" id="threading"></a><h2>Handling Expensive Operations in the UI Thread</h2>
-<p>Avoid performing long-running operations (such as network I/O) directly in the UI thread —
-the main thread of an application where the UI is run — or your application may be blocked
-and become unresponsive. Here is a brief summary of the recommended approach for handling expensive operations:</p>
-<ol>
-<li>Create a Handler object in your UI thread</li>
-<li>Spawn off worker threads to perform any required expensive operations</li>
-<li>Post results from a worker thread back to the UI thread's handler either through a Runnable or a {@link android.os.Message}</li>
-<li>Update the views on the UI thread as needed</li>
-</ol>
-
-<p>The following outline illustrates a typical implementation:</p>
-
-<pre>
-public class MyActivity extends Activity {
-
- [ . . . ]
- // Need handler for callbacks to the UI thread
- final Handler mHandler = new Handler();
-
- // Create runnable for posting
- final Runnable mUpdateResults = new Runnable() {
- public void run() {
- updateResultsInUi();
- }
- };
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- [ . . . ]
- }
-
- protected void startLongRunningOperation() {
-
- // Fire off a thread to do some work that we shouldn't do directly in the UI thread
- Thread t = new Thread() {
- public void run() {
- mResults = doSomethingExpensive();
- mHandler.post(mUpdateResults);
- }
- };
- t.start();
- }
-
- private void updateResultsInUi() {
-
- // Back in the UI thread -- update our UI elements based on the data in mResults
- [ . . . ]
- }
-}
-</pre>
-
-<p>For further discussions on this topic, see
-<a href="{@docRoot}guide/practices/design/responsiveness.html">Designing for Responsiveness</a>
-and the {@link android.os.Handler} documentation.</p>
-
-<a name="selectingtext" id="selectingtext"></a><h2>Selecting, Highlighting, or Styling Portions of Text</h2>
-<p>You can highlight or style the formatting of strings or substrings of text in
- a TextView object. There are two ways to do this:</p>
-<ul>
- <li>If you use a <a href="{@docRoot}guide/topics/resources/string-resource.html">string resource</a>,
- you can add some simple styling, such as bold or italic using HTML notation.
- The currently supported tags are: <code>B</code> (bold),
- <code>I</code> (italic), <code>U</code> (underline),
- <code>TT</code> (monospace), <code>BIG</code>, <code>SMALL</code>,
- <code>SUP</code> (superscript), <code>SUB</code> (subscript),
- and <code>STRIKE</code> (strikethrough).
- So, for example, in res/values/strings.xml you could declare this:<br />
- <code><resources><br />
- <string name="styled_welcome_message">We
- are <b><i>so</i></b> glad to see you.</string><br />
- </resources></code></li>
- <li>To style text on the fly, or to add highlighting or more complex styling,
- you must use the Spannable object as described next. </li>
-</ul>
-<p>To style text on the fly, you must make sure the TextView is using {@link android.text.Spannable}
- storage for the text (this will always be true if the TextView is an EditText),
- retrieve its text with {@link android.widget.TextView#getText}, and call {@link
- android.text.Spannable#setSpan}, passing in a new style class from the {@link
- android.text.style} package and the selection range. </p>
-<p>The following code snippet demonstrates creating a string with a highlighted section,
- italic section, and bold section, and adding it to an EditText object. </p>
-<pre>// Get our EditText object.
-EditText vw = (EditText)findViewById(R.id.text);
-
-// Set the EditText's text.
-vw.setText("Italic, highlighted, bold.");
-
-// If this were just a TextView, we could do:
-// vw.setText("Italic, highlighted, bold.", TextView.BufferType.SPANNABLE);
-// to force it to use Spannable storage so styles can be attached.
-// Or we could specify that in the XML.
-
-// Get the EditText's internal text storage
-Spannable str = vw.getText();
-
-// Create our span sections, and assign a format to each.
-str.setSpan(new StyleSpan(android.graphics.Typeface.ITALIC), 0, 7, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
-str.setSpan(new BackgroundColorSpan(0xFFFFFF00), 8, 19, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
-str.setSpan(new StyleSpan(android.graphics.Typeface.BOLD), 21, str.length() - 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
-</pre>
-
-<a name="querymap" id="querymap"></a><h2>Utilizing attributes in a Map query</h2>
-<p>
-When using a search intent to ask the Maps activity to search for something, the Maps activity responds to the following attributes in the optional context bundle:
-</p>
-<pre>
- float "centerLatitude" default 0.0f
- float "centerLongitude" default 0.0f
- float "latitudeSpan" default 0.0f
- float "longitudeSpan" default 0.0f
- int "zoomLevel" default 10
-</pre>
-<p>
-This context information is used to center the search result in a particular area, and is equivalent to adjusting the Map activity to the described location and zoom level before issuing the query.
-</p>
-<p>
-If the latitudeSpan, longitudeSpan, and zoomLevel attributes are not consistent, then it is undefined which one takes precedence.
-</p>
-
-<a name="filelist" id="filelist"></a><h2>List of Files for an Android Application</h2>
-<p>The following list describes the structure and files of an Android application.
- Many of these files can be built for you (or stubbed out) by the android tool
- shipped in the tools/ menu of the SDK. </p>
-<table width="100%" border="0">
- <tr>
- <td width="28%" valign="top">MyApp/<br /></td>
- <td width="72%" valign="top"> </td>
- </tr>
- <tr>
- <td valign="top"> AndroidManifest.xml</td>
- <td valign="top">(<em>required</em>) Advertises the screens that this application provides,
- where they can be launched (from the main program menu or elsewhere),
- any content providers it implements and what kind of data they handle,
- where the implementation classes are, and other application-wide
- information. Syntax details for this file are described in <a href="{@docRoot}guide/topics/manifest/manifest-intro.html">The AndroidManifest.xml File</a>.</td>
- </tr>
- <tr>
- <td valign="top"> src/<br />
- /<em>myPackagePath</em>/.../<em>MyClass</em>.java</td>
- <td valign="top">(<em>required</em>) This folder holds all the source code files for your
- application, inside the appropriate package subfolders. </td>
- </tr>
- <tr>
- <td valign="top"> res/</td>
- <td valign="top">(<em>required</em>) This folder holds all the <em>resources</em> for
- your application. Resources are external data files or description files
- that are compiled into your code at build time. Files in different folders
- are compiled differently, so you must put the proper resource into the
- proper folder. (See <a href="{@docRoot}guide/topics/resources/resources-i18n.html">Resources</a> for details.)</td>
- </tr>
- <tr>
- <td valign="top"> anim/<br />
- <em>animation1</em>.xml<br />
- <em>...</em></td>
- <td valign="top">(<em>optional</em>) Holds any animation XML description files that the
- application uses. The format of these files is described in <a href="{@docRoot}guide/topics/resources/resources-i18n.html">Resources</a>. </td>
- </tr>
- <tr>
- <td valign="top"> drawable/<br />
- <em>some_picture</em>.png<br />
- <em>some_stretchable</em>.9.png<br />
- <em>some_background</em>.xml<br />
- ...</td>
- <td valign="top">(<em>optional</em>) Zero or more files that will be compiled to {@link
- android.graphics.drawable android.graphics.drawable} resources. Files
- can be image files (png, gif, or other) or XML files describing other
- graphics such as bitmaps, stretchable bitmaps, or gradients. Supported
- bitmap file formats are PNG (preferred), JPG, and GIF (discouraged),
- as well as the custom 9-patch stretchable bitmap format. These formats
- are described in <a href="{@docRoot}guide/topics/resources/resources-i18n.html">Resources</a>. </td>
- </tr>
- <tr>
- <td valign="top"> layout/<br />
- <em>screen_1_layout</em>.xml<br />
- ...<br /></td>
- <td valign="top">(<em>optional</em>) Holds all the XML files describing screens or parts
- of screens. Although you could create a screen in Java, defining them
- in XML files is typically easier. A layout file is similar in concept
- to an HTML file that describes the screen layout and components. See <a href="{@docRoot}guide/topics/ui/index.html">User Interface</a> for more information about designing screens, and <a href="{@docRoot}guide/topics/resources/available-resources.html#layoutresources">Available Resource Types</a> for the syntax of these files.</td>
- </tr>
- <tr>
- <td valign="top"> values/<br />
- arrays<br />
- classes.xml<br />
- colors.xml<br />
- dimens.xml<br />
- strings.xml<br />
- styles.xml<br />
- values.xml<br /></td>
- <td valign="top"><p>(<em>optional</em>) XML files describing additional resources
- such as strings, colors, and styles. The naming, quantity, and number
- of these files are not enforced--any XML file is compiled, but these
- are the standard names given to these files. However, the syntax
- of these files is prescribed by Android, and described in <a href="{@docRoot}guide/topics/resources/resources-i18n.html">Resources</a>. </p>
- </td>
- </tr>
- <tr>
- <td valign="top"> xml/</td>
- <td valign="top">(<em>optional</em>) XML files that can be read at run time on the device. </td>
- </tr>
- <tr>
- <td valign="top"> raw/</td>
- <td valign="top">(<em>optional</em>) Any files to be copied directly to the device. </td>
- </tr>
-</table>
-
-
-<a name="logging" ></a>
-<h2>Print Messages to a Log File</h2>
-
-<p>To write log messages from your application:</p>
-<ol><li>Import <code>android.util.Log</code>.</li>
- <li>Use <code>Log.v()</code>, <code>Log.d()</code>, <code>Log.i()</code>,
- <code>Log.w()</code>, or <code>Log.e()</code> to log messages.
- (See the {@link android.util.Log} class.)<br/> E.g.,
- <code>Log.e(this.toString(), "error: " + err.toString())</code></li>
- <li>Launch <a href="{@docRoot}guide/developing/tools/ddms.html">DDMS</a> from a terminal
- by executing <code>ddms</code> in your Android SDK <code>/tools</code> path.</li>
- <li>Run your application in the Android emulator.</li>
- <li>From the DDMS application, select the emulator
- (e.g., "emulator-5554") and click <b>Device > Run logcat...</b>
- to view all the log data.</li>
-</ol>
-<p class="note"><strong>Note:</strong> If you are running Eclipse and
-encounter a warning about the VM debug port when opening DDMS, you can ignore it
-if you're only interested in logs. However, if you want to further inspect and
-control your processes from DDMS, then you should close Eclipse before launching DDMS so that
-it may use the VM debugging port.</p>
-
-
diff --git a/docs/html/guide/faq/framework.jd b/docs/html/guide/faq/framework.jd
deleted file mode 100644
index c851e72..0000000
--- a/docs/html/guide/faq/framework.jd
+++ /dev/null
@@ -1,185 +0,0 @@
-page.title=Android Application Framework FAQ
-excludeFromSuggestions=true
-@jd:body
-
-<ul>
- <li><a href="#1">Do all the Activities and Services of an
- application run in a single process?</a></li>
- <li><a href="#2">Do all Activities run in the main thread of
- an application process?</a></li>
- <li><a href="#3">How do I pass complicated data structures
- from one Activity/Service to another?</a></li>
- <li><a href="#4">How can I check if an Activity is already
- running before starting it?</a></li>
- <li><a href="#5">If an Activity starts a remote service, is
- there any way for the Service to pass a message back to the Activity?</a></li>
- <li><a href="#6">How to avoid getting the Application not
- responding dialog?</a></li>
- <li><a href="#7">How does an application know if a package is
- added or removed?</a></li>
-</ul>
-
-
-<a name="1" id="1"></a>
-
-<h2>Do all the Activities and Services of an application run in a
-single process?</h2>
-
-<p>All Activities and Services in an application run in a single process by
-default. If needed, you can declare an <code>android:process</code> attribute
-in your manifest file, to explicitly place a component (Activity/Service) in
-another process.</p>
-
-
-
-<a name="2" id="2"></a>
-
-<h2>Do all Activities run in the main thread of an application
-process?</h2>
-
-<p>By default, all of the application code in a single process runs
-in the main UI thread. This is the same thread
-that also handles UI events. The only exception is the code that handles
-IPC calls coming in from other processes. The system maintains a
-separate pool of transaction threads in each process to dispatch all
-incoming IPC calls. The developer should create separate threads for any
-long-running code, to avoid blocking the main UI thread.</p>
-
-
-
-<a name="3" id="3"></a>
-
-<h2>How do I pass data between Activities/Services within a single
-application?</h2>
-
-<p>It depends on the type of data that you want to share:</p>
-
-<h3>Primitive Data Types</h3>
-
-<p>To share primitive data between Activities/Services in an
-application, use Intent.putExtras(). For passing primitive data that
-needs to persist use the
-<a href="{@docRoot}guide/topics/data/data-storage.html#preferences">
-Preferences</a> storage mechanism.</p>
-
-<h3>Non-Persistent Objects</h3>
-
-<p>For sharing complex non-persistent user-defined objects for short
-duration, the following approaches are recommended:
-</p>
- <h4>Singleton class</h4>
- <p>You can take advantage of the fact that your application
-components run in the same process through the use of a singleton.
-This is a class that is designed to have only one instance. It
-has a static method with a name such as <code>getInstance()</code>
-that returns the instance; the first time this method is called,
-it creates the global instance. Because all callers get the same
-instance, they can use this as a point of interaction. For
-example activity A may retrieve the instance and call setValue(3);
-later activity B may retrieve the instance and call getValue() to
-retrieve the last set value.</p>
-
- <h4>A public static field/method</h4>
- <p>An alternate way to make data accessible across Activities/Services is to use <em>public static</em>
-fields and/or methods. You can access these static fields from any other
-class in your application. To share an object, the activity which creates your object sets a
-static field to point to this object and any other activity that wants to use
-this object just accesses this static field.</p>
-
- <h4>A HashMap of WeakReferences to Objects</h4>
- <p>You can also use a HashMap of WeakReferences to Objects with Long
-keys. When an activity wants to pass an object to another activity, it
-simply puts the object in the map and sends the key (which is a unique
-Long based on a counter or time stamp) to the recipient activity via
-intent extras. The recipient activity retrieves the object using this
-key.</p>
-
-<h3>Persistent Objects</h3>
-
-<p>Even while an application appears to continue running, the system
-may choose to kill its process and restart it later. If you have data
-that you need to persist from one activity invocation to the next, you
-need to represent that data as state that gets saved by an activity when
-it is informed that it might go away.</p>
-
-<p>For sharing complex persistent user-defined objects, the
-following approaches are recommended:
-<ul>
- <li>Application Preferences</li>
- <li>Files</li>
- <li>contentProviders</li>
- <li>SQLite DB</li>
-</ul>
-</p>
-
-<p>If the shared data needs to be retained across points where the application
-process can be killed, then place that data in persistent storage like
-Application Preferences, SQLite DB, Files or ContentProviders. Please refer to
-the <a href="{@docRoot}guide/topics/data/data-storage.html">Data Storage</a>
-for further details on how to use these components.</p>
-
-
-
-
-<a name="4" id="4"></a>
-
-<h2>How can I check if an Activity is already running before starting
-it?</h2>
-
-<p>The general mechanism to start a new activity if its not running—
-or to bring the activity stack to the front if is already running in the
-background— is the to use the NEW_TASK_LAUNCH flag in the startActivity()
-call.</p>
-
-
-
-<a name="5" id="5"></a>
-
-<h2>If an Activity starts a remote service, is there any way for the
-Service to pass a message back to the Activity?</h2>
-
-<p>See the {@link android.app.Service} documentation's for examples of
-how clients can interact with a service. You can take advantage of the
-fact that your components run in the same process to greatly simplify
-service interaction from the generic remote case, as shown by the "Local
-Service Sample". In some cases techniques like singletons may also make sense.
-
-
-<a name="6" id="6"></a>
-
-<h2>How to avoid getting the Application not responding dialog?</h2>
-
-<p>Please read the <a href="{@docRoot}guide/practices/design/responsiveness.html">Designing for Responsiveness</a>
-document.</p>
-
-
-
-
-<a name="7" id="7"></a>
-
-<h2>How does an application know if a package is added or removed?
-</h2>
-
-<p>Whenever a package is added, an intent with PACKAGE_ADDED action
-is broadcast by the system. Similarly when a package is removed, an
-intent with PACKAGE_REMOVED action is broadcast. To receive these
-intents, you should write something like this:
-<pre>
- <receiver android:name ="com.android.samples.app.PackageReceiver">
- <intent-filter>
- <action android:name="android.intent.action.PACKAGE_ADDED"/>
- <action android:name="android.intent.action.PACKAGE_REMOVED"/>
-
- <data android:scheme="package" />
- </intent-filter>
- </receiver>
- </pre>
- <br>
-Here PackageReceiver is a BroadcastReceiver class.Its onReceive()
-method is invoked, every time an application package is installed or
-removed.
-
-</p>
-
-
-
diff --git a/docs/html/guide/faq/index.jd b/docs/html/guide/faq/index.jd
deleted file mode 100644
index 0c5fb0e..0000000
--- a/docs/html/guide/faq/index.jd
+++ /dev/null
@@ -1,12 +0,0 @@
-page.title=Android FAQs
-excludeFromSuggestions=true
-@jd:body
-
-<dl>
- <dt><a href="framework.html">Application Framework FAQ</a></dt>
- <dd>Common questions about the Android Application Framework.</dd>
- <dt><a href="licensingandoss.html">Open Source Licensing FAQ</a></dt>
- <dd>Common topics around licensing and Android Open Source</dd>
- <dt><a href="security.html">Android Security FAQ</a></dt>
- <dd>Answers to common questions about Android security.</dd>
-</dl>
diff --git a/docs/html/guide/faq/licensingandoss.jd b/docs/html/guide/faq/licensingandoss.jd
deleted file mode 100644
index d1dd9a7..0000000
--- a/docs/html/guide/faq/licensingandoss.jd
+++ /dev/null
@@ -1,18 +0,0 @@
-page.title=Android Open Source Licensing FAQ
-excludeFromSuggestions=true
-@jd:body
-
-<ul>
- <li><a href="#mirror">Where can I find the open source components of Android?</a></li>
- <li><a href="#timeline">When will we see more code released under open source licenses?</a></li>
- <li><a href="#apache2">Why are you releasing the code under the Apache License instead of GPLv2?</a></li>
-</ul>
-
-<a name="mirror" id="mirror"></a><h2>Where can I find the open source components of Android?</h2>
-<p>The source code for the full Android stack is available from the <a href="http://source.android.com">Android Open Source Project </a> site.
-
-<p>Other mirrored GPL and LGPL'd components are available at <a href="http://code.google.com/p/android/downloads/list"><code>http://code.google.com/p/android/downloads/list</code></a>.</p>
-<p>Notices for other licenses can be found within the SDK.</p>
-
-<a name="apache2" id="apache2"></a><h2>Why are you releasing the code under the Apache License instead of GPLv2?</h2>
-<p>One of the best explanations for the reasoning behind releasing code under Apache2 can be found in a <a href="http://arstechnica.com/news.ars/post/20071106-why-google-chose-the-apache-software-license-over-gplv2.html">ArsTechnica article</a> by Ryan Paul.</p>
diff --git a/docs/html/guide/faq/security.jd b/docs/html/guide/faq/security.jd
deleted file mode 100644
index 8ccf21f..0000000
--- a/docs/html/guide/faq/security.jd
+++ /dev/null
@@ -1,157 +0,0 @@
-page.title=Android Security FAQ
-excludeFromSuggestions=true
-@jd:body
-
-<ul>
- <li><a href="#secure">Is Android Secure?</a></li>
- <li><a href="#issue">I think I found a security flaw. How do I report
- it?</a></li>
- <li><a href="#informed">How can I stay informed about Android security?</a></li>
- <li><a href="#use">How do I securely use my Android phone?</a></li>
- <li><a href="#malware">I think I found malicious software being distributed
- for Android. How can I help?</a></li>
- <li><a href="#fixes">How will Android-powered devices receive security fixes?</a>
- </li>
- <li><a href="#directfix">Can I get a fix directly from the Android Platform
- Project?</a></li>
-</ul>
-
-
-<a name="secure" id="secure"></a><h2>Is Android secure?</h2>
-
-<p>The security and privacy of our users' data is of primary importance to the
-Android Open Source Project. We are dedicated to building and maintaining one
-of the most secure mobile platforms available while still fulfilling our goal
-of opening the mobile device space to innovation and competition.</p>
-
-<p> A comprehensive overview of the <a
-href="http://source.android.com/tech/security/index.html">Android
-security model and Android security processes</a> is provided in the Android
-Open Source Project Website.</p>
-
-<p>Application developers play an important part in the security of Android.
-The Android Platform provides developers with a rich <a
-href="http://code.google.com/android/devel/security.html">security model</a>
-that to request the capabilities, or access, needed by their
-application and to define new capabilities that other applications can request.
-The Android user can choose to grant or deny an application's request for
-certain capabilities on the handset.</p>
-
-<p>We have made great efforts to secure the Android platform, but it is
-inevitable that security bugs will be found in any system of this complexity.
-Therefore, the Android team works hard to find new bugs internally and responds
-quickly and professionally to vulnerability reports from external researchers.
-</p>
-
-
-<a name="issue" id="issue"></a><h2>I think I found a security flaw. How do I
-report it?</h2>
-
-<p>You can reach the Android security team at security@android.com. If you like, you
-can protect your message using our <a
-href="http://code.google.com/android/security_at_android_dot_com.txt">PGP
-key</a>.</p>
-
-<p>We appreciate researchers practicing responsible disclosure by emailing us
-with a detailed summary of the issue and keeping the issue confidential while
-users are at risk. In return, we will make sure to keep the researcher informed
-of our progress in issuing a fix. </p>
-
-<p>Vulnerabilities specific to Android OEMs should be reported to the relevant
-vendor. An incomplete list of Android vendor security contacts can be found below.
-To be added to this list, please contact security@android.com.</p>
-
-<ul>
- <li><a href="http://www.htc.com/www/terms/product-security/">HTC</a></li>
- <li><a href="http://www.motorolasolutions.com/US-EN/About/Security%20Vulnerability">Motorola</a></li>
- <li><a href="http://developer.samsung.com/notice/How-to-Use-the-Forum">Samsung</a> - m.security@samsung.com</li>
-</ul>
-
-<a name="informed" id="informed"></a><h2>How can I stay informed about Android security?</h2>
-
-<p>For general discussion of Android platform security, or how to use
-security features in your Android application, please subscribe to <a
-href="http://groups.google.com/group/android-security-discuss">android-security-discuss</a>.
-</p>
-
-
-<a name="use" id="use"></a><h2>How do I securely use my Android phone?</h2>
-
-<p>Android was designed so that you can safely use your phone without making
-any changes to the device or installing any special software. Android applications
-run in an Application Sandbox that limits access to sensitive information or data
-with the users permission.</p>
-
-<p>To fully benefit from the security protections in Android, it is important that
-users only download and install software from known sources.</p>
-
-<p>As an open platform, Android allows users to visit any website and load
-software from any developer onto a device. As with a home PC, the user must be
-aware of who is providing the software they are downloading and must decide
-whether they want to grant the application the capabilities it requests.
-This decision can be informed by the user's judgment of the software
-developer's trustworthiness, and where the software came from.</p>
-
-
-<a name="malware" id="malware"></a><h2>I think I found malicious software being
-distributed for Android. How can I help?</h2>
-
-<p>Like any other platform, it will be possible for unethical developers
-to create malicious software, known as <a
-href="http://en.wikipedia.org/wiki/Malware">malware</a>, for Android. If you
-think somebody is trying to spread malware, please let us know at
-security@android.com. Please include as
-much detail about the application as possible, with the location it is
-being distributed from and why you suspect it of being malicious software.</p>
-
-<p>The term <i>malicious software</i> is subjective, and we cannot make an
-exhaustive definition. Some examples of what the Android Security Team believes
-to be malicious software is any application that:
-<ul>
- <li>uses a bug or security vulnerability to gain permissions that have not
- been granted by the user</li>
- <li>shows the user unsolicited messages (especially messages urging the
- user to buy something);</li>
- <li>resists (or attempts to resist) the user's effort to uninstall it;</li>
- <li>attempts to automatically spread itself to other devices;</li>
- <li>hides its files and/or processes;</li>
- <li>discloses the user's private information to a third party, without the
- user's knowledge and consent;</li>
- <li>destroys the user's data (or the device itself) without the user's
- knowledge and consent;</li>
- <li>impersonates the user (such as by sending email or buying things from a
- web store) without the user's knowledge and consent; or</li>
- <li>otherwise degrades the user's experience with the device.</li>
-</ul>
-</p>
-
-
-<a name="fixes" id="fixes"></a><h2>How do Android-powered devices receive security
-fixes?</h2>
-
-<p>The manufacturer of each device is responsible for distributing software
-upgrades for it, including security fixes. Many devices will update themselves
-automatically with software downloaded "over the air", while some devices
-require the user to upgrade them manually.</p>
-
-<p>Google provides software updates for a number of Android devices, including
-the <a href="http://www.google.com/nexus">Nexus</a>
-series of devices, using an "over the air" (OTA) update. These updates may include
-security fixes as well as new features.</p>
-
-<a name="directfix" id="directfix"></a><h2>Can I get a fix directly from the
-Android Platform Project?</h2>
-
-<p>Android is a mobile platform that is released as open source and
-available for free use by anybody. This means that there are many
-Android-based products available to consumers, and most of them are created
-without the knowledge or participation of the Android Open Source Project. Like
-the maintainers of other open source projects, we cannot build and release
-patches for the entire ecosystem of products using Android. Instead, we will
-work diligently to find and fix flaws as quickly as possible and to distribute
-those fixes to the manufacturers of the products through the open source project.</p>
-
-<p>If you are making an Android-powered device and would like to know how you can
-properly support your customers by keeping abreast of software updates, please
-contact us at <a
-href="mailto:info@openhandsetalliance.com">info@openhandsetalliance.com</a>.</p>
diff --git a/docs/html/guide/faq/troubleshooting.jd b/docs/html/guide/faq/troubleshooting.jd
deleted file mode 100644
index 8bb7eeb..0000000
--- a/docs/html/guide/faq/troubleshooting.jd
+++ /dev/null
@@ -1,336 +0,0 @@
-page.title=Troubleshooting
-excludeFromSuggestions=true
-@jd:body
-
-
-<p>Here are some tips and tricks for common Android errors. Don't forget to use the
- ddms logcat capability to get a deeper view when errors occur.
- See the <a href="{@docRoot}guide/developing/debugging/index.html">Debugging</a> documentation for more information.</p>
-<ul>
- <li><a href="#installeclipsecomponents">ADT Installation Error: "requires plug-in org.eclipse.wst.sse.ui".</a></li>
- <li><a href="#nodevice">ADB reports "no device" when an emulator is running</a></li>
- <li><a href="#noapp">My new application/activity isn't showing up in the device application
- list </a></li>
- <li><a href="#noupdate">I updated my app, but the updates don't seem to be showing up on
- the device</a></li>
- <li><a href="#layout_wilih">I'm getting a "Binary XML file line #2: You must supply a layout_wilih
- attribute" error when I start an application</a></li>
- <li><a href="#permission">My request to (<em>make a call, catch an incoming SMS, receive
- a notification, send an intent to an Android application</em>) is being
- ignored</a></li>
- <li><a href="#build">Help! My project won't build in Eclipse</a></li>
- <li><a href="#eclipse">Eclipse isn't talking to the emulator</a></li>
- <li><a href="#majorminor">When I go to preferences in Eclipse and select "Android", I get the following error message: Unsupported major.minor version 49.0.</a></li>
- <li><a href="#apidemosreinstall">I can't install ApiDemos apps in my IDE because of a signing error</a></li>
- <li><a href="#gesturebuilderinstall">I can't install the GestureBuilder sample
-app in the emulator</a></li>
- <li><a href="#signingcalendar">I can't compile my app because the build tools generated an expired debug certificate</a></li>
- <li><a href="#manifestfiles">Unable to view manifest files from within Eclipse</a></li>
-</ul>
-
-<a name="installeclipsecomponents" id="installeclipsecomponents"></a><h2>ADT Installation Error: "requires plug-in org.eclipse.wst.sse.ui".</h2>
-<p>
-The "Android Editors" feature of the ADT Plugin requires specific Eclipse components, such as WST. If you
-encounter this error message during ADT installation, you need to install the
-required Eclipse components and then try the ADT installation again. Follow the steps below to install the required components for the
-Android Editors feature, based on the version of Eclipse that you are using.</p>
-
-<table style="font-size:100%">
-<tr><th>Eclipse 3.3 (Europa)</th><th>Eclipse 3.4 (Ganymede)</th></tr>
-<tr>
-<td width="50%">
-<ol>
-<li>From the dialog where you select the <strong>Update sites to visit</strong>, select the checkboxes for both the
-ADT site, and the Callisto/Europa/Ganymede Discovery Site (you may want to
-check <strong>Automatically select mirrors</strong> at the bottom).</li>
-<li>Click <strong>Finish</strong>.</li>
-<li>In the <strong>Next</strong> dialog, select the Android Plugins.</li>
-<li>Now, expand the tree item of the discovery site. It seems that if you
-don't do it, it doesn't load the content of the discovery site.</li>
-<li>On the right, click <strong>Select required</strong>. This will select all the components
-that are required to install the Android plugin (wst, emf, etc...).</li>
-<li>Click <strong>Next</strong>, accept the agreement, click <strong>Install All</strong>, and restart Eclipse.</li>
-</ol>
-</td>
-<td>
-<ol>
- <li>Select <strong>Help</strong> > <strong>Software Updates...</strong></li>
- <li>Select the <strong>Installed Software</strong> tab.</li>
- <li>Click <strong>Update...</strong></li>
- <li>If an update for ADT is available, select it and click <strong>Finish</strong>.</li>
-</ol>
-</td>
-</tr>
-</table>
-
-
-</p>
-<a name="nodevice"></a><h2>ADB reports "no device" when an emulator is running</h2>
- <p>Try restarting adb by stopping it (<code>adb
- kill-server</code>) then any other adb command to restart it.</p>
-
-<a name="noapp"></a><h2>My new application/activity isn't showing up in the
- applications list </h2>
-<ul>
- <li>You often must restart your device or emulator before a new activity shows
- up in the applications list. This is particularly true when it is a completely
- new application with a new AndroidManifest.xml file.</li>
- <li>If this is for a new activity in an existing AndroidManifest.xml file, did
- you include an <code><activity></code> tag for your app (or a <code><service></code> tag
- for a service, or a <code><receiver></code> tag for a receiver, etc.)? </li>
- <li>Make sure that your AndroidManifest.xml file is valid. Errors in attribute
- values, such as the <em>value </em> attribute in <code><action <em>value</em>="<em><something></em>"></code>
- will often not be caught by compilers, but will prevent your application
- from being displayed because the intent filter will not be matched. Extra
- spaces or other characters can often sneak into these strings.</li>
- <li>Did you send your .apk file to the device (<a href="{@docRoot}guide/developing/tools/adb.html#move">adb install</a>)?</li>
- <li>Run logcat on your device (<code>adb logcat</code>)
- and then install your .apk file. Check the logcat output to see whether the
- application is being installed and recognized properly. Here's sample output
- from a successful installation:
-<pre>I/FileObserver( 414): *** onEvent wfd: 3 mask: 8 path: MyRSSReader.apk
-D/PackageManager( 414): Scanning package: /data/app/MyRSSReader.apk
-D/PackageManager( 414): Adding package com.example.codelab.rssexample
-D/PackageManager( 414): Registered content provider: my_rss_item, className = com.example.codelab.rssexample.RssContentProvider, isSyncable = false
-D/PackageManager( 414): Providers: com.example.codelab.rssexample.RssContentProvider
-D/PackageManager( 414): Activities: com.example.codelab.rssexample.MyRssReader com.example.codelab.rssexample.MyRssReader2 </pre>
- </li>
- <li>If logcat shows that the package manager is having problems loading the manifest
- file, force your manifest to be recompiled by adding a space in the file and
- compiling it.</li>
-</ul>
-<a name="noupdate"></a><h2>I updated my app, but the updates don't seem to be showing up on the device</h2>
- <p>Did you remember to send your .apk file to the device (<a href="{@docRoot}guide/developing/tools/adb.html#move">adb
- install</a>)?</p>
-
-<a name="layout_wilih"></a><h2>I'm getting a "Binary XML file line #2: You must supply a layout_wilih
- attribute" error
- when I start an application (but I declare a layout_wilih attribute <em>right
- there!!!</em>)</h2>
-<ul>
- <li>Make sure that the SDK you are building with is the same version as the Android
- OS that you are running on. </li>
- <li>Make sure that you're calling setContentView() early in your onCreate() method.
- Calling other methods, such as setListAdapter() before calling setContentView()
- can sometimes create odd errors when Android tries to access screen elements
- that haven't been set before.</li>
-</ul>
-<a name="permission"></a><h2>My request to (<em>make a call, catch an incoming SMS,
-receive a notification, send an intent to an Android application</em>) is being
-ignored</h2>
- <p>You might not have permission (or might not have requested permission) to
- call this activity or receive this intent. Many standard Android activities,
- such as making a call, have a permission assigned to it to prevent arbitrary
- applications from sending or receiving requests. See <a
- href="{@docRoot}guide/topics/security/security.html">Security and
- Permissions</a> for more information on permissions, and
- {@link android.Manifest.permission Manifest.permission} for a list of
- standard permissions supported by the Android platform.
-</p>
-<a name="build"></a><h2>Help! My project won't build in Eclipse</h2>
-<p>If your project doesn't build, you may notice symptoms such as new
-resources added in the <code>res/</code> sub-folders not showing up in the R class,
-the emulator not being started, not being able to run the application, or even seeming to run an old version of the application.</p>
-<p>To troubleshoot these types of problems, first try:</p>
-<ol>
- <li>Switch to the DDMS view in Eclipse (if you don't already have it open):
- <ol type="a">
- <li>From the menu select <code>Window > Open Perspective > Other</code></li>
- <li>Select DDMS from the list and hit OK</li>
- </ol>
- </li>
- <li>In the Devices panel (top right panel by default), click on the down triangle
- to bring up the panel menu</li>
- <li>Select <code>Reset ADB</code> from the menu, and then try running the
- application again</li>
-</ol>
-<p>If the above still doesn't work, you can try these steps:</p>
-<ol>
- <li>
- Check the console and problems tabs at the bottom of the Eclipse UI
- </li>
- <li>
- If there are problems listed in either place, they should give you a clue
- what is wrong
- </li>
- <li>
- If you aren't sure if the problems are fresh or stale, clear the console
- with a right click > Clear, then clean the project
- </li>
- <li>
- To clean the project (a good idea with any kind of build error), select
- Project > Clean from the eclipse main menu, then select the project you
- are working on (or clean all)
- </li>
-</ol>
-<a name="eclipse"></a><h2>Eclipse isn't talking to the emulator</h2>
-<p>When communication doesn't seem to be happening between Eclipse and the emulator, symptoms can include: nothing happening when you press run, the emulator hanging waiting
-for a debugger to connect, or errors that Eclipse reports about not being able
-to find the emulator or shell. By far the most common symptom is that when you press run, the emulator starts (or
-is already running), but the application doesn't start.</p>
-<p>
-You may find any of these steps will fix the problem and with practice you
-probably can figure out which one you need to do for your particular issue, but
-to start with, the safest option is to run through all of them in order:</p>
-<ol>
- <li>
- Quit the emulator if it is running
- </li>
- <li>
- Check that any emulator processes are killed (sometimes they can hang, use ps on unix or mac, or task manager in the process view on
- windows).
- </li>
- <li>
- Quit Eclipse
- </li>
- <li>
- From the command line, type:
-<pre>adb kill-server </pre>
- </li>
- <li>
- Start Eclipse and try again
- </li>
-</ol>
-
-<a name="majorminor"></a><h2>When I go to preferences in Eclipse and select "Android", I get the following error message: Unsupported major.minor version 49.0.</h2>
-<p>This error is displayed if you are using an older version of the JDK. Please make sure you are using JDK version 5 or 6.</p>
-
-<h2 id="apidemosreinstall">I can't install ApiDemos apps in my IDE because of a signing error</a></h2>
-
-<p>The Android system requires that all applications be signed, as described in
- <a href="{@docRoot}guide/publishing/app-signing.html">Signing Your Applications</a>. The ApiDemos
-applications included with the SDK are preinstalled on the emulator and for that reason have been
-compiled and signed with a private key.</p>
-
-If you want to modify or run one of the ApiDemos apps from Eclipse/ADT or other IDE, you can do so
-so only after you uninstall the <em>preinstalled</em> version of the app from the emulator. If
-you try to run an ApiDemos apps from your IDE without removing the preinstalled version first,
-you will get errors similar to: </p>
-
-<pre>[2008-08-13 15:14:15 - ApiDemos] Re-installation failed due to different application signatures.
-[2008-08-13 15:14:15 - ApiDemos] You must perform a full uninstall of the application. WARNING: ...This will remove the application data!
-[2008-08-13 15:14:15 - ApiDemos] Please execute 'adb uninstall com.android.samples' in a shell.</pre>
-
-<p>The error occurs because, in this case, you are attempting to install another copy of ApiDemos
-onto the emulator, a copy that is signed with a different certificate (the Android IDE tools will
-have signed the app with a debug certificate, where the existing version was already signed with
-a private certificate). The system does not allow this type of reinstallation. </p>
-
-<p>To resolve the issue, you need to fully uninstall the preinstalled and then reinstall it using
-the adb tool. Here's how to do that:</p>
-
-<ol>
- <li>In a terminal, change to the tools directory of the SDK.</li>
- <li>If no emulator instance is running, start an emulator using using the command <code>emulator</code>.</li>
- <li>Uninstall the preinstalled app using the command <code>adb uninstall com.example.android.apis</code>.</li>
- <li>Reinstall the app using the command <code>adb install <path to the ApiDemos.apk></code>. If you are
- working in Eclipse/ADT, you can just compile and run the app in the normal way. </li>
-</ol>
-
-<p>Note that if multiple emulator instances are running, you need to direct your uninstall/install
-commands to the emulator instance that you are targeting. To do that you can add the
-<code>-s <serialNumber></code> to the command, for example: </p>
-
-<pre>adb -s emulator-5556 install</pre>
-
-<p>For more information about adb, see the <a href="{@docRoot}guide/developing/tools/adb.html">Android Debug Bridge</a>
-documentation.</p>
-
-<h2 id="gesturebuilderinstall">I can't install the GestureBuilder sample
-app in the emulator</a></h2>
-
-<p>This is similar to the ApiDemos problem described above, except that
-you cannot fix it by uninstalling GestureBuilder from the emulator. The
-GestureBuilder app cannot be uninstalled because it is currently installed
-within the system files themselves.</p>
-
-<p><strong>Symptoms</strong></p>
-
-<ul><li><p>You cannot run GestureBuilder in the emulator:</p>
-
-<pre>[2009-12-10 14:57:19 - GestureBuilderActivity]Re-installation failed due to different application signatures.
-[2009-12-10 14:57:19 - GestureBuilderActivity]You must perform a full uninstall of the application. WARNING: This will remove the application data!
-[2009-12-10 14:57:19 - GestureBuilderActivity]Please execute 'adb uninstall com.android.gesture.builder' in a shell.</pre>
-</li>
-
-<li><p>Running <code>adb uninstall com.android.gesture.builder</code> fails:</p>
-<pre>$ adb uninstall com.android.gesture.builder
- Failure</pre>
-</li></ul>
-
-<p>For now, the work-around is to change the sample's package name
-so that the system can install it as a new app rather than as a
-replacement for the existing GestureBuilder app. To change the
-package name, open the manifest file and modify the package attribute
-of the manifest element. Next, update imports and other references to
-the package name, rebuild the app, and run it in an AVD.</p>
-
-<p>For example, here's how you could do this in Eclipse:</p>
-
-<ol>
- <li>Right-click on the package name
-(<code>src/com.android.gesture.builder</code>).</li>
- <li>Select <strong>Refactor > Rename</strong> and change the name, for example to
-<code>com.android.gestureNEW.builder</code>. </li>
- <li>Open the manifest file. Inside the <code><manifest></code>
-tag, change the package name to
-<code>com.android.gestureNEW.builder</code>.</li>
- <li>Open each of the two Activity files and do Ctrl-Shift-O to add
-missing import packages, then save each file.</li>
-<li>Run the GestureBuilder application on the emulator.</li>
-</ol>
-
-<p>If you get an error message such as "Could not load /sdcard/gestures.
-Make sure you have a mounted SD card," be sure that your target AVD has an
-SD card. To create an AVD that has an SD card, specify one when creating
-an AVD with the AVD manager. See
-<a href="{@docRoot}guide/developing/devices/managing-avds.html#createavd">
-Creating and Managing AVDs with AVD Manager</a> for more information.</p>
-
-<h2 id="signingcalendar">I can't compile my app because the build tools generated an expired debug certificate</h2>
-
-<p>If your development machine uses a locale that has a non-Gregorian calendar, you may encounter problems when first trying to compile and run your application. Specifically, you may find that the Android build tools won't compile your application because the debug key is expired. </p>
-
-<p>The problem occurs because the Keytool utility — included in the JDK and used by the Android build tools — fails to properly handle non-Gregorian locales and may create validity dates that are in the past. That is, it may generate a debug key that is already expired, which results in the compile error.</p>
-
-<p>If you encounter this problem, follow these steps to work around it: </p>
-
-<ol>
-<li>First, delete the debug keystore/key already generated by the Android build tools. Specifically, delete the <code>debug.keystore</code> file. On Linux/Mac OSX, the file is stored in <code>~/.android</code>. On Windows XP, the file is stored in <code>
-C:\Documents and Settings\<user>\.android</code>. On Windows Vista, the file is stored in <code>
-C:\Users\<user>\.android</code></li>
-<li>Next, you can either
-<ul>
-<li>Temporarily change your development machine's locale (date and time) to one that uses a Gregorian calendar, for example, United States. Once the locale is changed, use the Android build tools to compile and install your app. The build tools will regenerate a new keystore and debug key with valid dates. Once the new debug key is generated, you can reset your development machine to the original locale. </li>
-<li>Alternatively, if you do not want to change your machine's locale settings, you can generate the keystore/key on any machine using the Gregorian calendar, then copy the <code>debug.keystore</code> file from that computer to the proper location on your development machine. </li>
-</ul>
-</li>
-</ol>
-
-<p>This problem has been verified on Windows and may apply to other platforms. </p>
-
-<p>For general information about signing Android applications, see
-<a href="{@docRoot}guide/publishing/app-signing.html">Signing Your Applications</a>. </p>
-
-<h2 id="manifestfiles">Unable to view manifest files from within
-Eclipse</a></h2>
-
-<p>When you try to open an application's manifest file from within
-Eclipse, you might get an error such as this one:</p>
-<pre>An error has occurred. See error log for more details.
-org.eclipse.wst.sse.ui.StructuredTextEditor.isBlockSelectionModeEnabled()Z</pre>
-
-<p>Try reverting to the 3.0 version of the Eclipse XML Editors and
-Tools. If this does not work, remove the 3.1 version of the tool. To do
-this in Eclipse 3.4:</p>
-
-<ol>
- <li>Select <strong>Help > Software Updates...</strong></li>
- <li>Select the <strong>Installed Software</strong> tab.</li>
- <li>Select <strong>Eclipse XML Editors and Tools</strong>.</li>
- <li>Click <strong>Uninstall</strong>.</li>
- <li>Click <strong>Finish</strong>.</li>
-</ol>
-
-<p>When you restart Eclipse, you should be able to view the manifest
-files. </p>
\ No newline at end of file
diff --git a/docs/html/jd_collections.js b/docs/html/jd_collections.js
index cac93afc..2505746 100644
--- a/docs/html/jd_collections.js
+++ b/docs/html/jd_collections.js
@@ -687,7 +687,8 @@
"resources": [
"https://developers.google.com/app-indexing/",
"https://developers.google.com/app-indexing/webmasters/details",
- "distribute/engage/deep-linking.html"
+ "distribute/engage/deep-linking.html",
+ "training/app-indexing/index.html"
]
},
"distribute/users/otas": {
@@ -953,7 +954,8 @@
"resources": [
"distribute/engage/intents.html",
"distribute/engage/deep-linking.html",
- "distribute/users/appindexing.html"
+ "distribute/users/appindexing.html",
+ "training/app-indexing/index.html"
]
},
"distribute/engage/intents": {
diff --git a/docs/html/robots.txt b/docs/html/robots.txt
index ab379bb..f522220 100644
--- a/docs/html/robots.txt
+++ b/docs/html/robots.txt
@@ -15,5 +15,4 @@
Disallow: /guide/tutorials/
Disallow: /guide/samples/
Disallow: /community/
-Disallow: /preview/
Sitemap: http://developer.android.com/sitemap.txt
diff --git a/docs/html/sdk/index.jd b/docs/html/sdk/index.jd
index bdc60a2..02beefd 100644
--- a/docs/html/sdk/index.jd
+++ b/docs/html/sdk/index.jd
@@ -5,46 +5,46 @@
header.hide=1
page.metaDescription=Download the official Android IDE and developer tools to build apps for Android phones, tablets, wearables, TVs, and more.
-studio.version=1.2.1.1
+studio.version=1.2.2.0
-studio.linux_bundle_download=android-studio-ide-141.1903250-linux.zip
-studio.linux_bundle_bytes=258634089
-studio.linux_bundle_checksum=61f576a24ac9aa00d498bb62942c028ef4a8905b
+studio.linux_bundle_download=android-studio-ide-141.1980579-linux.zip
+studio.linux_bundle_bytes=258628239
+studio.linux_bundle_checksum=1fcb226bcf71760296b07dc0db74216563ce83f7
-studio.mac_bundle_download=android-studio-ide-141.1903250-mac.dmg
-studio.mac_bundle_bytes=260877150
-studio.mac_bundle_checksum=a5a6ba50e3590de0973230a238d17726a1d9395c
+studio.mac_bundle_download=android-studio-ide-141.1980579-mac.dmg
+studio.mac_bundle_bytes=260363204
+studio.mac_bundle_checksum=811a868958f8799a1c86a3acfab0fc5dc8de2f41
-studio.win_bundle_download=android-studio-ide-141.1903250-windows.zip
-studio.win_bundle_bytes=261042465
-studio.win_bundle_checksum=ce924e0e4cff4b7f24df3f7ce0c1ce2379347d72
+studio.win_bundle_download=android-studio-ide-141.1980579-windows.zip
+studio.win_bundle_bytes=261036618
+studio.win_bundle_checksum=e61c9c27a92eff943f6bfdcdec3827199dd0c63d
-studio.win_bundle_exe_download=android-studio-bundle-141.1903250-windows.exe
-studio.win_bundle_exe_bytes=930462136
-studio.win_bundle_exe_checksum=680668b6b4a51c519efda814b96c2b61541a50f2
+studio.win_bundle_exe_download=android-studio-bundle-141.1980579-windows.exe
+studio.win_bundle_exe_bytes=930456592
+studio.win_bundle_exe_checksum=964959e5165e90aaf693e868d5d1c2f7b38e8754
-studio.win_notools_exe_download=android-studio-ide-141.1903250-windows.exe
-studio.win_notools_exe_bytes=243747312
-studio.win_notools_exe_checksum=d89917dd044e0559c87d6a05d49780ab110269f7
+studio.win_notools_exe_download=android-studio-ide-141.1980579-windows.exe
+studio.win_notools_exe_bytes=243741776
+studio.win_notools_exe_checksum=ae09797db2537afb572a00b7eacc292bb66d539e
-sdk.linux_download=android-sdk_r24.2-linux.tgz
-sdk.linux_bytes=168119905
-sdk.linux_checksum=1a29f9827ef395a96db629209b0e38d5e2dd8089
+sdk.linux_download=android-sdk_r24.3.2-linux.tgz
+sdk.linux_bytes=309563606
+sdk.linux_checksum=98e70ce403fea2e24e90103395d418feb3a9b7e8
-sdk.mac_download=android-sdk_r24.2-macosx.zip
-sdk.mac_bytes=88949635
-sdk.mac_checksum=256c9bf642f56242d963c090d147de7402733451
+sdk.mac_download=android-sdk_r24.3.2-macosx.zip
+sdk.mac_bytes=98259310
+sdk.mac_checksum=aa9aef30ff27358118318d82414b1481625faf2a
-sdk.win_download=android-sdk_r24.2-windows.zip
-sdk.win_bytes=155944165
-sdk.win_checksum=2611ed9a6080f4838f1d4e55172801714a8a169b
+sdk.win_download=android-sdk_r24.3.2-windows.zip
+sdk.win_bytes=187214094
+sdk.win_checksum=c33a63a955bb448ee550710a764ba18c37cb58d6
-sdk.win_installer=installer_r24.2-windows.exe
-sdk.win_installer_bytes=107849819
-sdk.win_installer_checksum=e764ea93aa72766737f9be3b9fb3e42d879ab599
+sdk.win_installer=installer_r24.3.2-windows.exe
+sdk.win_installer_bytes=139471724
+sdk.win_installer_checksum=8f9d0ae9fdb37973ed62d6e93975ff375beb5542
diff --git a/docs/html/tools/revisions/studio.jd b/docs/html/tools/revisions/studio.jd
index 7138efe..b727d96 100644
--- a/docs/html/tools/revisions/studio.jd
+++ b/docs/html/tools/revisions/studio.jd
@@ -43,10 +43,24 @@
<div class="toggle-content opened">
<p><a href="#" onclick="return toggleContent(this)">
<img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-content-img"
+ alt=""/>Android Studio v1.2.2</a> <em>(June 2015)</em>
+ </p>
+ <div class="toggle-content-toggleme">
+ <p>Fixes and enhancements:</p>
+ <ul>
+ <li>Fixed build issues that were blocking builds from completing. </li>
+ </ul>
+ </div>
+</div>
+
+
+<div class="toggle-content closed">
+ <p><a href="#" onclick="return toggleContent(this)">
+ <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-content-img"
alt=""/>Android Studio v1.2.1</a> <em>(May 2015)</em>
</p>
<div class="toggle-content-toggleme">
- <p>Various fixes and enhancements:</p>
+ <p>Fixes and enhancements:</p>
<ul>
<li>Fixed minor performance and feature issues. </li>
</ul>
@@ -62,7 +76,7 @@
</p>
<div class="toggle-content-toggleme">
- <p>Various fixes and enhancements:</p>
+ <p>Fixes and enhancements:</p>
<ul>
<li>Updated the Android runtime window to include the
<a href="{@docRoot}tools/studio/index.html#mem-cpu">Memory Monitor</a> tool
diff --git a/docs/html/tools/sdk/tools-notes.jd b/docs/html/tools/sdk/tools-notes.jd
index 434dc44..326fbe2 100644
--- a/docs/html/tools/sdk/tools-notes.jd
+++ b/docs/html/tools/sdk/tools-notes.jd
@@ -21,9 +21,98 @@
<p>For a summary of all known issues in SDK Tools, see <a
href="http://tools.android.com/knownissues">http://tools.android.com/knownissues</a>.</p>
+
<div class="toggle-content opened">
<p><a href="#" onclick="return toggleContent(this)">
<img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-content-img"
+ alt=""/>SDK Tools, Revision 24.3.2</a> <em>(June 2015)</em>
+ </p>
+
+ <div class="toggle-content-toggleme">
+
+ <dl>
+ <dt>Dependencies:</dt>
+
+ <dd>
+ <ul>
+ <li>Android SDK Platform-tools revision 19 or later.</li>
+ </ul>
+ </dd>
+
+ <dt>General Notes:</dt>
+ <dd>
+ <ul>
+ <li>Fixed issues with the ARM 64-bit emulator.</li>
+ </ul>
+ </dd>
+ </div>
+</div>
+
+
+<div class="toggle-content closed">
+ <p><a href="#" onclick="return toggleContent(this)">
+ <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-content-img"
+ alt=""/>SDK Tools, Revision 24.3.1</a> <em>(June 2015)</em>
+ </p>
+
+ <div class="toggle-content-toggleme">
+
+ <dl>
+ <dt>Dependencies:</dt>
+
+ <dd>
+ <ul>
+ <li>Android SDK Platform-tools revision 19 or later.</li>
+ </ul>
+ </dd>
+
+ <dt>General Notes:</dt>
+ <dd>
+ <ul>
+ <li>Fixed issue with the <code>root/</code> and <code>lib/</code> folders. </li>
+ </ul>
+ <p class="caution"><strong>Caution:</strong> This release is known to contain issues which
+ prevent builds from completing. We strongly recommend that you update to SDK Tools 24.3.2
+ as soon as possible. </p>
+ </dd>
+ </div>
+</div>
+
+
+<div class="toggle-content closed">
+ <p><a href="#" onclick="return toggleContent(this)">
+ <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-content-img"
+ alt=""/>SDK Tools, Revision 24.3.0</a> <em>(June 2015)</em>
+ </p>
+
+ <div class="toggle-content-toggleme">
+
+ <dl>
+ <dt>Dependencies:</dt>
+
+ <dd>
+ <ul>
+ <li>Android SDK Platform-tools revision 19 or later.</li>
+ </ul>
+ </dd>
+
+ <dt>General Notes:</dt>
+ <dd>
+ <ul>
+ <li>Fixed several minor emulator issues.</li>
+ </ul>
+ <p class="caution"><strong>Caution:</strong> This release is known to contain issues which
+ prevent builds from completing. We strongly recommend that you update to SDK Tools 24.3.2
+ as soon as possible. </p>
+ </dd>
+ </div>
+</div>
+
+
+
+<div class="toggle-content closed">
+ <p><a href="#" onclick="return toggleContent(this)">
+ <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-content-img"
alt=""/>SDK Tools, Revision 24.2.0</a> <em>(May 2015)</em>
</p>
diff --git a/docs/html/training/app-indexing/index.jd b/docs/html/training/app-indexing/index.jd
index 45afea8..15a6367 100644
--- a/docs/html/training/app-indexing/index.jd
+++ b/docs/html/training/app-indexing/index.jd
@@ -1,6 +1,7 @@
page.title=Making Your App Content Searchable by Google
-page.tags="app indexing"
-
+page.tags="app indexing", "search"
+meta.tags="getusers", "search","appindexing"
+page.image=images/cards/google-search_2x.png
trainingnavtop=true
startpage=true
@@ -59,8 +60,8 @@
</li>
</ol>
-<p>This class shows how to enable deep linking and indexing of your application
-content so that users can open this content directly from mobile search
+<p itemprop="description">This class shows how to enable deep linking and indexing of
+your application content so that users can open this content directly from mobile search
results.</p>
<h2>Lessons</h2>
diff --git a/docs/html/training/cloudsync/gcm.jd b/docs/html/training/cloudsync/gcm.jd
deleted file mode 100644
index 6303372..0000000
--- a/docs/html/training/cloudsync/gcm.jd
+++ /dev/null
@@ -1,212 +0,0 @@
-page.title=Making the Most of Google Cloud Messaging
-
-trainingnavtop=true
-
-@jd:body
-
-<div id="tb-wrapper">
- <div id="tb">
- <h2>This lesson teaches you to</h2>
- <ol>
- <li><a href="#multicast">Send Multicast Messages Efficiently</a></li>
- <li><a href="#collapse">Collapse Messages that can Be Replaced</a></li>
- <li><a href="#embed">Embed Data Directly in the GCM Message</a></li>
- <li><a href="#react">React Intelligently to GCM Messages</a></li>
- </ol>
- <h2>You should also read</h2>
- <ul>
- <li><a href="http://developer.android.com/google/gcm/index.html">Google
- Cloud Messaging for Android</a></li>
- </ul>
- </div>
-</div>
-
-<p>Google Cloud Messaging (GCM) is a free service for sending
-messages to Android devices. GCM messaging can greatly enhance the user
-experience. Your application can stay up to date without wasting battery power
-on waking up the radio and polling the server when there are no updates. Also,
-GCM allows you to attach up to 1,000 recipients to a single message, letting you easily contact
-large user bases quickly when appropriate, while minimizing the work load on
-your server.</p>
-
-<p>This lesson covers some of the best practices
-for integrating GCM into your application, and assumes you are already familiar
-with basic implementation of this service. If this is not the case, you can read the <a
- href="{@docRoot}google/gcm/demo.html">GCM demo app tutorial</a>.</p>
-
-<h2 id="multicast">Send Multicast Messages Efficiently</h2>
-<p>One of the most useful features in GCM is support for up to 1,000 recipients for
-a single message. This capability makes it much easier to send out important messages to
-your entire user base. For instance, let's say you had a message that needed to
-be sent to 1,000,000 of your users, and your server could handle sending out
-about 500 messages per second. If you send each message with only a single
-recipient, it would take 1,000,000/500 = 2,000 seconds, or around half an hour.
-However, attaching 1,000 recipients to each message, the total time required to
-send a message out to 1,000,000 recipients becomes (1,000,000/1,000) / 500 = 2
-seconds. This is not only useful, but important for timely data, such as natural
-disaster alerts or sports scores, where a 30 minute interval might render the
-information useless.</p>
-
-<p>Taking advantage of this functionality is easy. If you're using the <a
- href="{@docRoot}google/gcm/gs.html#libs">GCM helper
- library</a> for Java, simply provide a <code>List<String></code> collection of
-registration IDs to the <code>send</code> or <code>sendNoRetry</code> method,
-instead of a single registration ID.</p>
-
-<pre>
-// This method name is completely fabricated, but you get the idea.
-List<String> regIds = whoShouldISendThisTo(message);
-
-// If you want the SDK to automatically retry a certain number of times, use the
-// standard send method.
-MulticastResult result = sender.send(message, regIds, 5);
-
-// Otherwise, use sendNoRetry.
-MulticastResult result = sender.sendNoRetry(message, regIds);
-</pre>
-
-<p>For those implementing GCM support in a language other than Java, construct
-an HTTP POST request with the following headers:</p>
-<ul>
- <li><code>Authorization: key=YOUR_API_KEY</code></li>
- <li><code>Content-type: application/json</code></li>
-</ul>
-
-<p>Then encode the parameters you want into a JSON object, listing all the
-registration IDs under the key <code>registration_ids</code>. The snippet below
-serves as an example. All parameters except <code>registration_ids</code> are
-optional, and the items nested in <code>data</code> represent the user-defined payload, not
-GCM-defined parameters. The endpoint for this HTTP POST message will be
-<code>https://android.googleapis.com/gcm/send</code>.</p>
-
-<pre>
-{ "collapse_key": "score_update",
- "time_to_live": 108,
- "delay_while_idle": true,
- "data": {
- "score": "4 x 8",
- "time": "15:16.2342"
- },
- "registration_ids":["4", "8", "15", "16", "23", "42"]
-}
-</pre>
-
-<p>For a more thorough overview of the format of multicast GCM messages, see the <a
- href="{@docRoot}google/gcm/gcm.html#send-msg">Sending
- Messages</a> section of the GCM guide.</pre>
-
-<h2 id="collapse">Collapse Messages that Can Be Replaced</h2>
-<p>GCM messages are often a tickle, telling the mobile application to
-contact the server for fresh data. In GCM, it's possible (and recommended) to
-create collapsible messages for this situation, wherein new messages replace
-older ones. Let's take the example
-of sports scores. If you send out a message to all users following a certain
-game with the updated score, and then 15 minutes later an updated score message
-goes out, the earlier one no longer matters. For any users who haven't received
-the first message yet, there's no reason to send both, and force the device to
-react (and possibly alert the user) twice when only one of the messages is still
-important.</p>
-
-<p>When you define a collapse key, when multiple messages are queued up in the GCM
-servers for the same user, only the last one with any given collapse key is
-delivered. For a situation like with sports scores, this saves the device from
-doing needless work and potentially over-notifying the user. For situations
-that involve a server sync (like checking email), this can cut down on the
-number of syncs the device has to do. For instance, if there are 10 emails
-waiting on the server, and ten "new email" GCM tickles have been sent to the
-device, it only needs one, since it should only sync once.</p>
-
-<p>In order to use this feature, just add a collapse key to your outgoing
-message. If you're using the GCM helper library, use the Message class's <code>collapseKey(String key)</code> method.</p>
-
-<pre>
-Message message = new Message.Builder(regId)
- .collapseKey("game4_scores") // The key for game 4.
- .ttl(600) // Time in seconds to keep message queued if device offline.
- .delayWhileIdle(true) // Wait for device to become active before sending.
- .addPayload("key1", "value1")
- .addPayload("key2", "value2")
- .build();
-</pre>
-
-<p>If not using the helper library, simply add a variable to the
-POST header you're constructing, with <code>collapse_key</code> as the field
-name, and the string you're using for that set of updates as the value.</p>
-
-
-
-<h2 id="embed">Embed Data Directly in the GCM Message</h2>
-<p>Often, GCM messages are meant to be a tickle, or indication to the device
-that there's fresh data waiting on a server somewhere. However, a GCM message
-can be up to 4kb in size, so sometimes it makes sense to simply send the
-data within the GCM message itself, so that the device doesn't need to contact the
-server at all. Consider this approach for situations where all of the
-following statements are true:
-<ul>
- <li>The total data fits inside the 4kb limit.</li>
- <li>Each message is important, and should be preserved.</li>
- <li>It doesn't make sense to collapse multiple GCM messages into a single
- "new data on the server" tickle.</li>
-</ul>
-
-<p>For instance, short messages or encoded player moves
-in a turn-based network game are examples of good use-cases for data to embed directly
-into a GCM message. Email is an example of a bad use-case, since messages are
-often larger than 4kb,
-and users don't need a GCM message for each email waiting for them on
-the server.</p>
-
-<p>Also consider this approach when sending
-multicast messages, so you don't tell every device across your user base to hit
-your server for updates simultaneously.</p>
-<p>This strategy isn't appropriate for sending large amounts of data, for a few
-reasons:</p>
-<ul>
- <li>Rate limits are in place to prevent malicious or poorly coded apps from spamming an
- individual device with messages.</li>
- <li>Messages aren't guaranteed to arrive in-order.</li>
- <li>Messages aren't guaranteed to arrive as fast as you send them out. Even
- if the device receives one GCM message a second, at a max of 1K, that's 8kbps, or
- about the speed of home dial-up internet in the early 1990's. Your app rating
- on Google Play will reflect having done that to your users.</p>
-</ul>
-
-<p>When used appropriately, directly embedding data in the GCM message can speed
-up the perceived speediness of your application, by letting it skip a round trip
-to the server.</p>
-
-<h2 id="react">React Intelligently to GCM Messages</h2>
-<p>Your application should not only react to incoming GCM messages, but react
-<em>intelligently</em>. How to react depends on the context.</p>
-
-<h3>Don't be irritating</h3>
-<p>When it comes to alerting your user of fresh data, it's easy to cross the line
-from "useful" to "annoying". If your application uses status bar notifications,
-<a
- href="http://developer.android.com/guide/topics/ui/notifiers/notifications.html#Updating">update
- your existing notification</a> instead of creating a second one. If you
-beep or vibrate to alert the user, consider setting up a timer. Don't let the
-application alert more than once a minute, lest users be tempted to uninstall
-your application, turn the device off, or toss it in a nearby river.</p>
-
-<h3>Sync smarter, not harder</h3>
-<p>When using GCM as an indicator to the device that data needs to be downloaded
-from the server, remember you have 4kb of metadata you can send along to
-help your application be smart about it. For instance, if you have a feed
-reading app, and your user has 100 feeds that they follow, help the device be
-smart about what it downloads from the server! Look at the following examples
-of what metadata is sent to your application in the GCM payload, and how the application
-can react:</p>
-<ul>
- <li><code>refresh</code> — Your app basically got told to request a dump of
- every feed it follows. Your app would either need to send feed requests to 100 different servers, or
- if you have an aggregator on your server, send a request to retrieve, bundle
- and
- transmit recent data from 100 different feeds, every time one updates.</li>
- <li><code>refresh</code>, <code>feedID</code> — Better: Your app knows to check
- a specific feed for updates.</li>
- <li><code>refresh</code>, <code>feedID</code>, <code>timestamp</code> —
- Best: If the user happened to manually refresh before the GCM message
- arrived, the application can compare timestamps of the most recent post, and
- determine that it <em>doesn't need to do anything</em>.
-</ul>
diff --git a/docs/html/training/cloudsync/index.jd b/docs/html/training/cloudsync/index.jd
index cf7117c..082ace5 100644
--- a/docs/html/training/cloudsync/index.jd
+++ b/docs/html/training/cloudsync/index.jd
@@ -21,10 +21,8 @@
service, making sure all your devices always stay in sync, and your valuable
data is always backed up to the cloud.</p>
-<p>This class covers different strategies for cloud enabled applications. It
-covers syncing data with the cloud using your own back-end web application, and
-backing up data using the cloud so that users can restore their data when
-installing your application on a new device.
+<p>This class covers strategies for backing up data using the cloud so that
+users can restore their data when installing your application on a new device.
</p>
<h2>Lessons</h2>
@@ -34,9 +32,5 @@
<dd>Learn how to integrate the Backup API into your Android Application, so
that user data such as preferences, notes, and high scores update seamlessly
across all of a user's devices</dd>
- <dt><strong><a href="gcm.html">Making the Most of Google Cloud Messaging</a></strong></dt>
- <dd>Learn how to efficiently send multicast messages, react intelligently to
- incoming Google Cloud Messaging (GCM) messages, and use GCM messages to
- efficiently sync with the server.</dd>
</dl>
diff --git a/docs/html/training/sync-adapters/creating-sync-adapter.jd b/docs/html/training/sync-adapters/creating-sync-adapter.jd
index b13ce07..9bd17ba 100644
--- a/docs/html/training/sync-adapters/creating-sync-adapter.jd
+++ b/docs/html/training/sync-adapters/creating-sync-adapter.jd
@@ -583,13 +583,6 @@
running the sync adapter, see <a href="running-sync-adapter.html"
>Running A Sync Adapter</a>.
</dd>
- <dt>
-{@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS android.permission.AUTHENTICATE_ACCOUNTS}
- </dt>
- <dd>
- Allows you to use the authenticator component you created in the lesson
- <a href="creating-authenticator.html">Creating a Stub Authenticator</a>.
- </dd>
</dl>
<p>
The following snippet shows how to add the permissions:
diff --git a/docs/html/training/training_toc.cs b/docs/html/training/training_toc.cs
index 0baef14..ccefe72 100644
--- a/docs/html/training/training_toc.cs
+++ b/docs/html/training/training_toc.cs
@@ -596,10 +596,6 @@
Using the Backup API
</a>
</li>
- <li><a href="<?cs var:toroot ?>training/cloudsync/gcm.html">
- Making the Most of Google Cloud Messaging
- </a>
- </li>
</ul>
<li><a href="<?cs var:toroot ?>training/cloudsave/conflict-res.html"
description=
diff --git a/graphics/java/android/graphics/BitmapShader.java b/graphics/java/android/graphics/BitmapShader.java
index bd74bc8..9211225 100644
--- a/graphics/java/android/graphics/BitmapShader.java
+++ b/graphics/java/android/graphics/BitmapShader.java
@@ -16,6 +16,8 @@
package android.graphics;
+import android.annotation.NonNull;
+
/**
* Shader used to draw a bitmap as a texture. The bitmap can be repeated or
* mirrored by setting the tiling mode.
@@ -38,7 +40,7 @@
* @param tileX The tiling mode for x to draw the bitmap in.
* @param tileY The tiling mode for y to draw the bitmap in.
*/
- public BitmapShader(Bitmap bitmap, TileMode tileX, TileMode tileY) {
+ public BitmapShader(@NonNull Bitmap bitmap, TileMode tileX, TileMode tileY) {
mBitmap = bitmap;
mTileX = tileX;
mTileY = tileY;
diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java
index 392a5b6..7386637 100644
--- a/graphics/java/android/graphics/Canvas.java
+++ b/graphics/java/android/graphics/Canvas.java
@@ -1728,8 +1728,7 @@
* @param contextIndex the start of the context for shaping. Must be
* no greater than index.
* @param contextCount the number of characters in the context for shaping.
- * contexIndex + contextCount must be no less than index
- * + count.
+ * contexIndex + contextCount must be no less than index + count.
* @param x the x position at which to draw the text
* @param y the y position at which to draw the text
* @param isRtl whether the run is in RTL direction
@@ -1744,12 +1743,14 @@
if (paint == null) {
throw new NullPointerException("paint is null");
}
- if ((index | count | text.length - index - count) < 0) {
+ if ((index | count | contextIndex | contextCount | index - contextIndex
+ | (contextIndex + contextCount) - (index + count)
+ | text.length - (contextIndex + contextCount)) < 0) {
throw new IndexOutOfBoundsException();
}
- native_drawTextRun(mNativeCanvasWrapper, text, index, count,
- contextIndex, contextCount, x, y, isRtl, paint.getNativeInstance(), paint.mNativeTypeface);
+ native_drawTextRun(mNativeCanvasWrapper, text, index, count, contextIndex, contextCount,
+ x, y, isRtl, paint.getNativeInstance(), paint.mNativeTypeface);
}
/**
@@ -1796,14 +1797,15 @@
if (paint == null) {
throw new NullPointerException("paint is null");
}
- if ((start | end | end - start | text.length() - end) < 0) {
+ if ((start | end | contextStart | contextEnd | start - contextStart | end - start
+ | contextEnd - end | text.length() - contextEnd) < 0) {
throw new IndexOutOfBoundsException();
}
if (text instanceof String || text instanceof SpannedString ||
text instanceof SpannableString) {
- native_drawTextRun(mNativeCanvasWrapper, text.toString(), start, end,
- contextStart, contextEnd, x, y, isRtl, paint.getNativeInstance(), paint.mNativeTypeface);
+ native_drawTextRun(mNativeCanvasWrapper, text.toString(), start, end, contextStart,
+ contextEnd, x, y, isRtl, paint.getNativeInstance(), paint.mNativeTypeface);
} else if (text instanceof GraphicsOperations) {
((GraphicsOperations) text).drawTextRun(this, start, end,
contextStart, contextEnd, x, y, isRtl, paint);
diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
index e8e4664..532c888 100644
--- a/graphics/java/android/graphics/drawable/Drawable.java
+++ b/graphics/java/android/graphics/drawable/Drawable.java
@@ -809,6 +809,14 @@
* {@link android.graphics.PixelFormat#TRANSPARENT}, or
* {@link android.graphics.PixelFormat#OPAQUE}.
*
+ * <p>An OPAQUE drawable is one that draws all all content within its bounds, completely
+ * covering anything behind the drawable. A TRANSPARENT drawable is one that draws nothing
+ * within its bounds, allowing everything behind it to show through. A TRANSLUCENT drawable
+ * is a drawable in any other state, where the drawable will draw some, but not all,
+ * of the content within its bounds and at least some content behind the drawable will
+ * be visible. If the visibility of the drawable's contents cannot be determined, the
+ * safest/best return value is TRANSLUCENT.
+ *
* <p>Generally a Drawable should be as conservative as possible with the
* value it returns. For example, if it contains multiple child drawables
* and only shows one of them at a time, if only one of the children is
diff --git a/graphics/java/android/graphics/drawable/RippleDrawable.java b/graphics/java/android/graphics/drawable/RippleDrawable.java
index 1af48ca..134451b 100644
--- a/graphics/java/android/graphics/drawable/RippleDrawable.java
+++ b/graphics/java/android/graphics/drawable/RippleDrawable.java
@@ -333,17 +333,29 @@
*/
@Override
public boolean isProjected() {
- // If the maximum radius is contained entirely within the bounds, we
- // don't need to project this ripple.
- final int radius = mState.mMaxRadius;
- final Rect bounds = getBounds();
- if (radius != RADIUS_AUTO && radius <= bounds.width() / 2
- && radius <= bounds.height() / 2) {
+ // If the layer is bounded, then we don't need to project.
+ if (isBounded()) {
return false;
}
- // Otherwise, if the layer is bounded then we don't need to project.
- return !isBounded();
+ // Otherwise, if the maximum radius is contained entirely within the
+ // bounds then we don't need to project. This is sort of a hack to
+ // prevent check box ripples from being projected across the edges of
+ // scroll views. It does not impact rendering performance, and it can
+ // be removed once we have better handling of projection in scrollable
+ // views.
+ final int radius = mState.mMaxRadius;
+ final Rect drawableBounds = getBounds();
+ final Rect hotspotBounds = mHotspotBounds;
+ if (radius != RADIUS_AUTO
+ && radius <= hotspotBounds.width() / 2
+ && radius <= hotspotBounds.height() / 2
+ && (drawableBounds.equals(hotspotBounds)
+ || drawableBounds.contains(hotspotBounds))) {
+ return false;
+ }
+
+ return true;
}
private boolean isBounded() {
diff --git a/keystore/java/android/security/KeyChain.java b/keystore/java/android/security/KeyChain.java
index 059d8e6..f482bf0 100644
--- a/keystore/java/android/security/KeyChain.java
+++ b/keystore/java/android/security/KeyChain.java
@@ -29,15 +29,14 @@
import android.os.Process;
import android.os.RemoteException;
import android.os.UserHandle;
-import android.security.keystore.KeyInfo;
+import android.security.keystore.AndroidKeyStoreProvider;
import android.security.keystore.KeyProperties;
import java.io.ByteArrayInputStream;
import java.io.Closeable;
-import java.security.InvalidKeyException;
-import java.security.KeyFactory;
import java.security.Principal;
import java.security.PrivateKey;
+import java.security.UnrecoverableKeyException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
@@ -47,7 +46,6 @@
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
-import com.android.org.conscrypt.OpenSSLEngine;
import com.android.org.conscrypt.TrustedCertificateStore;
/**
@@ -90,8 +88,6 @@
// TODO reference intent for credential installation when public
public final class KeyChain {
- private static final String TAG = "KeyChain";
-
/**
* @hide Also used by KeyChainService implementation
*/
@@ -372,15 +368,14 @@
if (keyId == null) {
throw new KeyChainException("keystore had a problem");
}
-
- final OpenSSLEngine engine = OpenSSLEngine.getInstance("keystore");
- return engine.getPrivateKeyById(keyId);
+ return AndroidKeyStoreProvider.loadAndroidKeyStorePrivateKeyFromKeystore(
+ KeyStore.getInstance(), keyId);
} catch (RemoteException e) {
throw new KeyChainException(e);
} catch (RuntimeException e) {
// only certain RuntimeExceptions can be propagated across the IKeyChainService call
throw new KeyChainException(e);
- } catch (InvalidKeyException e) {
+ } catch (UnrecoverableKeyException e) {
throw new KeyChainException(e);
} finally {
keyChainConnection.close();
diff --git a/keystore/java/android/security/KeyPairGeneratorSpec.java b/keystore/java/android/security/KeyPairGeneratorSpec.java
index efbce41..d849317 100644
--- a/keystore/java/android/security/KeyPairGeneratorSpec.java
+++ b/keystore/java/android/security/KeyPairGeneratorSpec.java
@@ -331,7 +331,9 @@
if (keyType == null) {
throw new NullPointerException("keyType == null");
} else {
- if (KeyStore.getKeyTypeForAlgorithm(keyType) == -1) {
+ try {
+ KeyProperties.KeyAlgorithm.toKeymasterAsymmetricKeyAlgorithm(keyType);
+ } catch (IllegalArgumentException e) {
throw new NoSuchAlgorithmException("Unsupported key type: " + keyType);
}
}
diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java
index 893771a..6a08368 100644
--- a/keystore/java/android/security/KeyStore.java
+++ b/keystore/java/android/security/KeyStore.java
@@ -19,7 +19,6 @@
import android.app.ActivityThread;
import android.app.Application;
import android.app.KeyguardManager;
-import com.android.org.conscrypt.NativeConstants;
import android.content.Context;
import android.hardware.fingerprint.FingerprintManager;
@@ -38,7 +37,6 @@
import android.security.keystore.KeyExpiredException;
import android.security.keystore.KeyNotYetValidException;
import android.security.keystore.KeyPermanentlyInvalidatedException;
-import android.security.keystore.KeyProperties;
import android.security.keystore.UserNotAuthenticatedException;
import android.util.Log;
@@ -110,15 +108,10 @@
}
public static Context getApplicationContext() {
- ActivityThread activityThread = ActivityThread.currentActivityThread();
- if (activityThread == null) {
- throw new IllegalStateException(
- "Failed to obtain application Context: no ActivityThread");
- }
- Application application = activityThread.getApplication();
+ Application application = ActivityThread.currentApplication();
if (application == null) {
throw new IllegalStateException(
- "Failed to obtain application Context: no Application");
+ "Failed to obtain application Context from ActivityThread");
}
return application;
}
@@ -136,16 +129,6 @@
return mToken;
}
- public static int getKeyTypeForAlgorithm(@KeyProperties.KeyAlgorithmEnum String keyType) {
- if (KeyProperties.KEY_ALGORITHM_RSA.equalsIgnoreCase(keyType)) {
- return NativeConstants.EVP_PKEY_RSA;
- } else if (KeyProperties.KEY_ALGORITHM_EC.equalsIgnoreCase(keyType)) {
- return NativeConstants.EVP_PKEY_EC;
- } else {
- return -1;
- }
- }
-
public State state(int userId) {
final int ret;
try {
@@ -710,16 +693,13 @@
}
private long getFingerprintOnlySid() {
- FingerprintManager fingerprintManager =
- mContext.getSystemService(FingerprintManager.class);
+ FingerprintManager fingerprintManager = mContext.getSystemService(FingerprintManager.class);
if (fingerprintManager == null) {
return 0;
}
- if (!fingerprintManager.isHardwareDetected()) {
- return 0;
- }
-
+ // TODO: Restore USE_FINGERPRINT permission check in
+ // FingerprintManager.getAuthenticatorId once the ID is no longer needed here.
return fingerprintManager.getAuthenticatorId();
}
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreECPrivateKey.java b/keystore/java/android/security/keystore/AndroidKeyStoreECPrivateKey.java
new file mode 100644
index 0000000..5dbcd68
--- /dev/null
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreECPrivateKey.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.keystore;
+
+import java.security.PrivateKey;
+import java.security.interfaces.ECKey;
+import java.security.spec.ECParameterSpec;
+
+/**
+ * EC private key (instance of {@link PrivateKey} and {@link ECKey}) backed by keystore.
+ *
+ * @hide
+ */
+public class AndroidKeyStoreECPrivateKey extends AndroidKeyStorePrivateKey implements ECKey {
+ private final ECParameterSpec mParams;
+
+ public AndroidKeyStoreECPrivateKey(String alias, ECParameterSpec params) {
+ super(alias, KeyProperties.KEY_ALGORITHM_EC);
+ mParams = params;
+ }
+
+ @Override
+ public ECParameterSpec getParams() {
+ return mParams;
+ }
+}
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreKey.java b/keystore/java/android/security/keystore/AndroidKeyStoreKey.java
index 1751aa5..e76802f 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreKey.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreKey.java
@@ -52,4 +52,42 @@
// This key does not export its key material
return null;
}
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((mAlgorithm == null) ? 0 : mAlgorithm.hashCode());
+ result = prime * result + ((mAlias == null) ? 0 : mAlias.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ AndroidKeyStoreKey other = (AndroidKeyStoreKey) obj;
+ if (mAlgorithm == null) {
+ if (other.mAlgorithm != null) {
+ return false;
+ }
+ } else if (!mAlgorithm.equals(other.mAlgorithm)) {
+ return false;
+ }
+ if (mAlias == null) {
+ if (other.mAlias != null) {
+ return false;
+ }
+ } else if (!mAlias.equals(other.mAlias)) {
+ return false;
+ }
+ return true;
+ }
}
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java
index 69155a8..35af34f 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java
@@ -20,7 +20,6 @@
import android.security.Credentials;
import android.security.KeyPairGeneratorSpec;
import android.security.KeyStore;
-import android.security.keymaster.ExportResult;
import android.security.keymaster.KeyCharacteristics;
import android.security.keymaster.KeymasterArguments;
import android.security.keymaster.KeymasterDefs;
@@ -44,29 +43,24 @@
import com.android.org.bouncycastle.jce.X509Principal;
import com.android.org.bouncycastle.jce.provider.X509CertificateObject;
import com.android.org.bouncycastle.x509.X509V3CertificateGenerator;
-import com.android.org.conscrypt.OpenSSLEngine;
import libcore.util.EmptyArray;
import java.math.BigInteger;
import java.security.InvalidAlgorithmParameterException;
-import java.security.InvalidKeyException;
-import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.KeyPairGeneratorSpi;
-import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.ProviderException;
import java.security.PublicKey;
import java.security.SecureRandom;
+import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateEncodingException;
import java.security.cert.X509Certificate;
import java.security.spec.AlgorithmParameterSpec;
import java.security.spec.ECGenParameterSpec;
-import java.security.spec.InvalidKeySpecException;
import java.security.spec.RSAKeyGenParameterSpec;
-import java.security.spec.X509EncodedKeySpec;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
@@ -147,6 +141,7 @@
SUPPORTED_EC_NIST_CURVE_NAMES.addAll(SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.keySet());
Collections.sort(SUPPORTED_EC_NIST_CURVE_NAMES);
}
+
private final int mOriginalKeymasterAlgorithm;
private KeyStore mKeyStore;
@@ -431,24 +426,6 @@
args.addInts(KeymasterDefs.KM_TAG_PADDING, mKeymasterSignaturePaddings);
args.addInts(KeymasterDefs.KM_TAG_DIGEST, mKeymasterDigests);
- // TODO: Remove the digest and padding NONE workaround below once Android Keystore returns
- // keys which are backed by AndroidKeyStoreBCWorkaround provider instead of Conscrypt. The
- // workaround is needed because Conscrypt (via keystore-engine) uses old KeyStore API which
- // translates into digest NONE and padding NONE in the new API. keystore-engine cannot be
- // updated to pass in the correct padding and digest values because it uses
- // OpenSSL/BoringSSL engine which performs digesting and padding prior before invoking
- // KeyStore API.
- if (!com.android.internal.util.ArrayUtils.contains(
- mKeymasterDigests, KeymasterDefs.KM_DIGEST_NONE)) {
- args.addInt(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_NONE);
- }
- if ((!com.android.internal.util.ArrayUtils.contains(
- mKeymasterSignaturePaddings, KeymasterDefs.KM_PAD_NONE))
- && (!com.android.internal.util.ArrayUtils.contains(
- mKeymasterEncryptionPaddings, KeymasterDefs.KM_PAD_NONE))) {
- args.addInt(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_NONE);
- }
-
KeymasterUtils.addUserAuthArgs(args,
mSpec.isUserAuthenticationRequired(),
mSpec.getUserAuthenticationValidityDurationSeconds());
@@ -483,40 +460,23 @@
"Failed to generate key pair", KeyStore.getKeyStoreException(errorCode));
}
- final PrivateKey privKey;
- final OpenSSLEngine engine = OpenSSLEngine.getInstance("keystore");
+ KeyPair result;
try {
- privKey = engine.getPrivateKeyById(privateKeyAlias);
- } catch (InvalidKeyException e) {
- throw new ProviderException("Failed to obtain generated private key", e);
+ result = AndroidKeyStoreProvider.loadAndroidKeyStoreKeyPairFromKeystore(
+ mKeyStore, privateKeyAlias);
+ } catch (UnrecoverableKeyException e) {
+ throw new ProviderException("Failed to load generated key pair from keystore", e);
}
- ExportResult exportResult =
- mKeyStore.exportKey(
- privateKeyAlias, KeymasterDefs.KM_KEY_FORMAT_X509, null, null);
- if (exportResult == null) {
- throw new KeyStoreConnectException();
- } else if (exportResult.resultCode != KeyStore.NO_ERROR) {
+ if (!mJcaKeyAlgorithm.equalsIgnoreCase(result.getPrivate().getAlgorithm())) {
throw new ProviderException(
- "Failed to obtain X.509 form of generated public key",
- KeyStore.getKeyStoreException(exportResult.resultCode));
- }
- final byte[] pubKeyBytes = exportResult.exportData;
-
- final PublicKey pubKey;
- try {
- final KeyFactory keyFact = KeyFactory.getInstance(mJcaKeyAlgorithm);
- pubKey = keyFact.generatePublic(new X509EncodedKeySpec(pubKeyBytes));
- } catch (NoSuchAlgorithmException e) {
- throw new ProviderException(
- "Failed to obtain " + mJcaKeyAlgorithm + " KeyFactory", e);
- } catch (InvalidKeySpecException e) {
- throw new ProviderException("Invalid X.509 encoding of generated public key", e);
+ "Generated key pair algorithm does not match requested algorithm: "
+ + result.getPrivate().getAlgorithm() + " vs " + mJcaKeyAlgorithm);
}
final X509Certificate cert;
try {
- cert = generateSelfSignedCertificate(privKey, pubKey);
+ cert = generateSelfSignedCertificate(result.getPrivate(), result.getPublic());
} catch (Exception e) {
throw new ProviderException("Failed to generate self-signed certificate", e);
}
@@ -539,7 +499,6 @@
KeyStore.getKeyStoreException(insertErrorCode));
}
- KeyPair result = new KeyPair(pubKey, privKey);
success = true;
return result;
} finally {
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java b/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java
index cb270bb..967319a 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java
@@ -16,11 +16,28 @@
package android.security.keystore;
+import android.annotation.NonNull;
import android.security.KeyStore;
+import android.security.keymaster.ExportResult;
+import android.security.keymaster.KeyCharacteristics;
+import android.security.keymaster.KeymasterDefs;
+import java.security.KeyFactory;
+import java.security.KeyPair;
+import java.security.NoSuchAlgorithmException;
import java.security.Provider;
+import java.security.ProviderException;
+import java.security.PublicKey;
import java.security.Security;
import java.security.Signature;
+import java.security.UnrecoverableKeyException;
+import java.security.interfaces.ECKey;
+import java.security.interfaces.ECPublicKey;
+import java.security.interfaces.RSAKey;
+import java.security.interfaces.RSAPublicKey;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.X509EncodedKeySpec;
+import java.util.List;
import javax.crypto.Cipher;
import javax.crypto.Mac;
@@ -146,4 +163,145 @@
}
return ((KeyStoreCryptoOperation) spi).getOperationHandle();
}
+
+ @NonNull
+ public static AndroidKeyStorePublicKey getAndroidKeyStorePublicKey(
+ @NonNull String alias,
+ @NonNull @KeyProperties.KeyAlgorithmEnum String keyAlgorithm,
+ @NonNull byte[] x509EncodedForm) {
+ PublicKey publicKey;
+ try {
+ KeyFactory keyFactory = KeyFactory.getInstance(keyAlgorithm);
+ publicKey = keyFactory.generatePublic(new X509EncodedKeySpec(x509EncodedForm));
+ } catch (NoSuchAlgorithmException e) {
+ throw new ProviderException(
+ "Failed to obtain " + keyAlgorithm + " KeyFactory", e);
+ } catch (InvalidKeySpecException e) {
+ throw new ProviderException("Invalid X.509 encoding of public key", e);
+ }
+ if (KeyProperties.KEY_ALGORITHM_EC.equalsIgnoreCase(keyAlgorithm)) {
+ return new AndroidKeyStoreECPublicKey(alias, (ECPublicKey) publicKey);
+ } else if (KeyProperties.KEY_ALGORITHM_RSA.equalsIgnoreCase(keyAlgorithm)) {
+ return new AndroidKeyStoreRSAPublicKey(alias, (RSAPublicKey) publicKey);
+ } else {
+ throw new ProviderException("Unsupported Android Keystore public key algorithm: "
+ + keyAlgorithm);
+ }
+ }
+
+ @NonNull
+ public static AndroidKeyStorePrivateKey getAndroidKeyStorePrivateKey(
+ @NonNull AndroidKeyStorePublicKey publicKey) {
+ String keyAlgorithm = publicKey.getAlgorithm();
+ if (KeyProperties.KEY_ALGORITHM_EC.equalsIgnoreCase(keyAlgorithm)) {
+ return new AndroidKeyStoreECPrivateKey(
+ publicKey.getAlias(), ((ECKey) publicKey).getParams());
+ } else if (KeyProperties.KEY_ALGORITHM_RSA.equalsIgnoreCase(keyAlgorithm)) {
+ return new AndroidKeyStoreRSAPrivateKey(
+ publicKey.getAlias(), ((RSAKey) publicKey).getModulus());
+ } else {
+ throw new ProviderException("Unsupported Android Keystore public key algorithm: "
+ + keyAlgorithm);
+ }
+ }
+
+ @NonNull
+ public static AndroidKeyStorePublicKey loadAndroidKeyStorePublicKeyFromKeystore(
+ @NonNull KeyStore keyStore, @NonNull String privateKeyAlias)
+ throws UnrecoverableKeyException {
+ KeyCharacteristics keyCharacteristics = new KeyCharacteristics();
+ int errorCode = keyStore.getKeyCharacteristics(
+ privateKeyAlias, null, null, keyCharacteristics);
+ if (errorCode != KeyStore.NO_ERROR) {
+ throw (UnrecoverableKeyException)
+ new UnrecoverableKeyException("Failed to obtain information about private key")
+ .initCause(KeyStore.getKeyStoreException(errorCode));
+ }
+ ExportResult exportResult = keyStore.exportKey(
+ privateKeyAlias, KeymasterDefs.KM_KEY_FORMAT_X509, null, null);
+ if (exportResult.resultCode != KeyStore.NO_ERROR) {
+ throw (UnrecoverableKeyException)
+ new UnrecoverableKeyException("Failed to obtain X.509 form of public key")
+ .initCause(KeyStore.getKeyStoreException(errorCode));
+ }
+ final byte[] x509EncodedPublicKey = exportResult.exportData;
+
+ int keymasterAlgorithm = keyCharacteristics.getInt(KeymasterDefs.KM_TAG_ALGORITHM, -1);
+ if (keymasterAlgorithm == -1) {
+ throw new UnrecoverableKeyException("Key algorithm unknown");
+ }
+
+ String jcaKeyAlgorithm;
+ try {
+ jcaKeyAlgorithm = KeyProperties.KeyAlgorithm.fromKeymasterAsymmetricKeyAlgorithm(
+ keymasterAlgorithm);
+ } catch (IllegalArgumentException e) {
+ throw (UnrecoverableKeyException)
+ new UnrecoverableKeyException("Failed to load private key")
+ .initCause(e);
+ }
+
+ return AndroidKeyStoreProvider.getAndroidKeyStorePublicKey(
+ privateKeyAlias, jcaKeyAlgorithm, x509EncodedPublicKey);
+ }
+
+ @NonNull
+ public static KeyPair loadAndroidKeyStoreKeyPairFromKeystore(
+ @NonNull KeyStore keyStore, @NonNull String privateKeyAlias)
+ throws UnrecoverableKeyException {
+ AndroidKeyStorePublicKey publicKey =
+ loadAndroidKeyStorePublicKeyFromKeystore(keyStore, privateKeyAlias);
+ AndroidKeyStorePrivateKey privateKey =
+ AndroidKeyStoreProvider.getAndroidKeyStorePrivateKey(publicKey);
+ return new KeyPair(publicKey, privateKey);
+ }
+
+ @NonNull
+ public static AndroidKeyStorePrivateKey loadAndroidKeyStorePrivateKeyFromKeystore(
+ @NonNull KeyStore keyStore, @NonNull String privateKeyAlias)
+ throws UnrecoverableKeyException {
+ KeyPair keyPair = loadAndroidKeyStoreKeyPairFromKeystore(keyStore, privateKeyAlias);
+ return (AndroidKeyStorePrivateKey) keyPair.getPrivate();
+ }
+
+ @NonNull
+ public static AndroidKeyStoreSecretKey loadAndroidKeyStoreSecretKeyFromKeystore(
+ @NonNull KeyStore keyStore, @NonNull String secretKeyAlias)
+ throws UnrecoverableKeyException {
+ KeyCharacteristics keyCharacteristics = new KeyCharacteristics();
+ int errorCode = keyStore.getKeyCharacteristics(
+ secretKeyAlias, null, null, keyCharacteristics);
+ if (errorCode != KeyStore.NO_ERROR) {
+ throw (UnrecoverableKeyException)
+ new UnrecoverableKeyException("Failed to obtain information about key")
+ .initCause(KeyStore.getKeyStoreException(errorCode));
+ }
+
+ int keymasterAlgorithm = keyCharacteristics.getInt(KeymasterDefs.KM_TAG_ALGORITHM, -1);
+ if (keymasterAlgorithm == -1) {
+ throw new UnrecoverableKeyException("Key algorithm unknown");
+ }
+
+ List<Integer> keymasterDigests =
+ keyCharacteristics.getInts(KeymasterDefs.KM_TAG_DIGEST);
+ int keymasterDigest;
+ if (keymasterDigests.isEmpty()) {
+ keymasterDigest = -1;
+ } else {
+ // More than one digest can be permitted for this key. Use the first one to form the
+ // JCA key algorithm name.
+ keymasterDigest = keymasterDigests.get(0);
+ }
+
+ @KeyProperties.KeyAlgorithmEnum String keyAlgorithmString;
+ try {
+ keyAlgorithmString = KeyProperties.KeyAlgorithm.fromKeymasterSecretKeyAlgorithm(
+ keymasterAlgorithm, keymasterDigest);
+ } catch (IllegalArgumentException e) {
+ throw (UnrecoverableKeyException)
+ new UnrecoverableKeyException("Unsupported secret key type").initCause(e);
+ }
+
+ return new AndroidKeyStoreSecretKey(secretKeyAlias, keyAlgorithmString);
+ }
}
diff --git a/keystore/java/android/security/keystore/AndroidKeyStorePublicKey.java b/keystore/java/android/security/keystore/AndroidKeyStorePublicKey.java
index 8133d46..9fea30d 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStorePublicKey.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStorePublicKey.java
@@ -17,6 +17,7 @@
package android.security.keystore;
import java.security.PublicKey;
+import java.util.Arrays;
/**
* {@link PublicKey} backed by Android Keystore.
@@ -41,4 +42,30 @@
public byte[] getEncoded() {
return ArrayUtils.cloneIfNotEmpty(mEncoded);
}
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = super.hashCode();
+ result = prime * result + Arrays.hashCode(mEncoded);
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (!super.equals(obj)) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ AndroidKeyStorePublicKey other = (AndroidKeyStorePublicKey) obj;
+ if (!Arrays.equals(mEncoded, other.mEncoded)) {
+ return false;
+ }
+ return true;
+ }
}
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreRSAPrivateKey.java b/keystore/java/android/security/keystore/AndroidKeyStoreRSAPrivateKey.java
new file mode 100644
index 0000000..179ffd8
--- /dev/null
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreRSAPrivateKey.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.keystore;
+
+import java.math.BigInteger;
+import java.security.PrivateKey;
+import java.security.interfaces.RSAKey;
+
+/**
+ * RSA private key (instance of {@link PrivateKey} and {@link RSAKey}) backed by keystore.
+ *
+ * @hide
+ */
+public class AndroidKeyStoreRSAPrivateKey extends AndroidKeyStorePrivateKey implements RSAKey {
+
+ private final BigInteger mModulus;
+
+ public AndroidKeyStoreRSAPrivateKey(String alias, BigInteger modulus) {
+ super(alias, KeyProperties.KEY_ALGORITHM_RSA);
+ mModulus = modulus;
+ }
+
+ @Override
+ public BigInteger getModulus() {
+ return mModulus;
+ }
+}
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreSignatureSpiBase.java b/keystore/java/android/security/keystore/AndroidKeyStoreSignatureSpiBase.java
index 4c4062f..f072ae7 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreSignatureSpiBase.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreSignatureSpiBase.java
@@ -25,7 +25,7 @@
import android.security.keymaster.KeymasterDefs;
import android.security.keymaster.OperationResult;
-import com.android.org.conscrypt.util.EmptyArray;
+import libcore.util.EmptyArray;
import java.nio.ByteBuffer;
import java.security.InvalidKeyException;
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
index c03be63..831a106 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
@@ -16,9 +16,6 @@
package android.security.keystore;
-import com.android.org.conscrypt.OpenSSLEngine;
-import com.android.org.conscrypt.OpenSSLKeyHolder;
-
import libcore.util.EmptyArray;
import android.security.Credentials;
@@ -35,7 +32,6 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
-import java.security.InvalidKeyException;
import java.security.Key;
import java.security.KeyStore.Entry;
import java.security.KeyStore.PrivateKeyEntry;
@@ -45,6 +41,7 @@
import java.security.KeyStoreSpi;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
+import java.security.PublicKey;
import java.security.UnrecoverableKeyException;
import java.security.cert.Certificate;
import java.security.cert.CertificateEncodingException;
@@ -59,7 +56,6 @@
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Iterator;
-import java.util.List;
import java.util.Set;
import javax.crypto.SecretKey;
@@ -92,59 +88,17 @@
public Key engineGetKey(String alias, char[] password) throws NoSuchAlgorithmException,
UnrecoverableKeyException {
if (isPrivateKeyEntry(alias)) {
- final OpenSSLEngine engine = OpenSSLEngine.getInstance("keystore");
- try {
- return engine.getPrivateKeyById(Credentials.USER_PRIVATE_KEY + alias);
- } catch (InvalidKeyException e) {
- UnrecoverableKeyException t = new UnrecoverableKeyException("Can't get key");
- t.initCause(e);
- throw t;
- }
+ String privateKeyAlias = Credentials.USER_PRIVATE_KEY + alias;
+ return AndroidKeyStoreProvider.loadAndroidKeyStorePrivateKeyFromKeystore(
+ mKeyStore, privateKeyAlias);
} else if (isSecretKeyEntry(alias)) {
- KeyCharacteristics keyCharacteristics = new KeyCharacteristics();
- String keyAliasInKeystore = Credentials.USER_SECRET_KEY + alias;
- int errorCode = mKeyStore.getKeyCharacteristics(
- keyAliasInKeystore, null, null, keyCharacteristics);
- if (errorCode != KeyStore.NO_ERROR) {
- throw (UnrecoverableKeyException)
- new UnrecoverableKeyException("Failed to load information about key")
- .initCause(mKeyStore.getInvalidKeyException(alias, errorCode));
- }
-
- int keymasterAlgorithm =
- keyCharacteristics.hwEnforced.getInt(KeymasterDefs.KM_TAG_ALGORITHM, -1);
- if (keymasterAlgorithm == -1) {
- keymasterAlgorithm =
- keyCharacteristics.swEnforced.getInt(KeymasterDefs.KM_TAG_ALGORITHM, -1);
- }
- if (keymasterAlgorithm == -1) {
- throw new UnrecoverableKeyException("Key algorithm unknown");
- }
-
- List<Integer> keymasterDigests =
- keyCharacteristics.getInts(KeymasterDefs.KM_TAG_DIGEST);
- int keymasterDigest;
- if (keymasterDigests.isEmpty()) {
- keymasterDigest = -1;
- } else {
- // More than one digest can be permitted for this key. Use the first one to form the
- // JCA key algorithm name.
- keymasterDigest = keymasterDigests.get(0);
- }
-
- @KeyProperties.KeyAlgorithmEnum String keyAlgorithmString;
- try {
- keyAlgorithmString = KeyProperties.KeyAlgorithm.fromKeymasterSecretKeyAlgorithm(
- keymasterAlgorithm, keymasterDigest);
- } catch (IllegalArgumentException e) {
- throw (UnrecoverableKeyException)
- new UnrecoverableKeyException("Unsupported secret key type").initCause(e);
- }
-
- return new AndroidKeyStoreSecretKey(keyAliasInKeystore, keyAlgorithmString);
+ String secretKeyAlias = Credentials.USER_SECRET_KEY + alias;
+ return AndroidKeyStoreProvider.loadAndroidKeyStoreSecretKeyFromKeystore(
+ mKeyStore, secretKeyAlias);
+ } else {
+ // Key not found
+ return null;
}
-
- return null;
}
@Override
@@ -188,22 +142,36 @@
byte[] certificate = mKeyStore.get(Credentials.USER_CERTIFICATE + alias);
if (certificate != null) {
- return toCertificate(certificate);
+ return wrapIntoKeyStoreCertificate(
+ Credentials.USER_PRIVATE_KEY + alias, toCertificate(certificate));
}
certificate = mKeyStore.get(Credentials.CA_CERTIFICATE + alias);
if (certificate != null) {
- return toCertificate(certificate);
+ return wrapIntoKeyStoreCertificate(
+ Credentials.USER_PRIVATE_KEY + alias, toCertificate(certificate));
}
return null;
}
+ /**
+ * Wraps the provided cerificate into {@link KeyStoreX509Certificate} so that the public key
+ * returned by the certificate contains information about the alias of the private key in
+ * keystore. This is needed so that Android Keystore crypto operations using public keys can
+ * find out which key alias to use. These operations cannot work without an alias.
+ */
+ private static KeyStoreX509Certificate wrapIntoKeyStoreCertificate(
+ String privateKeyAlias, X509Certificate certificate) {
+ return (certificate != null)
+ ? new KeyStoreX509Certificate(privateKeyAlias, certificate) : null;
+ }
+
private static X509Certificate toCertificate(byte[] bytes) {
try {
final CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
- return (X509Certificate) certFactory
- .generateCertificate(new ByteArrayInputStream(bytes));
+ return (X509Certificate) certFactory.generateCertificate(
+ new ByteArrayInputStream(bytes));
} catch (CertificateException e) {
Log.w(NAME, "Couldn't parse certificate in keystore", e);
return null;
@@ -214,8 +182,8 @@
private static Collection<X509Certificate> toCertificates(byte[] bytes) {
try {
final CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
- return (Collection<X509Certificate>) certFactory
- .generateCertificates(new ByteArrayInputStream(bytes));
+ return (Collection<X509Certificate>) certFactory.generateCertificates(
+ new ByteArrayInputStream(bytes));
} catch (CertificateException e) {
Log.w(NAME, "Couldn't parse certificates in keystore", e);
return new ArrayList<X509Certificate>();
@@ -406,9 +374,7 @@
}
final String pkeyAlias;
- if (key instanceof OpenSSLKeyHolder) {
- pkeyAlias = ((OpenSSLKeyHolder) key).getOpenSSLKey().getAlias();
- } else if (key instanceof AndroidKeyStorePrivateKey) {
+ if (key instanceof AndroidKeyStorePrivateKey) {
pkeyAlias = ((AndroidKeyStoreKey) key).getAlias();
} else {
pkeyAlias = null;
@@ -851,6 +817,19 @@
if (cert == null) {
return null;
}
+ if (!"X.509".equalsIgnoreCase(cert.getType())) {
+ // Only X.509 certificates supported
+ return null;
+ }
+ byte[] targetCertBytes;
+ try {
+ targetCertBytes = cert.getEncoded();
+ } catch (CertificateEncodingException e) {
+ return null;
+ }
+ if (targetCertBytes == null) {
+ return null;
+ }
final Set<String> nonCaEntries = new HashSet<String>();
@@ -868,10 +847,9 @@
continue;
}
- final Certificate c = toCertificate(certBytes);
nonCaEntries.add(alias);
- if (cert.equals(c)) {
+ if (Arrays.equals(certBytes, targetCertBytes)) {
return alias;
}
}
@@ -893,9 +871,7 @@
continue;
}
- final Certificate c =
- toCertificate(mKeyStore.get(Credentials.CA_CERTIFICATE + alias));
- if (cert.equals(c)) {
+ if (Arrays.equals(certBytes, targetCertBytes)) {
return alias;
}
}
@@ -954,4 +930,25 @@
}
}
+ /**
+ * {@link X509Certificate} which returns {@link AndroidKeyStorePublicKey} from
+ * {@link #getPublicKey()}. This is so that crypto operations on these public keys contain
+ * can find out which keystore private key entry to use. This is needed so that Android Keystore
+ * crypto operations using public keys can find out which key alias to use. These operations
+ * require an alias.
+ */
+ static class KeyStoreX509Certificate extends DelegatingX509Certificate {
+ private final String mPrivateKeyAlias;
+ KeyStoreX509Certificate(String privateKeyAlias, X509Certificate delegate) {
+ super(delegate);
+ mPrivateKeyAlias = privateKeyAlias;
+ }
+
+ @Override
+ public PublicKey getPublicKey() {
+ PublicKey original = super.getPublicKey();
+ return AndroidKeyStoreProvider.getAndroidKeyStorePublicKey(
+ mPrivateKeyAlias, original.getAlgorithm(), original.getEncoded());
+ }
+ }
}
diff --git a/keystore/java/android/security/keystore/DelegatingX509Certificate.java b/keystore/java/android/security/keystore/DelegatingX509Certificate.java
new file mode 100644
index 0000000..03d202f
--- /dev/null
+++ b/keystore/java/android/security/keystore/DelegatingX509Certificate.java
@@ -0,0 +1,212 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.keystore;
+
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Principal;
+import java.security.PublicKey;
+import java.security.SignatureException;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateExpiredException;
+import java.security.cert.CertificateNotYetValidException;
+import java.security.cert.CertificateParsingException;
+import java.security.cert.X509Certificate;
+import java.util.Collection;
+import java.util.Date;
+import java.util.List;
+import java.util.Set;
+
+import javax.security.auth.x500.X500Principal;
+
+class DelegatingX509Certificate extends X509Certificate {
+ private final X509Certificate mDelegate;
+
+ DelegatingX509Certificate(X509Certificate delegate) {
+ mDelegate = delegate;
+ }
+
+ @Override
+ public Set<String> getCriticalExtensionOIDs() {
+ return mDelegate.getCriticalExtensionOIDs();
+ }
+
+ @Override
+ public byte[] getExtensionValue(String oid) {
+ return mDelegate.getExtensionValue(oid);
+ }
+
+ @Override
+ public Set<String> getNonCriticalExtensionOIDs() {
+ return mDelegate.getNonCriticalExtensionOIDs();
+ }
+
+ @Override
+ public boolean hasUnsupportedCriticalExtension() {
+ return mDelegate.hasUnsupportedCriticalExtension();
+ }
+
+ @Override
+ public void checkValidity() throws CertificateExpiredException,
+ CertificateNotYetValidException {
+ mDelegate.checkValidity();
+ }
+
+ @Override
+ public void checkValidity(Date date) throws CertificateExpiredException,
+ CertificateNotYetValidException {
+ mDelegate.checkValidity(date);
+ }
+
+ @Override
+ public int getBasicConstraints() {
+ return mDelegate.getBasicConstraints();
+ }
+
+ @Override
+ public Principal getIssuerDN() {
+ return mDelegate.getIssuerDN();
+ }
+
+ @Override
+ public boolean[] getIssuerUniqueID() {
+ return mDelegate.getIssuerUniqueID();
+ }
+
+ @Override
+ public boolean[] getKeyUsage() {
+ return mDelegate.getKeyUsage();
+ }
+
+ @Override
+ public Date getNotAfter() {
+ return mDelegate.getNotAfter();
+ }
+
+ @Override
+ public Date getNotBefore() {
+ return mDelegate.getNotBefore();
+ }
+
+ @Override
+ public BigInteger getSerialNumber() {
+ return mDelegate.getSerialNumber();
+ }
+
+ @Override
+ public String getSigAlgName() {
+ return mDelegate.getSigAlgName();
+ }
+
+ @Override
+ public String getSigAlgOID() {
+ return mDelegate.getSigAlgOID();
+ }
+
+ @Override
+ public byte[] getSigAlgParams() {
+ return mDelegate.getSigAlgParams();
+ }
+
+ @Override
+ public byte[] getSignature() {
+ return mDelegate.getSignature();
+ }
+
+ @Override
+ public Principal getSubjectDN() {
+ return mDelegate.getSubjectDN();
+ }
+
+ @Override
+ public boolean[] getSubjectUniqueID() {
+ return mDelegate.getSubjectUniqueID();
+ }
+
+ @Override
+ public byte[] getTBSCertificate() throws CertificateEncodingException {
+ return mDelegate.getTBSCertificate();
+ }
+
+ @Override
+ public int getVersion() {
+ return mDelegate.getVersion();
+ }
+
+ @Override
+ public byte[] getEncoded() throws CertificateEncodingException {
+ return mDelegate.getEncoded();
+ }
+
+ @Override
+ public PublicKey getPublicKey() {
+ return mDelegate.getPublicKey();
+ }
+
+ @Override
+ public String toString() {
+ return mDelegate.toString();
+ }
+
+ @Override
+ public void verify(PublicKey key)
+ throws CertificateException,
+ NoSuchAlgorithmException,
+ InvalidKeyException,
+ NoSuchProviderException,
+ SignatureException {
+ mDelegate.verify(key);
+ }
+
+ @Override
+ public void verify(PublicKey key, String sigProvider)
+ throws CertificateException,
+ NoSuchAlgorithmException,
+ InvalidKeyException,
+ NoSuchProviderException,
+ SignatureException {
+ mDelegate.verify(key, sigProvider);
+ }
+
+ @Override
+ public List<String> getExtendedKeyUsage() throws CertificateParsingException {
+ return mDelegate.getExtendedKeyUsage();
+ }
+
+ @Override
+ public Collection<List<?>> getIssuerAlternativeNames() throws CertificateParsingException {
+ return mDelegate.getIssuerAlternativeNames();
+ }
+
+ @Override
+ public X500Principal getIssuerX500Principal() {
+ return mDelegate.getIssuerX500Principal();
+ }
+
+ @Override
+ public Collection<List<?>> getSubjectAlternativeNames() throws CertificateParsingException {
+ return mDelegate.getSubjectAlternativeNames();
+ }
+
+ @Override
+ public X500Principal getSubjectX500Principal() {
+ return mDelegate.getSubjectX500Principal();
+ }
+}
diff --git a/keystore/java/android/security/keystore/KeyGenParameterSpec.java b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
index 19ff9c7..68c9c79 100644
--- a/keystore/java/android/security/keystore/KeyGenParameterSpec.java
+++ b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
@@ -449,9 +449,6 @@
* invalid signature. This is OK if the certificate is only used for obtaining the
* public key from Android KeyStore.
*
- * <p><b>NOTE: The {@code purposes} parameter has currently no effect on asymmetric
- * key pairs.</b>
- *
* <p>See {@link KeyProperties}.{@code PURPOSE} flags.
*/
public Builder(@NonNull String keystoreAlias, @KeyProperties.PurposeEnum int purposes) {
@@ -556,8 +553,6 @@
*
* <p>By default, the key is valid at any instant.
*
- * <p><b>NOTE: This has currently no effect on asymmetric key pairs.</b>
- *
* @see #setKeyValidityEnd(Date)
*/
@NonNull
@@ -571,8 +566,6 @@
*
* <p>By default, the key is valid at any instant.
*
- * <p><b>NOTE: This has currently no effect on asymmetric key pairs.</b>
- *
* @see #setKeyValidityStart(Date)
* @see #setKeyValidityForConsumptionEnd(Date)
* @see #setKeyValidityForOriginationEnd(Date)
@@ -589,8 +582,6 @@
*
* <p>By default, the key is valid at any instant.
*
- * <p><b>NOTE: This has currently no effect on asymmetric key pairs.</b>
- *
* @see #setKeyValidityForConsumptionEnd(Date)
*/
@NonNull
@@ -605,8 +596,6 @@
*
* <p>By default, the key is valid at any instant.
*
- * <p><b>NOTE: This has currently no effect on asymmetric key pairs.</b>
- *
* @see #setKeyValidityForOriginationEnd(Date)
*/
@NonNull
@@ -624,8 +613,6 @@
* keys, the set of digests defaults to the digest associated with the key algorithm (e.g.,
* {@code SHA-256} for key algorithm {@code HmacSHA256}
*
- * <p><b>NOTE: This has currently no effect on asymmetric key pairs.</b>
- *
* @see KeyProperties.Digest
*/
@NonNull
@@ -642,8 +629,6 @@
*
* <p>This must be specified for keys which are used for encryption/decryption.
*
- * <p><b>NOTE: This has currently no effect on asymmetric key pairs.</b>
- *
* <p>See {@link KeyProperties}.{@code ENCRYPTION_PADDING} constants.
*/
@NonNull
@@ -660,8 +645,6 @@
*
* <p>This must be specified for RSA keys which are used for signing/verification.
*
- * <p><b>NOTE: This has currently no effect on asymmetric key pairs.</b>
- *
* <p>See {@link KeyProperties}.{@code SIGNATURE_PADDING} constants.
*/
@NonNull
@@ -678,8 +661,6 @@
*
* <p>This must be specified for encryption/decryption keys.
*
- * <p><b>NOTE: This has currently no effect on asymmetric key pairs.</b>
- *
* <p>See {@link KeyProperties}.{@code BLOCK_MODE} constants.
*/
@NonNull
@@ -723,8 +704,6 @@
* <li>If you are using RSA encryption without padding, consider switching to encryption
* padding schemes which offer {@code IND-CPA}, such as PKCS#1 or OAEP.</li>
* </ul>
- *
- * <p><b>NOTE: This has currently no effect on asymmetric key pairs.</b>
*/
@NonNull
public Builder setRandomizedEncryptionRequired(boolean required) {
@@ -748,8 +727,6 @@
* <p>This restriction applies only to private key operations. Public key operations are not
* restricted.
*
- * <p><b>NOTE: This has currently no effect on asymmetric key pairs.</b>
- *
* @see #setUserAuthenticationValidityDurationSeconds(int)
*/
@NonNull
@@ -764,8 +741,6 @@
*
* <p>By default, the user needs to authenticate for every use of the key.
*
- * <p><b>NOTE: This has currently no effect on asymmetric key pairs.</b>
- *
* @param seconds duration in seconds or {@code -1} if the user needs to authenticate for
* every use of the key.
*
diff --git a/keystore/java/android/security/keystore/KeyProtection.java b/keystore/java/android/security/keystore/KeyProtection.java
index f52a193..48c0ed0f 100644
--- a/keystore/java/android/security/keystore/KeyProtection.java
+++ b/keystore/java/android/security/keystore/KeyProtection.java
@@ -305,9 +305,6 @@
* @param purposes set of purposes (e.g., encrypt, decrypt, sign) for which the key can be
* used. Attempts to use the key for any other purpose will be rejected.
*
- * <p><b>NOTE: The {@code purposes} parameter has currently no effect on asymmetric
- * key pairs.</b>
- *
* <p>See {@link KeyProperties}.{@code PURPOSE} flags.
*/
public Builder(@KeyProperties.PurposeEnum int purposes) {
@@ -319,8 +316,6 @@
*
* <p>By default, the key is valid at any instant.
*
- * <p><b>NOTE: This has currently no effect on asymmetric key pairs.</b>
- *
* @see #setKeyValidityEnd(Date)
*/
@NonNull
@@ -334,8 +329,6 @@
*
* <p>By default, the key is valid at any instant.
*
- * <p><b>NOTE: This has currently no effect on asymmetric key pairs.</b>
- *
* @see #setKeyValidityStart(Date)
* @see #setKeyValidityForConsumptionEnd(Date)
* @see #setKeyValidityForOriginationEnd(Date)
@@ -352,8 +345,6 @@
*
* <p>By default, the key is valid at any instant.
*
- * <p><b>NOTE: This has currently no effect on asymmetric key pairs.</b>
- *
* @see #setKeyValidityForConsumptionEnd(Date)
*/
@NonNull
@@ -368,8 +359,6 @@
*
* <p>By default, the key is valid at any instant.
*
- * <p><b>NOTE: This has currently no effect on asymmetric key pairs.</b>
- *
* @see #setKeyValidityForOriginationEnd(Date)
*/
@NonNull
@@ -385,8 +374,6 @@
*
* <p>This must be specified for keys which are used for encryption/decryption.
*
- * <p><b>NOTE: This has currently no effect on asymmetric key pairs.</b>
- *
* <p>See {@link KeyProperties}.{@code ENCRYPTION_PADDING} constants.
*/
@NonNull
@@ -403,8 +390,6 @@
*
* <p>This must be specified for RSA keys which are used for signing/verification.
*
- * <p><b>NOTE: This has currently no effect on asymmetric key pairs.</b>
- *
* <p>See {@link KeyProperties}.{@code SIGNATURE_PADDING} constants.
*/
@NonNull
@@ -423,8 +408,6 @@
* {@link Key#getAlgorithm()}. For asymmetric signing keys the set of digest algorithms
* must be specified.
*
- * <p><b>NOTE: This has currently no effect on asymmetric key pairs.</b>
- *
* <p>See {@link KeyProperties}.{@code DIGEST} constants.
*/
@NonNull
@@ -440,8 +423,6 @@
*
* <p>This must be specified for encryption/decryption keys.
*
- * <p><b>NOTE: This has currently no effect on asymmetric key pairs.</b>
- *
* <p>See {@link KeyProperties}.{@code BLOCK_MODE} constants.
*/
@NonNull
@@ -483,8 +464,6 @@
* <li>If you are using RSA encryption without padding, consider switching to padding
* schemes which offer {@code IND-CPA}, such as PKCS#1 or OAEP.</li>
* </ul>
- *
- * <p><b>NOTE: This has currently no effect on asymmetric key pairs.</b>
*/
@NonNull
public Builder setRandomizedEncryptionRequired(boolean required) {
@@ -505,8 +484,6 @@
* <a href="{@docRoot}training/articles/keystore.html#UserAuthentication">More
* information</a>.
*
- * <p><b>NOTE: This has currently no effect on asymmetric key pairs.</b>
- *
* @see #setUserAuthenticationValidityDurationSeconds(int)
*/
@NonNull
@@ -521,8 +498,6 @@
*
* <p>By default, the user needs to authenticate for every use of the key.
*
- * <p><b>NOTE: This has currently no effect on asymmetric key pairs.</b>
- *
* @param seconds duration in seconds or {@code -1} if the user needs to authenticate for
* every use of the key.
*
diff --git a/keystore/java/android/security/keystore/KeymasterUtils.java b/keystore/java/android/security/keystore/KeymasterUtils.java
index 0639d49..4b37d90 100644
--- a/keystore/java/android/security/keystore/KeymasterUtils.java
+++ b/keystore/java/android/security/keystore/KeymasterUtils.java
@@ -101,13 +101,10 @@
// fingerprint-only auth.
FingerprintManager fingerprintManager =
KeyStore.getApplicationContext().getSystemService(FingerprintManager.class);
- if ((fingerprintManager == null) || (!fingerprintManager.isHardwareDetected())) {
- throw new IllegalStateException(
- "This device does not support keys which require authentication for every"
- + " use -- this requires fingerprint authentication which is not"
- + " available on this device");
- }
- long fingerprintOnlySid = fingerprintManager.getAuthenticatorId();
+ // TODO: Restore USE_FINGERPRINT permission check in
+ // FingerprintManager.getAuthenticatorId once the ID is no longer needed here.
+ long fingerprintOnlySid =
+ (fingerprintManager != null) ? fingerprintManager.getAuthenticatorId() : 0;
if (fingerprintOnlySid == 0) {
throw new IllegalStateException(
"At least one fingerprint must be enrolled to create keys requiring user"
diff --git a/keystore/tests/src/android/security/KeyStoreTest.java b/keystore/tests/src/android/security/KeyStoreTest.java
index 44fb826..0b60c62 100644
--- a/keystore/tests/src/android/security/KeyStoreTest.java
+++ b/keystore/tests/src/android/security/KeyStoreTest.java
@@ -20,7 +20,6 @@
import android.os.Binder;
import android.os.IBinder;
import android.os.Process;
-import android.os.ServiceManager;
import android.security.keymaster.ExportResult;
import android.security.keymaster.KeyCharacteristics;
import android.security.keymaster.KeymasterArguments;
@@ -34,13 +33,9 @@
import com.android.org.conscrypt.NativeConstants;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
-import java.util.Date;
import java.util.HashSet;
import java.security.spec.RSAKeyGenParameterSpec;
-import android.util.Log;
-import android.util.Base64;
-
/**
* Junit / Instrumentation test case for KeyStore class
*
diff --git a/keystore/tests/src/android/security/keystore/AndroidKeyPairGeneratorTest.java b/keystore/tests/src/android/security/keystore/AndroidKeyPairGeneratorTest.java
index 8488acd..e5c15c5 100644
--- a/keystore/tests/src/android/security/keystore/AndroidKeyPairGeneratorTest.java
+++ b/keystore/tests/src/android/security/keystore/AndroidKeyPairGeneratorTest.java
@@ -26,17 +26,21 @@
import java.io.ByteArrayInputStream;
import java.math.BigInteger;
import java.security.KeyPair;
+import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
+import java.security.interfaces.ECKey;
import java.security.interfaces.ECPublicKey;
+import java.security.interfaces.RSAKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.AlgorithmParameterSpec;
import java.security.spec.RSAKeyGenParameterSpec;
import java.text.SimpleDateFormat;
+import java.util.Arrays;
import java.util.Date;
import javax.security.auth.x500.X500Principal;
@@ -158,6 +162,26 @@
}
public void testKeyPairGenerator_GenerateKeyPair_EC_Unencrypted_Success() throws Exception {
+ KeyPairGenerator generator = KeyPairGenerator.getInstance("EC", "AndroidKeyStore");
+ generator.initialize(new KeyGenParameterSpec.Builder(
+ TEST_ALIAS_1,
+ KeyProperties.PURPOSE_SIGN | KeyProperties.PURPOSE_VERIFY)
+ .setCertificateSubject(TEST_DN_1)
+ .setCertificateSerialNumber(TEST_SERIAL_1)
+ .setCertificateNotBefore(NOW)
+ .setCertificateNotAfter(NOW_PLUS_10_YEARS)
+ .setDigests(KeyProperties.DIGEST_SHA256)
+ .build());
+
+ final KeyPair pair = generator.generateKeyPair();
+ assertNotNull("The KeyPair returned should not be null", pair);
+
+ assertKeyPairCorrect(pair, TEST_ALIAS_1, "EC", 256, null, TEST_DN_1, TEST_SERIAL_1, NOW,
+ NOW_PLUS_10_YEARS);
+ }
+
+ public void testKeyPairGenerator_Legacy_GenerateKeyPair_EC_Unencrypted_Success()
+ throws Exception {
mGenerator.initialize(new KeyPairGeneratorSpec.Builder(getContext())
.setAlias(TEST_ALIAS_1)
.setKeyType("EC")
@@ -328,19 +352,40 @@
assertNotNull("The PrivateKey for the KeyPair should be not null", privKey);
assertEquals(keyType, privKey.getAlgorithm());
+ if ("EC".equalsIgnoreCase(keyType)) {
+ assertTrue("EC private key must be instanceof ECKey: " + privKey.getClass().getName(),
+ privKey instanceof ECKey);
+ assertEquals("Private and public key must have the same EC parameters",
+ ((ECKey) pubKey).getParams(), ((ECKey) privKey).getParams());
+ } else if ("RSA".equalsIgnoreCase(keyType)) {
+ assertTrue("RSA private key must be instance of RSAKey: "
+ + privKey.getClass().getName(),
+ privKey instanceof RSAKey);
+ assertEquals("Private and public key must have the same RSA modulus",
+ ((RSAKey) pubKey).getModulus(), ((RSAKey) privKey).getModulus());
+ }
+
final byte[] userCertBytes = mAndroidKeyStore.get(Credentials.USER_CERTIFICATE + alias);
assertNotNull("The user certificate should exist for the generated entry", userCertBytes);
final CertificateFactory cf = CertificateFactory.getInstance("X.509");
- final Certificate userCert = cf
- .generateCertificate(new ByteArrayInputStream(userCertBytes));
+ final Certificate userCert =
+ cf.generateCertificate(new ByteArrayInputStream(userCertBytes));
assertTrue("Certificate should be in X.509 format", userCert instanceof X509Certificate);
final X509Certificate x509userCert = (X509Certificate) userCert;
+ assertEquals(
+ "Public key used to sign certificate should have the same algorithm as in KeyPair",
+ pubKey.getAlgorithm(), x509userCert.getPublicKey().getAlgorithm());
+
assertEquals("PublicKey used to sign certificate should match one returned in KeyPair",
- pubKey, x509userCert.getPublicKey());
+ pubKey,
+ AndroidKeyStoreProvider.getAndroidKeyStorePublicKey(
+ Credentials.USER_PRIVATE_KEY + alias,
+ x509userCert.getPublicKey().getAlgorithm(),
+ x509userCert.getPublicKey().getEncoded()));
assertEquals("The Subject DN should be the one passed into the params", dn,
x509userCert.getSubjectDN());
@@ -357,7 +402,10 @@
assertDateEquals("The notAfter date should be the one passed into the params", end,
x509userCert.getNotAfter());
+ // Assert that the cert's signature verifies using the public key from generated KeyPair
x509userCert.verify(pubKey);
+ // Assert that the cert's signature verifies using the public key from the cert itself.
+ x509userCert.verify(x509userCert.getPublicKey());
final byte[] caCerts = mAndroidKeyStore.get(Credentials.CA_CERTIFICATE + alias);
assertNull("A list of CA certificates should not exist for the generated entry", caCerts);
@@ -368,6 +416,8 @@
final byte[] pubKeyBytes = exportResult.exportData;
assertNotNull("The keystore should return the public key for the generated key",
pubKeyBytes);
+ assertTrue("Public key X.509 format should be as expected",
+ Arrays.equals(pubKey.getEncoded(), pubKeyBytes));
}
private static void assertDateEquals(String message, Date date1, Date date2) throws Exception {
diff --git a/keystore/tests/src/android/security/keystore/AndroidKeyStoreTest.java b/keystore/tests/src/android/security/keystore/AndroidKeyStoreTest.java
index 336fa40..c3b731b 100644
--- a/keystore/tests/src/android/security/keystore/AndroidKeyStoreTest.java
+++ b/keystore/tests/src/android/security/keystore/AndroidKeyStoreTest.java
@@ -19,38 +19,31 @@
import com.android.org.bouncycastle.x509.X509V3CertificateGenerator;
import com.android.org.conscrypt.NativeConstants;
-import com.android.org.conscrypt.OpenSSLEngine;
import android.security.Credentials;
import android.security.KeyStore;
import android.security.KeyStoreParameter;
-import android.security.keymaster.ExportResult;
-import android.security.keymaster.KeymasterDefs;
import android.test.AndroidTestCase;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.OutputStream;
import java.math.BigInteger;
-import java.security.InvalidKeyException;
import java.security.Key;
import java.security.KeyFactory;
+import java.security.KeyPair;
import java.security.KeyStore.Entry;
import java.security.KeyStore.PrivateKeyEntry;
import java.security.KeyStore.TrustedCertificateEntry;
import java.security.KeyStoreException;
-import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
-import java.security.interfaces.ECPrivateKey;
-import java.security.interfaces.ECPublicKey;
-import java.security.interfaces.RSAPrivateKey;
-import java.security.spec.InvalidKeySpecException;
+import java.security.interfaces.ECKey;
+import java.security.interfaces.RSAKey;
import java.security.spec.PKCS8EncodedKeySpec;
-import java.security.spec.X509EncodedKeySpec;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
@@ -1203,14 +1196,14 @@
private void assertPrivateKeyEntryEquals(PrivateKeyEntry keyEntry, PrivateKey expectedKey,
Certificate expectedCert, Collection<Certificate> expectedChain) throws Exception {
- if (expectedKey instanceof ECPrivateKey) {
+ if (expectedKey instanceof ECKey) {
assertEquals("Returned PrivateKey should be what we inserted",
- ((ECPrivateKey) expectedKey).getParams().getCurve(),
- ((ECPublicKey) keyEntry.getCertificate().getPublicKey()).getParams().getCurve());
- } else if (expectedKey instanceof RSAPrivateKey) {
+ ((ECKey) expectedKey).getParams().getCurve(),
+ ((ECKey) keyEntry.getCertificate().getPublicKey()).getParams().getCurve());
+ } else if (expectedKey instanceof RSAKey) {
assertEquals("Returned PrivateKey should be what we inserted",
- ((RSAPrivateKey) expectedKey).getModulus(),
- ((RSAPrivateKey) keyEntry.getPrivateKey()).getModulus());
+ ((RSAKey) expectedKey).getModulus(),
+ ((RSAKey) keyEntry.getPrivateKey()).getModulus());
}
assertEquals("Returned Certificate should be what we inserted", expectedCert,
@@ -1263,15 +1256,14 @@
Key key = mKeyStore.getKey(TEST_ALIAS_1, null);
assertNotNull("Key should exist", key);
- assertTrue("Should be a RSAPrivateKey", key instanceof RSAPrivateKey);
-
- RSAPrivateKey actualKey = (RSAPrivateKey) key;
+ assertTrue("Should be a PrivateKey", key instanceof PrivateKey);
+ assertTrue("Should be a RSAKey", key instanceof RSAKey);
KeyFactory keyFact = KeyFactory.getInstance("RSA");
PrivateKey expectedKey = keyFact.generatePrivate(new PKCS8EncodedKeySpec(FAKE_RSA_KEY_1));
assertEquals("Inserted key should be same as retrieved key",
- ((RSAPrivateKey) expectedKey).getModulus(), actualKey.getModulus());
+ ((RSAKey) expectedKey).getModulus(), ((RSAKey) key).getModulus());
}
public void testKeyStore_GetKey_NoPassword_Unencrypted_Success() throws Exception {
@@ -1287,15 +1279,14 @@
Key key = mKeyStore.getKey(TEST_ALIAS_1, null);
assertNotNull("Key should exist", key);
- assertTrue("Should be a RSAPrivateKey", key instanceof RSAPrivateKey);
-
- RSAPrivateKey actualKey = (RSAPrivateKey) key;
+ assertTrue("Should be a PrivateKey", key instanceof PrivateKey);
+ assertTrue("Should be a RSAKey", key instanceof RSAKey);
KeyFactory keyFact = KeyFactory.getInstance("RSA");
PrivateKey expectedKey = keyFact.generatePrivate(new PKCS8EncodedKeySpec(FAKE_RSA_KEY_1));
assertEquals("Inserted key should be same as retrieved key",
- ((RSAPrivateKey) expectedKey).getModulus(), actualKey.getModulus());
+ ((RSAKey) expectedKey).getModulus(), ((RSAKey) key).getModulus());
}
public void testKeyStore_GetKey_Certificate_Encrypted_Failure() throws Exception {
@@ -1926,31 +1917,11 @@
Date notAfter) throws Exception {
final String privateKeyAlias = Credentials.USER_PRIVATE_KEY + alias;
- final PrivateKey privKey;
- final OpenSSLEngine engine = OpenSSLEngine.getInstance("keystore");
- try {
- privKey = engine.getPrivateKeyById(privateKeyAlias);
- } catch (InvalidKeyException e) {
- throw new RuntimeException("Can't get key", e);
- }
-
- ExportResult exportResult =
- keyStore.exportKey(privateKeyAlias, KeymasterDefs.KM_KEY_FORMAT_X509, null, null);
- assertEquals(KeyStore.NO_ERROR, exportResult.resultCode);
- final byte[] pubKeyBytes = exportResult.exportData;
-
- final PublicKey pubKey;
- try {
- final KeyFactory keyFact = KeyFactory.getInstance("RSA");
- pubKey = keyFact.generatePublic(new X509EncodedKeySpec(pubKeyBytes));
- } catch (NoSuchAlgorithmException e) {
- throw new IllegalStateException("Can't instantiate RSA key generator", e);
- } catch (InvalidKeySpecException e) {
- throw new IllegalStateException("keystore returned invalid key encoding", e);
- }
+ KeyPair keyPair = AndroidKeyStoreProvider.loadAndroidKeyStoreKeyPairFromKeystore(
+ keyStore, privateKeyAlias);
final X509V3CertificateGenerator certGen = new X509V3CertificateGenerator();
- certGen.setPublicKey(pubKey);
+ certGen.setPublicKey(keyPair.getPublic());
certGen.setSerialNumber(serialNumber);
certGen.setSubjectDN(subjectDN);
certGen.setIssuerDN(subjectDN);
@@ -1958,7 +1929,7 @@
certGen.setNotAfter(notAfter);
certGen.setSignatureAlgorithm("sha1WithRSA");
- final X509Certificate cert = certGen.generate(privKey);
+ final X509Certificate cert = certGen.generate(keyPair.getPrivate());
return cert;
}
diff --git a/media/java/android/media/MediaCodecInfo.java b/media/java/android/media/MediaCodecInfo.java
index 89d419a..6c26220 100644
--- a/media/java/android/media/MediaCodecInfo.java
+++ b/media/java/android/media/MediaCodecInfo.java
@@ -1382,7 +1382,7 @@
// upper limit.
// for now we are keeping the profile specific "width/height
// in macroblocks" limits.
- if (Integer.valueOf(1).equals(map.get("feature-can-swap-width-height"))) {
+ if (map.containsKey("feature-can-swap-width-height")) {
if (widths != null) {
mSmallerDimensionUpperLimit =
Math.min(widths.getUpper(), heights.getUpper());
diff --git a/media/java/android/media/SoundPool.java b/media/java/android/media/SoundPool.java
index 64863c2..1355635 100644
--- a/media/java/android/media/SoundPool.java
+++ b/media/java/android/media/SoundPool.java
@@ -35,6 +35,7 @@
import android.util.AndroidRuntimeException;
import android.util.Log;
+import com.android.internal.app.IAppOpsCallback;
import com.android.internal.app.IAppOpsService;
@@ -125,10 +126,12 @@
private EventHandler mEventHandler;
private SoundPool.OnLoadCompleteListener mOnLoadCompleteListener;
+ private boolean mHasAppOpsPlayAudio;
private final Object mLock;
private final AudioAttributes mAttributes;
private final IAppOpsService mAppOps;
+ private final IAppOpsCallback mAppOpsCallback;
/**
* Constructor. Constructs a SoundPool object with the following
@@ -159,6 +162,24 @@
mAttributes = attributes;
IBinder b = ServiceManager.getService(Context.APP_OPS_SERVICE);
mAppOps = IAppOpsService.Stub.asInterface(b);
+ // initialize mHasAppOpsPlayAudio
+ updateAppOpsPlayAudio();
+ // register a callback to monitor whether the OP_PLAY_AUDIO is still allowed
+ mAppOpsCallback = new IAppOpsCallback.Stub() {
+ public void opChanged(int op, String packageName) {
+ synchronized (mLock) {
+ if (op == AppOpsManager.OP_PLAY_AUDIO) {
+ updateAppOpsPlayAudio();
+ }
+ }
+ }
+ };
+ try {
+ mAppOps.startWatchingMode(AppOpsManager.OP_PLAY_AUDIO,
+ ActivityThread.currentPackageName(), mAppOpsCallback);
+ } catch (RemoteException e) {
+ mHasAppOpsPlayAudio = false;
+ }
}
/**
@@ -168,7 +189,16 @@
* object. The SoundPool can no longer be used and the reference
* should be set to null.
*/
- public native final void release();
+ public final void release() {
+ try {
+ mAppOps.stopWatchingMode(mAppOpsCallback);
+ } catch (RemoteException e) {
+ // nothing to do here, the SoundPool is being released anyway
+ }
+ native_release();
+ }
+
+ private native final void native_release();
protected void finalize() { release(); }
@@ -466,13 +496,17 @@
if ((mAttributes.getAllFlags() & AudioAttributes.FLAG_BYPASS_INTERRUPTION_POLICY) != 0) {
return false;
}
+ return !mHasAppOpsPlayAudio;
+ }
+
+ private void updateAppOpsPlayAudio() {
try {
final int mode = mAppOps.checkAudioOperation(AppOpsManager.OP_PLAY_AUDIO,
mAttributes.getUsage(),
Process.myUid(), ActivityThread.currentPackageName());
- return mode != AppOpsManager.MODE_ALLOWED;
+ mHasAppOpsPlayAudio = (mode == AppOpsManager.MODE_ALLOWED);
} catch (RemoteException e) {
- return false;
+ mHasAppOpsPlayAudio = false;
}
}
diff --git a/media/java/android/media/browse/MediaBrowser.java b/media/java/android/media/browse/MediaBrowser.java
index ef8d169..ba867e1 100644
--- a/media/java/android/media/browse/MediaBrowser.java
+++ b/media/java/android/media/browse/MediaBrowser.java
@@ -375,7 +375,7 @@
* @param mediaId The id of the item to retrieve.
* @param cb The callback to receive the result on.
*/
- public void getMediaItem(@NonNull String mediaId, @NonNull final MediaItemCallback cb) {
+ public void getItem(final @NonNull String mediaId, @NonNull final ItemCallback cb) {
if (TextUtils.isEmpty(mediaId)) {
throw new IllegalArgumentException("mediaId is empty.");
}
@@ -387,7 +387,7 @@
mHandler.post(new Runnable() {
@Override
public void run() {
- cb.onError();
+ cb.onError(mediaId);
}
});
return;
@@ -397,15 +397,15 @@
protected void onReceiveResult(int resultCode, Bundle resultData) {
if (resultCode != 0 || resultData == null
|| !resultData.containsKey(MediaBrowserService.KEY_MEDIA_ITEM)) {
- cb.onError();
+ cb.onError(mediaId);
return;
}
Parcelable item = resultData.getParcelable(MediaBrowserService.KEY_MEDIA_ITEM);
if (!(item instanceof MediaItem)) {
- cb.onError();
+ cb.onError(mediaId);
+ return;
}
- cb.onMediaItemLoaded((MediaItem) resultData.getParcelable(
- MediaBrowserService.KEY_MEDIA_ITEM));
+ cb.onItemLoaded((MediaItem)item);
}
};
try {
@@ -415,7 +415,7 @@
mHandler.post(new Runnable() {
@Override
public void run() {
- cb.onError();
+ cb.onError(mediaId);
}
});
}
@@ -728,6 +728,9 @@
public static abstract class SubscriptionCallback {
/**
* Called when the list of children is loaded or updated.
+ *
+ * @param parentId The media id of the parent media item.
+ * @param children The children which were loaded.
*/
public void onChildrenLoaded(@NonNull String parentId,
@NonNull List<MediaItem> children) {
@@ -739,29 +742,32 @@
* If this is called, the subscription remains until {@link MediaBrowser#unsubscribe}
* called, because some errors may heal themselves.
* </p>
+ *
+ * @param parentId The media id of the parent media item whose children could
+ * not be loaded.
*/
- public void onError(@NonNull String id) {
+ public void onError(@NonNull String parentId) {
}
}
/**
- * Callback for receiving the result of {@link #getMediaItem}.
+ * Callback for receiving the result of {@link #getItem}.
*/
- public static abstract class MediaItemCallback {
-
+ public static abstract class ItemCallback {
/**
* Called when the item has been returned by the browser service.
*
* @param item The item that was returned or null if it doesn't exist.
*/
- public void onMediaItemLoaded(MediaItem item) {
+ public void onItemLoaded(MediaItem item) {
}
/**
- * Called when the id doesn't exist or there was an error retrieving the
- * item.
+ * Called when the item doesn't exist or there was an error retrieving it.
+ *
+ * @param itemId The media id of the media item which could not be loaded.
*/
- public void onError() {
+ public void onError(@NonNull String itemId) {
}
}
diff --git a/media/java/android/media/tv/TvInputInfo.java b/media/java/android/media/tv/TvInputInfo.java
index c537dd6..5d1aa14 100644
--- a/media/java/android/media/tv/TvInputInfo.java
+++ b/media/java/android/media/tv/TvInputInfo.java
@@ -29,6 +29,7 @@
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
import android.graphics.drawable.Drawable;
+import android.graphics.drawable.Icon;
import android.hardware.hdmi.HdmiDeviceInfo;
import android.net.Uri;
import android.os.Parcel;
@@ -125,7 +126,9 @@
private String mSettingsActivity;
private HdmiDeviceInfo mHdmiDeviceInfo;
+ private int mLabelRes;
private String mLabel;
+ private Icon mIcon;
private Uri mIconUri;
private boolean mIsConnectedToHdmiSwitch;
@@ -155,7 +158,7 @@
throws XmlPullParserException, IOException {
return createTvInputInfo(context, service, generateInputIdForComponentName(
new ComponentName(service.serviceInfo.packageName, service.serviceInfo.name)),
- null, TYPE_TUNER, false, null, null, false);
+ null, TYPE_TUNER, false, 0, null, null, null, false);
}
/**
@@ -165,11 +168,11 @@
* @param service The ResolveInfo returned from the package manager about this TV input service.
* @param hdmiDeviceInfo The HdmiDeviceInfo for a HDMI CEC logical device.
* @param parentId The ID of this TV input's parent input. {@code null} if none exists.
+ * @param label The label of this TvInputInfo. If it is {@code null} or empty, {@code service}
+ * label will be loaded.
* @param iconUri The {@link android.net.Uri} to load the icon image. See
* {@link android.content.ContentResolver#openInputStream}. If it is {@code null},
* the application icon of {@code service} will be loaded.
- * @param label The label of this TvInputInfo. If it is {@code null} or empty, {@code service}
- * label will be loaded.
* @hide
*/
@SystemApi
@@ -179,7 +182,34 @@
boolean isConnectedToHdmiSwitch = (hdmiDeviceInfo.getPhysicalAddress() & 0x0FFF) != 0;
TvInputInfo input = createTvInputInfo(context, service, generateInputIdForHdmiDevice(
new ComponentName(service.serviceInfo.packageName, service.serviceInfo.name),
- hdmiDeviceInfo), parentId, TYPE_HDMI, true, label, iconUri, isConnectedToHdmiSwitch);
+ hdmiDeviceInfo), parentId, TYPE_HDMI, true, 0, label, null, iconUri,
+ isConnectedToHdmiSwitch);
+ input.mHdmiDeviceInfo = hdmiDeviceInfo;
+ return input;
+ }
+
+ /**
+ * Create a new instance of the TvInputInfo class, instantiating it from the given Context,
+ * ResolveInfo, and HdmiDeviceInfo.
+ *
+ * @param service The ResolveInfo returned from the package manager about this TV input service.
+ * @param hdmiDeviceInfo The HdmiDeviceInfo for a HDMI CEC logical device.
+ * @param parentId The ID of this TV input's parent input. {@code null} if none exists.
+ * @param labelRes The label resource ID of this TvInputInfo. If it is {@code 0},
+ * {@code service} label will be loaded.
+ * @param icon The {@link android.graphics.drawable.Icon} to load the icon image. If it is
+ * {@code null}, the application icon of {@code service} will be loaded.
+ * @hide
+ */
+ @SystemApi
+ public static TvInputInfo createTvInputInfo(Context context, ResolveInfo service,
+ HdmiDeviceInfo hdmiDeviceInfo, String parentId, int labelRes, Icon icon)
+ throws XmlPullParserException, IOException {
+ boolean isConnectedToHdmiSwitch = (hdmiDeviceInfo.getPhysicalAddress() & 0x0FFF) != 0;
+ TvInputInfo input = createTvInputInfo(context, service, generateInputIdForHdmiDevice(
+ new ComponentName(service.serviceInfo.packageName, service.serviceInfo.name),
+ hdmiDeviceInfo), parentId, TYPE_HDMI, true, labelRes, null, icon, null,
+ isConnectedToHdmiSwitch);
input.mHdmiDeviceInfo = hdmiDeviceInfo;
return input;
}
@@ -190,11 +220,11 @@
*
* @param service The ResolveInfo returned from the package manager about this TV input service.
* @param hardwareInfo The TvInputHardwareInfo for a TV input hardware device.
+ * @param label The label of this TvInputInfo. If it is {@code null} or empty, {@code service}
+ * label will be loaded.
* @param iconUri The {@link android.net.Uri} to load the icon image. See
* {@link android.content.ContentResolver#openInputStream}. If it is {@code null},
* the application icon of {@code service} will be loaded.
- * @param label The label of this TvInputInfo. If it is {@code null} or empty, {@code service}
- * label will be loaded.
* @hide
*/
@SystemApi
@@ -204,12 +234,34 @@
int inputType = sHardwareTypeToTvInputType.get(hardwareInfo.getType(), TYPE_TUNER);
return createTvInputInfo(context, service, generateInputIdForHardware(
new ComponentName(service.serviceInfo.packageName, service.serviceInfo.name),
- hardwareInfo), null, inputType, true, label, iconUri, false);
+ hardwareInfo), null, inputType, true, 0, label, null, iconUri, false);
}
- private static TvInputInfo createTvInputInfo(Context context, ResolveInfo service,
- String id, String parentId, int inputType, boolean isHardwareInput, String label,
- Uri iconUri, boolean isConnectedToHdmiSwitch)
+ /**
+ * Create a new instance of the TvInputInfo class, instantiating it from the given Context,
+ * ResolveInfo, and TvInputHardwareInfo.
+ *
+ * @param service The ResolveInfo returned from the package manager about this TV input service.
+ * @param hardwareInfo The TvInputHardwareInfo for a TV input hardware device.
+ * @param labelRes The label resource ID of this TvInputInfo. If it is {@code 0},
+ * {@code service} label will be loaded.
+ * @param icon The {@link android.graphics.drawable.Icon} to load the icon image. If it is
+ * {@code null}, the application icon of {@code service} will be loaded.
+ * @hide
+ */
+ @SystemApi
+ public static TvInputInfo createTvInputInfo(Context context, ResolveInfo service,
+ TvInputHardwareInfo hardwareInfo, int labelRes, Icon icon)
+ throws XmlPullParserException, IOException {
+ int inputType = sHardwareTypeToTvInputType.get(hardwareInfo.getType(), TYPE_TUNER);
+ return createTvInputInfo(context, service, generateInputIdForHardware(
+ new ComponentName(service.serviceInfo.packageName, service.serviceInfo.name),
+ hardwareInfo), null, inputType, true, labelRes, null, icon, null, false);
+ }
+
+ private static TvInputInfo createTvInputInfo(Context context, ResolveInfo service, String id,
+ String parentId, int inputType, boolean isHardwareInput, int labelRes, String label,
+ Icon icon, Uri iconUri, boolean isConnectedToHdmiSwitch)
throws XmlPullParserException, IOException {
ServiceInfo si = service.serviceInfo;
PackageManager pm = context.getPackageManager();
@@ -254,7 +306,9 @@
}
sa.recycle();
+ input.mLabelRes = labelRes;
input.mLabel = label;
+ input.mIcon = icon;
input.mIconUri = iconUri;
input.mIsConnectedToHdmiSwitch = isConnectedToHdmiSwitch;
return input;
@@ -426,11 +480,13 @@
* a label, its name is returned.
*/
public CharSequence loadLabel(@NonNull Context context) {
- if (TextUtils.isEmpty(mLabel)) {
- return mService.loadLabel(context.getPackageManager());
- } else {
+ if (mLabelRes != 0) {
+ return context.getPackageManager().getText(mService.serviceInfo.packageName, mLabelRes,
+ null);
+ } else if (!TextUtils.isEmpty(mLabel)) {
return mLabel;
}
+ return mService.loadLabel(context.getPackageManager());
}
/**
@@ -454,19 +510,20 @@
* application's icon is returned. If it's unavailable too, {@code null} is returned.
*/
public Drawable loadIcon(@NonNull Context context) {
- if (mIconUri == null) {
- return loadServiceIcon(context);
- }
- try (InputStream is = context.getContentResolver().openInputStream(mIconUri)) {
- Drawable drawable = Drawable.createFromStream(is, null);
- if (drawable == null) {
- return loadServiceIcon(context);
+ if (mIcon != null) {
+ return mIcon.loadDrawable(context);
+ } else if (mIconUri != null) {
+ try (InputStream is = context.getContentResolver().openInputStream(mIconUri)) {
+ Drawable drawable = Drawable.createFromStream(is, null);
+ if (drawable != null) {
+ return drawable;
+ }
+ } catch (IOException e) {
+ Log.w(TAG, "Loading the default icon due to a failure on loading " + mIconUri, e);
+ // Falls back.
}
- return drawable;
- } catch (IOException e) {
- Log.w(TAG, "Loading the default icon due to a failure on loading " + mIconUri, e);
- return loadServiceIcon(context);
}
+ return loadServiceIcon(context);
}
@Override
@@ -516,7 +573,9 @@
dest.writeInt(mType);
dest.writeByte(mIsHardwareInput ? (byte) 1 : 0);
dest.writeParcelable(mHdmiDeviceInfo, flags);
+ dest.writeParcelable(mIcon, flags);
dest.writeParcelable(mIconUri, flags);
+ dest.writeInt(mLabelRes);
dest.writeString(mLabel);
dest.writeByte(mIsConnectedToHdmiSwitch ? (byte) 1 : 0);
}
@@ -591,7 +650,9 @@
mType = in.readInt();
mIsHardwareInput = in.readByte() == 1 ? true : false;
mHdmiDeviceInfo = in.readParcelable(null);
+ mIcon = in.readParcelable(null);
mIconUri = in.readParcelable(null);
+ mLabelRes = in.readInt();
mLabel = in.readString();
mIsConnectedToHdmiSwitch = in.readByte() == 1 ? true : false;
}
diff --git a/media/java/android/service/media/MediaBrowserService.java b/media/java/android/service/media/MediaBrowserService.java
index 41156cb..1bb99ff 100644
--- a/media/java/android/service/media/MediaBrowserService.java
+++ b/media/java/android/service/media/MediaBrowserService.java
@@ -76,7 +76,7 @@
public static final String SERVICE_INTERFACE = "android.media.browse.MediaBrowserService";
/**
- * A key for passing the MediaItem to the ResultReceiver in getMediaItem.
+ * A key for passing the MediaItem to the ResultReceiver in getItem.
*
* @hide
*/
@@ -109,6 +109,7 @@
* be thrown.
*
* @see MediaBrowserService#onLoadChildren
+ * @see MediaBrowserService#onGetMediaItem
*/
public class Result<T> {
private Object mDebug;
@@ -279,20 +280,7 @@
mHandler.post(new Runnable() {
@Override
public void run() {
- final Result<MediaBrowser.MediaItem> result
- = new Result<MediaBrowser.MediaItem>(mediaId) {
- @Override
- void onResultSent(MediaBrowser.MediaItem item) {
- Bundle bundle = new Bundle();
- bundle.putParcelable(KEY_MEDIA_ITEM, item);
- receiver.send(0, bundle);
- }
- };
- try {
- MediaBrowserService.this.getMediaItem(mediaId, result);
- } catch (UnsupportedOperationException e) {
- receiver.send(-1, null);
- }
+ performLoadItem(mediaId, receiver);
}
});
}
@@ -357,8 +345,7 @@
@NonNull Result<List<MediaBrowser.MediaItem>> result);
/**
- * Called to get a specific media item. The mediaId should be the same id
- * that would be returned for this item when it is in a list of child items.
+ * Called to get information about a specific media item.
* <p>
* Implementations must call {@link Result#sendResult result.sendResult}. If
* loading the item will be an expensive operation {@link Result#detach
@@ -366,17 +353,15 @@
* then {@link Result#sendResult result.sendResult} called when the item has
* been loaded.
* <p>
- * The default implementation throws an exception.
+ * The default implementation sends a null result.
*
- * @param mediaId The id for the specific
+ * @param itemId The id for the specific
* {@link android.media.browse.MediaBrowser.MediaItem}.
* @param result The Result to send the item to, or null if the id is
* invalid.
- * @throws UnsupportedOperationException
*/
- public void getMediaItem(String mediaId, Result<MediaBrowser.MediaItem> result)
- throws UnsupportedOperationException {
- throw new UnsupportedOperationException("getMediaItem is not supported.");
+ public void onLoadItem(String itemId, Result<MediaBrowser.MediaItem> result) {
+ result.sendResult(null);
}
/**
@@ -515,6 +500,25 @@
}
}
+ private void performLoadItem(String itemId, final ResultReceiver receiver) {
+ final Result<MediaBrowser.MediaItem> result =
+ new Result<MediaBrowser.MediaItem>(itemId) {
+ @Override
+ void onResultSent(MediaBrowser.MediaItem item) {
+ Bundle bundle = new Bundle();
+ bundle.putParcelable(KEY_MEDIA_ITEM, item);
+ receiver.send(0, bundle);
+ }
+ };
+
+ MediaBrowserService.this.onLoadItem(itemId, result);
+
+ if (!result.isDone()) {
+ throw new IllegalStateException("onLoadItem must call detach() or sendResult()"
+ + " before returning for id=" + itemId);
+ }
+ }
+
/**
* Contains information that the browser service needs to send to the client
* when first connected.
diff --git a/media/jni/android_media_ImageReader.cpp b/media/jni/android_media_ImageReader.cpp
index 49614bdc..635fa11 100644
--- a/media/jni/android_media_ImageReader.cpp
+++ b/media/jni/android_media_ImageReader.cpp
@@ -72,6 +72,12 @@
jmethodID ctor;
} gSurfacePlaneClassInfo;
+// Get an ID that's unique within this process.
+static int32_t createProcessUniqueId() {
+ static volatile int32_t globalCounter = 0;
+ return android_atomic_inc(&globalCounter);
+}
+
// ----------------------------------------------------------------------------
class JNIImageReaderContext : public ConsumerBase::FrameAvailableListener
@@ -808,6 +814,9 @@
sp<ConsumerBase> consumer;
sp<CpuConsumer> cpuConsumer;
sp<BufferItemConsumer> opaqueConsumer;
+ String8 consumerName = String8::format("ImageReader-%dx%df%xm%d-%d-%d",
+ width, height, format, maxImages, getpid(),
+ createProcessUniqueId());
if (isFormatOpaque(nativeFormat)) {
// Use the SW_READ_NEVER usage to tell producer that this format is not for preview or video
// encoding. The only possibility will be ZSL output.
@@ -819,6 +828,7 @@
return;
}
ctx->setOpaqueConsumer(opaqueConsumer);
+ opaqueConsumer->setName(consumerName);
consumer = opaqueConsumer;
} else {
cpuConsumer = new CpuConsumer(gbConsumer, maxImages, /*controlledByApp*/true);
@@ -828,6 +838,7 @@
return;
}
ctx->setCpuConsumer(cpuConsumer);
+ cpuConsumer->setName(consumerName);
consumer = cpuConsumer;
}
diff --git a/media/jni/android_media_ImageWriter.cpp b/media/jni/android_media_ImageWriter.cpp
index 294cd84..634ba64 100644
--- a/media/jni/android_media_ImageWriter.cpp
+++ b/media/jni/android_media_ImageWriter.cpp
@@ -293,7 +293,8 @@
res = native_window_set_usage(anw.get(), GRALLOC_USAGE_SW_WRITE_OFTEN);
if (res != OK) {
ALOGE("%s: Configure usage %08x for format %08x failed: %s (%d)",
- __FUNCTION__, GRALLOC_USAGE_SW_WRITE_OFTEN, format, strerror(-res), res);
+ __FUNCTION__, static_cast<unsigned int>(GRALLOC_USAGE_SW_WRITE_OFTEN),
+ format, strerror(-res), res);
jniThrowRuntimeException(env, "Failed to SW_WRITE_OFTEN configure usage");
return 0;
}
diff --git a/media/jni/soundpool/android_media_SoundPool.cpp b/media/jni/soundpool/android_media_SoundPool.cpp
index fc4cf05..ab3e340 100644
--- a/media/jni/soundpool/android_media_SoundPool.cpp
+++ b/media/jni/soundpool/android_media_SoundPool.cpp
@@ -286,7 +286,7 @@
"(Ljava/lang/Object;ILjava/lang/Object;)I",
(void*)android_media_SoundPool_native_setup
},
- { "release",
+ { "native_release",
"()V",
(void*)android_media_SoundPool_release
}
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/CodecTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/CodecTest.java
index bcfcbf3..8f7d6ac 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/CodecTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/CodecTest.java
@@ -60,6 +60,7 @@
private static boolean onPrepareSuccess = false;
public static boolean onCompleteSuccess = false;
public static boolean mPlaybackError = false;
+ public static boolean mFailedToCompleteWithNoError = true;
public static int mMediaInfoUnknownCount = 0;
public static int mMediaInfoVideoTrackLaggingCount = 0;
public static int mMediaInfoBadInterleavingCount = 0;
@@ -801,6 +802,7 @@
mMediaInfoNotSeekableCount = 0;
mMediaInfoMetdataUpdateCount = 0;
mPlaybackError = false;
+ mFailedToCompleteWithNoError = true;
String testResult;
initializeMessageLooper();
@@ -843,6 +845,9 @@
} catch (Exception e) {
Log.v(TAG, "playMediaSamples:" + e.getMessage());
}
+ // Check if playback state is unknown (neither completed nor erroneous) unless
+ // it's not interrupted in the middle. If true, that is an exceptional case to investigate.
+ mFailedToCompleteWithNoError = !(onCompleteSuccess || mPlaybackError);
return onCompleteSuccess;
}
}
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/MediaPlayerStressTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/MediaPlayerStressTest.java
index e289812..4221f1b 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/MediaPlayerStressTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/MediaPlayerStressTest.java
@@ -65,6 +65,7 @@
private int mTotalBadInterleaving = 0;
private int mTotalNotSeekable = 0;
private int mTotalMetaDataUpdate = 0;
+ private int mTotalFailedToCompleteWithNoError = 0;
//Test result output file
private static final String PLAYBACK_RESULT = "PlaybackTestResult.txt";
@@ -78,6 +79,8 @@
output.write(" Bad Interleaving: " + CodecTest.mMediaInfoBadInterleavingCount);
output.write(" Not Seekable: " + CodecTest.mMediaInfoNotSeekableCount);
output.write(" Info Meta data update: " + CodecTest.mMediaInfoMetdataUpdateCount);
+ output.write(" Failed To Complete With No Error: " +
+ CodecTest.mFailedToCompleteWithNoError);
output.write("\n");
}
@@ -90,16 +93,21 @@
output.write("Total Bad Interleaving: " + mTotalBadInterleaving + "\n");
output.write("Total Not Seekable: " + mTotalNotSeekable + "\n");
output.write("Total Info Meta data update: " + mTotalMetaDataUpdate + "\n");
+ output.write("Total Failed To Complete With No Error: " +
+ mTotalFailedToCompleteWithNoError);
output.write("\n");
}
private void updateTestResult(){
- if (CodecTest.onCompleteSuccess){
+ if (CodecTest.onCompleteSuccess) {
mTotalComplete++;
}
- else if (CodecTest.mPlaybackError){
+ else if (CodecTest.mPlaybackError) {
mTotalPlaybackError++;
}
+ else if (CodecTest.mFailedToCompleteWithNoError) {
+ mTotalFailedToCompleteWithNoError++;
+ }
mTotalInfoUnknown += CodecTest.mMediaInfoUnknownCount;
mTotalVideoTrackLagging += CodecTest.mMediaInfoVideoTrackLaggingCount;
mTotalBadInterleaving += CodecTest.mMediaInfoBadInterleavingCount;
@@ -149,4 +157,4 @@
assertTrue("testMediaSamples", testResult);
}
}
-}
\ No newline at end of file
+}
diff --git a/native/android/Android.mk b/native/android/Android.mk
index 12fdf71..1742bee 100644
--- a/native/android/Android.mk
+++ b/native/android/Android.mk
@@ -16,6 +16,7 @@
obb.cpp \
sensor.cpp \
storage_manager.cpp \
+ trace.cpp \
LOCAL_SHARED_LIBRARIES := \
liblog \
diff --git a/native/android/trace.cpp b/native/android/trace.cpp
new file mode 100644
index 0000000..db52220
--- /dev/null
+++ b/native/android/trace.cpp
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android/trace.h>
+#include <cutils/trace.h>
+
+bool ATrace_isEnabled() {
+ return atrace_is_tag_enabled(ATRACE_TAG_APP);
+}
+
+void ATrace_beginSection(const char* sectionName) {
+ atrace_begin(ATRACE_TAG_APP, sectionName);
+}
+
+void ATrace_endSection() {
+ atrace_end(ATRACE_TAG_APP);
+}
diff --git a/packages/DocumentsUI/res/layout-sw720dp/activity.xml b/packages/DocumentsUI/res/layout-sw720dp/activity.xml
index a9f1b3c..2a273f4 100644
--- a/packages/DocumentsUI/res/layout-sw720dp/activity.xml
+++ b/packages/DocumentsUI/res/layout-sw720dp/activity.xml
@@ -19,7 +19,7 @@
android:layout_height="match_parent"
android:orientation="vertical">
- <Toolbar
+ <com.android.documentsui.DocumentsToolBar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?android:attr/actionBarSize"
@@ -34,7 +34,7 @@
android:layout_marginStart="4dp"
android:overlapAnchor="true" />
- </Toolbar>
+ </com.android.documentsui.DocumentsToolBar>
<LinearLayout
android:layout_width="match_parent"
diff --git a/packages/DocumentsUI/res/layout/activity.xml b/packages/DocumentsUI/res/layout/activity.xml
index b549cd3..43fdaf2 100644
--- a/packages/DocumentsUI/res/layout/activity.xml
+++ b/packages/DocumentsUI/res/layout/activity.xml
@@ -24,7 +24,7 @@
android:layout_height="match_parent"
android:orientation="vertical">
- <Toolbar
+ <com.android.documentsui.DocumentsToolBar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?android:attr/actionBarSize"
@@ -39,7 +39,7 @@
android:layout_marginStart="4dp"
android:overlapAnchor="true" />
- </Toolbar>
+ </com.android.documentsui.DocumentsToolBar>
<com.android.documentsui.DirectoryContainerView
android:id="@+id/container_directory"
diff --git a/packages/DocumentsUI/res/values/strings.xml b/packages/DocumentsUI/res/values/strings.xml
index 9794273..a4e6ce7 100644
--- a/packages/DocumentsUI/res/values/strings.xml
+++ b/packages/DocumentsUI/res/values/strings.xml
@@ -45,7 +45,7 @@
<!-- Menu item title that deletes the selected documents [CHAR LIMIT=24] -->
<string name="menu_delete">Delete</string>
<!-- Menu item title that selects all documents in the current directory [CHAR LIMIT=24] -->
- <string name="menu_select_all">Select All</string>
+ <string name="menu_select_all">Select all</string>
<!-- Menu item title that copies the selected documents [CHAR LIMIT=24] -->
<string name="menu_copy">Copy to\u2026</string>
@@ -68,9 +68,6 @@
<!-- Button label that copies files to the current directory [CHAR LIMIT=24] -->
<string name="button_copy">Copy</string>
- <!-- Action mode title summarizing the number of documents selected [CHAR LIMIT=32] -->
- <string name="mode_selected_count"><xliff:g id="count" example="3">%1$d</xliff:g> selected</string>
-
<!-- Mode that sorts documents by their display name alphabetically [CHAR LIMIT=24] -->
<string name="sort_name">By name</string>
<!-- Mode that sorts documents by their last modified time in descending order; most recent first [CHAR LIMIT=24] -->
diff --git a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
index cb21131..bba33be 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
@@ -25,6 +25,7 @@
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
import java.util.concurrent.Executor;
@@ -32,6 +33,10 @@
import android.app.Activity;
import android.app.Fragment;
import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ProviderInfo;
import android.database.Cursor;
import android.net.Uri;
import android.os.AsyncTask;
@@ -96,7 +101,7 @@
boolean showMenu = super.onCreateOptionsMenu(menu);
getMenuInflater().inflate(R.menu.activity, menu);
- mSearchManager.install(menu.findItem(R.id.menu_search));
+ mSearchManager.install((DocumentsToolBar) findViewById(R.id.toolbar));
return showMenu;
}
@@ -232,9 +237,38 @@
invalidateOptionsMenu();
}
+ final List<String> getExcludedAuthorities() {
+ List<String> authorities = new ArrayList<>();
+ if (getIntent().getBooleanExtra(DocumentsContract.EXTRA_EXCLUDE_SELF, false)) {
+ // Exclude roots provided by the calling package.
+ String packageName = getCallingPackageMaybeExtra();
+ try {
+ PackageInfo pkgInfo = getPackageManager().getPackageInfo(packageName,
+ PackageManager.GET_PROVIDERS);
+ for (ProviderInfo provider: pkgInfo.providers) {
+ authorities.add(provider.authority);
+ }
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.e(mTag, "Calling package name does not resolve: " + packageName);
+ }
+ }
+ return authorities;
+ }
+
final String getCallingPackageMaybeExtra() {
- final String extra = getIntent().getStringExtra(DocumentsContract.EXTRA_PACKAGE_NAME);
- return (extra != null) ? extra : getCallingPackage();
+ String callingPackage = getCallingPackage();
+ // System apps can set the calling package name using an extra.
+ try {
+ ApplicationInfo info = getPackageManager().getApplicationInfo(callingPackage, 0);
+ if (info.isSystemApp() || info.isUpdatedSystemApp()) {
+ final String extra = getIntent().getStringExtra(DocumentsContract.EXTRA_PACKAGE_NAME);
+ if (extra != null) {
+ callingPackage = extra;
+ }
+ }
+ } finally {
+ return callingPackage;
+ }
}
public static BaseActivity get(Fragment fragment) {
@@ -287,6 +321,9 @@
/** Currently copying file */
public List<DocumentInfo> selectedDocumentsForCopy = new ArrayList<DocumentInfo>();
+ /** Name of the package that started DocsUI */
+ public List<String> excludedAuthorities = new ArrayList<>();
+
public static final int ACTION_OPEN = 1;
public static final int ACTION_CREATE = 2;
public static final int ACTION_GET_CONTENT = 3;
@@ -327,6 +364,7 @@
out.writeString(currentSearch);
out.writeMap(dirState);
out.writeList(selectedDocumentsForCopy);
+ out.writeList(excludedAuthorities);
}
public static final Creator<State> CREATOR = new Creator<State>() {
@@ -348,6 +386,7 @@
state.currentSearch = in.readString();
in.readMap(state.dirState, null);
in.readList(state.selectedDocumentsForCopy, null);
+ in.readList(state.excludedAuthorities, null);
return state;
}
@@ -627,20 +666,24 @@
* Facade over the various search parts in the menu.
*/
final class SearchManager implements
- SearchView.OnCloseListener, OnActionExpandListener, OnQueryTextListener {
+ SearchView.OnCloseListener, OnActionExpandListener, OnQueryTextListener,
+ DocumentsToolBar.OnActionViewCollapsedListener {
private boolean mSearchExpanded;
private boolean mIgnoreNextClose;
private boolean mIgnoreNextCollapse;
+ private DocumentsToolBar mActionBar;
private MenuItem mMenu;
private SearchView mView;
- public void install(MenuItem menu) {
- assert(mMenu == null);
- mMenu = menu;
- mView = (SearchView) menu.getActionView();
+ public void install(DocumentsToolBar actionBar) {
+ assert(mActionBar == null);
+ mActionBar = actionBar;
+ mMenu = actionBar.getSearchMenu();
+ mView = (SearchView) mMenu.getActionView();
+ mActionBar.setOnActionViewCollapsedListener(this);
mMenu.setOnActionExpandListener(this);
mView.setOnQueryTextListener(this);
mView.setOnCloseListener(this);
@@ -691,6 +734,19 @@
}
}
+ /**
+ * Cancels current search operation.
+ * @return True if it cancels search. False if it does not operate
+ * search currently.
+ */
+ boolean cancelSearch() {
+ if (mActionBar.hasExpandedActionView()) {
+ mActionBar.collapseActionView();
+ return true;
+ }
+ return false;
+ }
+
boolean isSearching() {
return getDisplayState().currentSearch != null;
}
@@ -726,7 +782,6 @@
mIgnoreNextCollapse = false;
return true;
}
-
getDisplayState().currentSearch = null;
onCurrentDirectoryChanged(ANIM_NONE);
return true;
@@ -745,5 +800,10 @@
public boolean onQueryTextChange(String newText) {
return false;
}
+
+ @Override
+ public void onActionViewCollapsed() {
+ updateActionBar();
+ }
}
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
index a789da8..f4be9c5 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
@@ -54,6 +54,7 @@
import android.os.Parcelable;
import android.provider.DocumentsContract;
import android.provider.DocumentsContract.Document;
+import android.text.TextUtils;
import android.text.format.DateUtils;
import android.text.format.Formatter;
import android.text.format.Time;
@@ -474,8 +475,7 @@
@Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
mode.getMenuInflater().inflate(R.menu.mode_directory, menu);
- mode.setTitle(getResources()
- .getString(R.string.mode_selected_count, mCurrentView.getCheckedItemCount()));
+ mode.setTitle(TextUtils.formatSelectedCount(mCurrentView.getCheckedItemCount()));
return true;
}
@@ -571,8 +571,7 @@
}
}
- mode.setTitle(getResources()
- .getString(R.string.mode_selected_count, mCurrentView.getCheckedItemCount()));
+ mode.setTitle(TextUtils.formatSelectedCount(mCurrentView.getCheckedItemCount()));
}
};
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
index da59d0e..90ccf91 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
@@ -31,6 +31,7 @@
import java.util.Arrays;
import java.util.List;
+import android.app.ActionBar;
import android.app.Activity;
import android.app.Fragment;
import android.app.FragmentManager;
@@ -256,6 +257,8 @@
BaseActivity.DocumentsIntent.EXTRA_DIRECTORY_COPY, false);
}
+ state.excludedAuthorities = getExcludedAuthorities();
+
return state;
}
@@ -506,6 +509,11 @@
@Override
public void onBackPressed() {
+ // While action bar is expanded, the state stack UI is hidden.
+ if (mSearchManager.cancelSearch()) {
+ return;
+ }
+
if (!mState.stackTouched) {
super.onBackPressed();
return;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DocumentsToolBar.java b/packages/DocumentsUI/src/com/android/documentsui/DocumentsToolBar.java
new file mode 100644
index 0000000..36b7646
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/DocumentsToolBar.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.documentsui;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.MenuItem;
+import android.widget.Toolbar;
+
+/**
+ * ToolBar of Documents UI.
+ */
+public class DocumentsToolBar extends Toolbar {
+ interface OnActionViewCollapsedListener {
+ void onActionViewCollapsed();
+ }
+
+ private OnActionViewCollapsedListener mOnActionViewCollapsedListener;
+
+ public DocumentsToolBar(Context context, AttributeSet attrs,
+ int defStyleAttr, int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ }
+
+ public DocumentsToolBar(Context context, AttributeSet attrs,
+ int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ }
+
+ public DocumentsToolBar(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public DocumentsToolBar(Context context) {
+ super(context);
+ }
+
+ @Override
+ public void collapseActionView() {
+ super.collapseActionView();
+ if (mOnActionViewCollapsedListener != null) {
+ mOnActionViewCollapsedListener.onActionViewCollapsed();
+ }
+ }
+
+ /**
+ * Adds a listener that is invoked after collapsing the action view.
+ * @param listener
+ */
+ public void setOnActionViewCollapsedListener(
+ OnActionViewCollapsedListener listener) {
+ mOnActionViewCollapsedListener = listener;
+ }
+
+ public MenuItem getSearchMenu() {
+ return getMenu().findItem(R.id.menu_search);
+ }
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java b/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
index 27e8f20..fbcb938 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
@@ -383,6 +383,12 @@
continue;
}
+ // Exclude roots from the calling package.
+ if (state.excludedAuthorities.contains(root.authority)) {
+ if (LOGD) Log.d(TAG, "Excluding root " + root.authority + " from calling package.");
+ continue;
+ }
+
matching.add(root);
}
return matching;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java b/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java
index 97d8ed0..ecf4d6c 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java
@@ -55,7 +55,6 @@
public String mimeTypes;
/** Derived fields that aren't persisted */
- public String derivedPackageName;
public String[] derivedMimeTypes;
public int derivedIcon;
@@ -75,7 +74,6 @@
availableBytes = -1;
mimeTypes = null;
- derivedPackageName = null;
derivedMimeTypes = null;
derivedIcon = 0;
}
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/RootsCacheTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/RootsCacheTest.java
index 7faa3ce..8c5bac1 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/RootsCacheTest.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/RootsCacheTest.java
@@ -114,6 +114,31 @@
RootsCache.getMatchingRoots(mRoots, mState));
}
+ public void testExcludedAuthorities() throws Exception {
+ final List<RootInfo> roots = Lists.newArrayList();
+
+ // Set up some roots
+ for (int i = 0; i < 5; ++i) {
+ RootInfo root = new RootInfo();
+ root.authority = "authority" + i;
+ roots.add(root);
+ }
+ // Make some allowed authorities
+ List<RootInfo> allowedRoots = Lists.newArrayList(
+ roots.get(0), roots.get(2), roots.get(4));
+ // Set up the excluded authority list
+ for (RootInfo root: roots) {
+ if (!allowedRoots.contains(root)) {
+ mState.excludedAuthorities.add(root.authority);
+ }
+ }
+ mState.acceptMimes = new String[] { "*/*" };
+
+ assertContainsExactly(
+ allowedRoots,
+ RootsCache.getMatchingRoots(roots, mState));
+ }
+
private static void assertContainsExactly(List<?> expected, List<?> actual) {
assertEquals(expected.size(), actual.size());
for (Object o : expected) {
diff --git a/packages/Keyguard/res/layout/keyguard_pattern_view.xml b/packages/Keyguard/res/layout/keyguard_pattern_view.xml
index 0f5431e..09c01de 100644
--- a/packages/Keyguard/res/layout/keyguard_pattern_view.xml
+++ b/packages/Keyguard/res/layout/keyguard_pattern_view.xml
@@ -31,8 +31,7 @@
android:clipToPadding="false"
androidprv:layout_maxWidth="@dimen/keyguard_security_width"
androidprv:layout_maxHeight="@dimen/keyguard_security_height"
- android:gravity="center_horizontal"
- android:contentDescription="@string/keyguard_accessibility_pattern_unlock">
+ android:gravity="center_horizontal">
<FrameLayout
android:layout_width="match_parent"
diff --git a/packages/Keyguard/res/values/strings.xml b/packages/Keyguard/res/values/strings.xml
index 49ce427..748129c 100644
--- a/packages/Keyguard/res/values/strings.xml
+++ b/packages/Keyguard/res/values/strings.xml
@@ -299,6 +299,42 @@
<!-- Description of airplane mode -->
<string name="airplane_mode">Airplane mode</string>
+ <!-- An explanation text that the pattern needs to be solved since the device has just been restarted. [CHAR LIMIT=80] -->
+ <string name="kg_prompt_reason_restart_pattern">Pattern required when you restart device.</string>
+
+ <!-- An explanation text that the pin needs to be entered since the device has just been restarted. [CHAR LIMIT=80] -->
+ <string name="kg_prompt_reason_restart_pin">PIN required when you restart device.</string>
+
+ <!-- An explanation text that the password needs to be entered since the device has just been restarted. [CHAR LIMIT=80] -->
+ <string name="kg_prompt_reason_restart_password">Password required when you restart device.</string>
+
+ <!-- An explanation text that the pattern needs to be solved since profiles have just been switched. [CHAR LIMIT=80] -->
+ <string name="kg_prompt_reason_switch_profiles_pattern">Pattern required when you switch profiles.</string>
+
+ <!-- An explanation text that the pin needs to be entered since profiles have just been switched. [CHAR LIMIT=80] -->
+ <string name="kg_prompt_reason_switch_profiles_pin">PIN required when you switch profiles.</string>
+
+ <!-- An explanation text that the password needs to be entered since profiles have just been switched. [CHAR LIMIT=80] -->
+ <string name="kg_prompt_reason_switch_profiles_password">Password required when you switch profiles.</string>
+
+ <!-- An explanation text that the pattern needs to be solved since it hasn't been solved in a while. [CHAR LIMIT=80]-->
+ <plurals name="kg_prompt_reason_time_pattern">
+ <item quantity="one">Device hasn\'t been unlocked for <xliff:g id="number">%d</xliff:g> hour. Confirm pattern.</item>
+ <item quantity="other">Device hasn\'t been unlocked for <xliff:g id="number">%d</xliff:g> hours. Confirm pattern.</item>
+ </plurals>
+
+ <!-- An explanation text that the pin needs to be entered since it hasn't been entered in a while. [CHAR LIMIT=80]-->
+ <plurals name="kg_prompt_reason_time_pin">
+ <item quantity="one">Device hasn\'t been unlocked for <xliff:g id="number">%d</xliff:g> hour. Confirm PIN.</item>
+ <item quantity="other">Device hasn\'t been unlocked for <xliff:g id="number">%d</xliff:g> hours. Confirm PIN.</item>
+ </plurals>
+
+ <!-- An explanation text that the password needs to be entered since it hasn't been entered in a while. [CHAR LIMIT=80]-->
+ <plurals name="kg_prompt_reason_time_password">
+ <item quantity="one">Device hasn\'t been unlocked for <xliff:g id="number">%d</xliff:g> hour. Confirm password.</item>
+ <item quantity="other">Device hasn\'t been unlocked for <xliff:g id="number">%d</xliff:g> hours. Confirm password.</item>
+ </plurals>
+
<!-- Fingerprint hint message when finger was not recognized.-->
<string name="fingerprint_not_recognized">Not recognized</string>
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardPINView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardPINView.java
index d0be855..ac9dc85 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardPINView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardPINView.java
@@ -22,6 +22,9 @@
import android.view.ViewGroup;
import android.view.animation.AnimationUtils;
+import com.android.settingslib.animation.AppearAnimationUtils;
+import com.android.settingslib.animation.DisappearAnimationUtils;
+
/**
* Displays a PIN pad for unlocking.
*/
@@ -115,7 +118,7 @@
.setDuration(500)
.setInterpolator(mAppearAnimationUtils.getInterpolator())
.translationY(0);
- mAppearAnimationUtils.startAnimation(mViews,
+ mAppearAnimationUtils.startAnimation2d(mViews,
new Runnable() {
@Override
public void run() {
@@ -132,7 +135,7 @@
.setDuration(280)
.setInterpolator(mDisappearAnimationUtils.getInterpolator())
.translationY(mDisappearYTranslation);
- mDisappearAnimationUtils.startAnimation(mViews,
+ mDisappearAnimationUtils.startAnimation2d(mViews,
new Runnable() {
@Override
public void run() {
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java
index a9b2978..1bd0bb4 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java
@@ -36,6 +36,9 @@
import com.android.internal.widget.LockPatternChecker;
import com.android.internal.widget.LockPatternUtils;
import com.android.internal.widget.LockPatternView;
+import com.android.settingslib.animation.AppearAnimationCreator;
+import com.android.settingslib.animation.AppearAnimationUtils;
+import com.android.settingslib.animation.DisappearAnimationUtils;
import java.util.List;
@@ -325,7 +328,7 @@
.setDuration(500)
.setInterpolator(mAppearAnimationUtils.getInterpolator())
.translationY(0);
- mAppearAnimationUtils.startAnimation(
+ mAppearAnimationUtils.startAnimation2d(
mLockPatternView.getCellStates(),
new Runnable() {
@Override
@@ -353,7 +356,7 @@
.setDuration(300)
.setInterpolator(mDisappearAnimationUtils.getInterpolator())
.translationY(-mDisappearAnimationUtils.getStartTranslation());
- mDisappearAnimationUtils.startAnimation(mLockPatternView.getCellStates(),
+ mDisappearAnimationUtils.startAnimation2d(mLockPatternView.getCellStates(),
new Runnable() {
@Override
public void run() {
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardPinBasedInputView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardPinBasedInputView.java
index ed0d4afe..23834a3 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardPinBasedInputView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardPinBasedInputView.java
@@ -150,13 +150,6 @@
// Set selected property on so the view can send accessibility events.
mPasswordEntry.setSelected(true);
- // Poke the wakelock any time the text is selected or modified
- mPasswordEntry.setOnClickListener(new OnClickListener() {
- public void onClick(View v) {
- onUserInput();
- }
- });
-
mPasswordEntry.setUserActivityListener(new PasswordTextView.UserActivityListener() {
@Override
public void onUserActivity() {
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
index e6a89f1..273f166 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -117,6 +117,7 @@
private static final int MSG_FINGERPRINT_AUTH_FAILED = 326;
private static final int MSG_FACE_UNLOCK_STATE_CHANGED = 327;
private static final int MSG_SIM_SUBSCRIPTION_INFO_CHANGED = 328;
+ private static final int MSG_AIRPLANE_MODE_CHANGED = 329;
private static KeyguardUpdateMonitor sInstance;
@@ -222,6 +223,9 @@
case MSG_SIM_SUBSCRIPTION_INFO_CHANGED:
handleSimSubscriptionInfoChanged();
break;
+ case MSG_AIRPLANE_MODE_CHANGED:
+ handleAirplaneModeChanged();
+ break;
}
}
};
@@ -305,6 +309,15 @@
}
}
+ private void handleAirplaneModeChanged() {
+ for (int j = 0; j < mCallbacks.size(); j++) {
+ KeyguardUpdateMonitorCallback cb = mCallbacks.get(j).get();
+ if (cb != null) {
+ cb.onRefreshCarrierInfo();
+ }
+ }
+ }
+
/** @return List of SubscriptionInfo records, maybe empty but never null */
List<SubscriptionInfo> getSubscriptionInfo(boolean forceReload) {
List<SubscriptionInfo> sil = mSubscriptionInfo;
@@ -486,6 +499,8 @@
} else if (TelephonyManager.ACTION_PHONE_STATE_CHANGED.equals(action)) {
String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE);
mHandler.sendMessage(mHandler.obtainMessage(MSG_PHONE_STATE_CHANGED, state));
+ } else if (Intent.ACTION_AIRPLANE_MODE_CHANGED.equals(action)) {
+ mHandler.sendEmptyMessage(MSG_AIRPLANE_MODE_CHANGED);
} else if (Intent.ACTION_BOOT_COMPLETED.equals(action)) {
dispatchBootCompleted();
}
@@ -721,6 +736,7 @@
filter.addAction(Intent.ACTION_TIME_CHANGED);
filter.addAction(Intent.ACTION_BATTERY_CHANGED);
filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
+ filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION);
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
index 4ba04e5..3c5dae3 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
@@ -679,6 +679,8 @@
if (resolvedActivities.get(0).activityInfo.exported) {
intent.putExtra(PrintService.EXTRA_PRINT_JOB_INFO, mPrintJob);
intent.putExtra(PrintService.EXTRA_PRINTER_INFO, printer);
+ intent.putExtra(PrintService.EXTRA_PRINT_JOB_INFO,
+ mPrintedDocument.getDocumentInfo().info);
// This is external activity and may not be there.
try {
diff --git a/packages/SettingsLib/res/values/dimens.xml b/packages/SettingsLib/res/values/dimens.xml
new file mode 100644
index 0000000..1c4b05f
--- /dev/null
+++ b/packages/SettingsLib/res/values/dimens.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2015 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+<resources>
+
+ <!-- The y translation to apply at the start in appear animations. -->
+ <dimen name="appear_y_translation_start">32dp</dimen>
+
+ <!-- The translation for disappearing security views after having solved them. -->
+ <dimen name="disappear_y_translation">-32dp</dimen>
+</resources>
\ No newline at end of file
diff --git a/packages/Keyguard/src/com/android/keyguard/AppearAnimationCreator.java b/packages/SettingsLib/src/com/android/settingslib/animation/AppearAnimationCreator.java
similarity index 86%
rename from packages/Keyguard/src/com/android/keyguard/AppearAnimationCreator.java
rename to packages/SettingsLib/src/com/android/settingslib/animation/AppearAnimationCreator.java
index e4706b6..8a61e4e 100644
--- a/packages/Keyguard/src/com/android/keyguard/AppearAnimationCreator.java
+++ b/packages/SettingsLib/src/com/android/settingslib/animation/AppearAnimationCreator.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,13 +14,13 @@
* limitations under the License
*/
-package com.android.keyguard;
+package com.android.settingslib.animation;
import android.view.animation.Interpolator;
/**
* An interface which can create animations when starting an appear animation with
- * {@link com.android.keyguard.AppearAnimationUtils}
+ * {@link AppearAnimationUtils}
*/
public interface AppearAnimationCreator<T> {
void createAnimation(T animatedObject, long delay, long duration,
diff --git a/packages/Keyguard/src/com/android/keyguard/AppearAnimationUtils.java b/packages/SettingsLib/src/com/android/settingslib/animation/AppearAnimationUtils.java
similarity index 85%
rename from packages/Keyguard/src/com/android/keyguard/AppearAnimationUtils.java
rename to packages/SettingsLib/src/com/android/settingslib/animation/AppearAnimationUtils.java
index 9045fe3..441474d 100644
--- a/packages/Keyguard/src/com/android/keyguard/AppearAnimationUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/animation/AppearAnimationUtils.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,13 +14,15 @@
* limitations under the License
*/
-package com.android.keyguard;
+package com.android.settingslib.animation;
import android.content.Context;
import android.view.View;
import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
+import com.android.settingslib.R;
+
/**
* A class to make nice appear transitions for views in a tabular layout.
*/
@@ -33,7 +35,7 @@
private final AppearAnimationProperties mProperties = new AppearAnimationProperties();
protected final float mDelayScale;
private final long mDuration;
- protected boolean mScaleTranslationWithRow;
+ protected RowTranslationScaler mRowTranslationScaler;
protected boolean mAppearing;
public AppearAnimationUtils(Context ctx) {
@@ -49,19 +51,18 @@
R.dimen.appear_y_translation_start) * translationScaleFactor;
mDelayScale = delayScaleFactor;
mDuration = duration;
- mScaleTranslationWithRow = false;
mAppearing = true;
}
- public void startAnimation(View[][] objects, final Runnable finishListener) {
- startAnimation(objects, finishListener, this);
+ public void startAnimation2d(View[][] objects, final Runnable finishListener) {
+ startAnimation2d(objects, finishListener, this);
}
public void startAnimation(View[] objects, final Runnable finishListener) {
startAnimation(objects, finishListener, this);
}
- public <T> void startAnimation(T[][] objects, final Runnable finishListener,
+ public <T> void startAnimation2d(T[][] objects, final Runnable finishListener,
AppearAnimationCreator<T> creator) {
AppearAnimationProperties properties = getDelays(objects);
startAnimations(properties, objects, finishListener, creator);
@@ -86,8 +87,13 @@
if (properties.maxDelayRowIndex == row && properties.maxDelayColIndex == 0) {
endRunnable = finishListener;
}
+ float translationScale = mRowTranslationScaler != null
+ ? mRowTranslationScaler.getRowTranslationScale(row, properties.delays.length)
+ : 1f;
+ float translation = translationScale * mStartTranslation;
creator.createAnimation(objects[row], delay, mDuration,
- mStartTranslation, true /* appearing */, mInterpolator, endRunnable);
+ mAppearing ? translation : -translation,
+ mAppearing, mInterpolator, endRunnable);
}
}
@@ -99,10 +105,10 @@
}
for (int row = 0; row < properties.delays.length; row++) {
long[] columns = properties.delays[row];
- float translation = mScaleTranslationWithRow
- ? (float) (Math.pow((properties.delays.length - row), 2)
- / properties.delays.length * mStartTranslation)
- : mStartTranslation;
+ float translationScale = mRowTranslationScaler != null
+ ? mRowTranslationScaler.getRowTranslationScale(row, properties.delays.length)
+ : 1f;
+ float translation = translationScale * mStartTranslation;
for (int col = 0; col < columns.length; col++) {
long delay = columns[col];
Runnable endRunnable = null;
@@ -193,4 +199,8 @@
public int maxDelayRowIndex;
public int maxDelayColIndex;
}
+
+ public interface RowTranslationScaler {
+ float getRowTranslationScale(int row, int numRows);
+ }
}
diff --git a/packages/Keyguard/src/com/android/keyguard/DisappearAnimationUtils.java b/packages/SettingsLib/src/com/android/settingslib/animation/DisappearAnimationUtils.java
similarity index 65%
rename from packages/Keyguard/src/com/android/keyguard/DisappearAnimationUtils.java
rename to packages/SettingsLib/src/com/android/settingslib/animation/DisappearAnimationUtils.java
index 517d96a..a444ff0 100644
--- a/packages/Keyguard/src/com/android/keyguard/DisappearAnimationUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/animation/DisappearAnimationUtils.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License
*/
-package com.android.keyguard;
+package com.android.settingslib.animation;
import android.content.Context;
import android.view.animation.AnimationUtils;
@@ -28,17 +28,31 @@
public DisappearAnimationUtils(Context ctx) {
this(ctx, DEFAULT_APPEAR_DURATION,
1.0f, 1.0f,
- AnimationUtils.loadInterpolator(ctx, android.R.interpolator.linear_out_slow_in));
+ AnimationUtils.loadInterpolator(ctx, android.R.interpolator.fast_out_linear_in));
}
public DisappearAnimationUtils(Context ctx, long duration, float translationScaleFactor,
float delayScaleFactor, Interpolator interpolator) {
+ this(ctx, duration, translationScaleFactor, delayScaleFactor, interpolator,
+ ROW_TRANSLATION_SCALER);
+ }
+
+ public DisappearAnimationUtils(Context ctx, long duration, float translationScaleFactor,
+ float delayScaleFactor, Interpolator interpolator, RowTranslationScaler rowScaler) {
super(ctx, duration, translationScaleFactor, delayScaleFactor, interpolator);
- mScaleTranslationWithRow = true;
+ mRowTranslationScaler = rowScaler;
mAppearing = false;
}
protected long calculateDelay(int row, int col) {
return (long) ((row * 60 + col * (Math.pow(row, 0.4) + 0.4) * 10) * mDelayScale);
}
+
+ private static final RowTranslationScaler ROW_TRANSLATION_SCALER = new RowTranslationScaler() {
+
+ @Override
+ public float getRowTranslationScale(int row, int numRows) {
+ return (float) (Math.pow((numRows - row), 2) / numRows);
+ }
+ };
}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 1dba942e..5137e1b 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -516,7 +516,7 @@
}
private void dumpSettings(Cursor cursor, PrintWriter pw) {
- if (!cursor.moveToFirst()) {
+ if (cursor == null || !cursor.moveToFirst()) {
return;
}
diff --git a/packages/StatementService/src/com/android/statementservice/retriever/AbstractStatementRetriever.java b/packages/StatementService/src/com/android/statementservice/retriever/AbstractStatementRetriever.java
index 3b59fd6..fe9b99a 100644
--- a/packages/StatementService/src/com/android/statementservice/retriever/AbstractStatementRetriever.java
+++ b/packages/StatementService/src/com/android/statementservice/retriever/AbstractStatementRetriever.java
@@ -90,7 +90,7 @@
* Creates a new StatementRetriever that directly retrieves statements from the asset.
*
* <p> For web assets, {@link AbstractStatementRetriever} will try to retrieve the statement
- * file from URL: {@code [webAsset.site]/.well-known/statements.json"} where {@code
+ * file from URL: {@code [webAsset.site]/.well-known/assetlinks.json"} where {@code
* [webAsset.site]} is in the form {@code http{s}://[hostname]:[optional_port]}. The file
* should contain one JSON array of statements.
*
diff --git a/packages/StatementService/src/com/android/statementservice/retriever/DirectStatementRetriever.java b/packages/StatementService/src/com/android/statementservice/retriever/DirectStatementRetriever.java
index 2ca85e9..e4feb90 100644
--- a/packages/StatementService/src/com/android/statementservice/retriever/DirectStatementRetriever.java
+++ b/packages/StatementService/src/com/android/statementservice/retriever/DirectStatementRetriever.java
@@ -38,7 +38,7 @@
private static final int HTTP_CONNECTION_TIMEOUT_MILLIS = 5000;
private static final long HTTP_CONTENT_SIZE_LIMIT_IN_BYTES = 1024 * 1024;
private static final int MAX_INCLUDE_LEVEL = 1;
- private static final String WELL_KNOWN_STATEMENT_PATH = "/.well-known/statements.json";
+ private static final String WELL_KNOWN_STATEMENT_PATH = "/.well-known/assetlinks.json";
private final URLFetcher mUrlFetcher;
private final AndroidPackageInfoFetcher mAndroidFetcher;
diff --git a/packages/StatementService/src/com/android/statementservice/retriever/Statement.java b/packages/StatementService/src/com/android/statementservice/retriever/Statement.java
index da3c355..0f40a62 100644
--- a/packages/StatementService/src/com/android/statementservice/retriever/Statement.java
+++ b/packages/StatementService/src/com/android/statementservice/retriever/Statement.java
@@ -21,7 +21,7 @@
/**
* An immutable value type representing a statement, consisting of a source, target, and relation.
* This reflects an assertion that the relation holds for the source, target pair. For example, if a
- * web site has the following in its statements.json file:
+ * web site has the following in its assetlinks.json file:
*
* <pre>
* {
diff --git a/packages/StatementService/src/com/android/statementservice/retriever/URLFetcher.java b/packages/StatementService/src/com/android/statementservice/retriever/URLFetcher.java
index 969aa88..225e26c 100644
--- a/packages/StatementService/src/com/android/statementservice/retriever/URLFetcher.java
+++ b/packages/StatementService/src/com/android/statementservice/retriever/URLFetcher.java
@@ -60,33 +60,36 @@
throw new IllegalArgumentException("The url protocol should be on http or https.");
}
- HttpURLConnection connection;
- connection = (HttpURLConnection) url.openConnection();
- connection.setInstanceFollowRedirects(true);
- connection.setConnectTimeout(connectionTimeoutMillis);
- connection.setReadTimeout(connectionTimeoutMillis);
- connection.setUseCaches(true);
- connection.setInstanceFollowRedirects(false);
- connection.addRequestProperty("Cache-Control", "max-stale=60");
-
- if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) {
- Log.e(TAG, "The responses code is not 200 but " + connection.getResponseCode());
- return new WebContent("", DO_NOT_CACHE_RESULT);
- }
-
- if (connection.getContentLength() > fileSizeLimit) {
- Log.e(TAG, "The content size of the url is larger than " + fileSizeLimit);
- return new WebContent("", DO_NOT_CACHE_RESULT);
- }
-
- Long expireTimeMillis = getExpirationTimeMillisFromHTTPHeader(connection.getHeaderFields());
-
+ HttpURLConnection connection = null;
try {
+ connection = (HttpURLConnection) url.openConnection();
+ connection.setInstanceFollowRedirects(true);
+ connection.setConnectTimeout(connectionTimeoutMillis);
+ connection.setReadTimeout(connectionTimeoutMillis);
+ connection.setUseCaches(true);
+ connection.setInstanceFollowRedirects(false);
+ connection.addRequestProperty("Cache-Control", "max-stale=60");
+
+ if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) {
+ Log.e(TAG, "The responses code is not 200 but " + connection.getResponseCode());
+ return new WebContent("", DO_NOT_CACHE_RESULT);
+ }
+
+ if (connection.getContentLength() > fileSizeLimit) {
+ Log.e(TAG, "The content size of the url is larger than " + fileSizeLimit);
+ return new WebContent("", DO_NOT_CACHE_RESULT);
+ }
+
+ Long expireTimeMillis = getExpirationTimeMillisFromHTTPHeader(
+ connection.getHeaderFields());
+
return new WebContent(inputStreamToString(
connection.getInputStream(), connection.getContentLength(), fileSizeLimit),
expireTimeMillis);
} finally {
- connection.disconnect();
+ if (connection != null) {
+ connection.disconnect();
+ }
}
}
diff --git a/packages/SystemUI/res/drawable/managed_profile_toast_background.xml b/packages/SystemUI/res/drawable/managed_profile_toast_background.xml
new file mode 100644
index 0000000..5c77b9a
--- /dev/null
+++ b/packages/SystemUI/res/drawable/managed_profile_toast_background.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <corners android:radius="2dp" />
+ <solid android:color="@color/managed_profile_toast_background" />
+</shape>
diff --git a/packages/SystemUI/res/drawable/stat_sys_managed_profile_status.xml b/packages/SystemUI/res/drawable/stat_sys_managed_profile_status.xml
index 3c4c646..2bfa39d 100644
--- a/packages/SystemUI/res/drawable/stat_sys_managed_profile_status.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_managed_profile_status.xml
@@ -20,10 +20,10 @@
android:viewportHeight="17.0">
<group android:translateX="2.0">
<path
- android:fillColor="#FF000000"
+ android:fillColor="@android:color/white"
android:pathData="M9.9,11.6H7v-1.1H2.1v2.8c0,0.8,0.6,1.4,1.4,1.4h9.9c0.8,0,1.4,-0.6,1.4,-1.4v-2.8H9.9V11.6z"/>
<path
- android:fillColor="#FF000000"
+ android:fillColor="@android:color/white"
android:pathData="M14.1,4.2h-2.5V3.2l-1.1,-1.1H6.3L5.3,3.2v1H2.8C2,4.2,1.4,4.9,1.4,5.6v2.8c0,0.8,0.6,1.4,1.4,1.4H7V8.8h2.8v1.1h4.2 c0.8,0,1.4,-0.6,1.4,-1.4V5.6C15.5,4.9,14.8,4.2,14.1,4.2z M10.6,4.2H6.3V3.2h4.2V4.2z"/>
</group>
</vector>
diff --git a/packages/SystemUI/res/layout-sw600dp/navigation_bar.xml b/packages/SystemUI/res/layout-sw600dp/navigation_bar.xml
index 456d2f9..9912343 100644
--- a/packages/SystemUI/res/layout-sw600dp/navigation_bar.xml
+++ b/packages/SystemUI/res/layout-sw600dp/navigation_bar.xml
@@ -3,16 +3,16 @@
**
** Copyright 2012, 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
+** 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
+** 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
+** 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.
-->
@@ -48,7 +48,7 @@
android:layout_marginStart="2dp"
android:visibility="invisible"
/>
- <Space
+ <Space
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
@@ -80,7 +80,7 @@
android:layout_weight="0"
android:contentDescription="@string/accessibility_recent"
/>
- <Space
+ <Space
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
@@ -120,7 +120,7 @@
android:id="@+id/lights_out"
android:visibility="gone"
>
- <Space
+ <Space
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
@@ -132,6 +132,7 @@
android:src="@drawable/ic_sysbar_lights_out_dot_small"
android:scaleType="center"
android:layout_weight="0"
+ android:contentDescription="@string/accessibility_back"
/>
<ImageView
android:layout_width="128dp" android:paddingStart="25dp" android:paddingEnd="25dp"
@@ -139,6 +140,7 @@
android:src="@drawable/ic_sysbar_lights_out_dot_large"
android:scaleType="center"
android:layout_weight="0"
+ android:contentDescription="@string/accessibility_home"
/>
<ImageView
android:layout_width="128dp" android:paddingStart="25dp" android:paddingEnd="25dp"
@@ -147,8 +149,9 @@
android:src="@drawable/ic_sysbar_lights_out_dot_small"
android:scaleType="center"
android:layout_weight="0"
+ android:contentDescription="@string/accessibility_recent"
/>
- <Space
+ <Space
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
@@ -193,7 +196,7 @@
android:layout_marginStart="2dp"
android:visibility="invisible"
/>
- <Space
+ <Space
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
@@ -225,7 +228,7 @@
android:layout_weight="0"
android:contentDescription="@string/accessibility_recent"
/>
- <Space
+ <Space
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
@@ -264,7 +267,7 @@
android:id="@+id/lights_out"
android:visibility="gone"
>
- <Space
+ <Space
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
@@ -276,6 +279,7 @@
android:src="@drawable/ic_sysbar_lights_out_dot_small"
android:scaleType="center"
android:layout_weight="0"
+ android:contentDescription="@string/accessibility_back"
/>
<ImageView
android:layout_width="162dp" android:paddingStart="42dp" android:paddingEnd="42dp"
@@ -283,6 +287,7 @@
android:src="@drawable/ic_sysbar_lights_out_dot_large"
android:scaleType="center"
android:layout_weight="0"
+ android:contentDescription="@string/accessibility_home"
/>
<ImageView
android:layout_width="162dp" android:paddingStart="42dp" android:paddingEnd="42dp"
@@ -291,8 +296,9 @@
android:src="@drawable/ic_sysbar_lights_out_dot_small"
android:scaleType="center"
android:layout_weight="0"
+ android:contentDescription="@string/accessibility_recent"
/>
- <Space
+ <Space
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
diff --git a/packages/SystemUI/res/layout/keyguard_bottom_area.xml b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
index 5d0367e..48af565 100644
--- a/packages/SystemUI/res/layout/keyguard_bottom_area.xml
+++ b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
@@ -33,7 +33,8 @@
android:gravity="center_horizontal"
android:textStyle="italic"
android:textColor="#ffffff"
- android:textAppearance="?android:attr/textAppearanceSmall" />
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:accessibilityLiveRegion="polite" />
<FrameLayout
android:id="@+id/preview_container"
diff --git a/packages/SystemUI/res/layout/managed_profile_toast.xml b/packages/SystemUI/res/layout/managed_profile_toast.xml
new file mode 100644
index 0000000..5a01ca7
--- /dev/null
+++ b/packages/SystemUI/res/layout/managed_profile_toast.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:paddingTop="16dp"
+ android:paddingBottom="16dp"
+ android:paddingLeft="32dp"
+ android:paddingRight="32dp"
+ android:background="@drawable/managed_profile_toast_background">
+ <ImageView
+ android:layout_width="32dp"
+ android:layout_height="32dp"
+ android:layout_gravity="center_horizontal"
+ android:layout_marginBottom="16dp"
+ android:src="@drawable/stat_sys_managed_profile_status"/>
+ <TextView android:text="@string/managed_profile_foreground_toast"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textColor="@android:color/white"
+ android:textSize="14sp"
+ android:layout_gravity="center_horizontal" />
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/mobile_signal_group.xml b/packages/SystemUI/res/layout/mobile_signal_group.xml
index 6a4ac2c..6ae5cf3 100644
--- a/packages/SystemUI/res/layout/mobile_signal_group.xml
+++ b/packages/SystemUI/res/layout/mobile_signal_group.xml
@@ -19,22 +19,25 @@
-->
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:systemui="http://schemas.android.com/apk/res-auto"
android:id="@+id/mobile_combo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
>
- <com.android.systemui.statusbar.AlphaOptimizedImageView
+ <com.android.systemui.statusbar.AnimatedImageView
android:theme="@style/DualToneLightTheme"
android:id="@+id/mobile_signal"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
+ systemui:hasOverlappingRendering="false"
/>
- <com.android.systemui.statusbar.AlphaOptimizedImageView
+ <com.android.systemui.statusbar.AnimatedImageView
android:theme="@style/DualToneDarkTheme"
android:id="@+id/mobile_signal_dark"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:alpha="0.0"
+ systemui:hasOverlappingRendering="false"
/>
<ImageView
android:id="@+id/mobile_type"
diff --git a/packages/SystemUI/res/layout/navigation_bar.xml b/packages/SystemUI/res/layout/navigation_bar.xml
index 898389d..c92ba45 100644
--- a/packages/SystemUI/res/layout/navigation_bar.xml
+++ b/packages/SystemUI/res/layout/navigation_bar.xml
@@ -4,16 +4,16 @@
**
** Copyright 2011, 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
+** 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
+** 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
+** 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.
*/
-->
@@ -57,7 +57,7 @@
android:scaleType="center"
android:contentDescription="@string/accessibility_back"
/>
- <View
+ <View
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
@@ -73,7 +73,7 @@
android:scaleType="center"
android:contentDescription="@string/accessibility_home"
/>
- <View
+ <View
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
@@ -130,8 +130,9 @@
android:src="@drawable/ic_sysbar_lights_out_dot_small"
android:scaleType="center"
android:layout_weight="0"
+ android:contentDescription="@string/accessibility_back"
/>
- <View
+ <View
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
@@ -143,8 +144,9 @@
android:src="@drawable/ic_sysbar_lights_out_dot_large"
android:scaleType="center"
android:layout_weight="0"
+ android:contentDescription="@string/accessibility_home"
/>
- <View
+ <View
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
@@ -157,6 +159,7 @@
android:src="@drawable/ic_sysbar_lights_out_dot_small"
android:scaleType="center"
android:layout_weight="0"
+ android:contentDescription="@string/accessibility_recent"
/>
</LinearLayout>
@@ -180,7 +183,7 @@
android:paddingTop="0dp"
>
- <LinearLayout
+ <LinearLayout
android:layout_height="match_parent"
android:layout_width="match_parent"
android:orientation="vertical"
@@ -225,7 +228,7 @@
android:layout_weight="0"
android:contentDescription="@string/accessibility_recent"
/>
- <View
+ <View
android:layout_height="match_parent"
android:layout_width="match_parent"
android:layout_weight="1"
@@ -241,7 +244,7 @@
android:layout_weight="0"
android:contentDescription="@string/accessibility_home"
/>
- <View
+ <View
android:layout_height="match_parent"
android:layout_width="match_parent"
android:layout_weight="1"
@@ -265,7 +268,7 @@
</LinearLayout>
<!-- lights out layout to match exactly -->
- <LinearLayout
+ <LinearLayout
android:layout_height="match_parent"
android:layout_width="match_parent"
android:orientation="vertical"
@@ -279,8 +282,9 @@
android:src="@drawable/ic_sysbar_lights_out_dot_small"
android:scaleType="center"
android:layout_weight="0"
+ android:contentDescription="@string/accessibility_recent"
/>
- <View
+ <View
android:layout_height="match_parent"
android:layout_width="match_parent"
android:layout_weight="1"
@@ -292,8 +296,9 @@
android:src="@drawable/ic_sysbar_lights_out_dot_large"
android:scaleType="center"
android:layout_weight="0"
+ android:contentDescription="@string/accessibility_home"
/>
- <View
+ <View
android:layout_height="match_parent"
android:layout_width="match_parent"
android:layout_weight="1"
@@ -306,6 +311,7 @@
android:src="@drawable/ic_sysbar_lights_out_dot_small"
android:scaleType="center"
android:layout_weight="0"
+ android:contentDescription="@string/accessibility_back"
/>
</LinearLayout>
diff --git a/packages/SystemUI/res/layout/quick_settings_brightness_dialog.xml b/packages/SystemUI/res/layout/quick_settings_brightness_dialog.xml
index a996260..38ea6e1 100644
--- a/packages/SystemUI/res/layout/quick_settings_brightness_dialog.xml
+++ b/packages/SystemUI/res/layout/quick_settings_brightness_dialog.xml
@@ -35,6 +35,7 @@
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_weight="1"
+ android:contentDescription="@string/accessibility_brightness"
systemui:text="@string/status_bar_settings_auto_brightness_label" />
</LinearLayout>
diff --git a/packages/SystemUI/res/layout/signal_cluster_view.xml b/packages/SystemUI/res/layout/signal_cluster_view.xml
index 69dcad2..f8bd6fd 100644
--- a/packages/SystemUI/res/layout/signal_cluster_view.xml
+++ b/packages/SystemUI/res/layout/signal_cluster_view.xml
@@ -20,6 +20,7 @@
<!-- extends LinearLayout -->
<com.android.systemui.statusbar.SignalClusterView
xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:systemui="http://schemas.android.com/apk/res-auto"
android:layout_height="match_parent"
android:layout_width="wrap_content"
android:gravity="center_vertical"
@@ -43,6 +44,7 @@
android:id="@+id/ethernet"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
+ systemui:hasOverlappingRendering="false"
/>
<com.android.systemui.statusbar.AlphaOptimizedImageView
android:theme="@style/DualToneDarkTheme"
@@ -50,6 +52,7 @@
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:alpha="0.0"
+ systemui:hasOverlappingRendering="false"
/>
</FrameLayout>
<FrameLayout
@@ -62,6 +65,7 @@
android:id="@+id/wifi_signal"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
+ systemui:hasOverlappingRendering="false"
/>
<com.android.systemui.statusbar.AlphaOptimizedImageView
android:theme="@style/DualToneDarkTheme"
@@ -69,6 +73,7 @@
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:alpha="0.0"
+ systemui:hasOverlappingRendering="false"
/>
</FrameLayout>
<View
@@ -84,14 +89,17 @@
>
</LinearLayout>
<FrameLayout
+ android:id="@+id/no_sims_combo"
android:layout_height="wrap_content"
- android:layout_width="wrap_content">
+ android:layout_width="wrap_content"
+ android:contentDescription="@string/accessibility_no_sims">
<com.android.systemui.statusbar.AlphaOptimizedImageView
android:theme="@style/DualToneLightTheme"
android:id="@+id/no_sims"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:src="@drawable/stat_sys_no_sims"
+ systemui:hasOverlappingRendering="false"
/>
<com.android.systemui.statusbar.AlphaOptimizedImageView
android:theme="@style/DualToneDarkTheme"
@@ -100,6 +108,7 @@
android:layout_width="wrap_content"
android:src="@drawable/stat_sys_no_sims"
android:alpha="0.0"
+ systemui:hasOverlappingRendering="false"
/>
</FrameLayout>
<View
diff --git a/packages/SystemUI/res/layout/status_bar_expanded_header.xml b/packages/SystemUI/res/layout/status_bar_expanded_header.xml
index 0e1517f..7262ed2 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded_header.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded_header.xml
@@ -162,6 +162,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
+ systemui:hasOverlappingRendering="false"
/>
<TextView
diff --git a/packages/SystemUI/res/layout/status_bar_toggle_slider.xml b/packages/SystemUI/res/layout/status_bar_toggle_slider.xml
index a5bf68e..062e6cb 100644
--- a/packages/SystemUI/res/layout/status_bar_toggle_slider.xml
+++ b/packages/SystemUI/res/layout/status_bar_toggle_slider.xml
@@ -45,7 +45,6 @@
android:paddingBottom="16dp"
android:thumb="@drawable/ic_brightness_thumb"
android:splitTrack="false"
- android:contentDescription="@string/accessibility_brightness"
/>
<TextView
android:id="@+id/label"
diff --git a/packages/SystemUI/res/layout/volume_dialog_row.xml b/packages/SystemUI/res/layout/volume_dialog_row.xml
index d12bf5d..c6aa588 100644
--- a/packages/SystemUI/res/layout/volume_dialog_row.xml
+++ b/packages/SystemUI/res/layout/volume_dialog_row.xml
@@ -22,15 +22,15 @@
<TextView
android:id="@+id/volume_row_header"
- style="?android:attr/textAppearanceButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:maxLines="1"
+ android:textAppearance="@style/TextAppearance.Volume.Header"
android:paddingBottom="0dp"
android:paddingEnd="12dp"
- android:paddingStart="13dp"
- android:paddingTop="8dp" />
+ android:paddingStart="12dp"
+ android:paddingTop="4dp" />
<com.android.keyguard.AlphaOptimizedImageButton
android:id="@+id/volume_row_icon"
diff --git a/packages/SystemUI/res/values/attrs.xml b/packages/SystemUI/res/values/attrs.xml
index 354b70b..527248c 100644
--- a/packages/SystemUI/res/values/attrs.xml
+++ b/packages/SystemUI/res/values/attrs.xml
@@ -86,5 +86,9 @@
<declare-styleable name="StatusBarWindowView_Layout">
<attr name="ignoreRightInset" format="boolean" />
</declare-styleable>
+
+ <declare-styleable name="AlphaOptimizedImageView">
+ <attr name="hasOverlappingRendering" format="boolean" />
+ </declare-styleable>
</resources>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 0dcbe88..9a96939 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -143,4 +143,6 @@
<color name="volume_icon_color">#ffffffff</color>
<color name="volume_settings_icon_color">#7fffffff</color>
<color name="volume_slider_inactive">#FFB0BEC5</color><!-- blue grey 200 -->
+
+ <color name="managed_profile_toast_background">#E5000000</color><!-- 90% black -->
</resources>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index de5639b..260d81b1 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -135,8 +135,6 @@
<!-- The maximum number of items to be displayed in quick settings -->
<integer name="quick_settings_detail_max_item_count">7</integer>
- <integer name="blinds_pop_duration_ms">10</integer>
-
<!-- Should "4G" be shown instead of "LTE" when the network is NETWORK_TYPE_LTE? -->
<bool name="config_show4GForLTE">true</bool>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 0e0584f..47c642d 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -374,6 +374,9 @@
<!-- Content description of the airplane mode icon for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_airplane_mode">Airplane mode.</string>
+ <!-- Content description of the no sim icon for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
+ <string name="accessibility_no_sims">No SIM card.</string>
+
<!-- Content description of the carrier network changing icon for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_carrier_network_change_mode">Carrier network changing.</string>
@@ -772,6 +775,9 @@
<!-- Shows when people have clicked on the camera icon [CHAR LIMIT=60] -->
<string name="camera_hint">Swipe from icon for camera</string>
+ <!-- Accessibility content description for Interruption level: None. [CHAR LIMIT=NONE] -->
+ <string name="interruption_level_none_with_warning">Total silence. This will also silence screen readers.</string>
+
<!-- Interruption level: None. [CHAR LIMIT=40] -->
<string name="interruption_level_none">Total silence</string>
@@ -847,7 +853,7 @@
<string name="guest_notification_title">Guest user</string>
<!-- Text of the notification shown to a new guest user [CHAR LIMIT=60] -->
- <string name="guest_notification_text">Remove guest to delete apps and data</string>
+ <string name="guest_notification_text">To delete apps and data, remove guest user</string>
<!-- Remove action in the notification shown to a new guest user [CHAR LIMIT=30] -->
<string name="guest_notification_remove_action">REMOVE GUEST</string>
@@ -1009,7 +1015,7 @@
<string name="volumeui_notification_text">Touch to restore the original.</string>
<!-- Toast shown when user unlocks screen and managed profile activity is in the foreground -->
- <string name="managed_profile_foreground_toast">You are in the work profile</string>
+ <string name="managed_profile_foreground_toast">You\'re using your work profile</string>
<string-array name="volume_stream_titles" translatable="false">
<item>Voice calls</item> <!-- STREAM_VOICE_CALL -->
@@ -1096,4 +1102,7 @@
<!-- Accessibility label for hotspot icon [CHAR LIMIT=NONE] -->
<string name="accessibility_status_bar_hotspot">Hotspot</string>
+ <!-- Accessibility label for managed profile icon (not shown on screen) [CHAR LIMIT=NONE] -->
+ <string name="accessibility_managed_profile">Work profile</string>
+
</resources>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index bda39b1..67d3312 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -275,6 +275,11 @@
<item name="android:fontFamily">sans-serif</item>
</style>
+ <style name="TextAppearance.Volume.Header">
+ <item name="android:textSize">12sp</item>
+ <item name="android:textColor">@color/volume_slider_inactive</item>
+ </style>
+
<style name="TextAppearance.Volume.ZenSummary">
<item name="android:textSize">14sp</item>
<item name="android:fontFamily">sans-serif-medium</item>
diff --git a/packages/SystemUI/src/com/android/systemui/ExpandHelper.java b/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
index fece07f..b0e2afa 100644
--- a/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
@@ -25,6 +25,7 @@
import android.os.Vibrator;
import android.util.Log;
import android.view.Gravity;
+import android.view.HapticFeedbackConstants;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.ScaleGestureDetector.OnScaleGestureListener;
@@ -64,15 +65,6 @@
// 2f: maximum brightness is stretching a 1U to 3U, or a 4U to 6U
private static final float STRETCH_INTERVAL = 2f;
- // level of glow for a touch, without overstretch
- // overstretch fills the range (GLOW_BASE, 1.0]
- private static final float GLOW_BASE = 0.5f;
-
- private static final AudioAttributes VIBRATION_ATTRIBUTES = new AudioAttributes.Builder()
- .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
- .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
- .build();
-
@SuppressWarnings("unused")
private Context mContext;
@@ -94,13 +86,11 @@
private float mLastSpanY;
private int mTouchSlop;
private float mLastMotionY;
- private int mPopDuration;
private float mPullGestureMinXSpan;
private Callback mCallback;
private ScaleGestureDetector mSGD;
private ViewScaler mScaler;
private ObjectAnimator mScaleAnimation;
- private Vibrator mVibrator;
private boolean mEnabled = true;
private ExpandableView mResizedView;
private float mCurrentHeight;
@@ -174,7 +164,6 @@
mScaler = new ViewScaler();
mGravity = Gravity.TOP;
mScaleAnimation = ObjectAnimator.ofFloat(mScaler, "height", 0f);
- mPopDuration = mContext.getResources().getInteger(R.integer.blinds_pop_duration_ms);
mPullGestureMinXSpan = mContext.getResources().getDimension(R.dimen.pull_span_min);
final ViewConfiguration configuration = ViewConfiguration.get(mContext);
@@ -452,7 +441,9 @@
}
if (!mHasPopped) {
- vibrate(mPopDuration);
+ if (mEventSource != null) {
+ mEventSource.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);
+ }
mHasPopped = true;
}
@@ -600,16 +591,5 @@
public void onlyObserveMovements(boolean onlyMovements) {
mOnlyMovements = onlyMovements;
}
-
- /**
- * Triggers haptic feedback.
- */
- private synchronized void vibrate(long duration) {
- if (mVibrator == null) {
- mVibrator = (android.os.Vibrator)
- mContext.getSystemService(Context.VIBRATOR_SERVICE);
- }
- mVibrator.vibrate(duration, VIBRATION_ATTRIBUTES);
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
index 3e122da..1e7ee98 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
@@ -116,7 +116,6 @@
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
WindowManager.LayoutParams lp = getLayoutParams();
mWindowManager.addView(mView, lp);
- mBar.getNavigationBarView().setDelegateView(mView);
if (visible) {
mView.show(true /* show */, false /* animate */);
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index 25e3d10..c8212c2 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -360,7 +360,7 @@
}
private void handleShowDetailTile(TileRecord r, boolean show) {
- if ((mDetailRecord != null) == show) return;
+ if ((mDetailRecord != null) == show && mDetailRecord == r) return;
if (show) {
r.detailAdapter = r.tile.getDetailAdapter();
@@ -373,7 +373,8 @@
}
private void handleShowDetailImpl(Record r, boolean show, int x, int y) {
- if ((mDetailRecord != null) == show) return; // already in right state
+ boolean visibleDiff = (mDetailRecord != null) != show;
+ if (!visibleDiff && mDetailRecord == r) return; // already in right state
DetailAdapter detailAdapter = null;
AnimatorListener listener = null;
if (show) {
@@ -399,11 +400,13 @@
mContext.getString(detailAdapter.getTitle())));
setDetailRecord(r);
listener = mHideGridContentWhenDone;
- if (r instanceof TileRecord) {
+ if (r instanceof TileRecord && visibleDiff) {
((TileRecord) r).openingDetail = true;
}
} else {
- MetricsLogger.hidden(mContext, mDetailRecord.detailAdapter.getMetricsCategory());
+ if (mDetailRecord != null) {
+ MetricsLogger.hidden(mContext, mDetailRecord.detailAdapter.getMetricsCategory());
+ }
mClosingDetail = true;
setGridContentVisibility(true);
listener = mTeardownDetailWhenDone;
@@ -411,7 +414,9 @@
}
sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
fireShowingDetail(show ? detailAdapter : null);
- mClipper.animateCircularClip(x, y, show, listener);
+ if (visibleDiff) {
+ mClipper.animateCircularClip(x, y, show, listener);
+ }
}
private void setGridContentVisibility(boolean visible) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
index 7c378f0..915867b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
@@ -73,6 +73,10 @@
: mController.isRotationLocked();
final boolean userInitiated = arg != null ? ((UserBoolean) arg).userInitiated : false;
state.visible = mController.isRotationLockAffordanceVisible();
+ if (state.value == rotationLocked) {
+ // No change, no need to update all the values.
+ return;
+ }
state.value = rotationLocked;
final boolean portrait = mContext.getResources().getConfiguration().orientation
!= Configuration.ORIENTATION_LANDSCAPE;
diff --git a/packages/SystemUI/src/com/android/systemui/settings/ToggleSlider.java b/packages/SystemUI/src/com/android/systemui/settings/ToggleSlider.java
index 8abfe03..cdb8e69 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/ToggleSlider.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/ToggleSlider.java
@@ -74,6 +74,8 @@
mLabel = (TextView) findViewById(R.id.label);
mLabel.setText(a.getString(R.styleable.ToggleSlider_text));
+ setLabelFor(R.id.slider); // use our a11y text to annotate, not replace, the slider's
+
a.recycle();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
index c0b3a9b..7cde44c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
@@ -21,15 +21,8 @@
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.content.Context;
-import android.graphics.Bitmap;
-import android.graphics.BitmapShader;
import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Paint;
-import android.graphics.PorterDuff;
-import android.graphics.PorterDuffColorFilter;
import android.graphics.RectF;
-import android.graphics.Shader;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
@@ -100,7 +93,6 @@
private boolean mDark;
private int mBgTint = 0;
- private final int mRoundedRectCornerRadius;
/**
* Flag to indicate that the notification has been touched once and the second touch will
@@ -126,10 +118,8 @@
private NotificationBackgroundView mBackgroundDimmed;
private ObjectAnimator mBackgroundAnimator;
private RectF mAppearAnimationRect = new RectF();
- private PorterDuffColorFilter mAppearAnimationFilter;
private float mAnimationTranslationY;
private boolean mDrawingAppearAnimation;
- private Paint mAppearPaint = new Paint();
private ValueAnimator mAppearAnimator;
private float mAppearAnimationFraction = -1.0f;
private float mAppearAnimationTranslation;
@@ -151,9 +141,6 @@
mLinearInterpolator = new LinearInterpolator();
setClipChildren(false);
setClipToPadding(false);
- mAppearAnimationFilter = new PorterDuffColorFilter(0, PorterDuff.Mode.SRC_ATOP);
- mRoundedRectCornerRadius = getResources().getDimensionPixelSize(
- R.dimen.notification_material_rounded_rect_radius);
mLegacyColor = context.getColor(R.color.notification_legacy_background_color);
mNormalColor = context.getColor(R.color.notification_material_background_color);
mLowPriorityColor = context.getColor(
@@ -540,9 +527,7 @@
private void startAppearAnimation(boolean isAppearing, float translationDirection, long delay,
long duration, final Runnable onFinishedRunnable) {
- if (mAppearAnimator != null) {
- mAppearAnimator.cancel();
- }
+ cancelAppearAnimation();
mAnimationTranslationY = translationDirection * getActualHeight();
if (mAppearAnimationFraction == -1.0f) {
// not initialized yet, we start anew
@@ -613,6 +598,17 @@
mAppearAnimator.start();
}
+ private void cancelAppearAnimation() {
+ if (mAppearAnimator != null) {
+ mAppearAnimator.cancel();
+ }
+ }
+
+ public void cancelAppearDrawing() {
+ cancelAppearAnimation();
+ enableAppearDrawing(false);
+ }
+
private void updateAppearRect() {
float inverseFraction = (1.0f - mAppearAnimationFraction);
float translationFraction = mCurrentAppearInterpolator.getInterpolation(inverseFraction);
@@ -652,20 +648,26 @@
}
private void updateAppearAnimationAlpha() {
- int backgroundColor = getBgColor();
- if (backgroundColor != -1) {
- float contentAlphaProgress = mAppearAnimationFraction;
- contentAlphaProgress = contentAlphaProgress / (1.0f - ALPHA_ANIMATION_END);
- contentAlphaProgress = Math.min(1.0f, contentAlphaProgress);
- contentAlphaProgress = mCurrentAlphaInterpolator.getInterpolation(contentAlphaProgress);
- int sourceColor = Color.argb((int) (255 * (1.0f - contentAlphaProgress)),
- Color.red(backgroundColor), Color.green(backgroundColor),
- Color.blue(backgroundColor));
- mAppearAnimationFilter.setColor(sourceColor);
- mAppearPaint.setColorFilter(mAppearAnimationFilter);
- }
+ float contentAlphaProgress = mAppearAnimationFraction;
+ contentAlphaProgress = contentAlphaProgress / (1.0f - ALPHA_ANIMATION_END);
+ contentAlphaProgress = Math.min(1.0f, contentAlphaProgress);
+ contentAlphaProgress = mCurrentAlphaInterpolator.getInterpolation(contentAlphaProgress);
+ setContentAlpha(contentAlphaProgress);
}
+ private void setContentAlpha(float contentAlpha) {
+ int layerType = contentAlpha == 0.0f || contentAlpha == 1.0f ? LAYER_TYPE_NONE
+ : LAYER_TYPE_HARDWARE;
+ View contentView = getContentView();
+ int currentLayerType = contentView.getLayerType();
+ if (currentLayerType != layerType) {
+ contentView.setLayerType(layerType, null);
+ }
+ contentView.setAlpha(contentAlpha);
+ }
+
+ protected abstract View getContentView();
+
private int getBgColor() {
if (mBgTint != 0) {
return mBgTint;
@@ -699,41 +701,24 @@
*/
private void enableAppearDrawing(boolean enable) {
if (enable != mDrawingAppearAnimation) {
- if (enable) {
- if (getWidth() == 0 || getActualHeight() == 0) {
- // TODO: This should not happen, but it can during expansion. Needs
- // investigation
- return;
- }
- Bitmap bitmap = Bitmap.createBitmap(getWidth(), getActualHeight(),
- Bitmap.Config.ARGB_8888);
- Canvas canvas = new Canvas(bitmap);
- draw(canvas);
- mAppearPaint.setShader(new BitmapShader(bitmap, Shader.TileMode.CLAMP,
- Shader.TileMode.CLAMP));
- } else {
- mAppearPaint.setShader(null);
- }
mDrawingAppearAnimation = enable;
+ if (!enable) {
+ setContentAlpha(1.0f);
+ }
invalidate();
}
}
@Override
protected void dispatchDraw(Canvas canvas) {
- if (!mDrawingAppearAnimation) {
- super.dispatchDraw(canvas);
- } else {
- drawAppearRect(canvas);
+ if (mDrawingAppearAnimation) {
+ canvas.save();
+ canvas.translate(0, mAppearAnimationTranslation);
}
- }
-
- private void drawAppearRect(Canvas canvas) {
- canvas.save();
- canvas.translate(0, mAppearAnimationTranslation);
- canvas.drawRoundRect(mAppearAnimationRect, mRoundedRectCornerRadius,
- mRoundedRectCornerRadius, mAppearPaint);
- canvas.restore();
+ super.dispatchDraw(canvas);
+ if (mDrawingAppearAnimation) {
+ canvas.restore();
+ }
}
public void setOnActivatedListener(OnActivatedListener onActivatedListener) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/AlphaOptimizedImageView.java b/packages/SystemUI/src/com/android/systemui/statusbar/AlphaOptimizedImageView.java
index 858c118..700ea34 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/AlphaOptimizedImageView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/AlphaOptimizedImageView.java
@@ -17,34 +17,49 @@
package com.android.systemui.statusbar;
import android.content.Context;
+import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.widget.ImageView;
+import com.android.systemui.R;
+
/**
- * An ImageView which does not have overlapping rendering commands and therefore does not need a
- * layer when alpha is changed.
+ * An ImageView which supports an attribute specifying whether it has overlapping rendering
+ * commands and therefore does not need a layer when alpha is changed.
*/
-public class AlphaOptimizedImageView extends ImageView
-{
+public class AlphaOptimizedImageView extends ImageView {
+ private final boolean mHasOverlappingRendering;
+
public AlphaOptimizedImageView(Context context) {
- super(context);
+ this(context, null /* attrs */);
}
public AlphaOptimizedImageView(Context context, AttributeSet attrs) {
- super(context, attrs);
+ this(context, attrs, 0 /* defStyleAttr */);
}
public AlphaOptimizedImageView(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
+ this(context, attrs, defStyleAttr, 0 /* defStyleRes */);
}
public AlphaOptimizedImageView(Context context, AttributeSet attrs, int defStyleAttr,
int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
+
+ TypedArray a = context.getTheme().obtainStyledAttributes(attrs,
+ R.styleable.AlphaOptimizedImageView, 0, 0);
+
+ try {
+ // Default to true, which is what View.java defaults to
+ mHasOverlappingRendering = a.getBoolean(
+ R.styleable.AlphaOptimizedImageView_hasOverlappingRendering, true);
+ } finally {
+ a.recycle();
+ }
}
@Override
public boolean hasOverlappingRendering() {
- return false;
+ return mHasOverlappingRendering;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/AnimatedImageView.java b/packages/SystemUI/src/com/android/systemui/statusbar/AnimatedImageView.java
index 9839fe9..90f7c08 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/AnimatedImageView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/AnimatedImageView.java
@@ -25,10 +25,15 @@
import android.widget.RemoteViews.RemoteView;
@RemoteView
-public class AnimatedImageView extends ImageView {
+public class AnimatedImageView extends AlphaOptimizedImageView {
AnimationDrawable mAnim;
boolean mAttached;
+ // Tracks the last image that was set, so that we don't refresh the image if it is exactly
+ // the same as the previous one. If this is a resid, we track that. If it's a drawable, we
+ // track the hashcode of the drawable.
+ int mDrawableId;
+
public AnimatedImageView(Context context) {
super(context);
}
@@ -43,7 +48,7 @@
mAnim.stop();
}
if (drawable instanceof AnimationDrawable) {
- mAnim = (AnimationDrawable)drawable;
+ mAnim = (AnimationDrawable) drawable;
if (isShown()) {
mAnim.start();
}
@@ -54,6 +59,13 @@
@Override
public void setImageDrawable(Drawable drawable) {
+ if (drawable != null) {
+ if (mDrawableId == drawable.hashCode()) return;
+
+ mDrawableId = drawable.hashCode();
+ } else {
+ mDrawableId = 0;
+ }
super.setImageDrawable(drawable);
updateAnim();
}
@@ -61,6 +73,9 @@
@Override
@android.view.RemotableViewMethod
public void setImageResource(int resid) {
+ if (mDrawableId == resid) return;
+
+ mDrawableId = resid;
super.setImageResource(resid);
updateAnim();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 4cce1a4..0b49564 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -24,7 +24,6 @@
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
-import android.app.RemoteInput;
import android.app.TaskStackBuilder;
import android.app.admin.DevicePolicyManager;
import android.content.BroadcastReceiver;
@@ -65,6 +64,7 @@
import android.util.SparseArray;
import android.util.SparseBooleanArray;
import android.view.Display;
+import android.view.Gravity;
import android.view.IWindowManager;
import android.view.LayoutInflater;
import android.view.MotionEvent;
@@ -101,7 +101,6 @@
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.statusbar.policy.PreviewInflater;
-import com.android.systemui.statusbar.policy.RemoteInputView;
import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
import java.util.ArrayList;
@@ -121,8 +120,6 @@
// STOPSHIP disable once we resolve b/18102199
private static final boolean NOTIFICATION_CLICK_DEBUG = true;
- public static final boolean ENABLE_REMOTE_INPUT =
- Build.IS_DEBUGGABLE && SystemProperties.getBoolean("debug.enable_remote_input", false);
public static final boolean ENABLE_CHILD_NOTIFICATIONS = Build.IS_DEBUGGABLE
&& SystemProperties.getBoolean("debug.child_notifs", false);
@@ -395,8 +392,14 @@
if (recentTask != null && recentTask.size() > 0) {
UserInfo user = mUserManager.getUserInfo(recentTask.get(0).userId);
if (user != null && user.isManagedProfile()) {
- Toast.makeText(mContext, R.string.managed_profile_foreground_toast,
- Toast.LENGTH_SHORT).show();
+ LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(
+ Context.LAYOUT_INFLATER_SERVICE);
+ View layout = inflater.inflate(R.layout.managed_profile_toast, null);
+ Toast toast = new Toast(mContext);
+ toast.setGravity(Gravity.CENTER_VERTICAL, 0, 0);
+ toast.setDuration(Toast.LENGTH_SHORT);
+ toast.setView(layout);
+ toast.show();
}
}
} else if (BANNER_ACTION_CANCEL.equals(action) || BANNER_ACTION_SETUP.equals(action)) {
@@ -456,7 +459,7 @@
mHandler.post(new Runnable() {
@Override
public void run() {
- processForRemoteInput(sbn.getNotification());
+
String key = sbn.getKey();
boolean isUpdate = mNotificationData.get(key) != null;
@@ -1307,9 +1310,6 @@
NotificationContentView contentContainerPublic = row.getPublicLayout();
row.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
- if (ENABLE_REMOTE_INPUT) {
- row.setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS);
- }
mNotificationClicker.register(row, sbn);
@@ -1472,106 +1472,10 @@
}
row.setUserLocked(userLocked);
row.setStatusBarNotification(entry.notification);
- applyRemoteInput(entry);
+
return true;
}
- /**
- * Adds RemoteInput actions from the WearableExtender; to be removed once more apps support this
- * via first-class API.
- *
- * TODO: Remove once enough apps specify remote inputs on their own.
- */
- private void processForRemoteInput(Notification n) {
- if (!ENABLE_REMOTE_INPUT) return;
-
- if (n.extras != null && n.extras.containsKey("android.wearable.EXTENSIONS") &&
- (n.actions == null || n.actions.length == 0)) {
- Notification.Action viableAction = null;
- Notification.WearableExtender we = new Notification.WearableExtender(n);
-
- List<Notification.Action> actions = we.getActions();
- final int numActions = actions.size();
-
- for (int i = 0; i < numActions; i++) {
- Notification.Action action = actions.get(i);
- RemoteInput[] remoteInputs = action.getRemoteInputs();
- for (RemoteInput ri : action.getRemoteInputs()) {
- if (ri.getAllowFreeFormInput()) {
- viableAction = action;
- break;
- }
- }
- if (viableAction != null) {
- break;
- }
- }
-
- if (viableAction != null) {
- Notification stripped = n.clone();
- Notification.Builder.stripForDelivery(stripped);
- stripped.actions = new Notification.Action[] { viableAction };
- stripped.extras.putBoolean("android.rebuild.contentView", true);
- stripped.contentView = null;
- stripped.extras.putBoolean("android.rebuild.bigView", true);
- stripped.bigContentView = null;
- stripped.extras.putBoolean("android.rebuild.hudView", true);
- stripped.headsUpContentView = null;
-
- Notification rebuilt = Notification.Builder.rebuild(mContext, stripped);
-
- n.actions = rebuilt.actions;
- n.bigContentView = rebuilt.bigContentView;
- n.headsUpContentView = rebuilt.headsUpContentView;
- n.publicVersion = rebuilt.publicVersion;
- }
- }
- }
-
- private void applyRemoteInput(final Entry entry) {
- if (!ENABLE_REMOTE_INPUT) return;
-
- RemoteInput remoteInput = null;
-
- // See if the notification has exactly one action and this action allows free-form input
- // TODO: relax restrictions once we support more than one remote input action.
- Notification.Action[] actions = entry.notification.getNotification().actions;
- if (actions != null && actions.length == 1) {
- if (actions[0].getRemoteInputs() != null) {
- for (RemoteInput ri : actions[0].getRemoteInputs()) {
- if (ri.getAllowFreeFormInput()) {
- remoteInput = ri;
- break;
- }
- }
- }
- }
-
- // See if we have somewhere to put that remote input
- if (remoteInput != null) {
- View bigContentView = entry.getExpandedContentView();
- if (bigContentView != null) {
- inflateRemoteInput(bigContentView, remoteInput, actions);
- }
- View headsUpContentView = entry.getHeadsUpContentView();
- if (headsUpContentView != null) {
- inflateRemoteInput(headsUpContentView, remoteInput, actions);
- }
- }
-
- }
-
- private void inflateRemoteInput(View view, RemoteInput remoteInput,
- Notification.Action[] actions) {
- View actionContainerCandidate = view.findViewById(com.android.internal.R.id.actions);
- if (actionContainerCandidate instanceof ViewGroup) {
- ViewGroup actionContainer = (ViewGroup) actionContainerCandidate;
- actionContainer.removeAllViews();
- actionContainer.addView(
- RemoteInputView.inflate(mContext, actionContainer, actions[0], remoteInput));
- }
- }
-
private final class NotificationClicker implements View.OnClickListener {
public void onClick(final View v) {
if (!(v instanceof ExpandableNotificationRow)) {
@@ -1848,11 +1752,8 @@
}
}
- if (onKeyguard && mKeyguardIconOverflowContainer.getIconsView().getChildCount() > 0) {
- mKeyguardIconOverflowContainer.setVisibility(View.VISIBLE);
- } else {
- mKeyguardIconOverflowContainer.setVisibility(View.GONE);
- }
+ mStackScroller.updateOverflowContainerVisibility(onKeyguard
+ && mKeyguardIconOverflowContainer.getIconsView().getChildCount() > 0);
mStackScroller.changeViewPosition(mDismissView, mStackScroller.getChildCount() - 1);
mStackScroller.changeViewPosition(mEmptyShadeView, mStackScroller.getChildCount() - 2);
@@ -2068,8 +1969,6 @@
entry.row.setStatusBarNotification(notification);
entry.row.notifyContentUpdated();
entry.row.resetHeight();
-
- applyRemoteInput(entry);
}
protected void notifyHeadsUpScreenOff() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/DelegateViewHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/DelegateViewHelper.java
deleted file mode 100644
index 2dc521e..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/DelegateViewHelper.java
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- * Copyright (C) 2010 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.app.StatusBarManager;
-import android.content.res.Resources;
-import android.graphics.RectF;
-import android.view.MotionEvent;
-import android.view.View;
-import com.android.systemui.R;
-import com.android.systemui.statusbar.phone.PhoneStatusBar;
-
-public class DelegateViewHelper {
- private View mDelegateView;
- private View mSourceView;
- private PhoneStatusBar mBar;
- private int[] mTempPoint = new int[2];
- private float[] mDownPoint = new float[2];
- private float mTriggerThreshhold;
- private boolean mPanelShowing;
-
- RectF mInitialTouch = new RectF();
- private boolean mStarted;
- private boolean mSwapXY = false;
- private boolean mDisabled;
-
- public DelegateViewHelper(View sourceView) {
- setSourceView(sourceView);
- }
-
- public void setDelegateView(View view) {
- mDelegateView = view;
- }
-
- public void setBar(PhoneStatusBar phoneStatusBar) {
- mBar = phoneStatusBar;
- }
-
- public boolean onInterceptTouchEvent(MotionEvent event) {
- if (mSourceView == null || mDelegateView == null || mBar.shouldDisableNavbarGestures()) {
- return false;
- }
-
- mSourceView.getLocationOnScreen(mTempPoint);
- final float sourceX = mTempPoint[0];
- final float sourceY = mTempPoint[1];
-
- final int action = event.getAction();
- switch (action) {
- case MotionEvent.ACTION_DOWN:
- mPanelShowing = mDelegateView.getVisibility() == View.VISIBLE;
- mDownPoint[0] = event.getX();
- mDownPoint[1] = event.getY();
- mStarted = mInitialTouch.contains(mDownPoint[0] + sourceX, mDownPoint[1] + sourceY);
- break;
- }
-
- if (!mStarted) {
- return false;
- }
-
- if (!mDisabled && !mPanelShowing && action == MotionEvent.ACTION_MOVE) {
- final int historySize = event.getHistorySize();
- for (int k = 0; k < historySize + 1; k++) {
- float x = k < historySize ? event.getHistoricalX(k) : event.getX();
- float y = k < historySize ? event.getHistoricalY(k) : event.getY();
- final float distance = mSwapXY ? (mDownPoint[0] - x) : (mDownPoint[1] - y);
- if (distance > mTriggerThreshhold) {
- mBar.invokeAssistGesture(false /* vibrate */);
- mPanelShowing = true;
- break;
- }
- }
- }
-
- if (action == MotionEvent.ACTION_DOWN) {
- mBar.setInteracting(StatusBarManager.WINDOW_NAVIGATION_BAR, true);
- } else if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
- mBar.setInteracting(StatusBarManager.WINDOW_NAVIGATION_BAR, false);
- }
-
- mDelegateView.getLocationOnScreen(mTempPoint);
- final float delegateX = mTempPoint[0];
- final float delegateY = mTempPoint[1];
-
- float deltaX = sourceX - delegateX;
- float deltaY = sourceY - delegateY;
- event.offsetLocation(deltaX, deltaY);
- mDelegateView.dispatchTouchEvent(event);
- event.offsetLocation(-deltaX, -deltaY);
- return mPanelShowing;
- }
-
- public void abortCurrentGesture() {
- if (mStarted) {
- mStarted = false;
- mBar.setInteracting(StatusBarManager.WINDOW_NAVIGATION_BAR, false);
- }
- }
-
- public void setSourceView(View view) {
- mSourceView = view;
- if (mSourceView != null) {
- Resources r = mSourceView.getContext().getResources();
- mTriggerThreshhold = r.getDimensionPixelSize(R.dimen.navigation_bar_min_swipe_distance);
- }
- }
-
- /**
- * Selects the initial touch region based on a list of views. This is meant to be called by
- * a container widget on children over which the initial touch should be detected. Note this
- * will compute a minimum bound that contains all specified views.
- *
- * @param views
- */
- public void setInitialTouchRegion(View ... views) {
- RectF bounds = new RectF();
- int p[] = new int[2];
- for (int i = 0; i < views.length; i++) {
- View view = views[i];
- if (view == null) continue;
- view.getLocationOnScreen(p);
- if (i == 0) {
- bounds.set(p[0], p[1], p[0] + view.getWidth(), p[1] + view.getHeight());
- } else {
- bounds.union(p[0], p[1], p[0] + view.getWidth(), p[1] + view.getHeight());
- }
- }
- mInitialTouch.set(bounds);
- }
-
- /**
- * When rotation is set to NO_SENSOR, then this allows swapping x/y for gesture detection
- * @param swap
- */
- public void setSwapXY(boolean swap) {
- mSwapXY = swap;
- }
-
- public void setDisabled(boolean disabled) {
- mDisabled = disabled;
- }
-}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index d444ea8..b88e5ca 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -856,6 +856,11 @@
}
@Override
+ protected View getContentView() {
+ return getShowingLayout();
+ }
+
+ @Override
public void setActualHeight(int height, boolean notifyListeners) {
super.setActualHeight(height, notifyListeners);
int contentHeight = calculateContentHeightFromActualHeight(height);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java
index a18fff2..d77e050 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java
@@ -24,16 +24,21 @@
import android.view.View;
import android.view.ViewOutlineProvider;
+import com.android.systemui.R;
+
/**
* Like {@link ExpandableView}, but setting an outline for the height and clipping.
*/
public abstract class ExpandableOutlineView extends ExpandableView {
private final Rect mOutlineRect = new Rect();
+ protected final int mRoundedRectCornerRadius;
private boolean mCustomOutline;
public ExpandableOutlineView(Context context, AttributeSet attrs) {
super(context, attrs);
+ mRoundedRectCornerRadius = getResources().getDimensionPixelSize(
+ R.dimen.notification_material_rounded_rect_radius);
setOutlineProvider(new ViewOutlineProvider() {
@Override
public void getOutline(View view, Outline outline) {
@@ -43,7 +48,7 @@
getWidth(),
Math.max(getActualHeight(), mClipTopAmount));
} else {
- outline.setRect(mOutlineRect);
+ outline.setRoundRect(mOutlineRect, mRoundedRectCornerRadius);
}
}
});
@@ -66,12 +71,14 @@
setOutlineRect(rect.left, rect.top, rect.right, rect.bottom);
} else {
mCustomOutline = false;
+ setClipToOutline(false);
invalidateOutline();
}
}
protected void setOutlineRect(float left, float top, float right, float bottom) {
mCustomOutline = true;
+ setClipToOutline(true);
mOutlineRect.set((int) left, (int) top, (int) right, (int) bottom);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
index 3feec9e..08a6603 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
@@ -43,6 +43,7 @@
private ArrayList<View> mMatchParentViews = new ArrayList<View>();
private int mClipTopOptimization;
private static Rect mClipRect = new Rect();
+ private boolean mWillBeGone;
public ExpandableView(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -133,6 +134,14 @@
}
@Override
+ public boolean dispatchGenericMotionEvent(MotionEvent ev) {
+ if (filterMotionEvent(ev)) {
+ return super.dispatchGenericMotionEvent(ev);
+ }
+ return false;
+ }
+
+ @Override
public boolean dispatchTouchEvent(MotionEvent ev) {
if (filterMotionEvent(ev)) {
return super.dispatchTouchEvent(ev);
@@ -142,6 +151,8 @@
protected boolean filterMotionEvent(MotionEvent event) {
return event.getActionMasked() != MotionEvent.ACTION_DOWN
+ && event.getActionMasked() != MotionEvent.ACTION_HOVER_ENTER
+ && event.getActionMasked() != MotionEvent.ACTION_HOVER_MOVE
|| event.getY() > mClipTopAmount && event.getY() < mActualHeight;
}
@@ -339,6 +350,13 @@
outRect.top += getTranslationY() + getClipTopAmount();
}
+ @Override
+ public void getBoundsOnScreen(Rect outRect, boolean clipToParent) {
+ super.getBoundsOnScreen(outRect, clipToParent);
+ outRect.bottom = outRect.top + getActualHeight();
+ outRect.top += getClipTopOptimization();
+ }
+
public int getContentHeight() {
return mActualHeight - getBottomDecorHeight();
}
@@ -374,6 +392,14 @@
updateClipping();
}
+ public boolean willBeGone() {
+ return mWillBeGone;
+ }
+
+ public void setWillBeGone(boolean willBeGone) {
+ mWillBeGone = willBeGone;
+ }
+
/**
* A listener notifying when {@link #getActualHeight} changes.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowContainer.java
index 5fa7070..9653b67 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowContainer.java
@@ -18,6 +18,7 @@
import android.content.Context;
import android.util.AttributeSet;
+import android.view.View;
import android.widget.TextView;
import com.android.systemui.R;
@@ -32,6 +33,7 @@
private NotificationOverflowIconsView mIconsView;
private ViewInvertHelper mViewInvertHelper;
private boolean mDark;
+ private View mContent;
public NotificationOverflowContainer(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -43,7 +45,8 @@
mIconsView = (NotificationOverflowIconsView) findViewById(R.id.overflow_icons_view);
mIconsView.setMoreText((TextView) findViewById(R.id.more_text));
mIconsView.setOverflowIndicator(findViewById(R.id.more_icon_overflow));
- mViewInvertHelper = new ViewInvertHelper(findViewById(R.id.content),
+ mContent = findViewById(R.id.content);
+ mViewInvertHelper = new ViewInvertHelper(mContent,
NotificationPanelView.DOZE_ANIMATION_DURATION);
}
@@ -59,6 +62,11 @@
}
}
+ @Override
+ protected View getContentView() {
+ return mContent;
+ }
+
public NotificationOverflowIconsView getIconsView() {
return mIconsView;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
index 2f63c73..ff7b37f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
@@ -80,6 +80,7 @@
private float mDarkIntensity;
ViewGroup mEthernetGroup, mWifiGroup;
+ View mNoSimsCombo;
ImageView mVpn, mEthernet, mWifi, mAirplane, mNoSims, mEthernetDark, mWifiDark, mNoSimsDark;
View mWifiAirplaneSpacer;
View mWifiSignalSpacer;
@@ -162,6 +163,7 @@
mAirplane = (ImageView) findViewById(R.id.airplane);
mNoSims = (ImageView) findViewById(R.id.no_sims);
mNoSimsDark = (ImageView) findViewById(R.id.no_sims_dark);
+ mNoSimsCombo = findViewById(R.id.no_sims_combo);
mWifiAirplaneSpacer = findViewById(R.id.wifi_airplane_spacer);
mWifiSignalSpacer = findViewById(R.id.wifi_signal_spacer);
mMobileSignalGroup = (LinearLayout) findViewById(R.id.mobile_signal_group);
@@ -416,8 +418,7 @@
mWifiSignalSpacer.setVisibility(View.GONE);
}
- mNoSims.setVisibility(mNoSimsVisible ? View.VISIBLE : View.GONE);
- mNoSimsDark.setVisibility(mNoSimsVisible ? View.VISIBLE : View.GONE);
+ mNoSimsCombo.setVisibility(mNoSimsVisible ? View.VISIBLE : View.GONE);
boolean anythingVisible = mNoSimsVisible || mWifiVisible || mIsAirplaneMode
|| anyMobileVisible || mVpnVisible || mEthernetVisible;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StackScrollerDecorView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StackScrollerDecorView.java
index 64d80cc..2f66c41 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StackScrollerDecorView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StackScrollerDecorView.java
@@ -32,7 +32,6 @@
protected View mContent;
private boolean mIsVisible;
private boolean mAnimating;
- private boolean mWillBeGone;
public StackScrollerDecorView(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -134,13 +133,5 @@
mContent.animate().cancel();
}
- public boolean willBeGone() {
- return mWillBeGone;
- }
-
- public void setWillBeGone(boolean willBeGone) {
- mWillBeGone = willBeGone;
- }
-
protected abstract View findContentView();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index 636c511..f40f5016 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -47,7 +47,6 @@
import android.widget.LinearLayout;
import com.android.systemui.R;
-import com.android.systemui.statusbar.DelegateViewHelper;
import com.android.systemui.statusbar.policy.DeadZone;
import com.android.systemui.statusbar.policy.KeyButtonView;
@@ -79,7 +78,6 @@
private Drawable mRecentLandIcon;
private NavigationBarViewTaskSwitchHelper mTaskSwitchHelper;
- private DelegateViewHelper mDelegateHelper;
private DeadZone mDeadZone;
private final NavigationBarTransitions mBarTransitions;
@@ -92,7 +90,6 @@
private OnVerticalChangedListener mOnVerticalChangedListener;
private boolean mIsLayoutRtl;
- private boolean mDelegateIntercepted;
private class NavTransitionListener implements TransitionListener {
private boolean mBackTransitioning;
@@ -180,7 +177,6 @@
mBarSize = res.getDimensionPixelSize(R.dimen.navigation_bar_size);
mVertical = false;
mShowMenu = false;
- mDelegateHelper = new DelegateViewHelper(this);
mTaskSwitchHelper = new NavigationBarViewTaskSwitchHelper(context);
getIcons(res);
@@ -192,13 +188,8 @@
return mBarTransitions;
}
- public void setDelegateView(View view) {
- mDelegateHelper.setDelegateView(view);
- }
-
public void setBar(PhoneStatusBar phoneStatusBar) {
mTaskSwitchHelper.setBar(phoneStatusBar);
- mDelegateHelper.setBar(phoneStatusBar);
}
public void setOnVerticalChangedListener(OnVerticalChangedListener onVerticalChangedListener) {
@@ -208,44 +199,21 @@
@Override
public boolean onTouchEvent(MotionEvent event) {
- initDownStates(event);
- if (!mDelegateIntercepted && mTaskSwitchHelper.onTouchEvent(event)) {
+ if (mTaskSwitchHelper.onTouchEvent(event)) {
return true;
}
if (mDeadZone != null && event.getAction() == MotionEvent.ACTION_OUTSIDE) {
mDeadZone.poke(event);
}
- if (mDelegateHelper != null && mDelegateIntercepted) {
- boolean ret = mDelegateHelper.onInterceptTouchEvent(event);
- if (ret) return true;
- }
return super.onTouchEvent(event);
}
- private void initDownStates(MotionEvent ev) {
- if (ev.getAction() == MotionEvent.ACTION_DOWN) {
- mDelegateIntercepted = false;
- }
- }
-
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
- initDownStates(event);
- boolean intercept = mTaskSwitchHelper.onInterceptTouchEvent(event);
- if (!intercept) {
- mDelegateIntercepted = mDelegateHelper.onInterceptTouchEvent(event);
- intercept = mDelegateIntercepted;
- } else {
- MotionEvent cancelEvent = MotionEvent.obtain(event);
- cancelEvent.setAction(MotionEvent.ACTION_CANCEL);
- mDelegateHelper.onInterceptTouchEvent(cancelEvent);
- cancelEvent.recycle();
- }
- return intercept;
+ return mTaskSwitchHelper.onInterceptTouchEvent(event);
}
public void abortCurrentGesture() {
- mDelegateHelper.abortCurrentGesture();
getHomeButton().abortCurrentGesture();
}
@@ -461,10 +429,6 @@
Log.d(TAG, "reorient(): rot=" + mDisplay.getRotation());
}
- // swap to x coordinate if orientation is not in vertical
- if (mDelegateHelper != null) {
- mDelegateHelper.setSwapXY(mVertical);
- }
updateTaskSwitchHelper();
setNavigationIconHints(mNavigationIconHints, true);
@@ -476,12 +440,6 @@
}
@Override
- protected void onLayout(boolean changed, int l, int t, int r, int b) {
- super.onLayout(changed, l, t, r, b);
- mDelegateHelper.setInitialTouchRegion(getHomeButton(), getBackButton(), getRecentsButton());
- }
-
- @Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
if (DEBUG) Log.d(TAG, String.format(
"onSizeChanged: (%dx%d) old: (%dx%d)", w, h, oldw, oldh));
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 9e1af82..a750572 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -487,6 +487,7 @@
mStatusBar.dismissPopups();
mNotificationStackScroller.setOverScrollAmount(0f, true /* onTop */, false /* animate */,
true /* cancelAnimators */);
+ mNotificationStackScroller.resetScrollPosition();
}
public void closeQs() {
@@ -1716,12 +1717,16 @@
float alphaQsExpansion = 1 - Math.min(1, getQsExpansionFraction() * 2);
mKeyguardStatusBar.setAlpha(Math.min(getKeyguardContentsAlpha(), alphaQsExpansion)
* mKeyguardStatusBarAnimateAlpha);
+ mKeyguardStatusBar.setVisibility(mKeyguardStatusBar.getAlpha() != 0f ? VISIBLE : INVISIBLE);
setQsTranslation(mQsExpansionHeight);
}
private void updateKeyguardBottomAreaAlpha() {
- mKeyguardBottomArea.setAlpha(
- Math.min(getKeyguardContentsAlpha(), 1 - getQsExpansionFraction()));
+ float alpha = Math.min(getKeyguardContentsAlpha(), 1 - getQsExpansionFraction());
+ mKeyguardBottomArea.setAlpha(alpha);
+ mKeyguardBottomArea.setImportantForAccessibility(alpha == 0f
+ ? IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS
+ : IMPORTANT_FOR_ACCESSIBILITY_AUTO);
}
private float getNotificationsTopY() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java
index 54bd3e9..552a0b2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java
@@ -81,10 +81,13 @@
}
public void setBouncerShowing(boolean showing) {
+ int important = showing ? IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS
+ : IMPORTANT_FOR_ACCESSIBILITY_AUTO;
+
+ setImportantForAccessibility(important);
+
if (mPanelHolder != null) {
- mPanelHolder.setImportantForAccessibility(
- showing ? IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS
- : IMPORTANT_FOR_ACCESSIBILITY_AUTO);
+ mPanelHolder.setImportantForAccessibility(important);
}
}
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 a5b18f9..33e8e59 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -707,7 +707,7 @@
R.layout.status_bar_notification_keyguard_overflow, mStackScroller, false);
mKeyguardIconOverflowContainer.setOnActivatedListener(this);
mKeyguardIconOverflowContainer.setOnClickListener(mOverflowClickListener);
- mStackScroller.addView(mKeyguardIconOverflowContainer);
+ mStackScroller.setOverflowContainer(mKeyguardIconOverflowContainer);
SpeedBumpView speedBump = (SpeedBumpView) LayoutInflater.from(mContext).inflate(
R.layout.status_bar_notification_speed_bump, mStackScroller, false);
@@ -1861,6 +1861,9 @@
public void setQsExpanded(boolean expanded) {
mStatusBarWindowManager.setQsExpanded(expanded);
+ mKeyguardStatusView.setImportantForAccessibility(expanded
+ ? View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS
+ : View.IMPORTANT_FOR_ACCESSIBILITY_AUTO);
}
public boolean isGoingToNotificationShade() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
index 6a6266e..59e1bba 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -168,7 +168,8 @@
mHotspot.addCallback(mHotspotCallback);
// managed profile
- mService.setIcon(SLOT_MANAGED_PROFILE, R.drawable.stat_sys_managed_profile_status, 0, null);
+ mService.setIcon(SLOT_MANAGED_PROFILE, R.drawable.stat_sys_managed_profile_status, 0,
+ mContext.getString(R.string.accessibility_managed_profile));
mService.setIconVisibility(SLOT_MANAGED_PROFILE, false);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
index 58017d0..0d816dd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
@@ -119,8 +119,7 @@
private void applyFocusableFlag(State state) {
boolean panelFocusable = state.statusBarFocusable && state.panelExpanded;
- if (state.keyguardShowing && state.keyguardNeedsInput && state.bouncerShowing
- || BaseStatusBar.ENABLE_REMOTE_INPUT && panelFocusable) {
+ if (state.keyguardShowing && state.keyguardNeedsInput && state.bouncerShowing) {
mLpChanged.flags &= ~WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
mLpChanged.flags &= ~WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
} else if (state.isKeyguardShowingAndNotOccluded() || panelFocusable) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
index 7f1fea1..634270c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
@@ -83,6 +83,10 @@
insets.top = 0;
insets.right = 0;
} else {
+ if (mRightInset != 0) {
+ mRightInset = 0;
+ applyMargins();
+ }
boolean changed = getPaddingLeft() != 0
|| getPaddingRight() != 0
|| getPaddingTop() != 0
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
index 6e30803..98bbe7c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
@@ -552,6 +552,7 @@
}
public void updateEntry() {
+ mSortedEntries.remove(HeadsUpEntry.this);
long currentTime = mClock.currentTimeMillis();
earliestRemovaltime = currentTime + mMinimumDisplayTime;
postTime = Math.max(postTime, currentTime);
@@ -561,13 +562,13 @@
long removeDelay = Math.max(finishTime - currentTime, mMinimumDisplayTime);
mHandler.postDelayed(mRemoveHeadsUpRunnable, removeDelay);
}
- updateSortOrder(HeadsUpEntry.this);
+ mSortedEntries.add(HeadsUpEntry.this);
}
@Override
public int compareTo(HeadsUpEntry o) {
return postTime < o.postTime ? 1
- : postTime == o.postTime ? 0
+ : postTime == o.postTime ? entry.key.compareTo(o.entry.key)
: -1;
}
@@ -592,16 +593,6 @@
}
}
- /**
- * Update the sorted heads up order.
- *
- * @param headsUpEntry the headsUp that changed
- */
- private void updateSortOrder(HeadsUpEntry headsUpEntry) {
- mSortedEntries.remove(headsUpEntry);
- mSortedEntries.add(headsUpEntry);
- }
-
public static class Clock {
public long currentTimeMillis() {
return SystemClock.elapsedRealtime();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java
index 1460e5f..5cf6156 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java
@@ -30,7 +30,7 @@
import android.view.animation.AnimationUtils;
import android.widget.FrameLayout;
-import com.android.keyguard.AppearAnimationUtils;
+import com.android.settingslib.animation.AppearAnimationUtils;
import com.android.systemui.R;
import com.android.systemui.qs.tiles.UserDetailItemView;
import com.android.systemui.statusbar.phone.KeyguardStatusBarView;
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 d8f6bcd..1bf4547 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -43,6 +43,7 @@
import com.android.systemui.statusbar.ExpandableNotificationRow;
import com.android.systemui.statusbar.ExpandableView;
import com.android.systemui.statusbar.NotificationData;
+import com.android.systemui.statusbar.NotificationOverflowContainer;
import com.android.systemui.statusbar.SpeedBumpView;
import com.android.systemui.statusbar.StackScrollerDecorView;
import com.android.systemui.statusbar.StatusBarState;
@@ -226,6 +227,7 @@
private boolean mTrackingHeadsUp;
private ScrimController mScrimController;
private boolean mForceNoOverlappingRendering;
+ private NotificationOverflowContainer mOverflowContainer;
public NotificationStackScrollLayout(Context context) {
this(context, null);
@@ -1368,17 +1370,11 @@
int childCount = getChildCount();
int count = 0;
for (int i = 0; i < childCount; i++) {
- View child = getChildAt(i);
- if (child.getVisibility() != View.GONE) {
+ ExpandableView child = (ExpandableView) getChildAt(i);
+ if (child.getVisibility() != View.GONE && !child.willBeGone()) {
count++;
}
}
- if (mDismissView.willBeGone()) {
- count--;
- }
- if (mEmptyShadeView.willBeGone()) {
- count--;
- }
return count;
}
@@ -2234,6 +2230,11 @@
}
}
+ public void resetScrollPosition() {
+ mScroller.abortAnimation();
+ mOwnScrollY = 0;
+ }
+
private void setIsExpanded(boolean isExpanded) {
boolean changed = isExpanded != mIsExpanded;
mIsExpanded = isExpanded;
@@ -2291,6 +2292,10 @@
public void onChildAnimationFinished() {
requestChildrenUpdate();
+ runAnimationFinishedRunnables();
+ }
+
+ private void runAnimationFinishedRunnables() {
for (Runnable runnable : mAnimationFinishedRunnables) {
runnable.run();
}
@@ -2348,6 +2353,7 @@
if (mListener != null) {
mListener.onChildLocationsChanged(this);
}
+ runAnimationFinishedRunnables();
}
public void setSpeedBumpView(SpeedBumpView speedBumpView) {
@@ -2470,7 +2476,7 @@
mEmptyShadeView.setVisibility(newVisibility);
mEmptyShadeView.setWillBeGone(false);
updateContentHeight();
- notifyHeightChangeListener(mDismissView);
+ notifyHeightChangeListener(mEmptyShadeView);
} else {
Runnable onFinishedRunnable = new Runnable() {
@Override
@@ -2478,7 +2484,7 @@
mEmptyShadeView.setVisibility(GONE);
mEmptyShadeView.setWillBeGone(false);
updateContentHeight();
- notifyHeightChangeListener(mDismissView);
+ notifyHeightChangeListener(mEmptyShadeView);
}
};
if (mAnimationsEnabled) {
@@ -2492,6 +2498,45 @@
}
}
+ public void setOverflowContainer(NotificationOverflowContainer overFlowContainer) {
+ mOverflowContainer = overFlowContainer;
+ addView(mOverflowContainer);
+ }
+
+ public void updateOverflowContainerVisibility(boolean visible) {
+ int oldVisibility = mOverflowContainer.willBeGone() ? GONE
+ : mOverflowContainer.getVisibility();
+ final int newVisibility = visible ? VISIBLE : GONE;
+ if (oldVisibility != newVisibility) {
+ Runnable onFinishedRunnable = new Runnable() {
+ @Override
+ public void run() {
+ mOverflowContainer.setVisibility(newVisibility);
+ mOverflowContainer.setWillBeGone(false);
+ updateContentHeight();
+ notifyHeightChangeListener(mOverflowContainer);
+ }
+ };
+ if (!mAnimationsEnabled || !mIsExpanded) {
+ mOverflowContainer.cancelAppearDrawing();
+ onFinishedRunnable.run();
+ } else if (newVisibility != GONE) {
+ mOverflowContainer.performAddAnimation(0,
+ StackStateAnimator.ANIMATION_DURATION_STANDARD);
+ mOverflowContainer.setVisibility(newVisibility);
+ mOverflowContainer.setWillBeGone(false);
+ updateContentHeight();
+ notifyHeightChangeListener(mOverflowContainer);
+ } else {
+ mOverflowContainer.performRemoveAnimation(
+ StackStateAnimator.ANIMATION_DURATION_STANDARD,
+ 0.0f,
+ onFinishedRunnable);
+ mOverflowContainer.setWillBeGone(true);
+ }
+ }
+ }
+
public void updateDismissView(boolean visible) {
int oldVisibility = mDismissView.willBeGone() ? GONE : mDismissView.getVisibility();
int newVisibility = visible ? VISIBLE : GONE;
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 feae590..a70ad43 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java
@@ -210,7 +210,10 @@
int oldVisibility = view.getVisibility();
int newVisibility = becomesInvisible ? View.INVISIBLE : View.VISIBLE;
if (newVisibility != oldVisibility) {
- view.setVisibility(newVisibility);
+ if (!(view instanceof ExpandableView) || !((ExpandableView) view).willBeGone()) {
+ // We don't want views to change visibility when they are animating to GONE
+ view.setVisibility(newVisibility);
+ }
}
// apply yTranslation
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 c31244c..c995c8e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
@@ -285,6 +285,10 @@
boolean scaleChanging = child.getScaleX() != viewState.scale;
float childAlpha = child.getVisibility() == View.INVISIBLE ? 0.0f : child.getAlpha();
boolean alphaChanging = viewState.alpha != childAlpha;
+ if (child instanceof ExpandableView) {
+ // We don't want views to change visibility when they are animating to GONE
+ alphaChanging &= !((ExpandableView) child).willBeGone();
+ }
// start translationY animation
if (yTranslationChanging) {
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
index 29bea4d..aa891b6 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
@@ -17,6 +17,7 @@
package com.android.systemui.volume;
import static android.accessibilityservice.AccessibilityServiceInfo.FEEDBACK_ALL_MASK;
+import static android.accessibilityservice.AccessibilityServiceInfo.FEEDBACK_GENERIC;
import android.accessibilityservice.AccessibilityServiceInfo;
import android.animation.LayoutTransition;
@@ -422,17 +423,15 @@
protected void rescheduleTimeoutH() {
mHandler.removeMessages(H.DISMISS);
- int timeout = -1;
- if (!mAccessibility.mFeedbackEnabled) {
- timeout = computeTimeoutH();
- mHandler.sendMessageDelayed(mHandler
- .obtainMessage(H.DISMISS, Events.DISMISS_REASON_TIMEOUT, 0), timeout);
- }
+ final int timeout = computeTimeoutH();
+ mHandler.sendMessageDelayed(mHandler
+ .obtainMessage(H.DISMISS, Events.DISMISS_REASON_TIMEOUT, 0), timeout);
if (D.BUG) Log.d(TAG, "rescheduleTimeout " + timeout + " " + Debug.getCaller());
mController.userActivity();
}
private int computeTimeoutH() {
+ if (mAccessibility.mFeedbackEnabled) return 20000;
if (mSafetyWarning != null) return 5000;
if (mExpanded || mExpanding) return 5000;
if (mActiveStream == AudioManager.STREAM_MUSIC) return 1500;
@@ -524,6 +523,7 @@
}
}
Util.setVisOrInvis(row.settingsButton, false);
+ updateVolumeRowHeaderVisibleH(row);
row.header.setAlpha(mExpanded && isActive ? 1 : 0.5f);
updateVolumeRowSliderTintH(row, isActive);
}
@@ -606,25 +606,22 @@
}
// update header visible
- if (row.cachedShowHeaders != mShowHeaders) {
- row.cachedShowHeaders = mShowHeaders;
- Util.setVisOrGone(row.header, mShowHeaders);
- }
+ updateVolumeRowHeaderVisibleH(row);
// update header text
- final String text;
- if (isRingZenNone) {
- text = mContext.getString(R.string.volume_stream_muted_dnd, ss.name);
- } else if (isRingVibrate && isRingLimited) {
- text = mContext.getString(R.string.volume_stream_vibrate_dnd, ss.name);
- } else if (isRingVibrate) {
- text = mContext.getString(R.string.volume_stream_vibrate, ss.name);
- } else if (ss.muted || mAutomute && ss.level == 0) {
- text = mContext.getString(R.string.volume_stream_muted, ss.name);
- } else if (isRingLimited) {
- text = mContext.getString(R.string.volume_stream_limited_dnd, ss.name);
- } else {
- text = ss.name;
+ String text = ss.name;
+ if (mShowHeaders) {
+ if (isRingZenNone) {
+ text = mContext.getString(R.string.volume_stream_muted_dnd, ss.name);
+ } else if (isRingVibrate && isRingLimited) {
+ text = mContext.getString(R.string.volume_stream_vibrate_dnd, ss.name);
+ } else if (isRingVibrate) {
+ text = mContext.getString(R.string.volume_stream_vibrate, ss.name);
+ } else if (ss.muted || mAutomute && ss.level == 0) {
+ text = mContext.getString(R.string.volume_stream_muted, ss.name);
+ } else if (isRingLimited) {
+ text = mContext.getString(R.string.volume_stream_limited_dnd, ss.name);
+ }
}
Util.setText(row.header, text);
@@ -663,6 +660,15 @@
updateVolumeRowSliderH(row, enableSlider, vlevel);
}
+ private void updateVolumeRowHeaderVisibleH(VolumeRow row) {
+ final boolean dynamic = row.ss != null && row.ss.dynamic;
+ final boolean showHeaders = mShowHeaders || mExpanded && dynamic;
+ if (row.cachedShowHeaders != showHeaders) {
+ row.cachedShowHeaders = showHeaders;
+ Util.setVisOrGone(row.header, showHeaders);
+ }
+ }
+
private void updateVolumeRowSliderTintH(VolumeRow row, boolean isActive) {
final ColorStateList tint = isActive && row.slider.isEnabled() ? mActiveSliderTint
: mInactiveSliderTint;
@@ -952,7 +958,7 @@
}
}
- private final class Accessibility {
+ private final class Accessibility extends AccessibilityDelegate {
private AccessibilityManager mMgr;
private boolean mFeedbackEnabled;
@@ -969,14 +975,7 @@
updateFeedbackEnabled();
}
});
- mDialogView.setAccessibilityDelegate(new AccessibilityDelegate() {
- @Override
- public boolean onRequestSendAccessibilityEvent(ViewGroup host, View child,
- AccessibilityEvent event) {
- rescheduleTimeoutH();
- return super.onRequestSendAccessibilityEvent(host, child, event);
- }
- });
+ mDialogView.setAccessibilityDelegate(this);
mMgr.addAccessibilityStateChangeListener(new AccessibilityStateChangeListener() {
@Override
public void onAccessibilityStateChanged(boolean enabled) {
@@ -986,15 +985,23 @@
updateFeedbackEnabled();
}
+ @Override
+ public boolean onRequestSendAccessibilityEvent(ViewGroup host, View child,
+ AccessibilityEvent event) {
+ rescheduleTimeoutH();
+ return super.onRequestSendAccessibilityEvent(host, child, event);
+ }
+
private void updateFeedbackEnabled() {
mFeedbackEnabled = computeFeedbackEnabled();
}
private boolean computeFeedbackEnabled() {
+ // are there any enabled non-generic a11y services?
final List<AccessibilityServiceInfo> services =
mMgr.getEnabledAccessibilityServiceList(FEEDBACK_ALL_MASK);
for (AccessibilityServiceInfo asi : services) {
- if ((asi.feedbackType & FEEDBACK_ALL_MASK) != 0) {
+ if (asi.feedbackType != 0 && asi.feedbackType != FEEDBACK_GENERIC) {
return true;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
index ced1a3c..a0eb61f 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
@@ -153,7 +153,7 @@
mZenButtons = (SegmentedButtons) findViewById(R.id.zen_buttons);
mZenButtons.addButton(R.string.interruption_level_none_twoline,
- R.string.interruption_level_none,
+ R.string.interruption_level_none_with_warning,
Global.ZEN_MODE_NO_INTERRUPTIONS);
mZenButtons.addButton(R.string.interruption_level_alarms_twoline,
R.string.interruption_level_alarms,
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index 66fd36f..fbb6dc9 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -21,8 +21,8 @@
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.IBluetooth;
-import android.bluetooth.IBluetoothGatt;
import android.bluetooth.IBluetoothCallback;
+import android.bluetooth.IBluetoothGatt;
import android.bluetooth.IBluetoothHeadset;
import android.bluetooth.IBluetoothManager;
import android.bluetooth.IBluetoothManagerCallback;
@@ -37,6 +37,7 @@
import android.content.ServiceConnection;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
+import android.database.ContentObserver;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
@@ -56,11 +57,8 @@
import java.io.FileDescriptor;
import java.io.IOException;
import java.io.PrintWriter;
-
import java.util.HashMap;
import java.util.Map;
-
-import java.util.*;
class BluetoothManagerService extends IBluetoothManager.Stub {
private static final String TAG = "BluetoothManagerService";
private static final boolean DBG = true;
@@ -259,6 +257,8 @@
mName = null;
mErrorRecoveryRetryCounter = 0;
mContentResolver = context.getContentResolver();
+ // Observe BLE scan only mode settings change.
+ registerForBleScanModeChange();
mCallbacks = new RemoteCallbackList<IBluetoothManagerCallback>();
mStateChangeCallbacks = new RemoteCallbackList<IBluetoothStateChangeCallback>();
IntentFilter filter = new IntentFilter(Intent.ACTION_BOOT_COMPLETED);
@@ -458,6 +458,40 @@
return false;
}
+ // Monitor change of BLE scan only mode settings.
+ private void registerForBleScanModeChange() {
+ ContentObserver contentObserver = new ContentObserver(null) {
+ @Override
+ public void onChange(boolean selfChange) {
+ if (!isBleScanAlwaysAvailable()) {
+ disableBleScanMode();
+ clearBleApps();
+ try {
+ if (mBluetooth != null) mBluetooth.onBrEdrDown();
+ } catch (RemoteException e) {
+ Log.e(TAG, "error when disabling bluetooth", e);
+ }
+ }
+ }
+ };
+
+ mContentResolver.registerContentObserver(
+ Settings.Global.getUriFor(Settings.Global.BLE_SCAN_ALWAYS_AVAILABLE),
+ false, contentObserver);
+ }
+
+ // Disable ble scan only mode.
+ private void disableBleScanMode() {
+ try {
+ if (mBluetooth != null && (mBluetooth.getState() != BluetoothAdapter.STATE_ON)) {
+ if (DBG) Log.d(TAG, "Reseting the mEnable flag for clean disable");
+ mEnable = false;
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "getState()", e);
+ }
+ }
+
public int updateBleAppCount(IBinder token, boolean enable) {
if (enable) {
ClientDeathRecipient r = mBleApps.get(token);
@@ -478,11 +512,8 @@
} else {
ClientDeathRecipient r = mBleApps.get(token);
if (r != null) {
- try {
- token.linkToDeath(r, 0);
- } catch (RemoteException ex) {
- throw new IllegalArgumentException("Wake lock is already dead.");
- }
+ // Unregister death recipient as the app goes away.
+ token.unlinkToDeath(r, 0);
mBleApps.remove(token);
synchronized (this) {
if (mBleAppCount > 0) --mBleAppCount;
@@ -492,18 +523,19 @@
}
if (DBG) Log.d(TAG, "Updated BleAppCount" + mBleAppCount);
if (mBleAppCount == 0 && mEnable) {
- try {
- if (mBluetooth != null && (mBluetooth.getState() != BluetoothAdapter.STATE_ON)) {
- if (DBG) Log.d(TAG, "Reseting the mEnable flag for clean disable");
- mEnable = false;
- }
- } catch (RemoteException e) {
- Log.e(TAG, "getState()", e);
- }
+ disableBleScanMode();
}
return mBleAppCount;
}
+ // Clear all apps using BLE scan only mode.
+ private void clearBleApps() {
+ synchronized (this) {
+ mBleApps.clear();
+ mBleAppCount = 0;
+ }
+ }
+
/** @hide*/
public boolean isBleAppPresent() {
if (DBG) Log.d(TAG, "isBleAppPresent() count: " + mBleAppCount);
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 2f68aa8..9c6e16f 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -100,6 +100,7 @@
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.IBatteryStats;
import com.android.internal.net.LegacyVpnInfo;
import com.android.internal.net.NetworkStatsFactory;
@@ -768,7 +769,8 @@
return mNextNetworkRequestId++;
}
- private int reserveNetId() {
+ @VisibleForTesting
+ protected int reserveNetId() {
synchronized (mNetworkForNetId) {
for (int i = MIN_NET_ID; i <= MAX_NET_ID; i++) {
int netId = mNextNetId;
@@ -1665,6 +1667,7 @@
private static final String DEFAULT_TCP_RWND_KEY = "net.tcp.default_init_rwnd";
// Overridden for testing purposes to avoid writing to SystemProperties.
+ @VisibleForTesting
protected int getDefaultTcpRwnd() {
return SystemProperties.getInt(DEFAULT_TCP_RWND_KEY, 0);
}
diff --git a/services/core/java/com/android/server/DeviceIdleController.java b/services/core/java/com/android/server/DeviceIdleController.java
index 4c7b523..ad34b37 100644
--- a/services/core/java/com/android/server/DeviceIdleController.java
+++ b/services/core/java/com/android/server/DeviceIdleController.java
@@ -22,6 +22,7 @@
import android.app.AppGlobals;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
@@ -29,12 +30,14 @@
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
+import android.database.ContentObserver;
import android.hardware.Sensor;
import android.hardware.SensorManager;
import android.hardware.TriggerEvent;
import android.hardware.TriggerEventListener;
import android.hardware.display.DisplayManager;
import android.net.INetworkPolicyManager;
+import android.net.Uri;
import android.os.Binder;
import android.os.Environment;
import android.os.FileUtils;
@@ -48,11 +51,11 @@
import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.UserHandle;
+import android.provider.Settings;
import android.util.ArrayMap;
import android.util.ArraySet;
-import android.util.Log;
+import android.util.KeyValueListParser;
import android.util.Slog;
-import android.util.SparseArray;
import android.util.SparseBooleanArray;
import android.util.SparseLongArray;
import android.util.TimeUtils;
@@ -62,7 +65,6 @@
import com.android.internal.app.IBatteryStats;
import com.android.internal.os.AtomicFile;
import com.android.internal.os.BackgroundThread;
-import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.XmlUtils;
import com.android.server.am.BatteryStatsService;
@@ -103,84 +105,7 @@
// TODO: These need to be moved to system settings.
- /**
- * This is the time, after becoming inactive, at which we start looking at the
- * motion sensor to determine if the device is being left alone. We don't do this
- * immediately after going inactive just because we don't want to be continually running
- * the significant motion sensor whenever the screen is off.
- */
- private static final long DEFAULT_INACTIVE_TIMEOUT = !COMPRESS_TIME ? 30*60*1000L
- : 3 * 60 * 1000L;
-
- /**
- * If we don't receive a callback from AnyMotion in this amount of time, we will change from
- * STATE_SENSING to STATE_INACTIVE, and any AnyMotion callbacks while not in STATE_SENSING will
- * be ignored.
- */
- private static final long DEFAULT_SENSING_TIMEOUT = !DEBUG ? 5 * 60 * 1000L : 60 * 1000L;
-
- /**
- * This is the time, after seeing motion, that we wait after becoming inactive from
- * that until we start looking for motion again.
- */
- private static final long DEFAULT_MOTION_INACTIVE_TIMEOUT = !COMPRESS_TIME ? 10*60*1000L
- : 60 * 1000L;
-
- /**
- * This is the time, after the inactive timeout elapses, that we will wait looking
- * for significant motion until we truly consider the device to be idle.
- */
-
- private static final long DEFAULT_IDLE_AFTER_INACTIVE_TIMEOUT = !COMPRESS_TIME ? 30*60*1000L
- : 3 * 60 * 1000L;
-
- /**
- * This is the initial time, after being idle, that we will allow ourself to be back
- * in the IDLE_PENDING state allowing the system to run normally until we return to idle.
- */
-
- private static final long DEFAULT_IDLE_PENDING_TIMEOUT = !COMPRESS_TIME ? 5*60*1000L
- : 30 * 1000L;
-
- /**
- * Maximum pending idle timeout (time spent running) we will be allowed to use.
- */
- private static final long DEFAULT_MAX_IDLE_PENDING_TIMEOUT = !COMPRESS_TIME ? 10*60*1000L
- : 60 * 1000L;
- /**
- * Scaling factor to apply to current pending idle timeout each time we cycle through
- * that state.
- */
- private static final float DEFAULT_IDLE_PENDING_FACTOR = 2f;
- /**
- * This is the initial time that we want to sit in the idle state before waking up
- * again to return to pending idle and allowing normal work to run.
- */
-
- private static final long DEFAULT_IDLE_TIMEOUT = !COMPRESS_TIME ? 60*60*1000L
- : 6 * 60 * 1000L;
-
- /**
- * Maximum idle duration we will be allowed to use.
- */
- private static final long DEFAULT_MAX_IDLE_TIMEOUT = !COMPRESS_TIME ? 6*60*60*1000L
- : 30 * 60 * 1000L;
- /**
- * Scaling factor to apply to current idle timeout each time we cycle through that state.
- */
- private static final float DEFAULT_IDLE_FACTOR = 2f;
- /**
- * This is the minimum time we will allow until the next upcoming alarm for us to
- * actually go in to idle mode.
- */
- private static final long DEFAULT_MIN_TIME_TO_ALARM = !COMPRESS_TIME ? 60*60*1000L
- : 6 * 60 * 1000L;
-
- /**
- * Max amount of time to temporarily whitelist an app when it receives a high priority tickle.
- */
- private static final long MAX_TEMP_APP_WHITELIST_DURATION = 5 * 60 * 1000L;
private AlarmManager mAlarmManager;
private IBatteryStats mBatteryStats;
@@ -306,6 +231,230 @@
}
};
+ /**
+ * All times are in milliseconds. These constants are kept synchronized with the system
+ * global Settings. Any access to this class or its fields should be done while
+ * holding the DeviceIdleController lock.
+ */
+ private class Constants extends ContentObserver {
+ // Key names stored in the settings value.
+ private static final String KEY_INACTIVE_TIMEOUT = "inactive_to";
+ private static final String KEY_SENSING_TIMEOUT = "sensing_to";
+ private static final String KEY_MOTION_INACTIVE_TIMEOUT = "motion_inactive_to";
+ private static final String KEY_IDLE_AFTER_INACTIVE_TIMEOUT = "idle_after_inactive_to";
+ private static final String KEY_IDLE_PENDING_TIMEOUT = "idle_pending_to";
+ private static final String KEY_MAX_IDLE_PENDING_TIMEOUT = "max_idle_pending_to";
+ private static final String KEY_IDLE_PENDING_FACTOR = "idle_pending_factor";
+ private static final String KEY_IDLE_TIMEOUT = "idle_to";
+ private static final String KEY_MAX_IDLE_TIMEOUT = "max_idle_to";
+ private static final String KEY_IDLE_FACTOR = "idle_factor";
+ private static final String KEY_MIN_TIME_TO_ALARM = "min_time_to_alarm";
+ private static final String KEY_MAX_TEMP_APP_WHITELIST_DURATION =
+ "max_temp_app_whitelist_duration";
+
+ /**
+ * This is the time, after becoming inactive, at which we start looking at the
+ * motion sensor to determine if the device is being left alone. We don't do this
+ * immediately after going inactive just because we don't want to be continually running
+ * the significant motion sensor whenever the screen is off.
+ * @see Settings.Global#DEVICE_IDLE_CONSTANTS
+ * @see #KEY_INACTIVE_TIMEOUT
+ */
+ public long INACTIVE_TIMEOUT;
+
+ /**
+ * If we don't receive a callback from AnyMotion in this amount of time, we will change from
+ * STATE_SENSING to STATE_INACTIVE, and any AnyMotion callbacks while not in STATE_SENSING
+ * will be ignored.
+ * @see Settings.Global#DEVICE_IDLE_CONSTANTS
+ * @see #KEY_SENSING_TIMEOUT
+ */
+ public long SENSING_TIMEOUT;
+
+ /**
+ * This is the time, after seeing motion, that we wait after becoming inactive from
+ * that until we start looking for motion again.
+ * @see Settings.Global#DEVICE_IDLE_CONSTANTS
+ * @see #KEY_MOTION_INACTIVE_TIMEOUT
+ */
+ public long MOTION_INACTIVE_TIMEOUT;
+
+ /**
+ * This is the time, after the inactive timeout elapses, that we will wait looking
+ * for significant motion until we truly consider the device to be idle.
+ * @see Settings.Global#DEVICE_IDLE_CONSTANTS
+ * @see #KEY_IDLE_AFTER_INACTIVE_TIMEOUT
+ */
+ public long IDLE_AFTER_INACTIVE_TIMEOUT;
+
+ /**
+ * This is the initial time, after being idle, that we will allow ourself to be back
+ * in the IDLE_PENDING state allowing the system to run normally until we return to idle.
+ * @see Settings.Global#DEVICE_IDLE_CONSTANTS
+ * @see #KEY_IDLE_PENDING_TIMEOUT
+ */
+ public long IDLE_PENDING_TIMEOUT;
+
+ /**
+ * Maximum pending idle timeout (time spent running) we will be allowed to use.
+ * @see Settings.Global#DEVICE_IDLE_CONSTANTS
+ * @see #KEY_MAX_IDLE_PENDING_TIMEOUT
+ */
+ public long MAX_IDLE_PENDING_TIMEOUT;
+
+ /**
+ * Scaling factor to apply to current pending idle timeout each time we cycle through
+ * that state.
+ * @see Settings.Global#DEVICE_IDLE_CONSTANTS
+ * @see #KEY_IDLE_PENDING_FACTOR
+ */
+ public float IDLE_PENDING_FACTOR;
+
+ /**
+ * This is the initial time that we want to sit in the idle state before waking up
+ * again to return to pending idle and allowing normal work to run.
+ * @see Settings.Global#DEVICE_IDLE_CONSTANTS
+ * @see #KEY_IDLE_TIMEOUT
+ */
+ public long IDLE_TIMEOUT;
+
+ /**
+ * Maximum idle duration we will be allowed to use.
+ * @see Settings.Global#DEVICE_IDLE_CONSTANTS
+ * @see #KEY_MAX_IDLE_TIMEOUT
+ */
+ public long MAX_IDLE_TIMEOUT;
+
+ /**
+ * Scaling factor to apply to current idle timeout each time we cycle through that state.
+ * @see Settings.Global#DEVICE_IDLE_CONSTANTS
+ * @see #KEY_IDLE_FACTOR
+ */
+ public float IDLE_FACTOR;
+
+ /**
+ * This is the minimum time we will allow until the next upcoming alarm for us to
+ * actually go in to idle mode.
+ * @see Settings.Global#DEVICE_IDLE_CONSTANTS
+ * @see #KEY_MIN_TIME_TO_ALARM
+ */
+ public long MIN_TIME_TO_ALARM;
+
+ /**
+ * Max amount of time to temporarily whitelist an app when it receives a high priority
+ * tickle.
+ * @see Settings.Global#DEVICE_IDLE_CONSTANTS
+ * @see #KEY_MAX_TEMP_APP_WHITELIST_DURATION
+ */
+ public long MAX_TEMP_APP_WHITELIST_DURATION;
+
+ private final ContentResolver mResolver;
+ private final KeyValueListParser mParser = new KeyValueListParser(',');
+
+ public Constants(Handler handler, ContentResolver resolver) {
+ super(handler);
+ mResolver = resolver;
+ mResolver.registerContentObserver(
+ Settings.Global.getUriFor(Settings.Global.DEVICE_IDLE_CONSTANTS), false, this);
+ updateConstants();
+ }
+
+ @Override
+ public void onChange(boolean selfChange, Uri uri) {
+ updateConstants();
+ }
+
+ private void updateConstants() {
+ synchronized (DeviceIdleController.this) {
+ try {
+ mParser.setString(Settings.Global.getString(mResolver,
+ Settings.Global.DEVICE_IDLE_CONSTANTS));
+ } catch (IllegalArgumentException e) {
+ // Failed to parse the settings string, log this and move on
+ // with defaults.
+ Slog.e(TAG, "Bad device idle settings", e);
+ }
+
+ INACTIVE_TIMEOUT = mParser.getLong(KEY_INACTIVE_TIMEOUT,
+ !COMPRESS_TIME ? 30 * 60 * 1000L : 3 * 60 * 1000L);
+ SENSING_TIMEOUT = mParser.getLong(KEY_SENSING_TIMEOUT,
+ !DEBUG ? 5 * 60 * 1000L : 60 * 1000L);
+ MOTION_INACTIVE_TIMEOUT = mParser.getLong(KEY_MOTION_INACTIVE_TIMEOUT,
+ !COMPRESS_TIME ? 10 * 60 * 1000L : 60 * 1000L);
+ IDLE_AFTER_INACTIVE_TIMEOUT = mParser.getLong(KEY_IDLE_AFTER_INACTIVE_TIMEOUT,
+ !COMPRESS_TIME ? 30 * 60 * 1000L : 3 * 60 * 1000L);
+ IDLE_PENDING_TIMEOUT = mParser.getLong(KEY_IDLE_PENDING_TIMEOUT,
+ !COMPRESS_TIME ? 5 * 60 * 1000L : 30 * 1000L);
+ MAX_IDLE_PENDING_TIMEOUT = mParser.getLong(KEY_MAX_IDLE_PENDING_TIMEOUT,
+ !COMPRESS_TIME ? 10 * 60 * 1000L : 60 * 1000L);
+ IDLE_PENDING_FACTOR = mParser.getFloat(KEY_IDLE_PENDING_FACTOR,
+ 2f);
+ IDLE_TIMEOUT = mParser.getLong(KEY_IDLE_TIMEOUT,
+ !COMPRESS_TIME ? 60 * 60 * 1000L : 6 * 60 * 1000L);
+ MAX_IDLE_TIMEOUT = mParser.getLong(KEY_MAX_IDLE_TIMEOUT,
+ !COMPRESS_TIME ? 6 * 60 * 60 * 1000L : 30 * 60 * 1000L);
+ IDLE_FACTOR = mParser.getFloat(KEY_IDLE_FACTOR,
+ 2f);
+ MIN_TIME_TO_ALARM = mParser.getLong(KEY_MIN_TIME_TO_ALARM,
+ !COMPRESS_TIME ? 60 * 60 * 1000L : 6 * 60 * 1000L);
+ MAX_TEMP_APP_WHITELIST_DURATION = mParser.getLong(KEY_MAX_TEMP_APP_WHITELIST_DURATION,
+ 5 * 60 * 1000L);
+ }
+ }
+
+ void dump(PrintWriter pw) {
+ pw.println(" Settings:");
+
+ pw.print(" DOZE_INACTIVE_TIMEOUT=");
+ TimeUtils.formatDuration(INACTIVE_TIMEOUT, pw);
+ pw.println();
+
+ pw.print(" DOZE_SENSING_TIMEOUT=");
+ TimeUtils.formatDuration(SENSING_TIMEOUT, pw);
+ pw.println();
+
+ pw.print(" DOZE_MOTION_INACTIVE_TIMEOUT=");
+ TimeUtils.formatDuration(MOTION_INACTIVE_TIMEOUT, pw);
+ pw.println();
+
+ pw.print(" DOZE_IDLE_AFTER_INACTIVE_TIMEOUT=");
+ TimeUtils.formatDuration(IDLE_AFTER_INACTIVE_TIMEOUT, pw);
+ pw.println();
+
+ pw.print(" DOZE_IDLE_PENDING_TIMEOUT=");
+ TimeUtils.formatDuration(IDLE_PENDING_TIMEOUT, pw);
+ pw.println();
+
+ pw.print(" DOZE_MAX_IDLE_PENDING_TIMEOUT=");
+ TimeUtils.formatDuration(MAX_IDLE_PENDING_TIMEOUT, pw);
+ pw.println();
+
+ pw.print(" DOZE_IDLE_PENDING_FACTOR=");
+ pw.println(IDLE_PENDING_FACTOR);
+
+ pw.print(" DOZE_IDLE_TIMEOUT=");
+ TimeUtils.formatDuration(IDLE_TIMEOUT, pw);
+ pw.println();
+
+ pw.print(" DOZE_MAX_IDLE_TIMEOUT=");
+ TimeUtils.formatDuration(MAX_IDLE_TIMEOUT, pw);
+ pw.println();
+
+ pw.print(" DOZE_IDLE_FACTOR=");
+ pw.println(IDLE_FACTOR);
+
+ pw.print(" DOZE_MIN_TIME_TO_ALARM=");
+ TimeUtils.formatDuration(MIN_TIME_TO_ALARM, pw);
+ pw.println();
+
+ pw.print(" DOZE_MAX_TEMP_APP_WHITELIST_DURATION=");
+ TimeUtils.formatDuration(MAX_TEMP_APP_WHITELIST_DURATION, pw);
+ pw.println();
+ }
+ }
+
+ private Constants mConstants;
+
@Override
public void onAnyMotionResult(int result) {
if (DEBUG) Slog.d(TAG, "onAnyMotionResult(" + result + ")");
@@ -474,6 +623,8 @@
}
}
+ mConstants = new Constants(mHandler, getContext().getContentResolver());
+
readConfigFileLocked();
updateWhitelistAppIdsLocked();
@@ -482,7 +633,7 @@
// a battery update the next time the level drops.
mCharging = true;
mState = STATE_ACTIVE;
- mInactiveTimeout = DEFAULT_INACTIVE_TIMEOUT;
+ mInactiveTimeout = mConstants.INACTIVE_TIMEOUT;
}
publishBinderService(SERVICE_NAME, new BinderService());
@@ -613,14 +764,12 @@
*/
public void addPowerSaveTempWhitelistAppInternal(String packageName, long duration,
int userId) {
- if (duration > MAX_TEMP_APP_WHITELIST_DURATION) {
- duration = MAX_TEMP_APP_WHITELIST_DURATION;
- }
try {
int uid = getContext().getPackageManager().getPackageUid(packageName, userId);
int appId = UserHandle.getAppId(uid);
final long timeNow = System.currentTimeMillis();
synchronized (this) {
+ duration = Math.min(duration, mConstants.MAX_TEMP_APP_WHITELIST_DURATION);
long currentEndTime = mTempWhitelistAppIdEndTimes.get(appId);
// Set the new end time
mTempWhitelistAppIdEndTimes.put(appId, timeNow + duration);
@@ -704,7 +853,7 @@
EventLogTags.writeDeviceIdle(STATE_ACTIVE, reason);
scheduleReportActiveLocked(false);
mState = STATE_ACTIVE;
- mInactiveTimeout = DEFAULT_INACTIVE_TIMEOUT;
+ mInactiveTimeout = mConstants.INACTIVE_TIMEOUT;
mNextIdlePendingDelay = 0;
mNextIdleDelay = 0;
cancelAlarmLocked();
@@ -731,7 +880,7 @@
* within the DEFAULT_SENSING_TIMEOUT, to return to STATE_INACTIVE.
*/
void enterInactiveStateLocked() {
- mInactiveTimeout = DEFAULT_INACTIVE_TIMEOUT;
+ mInactiveTimeout = mConstants.INACTIVE_TIMEOUT;
becomeInactiveIfAppropriateLocked();
}
@@ -740,7 +889,7 @@
EventLogTags.writeDeviceIdleStep();
final long now = SystemClock.elapsedRealtime();
- if ((now+DEFAULT_MIN_TIME_TO_ALARM) > mAlarmManager.getNextWakeFromIdleTime()) {
+ if ((now+mConstants.MIN_TIME_TO_ALARM) > mAlarmManager.getNextWakeFromIdleTime()) {
// Whoops, there is an upcoming alarm. We don't actually want to go idle.
if (mState != STATE_ACTIVE) {
becomeActiveLocked("alarm");
@@ -753,10 +902,10 @@
// We have now been inactive long enough, it is time to start looking
// for significant motion and sleep some more while doing so.
startMonitoringSignificantMotion();
- scheduleAlarmLocked(DEFAULT_IDLE_AFTER_INACTIVE_TIMEOUT, false);
+ scheduleAlarmLocked(mConstants.IDLE_AFTER_INACTIVE_TIMEOUT, false);
// Reset the upcoming idle delays.
- mNextIdlePendingDelay = DEFAULT_IDLE_PENDING_TIMEOUT;
- mNextIdleDelay = DEFAULT_IDLE_TIMEOUT;
+ mNextIdlePendingDelay = mConstants.IDLE_PENDING_TIMEOUT;
+ mNextIdleDelay = mConstants.IDLE_TIMEOUT;
mState = STATE_IDLE_PENDING;
if (DEBUG) Slog.d(TAG, "Moved from STATE_INACTIVE to STATE_IDLE_PENDING.");
EventLogTags.writeDeviceIdle(mState, "step");
@@ -764,7 +913,7 @@
case STATE_IDLE_PENDING:
mState = STATE_SENSING;
if (DEBUG) Slog.d(TAG, "Moved from STATE_IDLE_PENDING to STATE_SENSING.");
- scheduleSensingAlarmLocked(DEFAULT_SENSING_TIMEOUT);
+ scheduleSensingAlarmLocked(mConstants.SENSING_TIMEOUT);
mAnyMotionDetector.checkForAnyMotion();
break;
case STATE_SENSING:
@@ -773,11 +922,9 @@
scheduleAlarmLocked(mNextIdleDelay, true);
if (DEBUG) Slog.d(TAG, "Moved to STATE_IDLE. Next alarm in " + mNextIdleDelay +
" ms.");
- mNextIdleDelay = (long)(mNextIdleDelay * DEFAULT_IDLE_FACTOR);
+ mNextIdleDelay = (long)(mNextIdleDelay * mConstants.IDLE_FACTOR);
if (DEBUG) Slog.d(TAG, "Setting mNextIdleDelay = " + mNextIdleDelay);
- if (mNextIdleDelay > DEFAULT_MAX_IDLE_TIMEOUT) {
- mNextIdleDelay = DEFAULT_MAX_IDLE_TIMEOUT;
- }
+ mNextIdleDelay = Math.min(mNextIdleDelay, mConstants.MAX_IDLE_TIMEOUT);
mState = STATE_IDLE;
mHandler.sendEmptyMessage(MSG_REPORT_IDLE_ON);
break;
@@ -786,10 +933,8 @@
scheduleAlarmLocked(mNextIdlePendingDelay, false);
if (DEBUG) Slog.d(TAG, "Moved from STATE_IDLE to STATE_IDLE_MAINTENANCE. " +
"Next alarm in " + mNextIdlePendingDelay + " ms.");
- mNextIdlePendingDelay = (long)(mNextIdlePendingDelay*DEFAULT_IDLE_PENDING_FACTOR);
- if (mNextIdlePendingDelay > DEFAULT_MAX_IDLE_PENDING_TIMEOUT) {
- mNextIdlePendingDelay = DEFAULT_MAX_IDLE_PENDING_TIMEOUT;
- }
+ mNextIdlePendingDelay = Math.min(mConstants.MAX_IDLE_PENDING_TIMEOUT,
+ (long)(mNextIdlePendingDelay * mConstants.IDLE_PENDING_FACTOR));
mState = STATE_IDLE_MAINTENANCE;
EventLogTags.writeDeviceIdle(mState, "step");
mHandler.sendEmptyMessage(MSG_REPORT_IDLE_OFF);
@@ -807,7 +952,7 @@
if (mState != STATE_ACTIVE) {
scheduleReportActiveLocked(true);
mState = STATE_ACTIVE;
- mInactiveTimeout = DEFAULT_MOTION_INACTIVE_TIMEOUT;
+ mInactiveTimeout = mConstants.MOTION_INACTIVE_TIMEOUT;
EventLogTags.writeDeviceIdle(mState, "motion");
becomeInactiveIfAppropriateLocked();
}
@@ -1179,6 +1324,9 @@
pw.println();
}
}
+
+ mConstants.dump(pw);
+
pw.print(" mSigMotionSensor="); pw.println(mSigMotionSensor);
pw.print(" mCurDisplay="); pw.println(mCurDisplay);
pw.print(" mIdleDisabled="); pw.println(mIdleDisabled);
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index 21f96c9..49d9988 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -87,11 +87,8 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.lang.ref.WeakReference;
-import java.nio.ByteBuffer;
-import java.nio.charset.Charset;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
-import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
@@ -100,7 +97,6 @@
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
-import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
@@ -526,14 +522,20 @@
@Override
public String getPassword(Account account) {
+ int callingUid = Binder.getCallingUid();
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "getPassword: " + account
+ ", caller's uid " + Binder.getCallingUid()
+ ", pid " + Binder.getCallingPid());
}
if (account == null) throw new IllegalArgumentException("account is null");
- checkAuthenticateAccountsPermission(account);
-
+ if (!isAccountOwnedByCallingUid(account.type, callingUid)) {
+ String msg = String.format(
+ "uid %s cannot get secrets for accounts of type: %s",
+ callingUid,
+ account.type);
+ throw new SecurityException(msg);
+ }
UserAccounts accounts = getUserAccountsForCaller();
long identityToken = clearCallingIdentity();
try {
@@ -617,15 +619,21 @@
@Override
public String getUserData(Account account, String key) {
+ final int callingUid = Binder.getCallingUid();
if (Log.isLoggable(TAG, Log.VERBOSE)) {
- Log.v(TAG, "getUserData: " + account
- + ", key " + key
- + ", caller's uid " + Binder.getCallingUid()
- + ", pid " + Binder.getCallingPid());
+ String msg = String.format("getUserData( account: %s, key: %s, callerUid: %s, pid: %s",
+ account, key, callingUid, Binder.getCallingPid());
+ Log.v(TAG, msg);
}
if (account == null) throw new IllegalArgumentException("account is null");
if (key == null) throw new IllegalArgumentException("key is null");
- checkAuthenticateAccountsPermission(account);
+ if (!isAccountOwnedByCallingUid(account.type, callingUid)) {
+ String msg = String.format(
+ "uid %s cannot get user data for accounts of type: %s",
+ callingUid,
+ account.type);
+ throw new SecurityException(msg);
+ }
UserAccounts accounts = getUserAccountsForCaller();
long identityToken = clearCallingIdentity();
try {
@@ -676,13 +684,20 @@
@Override
public boolean addAccountExplicitly(Account account, String password, Bundle extras) {
+ final int callingUid = Binder.getCallingUid();
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "addAccountExplicitly: " + account
- + ", caller's uid " + Binder.getCallingUid()
+ + ", caller's uid " + callingUid
+ ", pid " + Binder.getCallingPid());
}
if (account == null) throw new IllegalArgumentException("account is null");
- checkAuthenticateAccountsPermission(account);
+ if (!isAccountOwnedByCallingUid(account.type, callingUid)) {
+ String msg = String.format(
+ "uid %s cannot explicitly add accounts of type: %s",
+ callingUid,
+ account.type);
+ throw new SecurityException(msg);
+ }
/*
* Child users are not allowed to add accounts. Only the accounts that are
* shared by the parent profile can be added to child profile.
@@ -758,10 +773,24 @@
@Override
public boolean accountAuthenticated(final Account account) {
+ final int callingUid = Binder.getCallingUid();
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ String msg = String.format(
+ "accountAuthenticated( account: %s, callerUid: %s)",
+ account,
+ callingUid);
+ Log.v(TAG, msg);
+ }
if (account == null) {
throw new IllegalArgumentException("account is null");
}
- checkAuthenticateAccountsPermission(account);
+ if (!isAccountOwnedByCallingUid(account.type, callingUid)) {
+ String msg = String.format(
+ "uid %s cannot notify authentication for accounts of type: %s",
+ callingUid,
+ account.type);
+ throw new SecurityException(msg);
+ }
int userId = Binder.getCallingUserHandle().getIdentifier();
if (!canUserModifyAccounts(userId) || !canUserModifyAccountsForType(userId, account.type)) {
return false;
@@ -1007,16 +1036,21 @@
@Override
public void renameAccount(
IAccountManagerResponse response, Account accountToRename, String newName) {
+ final int callingUid = Binder.getCallingUid();
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "renameAccount: " + accountToRename + " -> " + newName
- + ", caller's uid " + Binder.getCallingUid()
+ + ", caller's uid " + callingUid
+ ", pid " + Binder.getCallingPid());
}
if (accountToRename == null) throw new IllegalArgumentException("account is null");
- checkAuthenticateAccountsPermission(accountToRename);
+ if (!isAccountOwnedByCallingUid(accountToRename.type, callingUid)) {
+ String msg = String.format(
+ "uid %s cannot rename accounts of type: %s",
+ callingUid,
+ accountToRename.type);
+ throw new SecurityException(msg);
+ }
UserAccounts accounts = getUserAccountsForCaller();
-
- int callingUid = getCallingUid();
long identityToken = clearCallingIdentity();
try {
Account resultingAccount = renameAccountInternal(accounts, accountToRename, newName,
@@ -1125,65 +1159,21 @@
@Override
public void removeAccount(IAccountManagerResponse response, Account account,
boolean expectActivityLaunch) {
- if (Log.isLoggable(TAG, Log.VERBOSE)) {
- Log.v(TAG, "removeAccount: " + account
- + ", response " + response
- + ", caller's uid " + Binder.getCallingUid()
- + ", pid " + Binder.getCallingPid());
- }
- if (response == null) throw new IllegalArgumentException("response is null");
- if (account == null) throw new IllegalArgumentException("account is null");
- checkManageAccountsPermission();
- UserHandle user = Binder.getCallingUserHandle();
- UserAccounts accounts = getUserAccountsForCaller();
- int userId = Binder.getCallingUserHandle().getIdentifier();
- if (!canUserModifyAccounts(userId)) {
- try {
- // TODO: This should be ERROR_CODE_USER_RESTRICTED instead. See http://b/16322768
- response.onError(AccountManager.ERROR_CODE_UNSUPPORTED_OPERATION,
- "User cannot modify accounts");
- } catch (RemoteException re) {
- }
- return;
- }
- if (!canUserModifyAccountsForType(userId, account.type)) {
- try {
- response.onError(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
- "User cannot modify accounts of this type (policy).");
- } catch (RemoteException re) {
- }
- return;
- }
-
- long identityToken = clearCallingIdentity();
-
- cancelNotification(getSigninRequiredNotificationId(accounts, account), user);
- synchronized (accounts.credentialsPermissionNotificationIds) {
- for (Pair<Pair<Account, String>, Integer> pair:
- accounts.credentialsPermissionNotificationIds.keySet()) {
- if (account.equals(pair.first.first)) {
- int id = accounts.credentialsPermissionNotificationIds.get(pair);
- cancelNotification(id, user);
- }
- }
- }
-
- logRecord(accounts, DebugDbHelper.ACTION_CALLED_ACCOUNT_REMOVE, TABLE_ACCOUNTS);
-
- try {
- new RemoveAccountSession(accounts, response, account, expectActivityLaunch).bind();
- } finally {
- restoreCallingIdentity(identityToken);
- }
+ removeAccountAsUser(
+ response,
+ account,
+ expectActivityLaunch,
+ UserHandle.getCallingUserId());
}
@Override
public void removeAccountAsUser(IAccountManagerResponse response, Account account,
boolean expectActivityLaunch, int userId) {
+ final int callingUid = Binder.getCallingUid();
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "removeAccount: " + account
+ ", response " + response
- + ", caller's uid " + Binder.getCallingUid()
+ + ", caller's uid " + callingUid
+ ", pid " + Binder.getCallingPid()
+ ", for user id " + userId);
}
@@ -1193,7 +1183,18 @@
// Only allow the system process to modify accounts of other users
enforceCrossUserPermission(userId, "User " + UserHandle.getCallingUserId()
+ " trying to remove account for " + userId);
- checkManageAccountsPermission();
+ /*
+ * Only the system or authenticator should be allowed to remove accounts for that
+ * authenticator. This will let users remove accounts (via Settings in the system) but not
+ * arbitrary applications (like competing authenticators).
+ */
+ if (!isAccountOwnedByCallingUid(account.type, callingUid) && !isSystemUid(callingUid)) {
+ String msg = String.format(
+ "uid %s cannot remove accounts of type: %s",
+ callingUid,
+ account.type);
+ throw new SecurityException(msg);
+ }
UserAccounts accounts = getUserAccounts(userId);
if (!canUserModifyAccounts(userId)) {
@@ -1238,13 +1239,26 @@
@Override
public boolean removeAccountExplicitly(Account account) {
+ final int callingUid = Binder.getCallingUid();
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "removeAccountExplicitly: " + account
- + ", caller's uid " + Binder.getCallingUid()
+ + ", caller's uid " + callingUid
+ ", pid " + Binder.getCallingPid());
}
- if (account == null) throw new IllegalArgumentException("account is null");
- checkAuthenticateAccountsPermission(account);
+ if (account == null) {
+ /*
+ * Null accounts should result in returning false, as per
+ * AccountManage.addAccountExplicitly(...) java doc.
+ */
+ Log.e(TAG, "account is null");
+ return false;
+ } else if (!isAccountOwnedByCallingUid(account.type, callingUid)) {
+ String msg = String.format(
+ "uid %s cannot explicitly add accounts of type: %s",
+ callingUid,
+ account.type);
+ throw new SecurityException(msg);
+ }
UserAccounts accounts = getUserAccountsForCaller();
int userId = Binder.getCallingUserHandle().getIdentifier();
@@ -1357,7 +1371,6 @@
}
if (accountType == null) throw new IllegalArgumentException("accountType is null");
if (authToken == null) throw new IllegalArgumentException("authToken is null");
- checkManageAccountsOrUseCredentialsPermissions();
UserAccounts accounts = getUserAccountsForCaller();
long identityToken = clearCallingIdentity();
try {
@@ -1490,15 +1503,22 @@
@Override
public String peekAuthToken(Account account, String authTokenType) {
+ final int callingUid = Binder.getCallingUid();
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "peekAuthToken: " + account
+ ", authTokenType " + authTokenType
- + ", caller's uid " + Binder.getCallingUid()
+ + ", caller's uid " + callingUid
+ ", pid " + Binder.getCallingPid());
}
if (account == null) throw new IllegalArgumentException("account is null");
if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
- checkAuthenticateAccountsPermission(account);
+ if (!isAccountOwnedByCallingUid(account.type, callingUid)) {
+ String msg = String.format(
+ "uid %s cannot peek the authtokens associated with accounts of type: %s",
+ callingUid,
+ account.type);
+ throw new SecurityException(msg);
+ }
UserAccounts accounts = getUserAccountsForCaller();
long identityToken = clearCallingIdentity();
try {
@@ -1510,15 +1530,22 @@
@Override
public void setAuthToken(Account account, String authTokenType, String authToken) {
+ final int callingUid = Binder.getCallingUid();
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "setAuthToken: " + account
+ ", authTokenType " + authTokenType
- + ", caller's uid " + Binder.getCallingUid()
+ + ", caller's uid " + callingUid
+ ", pid " + Binder.getCallingPid());
}
if (account == null) throw new IllegalArgumentException("account is null");
if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
- checkAuthenticateAccountsPermission(account);
+ if (!isAccountOwnedByCallingUid(account.type, callingUid)) {
+ String msg = String.format(
+ "uid %s cannot set auth tokens associated with accounts of type: %s",
+ callingUid,
+ account.type);
+ throw new SecurityException(msg);
+ }
UserAccounts accounts = getUserAccountsForCaller();
long identityToken = clearCallingIdentity();
try {
@@ -1530,15 +1557,21 @@
@Override
public void setPassword(Account account, String password) {
+ final int callingUid = Binder.getCallingUid();
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "setAuthToken: " + account
- + ", caller's uid " + Binder.getCallingUid()
+ + ", caller's uid " + callingUid
+ ", pid " + Binder.getCallingPid());
}
if (account == null) throw new IllegalArgumentException("account is null");
- checkAuthenticateAccountsPermission(account);
+ if (!isAccountOwnedByCallingUid(account.type, callingUid)) {
+ String msg = String.format(
+ "uid %s cannot set secrets for accounts of type: %s",
+ callingUid,
+ account.type);
+ throw new SecurityException(msg);
+ }
UserAccounts accounts = getUserAccountsForCaller();
- int callingUid = getCallingUid();
long identityToken = clearCallingIdentity();
try {
setPasswordInternal(accounts, account, password, callingUid);
@@ -1594,16 +1627,21 @@
@Override
public void clearPassword(Account account) {
+ final int callingUid = Binder.getCallingUid();
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "clearPassword: " + account
- + ", caller's uid " + Binder.getCallingUid()
+ + ", caller's uid " + callingUid
+ ", pid " + Binder.getCallingPid());
}
if (account == null) throw new IllegalArgumentException("account is null");
- checkManageAccountsPermission();
+ if (!isAccountOwnedByCallingUid(account.type, callingUid)) {
+ String msg = String.format(
+ "uid %s cannot clear passwords for accounts of type: %s",
+ callingUid,
+ account.type);
+ throw new SecurityException(msg);
+ }
UserAccounts accounts = getUserAccountsForCaller();
-
- int callingUid = getCallingUid();
long identityToken = clearCallingIdentity();
try {
setPasswordInternal(accounts, account, null, callingUid);
@@ -1614,15 +1652,22 @@
@Override
public void setUserData(Account account, String key, String value) {
+ final int callingUid = Binder.getCallingUid();
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "setUserData: " + account
+ ", key " + key
- + ", caller's uid " + Binder.getCallingUid()
+ + ", caller's uid " + callingUid
+ ", pid " + Binder.getCallingPid());
}
if (key == null) throw new IllegalArgumentException("key is null");
if (account == null) throw new IllegalArgumentException("account is null");
- checkAuthenticateAccountsPermission(account);
+ if (!isAccountOwnedByCallingUid(account.type, callingUid)) {
+ String msg = String.format(
+ "uid %s cannot set user data for accounts of type: %s",
+ callingUid,
+ account.type);
+ throw new SecurityException(msg);
+ }
UserAccounts accounts = getUserAccountsForCaller();
long identityToken = clearCallingIdentity();
try {
@@ -1769,7 +1814,6 @@
return;
}
- checkBinderPermission(Manifest.permission.USE_CREDENTIALS);
final UserAccounts accounts = getUserAccountsForCaller();
final RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> authenticatorInfo;
authenticatorInfo = mAuthenticatorCache.getServiceInfo(
@@ -2047,7 +2091,6 @@
}
if (response == null) throw new IllegalArgumentException("response is null");
if (accountType == null) throw new IllegalArgumentException("accountType is null");
- checkManageAccountsPermission();
// Is user disallowed from modifying accounts?
int userId = Binder.getCallingUserHandle().getIdentifier();
@@ -2122,7 +2165,6 @@
}
if (response == null) throw new IllegalArgumentException("response is null");
if (accountType == null) throw new IllegalArgumentException("accountType is null");
- checkManageAccountsPermission();
// Only allow the system process to add accounts of other users
enforceCrossUserPermission(userId, "User " + UserHandle.getCallingUserId()
@@ -2213,7 +2255,6 @@
}
if (response == null) throw new IllegalArgumentException("response is null");
if (account == null) throw new IllegalArgumentException("account is null");
- checkManageAccountsPermission();
UserAccounts accounts = getUserAccounts(userId);
long identityToken = clearCallingIdentity();
try {
@@ -2250,7 +2291,6 @@
if (response == null) throw new IllegalArgumentException("response is null");
if (account == null) throw new IllegalArgumentException("account is null");
if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
- checkManageAccountsPermission();
UserAccounts accounts = getUserAccountsForCaller();
long identityToken = clearCallingIdentity();
try {
@@ -2278,16 +2318,23 @@
@Override
public void editProperties(IAccountManagerResponse response, final String accountType,
final boolean expectActivityLaunch) {
+ final int callingUid = Binder.getCallingUid();
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "editProperties: accountType " + accountType
+ ", response " + response
+ ", expectActivityLaunch " + expectActivityLaunch
- + ", caller's uid " + Binder.getCallingUid()
+ + ", caller's uid " + callingUid
+ ", pid " + Binder.getCallingPid());
}
if (response == null) throw new IllegalArgumentException("response is null");
if (accountType == null) throw new IllegalArgumentException("accountType is null");
- checkManageAccountsPermission();
+ if (!isAccountOwnedByCallingUid(accountType, callingUid) && !isSystemUid(callingUid)) {
+ String msg = String.format(
+ "uid %s cannot edit authenticator properites for account type: %s",
+ callingUid,
+ accountType);
+ throw new SecurityException(msg);
+ }
UserAccounts accounts = getUserAccountsForCaller();
long identityToken = clearCallingIdentity();
try {
@@ -3588,7 +3635,7 @@
private boolean permissionIsGranted(Account account, String authTokenType, int callerUid) {
final boolean isPrivileged = isPrivileged(callerUid);
final boolean fromAuthenticator = account != null
- && hasAuthenticatorUid(account.type, callerUid);
+ && isAccountManagedByCaller(account.type, callerUid);
final boolean hasExplicitGrants = account != null
&& hasExplicitlyGrantedPermission(account, authTokenType, callerUid);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
@@ -3600,14 +3647,17 @@
return fromAuthenticator || hasExplicitGrants || isPrivileged;
}
- private boolean hasAuthenticatorUid(String accountType, int callingUid) {
+ private boolean isAccountManagedByCaller(String accountType, int callingUid) {
final int callingUserId = UserHandle.getUserId(callingUid);
for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> serviceInfo :
mAuthenticatorCache.getAllServices(callingUserId)) {
if (serviceInfo.type.type.equals(accountType)) {
- return (serviceInfo.uid == callingUid) ||
- (mPackageManager.checkSignatures(serviceInfo.uid, callingUid)
- == PackageManager.SIGNATURE_MATCH);
+ /*
+ * We can't simply compare uids because uids can be recycled before the
+ * authenticator cache is updated.
+ */
+ final int sigChk = mPackageManager.checkSignatures(serviceInfo.uid, callingUid);
+ return sigChk == PackageManager.SIGNATURE_MATCH;
}
}
return false;
@@ -3648,36 +3698,49 @@
}
}
- private void checkCallingUidAgainstAuthenticator(Account account) {
- final int uid = Binder.getCallingUid();
- if (account == null || !hasAuthenticatorUid(account.type, uid)) {
- String msg = "caller uid " + uid + " is different than the authenticator's uid";
- Log.w(TAG, msg);
- throw new SecurityException(msg);
+ private boolean isSystemUid(int callingUid) {
+ String[] packages = null;
+ long ident = Binder.clearCallingIdentity();
+ try {
+ packages = mPackageManager.getPackagesForUid(callingUid);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
}
- if (Log.isLoggable(TAG, Log.VERBOSE)) {
- Log.v(TAG, "caller uid " + uid + " is the same as the authenticator's uid");
+ if (packages != null) {
+ for (String name : packages) {
+ try {
+ PackageInfo packageInfo = mPackageManager.getPackageInfo(name, 0 /* flags */);
+ if (packageInfo != null
+ && (packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM)
+ != 0) {
+ return true;
+ }
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.w(TAG, String.format("Could not find package [%s]", name), e);
+ }
+ }
+ } else {
+ Log.w(TAG, "No known packages with uid " + callingUid);
}
+ return false;
}
- private void checkAuthenticateAccountsPermission(Account account) {
- checkBinderPermission(Manifest.permission.AUTHENTICATE_ACCOUNTS);
- checkCallingUidAgainstAuthenticator(account);
+ private boolean isAccountOwnedByCallingUid(String accountType, int callingUid) {
+ if (!isAccountManagedByCaller(accountType, callingUid)) {
+ String msg = "caller uid " + callingUid + " is different than the authenticator's uid";
+ Log.w(TAG, msg);
+ return false;
+ }
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "caller uid " + callingUid + " is the same as the authenticator's uid");
+ }
+ return true;
}
private void checkReadAccountsPermission() {
checkBinderPermission(Manifest.permission.GET_ACCOUNTS);
}
- private void checkManageAccountsPermission() {
- checkBinderPermission(Manifest.permission.MANAGE_ACCOUNTS);
- }
-
- private void checkManageAccountsOrUseCredentialsPermissions() {
- checkBinderPermission(Manifest.permission.MANAGE_ACCOUNTS,
- Manifest.permission.USE_CREDENTIALS);
- }
-
private boolean canUserModifyAccounts(int userId) {
if (getUserManager().getUserRestrictions(new UserHandle(userId))
.getBoolean(UserManager.DISALLOW_MODIFY_ACCOUNTS)) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 0d08c2a..029a3b2 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -32,6 +32,7 @@
import static com.android.server.am.TaskRecord.INVALID_TASK_ID;
import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_DONT_LOCK;
import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_LAUNCHABLE;
+import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_LAUNCHABLE_PRIV;
import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_PINNABLE;
import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
import static org.xmlpull.v1.XmlPullParser.START_TAG;
@@ -2967,9 +2968,14 @@
// should never happen).
SparseArray<ProcessRecord> procs = mProcessNames.getMap().get(processName);
if (procs == null) return null;
- final int N = procs.size();
- for (int i = 0; i < N; i++) {
- if (UserHandle.isSameUser(procs.keyAt(i), uid)) return procs.valueAt(i);
+ final int procCount = procs.size();
+ for (int i = 0; i < procCount; i++) {
+ final int procUid = procs.keyAt(i);
+ if (UserHandle.isApp(procUid) || !UserHandle.isSameUser(procUid, uid)) {
+ // Don't use an app process or different user process for system component.
+ continue;
+ }
+ return procs.valueAt(i);
}
}
ProcessRecord proc = mProcessNames.get(processName, uid);
@@ -4197,9 +4203,9 @@
if (rootR == null) {
Slog.w(TAG, "Finishing task with all activities already finished");
}
- // Do not allow task to finish if last task in lockTask mode. Launchable apps can
- // finish themselves.
- if (tr.mLockTaskAuth != LOCK_TASK_AUTH_LAUNCHABLE && rootR == r &&
+ // Do not allow task to finish if last task in lockTask mode. Launchable priv-apps can
+ // finish.
+ if (tr.mLockTaskAuth != LOCK_TASK_AUTH_LAUNCHABLE_PRIV && rootR == r &&
mStackSupervisor.isLastLockedTask(tr)) {
Slog.i(TAG, "Not finishing task in lock task mode");
mStackSupervisor.showLockTaskToast();
@@ -4361,9 +4367,10 @@
return false;
}
- // Do not allow the last non-launchable task to finish in Lock Task mode.
+ // Do not allow task to finish if last task in lockTask mode. Launchable priv-apps
+ // can finish.
final TaskRecord task = r.task;
- if (task.mLockTaskAuth != LOCK_TASK_AUTH_LAUNCHABLE &&
+ if (task.mLockTaskAuth != LOCK_TASK_AUTH_LAUNCHABLE_PRIV &&
mStackSupervisor.isLastLockedTask(task) && task.getRootActivity() == r) {
mStackSupervisor.showLockTaskToast();
return false;
@@ -18617,7 +18624,7 @@
if (packages != null) {
for (int i = 0; i < packages.length; i++) {
mUsageStatsService.reportEvent(packages[i], app.userId,
- UsageEvents.Event.INTERACTION);
+ UsageEvents.Event.SYSTEM_INTERACTION);
}
}
}
@@ -19375,15 +19382,16 @@
enforceCallingPermission(android.Manifest.permission.SET_DEBUG_APP,
"setDumpHeapDebugLimit()");
} else {
- if (!Build.IS_DEBUGGABLE) {
- throw new SecurityException("Not running a debuggable build");
- }
synchronized (mPidsSelfLocked) {
ProcessRecord proc = mPidsSelfLocked.get(Binder.getCallingPid());
if (proc == null) {
throw new SecurityException("No process found for calling pid "
+ Binder.getCallingPid());
}
+ if (!Build.IS_DEBUGGABLE
+ && (proc.info.flags&ApplicationInfo.FLAG_DEBUGGABLE) == 0) {
+ throw new SecurityException("Not running a debuggable build");
+ }
processName = proc.processName;
uid = proc.uid;
if (reportPackage != null && !proc.pkgList.containsKey(reportPackage)) {
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 577a4f9..9e33f2a 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -35,6 +35,7 @@
import static com.android.server.am.ActivityStack.ActivityState.*;
import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_DONT_LOCK;
import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_LAUNCHABLE;
+import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_LAUNCHABLE_PRIV;
import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_PINNABLE;
import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_WHITELISTED;
@@ -1179,7 +1180,8 @@
mService.updateOomAdjLocked();
final TaskRecord task = r.task;
- if (task.mLockTaskAuth == LOCK_TASK_AUTH_LAUNCHABLE) {
+ if (task.mLockTaskAuth == LOCK_TASK_AUTH_LAUNCHABLE ||
+ task.mLockTaskAuth == LOCK_TASK_AUTH_LAUNCHABLE_PRIV) {
setLockTaskModeLocked(task, LOCK_TASK_MODE_LOCKED, "mLockTaskAuth==LAUNCHABLE", false);
}
@@ -2019,15 +2021,22 @@
r, top.task);
top.deliverNewIntentLocked(callingUid, r.intent, r.launchedFromPackage);
} else {
- // A special case: we need to
- // start the activity because it is not currently
- // running, and the caller has asked to clear the
- // current task to have this activity at the top.
+ // A special case: we need to start the activity because it is not
+ // currently running, and the caller has asked to clear the current
+ // task to have this activity at the top.
addingToTask = true;
- // Now pretend like this activity is being started
- // by the top of its task, so it is put in the
- // right place.
+ // Now pretend like this activity is being started by the top of its
+ // task, so it is put in the right place.
sourceRecord = intentActivity;
+ TaskRecord task = sourceRecord.task;
+ if (task != null && task.stack == null) {
+ // Target stack got cleared when we all activities were removed
+ // above. Go ahead and reset it.
+ targetStack = computeStackFocus(sourceRecord, false /* newTask */);
+ targetStack.addTask(
+ task, !launchTaskBehind /* toTop */, false /* moving */);
+ }
+
}
} else if (r.realActivity.equals(intentActivity.task.realActivity)) {
// In this case the top activity on the task is the
@@ -3778,6 +3787,7 @@
switch (lockTaskAuth) {
case LOCK_TASK_AUTH_DONT_LOCK:
return !mLockTaskModeTasks.isEmpty();
+ case LOCK_TASK_AUTH_LAUNCHABLE_PRIV:
case LOCK_TASK_AUTH_LAUNCHABLE:
case LOCK_TASK_AUTH_WHITELISTED:
return false;
@@ -3794,12 +3804,14 @@
boolean didSomething = false;
for (int taskNdx = mLockTaskModeTasks.size() - 1; taskNdx >= 0; --taskNdx) {
final TaskRecord lockedTask = mLockTaskModeTasks.get(taskNdx);
- if (lockedTask.mLockTaskMode != LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED) {
- continue;
- }
- final boolean wasLaunchable = lockedTask.mLockTaskAuth == LOCK_TASK_AUTH_LAUNCHABLE;
+ final boolean wasWhitelisted =
+ (lockedTask.mLockTaskAuth == LOCK_TASK_AUTH_LAUNCHABLE) ||
+ (lockedTask.mLockTaskAuth == LOCK_TASK_AUTH_WHITELISTED);
lockedTask.setLockTaskAuth();
- if (wasLaunchable && lockedTask.mLockTaskAuth != LOCK_TASK_AUTH_LAUNCHABLE) {
+ final boolean isWhitelisted =
+ (lockedTask.mLockTaskAuth == LOCK_TASK_AUTH_LAUNCHABLE) ||
+ (lockedTask.mLockTaskAuth == LOCK_TASK_AUTH_WHITELISTED);
+ if (wasWhitelisted && !isWhitelisted) {
// Lost whitelisting authorization. End it now.
if (DEBUG_LOCKTASK) Slog.d(TAG_LOCKTASK, "onLockTaskPackagesUpdated: removing " +
lockedTask + " mLockTaskAuth=" + lockedTask.lockTaskAuthToString());
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index f966bcf..78f9f18 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -134,12 +134,15 @@
/** Can't be put in lockTask mode. */
final static int LOCK_TASK_AUTH_DONT_LOCK = 0;
- /** Can enter lockTask with user approval. Can never start over existing lockTask task. */
+ /** Can enter app pinning with user approval. Can never start over existing lockTask task. */
final static int LOCK_TASK_AUTH_PINNABLE = 1;
/** Starts in LOCK_TASK_MODE_LOCKED automatically. Can start over existing lockTask task. */
final static int LOCK_TASK_AUTH_LAUNCHABLE = 2;
- /** Can enter lockTask with user approval. Can start over existing lockTask task. */
+ /** Can enter lockTask without user approval. Can start over existing lockTask task. */
final static int LOCK_TASK_AUTH_WHITELISTED = 3;
+ /** Priv-app that starts in LOCK_TASK_MODE_LOCKED automatically. Can start over existing
+ * lockTask task. */
+ final static int LOCK_TASK_AUTH_LAUNCHABLE_PRIV = 4;
int mLockTaskAuth = LOCK_TASK_AUTH_PINNABLE;
int mLockTaskUid = -1; // The uid of the application that called startLockTask().
@@ -747,11 +750,18 @@
case LOCK_TASK_AUTH_PINNABLE: return "LOCK_TASK_AUTH_PINNABLE";
case LOCK_TASK_AUTH_LAUNCHABLE: return "LOCK_TASK_AUTH_LAUNCHABLE";
case LOCK_TASK_AUTH_WHITELISTED: return "LOCK_TASK_AUTH_WHITELISTED";
+ case LOCK_TASK_AUTH_LAUNCHABLE_PRIV: return "LOCK_TASK_AUTH_LAUNCHABLE_PRIV";
default: return "unknown=" + mLockTaskAuth;
}
}
void setLockTaskAuth() {
+ if (!mPrivileged &&
+ (mLockTaskMode == LOCK_TASK_LAUNCH_MODE_ALWAYS ||
+ mLockTaskMode == LOCK_TASK_LAUNCH_MODE_NEVER)) {
+ // Non-priv apps are not allowed to use always or never, fall back to default
+ mLockTaskMode = LOCK_TASK_LAUNCH_MODE_DEFAULT;
+ }
switch (mLockTaskMode) {
case LOCK_TASK_LAUNCH_MODE_DEFAULT:
mLockTaskAuth = isLockTaskWhitelistedLocked() ?
@@ -759,13 +769,11 @@
break;
case LOCK_TASK_LAUNCH_MODE_NEVER:
- mLockTaskAuth = mPrivileged ?
- LOCK_TASK_AUTH_DONT_LOCK : LOCK_TASK_AUTH_PINNABLE;
+ mLockTaskAuth = LOCK_TASK_AUTH_DONT_LOCK;
break;
case LOCK_TASK_LAUNCH_MODE_ALWAYS:
- mLockTaskAuth = mPrivileged ?
- LOCK_TASK_AUTH_LAUNCHABLE: LOCK_TASK_AUTH_PINNABLE;
+ mLockTaskAuth = LOCK_TASK_AUTH_LAUNCHABLE_PRIV;
break;
case LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED:
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index 7440b8c..b2ab797 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -346,6 +346,8 @@
synchronized (mTempDisplayStateWorkQueue) {
try {
// Update the display state within the lock.
+ // Note that we do not need to schedule traversals here although it
+ // may happen as a side-effect of displays changing state.
synchronized (mSyncRoot) {
if (mGlobalDisplayState == state
&& mGlobalDisplayBrightness == brightness) {
@@ -357,8 +359,7 @@
+ ", brightness=" + brightness + ")");
mGlobalDisplayState = state;
mGlobalDisplayBrightness = brightness;
- updateGlobalDisplayStateLocked(mTempDisplayStateWorkQueue);
- scheduleTraversalLocked(false);
+ applyGlobalDisplayStateLocked(mTempDisplayStateWorkQueue);
}
// Setting the display power state can take hundreds of milliseconds
@@ -715,6 +716,7 @@
handleDisplayDeviceRemovedLocked(device);
}
}
+
private void handleDisplayDeviceRemovedLocked(DisplayDevice device) {
DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked();
if (!mDisplayDevices.remove(device)) {
@@ -729,7 +731,7 @@
scheduleTraversalLocked(false);
}
- private void updateGlobalDisplayStateLocked(List<Runnable> workQueue) {
+ private void applyGlobalDisplayStateLocked(List<Runnable> workQueue) {
final int count = mDisplayDevices.size();
for (int i = 0; i < count; i++) {
DisplayDevice device = mDisplayDevices.get(i);
diff --git a/services/core/java/com/android/server/display/LogicalDisplay.java b/services/core/java/com/android/server/display/LogicalDisplay.java
index 4823769..6efc99a 100644
--- a/services/core/java/com/android/server/display/LogicalDisplay.java
+++ b/services/core/java/com/android/server/display/LogicalDisplay.java
@@ -133,6 +133,8 @@
mInfo.overscanBottom = mOverrideDisplayInfo.overscanBottom;
mInfo.rotation = mOverrideDisplayInfo.rotation;
mInfo.logicalDensityDpi = mOverrideDisplayInfo.logicalDensityDpi;
+ mInfo.physicalXDpi = mOverrideDisplayInfo.physicalXDpi;
+ mInfo.physicalYDpi = mOverrideDisplayInfo.physicalYDpi;
}
}
return mInfo;
diff --git a/services/core/java/com/android/server/display/OverlayDisplayAdapter.java b/services/core/java/com/android/server/display/OverlayDisplayAdapter.java
index 0462035..0bddff0 100644
--- a/services/core/java/com/android/server/display/OverlayDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/OverlayDisplayAdapter.java
@@ -174,9 +174,11 @@
if (width >= MIN_WIDTH && width <= MAX_WIDTH
&& height >= MIN_HEIGHT && height <= MAX_HEIGHT
&& densityDpi >= DisplayMetrics.DENSITY_LOW
- && densityDpi <= DisplayMetrics.DENSITY_XXHIGH) {
+ && densityDpi <= DisplayMetrics.DENSITY_XXXHIGH) {
modes.add(new OverlayMode(width, height, densityDpi));
continue;
+ } else {
+ Slog.w(TAG, "Ignoring out-of-range overlay display mode: " + mode);
}
} catch (NumberFormatException ex) {
}
diff --git a/services/core/java/com/android/server/fingerprint/FingerprintService.java b/services/core/java/com/android/server/fingerprint/FingerprintService.java
index b0d5765..7f0be57 100644
--- a/services/core/java/com/android/server/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/fingerprint/FingerprintService.java
@@ -706,9 +706,22 @@
@Override // Binder call
public long getAuthenticatorId(String opPackageName) {
- if (!canUseFingerprint(opPackageName)) {
- return 0;
- }
+ // In this method, we're not checking whether the caller is permitted to use fingerprint
+ // API because current authenticator ID is leaked (in a more contrived way) via Android
+ // Keystore (android.security.keystore package): the user of that API can create a key
+ // which requires fingerprint authentication for its use, and then query the key's
+ // characteristics (hidden API) which returns, among other things, fingerprint
+ // authenticator ID which was active at key creation time.
+ //
+ // Reason: The part of Android Keystore which runs inside an app's process invokes this
+ // method in certain cases. Those cases are not always where the developer demonstrates
+ // explicit intent to use fingerprint functionality. Thus, to avoiding throwing an
+ // unexpected SecurityException this method does not check whether its caller is
+ // permitted to use fingerprint API.
+ //
+ // The permission check should be restored once Android Keystore no longer invokes this
+ // method from inside app processes.
+
return FingerprintService.this.getAuthenticatorId();
}
}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 8ee2076..90e912d 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -1407,7 +1407,7 @@
mAppUsageStats.reportEvent(r.sbn.getPackageName(),
userId == UserHandle.USER_ALL ? UserHandle.USER_OWNER
: userId,
- UsageEvents.Event.INTERACTION);
+ UsageEvents.Event.USER_INTERACTION);
r.setSeen();
}
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index e2cc3f7..6c9fd3f 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -92,6 +92,7 @@
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.FeatureInfo;
+import android.content.pm.IOnPermissionsChangeListener;
import android.content.pm.IPackageDataObserver;
import android.content.pm.IPackageDeleteObserver;
import android.content.pm.IPackageDeleteObserver2;
@@ -144,6 +145,7 @@
import android.os.Parcel;
import android.os.ParcelFileDescriptor;
import android.os.Process;
+import android.os.RemoteCallback;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.SELinux;
@@ -523,6 +525,8 @@
private AtomicInteger mNextMoveId = new AtomicInteger();
private final MoveCallbacks mMoveCallbacks;
+ private final OnPermissionChangeListeners mOnPermissionChangeListeners;
+
// Cache of users who need badging.
SparseBooleanArray mUserNeedsBadging = new SparseBooleanArray();
@@ -1731,6 +1735,9 @@
mPackageDexOptimizer = new PackageDexOptimizer(this);
mMoveCallbacks = new MoveCallbacks(FgThread.get().getLooper());
+ mOnPermissionChangeListeners = new OnPermissionChangeListeners(
+ FgThread.get().getLooper());
+
getDefaultDisplayMetrics(context, mMetrics);
SystemConfig systemConfig = SystemConfig.getInstance();
@@ -3195,10 +3202,11 @@
case PermissionsState.PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED: {
gidsChanged = true;
- }
- break;
+ } break;
}
+ mOnPermissionChangeListeners.onPermissionsChanged(pkg.applicationInfo.uid);
+
// Not critical if that is lost - app has to request again.
mSettings.writeRuntimePermissionsForUserLPr(userId, false);
}
@@ -3255,6 +3263,8 @@
return;
}
+ mOnPermissionChangeListeners.onPermissionsChanged(pkg.applicationInfo.uid);
+
// Critical, after this call app should never have the permission.
mSettings.writeRuntimePermissionsForUserLPr(userId, true);
}
@@ -3397,6 +3407,24 @@
}
@Override
+ public void addOnPermissionsChangeListener(IOnPermissionsChangeListener listener) {
+ mContext.enforceCallingOrSelfPermission(
+ Manifest.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS,
+ "addOnPermissionsChangeListener");
+
+ synchronized (mPackages) {
+ mOnPermissionChangeListeners.addListenerLocked(listener);
+ }
+ }
+
+ @Override
+ public void removeOnPermissionsChangeListener(IOnPermissionsChangeListener listener) {
+ synchronized (mPackages) {
+ mOnPermissionChangeListeners.removeListenerLocked(listener);
+ }
+ }
+
+ @Override
public boolean isProtectedBroadcast(String actionName) {
synchronized (mPackages) {
return mProtectedBroadcasts.contains(actionName);
@@ -6368,6 +6396,16 @@
if ((scanFlags & SCAN_NEW_INSTALL) == 0) {
derivePackageAbi(pkg, scanFile, cpuAbiOverride, true /* extract libs */);
+
+ // Some system apps still use directory structure for native libraries
+ // in which case we might end up not detecting abi solely based on apk
+ // structure. Try to detect abi based on directory structure.
+ if (isSystemApp(pkg) && !pkg.isUpdatedSystemApp() &&
+ pkg.applicationInfo.primaryCpuAbi == null) {
+ setBundledAppAbisAndRoots(pkg, pkgSetting);
+ setNativeLibraryPaths(pkg);
+ }
+
} else {
if ((scanFlags & SCAN_MOVE) != 0) {
// We haven't run dex-opt for this move (since we've moved the compiled output too)
@@ -7273,6 +7311,33 @@
}
/**
+ * Calculate the abis and roots for a bundled app. These can uniquely
+ * be determined from the contents of the system partition, i.e whether
+ * it contains 64 or 32 bit shared libraries etc. We do not validate any
+ * of this information, and instead assume that the system was built
+ * sensibly.
+ */
+ private void setBundledAppAbisAndRoots(PackageParser.Package pkg,
+ PackageSetting pkgSetting) {
+ final String apkName = deriveCodePathName(pkg.applicationInfo.getCodePath());
+
+ // If "/system/lib64/apkname" exists, assume that is the per-package
+ // native library directory to use; otherwise use "/system/lib/apkname".
+ final String apkRoot = calculateBundledApkRoot(pkg.applicationInfo.sourceDir);
+ setBundledAppAbi(pkg, apkRoot, apkName);
+ // pkgSetting might be null during rescan following uninstall of updates
+ // to a bundled app, so accommodate that possibility. The settings in
+ // that case will be established later from the parsed package.
+ //
+ // If the settings aren't null, sync them up with what we've just derived.
+ // note that apkRoot isn't stored in the package settings.
+ if (pkgSetting != null) {
+ pkgSetting.primaryCpuAbiString = pkg.applicationInfo.primaryCpuAbi;
+ pkgSetting.secondaryCpuAbiString = pkg.applicationInfo.secondaryCpuAbi;
+ }
+ }
+
+ /**
* Deduces the ABI of a bundled app and sets the relevant fields on the
* parsed pkg object.
*
@@ -15260,4 +15325,57 @@
}
}
}
+
+ private final class OnPermissionChangeListeners extends Handler {
+ private static final int MSG_ON_PERMISSIONS_CHANGED = 1;
+
+ private final RemoteCallbackList<IOnPermissionsChangeListener> mPermissionListeners =
+ new RemoteCallbackList<>();
+
+ public OnPermissionChangeListeners(Looper looper) {
+ super(looper);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_ON_PERMISSIONS_CHANGED: {
+ final int uid = msg.arg1;
+ handleOnPermissionsChanged(uid);
+ } break;
+ }
+ }
+
+ public void addListenerLocked(IOnPermissionsChangeListener listener) {
+ mPermissionListeners.register(listener);
+
+ }
+
+ public void removeListenerLocked(IOnPermissionsChangeListener listener) {
+ mPermissionListeners.unregister(listener);
+ }
+
+ public void onPermissionsChanged(int uid) {
+ if (mPermissionListeners.getRegisteredCallbackCount() > 0) {
+ obtainMessage(MSG_ON_PERMISSIONS_CHANGED, uid, 0).sendToTarget();
+ }
+ }
+
+ private void handleOnPermissionsChanged(int uid) {
+ final int count = mPermissionListeners.beginBroadcast();
+ try {
+ for (int i = 0; i < count; i++) {
+ IOnPermissionsChangeListener callback = mPermissionListeners
+ .getBroadcastItem(i);
+ try {
+ callback.onPermissionsChanged(uid);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Permission listener is dead", e);
+ }
+ }
+ } finally {
+ mPermissionListeners.finishBroadcast();
+ }
+ }
+ }
}
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 6e52358..25ca167 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -514,6 +514,7 @@
boolean mDreamingLockscreen;
boolean mDreamingSleepTokenNeeded;
SleepToken mDreamingSleepToken;
+ SleepToken mScreenOffSleepToken;
boolean mKeyguardSecure;
boolean mKeyguardSecureIncludingHidden;
volatile boolean mKeyguardOccluded;
@@ -5385,6 +5386,7 @@
public void screenTurnedOff() {
if (DEBUG_WAKEUP) Slog.i(TAG, "Screen turned off...");
+ updateScreenOffSleepToken(true);
synchronized (mLock) {
mScreenOnEarly = false;
mScreenOnFully = false;
@@ -5399,6 +5401,7 @@
public void screenTurningOn(final ScreenOnListener screenOnListener) {
if (DEBUG_WAKEUP) Slog.i(TAG, "Screen turning on...");
+ updateScreenOffSleepToken(false);
synchronized (mLock) {
mScreenOnEarly = true;
mScreenOnFully = false;
@@ -6021,6 +6024,20 @@
} else {
if (mDreamingSleepToken != null) {
mDreamingSleepToken.release();
+ mDreamingSleepToken = null;
+ }
+ }
+ }
+
+ private void updateScreenOffSleepToken(boolean acquire) {
+ if (acquire) {
+ if (mScreenOffSleepToken == null) {
+ mScreenOffSleepToken = mActivityManagerInternal.acquireSleepToken("ScreenOff");
+ }
+ } else {
+ if (mScreenOffSleepToken != null) {
+ mScreenOffSleepToken.release();
+ mScreenOffSleepToken = null;
}
}
}
diff --git a/services/core/java/com/android/server/policy/WindowOrientationListener.java b/services/core/java/com/android/server/policy/WindowOrientationListener.java
index c8fd82e..147efdd 100644
--- a/services/core/java/com/android/server/policy/WindowOrientationListener.java
+++ b/services/core/java/com/android/server/policy/WindowOrientationListener.java
@@ -24,10 +24,10 @@
import android.os.Handler;
import android.os.SystemClock;
import android.os.SystemProperties;
-import android.util.Log;
import android.util.Slog;
import java.io.PrintWriter;
+import java.util.Arrays;
/**
* A special helper class used by the WindowManager
@@ -40,8 +40,6 @@
*
* You can also visualize the behavior of the WindowOrientationListener.
* Refer to frameworks/base/tools/orientationplot/README.txt for details.
- *
- * @hide
*/
public abstract class WindowOrientationListener {
private static final String TAG = "WindowOrientationListener";
@@ -90,7 +88,7 @@
? Sensor.TYPE_GRAVITY : Sensor.TYPE_ACCELEROMETER);
if (mSensor != null) {
// Create listener only if sensors do exist
- mSensorEventListener = new SensorEventListenerImpl();
+ mSensorEventListener = new SensorEventListenerImpl(context);
}
}
@@ -101,12 +99,12 @@
public void enable() {
synchronized (mLock) {
if (mSensor == null) {
- Log.w(TAG, "Cannot detect sensors. Not enabled");
+ Slog.w(TAG, "Cannot detect sensors. Not enabled");
return;
}
if (mEnabled == false) {
if (LOG) {
- Log.d(TAG, "WindowOrientationListener enabled");
+ Slog.d(TAG, "WindowOrientationListener enabled");
}
mSensorEventListener.resetLocked();
mSensorManager.registerListener(mSensorEventListener, mSensor, mRate, mHandler);
@@ -121,12 +119,12 @@
public void disable() {
synchronized (mLock) {
if (mSensor == null) {
- Log.w(TAG, "Cannot detect sensors. Invalid disable");
+ Slog.w(TAG, "Cannot detect sensors. Invalid disable");
return;
}
if (mEnabled == true) {
if (LOG) {
- Log.d(TAG, "WindowOrientationListener disabled");
+ Slog.d(TAG, "WindowOrientationListener disabled");
}
mSensorManager.unregisterListener(mSensorEventListener);
mEnabled = false;
@@ -296,7 +294,7 @@
// If the tilt angle remains greater than the specified angle for a minimum of
// the specified time, then the device is deemed to be lying flat
// (just chillin' on a table).
- private static final float FLAT_ANGLE = 75;
+ private static final float FLAT_ANGLE = 80;
private static final long FLAT_TIME_NANOS = 1000 * NANOS_PER_MS;
// If the tilt angle has increased by at least delta degrees within the specified amount
@@ -361,8 +359,24 @@
SensorManager.STANDARD_GRAVITY + ACCELERATION_TOLERANCE;
// Maximum absolute tilt angle at which to consider orientation data. Beyond this (i.e.
- // when screen is facing the sky or ground), we completely ignore orientation data.
- private static final int MAX_TILT = 75;
+ // when screen is facing the sky or ground), we completely ignore orientation data
+ // because it's too unstable.
+ private static final int MAX_TILT = 80;
+
+ // The tilt angle below which we conclude that the user is holding the device
+ // overhead reading in bed and lock into that state.
+ private static final int TILT_OVERHEAD_ENTER = -40;
+
+ // The tilt angle above which we conclude that the user would like a rotation
+ // change to occur and unlock from the overhead state.
+ private static final int TILT_OVERHEAD_EXIT = -15;
+
+ // The gap angle in degrees between adjacent orientation angles for hysteresis.
+ // This creates a "dead zone" between the current orientation and a proposed
+ // adjacent orientation. No orientation proposal is made when the orientation
+ // angle is within the gap between the current orientation and the adjacent
+ // orientation.
+ private static final int ADJACENT_ORIENTATION_ANGLE_GAP = 45;
// The tilt angle range in degrees for each orientation.
// Beyond these tilt angles, we don't even consider transitioning into the
@@ -375,28 +389,13 @@
// facing up (resting on a table).
// The ideal tilt angle is 0 (when the device is vertical) so the limits establish
// how close to vertical the device must be in order to change orientation.
- private final int[][] TILT_TOLERANCE = new int[][] {
- /* ROTATION_0 */ { -25, 70 },
+ private final int[][] mTiltToleranceConfig = new int[][] {
+ /* ROTATION_0 */ { -25, 70 }, // note: these are overridden by config.xml
/* ROTATION_90 */ { -25, 65 },
/* ROTATION_180 */ { -25, 60 },
/* ROTATION_270 */ { -25, 65 }
};
- // The tilt angle below which we conclude that the user is holding the device
- // overhead reading in bed and lock into that state.
- private final int TILT_OVERHEAD_ENTER = -40;
-
- // The tilt angle above which we conclude that the user would like a rotation
- // change to occur and unlock from the overhead state.
- private final int TILT_OVERHEAD_EXIT = -15;
-
- // The gap angle in degrees between adjacent orientation angles for hysteresis.
- // This creates a "dead zone" between the current orientation and a proposed
- // adjacent orientation. No orientation proposal is made when the orientation
- // angle is within the gap between the current orientation and the adjacent
- // orientation.
- private static final int ADJACENT_ORIENTATION_ANGLE_GAP = 45;
-
// Timestamp and value of the last accelerometer sample.
private long mLastFilteredTimestampNanos;
private float mLastFilteredX, mLastFilteredY, mLastFilteredZ;
@@ -430,11 +429,32 @@
private boolean mOverhead;
// History of observed tilt angles.
- private static final int TILT_HISTORY_SIZE = 40;
+ private static final int TILT_HISTORY_SIZE = 200;
private float[] mTiltHistory = new float[TILT_HISTORY_SIZE];
private long[] mTiltHistoryTimestampNanos = new long[TILT_HISTORY_SIZE];
private int mTiltHistoryIndex;
+ public SensorEventListenerImpl(Context context) {
+ // Load tilt tolerance configuration.
+ int[] tiltTolerance = context.getResources().getIntArray(
+ com.android.internal.R.array.config_autoRotationTiltTolerance);
+ if (tiltTolerance.length == 8) {
+ for (int i = 0; i < 4; i++) {
+ int min = tiltTolerance[i * 2];
+ int max = tiltTolerance[i * 2 + 1];
+ if (min >= -90 && min <= max && max <= 90) {
+ mTiltToleranceConfig[i][0] = min;
+ mTiltToleranceConfig[i][1] = max;
+ } else {
+ Slog.wtf(TAG, "config_autoRotationTiltTolerance contains invalid range: "
+ + "min=" + min + ", max=" + max);
+ }
+ }
+ } else {
+ Slog.wtf(TAG, "config_autoRotationTiltTolerance should have exactly 8 elements");
+ }
+ }
+
public int getProposedRotationLocked() {
return mProposedRotation;
}
@@ -451,6 +471,18 @@
pw.println(prefix + "mAccelerating=" + mAccelerating);
pw.println(prefix + "mOverhead=" + mOverhead);
pw.println(prefix + "mTouched=" + mTouched);
+ pw.print(prefix + "mTiltToleranceConfig=[");
+ for (int i = 0; i < 4; i++) {
+ if (i != 0) {
+ pw.print(", ");
+ }
+ pw.print("[");
+ pw.print(mTiltToleranceConfig[i][0]);
+ pw.print(", ");
+ pw.print(mTiltToleranceConfig[i][1]);
+ pw.print("]");
+ }
+ pw.println("]");
}
@Override
@@ -658,8 +690,8 @@
* Returns true if the tilt angle is acceptable for a given predicted rotation.
*/
private boolean isTiltAngleAcceptableLocked(int rotation, int tiltAngle) {
- return tiltAngle >= TILT_TOLERANCE[rotation][0]
- && tiltAngle <= TILT_TOLERANCE[rotation][1];
+ return tiltAngle >= mTiltToleranceConfig[rotation][0]
+ && tiltAngle <= mTiltToleranceConfig[rotation][1];
}
/**
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 4861050..1b63ca0 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -208,7 +208,7 @@
static final boolean DEBUG_APP_ORIENTATION = false;
static final boolean DEBUG_CONFIGURATION = false;
static final boolean DEBUG_APP_TRANSITIONS = false;
- static final boolean DEBUG_STARTING_WINDOW = true;
+ static final boolean DEBUG_STARTING_WINDOW = false;
static final boolean DEBUG_WALLPAPER = false;
static final boolean DEBUG_WALLPAPER_LIGHT = false || DEBUG_WALLPAPER;
static final boolean DEBUG_DRAG = false;
@@ -577,8 +577,10 @@
public SettingsObserver() {
super(new Handler());
ContentResolver resolver = mContext.getContentResolver();
- resolver.registerContentObserver(mShowImeWithHardKeyboardUri, false, this);
- resolver.registerContentObserver(mDisplayInversionEnabledUri, false, this);
+ resolver.registerContentObserver(mShowImeWithHardKeyboardUri, false, this,
+ UserHandle.USER_ALL);
+ resolver.registerContentObserver(mDisplayInversionEnabledUri, false, this,
+ UserHandle.USER_ALL);
}
@Override
@@ -5917,11 +5919,15 @@
if (mContext.getResources().getConfiguration().isScreenRound()
&& mContext.getResources().getBoolean(
com.android.internal.R.bool.config_windowShowCircularMask)) {
+ final int currentUserId;
+ synchronized(mWindowMap) {
+ currentUserId = mCurrentUserId;
+ }
// Device configuration calls for a circular display mask, but we only enable the mask
// if the accessibility color inversion feature is disabled, as the inverted mask
// causes artifacts.
int inversionState = Settings.Secure.getIntForUser(mContext.getContentResolver(),
- Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED, 0, mCurrentUserId);
+ Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED, 0, currentUserId);
int showMask = (inversionState == 1) ? 0 : 1;
Message m = mH.obtainMessage(H.SHOW_CIRCULAR_DISPLAY_MASK);
m.arg1 = showMask;
@@ -7422,10 +7428,10 @@
}
public void updateShowImeWithHardKeyboard() {
- final boolean showImeWithHardKeyboard = Settings.Secure.getIntForUser(
- mContext.getContentResolver(), Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD, 0,
- mCurrentUserId) == 1;
synchronized (mWindowMap) {
+ final boolean showImeWithHardKeyboard = Settings.Secure.getIntForUser(
+ mContext.getContentResolver(), Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD, 0,
+ mCurrentUserId) == 1;
if (mShowImeWithHardKeyboard != showImeWithHardKeyboard) {
mShowImeWithHardKeyboard = showImeWithHardKeyboard;
mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index feb0285..ea66a04 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -21,6 +21,9 @@
import static android.app.admin.DevicePolicyManager.WIPE_EXTERNAL_STORAGE;
import static android.app.admin.DevicePolicyManager.WIPE_RESET_PROTECTION_DATA;
import static android.content.pm.PackageManager.GET_UNINSTALLED_PACKAGES;
+import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
+import static org.xmlpull.v1.XmlPullParser.END_TAG;
+import static org.xmlpull.v1.XmlPullParser.TEXT;
import android.Manifest.permission;
import android.accessibilityservice.AccessibilityServiceInfo;
@@ -90,19 +93,19 @@
import android.security.IKeyChainService;
import android.security.KeyChain;
import android.security.KeyChain.KeyChainConnection;
-import android.text.TextUtils;
import android.service.persistentdata.PersistentDataBlockManager;
+import android.text.TextUtils;
import android.util.Log;
import android.util.PrintWriterPrinter;
import android.util.Printer;
import android.util.Slog;
import android.util.SparseArray;
import android.util.Xml;
+import android.view.IWindowManager;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.IAccessibilityManager;
import android.view.inputmethod.InputMethodInfo;
import android.view.inputmethod.InputMethodManager;
-import android.view.IWindowManager;
import com.android.internal.R;
import com.android.internal.os.storage.ExternalStorageFormatter;
@@ -117,11 +120,6 @@
import com.android.server.devicepolicy.DevicePolicyManagerService.ActiveAdmin.TrustAgentInfo;
import org.xmlpull.v1.XmlPullParser;
-
-import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
-import static org.xmlpull.v1.XmlPullParser.END_TAG;
-import static org.xmlpull.v1.XmlPullParser.TEXT;
-
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;
@@ -178,6 +176,7 @@
= "com.android.server.ACTION_EXPIRED_PASSWORD_NOTIFICATION";
private static final int MONITORING_CERT_NOTIFICATION_ID = R.string.ssl_ca_cert_warning;
+ private static final int PROFILE_WIPED_NOTIFICATION_ID = 1001;
private static final boolean DBG = false;
@@ -354,6 +353,7 @@
if (DBG) Slog.v(LOG_TAG, "Sending password expiration notifications for action "
+ action + " for user " + userHandle);
mHandler.post(new Runnable() {
+ @Override
public void run() {
handlePasswordExpirationNotification(userHandle);
}
@@ -1929,6 +1929,7 @@
* @param adminReceiver The admin to add
* @param refreshing true = update an active admin, no error
*/
+ @Override
public void setActiveAdmin(ComponentName adminReceiver, boolean refreshing, int userHandle) {
if (!mHasFeature) {
return;
@@ -1980,6 +1981,7 @@
}
}
+ @Override
public boolean isAdminActive(ComponentName adminReceiver, int userHandle) {
if (!mHasFeature) {
return false;
@@ -2002,6 +2004,7 @@
}
}
+ @Override
public boolean hasGrantedPolicy(ComponentName adminReceiver, int policyId, int userHandle) {
if (!mHasFeature) {
return false;
@@ -2016,6 +2019,7 @@
}
}
+ @Override
@SuppressWarnings("unchecked")
public List<ComponentName> getActiveAdmins(int userHandle) {
if (!mHasFeature) {
@@ -2037,6 +2041,7 @@
}
}
+ @Override
public boolean packageHasActiveAdmins(String packageName, int userHandle) {
if (!mHasFeature) {
return false;
@@ -2054,6 +2059,7 @@
}
}
+ @Override
public void removeActiveAdmin(ComponentName adminReceiver, int userHandle) {
if (!mHasFeature) {
return;
@@ -2081,6 +2087,7 @@
}
}
+ @Override
public void setPasswordQuality(ComponentName who, int quality) {
if (!mHasFeature) {
return;
@@ -2099,6 +2106,7 @@
}
}
+ @Override
public int getPasswordQuality(ComponentName who, int userHandle) {
if (!mHasFeature) {
return DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
@@ -2128,6 +2136,7 @@
}
}
+ @Override
public void setPasswordMinimumLength(ComponentName who, int length) {
if (!mHasFeature) {
return;
@@ -2144,6 +2153,7 @@
}
}
+ @Override
public int getPasswordMinimumLength(ComponentName who, int userHandle) {
if (!mHasFeature) {
return 0;
@@ -2173,6 +2183,7 @@
}
}
+ @Override
public void setPasswordHistoryLength(ComponentName who, int length) {
if (!mHasFeature) {
return;
@@ -2189,6 +2200,7 @@
}
}
+ @Override
public int getPasswordHistoryLength(ComponentName who, int userHandle) {
if (!mHasFeature) {
return 0;
@@ -2218,6 +2230,7 @@
}
}
+ @Override
public void setPasswordExpirationTimeout(ComponentName who, long timeout) {
if (!mHasFeature) {
return;
@@ -2247,6 +2260,7 @@
* Return a single admin's expiration cycle time, or the min of all cycle times.
* Returns 0 if not configured.
*/
+ @Override
public long getPasswordExpirationTimeout(ComponentName who, int userHandle) {
if (!mHasFeature) {
return 0L;
@@ -2373,6 +2387,7 @@
return timeout;
}
+ @Override
public long getPasswordExpiration(ComponentName who, int userHandle) {
if (!mHasFeature) {
return 0L;
@@ -2383,6 +2398,7 @@
}
}
+ @Override
public void setPasswordMinimumUpperCase(ComponentName who, int length) {
if (!mHasFeature) {
return;
@@ -2399,6 +2415,7 @@
}
}
+ @Override
public int getPasswordMinimumUpperCase(ComponentName who, int userHandle) {
if (!mHasFeature) {
return 0;
@@ -2428,6 +2445,7 @@
}
}
+ @Override
public void setPasswordMinimumLowerCase(ComponentName who, int length) {
Preconditions.checkNotNull(who, "ComponentName is null");
final int userHandle = UserHandle.getCallingUserId();
@@ -2441,6 +2459,7 @@
}
}
+ @Override
public int getPasswordMinimumLowerCase(ComponentName who, int userHandle) {
if (!mHasFeature) {
return 0;
@@ -2470,6 +2489,7 @@
}
}
+ @Override
public void setPasswordMinimumLetters(ComponentName who, int length) {
if (!mHasFeature) {
return;
@@ -2486,6 +2506,7 @@
}
}
+ @Override
public int getPasswordMinimumLetters(ComponentName who, int userHandle) {
if (!mHasFeature) {
return 0;
@@ -2518,6 +2539,7 @@
}
}
+ @Override
public void setPasswordMinimumNumeric(ComponentName who, int length) {
if (!mHasFeature) {
return;
@@ -2534,6 +2556,7 @@
}
}
+ @Override
public int getPasswordMinimumNumeric(ComponentName who, int userHandle) {
if (!mHasFeature) {
return 0;
@@ -2566,6 +2589,7 @@
}
}
+ @Override
public void setPasswordMinimumSymbols(ComponentName who, int length) {
if (!mHasFeature) {
return;
@@ -2582,6 +2606,7 @@
}
}
+ @Override
public int getPasswordMinimumSymbols(ComponentName who, int userHandle) {
if (!mHasFeature) {
return 0;
@@ -2614,6 +2639,7 @@
}
}
+ @Override
public void setPasswordMinimumNonLetter(ComponentName who, int length) {
if (!mHasFeature) {
return;
@@ -2630,6 +2656,7 @@
}
}
+ @Override
public int getPasswordMinimumNonLetter(ComponentName who, int userHandle) {
if (!mHasFeature) {
return 0;
@@ -2662,6 +2689,7 @@
}
}
+ @Override
public boolean isActivePasswordSufficient(int userHandle) {
if (!mHasFeature) {
return true;
@@ -2696,6 +2724,7 @@
}
}
+ @Override
public int getCurrentFailedPasswordAttempts(int userHandle) {
synchronized (this) {
// This API can only be called by an active device admin,
@@ -2712,6 +2741,7 @@
}
}
+ @Override
public void setMaximumFailedPasswordsForWipe(ComponentName who, int num) {
if (!mHasFeature) {
return;
@@ -2786,6 +2816,7 @@
return strictestAdmin;
}
+ @Override
public boolean resetPassword(String passwordOrNull, int flags) {
if (!mHasFeature) {
return false;
@@ -2938,6 +2969,7 @@
}
}
+ @Override
public boolean getDoNotAskCredentialsOnBoot() {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.QUERY_DO_NOT_ASK_CREDENTIALS_ON_BOOT, null);
@@ -2947,6 +2979,7 @@
}
}
+ @Override
public void setMaximumTimeToLock(ComponentName who, long timeMs) {
if (!mHasFeature) {
return;
@@ -2988,6 +3021,7 @@
}
}
+ @Override
public long getMaximumTimeToLock(ComponentName who, int userHandle) {
if (!mHasFeature) {
return 0;
@@ -3020,6 +3054,7 @@
}
}
+ @Override
public void lockNow() {
if (!mHasFeature) {
return;
@@ -3129,7 +3164,7 @@
}
@Override
- public void uninstallCaCert(ComponentName admin, String alias) {
+ public void uninstallCaCerts(ComponentName admin, String[] aliases) {
enforceCanManageCaCerts(admin);
final UserHandle userHandle = new UserHandle(UserHandle.getCallingUserId());
@@ -3137,7 +3172,9 @@
try {
final KeyChainConnection keyChainConnection = KeyChain.bindAsUser(mContext, userHandle);
try {
- keyChainConnection.getService().deleteCaCertificate(alias);
+ for (int i = 0 ; i < aliases.length; i++) {
+ keyChainConnection.getService().deleteCaCertificate(aliases[i]);
+ }
} catch (RemoteException e) {
Log.e(LOG_TAG, "from CaCertUninstaller: ", e);
} finally {
@@ -3334,14 +3371,19 @@
wipeDataLocked(wipeExtRequested, reason);
} else {
mHandler.post(new Runnable() {
+ @Override
public void run() {
try {
IActivityManager am = ActivityManagerNative.getDefault();
if (am.getCurrentUser().id == userHandle) {
am.switchUser(UserHandle.USER_OWNER);
}
+
+ boolean isManagedProfile = isManagedProfile(userHandle);
if (!mUserManager.removeUser(userHandle)) {
Slog.w(LOG_TAG, "Couldn't remove user " + userHandle);
+ } else if (isManagedProfile) {
+ sendWipeProfileNotification();
}
} catch (RemoteException re) {
// Shouldn't happen
@@ -3351,6 +3393,19 @@
}
}
+ private void sendWipeProfileNotification() {
+ String contentText = mContext.getString(R.string.work_profile_deleted_description_dpm_wipe);
+ Notification notification = new Notification.Builder(mContext)
+ .setSmallIcon(android.R.drawable.stat_sys_warning)
+ .setContentTitle(mContext.getString(R.string.work_profile_deleted))
+ .setContentText(contentText)
+ .setColor(mContext.getColor(R.color.system_notification_accent_color))
+ .setStyle(new Notification.BigTextStyle().bigText(contentText))
+ .build();
+ getNotificationManager().notify(PROFILE_WIPED_NOTIFICATION_ID, notification);
+ }
+
+ @Override
public void getRemoveWarning(ComponentName comp, final RemoteCallback result, int userHandle) {
if (!mHasFeature) {
return;
@@ -3384,6 +3439,7 @@
}
}
+ @Override
public void setActivePasswordState(int quality, int length, int letters, int uppercase,
int lowercase, int numbers, int symbols, int nonletter, int userHandle) {
if (!mHasFeature) {
@@ -3453,6 +3509,7 @@
}
}
+ @Override
public void reportFailedPasswordAttempt(int userHandle) {
enforceCrossUserPermission(userHandle);
enforceNotManagedProfile(userHandle, "report failed password attempt");
@@ -3494,6 +3551,7 @@
}
}
+ @Override
public void reportSuccessfulPasswordAttempt(int userHandle) {
enforceCrossUserPermission(userHandle);
mContext.enforceCallingOrSelfPermission(
@@ -3519,6 +3577,7 @@
}
}
+ @Override
public ComponentName setGlobalProxy(ComponentName who, String proxySpec,
String exclusionList) {
if (!mHasFeature) {
@@ -3573,6 +3632,7 @@
}
}
+ @Override
public ComponentName getGlobalProxyAdmin(int userHandle) {
if (!mHasFeature) {
return null;
@@ -3596,6 +3656,7 @@
return null;
}
+ @Override
public void setRecommendedGlobalProxy(ComponentName who, ProxyInfo proxyInfo) {
synchronized (this) {
getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
@@ -3657,6 +3718,7 @@
* Set the storage encryption request for a single admin. Returns the new total request
* status (for all admins).
*/
+ @Override
public int setStorageEncryption(ComponentName who, boolean encrypt) {
if (!mHasFeature) {
return DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED;
@@ -3709,6 +3771,7 @@
* Get the current storage encryption request status for a given admin, or aggregate of all
* active admins.
*/
+ @Override
public boolean getStorageEncryption(ComponentName who, int userHandle) {
if (!mHasFeature) {
return false;
@@ -3738,6 +3801,7 @@
/**
* Get the current encryption status of the device.
*/
+ @Override
public int getStorageEncryptionStatus(int userHandle) {
if (!mHasFeature) {
// Ok to return current status.
@@ -3792,6 +3856,7 @@
/**
* Set whether the screen capture is disabled for the user managed by the specified admin.
*/
+ @Override
public void setScreenCaptureDisabled(ComponentName who, boolean disabled) {
if (!mHasFeature) {
return;
@@ -3813,6 +3878,7 @@
* Returns whether or not screen capture is disabled for a given admin, or disabled for any
* active admin (if given admin is null).
*/
+ @Override
public boolean getScreenCaptureDisabled(ComponentName who, int userHandle) {
if (!mHasFeature) {
return false;
@@ -3849,6 +3915,7 @@
/**
* Set whether auto time is required by the specified admin (must be device owner).
*/
+ @Override
public void setAutoTimeRequired(ComponentName who, boolean required) {
if (!mHasFeature) {
return;
@@ -3879,6 +3946,7 @@
/**
* Returns whether or not auto time is required by the device owner.
*/
+ @Override
public boolean getAutoTimeRequired() {
if (!mHasFeature) {
return false;
@@ -3899,6 +3967,7 @@
/**
* Disables all device cameras according to the specified admin.
*/
+ @Override
public void setCameraDisabled(ComponentName who, boolean disabled) {
if (!mHasFeature) {
return;
@@ -3920,6 +3989,7 @@
* Gets whether or not all device cameras are disabled for a given admin, or disabled for any
* active admins.
*/
+ @Override
public boolean getCameraDisabled(ComponentName who, int userHandle) {
if (!mHasFeature) {
return false;
@@ -3946,6 +4016,7 @@
/**
* Selectively disable keyguard features.
*/
+ @Override
public void setKeyguardDisabledFeatures(ComponentName who, int which) {
if (!mHasFeature) {
return;
@@ -3970,6 +4041,7 @@
* Gets the disabled state for features in keyguard for the given admin,
* or the aggregate of all active admins if who is null.
*/
+ @Override
public int getKeyguardDisabledFeatures(ComponentName who, int userHandle) {
if (!mHasFeature) {
return 0;
@@ -4733,6 +4805,7 @@
}
}
+ @Override
public void setTrustAgentConfiguration(ComponentName admin, ComponentName agent,
PersistableBundle args) {
if (!mHasFeature) {
@@ -4751,6 +4824,7 @@
}
}
+ @Override
public List<PersistableBundle> getTrustAgentConfiguration(ComponentName admin,
ComponentName agent, int userHandle) {
if (!mHasFeature) {
@@ -4832,6 +4906,7 @@
}
}
+ @Override
public void addCrossProfileIntentFilter(ComponentName who, IntentFilter filter, int flags) {
Preconditions.checkNotNull(who, "ComponentName is null");
int callingUserId = UserHandle.getCallingUserId();
@@ -4857,6 +4932,7 @@
}
}
+ @Override
public void clearCrossProfileIntentFilters(ComponentName who) {
Preconditions.checkNotNull(who, "ComponentName is null");
int callingUserId = UserHandle.getCallingUserId();
@@ -5777,6 +5853,7 @@
* This function can only be called by the device owner.
* @param packages The list of packages allowed to enter lock task mode.
*/
+ @Override
public void setLockTaskPackages(ComponentName who, String[] packages)
throws SecurityException {
Preconditions.checkNotNull(who, "ComponentName is null");
@@ -5800,6 +5877,7 @@
/**
* This function returns the list of components allowed to start the task lock mode.
*/
+ @Override
public String[] getLockTaskPackages(ComponentName who) {
Preconditions.checkNotNull(who, "ComponentName is null");
synchronized (this) {
@@ -5820,6 +5898,7 @@
* lock task mode.
* @param pkg The package to check
*/
+ @Override
public boolean isLockTaskPermitted(String pkg) {
// Get current user's devicepolicy
int uid = Binder.getCallingUid();
@@ -5973,40 +6052,6 @@
}
@Override
- public void sendDeviceInitializerStatus(int statusCode, String description) {
- synchronized (this) {
- String packageName = getDeviceInitializer();
- if (packageName == null) {
- throw new SecurityException("No device initializers");
- }
- UserHandle callingUser = Binder.getCallingUserHandle();
- int deviceInitializerUid = -1;
- try {
- deviceInitializerUid = mContext.getPackageManager().getPackageUid(
- packageName, callingUser.getIdentifier());
- } catch (NameNotFoundException e) {
- throw new SecurityException(e);
- }
- if (Binder.getCallingUid() != deviceInitializerUid) {
- throw new SecurityException("Caller must be a device initializer");
- }
- long id = Binder.clearCallingIdentity();
- try {
- Intent intent = new Intent(
- DevicePolicyManager.ACTION_SEND_DEVICE_INITIALIZER_STATUS);
- intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_INITIALIZER_STATUS_CODE,
- statusCode);
- intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_INITIALIZER_STATUS_DESCRIPTION,
- description);
- mContext.sendBroadcastAsUser(intent, callingUser,
- android.Manifest.permission.RECEIVE_DEVICE_INITIALIZER_STATUS);
- } finally {
- restoreCallingIdentity(id);
- }
- }
- }
-
- @Override
public boolean setKeyguardDisabled(ComponentName who, boolean disabled) {
Preconditions.checkNotNull(who, "ComponentName is null");
synchronized (this) {
diff --git a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
index 56f1d48c..bb0a36f 100644
--- a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
@@ -48,6 +48,7 @@
import android.net.NetworkAgent;
import android.net.NetworkCapabilities;
import android.net.NetworkConfig;
+import android.net.NetworkFactory;
import android.net.NetworkInfo;
import android.net.NetworkInfo.DetailedState;
import android.net.NetworkMisc;
@@ -55,6 +56,7 @@
import android.net.RouteInfo;
import android.os.ConditionVariable;
import android.os.Handler;
+import android.os.HandlerThread;
import android.os.Looper;
import android.os.INetworkManagementService;
import android.test.AndroidTestCase;
@@ -68,6 +70,7 @@
import java.net.InetAddress;
import java.util.concurrent.Future;
+import java.util.concurrent.atomic.AtomicBoolean;
/**
* Tests for {@link ConnectivityService}.
@@ -224,6 +227,31 @@
}
}
+ private static class MockNetworkFactory extends NetworkFactory {
+ final AtomicBoolean mNetworkStarted = new AtomicBoolean(false);
+
+ public MockNetworkFactory(Looper looper, Context context, String logTag,
+ NetworkCapabilities filter) {
+ super(looper, context, logTag, filter);
+ }
+
+ public int getMyRequestCount() {
+ return getRequestCount();
+ }
+
+ protected void startNetwork() {
+ mNetworkStarted.set(true);
+ }
+
+ protected void stopNetwork() {
+ mNetworkStarted.set(false);
+ }
+
+ public boolean getMyStartRequested() {
+ return mNetworkStarted.get();
+ }
+ }
+
private class WrappedConnectivityService extends ConnectivityService {
public WrappedConnectivityService(Context context, INetworkManagementService netManager,
INetworkStatsService statsService, INetworkPolicyManager policyManager) {
@@ -235,6 +263,27 @@
// Prevent wrapped ConnectivityService from trying to write to SystemProperties.
return 0;
}
+
+ @Override
+ protected int reserveNetId() {
+ while (true) {
+ final int netId = super.reserveNetId();
+
+ // Don't overlap test NetIDs with real NetIDs as binding sockets to real networks
+ // can have odd side-effects, like network validations succeeding.
+ final Network[] networks = ConnectivityManager.from(getContext()).getAllNetworks();
+ boolean overlaps = false;
+ for (Network network : networks) {
+ if (netId == network.netId) {
+ overlaps = true;
+ break;
+ }
+ }
+ if (overlaps) continue;
+
+ return netId;
+ }
+ }
}
@Override
@@ -426,6 +475,71 @@
verifyNoNetwork();
}
+ @LargeTest
+ public void testNetworkFactoryRequests() throws Exception {
+ NetworkCapabilities filter = new NetworkCapabilities();
+ filter.addCapability(NET_CAPABILITY_INTERNET);
+ final HandlerThread handlerThread = new HandlerThread("testNetworkFactoryRequests");
+ handlerThread.start();
+ MockNetworkFactory testFactory = new MockNetworkFactory(handlerThread.getLooper(),
+ mServiceContext, "testFactory", filter);
+ testFactory.setScoreFilter(40);
+ testFactory.register();
+ try {
+ Thread.sleep(500);
+ } catch (Exception e) {}
+ assertEquals(1, testFactory.getMyRequestCount());
+ assertEquals(true, testFactory.getMyStartRequested());
+
+ // now bring in a higher scored network
+ MockNetworkAgent testAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+ ConditionVariable cv = waitForConnectivityBroadcasts(1);
+ testAgent.connect(true);
+ cv.block();
+ // part of the bringup makes another network request and then releases it
+ // wait for the release
+ try { Thread.sleep(500); } catch (Exception e) {}
+ assertEquals(1, testFactory.getMyRequestCount());
+ assertEquals(false, testFactory.getMyStartRequested());
+
+ // bring in a bunch of requests..
+ ConnectivityManager.NetworkCallback[] networkCallbacks =
+ new ConnectivityManager.NetworkCallback[10];
+ for (int i = 0; i< networkCallbacks.length; i++) {
+ networkCallbacks[i] = new ConnectivityManager.NetworkCallback();
+ NetworkRequest.Builder builder = new NetworkRequest.Builder();
+ builder.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
+ mCm.requestNetwork(builder.build(), networkCallbacks[i]);
+ }
+
+ try {
+ Thread.sleep(1000);
+ } catch (Exception e) {}
+ assertEquals(11, testFactory.getMyRequestCount());
+ assertEquals(false, testFactory.getMyStartRequested());
+
+ // remove the requests
+ for (int i = 0; i < networkCallbacks.length; i++) {
+ mCm.unregisterNetworkCallback(networkCallbacks[i]);
+ }
+ try {
+ Thread.sleep(500);
+ } catch (Exception e) {}
+ assertEquals(1, testFactory.getMyRequestCount());
+ assertEquals(false, testFactory.getMyStartRequested());
+
+ // drop the higher scored network
+ cv = waitForConnectivityBroadcasts(1);
+ testAgent.disconnect();
+ cv.block();
+ assertEquals(1, testFactory.getMyRequestCount());
+ assertEquals(true, testFactory.getMyStartRequested());
+
+ testFactory.unregister();
+ handlerThread.quit();
+ }
+
+
// @Override
// public void tearDown() throws Exception {
// super.tearDown();
diff --git a/services/usage/java/com/android/server/usage/AppIdleHistory.java b/services/usage/java/com/android/server/usage/AppIdleHistory.java
index 9d3db16..e3c0868 100644
--- a/services/usage/java/com/android/server/usage/AppIdleHistory.java
+++ b/services/usage/java/com/android/server/usage/AppIdleHistory.java
@@ -27,34 +27,27 @@
*/
public class AppIdleHistory {
- private SparseArray<ArrayMap<String,byte[]>> idleHistory = new SparseArray<>();
+ private SparseArray<ArrayMap<String,byte[]>> mIdleHistory = new SparseArray<>();
private long lastPeriod = 0;
private static final long ONE_MINUTE = 60 * 1000;
private static final int HISTORY_SIZE = 100;
private static final int FLAG_LAST_STATE = 2;
private static final int FLAG_PARTIAL_ACTIVE = 1;
- private static final long PERIOD_DURATION = UsageStatsService.DEBUG ? ONE_MINUTE
+ private static final long PERIOD_DURATION = UsageStatsService.COMPRESS_TIME ? ONE_MINUTE
: 60 * ONE_MINUTE;
public void addEntry(String packageName, int userId, boolean idle, long timeNow) {
- ArrayMap<String, byte[]> userHistory = idleHistory.get(userId);
- if (userHistory == null) {
- userHistory = new ArrayMap<>();
- idleHistory.put(userId, userHistory);
- }
- byte[] packageHistory = userHistory.get(packageName);
- if (packageHistory == null) {
- packageHistory = new byte[HISTORY_SIZE];
- userHistory.put(packageName, packageHistory);
- }
+ ArrayMap<String, byte[]> userHistory = getUserHistory(userId);
+ byte[] packageHistory = getPackageHistory(userHistory, packageName);
+
long thisPeriod = timeNow / PERIOD_DURATION;
// Has the period switched over? Slide all users' package histories
if (lastPeriod != 0 && lastPeriod < thisPeriod
&& (thisPeriod - lastPeriod) < HISTORY_SIZE - 1) {
int diff = (int) (thisPeriod - lastPeriod);
- final int NUSERS = idleHistory.size();
+ final int NUSERS = mIdleHistory.size();
for (int u = 0; u < NUSERS; u++) {
- userHistory = idleHistory.valueAt(u);
+ userHistory = mIdleHistory.valueAt(u);
for (byte[] history : userHistory.values()) {
// Shift left
System.arraycopy(history, diff, history, 0, HISTORY_SIZE - diff);
@@ -74,12 +67,36 @@
}
}
+ private ArrayMap<String, byte[]> getUserHistory(int userId) {
+ ArrayMap<String, byte[]> userHistory = mIdleHistory.get(userId);
+ if (userHistory == null) {
+ userHistory = new ArrayMap<>();
+ mIdleHistory.put(userId, userHistory);
+ }
+ return userHistory;
+ }
+
+ private byte[] getPackageHistory(ArrayMap<String, byte[]> userHistory, String packageName) {
+ byte[] packageHistory = userHistory.get(packageName);
+ if (packageHistory == null) {
+ packageHistory = new byte[HISTORY_SIZE];
+ userHistory.put(packageName, packageHistory);
+ }
+ return packageHistory;
+ }
+
public void removeUser(int userId) {
- idleHistory.remove(userId);
+ mIdleHistory.remove(userId);
+ }
+
+ public boolean isIdle(int userId, String packageName) {
+ ArrayMap<String, byte[]> userHistory = getUserHistory(userId);
+ byte[] packageHistory = getPackageHistory(userHistory, packageName);
+ return (packageHistory[HISTORY_SIZE - 1] & FLAG_LAST_STATE) == 0;
}
public void dump(IndentingPrintWriter idpw, int userId) {
- ArrayMap<String, byte[]> userHistory = idleHistory.get(userId);
+ ArrayMap<String, byte[]> userHistory = mIdleHistory.get(userId);
if (userHistory == null) return;
final int P = userHistory.size();
for (int p = 0; p < P; p++) {
diff --git a/services/usage/java/com/android/server/usage/IntervalStats.java b/services/usage/java/com/android/server/usage/IntervalStats.java
index a615675..1aa2978 100644
--- a/services/usage/java/com/android/server/usage/IntervalStats.java
+++ b/services/usage/java/com/android/server/usage/IntervalStats.java
@@ -110,7 +110,10 @@
usageStats.mLastEvent = eventType;
}
- usageStats.mLastTimeUsed = timeStamp;
+ if (eventType != UsageEvents.Event.SYSTEM_INTERACTION) {
+ usageStats.mLastTimeUsed = timeStamp;
+ }
+ usageStats.mLastTimeSystemUsed = timeStamp;
usageStats.mEndTimeStamp = timeStamp;
if (eventType == UsageEvents.Event.MOVE_TO_FOREGROUND) {
@@ -131,9 +134,9 @@
usageStats.mBeginIdleTime = timeStamp;
}
- void updateLastUsedTime(String packageName, long lastUsedTime) {
+ void updateSystemLastUsedTime(String packageName, long lastUsedTime) {
UsageStats usageStats = getOrCreateUsageStats(packageName);
- usageStats.mLastTimeUsed = lastUsedTime;
+ usageStats.mLastTimeSystemUsed = lastUsedTime;
}
void updateConfigurationStats(Configuration config, long timeStamp) {
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index 633aee8..8e1895e 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -43,6 +43,7 @@
import android.hardware.display.DisplayManager;
import android.net.Uri;
import android.os.BatteryManager;
+import android.os.BatteryStats;
import android.os.Binder;
import android.os.Environment;
import android.os.Handler;
@@ -60,12 +61,12 @@
import android.telephony.TelephonyManager;
import android.util.ArraySet;
import android.util.AtomicFile;
-import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
import android.view.Display;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.app.IBatteryStats;
import com.android.internal.os.BackgroundThread;
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.DeviceIdleController;
@@ -92,7 +93,7 @@
static final String TAG = "UsageStatsService";
static final boolean DEBUG = false;
- private static final boolean COMPRESS_TIME = false;
+ static final boolean COMPRESS_TIME = false;
private static final long TEN_SECONDS = 10 * 1000;
private static final long ONE_MINUTE = 60 * 1000;
@@ -129,6 +130,7 @@
IDeviceIdleController mDeviceIdleController;
private DisplayManager mDisplayManager;
private PowerManager mPowerManager;
+ private IBatteryStats mBatteryStats;
private final SparseArray<UserUsageStatsService> mUserState = new SparseArray<>();
private File mUsageStatsDir;
@@ -201,6 +203,8 @@
mAppWidgetManager = getContext().getSystemService(AppWidgetManager.class);
mDeviceIdleController = IDeviceIdleController.Stub.asInterface(
ServiceManager.getService(DeviceIdleController.SERVICE_NAME));
+ mBatteryStats = IBatteryStats.Stub.asInterface(
+ ServiceManager.getService(BatteryStats.SERVICE_NAME));
mDisplayManager = (DisplayManager) getContext().getSystemService(
Context.DISPLAY_SERVICE);
mPowerManager = getContext().getSystemService(PowerManager.class);
@@ -229,7 +233,7 @@
}
} else if (Intent.ACTION_USER_STARTED.equals(intent.getAction())) {
if (userId >=0) {
- postCheckIdleStates();
+ postCheckIdleStates(userId);
}
}
}
@@ -308,7 +312,7 @@
mLastAppIdleParoledTime = checkAndGetTimeLocked();
postNextParoleTimeout();
}
- postCheckIdleStates();
+ postCheckIdleStates(UserHandle.USER_ALL);
}
}
}
@@ -333,22 +337,25 @@
mHandler.sendEmptyMessageDelayed(MSG_PAROLE_END_TIMEOUT, DEFAULT_PAROLE_DURATION);
}
- void postCheckIdleStates() {
- mHandler.removeMessages(MSG_CHECK_IDLE_STATES);
- mHandler.sendEmptyMessage(MSG_CHECK_IDLE_STATES);
+ void postCheckIdleStates(int userId) {
+ mHandler.sendMessage(mHandler.obtainMessage(MSG_CHECK_IDLE_STATES, userId, 0));
}
- /** Check all running users' apps to see if they enter an idle state. */
- void checkIdleStates() {
- final int[] runningUsers;
+ /** Check all running users' or specified user's apps to see if they enter an idle state. */
+ void checkIdleStates(int checkUserId) {
+ final int[] userIds;
try {
- runningUsers = ActivityManagerNative.getDefault().getRunningUserIds();
+ if (checkUserId == UserHandle.USER_ALL) {
+ userIds = ActivityManagerNative.getDefault().getRunningUserIds();
+ } else {
+ userIds = new int[] { checkUserId };
+ }
} catch (RemoteException re) {
return;
}
- for (int i = 0; i < runningUsers.length; i++) {
- final int userId = runningUsers[i];
+ for (int i = 0; i < userIds.length; i++) {
+ final int userId = userIds[i];
List<PackageInfo> packages =
getContext().getPackageManager().getInstalledPackages(
PackageManager.GET_DISABLED_COMPONENTS
@@ -356,17 +363,22 @@
userId);
synchronized (mLock) {
final long timeNow = checkAndGetTimeLocked();
+ final long screenOnTime = getScreenOnTimeLocked(timeNow);
+ UserUsageStatsService service = getUserDataAndInitializeIfNeededLocked(userId,
+ timeNow);
final int packageCount = packages.size();
for (int p = 0; p < packageCount; p++) {
final String packageName = packages.get(p).packageName;
- final boolean isIdle = isAppIdleFiltered(packageName, userId, timeNow);
+ final boolean isIdle = isAppIdleFiltered(packageName, userId, service, timeNow,
+ screenOnTime);
mHandler.sendMessage(mHandler.obtainMessage(MSG_INFORM_LISTENERS,
userId, isIdle ? 1 : 0, packageName));
mAppIdleHistory.addEntry(packageName, userId, isIdle, timeNow);
}
}
}
- mHandler.sendEmptyMessageDelayed(MSG_CHECK_IDLE_STATES, mCheckIdleIntervalMillis);
+ mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_CHECK_IDLE_STATES, checkUserId, 0),
+ mCheckIdleIntervalMillis);
}
/** Check if it's been a while since last parole and let idle apps do some work */
@@ -387,6 +399,20 @@
}
}
+ private void notifyBatteryStats(String packageName, int userId, boolean idle) {
+ try {
+ int uid = AppGlobals.getPackageManager().getPackageUid(packageName, userId);
+ if (idle) {
+ mBatteryStats.noteEvent(BatteryStats.HistoryItem.EVENT_PACKAGE_INACTIVE,
+ packageName, uid);
+ } else {
+ mBatteryStats.noteEvent(BatteryStats.HistoryItem.EVENT_PACKAGE_ACTIVE,
+ packageName, uid);
+ }
+ } catch (RemoteException re) {
+ }
+ }
+
void updateDisplayLocked() {
boolean screenOn = mDisplayManager.getDisplay(Display.DEFAULT_DISPLAY).getState()
== Display.STATE_ON;
@@ -543,18 +569,20 @@
final UserUsageStatsService service =
getUserDataAndInitializeIfNeededLocked(userId, timeNow);
final long beginIdleTime = service.getBeginIdleTime(event.mPackage);
- final long lastUsedTime = service.getLastUsedTime(event.mPackage);
+ final long lastUsedTime = service.getSystemLastUsedTime(event.mPackage);
final boolean previouslyIdle = hasPassedIdleTimeoutLocked(beginIdleTime,
lastUsedTime, screenOnTime, timeNow);
- service.reportEvent(event, getScreenOnTimeLocked(timeNow));
+ service.reportEvent(event, screenOnTime);
// Inform listeners if necessary
if ((event.mEventType == Event.MOVE_TO_FOREGROUND
|| event.mEventType == Event.MOVE_TO_BACKGROUND
- || event.mEventType == Event.INTERACTION)) {
+ || event.mEventType == Event.SYSTEM_INTERACTION
+ || event.mEventType == Event.USER_INTERACTION)) {
if (previouslyIdle) {
// Slog.d(TAG, "Informing listeners of out-of-idle " + event.mPackage);
mHandler.sendMessage(mHandler.obtainMessage(MSG_INFORM_LISTENERS, userId,
/* idle = */ 0, event.mPackage));
+ notifyBatteryStats(event.mPackage, userId, false);
mAppIdleHistory.addEntry(event.mPackage, userId, false, timeNow);
}
}
@@ -575,17 +603,20 @@
final UserUsageStatsService service =
getUserDataAndInitializeIfNeededLocked(userId, timeNow);
final long beginIdleTime = service.getBeginIdleTime(packageName);
- final long lastUsedTime = service.getLastUsedTime(packageName);
+ final long lastUsedTime = service.getSystemLastUsedTime(packageName);
final boolean previouslyIdle = hasPassedIdleTimeoutLocked(beginIdleTime,
lastUsedTime, screenOnTime, timeNow);
service.setBeginIdleTime(packageName, deviceUsageTime);
- service.setLastUsedTime(packageName,
+ service.setSystemLastUsedTime(packageName,
timeNow - (idle ? DEFAULT_WALLCLOCK_APP_IDLE_THRESHOLD_MILLIS : 0) - 5000);
// Inform listeners if necessary
if (previouslyIdle != idle) {
// Slog.d(TAG, "Informing listeners of out-of-idle " + event.mPackage);
mHandler.sendMessage(mHandler.obtainMessage(MSG_INFORM_LISTENERS, userId,
/* idle = */ idle ? 1 : 0, packageName));
+ if (!idle) {
+ notifyBatteryStats(packageName, userId, idle);
+ }
mAppIdleHistory.addEntry(packageName, userId, idle, timeNow);
}
}
@@ -660,19 +691,20 @@
}
}
- private boolean isAppIdleUnfiltered(String packageName, int userId, long timeNow) {
+ private boolean isAppIdleUnfiltered(String packageName, UserUsageStatsService userService,
+ long timeNow, long screenOnTime) {
synchronized (mLock) {
- final long screenOnTime = getScreenOnTimeLocked(timeNow);
- final UserUsageStatsService service =
- getUserDataAndInitializeIfNeededLocked(userId, timeNow);
- long beginIdleTime = service.getBeginIdleTime(packageName);
- long lastUsedTime = service.getLastUsedTime(packageName);
- return hasPassedIdleTimeoutLocked(beginIdleTime, lastUsedTime, screenOnTime, timeNow);
+ long beginIdleTime = userService.getBeginIdleTime(packageName);
+ long lastUsedTime = userService.getSystemLastUsedTime(packageName);
+ return hasPassedIdleTimeoutLocked(beginIdleTime, lastUsedTime, screenOnTime,
+ timeNow);
}
}
/**
- * @param timestamp when the app was last used in device usage timebase
+ * @param beginIdleTime when the app was last used in device usage timebase
+ * @param lastUsedTime wallclock time of when the app was last used
+ * @param screenOnTime screen-on timebase time
* @param currentTime current time in device usage timebase
* @return whether it's been used far enough in the past to be considered inactive
*/
@@ -696,18 +728,29 @@
}
}
+ boolean isAppIdleFiltered(String packageName, int userId, long timeNow) {
+ final UserUsageStatsService userService;
+ final long screenOnTime;
+ synchronized (mLock) {
+ if (timeNow == -1) {
+ timeNow = checkAndGetTimeLocked();
+ }
+ userService = getUserDataAndInitializeIfNeededLocked(userId, timeNow);
+ screenOnTime = getScreenOnTimeLocked(timeNow);
+ }
+ return isAppIdleFiltered(packageName, userId, userService, timeNow, screenOnTime);
+ }
+
/**
* Checks if an app has been idle for a while and filters out apps that are excluded.
* It returns false if the current system state allows all apps to be considered active.
* This happens if the device is plugged in or temporarily allowed to make exceptions.
* Called by interface impls.
*/
- boolean isAppIdleFiltered(String packageName, int userId, long timeNow) {
+ private boolean isAppIdleFiltered(String packageName, int userId,
+ UserUsageStatsService userService, long timeNow, long screenOnTime) {
if (packageName == null) return false;
synchronized (mLock) {
- if (timeNow == -1) {
- timeNow = checkAndGetTimeLocked();
- }
// Temporary exemption, probably due to device charging or occasional allowance to
// be allowed to sync, etc.
if (mAppIdleParoled) {
@@ -735,7 +778,7 @@
return false;
}
- return isAppIdleUnfiltered(packageName, userId, timeNow);
+ return isAppIdleUnfiltered(packageName, userService, timeNow, screenOnTime);
}
void setAppIdle(String packageName, boolean idle, int userId) {
@@ -844,7 +887,7 @@
break;
case MSG_CHECK_IDLE_STATES:
- checkIdleStates();
+ checkIdleStates(msg.arg1);
break;
case MSG_CHECK_PAROLE_TIMEOUT:
@@ -884,7 +927,7 @@
UserHandle.USER_OWNER);
mCheckIdleIntervalMillis = Math.min(DEFAULT_CHECK_IDLE_INTERVAL,
mAppIdleDurationMillis / 4);
- postCheckIdleStates();
+ postCheckIdleStates(UserHandle.USER_ALL);
}
}
diff --git a/services/usage/java/com/android/server/usage/UsageStatsXmlV1.java b/services/usage/java/com/android/server/usage/UsageStatsXmlV1.java
index 0111201..f2ca3a4 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsXmlV1.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsXmlV1.java
@@ -55,6 +55,7 @@
// Time attributes stored as an offset of the beginTime.
private static final String LAST_TIME_ACTIVE_ATTR = "lastTimeActive";
+ private static final String LAST_TIME_ACTIVE_SYSTEM_ATTR = "lastTimeActiveSystem";
private static final String BEGIN_IDLE_TIME_ATTR = "beginIdleTime";
private static final String END_TIME_ATTR = "endTime";
private static final String TIME_ATTR = "time";
@@ -71,6 +72,16 @@
// Apply the offset to the beginTime to find the absolute time.
stats.mLastTimeUsed = statsOut.beginTime + XmlUtils.readLongAttribute(
parser, LAST_TIME_ACTIVE_ATTR);
+
+ final String lastTimeUsedSystem = parser.getAttributeValue(null,
+ LAST_TIME_ACTIVE_SYSTEM_ATTR);
+ if (TextUtils.isEmpty(lastTimeUsedSystem)) {
+ // If the field isn't present, use the old one.
+ stats.mLastTimeSystemUsed = stats.mLastTimeUsed;
+ } else {
+ stats.mLastTimeSystemUsed = statsOut.beginTime + Long.parseLong(lastTimeUsedSystem);
+ }
+
final String beginIdleTime = parser.getAttributeValue(null, BEGIN_IDLE_TIME_ATTR);
if (!TextUtils.isEmpty(beginIdleTime)) {
stats.mBeginIdleTime = Long.parseLong(beginIdleTime);
@@ -130,6 +141,8 @@
// Write the time offset.
XmlUtils.writeLongAttribute(xml, LAST_TIME_ACTIVE_ATTR,
usageStats.mLastTimeUsed - stats.beginTime);
+ XmlUtils.writeLongAttribute(xml, LAST_TIME_ACTIVE_SYSTEM_ATTR,
+ usageStats.mLastTimeSystemUsed - stats.beginTime);
XmlUtils.writeStringAttribute(xml, PACKAGE_ATTR, usageStats.mPackageName);
XmlUtils.writeLongAttribute(xml, TOTAL_TIME_ACTIVE_ATTR, usageStats.mTotalTimeInForeground);
diff --git a/services/usage/java/com/android/server/usage/UserUsageStatsService.java b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
index 7c00dae..b07b815 100644
--- a/services/usage/java/com/android/server/usage/UserUsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
@@ -157,7 +157,7 @@
if (pi.applicationInfo != null && (firstUpdate || pi.applicationInfo.isSystemApp())
&& getBeginIdleTime(packageName) == -1) {
for (IntervalStats stats : mCurrentStats) {
- stats.update(packageName, currentTimeMillis, Event.INTERACTION);
+ stats.update(packageName, currentTimeMillis, Event.SYSTEM_INTERACTION);
stats.updateBeginIdleTime(packageName, deviceUsageTime);
mStatsChanged = true;
}
@@ -199,7 +199,7 @@
if (currentDailyStats.events == null) {
currentDailyStats.events = new TimeSparseArray<>();
}
- if (event.mEventType != UsageEvents.Event.INTERACTION) {
+ if (event.mEventType != UsageEvents.Event.SYSTEM_INTERACTION) {
currentDailyStats.events.put(event.mTimeStamp, event);
}
@@ -226,9 +226,9 @@
notifyStatsChanged();
}
- void setLastUsedTime(String packageName, long lastUsedTime) {
+ void setSystemLastUsedTime(String packageName, long lastUsedTime) {
for (IntervalStats stats : mCurrentStats) {
- stats.updateLastUsedTime(packageName, lastUsedTime);
+ stats.updateSystemLastUsedTime(packageName, lastUsedTime);
}
notifyStatsChanged();
}
@@ -397,13 +397,13 @@
}
}
- long getLastUsedTime(String packageName) {
+ long getSystemLastUsedTime(String packageName) {
final IntervalStats yearly = mCurrentStats[UsageStatsManager.INTERVAL_YEARLY];
UsageStats packageUsage;
if ((packageUsage = yearly.packageStats.get(packageName)) == null) {
return -1;
} else {
- return packageUsage.getLastTimeUsed();
+ return packageUsage.getLastTimeSystemUsed();
}
}
@@ -586,8 +586,11 @@
for (int i = 0; i < pkgCount; i++) {
final UsageStats usageStats = pkgStats.valueAt(i);
pw.printPair("package", usageStats.mPackageName);
- pw.printPair("totalTime", formatElapsedTime(usageStats.mTotalTimeInForeground, prettyDates));
+ pw.printPair("totalTime",
+ formatElapsedTime(usageStats.mTotalTimeInForeground, prettyDates));
pw.printPair("lastTime", formatDateTime(usageStats.mLastTimeUsed, prettyDates));
+ pw.printPair("lastTimeSystem",
+ formatDateTime(usageStats.mLastTimeSystemUsed, prettyDates));
pw.printPair("inactiveTime",
formatElapsedTime(screenOnTime - usageStats.mBeginIdleTime, prettyDates));
pw.println();
@@ -596,8 +599,7 @@
pw.println("configurations");
pw.increaseIndent();
- final ArrayMap<Configuration, ConfigurationStats> configStats =
- stats.configurations;
+ final ArrayMap<Configuration, ConfigurationStats> configStats = stats.configurations;
final int configCount = configStats.size();
for (int i = 0; i < configCount; i++) {
final ConfigurationStats config = configStats.valueAt(i);
@@ -659,8 +661,10 @@
return "CONTINUE_PREVIOUS_DAY";
case UsageEvents.Event.CONFIGURATION_CHANGE:
return "CONFIGURATION_CHANGE";
- case UsageEvents.Event.INTERACTION:
- return "INTERACTION";
+ case UsageEvents.Event.SYSTEM_INTERACTION:
+ return "SYSTEM_INTERACTION";
+ case UsageEvents.Event.USER_INTERACTION:
+ return "USER_INTERACTION";
default:
return "UNKNOWN";
}
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index d6a7dd1..588f8c6 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -91,6 +91,7 @@
private static final int MSG_SYSTEM_READY = 3;
private static final int MSG_BOOT_COMPLETED = 4;
private static final int MSG_USER_SWITCHED = 5;
+ private static final int MSG_SET_USB_DATA_UNLOCKED = 6;
private static final int AUDIO_MODE_SOURCE = 1;
@@ -314,6 +315,7 @@
// current USB state
private boolean mConnected;
private boolean mConfigured;
+ private boolean mUsbDataUnlocked;
private String mCurrentFunctions;
private UsbAccessory mCurrentAccessory;
private int mUsbNotificationId;
@@ -350,7 +352,7 @@
SystemProperties.get(UsbManager.ADB_PERSISTENT_PROPERTY, "adb"),
UsbManager.USB_FUNCTION_ADB);
- mCurrentFunctions = mAdbEnabled ? "adb" : "none";
+ mCurrentFunctions = mAdbEnabled ? "adb" : UsbManager.USB_FUNCTION_MTP;
String state = FileUtils.readTextFile(new File(STATE_PATH), 0, null).trim();
updateState(state);
@@ -459,6 +461,15 @@
}
}
+ /**
+ * Stop and start the USB driver. This is needed to close all outstanding
+ * USB connections.
+ */
+ private void restartCurrentFunction() {
+ setUsbConfig("none");
+ setUsbConfig(mCurrentFunctions);
+ }
+
private void setEnabledFunctions(String functions) {
if (DEBUG) Slog.d(TAG, "setEnabledFunctions " + functions);
@@ -531,6 +542,7 @@
intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
intent.putExtra(UsbManager.USB_CONNECTED, mConnected);
intent.putExtra(UsbManager.USB_CONFIGURED, mConfigured);
+ intent.putExtra(UsbManager.USB_DATA_UNLOCKED, mUsbDataUnlocked);
if (mCurrentFunctions != null) {
String[] functions = mCurrentFunctions.split(",");
@@ -599,6 +611,10 @@
case MSG_UPDATE_STATE:
mConnected = (msg.arg1 == 1);
mConfigured = (msg.arg2 == 1);
+ if (!mConnected) {
+ // When a disconnect occurs, relock access to sensitive user data
+ mUsbDataUnlocked = false;
+ }
updateUsbNotification();
updateAdbNotification();
if (containsFunction(mCurrentFunctions,
@@ -621,6 +637,12 @@
String functions = (String)msg.obj;
setEnabledFunctions(functions);
break;
+ case MSG_SET_USB_DATA_UNLOCKED:
+ mUsbDataUnlocked = (msg.arg1 == 1);
+ updateUsbNotification();
+ updateUsbState();
+ restartCurrentFunction();
+ break;
case MSG_SYSTEM_READY:
setUsbConfig(mCurrentFunctions);
updatePersistentProperty();
@@ -676,7 +698,9 @@
int id = 0;
Resources r = mContext.getResources();
if (mConnected) {
- if (containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_MTP)) {
+ if (!mUsbDataUnlocked) {
+ id = com.android.internal.R.string.usb_charging_notification_title;
+ } else if (containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_MTP)) {
id = com.android.internal.R.string.usb_mtp_notification_title;
} else if (containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_PTP)) {
id = com.android.internal.R.string.usb_ptp_notification_title;
@@ -771,7 +795,7 @@
}
private String getDefaultFunctions() {
- return "none";
+ return UsbManager.USB_FUNCTION_MTP;
}
public void dump(FileDescriptor fd, PrintWriter pw) {
@@ -817,6 +841,16 @@
mHandler.sendMessage(MSG_SET_CURRENT_FUNCTIONS, functions);
}
+ public void setUsbDataUnlocked(boolean unlocked) {
+ if (DEBUG) Slog.d(TAG, "setUsbDataUnlocked(" + unlocked + ")");
+ mHandler.sendMessage(MSG_SET_USB_DATA_UNLOCKED, unlocked);
+ }
+
+ public boolean isUsbDataUnlocked() {
+ if (DEBUG) Slog.d(TAG, "isUsbDataUnlocked() -> " + mHandler.mUsbDataUnlocked);
+ return mHandler.mUsbDataUnlocked;
+ }
+
private void readOemUsbOverrideConfig() {
String[] configList = mContext.getResources().getStringArray(
com.android.internal.R.array.config_oemUsbModeOverride);
diff --git a/services/usb/java/com/android/server/usb/UsbService.java b/services/usb/java/com/android/server/usb/UsbService.java
index 51281a2..7a3426c 100644
--- a/services/usb/java/com/android/server/usb/UsbService.java
+++ b/services/usb/java/com/android/server/usb/UsbService.java
@@ -271,6 +271,18 @@
}
@Override
+ public void setUsbDataUnlocked(boolean unlocked) {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
+ mDeviceManager.setUsbDataUnlocked(unlocked);
+ }
+
+ @Override
+ public boolean isUsbDataUnlocked() {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
+ return mDeviceManager.isUsbDataUnlocked();
+ }
+
+ @Override
public void allowUsbDebugging(boolean alwaysAllow, String publicKey) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
mDeviceManager.allowUsbDebugging(alwaysAllow, publicKey);
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index 4cdf254..b0fca95 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -839,7 +839,8 @@
super(handler);
ContentResolver resolver = mContext.getContentResolver();
resolver.registerContentObserver(Settings.Secure.getUriFor(
- Settings.Secure.VOICE_INTERACTION_SERVICE), false, this);
+ Settings.Secure.VOICE_INTERACTION_SERVICE), false, this,
+ UserHandle.USER_ALL);
}
@Override public void onChange(boolean selfChange) {
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index a2e0706..e756a57 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -380,7 +380,7 @@
builder.append(" PROPERTY_HIGH_DEF_AUDIO");
}
if (hasProperty(properties, PROPERTY_EMERGENCY_CALLBACK_MODE)) {
- builder.append(" EMERGENCY_CALLBACK_MODE");
+ builder.append(" PROPERTY_EMERGENCY_CALLBACK_MODE");
}
builder.append("]");
return builder.toString();
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index 0042414..9a63aa3 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -27,6 +27,7 @@
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
+import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
import android.view.Surface;
@@ -442,8 +443,7 @@
private static final int MSG_SET_PAUSE_IMAGE = 11;
private static final int MSG_REMOVE_VIDEO_CALLBACK = 12;
- private final VideoProvider.VideoProviderHandler
- mMessageHandler = new VideoProvider.VideoProviderHandler();
+ private VideoProvider.VideoProviderHandler mMessageHandler;
private final VideoProvider.VideoProviderBinder mBinder;
/**
@@ -455,6 +455,14 @@
* Default handler used to consolidate binder method calls onto a single thread.
*/
private final class VideoProviderHandler extends Handler {
+ public VideoProviderHandler() {
+ super();
+ }
+
+ public VideoProviderHandler(Looper looper) {
+ super(looper);
+ }
+
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
@@ -586,6 +594,18 @@
public VideoProvider() {
mBinder = new VideoProvider.VideoProviderBinder();
+ mMessageHandler = new VideoProvider.VideoProviderHandler();
+ }
+
+ /**
+ * Creates an instance of the {@link VideoProvider}, specifying the looper to use.
+ *
+ * @param looper The looper.
+ * @hide
+ */
+ public VideoProvider(Looper looper) {
+ mBinder = new VideoProvider.VideoProviderBinder();
+ mMessageHandler = new VideoProvider.VideoProviderHandler(looper);
}
/**
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index b74b52d..da0c547 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -114,17 +114,12 @@
* (Some carriers require that emergency calls *not* be logged, presumably to avoid the risk of
* accidental redialing from the call log UI. This is a good idea, so the default here is
* false.)
- * <p>
- * TODO: on the other hand, it might still be useful to have some record of the emergency calls
- * you've made, or to be able to look up the exact date/time of an emergency call. So perhaps we
- * <b>should</b> log those calls, but instead fix the call log to disable the "call" button for
- * emergency numbers.
*/
public static final String
KEY_ALLOW_EMERGENCY_NUMBERS_IN_CALL_LOG_BOOL = "allow_emergency_numbers_in_call_log_bool";
/** If true, removes the Voice Privacy option from Call Settings */
- public static final String KEY_VOICE_PRIVACY_DISABLE_BOOL = "voice_privacy_disable_bool";
+ public static final String KEY_VOICE_PRIVACY_DISABLE_UI_BOOL = "voice_privacy_disable_ui_bool";
/** Control whether users can reach the carrier portions of Cellular Network Settings. */
public static final String
@@ -302,7 +297,7 @@
sDefaults.putBoolean(KEY_USE_HFA_FOR_PROVISIONING_BOOL, false);
sDefaults.putBoolean(KEY_USE_OTASP_FOR_PROVISIONING_BOOL, false);
sDefaults.putBoolean(KEY_VOICEMAIL_NOTIFICATION_PERSISTENT_BOOL, false);
- sDefaults.putBoolean(KEY_VOICE_PRIVACY_DISABLE_BOOL, false);
+ sDefaults.putBoolean(KEY_VOICE_PRIVACY_DISABLE_UI_BOOL, false);
sDefaults.putBoolean(KEY_WORLD_PHONE_BOOL, false);
sDefaults.putInt(KEY_VOLTE_REPLACEMENT_RAT_INT, 0);
sDefaults.putString(KEY_VVM_DESTINATION_NUMBER_STRING, "");
diff --git a/telephony/java/android/telephony/SignalStrength.java b/telephony/java/android/telephony/SignalStrength.java
index 7b58755..f02d109 100644
--- a/telephony/java/android/telephony/SignalStrength.java
+++ b/telephony/java/android/telephony/SignalStrength.java
@@ -469,7 +469,12 @@
}
/**
- * Get signal level as an int from 0..4
+ * Retrieve an abstract level value for the overall signal strength.
+ *
+ * @return a single integer from 0 to 4 representing the general signal quality.
+ * This may take into account many different radio technology inputs.
+ * 0 represents very poor signal strength
+ * while 4 represents a very strong signal strength.
*/
public int getLevel() {
int level;
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 12f1644..1cc275d 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -193,7 +193,7 @@
//
/**
- * Broadcast intent action indicating that the call state (cellular)
+ * Broadcast intent action indicating that the call state
* on the device has changed.
*
* <p>
@@ -2437,10 +2437,23 @@
public static final int CALL_STATE_OFFHOOK = 2;
/**
- * Returns a constant indicating the call state (cellular) on the device.
+ * Returns one of the following constants that represents the current state of all
+ * phone calls.
+ *
+ * {@link TelephonyManager#CALL_STATE_RINGING}
+ * {@link TelephonyManager#CALL_STATE_OFFHOOK}
+ * {@link TelephonyManager#CALL_STATE_IDLE}
*/
public int getCallState() {
- return getCallState(getDefaultSubscription());
+ try {
+ ITelecomService telecom = getTelecomService();
+ if (telecom != null) {
+ return telecom.getCallState();
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error calling ITelecomService#getCallState", e);
+ }
+ return CALL_STATE_IDLE;
}
/**
@@ -3488,13 +3501,13 @@
/**
* Values used to return status for hasCarrierPrivileges call.
*/
- /** @hide */
+ /** @hide */ @SystemApi
public static final int CARRIER_PRIVILEGE_STATUS_HAS_ACCESS = 1;
- /** @hide */
+ /** @hide */ @SystemApi
public static final int CARRIER_PRIVILEGE_STATUS_NO_ACCESS = 0;
- /** @hide */
+ /** @hide */ @SystemApi
public static final int CARRIER_PRIVILEGE_STATUS_RULES_NOT_LOADED = -1;
- /** @hide */
+ /** @hide */ @SystemApi
public static final int CARRIER_PRIVILEGE_STATUS_ERROR_LOADING_RULES = -2;
/**
diff --git a/telephony/java/com/android/internal/telephony/IMms.aidl b/telephony/java/com/android/internal/telephony/IMms.aidl
index 49ac400..fa5073e 100644
--- a/telephony/java/com/android/internal/telephony/IMms.aidl
+++ b/telephony/java/com/android/internal/telephony/IMms.aidl
@@ -34,8 +34,7 @@
* PDU format
* @param locationUrl the optional location url for where this message should be sent to
* @param configOverrides the carrier-specific messaging configuration values to override for
- * sending the message. See {@link android.telephony.MessagingConfigurationManager} for the
- * value names and types.
+ * sending the message. See {@link android.telephony.SmsManager} for the value names and types.
* @param sentIntent if not NULL this <code>PendingIntent</code> is
* broadcast when the message is successfully sent, or failed
*/
@@ -51,8 +50,8 @@
* from the MMS WAP push notification
* @param contentUri a contentUri to which the downloaded MMS message will be written
* @param configOverrides the carrier-specific messaging configuration values to override for
- * downloading the message. See {@link android.telephony.MessagingConfigurationManager} for the
- * value names and types.
+ * downloading the message. See {@link android.telephony.SmsManager} for the value names and
+ * types.
* @param downloadedIntent if not NULL this <code>PendingIntent</code> is
* broadcast when the message is downloaded, or the download is failed
*/
@@ -165,8 +164,7 @@
* @param callingPkg the package name of the calling app
* @param messageUri the URI of the stored message
* @param configOverrides the carrier-specific messaging configuration values to override for
- * sending the message. See {@link android.telephony.MessagingConfigurationManager} for the
- * value names and types.
+ * sending the message. See {@link android.telephony.SmsManager} for the value names and types.
* @param sentIntent if not NULL this <code>PendingIntent</code> is
* broadcast when the message is successfully sent, or failed
*/
diff --git a/test-runner/src/android/test/mock/MockPackageManager.java b/test-runner/src/android/test/mock/MockPackageManager.java
index 3b7aa9f..ac92dc0 100644
--- a/test-runner/src/android/test/mock/MockPackageManager.java
+++ b/test-runner/src/android/test/mock/MockPackageManager.java
@@ -224,6 +224,18 @@
throw new UnsupportedOperationException();
}
+ /** @hide */
+ @Override
+ public void addOnPermissionsChangeListener(OnPermissionsChangedListener listener) {
+ throw new UnsupportedOperationException();
+ }
+
+ /** @hide */
+ @Override
+ public void removeOnPermissionsChangeListener(OnPermissionsChangedListener listener) {
+ throw new UnsupportedOperationException();
+ }
+
@Override
public int checkSignatures(String pkg1, String pkg2) {
throw new UnsupportedOperationException();
diff --git a/tests/UsageStatsTest/src/com/android/tests/usagestats/UsageLogActivity.java b/tests/UsageStatsTest/src/com/android/tests/usagestats/UsageLogActivity.java
index 8e6daea..05cac10 100644
--- a/tests/UsageStatsTest/src/com/android/tests/usagestats/UsageLogActivity.java
+++ b/tests/UsageStatsTest/src/com/android/tests/usagestats/UsageLogActivity.java
@@ -28,8 +28,6 @@
import android.widget.BaseAdapter;
import android.widget.TextView;
-import java.util.ArrayList;
-
public class UsageLogActivity extends ListActivity implements Runnable {
private static final long USAGE_STATS_PERIOD = 1000 * 60 * 60 * 24 * 14;
@@ -166,8 +164,8 @@
case UsageEvents.Event.CONFIGURATION_CHANGE:
return "Config change";
- case UsageEvents.Event.INTERACTION:
- return "Interaction";
+ case UsageEvents.Event.USER_INTERACTION:
+ return "User Interaction";
default:
return "Unknown: " + eventType;
diff --git a/tools/layoutlib/bridge/src/android/view/BridgeInflater.java b/tools/layoutlib/bridge/src/android/view/BridgeInflater.java
index 32ee9e8..6767a07 100644
--- a/tools/layoutlib/bridge/src/android/view/BridgeInflater.java
+++ b/tools/layoutlib/bridge/src/android/view/BridgeInflater.java
@@ -22,6 +22,7 @@
import com.android.ide.common.rendering.api.ResourceReference;
import com.android.ide.common.rendering.api.ResourceValue;
import com.android.layoutlib.bridge.Bridge;
+import com.android.layoutlib.bridge.BridgeConstants;
import com.android.layoutlib.bridge.android.BridgeContext;
import com.android.layoutlib.bridge.android.BridgeXmlBlockParser;
import com.android.layoutlib.bridge.impl.ParserFactory;
@@ -234,6 +235,13 @@
if (viewKey != null) {
bc.addViewKey(view, viewKey);
}
+ String scrollPos = attrs.getAttributeValue(BridgeConstants.NS_RESOURCES, "scrollY");
+ if (scrollPos != null) {
+ if (scrollPos.endsWith("px")) {
+ int value = Integer.parseInt(scrollPos.substring(0, scrollPos.length() - 2));
+ bc.setScrollYPos(view, value);
+ }
+ }
}
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
index a2518fa..6be5a95 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
@@ -37,6 +37,7 @@
import org.xmlpull.v1.XmlPullParserException;
import android.annotation.Nullable;
+import android.annotation.NonNull;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentResolver;
@@ -125,6 +126,7 @@
private final LayoutlibCallback mLayoutlibCallback;
private final WindowManager mWindowManager;
private final DisplayManager mDisplayManager;
+ private final HashMap<View, Integer> mScrollYPos = new HashMap<View, Integer>();
private Resources.Theme mTheme;
@@ -1738,4 +1740,13 @@
// pass
return new File[0];
}
+
+ public void setScrollYPos(@NonNull View view, int scrollPos) {
+ mScrollYPos.put(view, scrollPos);
+ }
+
+ public int getScrollYPos(@NonNull View view) {
+ Integer pos = mScrollYPos.get(view);
+ return pos != null ? pos : 0;
+ }
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/support/DesignLibUtil.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/support/DesignLibUtil.java
new file mode 100644
index 0000000..0426907
--- /dev/null
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/support/DesignLibUtil.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.layoutlib.bridge.android.support;
+
+import com.android.ide.common.rendering.api.LayoutLog;
+import com.android.layoutlib.bridge.Bridge;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.view.View;
+
+import java.lang.reflect.Method;
+
+import static com.android.layoutlib.bridge.util.ReflectionUtils.ReflectionException;
+import static com.android.layoutlib.bridge.util.ReflectionUtils.getMethod;
+import static com.android.layoutlib.bridge.util.ReflectionUtils.invoke;
+
+/**
+ * Utility class for working with the design support lib.
+ */
+public class DesignLibUtil {
+
+ private static final String PKG_PREFIX = "android.support.design.widget.";
+ public static final String CN_COORDINATOR_LAYOUT = PKG_PREFIX + "CoordinatorLayout";
+ public static final String CN_APPBAR_LAYOUT = PKG_PREFIX + "AppBarLayout";
+ public static final String CN_COLLAPSING_TOOLBAR_LAYOUT =
+ PKG_PREFIX + "CollapsingToolbarLayout";
+ public static final String CN_TOOLBAR = "android.support.v7.widget.Toolbar";
+ public static final int SCROLL_AXIS_VERTICAL = 1 << 1;
+
+ /**
+ * Tries to set the title of a view. This is used to set the title in a
+ * CollapsingToolbarLayout.
+ * <p/>
+ * Any exceptions thrown during the process are logged in {@link Bridge#getLog()}
+ */
+ public static void setTitle(@NonNull View view, @Nullable String title) {
+ if (title == null) {
+ return;
+ }
+ try {
+ Method setTitle = getMethod(view.getClass(), "setTitle", CharSequence.class);
+ if (setTitle != null) {
+ invoke(setTitle, view, title);
+ }
+ } catch (ReflectionException e) {
+ Bridge.getLog().warning(LayoutLog.TAG_INFO,
+ "Error occurred while trying to set title.", e);
+ }
+ }
+}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
index ff77b58..d571d35 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
@@ -44,6 +44,7 @@
import com.android.layoutlib.bridge.android.BridgeLayoutParamsMapAttributes;
import com.android.layoutlib.bridge.android.BridgeXmlBlockParser;
import com.android.layoutlib.bridge.android.RenderParamsFlags;
+import com.android.layoutlib.bridge.android.support.DesignLibUtil;
import com.android.layoutlib.bridge.android.support.RecyclerViewUtil;
import com.android.layoutlib.bridge.bars.AppCompatActionBar;
import com.android.layoutlib.bridge.bars.BridgeActionBar;
@@ -148,7 +149,6 @@
private int mTitleBarSize;
private int mActionBarSize;
-
// information being returned through the API
private BufferedImage mImage;
private List<ViewInfo> mViewInfoList;
@@ -424,6 +424,8 @@
// post-inflate process. For now this supports TabHost/TabWidget
postInflateProcess(view, params.getLayoutlibCallback(), isPreference ? view : null);
+ setActiveToolbar(view, context, params);
+
// get the background drawable
if (mWindowBackground != null) {
Drawable d = ResourceHelper.getDrawable(mWindowBackground, context);
@@ -544,6 +546,8 @@
// now do the layout.
mViewRoot.layout(0, 0, mMeasuredScreenWidth, mMeasuredScreenHeight);
+ handleScrolling(mViewRoot);
+
if (params.isLayoutOnly()) {
// delete the canvas and image to reset them on the next full rendering
mImage = null;
@@ -1350,6 +1354,99 @@
}
/**
+ * If the root layout is a CoordinatorLayout with an AppBar:
+ * Set the title of the AppBar to the title of the activity context.
+ */
+ private void setActiveToolbar(View view, BridgeContext context, SessionParams params) {
+ View coordinatorLayout = findChildView(view, DesignLibUtil.CN_COORDINATOR_LAYOUT);
+ if (coordinatorLayout == null) {
+ return;
+ }
+ View appBar = findChildView(coordinatorLayout, DesignLibUtil.CN_APPBAR_LAYOUT);
+ if (appBar == null) {
+ return;
+ }
+ ViewGroup collapsingToolbar =
+ (ViewGroup) findChildView(appBar, DesignLibUtil.CN_COLLAPSING_TOOLBAR_LAYOUT);
+ if (collapsingToolbar == null) {
+ return;
+ }
+ if (!hasToolbar(collapsingToolbar)) {
+ return;
+ }
+ RenderResources res = context.getRenderResources();
+ String title = params.getAppLabel();
+ ResourceValue titleValue = res.findResValue(title, false);
+ if (titleValue != null && titleValue.getValue() != null) {
+ title = titleValue.getValue();
+ }
+ DesignLibUtil.setTitle(collapsingToolbar, title);
+ }
+
+ private View findChildView(View view, String className) {
+ if (!(view instanceof ViewGroup)) {
+ return null;
+ }
+ ViewGroup group = (ViewGroup) view;
+ for (int i = 0; i < group.getChildCount(); i++) {
+ if (isInstanceOf(group.getChildAt(i), className)) {
+ return group.getChildAt(i);
+ }
+ }
+ return null;
+ }
+
+ private boolean hasToolbar(View collapsingToolbar) {
+ if (!(collapsingToolbar instanceof ViewGroup)) {
+ return false;
+ }
+ ViewGroup group = (ViewGroup) collapsingToolbar;
+ for (int i = 0; i < group.getChildCount(); i++) {
+ if (isInstanceOf(group.getChildAt(i), DesignLibUtil.CN_TOOLBAR)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Set the vertical scroll position on all the components with the "scrollY" attribute. If the
+ * component supports nested scrolling attempt that first, then use the unconsumed scroll part
+ * to scroll the content in the component.
+ */
+ private void handleScrolling(View view) {
+ BridgeContext context = getContext();
+ int scrollPos = context.getScrollYPos(view);
+ if (scrollPos != 0) {
+ if (view.isNestedScrollingEnabled()) {
+ int[] consumed = new int[2];
+ if (view.startNestedScroll(DesignLibUtil.SCROLL_AXIS_VERTICAL)) {
+ view.dispatchNestedPreScroll(0, scrollPos, consumed, null);
+ view.dispatchNestedScroll(consumed[0], consumed[1], 0, scrollPos, null);
+ view.stopNestedScroll();
+ scrollPos -= consumed[1];
+ }
+ }
+ if (scrollPos != 0) {
+ view.scrollBy(0, scrollPos);
+ } else {
+ view.scrollBy(0, scrollPos);
+ }
+ } else {
+ view.scrollBy(0, scrollPos);
+ }
+
+ if (!(view instanceof ViewGroup)) {
+ return;
+ }
+ ViewGroup group = (ViewGroup) view;
+ for (int i = 0; i < group.getChildCount(); i++) {
+ View child = group.getChildAt(i);
+ handleScrolling(child);
+ }
+ }
+
+ /**
* Check if the object is an instance of a class named {@code className}. This doesn't work
* for interfaces.
*/
diff --git a/tools/orientationplot/README.txt b/tools/orientationplot/README.txt
index d53f65e..958207dc 100644
--- a/tools/orientationplot/README.txt
+++ b/tools/orientationplot/README.txt
@@ -9,6 +9,8 @@
2. numpy
3. matplotlib
+eg. sudo apt-get install python-numpy python-matplotlib
+
USAGE
-----
diff --git a/tools/orientationplot/orientationplot.py b/tools/orientationplot/orientationplot.py
index 6fc3922..77ed074 100755
--- a/tools/orientationplot/orientationplot.py
+++ b/tools/orientationplot/orientationplot.py
@@ -440,7 +440,7 @@
# Notice
print "Window Orientation Listener plotting tool"
print "-----------------------------------------\n"
-print "Please turn on the Window Orientation Listener logging in Development Settings."
+print "Please turn on the Window Orientation Listener logging. See README.txt."
# Start adb.
print "Starting adb logcat.\n"