diff --git a/Android.mk b/Android.mk
index 7fbaefd57c144cf7be8c4063cdd527f890caae1e..d0ec016440b90b3f502d5196540022c4491cdb82 100644
--- a/Android.mk
+++ b/Android.mk
@@ -75,6 +75,7 @@ LOCAL_SRC_FILES += \
core/java/android/app/IAppTask.aidl \
core/java/android/app/ITaskStackListener.aidl \
core/java/android/app/IBackupAgent.aidl \
+ core/java/android/app/IEphemeralResolver.aidl \
core/java/android/app/IInstrumentationWatcher.aidl \
core/java/android/app/INotificationManager.aidl \
core/java/android/app/IProcessObserver.aidl \
@@ -306,9 +307,9 @@ LOCAL_SRC_FILES += \
core/java/com/android/internal/app/IAppOpsService.aidl \
core/java/com/android/internal/app/IAssistScreenshotReceiver.aidl \
core/java/com/android/internal/app/IBatteryStats.aidl \
- core/java/com/android/internal/app/IEphemeralResolver.aidl \
core/java/com/android/internal/app/ISoundTriggerService.aidl \
core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl \
+ core/java/com/android/internal/app/IVoiceInteractionSessionListener.aidl \
core/java/com/android/internal/app/IVoiceInteractionSessionShowCallback.aidl \
core/java/com/android/internal/app/IVoiceInteractor.aidl \
core/java/com/android/internal/app/IVoiceInteractorCallback.aidl \
@@ -319,6 +320,7 @@ LOCAL_SRC_FILES += \
core/java/com/android/internal/appwidget/IAppWidgetHost.aidl \
core/java/com/android/internal/backup/IBackupTransport.aidl \
core/java/com/android/internal/backup/IObbBackupService.aidl \
+ core/java/com/android/internal/inputmethod/IInputContentUriToken.aidl \
core/java/com/android/internal/policy/IKeyguardDrawnCallback.aidl \
core/java/com/android/internal/policy/IKeyguardExitCallback.aidl \
core/java/com/android/internal/policy/IKeyguardService.aidl \
@@ -343,6 +345,7 @@ LOCAL_SRC_FILES += \
core/java/com/android/internal/view/IInputMethodManager.aidl \
core/java/com/android/internal/view/IInputMethodSession.aidl \
core/java/com/android/internal/view/IInputSessionCallback.aidl \
+ core/java/com/android/internal/widget/ICheckCredentialProgressCallback.aidl \
core/java/com/android/internal/widget/ILockSettings.aidl \
core/java/com/android/internal/widget/IRemoteViewsFactory.aidl \
core/java/com/android/internal/widget/IRemoteViewsAdapterConnection.aidl \
@@ -469,6 +472,9 @@ LOCAL_SRC_FILES += \
../../system/update_engine/binder_bindings/android/os/IUpdateEngine.aidl \
../../system/update_engine/binder_bindings/android/os/IUpdateEngineCallback.aidl \
+LOCAL_SRC_FILES += \
+ ../../system/netd/server/binder/android/net/INetd.aidl \
+
LOCAL_AIDL_INCLUDES += system/update_engine/binder_bindings
# FRAMEWORKS_BASE_JAVA_SRC_DIRS comes from build/core/pathmap.mk
@@ -702,6 +708,7 @@ aidl_files := \
frameworks/base/core/java/android/service/quicksettings/Tile.aidl \
frameworks/native/aidl/binder/android/os/PersistableBundle.aidl \
system/netd/server/binder/android/net/UidRange.aidl \
+ frameworks/base/telephony/java/android/telephony/PcoData.aidl \
gen := $(TARGET_OUT_COMMON_INTERMEDIATES)/framework.aidl
$(gen): PRIVATE_SRC_FILES := $(aidl_files)
@@ -893,16 +900,16 @@ sample_groups := -samplegroup Admin \
## SDK version identifiers used in the published docs
# major[.minor] version for current SDK. (full releases only)
-framework_docs_SDK_VERSION:=6.0
+framework_docs_SDK_VERSION:=7.0
# release version (ie "Release x") (full releases only)
framework_docs_SDK_REL_ID:=1
framework_docs_LOCAL_DROIDDOC_OPTIONS += \
-hdf sdk.codename N \
- -hdf sdk.preview.version 2 \
+ -hdf sdk.preview.version 5 \
-hdf sdk.version $(framework_docs_SDK_VERSION) \
-hdf sdk.rel.id $(framework_docs_SDK_REL_ID) \
- -hdf sdk.preview 1
+ -hdf sdk.preview 0
# ==== the api stubs and current.xml ===========================
include $(CLEAR_VARS)
@@ -1052,6 +1059,42 @@ LOCAL_ADDITIONAL_DEPENDENCIES:=$(framework_docs_LOCAL_ADDITIONAL_DEPENDENCIES)
LOCAL_MODULE := offline-sdk
+LOCAL_DROIDDOC_OPTIONS:=\
+ $(framework_docs_LOCAL_DROIDDOC_OPTIONS) \
+ -offlinemode \
+ -title "Android SDK" \
+ -proofread $(OUT_DOCS)/$(LOCAL_MODULE)-proofread.txt \
+ -sdkvalues $(OUT_DOCS) \
+ -hdf android.whichdoc offline
+
+LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=build/tools/droiddoc/templates-sdk-dev
+
+include $(BUILD_DROIDDOC)
+
+static_doc_index_redirect := $(out_dir)/index.html
+$(static_doc_index_redirect): \
+ $(LOCAL_PATH)/docs/docs-preview-index.html | $(ACP)
+ $(hide) mkdir -p $(dir $@)
+ $(hide) $(ACP) $< $@
+
+$(full_target): $(static_doc_index_redirect)
+$(full_target): $(framework_built)
+
+
+# ==== static html in the sdk ==================================
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:=$(framework_docs_LOCAL_SRC_FILES)
+LOCAL_INTERMEDIATE_SOURCES:=$(framework_docs_LOCAL_INTERMEDIATE_SOURCES)
+LOCAL_JAVA_LIBRARIES:=$(framework_docs_LOCAL_JAVA_LIBRARIES)
+LOCAL_MODULE_CLASS:=$(framework_docs_LOCAL_MODULE_CLASS)
+LOCAL_DROIDDOC_SOURCE_PATH:=$(framework_docs_LOCAL_DROIDDOC_SOURCE_PATH)
+LOCAL_DROIDDOC_HTML_DIR:=$(framework_docs_LOCAL_DROIDDOC_HTML_DIR)
+LOCAL_ADDITIONAL_JAVA_DIR:=$(framework_docs_LOCAL_ADDITIONAL_JAVA_DIR)
+LOCAL_ADDITIONAL_DEPENDENCIES:=$(framework_docs_LOCAL_ADDITIONAL_DEPENDENCIES)
+
+LOCAL_MODULE := offline-sdk-referenceonly
+
LOCAL_DROIDDOC_OPTIONS:=\
$(framework_docs_LOCAL_DROIDDOC_OPTIONS) \
-offlinemode \
@@ -1061,13 +1104,13 @@ LOCAL_DROIDDOC_OPTIONS:=\
-hdf android.whichdoc offline \
-referenceonly
-LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=build/tools/droiddoc/templates-sdk
+LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=build/tools/droiddoc/templates-sdk-dev
include $(BUILD_DROIDDOC)
static_doc_index_redirect := $(out_dir)/index.html
$(static_doc_index_redirect): \
- $(LOCAL_PATH)/docs/docs-preview-index.html | $(ACP)
+ $(LOCAL_PATH)/docs/docs-documentation-redirect.html | $(ACP)
$(hide) mkdir -p $(dir $@)
$(hide) $(ACP) $< $@
@@ -1099,7 +1142,7 @@ LOCAL_DROIDDOC_OPTIONS:= \
-hdf android.hasSamples true \
-samplesdir $(samples_dir)
-LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=build/tools/droiddoc/templates-sdk
+LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=build/tools/droiddoc/templates-sdk-dev
include $(BUILD_DROIDDOC)
@@ -1159,20 +1202,45 @@ LOCAL_MODULE := ds
LOCAL_DROIDDOC_OPTIONS:= \
$(framework_docs_LOCAL_DROIDDOC_OPTIONS) \
- -devsite \
- -hdf devsite true \
-toroot / \
-hdf android.whichdoc online \
+ -devsite \
$(sample_groups) \
- -useUpdatedTemplates \
-hdf android.hasSamples true \
- -yaml _book.yaml \
-samplesdir $(samples_dir)
LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=build/tools/droiddoc/templates-sdk-dev
include $(BUILD_DROIDDOC)
+# ==== docs for the web (on the devsite app engine server) =======================
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES:=$(framework_docs_LOCAL_SRC_FILES)
+LOCAL_INTERMEDIATE_SOURCES:=$(framework_docs_LOCAL_INTERMEDIATE_SOURCES)
+LOCAL_STATIC_JAVA_LIBRARIES:=$(framework_docs_LOCAL_STATIC_JAVA_LIBRARIES)
+LOCAL_JAVA_LIBRARIES:=$(framework_docs_LOCAL_JAVA_LIBRARIES)
+LOCAL_MODULE_CLASS:=$(framework_docs_LOCAL_MODULE_CLASS)
+LOCAL_DROIDDOC_SOURCE_PATH:=$(framework_docs_LOCAL_DROIDDOC_SOURCE_PATH)
+LOCAL_DROIDDOC_HTML_DIR:=$(framework_docs_LOCAL_DROIDDOC_HTML_DIR)
+LOCAL_ADDITIONAL_JAVA_DIR:=$(framework_docs_LOCAL_ADDITIONAL_JAVA_DIR)
+LOCAL_ADDITIONAL_DEPENDENCIES:=$(framework_docs_LOCAL_ADDITIONAL_DEPENDENCIES)
+# specify a second html input dir and an output path relative to OUT_DIR)
+LOCAL_ADDITIONAL_HTML_DIR:=docs/html-intl /
+
+LOCAL_MODULE := ds-static
+
+LOCAL_DROIDDOC_OPTIONS:= \
+ $(framework_docs_LOCAL_DROIDDOC_OPTIONS) \
+ -hdf android.whichdoc online \
+ -staticonly \
+ -toroot / \
+ -devsite \
+ -ignoreJdLinks
+
+LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=build/tools/droiddoc/templates-sdk-dev
+
+include $(BUILD_DROIDDOC)
+
# ==== site updates for docs (on the androiddevdocs app engine server) =======================
include $(CLEAR_VARS)
diff --git a/api/current.txt b/api/current.txt
index 4f12ad4ed8c8944a28f9ad01a6fa207945343791..533b577034db0921003828891337b704c6a15581 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -397,6 +397,7 @@ package android {
field public static final int colorPressedHighlight = 16843661; // 0x101038d
field public static final int colorPrimary = 16843827; // 0x1010433
field public static final int colorPrimaryDark = 16843828; // 0x1010434
+ field public static final int colorSecondary = 16844080; // 0x1010530
field public static final int columnCount = 16843639; // 0x1010377
field public static final int columnDelay = 16843215; // 0x10101cf
field public static final int columnOrderPreserved = 16843640; // 0x1010378
@@ -420,7 +421,9 @@ package android {
field public static final int contentInsetStart = 16843859; // 0x1010453
field public static final int contentInsetStartWithNavigation = 16844066; // 0x1010522
field public static final int contextClickable = 16844007; // 0x10104e7
+ field public static final int contextDescription = 16844078; // 0x101052e
field public static final int contextPopupMenuStyle = 16844033; // 0x1010501
+ field public static final int contextUri = 16844077; // 0x101052d
field public static final int controlX1 = 16843772; // 0x10103fc
field public static final int controlX2 = 16843774; // 0x10103fe
field public static final int controlY1 = 16843773; // 0x10103fd
@@ -1039,6 +1042,7 @@ package android {
field public static final int rotation = 16843558; // 0x1010326
field public static final int rotationX = 16843559; // 0x1010327
field public static final int rotationY = 16843560; // 0x1010328
+ field public static final int roundIcon = 16844076; // 0x101052c
field public static final int rowCount = 16843637; // 0x1010375
field public static final int rowDelay = 16843216; // 0x10101d0
field public static final int rowEdgeFlags = 16843329; // 0x1010241
@@ -1106,11 +1110,16 @@ package android {
field public static final int shareInterpolator = 16843195; // 0x10101bb
field public static final int sharedUserId = 16842763; // 0x101000b
field public static final int sharedUserLabel = 16843361; // 0x1010261
+ field public static final int shortcutDisabledMessage = 16844075; // 0x101052b
+ field public static final int shortcutId = 16844072; // 0x1010528
+ field public static final int shortcutLongLabel = 16844074; // 0x101052a
+ field public static final int shortcutShortLabel = 16844073; // 0x1010529
field public static final int shouldDisableView = 16843246; // 0x10101ee
field public static final int showAsAction = 16843481; // 0x10102d9
field public static final int showDefault = 16843258; // 0x10101fa
field public static final int showDividers = 16843561; // 0x1010329
field public static final int showForAllUsers = 16844015; // 0x10104ef
+ field public static final int showMetadataInPreview = 16844079; // 0x101052f
field public static final deprecated int showOnLockScreen = 16843721; // 0x10103c9
field public static final int showSilent = 16843259; // 0x10101fb
field public static final int showText = 16843949; // 0x10104ad
@@ -3696,6 +3705,7 @@ package android.app {
method public void moveTaskToFront(int, int);
method public void moveTaskToFront(int, int, android.os.Bundle);
method public deprecated void restartPackage(java.lang.String);
+ method public static void setVrThread(int);
method public void setWatchHeapLimit(long);
field public static final java.lang.String ACTION_REPORT_HEAP_LIMIT = "android.app.action.REPORT_HEAP_LIMIT";
field public static final int LOCK_TASK_MODE_LOCKED = 1; // 0x1
@@ -5037,12 +5047,14 @@ package android.app {
method public android.app.Notification.Action.Builder extend(android.app.Notification.Action.Builder);
method public java.lang.CharSequence getCancelLabel();
method public java.lang.CharSequence getConfirmLabel();
+ method public boolean getHintDisplayActionInline();
method public boolean getHintLaunchesActivity();
method public java.lang.CharSequence getInProgressLabel();
method public boolean isAvailableOffline();
method public android.app.Notification.Action.WearableExtender setAvailableOffline(boolean);
method public android.app.Notification.Action.WearableExtender setCancelLabel(java.lang.CharSequence);
method public android.app.Notification.Action.WearableExtender setConfirmLabel(java.lang.CharSequence);
+ method public android.app.Notification.Action.WearableExtender setHintDisplayActionInline(boolean);
method public android.app.Notification.Action.WearableExtender setHintLaunchesActivity(boolean);
method public android.app.Notification.Action.WearableExtender setInProgressLabel(java.lang.CharSequence);
}
@@ -5756,7 +5768,10 @@ package android.app {
method public android.content.pm.ServiceInfo getServiceInfo();
method public java.lang.String getServiceName();
method public java.lang.String getSettingsActivity();
+ method public boolean getShowMetadataInPreview();
method public java.lang.CharSequence loadAuthor(android.content.pm.PackageManager) throws android.content.res.Resources.NotFoundException;
+ method public java.lang.CharSequence loadContextDescription(android.content.pm.PackageManager) throws android.content.res.Resources.NotFoundException;
+ method public android.net.Uri loadContextUri(android.content.pm.PackageManager) throws android.content.res.Resources.NotFoundException;
method public java.lang.CharSequence loadDescription(android.content.pm.PackageManager) throws android.content.res.Resources.NotFoundException;
method public android.graphics.drawable.Drawable loadIcon(android.content.pm.PackageManager);
method public java.lang.CharSequence loadLabel(android.content.pm.PackageManager);
@@ -6484,11 +6499,13 @@ package android.app.usage {
method public android.content.res.Configuration getConfiguration();
method public int getEventType();
method public java.lang.String getPackageName();
+ method public java.lang.String getShortcutId();
method public long getTimeStamp();
field public static final int CONFIGURATION_CHANGE = 5; // 0x5
field public static final int MOVE_TO_BACKGROUND = 2; // 0x2
field public static final int MOVE_TO_FOREGROUND = 1; // 0x1
field public static final int NONE = 0; // 0x0
+ field public static final int SHORTCUT_INVOCATION = 8; // 0x8
field public static final int USER_INTERACTION = 7; // 0x7
}
@@ -8191,6 +8208,7 @@ package android.content {
field public static final java.lang.String RESTRICTIONS_SERVICE = "restrictions";
field public static final java.lang.String SEARCH_SERVICE = "search";
field public static final java.lang.String SENSOR_SERVICE = "sensor";
+ field public static final java.lang.String SHORTCUT_SERVICE = "shortcut";
field public static final java.lang.String STORAGE_SERVICE = "storage";
field public static final java.lang.String SYSTEM_HEALTH_SERVICE = "systemhealth";
field public static final java.lang.String TELECOM_SERVICE = "telecom";
@@ -9500,13 +9518,20 @@ package android.content.pm {
public class LauncherApps {
method public java.util.List getActivityList(java.lang.String, android.os.UserHandle);
+ method public android.graphics.drawable.Drawable getShortcutBadgedIconDrawable(android.content.pm.ShortcutInfo, int);
+ method public android.graphics.drawable.Drawable getShortcutIconDrawable(android.content.pm.ShortcutInfo, int);
+ method public java.util.List getShortcuts(android.content.pm.LauncherApps.ShortcutQuery, android.os.UserHandle);
+ method public boolean hasShortcutHostPermission();
method public boolean isActivityEnabled(android.content.ComponentName, android.os.UserHandle);
method public boolean isPackageEnabled(java.lang.String, android.os.UserHandle);
+ method public void pinShortcuts(java.lang.String, java.util.List, android.os.UserHandle);
method public void registerCallback(android.content.pm.LauncherApps.Callback);
method public void registerCallback(android.content.pm.LauncherApps.Callback, android.os.Handler);
method public android.content.pm.LauncherActivityInfo resolveActivity(android.content.Intent, android.os.UserHandle);
method public void startAppDetailsActivity(android.content.ComponentName, android.os.UserHandle, android.graphics.Rect, android.os.Bundle);
method public void startMainActivity(android.content.ComponentName, android.os.UserHandle, android.graphics.Rect, android.os.Bundle);
+ method public void startShortcut(java.lang.String, java.lang.String, android.graphics.Rect, android.os.Bundle, android.os.UserHandle);
+ method public void startShortcut(android.content.pm.ShortcutInfo, android.graphics.Rect, android.os.Bundle);
method public void unregisterCallback(android.content.pm.LauncherApps.Callback);
}
@@ -9519,6 +9544,20 @@ package android.content.pm {
method public void onPackagesSuspended(java.lang.String[], android.os.UserHandle);
method public abstract void onPackagesUnavailable(java.lang.String[], android.os.UserHandle, boolean);
method public void onPackagesUnsuspended(java.lang.String[], android.os.UserHandle);
+ method public void onShortcutsChanged(java.lang.String, java.util.List, android.os.UserHandle);
+ }
+
+ public static class LauncherApps.ShortcutQuery {
+ ctor public LauncherApps.ShortcutQuery();
+ method public android.content.pm.LauncherApps.ShortcutQuery setActivity(android.content.ComponentName);
+ method public android.content.pm.LauncherApps.ShortcutQuery setChangedSince(long);
+ method public android.content.pm.LauncherApps.ShortcutQuery setPackage(java.lang.String);
+ method public android.content.pm.LauncherApps.ShortcutQuery setQueryFlags(int);
+ method public android.content.pm.LauncherApps.ShortcutQuery setShortcutIds(java.util.List);
+ field public static final int FLAG_GET_KEY_FIELDS_ONLY = 4; // 0x4
+ field public static final int FLAG_MATCH_DYNAMIC = 1; // 0x1
+ field public static final int FLAG_MATCH_MANIFEST = 8; // 0x8
+ field public static final int FLAG_MATCH_PINNED = 2; // 0x2
}
public class PackageInfo implements android.os.Parcelable {
@@ -10019,6 +10058,66 @@ package android.content.pm {
field public java.lang.String permission;
}
+ public final class ShortcutInfo implements android.os.Parcelable {
+ method public int describeContents();
+ method public android.content.ComponentName getActivity();
+ method public java.util.Set getCategories();
+ method public java.lang.CharSequence getDisabledMessage();
+ method public android.os.PersistableBundle getExtras();
+ method public java.lang.String getId();
+ method public android.content.Intent getIntent();
+ method public android.content.Intent[] getIntents();
+ method public long getLastChangedTimestamp();
+ method public java.lang.CharSequence getLongLabel();
+ method public java.lang.String getPackage();
+ method public int getRank();
+ method public java.lang.CharSequence getShortLabel();
+ method public android.os.UserHandle getUserHandle();
+ method public boolean hasKeyFieldsOnly();
+ method public boolean isDeclaredInManifest();
+ method public boolean isDynamic();
+ method public boolean isEnabled();
+ method public boolean isImmutable();
+ method public boolean isPinned();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator CREATOR;
+ field public static final java.lang.String SHORTCUT_CATEGORY_CONVERSATION = "android.shortcut.conversation";
+ }
+
+ public static class ShortcutInfo.Builder {
+ ctor public ShortcutInfo.Builder(android.content.Context, java.lang.String);
+ method public android.content.pm.ShortcutInfo build();
+ method public android.content.pm.ShortcutInfo.Builder setActivity(android.content.ComponentName);
+ method public android.content.pm.ShortcutInfo.Builder setCategories(java.util.Set);
+ method public android.content.pm.ShortcutInfo.Builder setDisabledMessage(java.lang.CharSequence);
+ method public android.content.pm.ShortcutInfo.Builder setExtras(android.os.PersistableBundle);
+ method public android.content.pm.ShortcutInfo.Builder setIcon(android.graphics.drawable.Icon);
+ method public android.content.pm.ShortcutInfo.Builder setIntent(android.content.Intent);
+ method public android.content.pm.ShortcutInfo.Builder setIntents(android.content.Intent[]);
+ method public android.content.pm.ShortcutInfo.Builder setLongLabel(java.lang.CharSequence);
+ method public android.content.pm.ShortcutInfo.Builder setRank(int);
+ method public android.content.pm.ShortcutInfo.Builder setShortLabel(java.lang.CharSequence);
+ }
+
+ public class ShortcutManager {
+ method public boolean addDynamicShortcuts(java.util.List);
+ method public void disableShortcuts(java.util.List);
+ method public void disableShortcuts(java.util.List, java.lang.CharSequence);
+ method public void enableShortcuts(java.util.List);
+ method public java.util.List getDynamicShortcuts();
+ method public int getIconMaxHeight();
+ method public int getIconMaxWidth();
+ method public java.util.List getManifestShortcuts();
+ method public int getMaxShortcutCountPerActivity();
+ method public java.util.List getPinnedShortcuts();
+ method public boolean isRateLimitingActive();
+ method public void removeAllDynamicShortcuts();
+ method public void removeDynamicShortcuts(java.util.List);
+ method public void reportShortcutUsed(java.lang.String);
+ method public boolean setDynamicShortcuts(java.util.List);
+ method public boolean updateShortcuts(java.util.List);
+ }
+
public class Signature implements android.os.Parcelable {
ctor public Signature(byte[]);
ctor public Signature(java.lang.String);
@@ -10225,7 +10324,7 @@ package android.content.res {
}
public class Resources {
- ctor public Resources(android.content.res.AssetManager, android.util.DisplayMetrics, android.content.res.Configuration);
+ ctor public deprecated Resources(android.content.res.AssetManager, android.util.DisplayMetrics, android.content.res.Configuration);
method public final void finishPreloading();
method public final void flushLayoutCache();
method public android.content.res.XmlResourceParser getAnimation(int) throws android.content.res.Resources.NotFoundException;
@@ -10276,7 +10375,7 @@ package android.content.res {
method public android.content.res.AssetFileDescriptor openRawResourceFd(int) throws android.content.res.Resources.NotFoundException;
method public void parseBundleExtra(java.lang.String, android.util.AttributeSet, android.os.Bundle) throws org.xmlpull.v1.XmlPullParserException;
method public void parseBundleExtras(android.content.res.XmlResourceParser, android.os.Bundle) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
- method public void updateConfiguration(android.content.res.Configuration, android.util.DisplayMetrics);
+ method public deprecated void updateConfiguration(android.content.res.Configuration, android.util.DisplayMetrics);
}
public static class Resources.NotFoundException extends java.lang.RuntimeException {
@@ -19556,6 +19655,7 @@ package android.media {
field public static final android.os.Parcelable.Creator CREATOR;
field public static final int ENCODING_AC3 = 5; // 0x5
field public static final int ENCODING_DEFAULT = 1; // 0x1
+ field public static final int ENCODING_DOLBY_TRUEHD = 14; // 0xe
field public static final int ENCODING_DTS = 7; // 0x7
field public static final int ENCODING_DTS_HD = 8; // 0x8
field public static final int ENCODING_E_AC3 = 6; // 0x6
@@ -28268,6 +28368,7 @@ package android.os {
field public static final int LOLLIPOP_MR1 = 22; // 0x16
field public static final int M = 23; // 0x17
field public static final int N = 24; // 0x18
+ field public static final int N_MR1 = 25; // 0x19
}
public final class Bundle extends android.os.BaseBundle implements java.lang.Cloneable android.os.Parcelable {
@@ -29259,6 +29360,7 @@ package android.os {
method public android.os.Bundle getUserRestrictions();
method public android.os.Bundle getUserRestrictions(android.os.UserHandle);
method public boolean hasUserRestriction(java.lang.String);
+ method public boolean isDemoUser();
method public boolean isQuietModeEnabled(android.os.UserHandle);
method public boolean isSystemUser();
method public boolean isUserAGoat();
@@ -29498,6 +29600,7 @@ package android.os.storage {
method public boolean isObbMounted(java.lang.String);
method public boolean mountObb(java.lang.String, java.lang.String, android.os.storage.OnObbStateChangeListener);
method public boolean unmountObb(java.lang.String, boolean, android.os.storage.OnObbStateChangeListener);
+ field public static final java.lang.String ACTION_MANAGE_STORAGE = "android.os.storage.action.MANAGE_STORAGE";
}
public final class StorageVolume implements android.os.Parcelable {
@@ -30640,6 +30743,7 @@ package android.provider {
public static class CallLog.Calls implements android.provider.BaseColumns {
ctor public CallLog.Calls();
method public static java.lang.String getLastOutgoingCall(android.content.Context);
+ field public static final int ANSWERED_EXTERNALLY_TYPE = 7; // 0x7
field public static final int BLOCKED_TYPE = 6; // 0x6
field public static final java.lang.String CACHED_FORMATTED_NUMBER = "formatted_number";
field public static final java.lang.String CACHED_LOOKUP_URI = "lookup_uri";
@@ -30662,6 +30766,7 @@ package android.provider {
field public static final java.lang.String DURATION = "duration";
field public static final java.lang.String EXTRA_CALL_TYPE_FILTER = "android.provider.extra.CALL_TYPE_FILTER";
field public static final java.lang.String FEATURES = "features";
+ field public static final int FEATURES_PULLED_EXTERNALLY = 2; // 0x2
field public static final int FEATURES_VIDEO = 1; // 0x1
field public static final java.lang.String GEOCODED_LOCATION = "geocoded_location";
field public static final int INCOMING_TYPE = 1; // 0x1
@@ -32367,6 +32472,7 @@ package android.provider {
field public static final java.lang.String DATA_ROAMING = "data_roaming";
field public static final java.lang.String DEBUG_APP = "debug_app";
field public static final java.lang.String DEVELOPMENT_SETTINGS_ENABLED = "development_settings_enabled";
+ field public static final java.lang.String DEVICE_NAME = "device_name";
field public static final java.lang.String DEVICE_PROVISIONED = "device_provisioned";
field public static final java.lang.String HTTP_PROXY = "http_proxy";
field public static final deprecated java.lang.String INSTALL_NON_MARKET_APPS = "install_non_market_apps";
@@ -32952,6 +33058,7 @@ package android.provider {
field public static final java.lang.String ACTION_NEW_VOICEMAIL = "android.intent.action.NEW_VOICEMAIL";
field public static final java.lang.String ACTION_SYNC_VOICEMAIL = "android.provider.action.SYNC_VOICEMAIL";
field public static final java.lang.String AUTHORITY = "com.android.voicemail";
+ field public static final java.lang.String EXTRA_PHONE_ACCOUNT_HANDLE = "android.provider.extra.PHONE_ACCOUNT_HANDLE";
field public static final java.lang.String EXTRA_SELF_CHANGE = "com.android.voicemail.extra.SELF_CHANGE";
field public static final java.lang.String PARAM_KEY_SOURCE_PACKAGE = "source_package";
}
@@ -32960,6 +33067,9 @@ package android.provider {
method public static android.net.Uri buildSourceUri(java.lang.String);
field public static final java.lang.String CONFIGURATION_STATE = "configuration_state";
field public static final int CONFIGURATION_STATE_CAN_BE_CONFIGURED = 2; // 0x2
+ field public static final int CONFIGURATION_STATE_CONFIGURING = 3; // 0x3
+ field public static final int CONFIGURATION_STATE_DISABLED = 5; // 0x5
+ field public static final int CONFIGURATION_STATE_FAILED = 4; // 0x4
field public static final int CONFIGURATION_STATE_NOT_CONFIGURED = 1; // 0x1
field public static final int CONFIGURATION_STATE_OK = 0; // 0x0
field public static final android.net.Uri CONTENT_URI;
@@ -32984,6 +33094,7 @@ package android.provider {
field public static final int QUOTA_UNAVAILABLE = -1; // 0xffffffff
field public static final java.lang.String SETTINGS_URI = "settings_uri";
field public static final java.lang.String SOURCE_PACKAGE = "source_package";
+ field public static final java.lang.String SOURCE_TYPE = "source_type";
field public static final java.lang.String VOICEMAIL_ACCESS_URI = "voicemail_access_uri";
}
@@ -35936,9 +36047,14 @@ package android.telecom {
method public void phoneAccountSelected(android.telecom.PhoneAccountHandle, boolean);
method public void playDtmfTone(char);
method public void postDialContinue(boolean);
+ method public void pullExternalCall();
+ method public final void putExtras(android.os.Bundle);
method public void registerCallback(android.telecom.Call.Callback);
method public void registerCallback(android.telecom.Call.Callback, android.os.Handler);
method public void reject(boolean, java.lang.String);
+ method public final void removeExtras(java.util.List);
+ method public final void removeExtras(java.lang.String...);
+ method public void sendCallEvent(java.lang.String, android.os.Bundle);
method public void splitFromConference();
method public void stopDtmfTone();
method public void swapConference();
@@ -35952,6 +36068,7 @@ package android.telecom {
field public static final int STATE_DISCONNECTING = 10; // 0xa
field public static final int STATE_HOLDING = 3; // 0x3
field public static final int STATE_NEW = 0; // 0x0
+ field public static final int STATE_PULLING_CALL = 11; // 0xb
field public static final int STATE_RINGING = 2; // 0x2
field public static final int STATE_SELECT_PHONE_ACCOUNT = 8; // 0x8
}
@@ -35962,6 +36079,7 @@ package android.telecom {
method public void onCannedTextResponsesLoaded(android.telecom.Call, java.util.List);
method public void onChildrenChanged(android.telecom.Call, java.util.List);
method public void onConferenceableCallsChanged(android.telecom.Call, java.util.List);
+ method public void onConnectionEvent(android.telecom.Call, java.lang.String, android.os.Bundle);
method public void onDetailsChanged(android.telecom.Call, android.telecom.Call.Details);
method public void onParentChanged(android.telecom.Call, android.telecom.Call);
method public void onPostDialWait(android.telecom.Call, java.lang.String);
@@ -35992,6 +36110,7 @@ package android.telecom {
method public static java.lang.String propertiesToString(int);
field public static final int CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO = 4194304; // 0x400000
field public static final int CAPABILITY_CAN_PAUSE_VIDEO = 1048576; // 0x100000
+ field public static final int CAPABILITY_CAN_PULL_CALL = 8388608; // 0x800000
field public static final int CAPABILITY_DISCONNECT_FROM_CONFERENCE = 8192; // 0x2000
field public static final int CAPABILITY_HOLD = 1; // 0x1
field public static final int CAPABILITY_MANAGE_CONFERENCE = 128; // 0x80
@@ -36011,7 +36130,9 @@ package android.telecom {
field public static final int PROPERTY_EMERGENCY_CALLBACK_MODE = 4; // 0x4
field public static final int PROPERTY_ENTERPRISE_CALL = 32; // 0x20
field public static final int PROPERTY_GENERIC_CONFERENCE = 2; // 0x2
+ field public static final int PROPERTY_HAS_CDMA_VOICE_PRIVACY = 128; // 0x80
field public static final int PROPERTY_HIGH_DEF_AUDIO = 16; // 0x10
+ field public static final int PROPERTY_IS_EXTERNAL_CALL = 64; // 0x40
field public static final int PROPERTY_WIFI = 8; // 0x8
}
@@ -36062,6 +36183,7 @@ package android.telecom {
method public final android.telecom.CallAudioState getCallAudioState();
method public final java.util.List getConferenceableConnections();
method public final int getConnectionCapabilities();
+ method public final int getConnectionProperties();
method public final long getConnectionTime();
method public final java.util.List getConnections();
method public final android.telecom.DisconnectCause getDisconnectCause();
@@ -36074,6 +36196,7 @@ package android.telecom {
method public void onCallAudioStateChanged(android.telecom.CallAudioState);
method public void onConnectionAdded(android.telecom.Connection);
method public void onDisconnect();
+ method public void onExtrasChanged(android.os.Bundle);
method public void onHold();
method public void onMerge(android.telecom.Connection);
method public void onMerge();
@@ -36082,10 +36205,14 @@ package android.telecom {
method public void onStopDtmfTone();
method public void onSwap();
method public void onUnhold();
+ method public final void putExtras(android.os.Bundle);
method public final void removeConnection(android.telecom.Connection);
+ method public final void removeExtras(java.util.List);
+ method public final void removeExtras(java.lang.String...);
method public final void setActive();
method public final void setConferenceableConnections(java.util.List);
method public final void setConnectionCapabilities(int);
+ method public final void setConnectionProperties(int);
method public final void setConnectionTime(long);
method public final void setDialing();
method public final void setDisconnected(android.telecom.DisconnectCause);
@@ -36115,6 +36242,7 @@ package android.telecom {
method public final android.telecom.Conference getConference();
method public final java.util.List getConferenceables();
method public final int getConnectionCapabilities();
+ method public final int getConnectionProperties();
method public final android.telecom.DisconnectCause getDisconnectCause();
method public final android.os.Bundle getExtras();
method public final int getState();
@@ -36125,16 +36253,24 @@ package android.telecom {
method public void onAnswer(int);
method public void onAnswer();
method public void onCallAudioStateChanged(android.telecom.CallAudioState);
+ method public void onCallEvent(java.lang.String, android.os.Bundle);
method public void onDisconnect();
+ method public void onExtrasChanged(android.os.Bundle);
method public void onHold();
method public void onPlayDtmfTone(char);
method public void onPostDialContinue(boolean);
+ method public void onPullExternalCall();
method public void onReject();
method public void onReject(java.lang.String);
method public void onSeparate();
method public void onStateChanged(int);
method public void onStopDtmfTone();
method public void onUnhold();
+ method public static java.lang.String propertiesToString(int);
+ method public final void putExtras(android.os.Bundle);
+ method public final void removeExtras(java.util.List);
+ method public final void removeExtras(java.lang.String...);
+ method public void sendConnectionEvent(java.lang.String, android.os.Bundle);
method public final void setActive();
method public final void setAddress(android.net.Uri, int);
method public final void setAudioModeIsVoip(boolean);
@@ -36142,6 +36278,7 @@ package android.telecom {
method public final void setConferenceableConnections(java.util.List);
method public final void setConferenceables(java.util.List);
method public final void setConnectionCapabilities(int);
+ method public final void setConnectionProperties(int);
method public final void setDialing();
method public final void setDisconnected(android.telecom.DisconnectCause);
method public final void setExtras(android.os.Bundle);
@@ -36150,6 +36287,7 @@ package android.telecom {
method public final void setNextPostDialChar(char);
method public final void setOnHold();
method public final void setPostDialWait(java.lang.String);
+ method public final void setPulling();
method public final void setRingbackRequested(boolean);
method public final void setRinging();
method public final void setStatusHints(android.telecom.StatusHints);
@@ -36158,6 +36296,7 @@ package android.telecom {
method public static java.lang.String stateToString(int);
field public static final int CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO = 8388608; // 0x800000
field public static final int CAPABILITY_CAN_PAUSE_VIDEO = 1048576; // 0x100000
+ field public static final int CAPABILITY_CAN_PULL_CALL = 16777216; // 0x1000000
field public static final int CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION = 4194304; // 0x400000
field public static final int CAPABILITY_CAN_UPGRADE_TO_VIDEO = 524288; // 0x80000
field public static final int CAPABILITY_DISCONNECT_FROM_CONFERENCE = 8192; // 0x2000
@@ -36175,15 +36314,21 @@ package android.telecom {
field public static final int CAPABILITY_SUPPORTS_VT_REMOTE_TX = 2048; // 0x800
field public static final int CAPABILITY_SUPPORT_HOLD = 2; // 0x2
field public static final int CAPABILITY_SWAP_CONFERENCE = 8; // 0x8
+ field public static final java.lang.String EVENT_CALL_MERGE_FAILED = "android.telecom.event.CALL_MERGE_FAILED";
+ field public static final java.lang.String EVENT_CALL_PULL_FAILED = "android.telecom.event.CALL_PULL_FAILED";
+ field public static final java.lang.String EXTRA_ANSWERING_DROPS_FG_CALL = "android.telecom.extra.ANSWERING_DROPS_FG_CALL";
field public static final java.lang.String EXTRA_CALL_SUBJECT = "android.telecom.extra.CALL_SUBJECT";
field public static final java.lang.String EXTRA_CHILD_ADDRESS = "android.telecom.extra.CHILD_ADDRESS";
field public static final java.lang.String EXTRA_LAST_FORWARDED_NUMBER = "android.telecom.extra.LAST_FORWARDED_NUMBER";
+ field public static final int PROPERTY_HAS_CDMA_VOICE_PRIVACY = 32; // 0x20
+ field public static final int PROPERTY_IS_EXTERNAL_CALL = 16; // 0x10
field public static final int STATE_ACTIVE = 4; // 0x4
field public static final int STATE_DIALING = 3; // 0x3
field public static final int STATE_DISCONNECTED = 6; // 0x6
field public static final int STATE_HOLDING = 5; // 0x5
field public static final int STATE_INITIALIZING = 0; // 0x0
field public static final int STATE_NEW = 1; // 0x1
+ field public static final int STATE_PULLING_CALL = 7; // 0x7
field public static final int STATE_RINGING = 2; // 0x2
}
@@ -36261,7 +36406,9 @@ package android.telecom {
method public java.lang.String getReason();
method public int getTone();
method public void writeToParcel(android.os.Parcel, int);
+ field public static final int ANSWERED_ELSEWHERE = 11; // 0xb
field public static final int BUSY = 7; // 0x7
+ field public static final int CALL_PULLED = 12; // 0xc
field public static final int CANCELED = 4; // 0x4
field public static final int CONNECTION_MANAGER_NOT_SUPPORTED = 10; // 0xa
field public static final android.os.Parcelable.Creator CREATOR;
@@ -36297,6 +36444,7 @@ package android.telecom {
method public void onCallAudioStateChanged(android.telecom.CallAudioState);
method public void onCallRemoved(android.telecom.Call);
method public void onCanAddCallChanged(boolean);
+ method public void onConnectionEvent(android.telecom.Call, java.lang.String, android.os.Bundle);
method public void onSilenceRinger();
method public final void setAudioRoute(int);
method public final void setMuted(boolean);
@@ -36419,6 +36567,7 @@ package android.telecom {
method public void onConferenceableConnectionsChanged(android.telecom.RemoteConference, java.util.List);
method public void onConnectionAdded(android.telecom.RemoteConference, android.telecom.RemoteConnection);
method public void onConnectionCapabilitiesChanged(android.telecom.RemoteConference, int);
+ method public void onConnectionPropertiesChanged(android.telecom.RemoteConference, int);
method public void onConnectionRemoved(android.telecom.RemoteConference, android.telecom.RemoteConnection);
method public void onDestroyed(android.telecom.RemoteConference);
method public void onDisconnected(android.telecom.RemoteConference, android.telecom.DisconnectCause);
@@ -36437,6 +36586,7 @@ package android.telecom {
method public android.telecom.RemoteConference getConference();
method public java.util.List getConferenceableConnections();
method public int getConnectionCapabilities();
+ method public int getConnectionProperties();
method public android.telecom.DisconnectCause getDisconnectCause();
method public final android.os.Bundle getExtras();
method public int getState();
@@ -36448,6 +36598,7 @@ package android.telecom {
method public boolean isVoipAudioMode();
method public void playDtmfTone(char);
method public void postDialContinue(boolean);
+ method public void pullExternalCall();
method public void registerCallback(android.telecom.RemoteConnection.Callback);
method public void registerCallback(android.telecom.RemoteConnection.Callback, android.os.Handler);
method public void reject();
@@ -36464,6 +36615,8 @@ package android.telecom {
method public void onConferenceChanged(android.telecom.RemoteConnection, android.telecom.RemoteConference);
method public void onConferenceableConnectionsChanged(android.telecom.RemoteConnection, java.util.List);
method public void onConnectionCapabilitiesChanged(android.telecom.RemoteConnection, int);
+ method public void onConnectionEvent(android.telecom.RemoteConnection, java.lang.String, android.os.Bundle);
+ method public void onConnectionPropertiesChanged(android.telecom.RemoteConnection, int);
method public void onDestroyed(android.telecom.RemoteConnection);
method public void onDisconnected(android.telecom.RemoteConnection, android.telecom.DisconnectCause);
method public void onExtrasChanged(android.telecom.RemoteConnection, android.os.Bundle);
@@ -36560,6 +36713,7 @@ package android.telecom {
field public static final java.lang.String EXTRA_START_CALL_WITH_VIDEO_STATE = "android.telecom.extra.START_CALL_WITH_VIDEO_STATE";
field public static final java.lang.String GATEWAY_ORIGINAL_ADDRESS = "android.telecom.extra.GATEWAY_ORIGINAL_ADDRESS";
field public static final java.lang.String GATEWAY_PROVIDER_PACKAGE = "android.telecom.extra.GATEWAY_PROVIDER_PACKAGE";
+ field public static final java.lang.String METADATA_INCLUDE_EXTERNAL_CALLS = "android.telecom.INCLUDE_EXTERNAL_CALLS";
field public static final java.lang.String METADATA_IN_CALL_SERVICE_RINGING = "android.telecom.IN_CALL_SERVICE_RINGING";
field public static final java.lang.String METADATA_IN_CALL_SERVICE_UI = "android.telecom.IN_CALL_SERVICE_UI";
field public static final int PRESENTATION_ALLOWED = 1; // 0x1
@@ -36614,9 +36768,11 @@ package android.telephony {
field public static final java.lang.String ACTION_CARRIER_CONFIG_CHANGED = "android.telephony.action.CARRIER_CONFIG_CHANGED";
field public static final java.lang.String KEY_ADDITIONAL_CALL_SETTING_BOOL = "additional_call_setting_bool";
field public static final java.lang.String KEY_ALLOW_ADDING_APNS_BOOL = "allow_adding_apns_bool";
+ field public static final java.lang.String KEY_ALLOW_ADD_CALL_DURING_VIDEO_CALL_BOOL = "allow_add_call_during_video_call";
field public static final java.lang.String KEY_ALLOW_EMERGENCY_NUMBERS_IN_CALL_LOG_BOOL = "allow_emergency_numbers_in_call_log_bool";
field public static final java.lang.String KEY_ALLOW_EMERGENCY_VIDEO_CALLS_BOOL = "allow_emergency_video_calls_bool";
field public static final java.lang.String KEY_ALLOW_LOCAL_DTMF_TONES_BOOL = "allow_local_dtmf_tones_bool";
+ field public static final java.lang.String KEY_ALLOW_MERGE_WIFI_CALLS_WHEN_VOWIFI_OFF_BOOL = "allow_merge_wifi_calls_when_vowifi_off_bool";
field public static final java.lang.String KEY_ALLOW_NON_EMERGENCY_CALLS_IN_ECM_BOOL = "allow_non_emergency_calls_in_ecm_bool";
field public static final java.lang.String KEY_ALWAYS_SHOW_EMERGENCY_ALERT_ONOFF_BOOL = "always_show_emergency_alert_onoff_bool";
field public static final java.lang.String KEY_APN_EXPAND_BOOL = "apn_expand_bool";
@@ -36648,6 +36804,7 @@ package android.telephony {
field public static final java.lang.String KEY_CSP_ENABLED_BOOL = "csp_enabled_bool";
field public static final java.lang.String KEY_DEFAULT_SIM_CALL_MANAGER_STRING = "default_sim_call_manager_string";
field public static final java.lang.String KEY_DISABLE_CDMA_ACTIVATION_CODE_BOOL = "disable_cdma_activation_code_bool";
+ field public static final java.lang.String KEY_DROP_VIDEO_CALL_WHEN_ANSWERING_AUDIO_CALL_BOOL = "drop_video_call_when_answering_audio_call_bool";
field public static final java.lang.String KEY_DTMF_TYPE_ENABLED_BOOL = "dtmf_type_enabled_bool";
field public static final java.lang.String KEY_DURATION_BLOCKING_DISABLED_AFTER_EMERGENCY_INT = "duration_blocking_disabled_after_emergency_int";
field public static final java.lang.String KEY_EDITABLE_ENHANCED_4G_LTE_BOOL = "editable_enhanced_4g_lte_bool";
@@ -36705,6 +36862,7 @@ package android.telephony {
field public static final java.lang.String KEY_SUPPORT_CONFERENCE_CALL_BOOL = "support_conference_call_bool";
field public static final java.lang.String KEY_SUPPORT_PAUSE_IMS_VIDEO_CALLS_BOOL = "support_pause_ims_video_calls_bool";
field public static final java.lang.String KEY_SUPPORT_SWAP_AFTER_MERGE_BOOL = "support_swap_after_merge_bool";
+ field public static final java.lang.String KEY_TREAT_DOWNGRADED_VIDEO_CALLS_AS_VIDEO_CALLS_BOOL = "treat_downgraded_video_calls_as_video_calls_bool";
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_USE_RCS_PRESENCE_BOOL = "use_rcs_presence_bool";
@@ -37289,12 +37447,15 @@ package android.telephony {
field public static final int NETWORK_TYPE_EVDO_A = 6; // 0x6
field public static final int NETWORK_TYPE_EVDO_B = 12; // 0xc
field public static final int NETWORK_TYPE_GPRS = 1; // 0x1
+ field public static final int NETWORK_TYPE_GSM = 16; // 0x10
field public static final int NETWORK_TYPE_HSDPA = 8; // 0x8
field public static final int NETWORK_TYPE_HSPA = 10; // 0xa
field public static final int NETWORK_TYPE_HSPAP = 15; // 0xf
field public static final int NETWORK_TYPE_HSUPA = 9; // 0x9
field public static final int NETWORK_TYPE_IDEN = 11; // 0xb
+ field public static final int NETWORK_TYPE_IWLAN = 18; // 0x12
field public static final int NETWORK_TYPE_LTE = 13; // 0xd
+ field public static final int NETWORK_TYPE_TD_SCDMA = 17; // 0x11
field public static final int NETWORK_TYPE_UMTS = 3; // 0x3
field public static final int NETWORK_TYPE_UNKNOWN = 0; // 0x0
field public static final int PHONE_TYPE_CDMA = 2; // 0x2
@@ -40095,7 +40256,10 @@ package android.util {
method public boolean equals(android.util.DisplayMetrics);
method public void setTo(android.util.DisplayMetrics);
method public void setToDefaults();
+ field public static final int DENSITY_260 = 260; // 0x104
field public static final int DENSITY_280 = 280; // 0x118
+ field public static final int DENSITY_300 = 300; // 0x12c
+ field public static final int DENSITY_340 = 340; // 0x154
field public static final int DENSITY_360 = 360; // 0x168
field public static final int DENSITY_400 = 400; // 0x190
field public static final int DENSITY_420 = 420; // 0x1a4
@@ -41425,6 +41589,10 @@ package android.view {
field public static final int KEYCODE_SWITCH_CHARSET = 95; // 0x5f
field public static final int KEYCODE_SYM = 63; // 0x3f
field public static final int KEYCODE_SYSRQ = 120; // 0x78
+ field public static final int KEYCODE_SYSTEM_NAVIGATION_DOWN = 281; // 0x119
+ field public static final int KEYCODE_SYSTEM_NAVIGATION_LEFT = 282; // 0x11a
+ field public static final int KEYCODE_SYSTEM_NAVIGATION_RIGHT = 283; // 0x11b
+ field public static final int KEYCODE_SYSTEM_NAVIGATION_UP = 280; // 0x118
field public static final int KEYCODE_T = 48; // 0x30
field public static final int KEYCODE_TAB = 61; // 0x3d
field public static final int KEYCODE_TV = 170; // 0xaa
@@ -42307,6 +42475,7 @@ package android.view {
method public float getPivotY();
method public android.view.PointerIcon getPointerIcon();
method public android.content.res.Resources getResources();
+ method public final boolean getRevealOnFocusHint();
method public final int getRight();
method protected float getRightFadingEdgeStrength();
method protected int getRightPaddingOffset();
@@ -42594,6 +42763,7 @@ package android.view {
method public void setPivotY(float);
method public void setPointerIcon(android.view.PointerIcon);
method public void setPressed(boolean);
+ method public final void setRevealOnFocusHint(boolean);
method public final void setRight(int);
method public void setRotation(float);
method public void setRotationX(float);
@@ -43743,6 +43913,7 @@ package android.view {
field public static final int TYPE_APPLICATION_SUB_PANEL = 1002; // 0x3ea
field public static final int TYPE_BASE_APPLICATION = 1; // 0x1
field public static final int TYPE_CHANGED = 2; // 0x2
+ field public static final int TYPE_DRAWN_APPLICATION = 4; // 0x4
field public static final int TYPE_INPUT_METHOD = 2011; // 0x7db
field public static final int TYPE_INPUT_METHOD_DIALOG = 2012; // 0x7dc
field public static final int TYPE_KEYGUARD_DIALOG = 2009; // 0x7d9
@@ -44515,6 +44686,7 @@ package android.view.inputmethod {
method public boolean clearMetaKeyStates(int);
method public void closeConnection();
method public boolean commitCompletion(android.view.inputmethod.CompletionInfo);
+ method public boolean commitContent(android.view.inputmethod.InputContentInfo, int, android.os.Bundle);
method public boolean commitCorrection(android.view.inputmethod.CorrectionInfo);
method public boolean commitText(java.lang.CharSequence, int);
method public boolean deleteSurroundingText(int, int);
@@ -44624,6 +44796,7 @@ package android.view.inputmethod {
field public static final int IME_NULL = 0; // 0x0
field public int actionId;
field public java.lang.CharSequence actionLabel;
+ field public java.lang.String[] contentMimeTypes;
field public android.os.Bundle extras;
field public int fieldId;
field public java.lang.String fieldName;
@@ -44683,6 +44856,7 @@ package android.view.inputmethod {
method public abstract boolean clearMetaKeyStates(int);
method public abstract void closeConnection();
method public abstract boolean commitCompletion(android.view.inputmethod.CompletionInfo);
+ method public abstract boolean commitContent(android.view.inputmethod.InputContentInfo, int, android.os.Bundle);
method public abstract boolean commitCorrection(android.view.inputmethod.CorrectionInfo);
method public abstract boolean commitText(java.lang.CharSequence, int);
method public abstract boolean deleteSurroundingText(int, int);
@@ -44708,6 +44882,7 @@ package android.view.inputmethod {
field public static final int CURSOR_UPDATE_MONITOR = 2; // 0x2
field public static final int GET_EXTRACTED_TEXT_MONITOR = 1; // 0x1
field public static final int GET_TEXT_WITH_STYLES = 1; // 0x1
+ field public static final int INPUT_CONTENT_GRANT_READ_URI_PERMISSION = 1; // 0x1
}
public class InputConnectionWrapper implements android.view.inputmethod.InputConnection {
@@ -44716,6 +44891,7 @@ package android.view.inputmethod {
method public boolean clearMetaKeyStates(int);
method public void closeConnection();
method public boolean commitCompletion(android.view.inputmethod.CompletionInfo);
+ method public boolean commitContent(android.view.inputmethod.InputContentInfo, int, android.os.Bundle);
method public boolean commitCorrection(android.view.inputmethod.CorrectionInfo);
method public boolean commitText(java.lang.CharSequence, int);
method public boolean deleteSurroundingText(int, int);
@@ -44740,6 +44916,19 @@ package android.view.inputmethod {
method public void setTarget(android.view.inputmethod.InputConnection);
}
+ public final class InputContentInfo implements android.os.Parcelable {
+ ctor public InputContentInfo(android.net.Uri, android.content.ClipDescription);
+ ctor public InputContentInfo(android.net.Uri, android.content.ClipDescription, android.net.Uri);
+ method public int describeContents();
+ method public android.net.Uri getContentUri();
+ method public android.content.ClipDescription getDescription();
+ method public android.net.Uri getLinkUri();
+ method public void releasePermission();
+ method public void requestPermission();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator CREATOR;
+ }
+
public abstract interface InputMethod {
method public abstract void attachToken(android.os.IBinder);
method public abstract void bindInput(android.view.inputmethod.InputBinding);
diff --git a/api/system-current.txt b/api/system-current.txt
index d1c03942229fa6ab892b3e36f16747d5a9866f01..c33fe6eed6cc983005903996552c3e3af4127704 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -504,6 +504,7 @@ package android {
field public static final int colorPressedHighlight = 16843661; // 0x101038d
field public static final int colorPrimary = 16843827; // 0x1010433
field public static final int colorPrimaryDark = 16843828; // 0x1010434
+ field public static final int colorSecondary = 16844080; // 0x1010530
field public static final int columnCount = 16843639; // 0x1010377
field public static final int columnDelay = 16843215; // 0x10101cf
field public static final int columnOrderPreserved = 16843640; // 0x1010378
@@ -527,7 +528,9 @@ package android {
field public static final int contentInsetStart = 16843859; // 0x1010453
field public static final int contentInsetStartWithNavigation = 16844066; // 0x1010522
field public static final int contextClickable = 16844007; // 0x10104e7
+ field public static final int contextDescription = 16844078; // 0x101052e
field public static final int contextPopupMenuStyle = 16844033; // 0x1010501
+ field public static final int contextUri = 16844077; // 0x101052d
field public static final int controlX1 = 16843772; // 0x10103fc
field public static final int controlX2 = 16843774; // 0x10103fe
field public static final int controlY1 = 16843773; // 0x10103fd
@@ -1146,6 +1149,7 @@ package android {
field public static final int rotation = 16843558; // 0x1010326
field public static final int rotationX = 16843559; // 0x1010327
field public static final int rotationY = 16843560; // 0x1010328
+ field public static final int roundIcon = 16844076; // 0x101052c
field public static final int rowCount = 16843637; // 0x1010375
field public static final int rowDelay = 16843216; // 0x10101d0
field public static final int rowEdgeFlags = 16843329; // 0x1010241
@@ -1217,11 +1221,16 @@ package android {
field public static final int shareInterpolator = 16843195; // 0x10101bb
field public static final int sharedUserId = 16842763; // 0x101000b
field public static final int sharedUserLabel = 16843361; // 0x1010261
+ field public static final int shortcutDisabledMessage = 16844075; // 0x101052b
+ field public static final int shortcutId = 16844072; // 0x1010528
+ field public static final int shortcutLongLabel = 16844074; // 0x101052a
+ field public static final int shortcutShortLabel = 16844073; // 0x1010529
field public static final int shouldDisableView = 16843246; // 0x10101ee
field public static final int showAsAction = 16843481; // 0x10102d9
field public static final int showDefault = 16843258; // 0x10101fa
field public static final int showDividers = 16843561; // 0x1010329
field public static final int showForAllUsers = 16844015; // 0x10104ef
+ field public static final int showMetadataInPreview = 16844079; // 0x101052f
field public static final deprecated int showOnLockScreen = 16843721; // 0x10103c9
field public static final int showSilent = 16843259; // 0x10101fb
field public static final int showText = 16843949; // 0x10104ad
@@ -3832,6 +3841,7 @@ package android.app {
method public void moveTaskToFront(int, int);
method public void moveTaskToFront(int, int, android.os.Bundle);
method public deprecated void restartPackage(java.lang.String);
+ method public static void setVrThread(int);
method public void setWatchHeapLimit(long);
field public static final java.lang.String ACTION_REPORT_HEAP_LIMIT = "android.app.action.REPORT_HEAP_LIMIT";
field public static final int LOCK_TASK_MODE_LOCKED = 1; // 0x1
@@ -4515,6 +4525,15 @@ package android.app {
field public static final int VISIBILITY_VISIBLE_NOTIFY_ONLY_COMPLETION = 3; // 0x3
}
+ public abstract class EphemeralResolverService extends android.app.Service {
+ ctor public EphemeralResolverService();
+ method public final void attachBaseContext(android.content.Context);
+ method public final android.os.IBinder onBind(android.content.Intent);
+ method public abstract java.util.List onEphemeralResolveInfoList(int[], int);
+ field public static final java.lang.String EXTRA_RESOLVE_INFO = "android.app.extra.RESOLVE_INFO";
+ field public static final java.lang.String EXTRA_SEQUENCE = "android.app.extra.SEQUENCE";
+ }
+
public class ExpandableListActivity extends android.app.Activity implements android.widget.ExpandableListView.OnChildClickListener android.widget.ExpandableListView.OnGroupCollapseListener android.widget.ExpandableListView.OnGroupExpandListener android.view.View.OnCreateContextMenuListener {
ctor public ExpandableListActivity();
method public android.widget.ExpandableListAdapter getExpandableListAdapter();
@@ -5185,12 +5204,14 @@ package android.app {
method public android.app.Notification.Action.Builder extend(android.app.Notification.Action.Builder);
method public java.lang.CharSequence getCancelLabel();
method public java.lang.CharSequence getConfirmLabel();
+ method public boolean getHintDisplayActionInline();
method public boolean getHintLaunchesActivity();
method public java.lang.CharSequence getInProgressLabel();
method public boolean isAvailableOffline();
method public android.app.Notification.Action.WearableExtender setAvailableOffline(boolean);
method public android.app.Notification.Action.WearableExtender setCancelLabel(java.lang.CharSequence);
method public android.app.Notification.Action.WearableExtender setConfirmLabel(java.lang.CharSequence);
+ method public android.app.Notification.Action.WearableExtender setHintDisplayActionInline(boolean);
method public android.app.Notification.Action.WearableExtender setHintLaunchesActivity(boolean);
method public android.app.Notification.Action.WearableExtender setInProgressLabel(java.lang.CharSequence);
}
@@ -5904,7 +5925,10 @@ package android.app {
method public android.content.pm.ServiceInfo getServiceInfo();
method public java.lang.String getServiceName();
method public java.lang.String getSettingsActivity();
+ method public boolean getShowMetadataInPreview();
method public java.lang.CharSequence loadAuthor(android.content.pm.PackageManager) throws android.content.res.Resources.NotFoundException;
+ method public java.lang.CharSequence loadContextDescription(android.content.pm.PackageManager) throws android.content.res.Resources.NotFoundException;
+ method public android.net.Uri loadContextUri(android.content.pm.PackageManager) throws android.content.res.Resources.NotFoundException;
method public java.lang.CharSequence loadDescription(android.content.pm.PackageManager) throws android.content.res.Resources.NotFoundException;
method public android.graphics.drawable.Drawable loadIcon(android.content.pm.PackageManager);
method public java.lang.CharSequence loadLabel(android.content.pm.PackageManager);
@@ -6767,11 +6791,13 @@ package android.app.usage {
method public android.content.res.Configuration getConfiguration();
method public int getEventType();
method public java.lang.String getPackageName();
+ method public java.lang.String getShortcutId();
method public long getTimeStamp();
field public static final int CONFIGURATION_CHANGE = 5; // 0x5
field public static final int MOVE_TO_BACKGROUND = 2; // 0x2
field public static final int MOVE_TO_FOREGROUND = 1; // 0x1
field public static final int NONE = 0; // 0x0
+ field public static final int SHORTCUT_INVOCATION = 8; // 0x8
field public static final int USER_INTERACTION = 7; // 0x7
}
@@ -8515,6 +8541,7 @@ package android.content {
field public static final java.lang.String RESTRICTIONS_SERVICE = "restrictions";
field public static final java.lang.String SEARCH_SERVICE = "search";
field public static final java.lang.String SENSOR_SERVICE = "sensor";
+ field public static final java.lang.String SHORTCUT_SERVICE = "shortcut";
field public static final java.lang.String STORAGE_SERVICE = "storage";
field public static final java.lang.String SYSTEM_HEALTH_SERVICE = "systemhealth";
field public static final java.lang.String TELECOM_SERVICE = "telecom";
@@ -9855,13 +9882,20 @@ package android.content.pm {
public class LauncherApps {
method public java.util.List getActivityList(java.lang.String, android.os.UserHandle);
+ method public android.graphics.drawable.Drawable getShortcutBadgedIconDrawable(android.content.pm.ShortcutInfo, int);
+ method public android.graphics.drawable.Drawable getShortcutIconDrawable(android.content.pm.ShortcutInfo, int);
+ method public java.util.List getShortcuts(android.content.pm.LauncherApps.ShortcutQuery, android.os.UserHandle);
+ method public boolean hasShortcutHostPermission();
method public boolean isActivityEnabled(android.content.ComponentName, android.os.UserHandle);
method public boolean isPackageEnabled(java.lang.String, android.os.UserHandle);
+ method public void pinShortcuts(java.lang.String, java.util.List, android.os.UserHandle);
method public void registerCallback(android.content.pm.LauncherApps.Callback);
method public void registerCallback(android.content.pm.LauncherApps.Callback, android.os.Handler);
method public android.content.pm.LauncherActivityInfo resolveActivity(android.content.Intent, android.os.UserHandle);
method public void startAppDetailsActivity(android.content.ComponentName, android.os.UserHandle, android.graphics.Rect, android.os.Bundle);
method public void startMainActivity(android.content.ComponentName, android.os.UserHandle, android.graphics.Rect, android.os.Bundle);
+ method public void startShortcut(java.lang.String, java.lang.String, android.graphics.Rect, android.os.Bundle, android.os.UserHandle);
+ method public void startShortcut(android.content.pm.ShortcutInfo, android.graphics.Rect, android.os.Bundle);
method public void unregisterCallback(android.content.pm.LauncherApps.Callback);
}
@@ -9874,6 +9908,20 @@ package android.content.pm {
method public void onPackagesSuspended(java.lang.String[], android.os.UserHandle);
method public abstract void onPackagesUnavailable(java.lang.String[], android.os.UserHandle, boolean);
method public void onPackagesUnsuspended(java.lang.String[], android.os.UserHandle);
+ method public void onShortcutsChanged(java.lang.String, java.util.List, android.os.UserHandle);
+ }
+
+ public static class LauncherApps.ShortcutQuery {
+ ctor public LauncherApps.ShortcutQuery();
+ method public android.content.pm.LauncherApps.ShortcutQuery setActivity(android.content.ComponentName);
+ method public android.content.pm.LauncherApps.ShortcutQuery setChangedSince(long);
+ method public android.content.pm.LauncherApps.ShortcutQuery setPackage(java.lang.String);
+ method public android.content.pm.LauncherApps.ShortcutQuery setQueryFlags(int);
+ method public android.content.pm.LauncherApps.ShortcutQuery setShortcutIds(java.util.List);
+ field public static final int FLAG_GET_KEY_FIELDS_ONLY = 4; // 0x4
+ field public static final int FLAG_MATCH_DYNAMIC = 1; // 0x1
+ field public static final int FLAG_MATCH_MANIFEST = 8; // 0x8
+ field public static final int FLAG_MATCH_PINNED = 2; // 0x2
}
public class PackageInfo implements android.os.Parcelable {
@@ -10444,6 +10492,66 @@ package android.content.pm {
field public java.lang.String permission;
}
+ public final class ShortcutInfo implements android.os.Parcelable {
+ method public int describeContents();
+ method public android.content.ComponentName getActivity();
+ method public java.util.Set getCategories();
+ method public java.lang.CharSequence getDisabledMessage();
+ method public android.os.PersistableBundle getExtras();
+ method public java.lang.String getId();
+ method public android.content.Intent getIntent();
+ method public android.content.Intent[] getIntents();
+ method public long getLastChangedTimestamp();
+ method public java.lang.CharSequence getLongLabel();
+ method public java.lang.String getPackage();
+ method public int getRank();
+ method public java.lang.CharSequence getShortLabel();
+ method public android.os.UserHandle getUserHandle();
+ method public boolean hasKeyFieldsOnly();
+ method public boolean isDeclaredInManifest();
+ method public boolean isDynamic();
+ method public boolean isEnabled();
+ method public boolean isImmutable();
+ method public boolean isPinned();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator CREATOR;
+ field public static final java.lang.String SHORTCUT_CATEGORY_CONVERSATION = "android.shortcut.conversation";
+ }
+
+ public static class ShortcutInfo.Builder {
+ ctor public ShortcutInfo.Builder(android.content.Context, java.lang.String);
+ method public android.content.pm.ShortcutInfo build();
+ method public android.content.pm.ShortcutInfo.Builder setActivity(android.content.ComponentName);
+ method public android.content.pm.ShortcutInfo.Builder setCategories(java.util.Set);
+ method public android.content.pm.ShortcutInfo.Builder setDisabledMessage(java.lang.CharSequence);
+ method public android.content.pm.ShortcutInfo.Builder setExtras(android.os.PersistableBundle);
+ method public android.content.pm.ShortcutInfo.Builder setIcon(android.graphics.drawable.Icon);
+ method public android.content.pm.ShortcutInfo.Builder setIntent(android.content.Intent);
+ method public android.content.pm.ShortcutInfo.Builder setIntents(android.content.Intent[]);
+ method public android.content.pm.ShortcutInfo.Builder setLongLabel(java.lang.CharSequence);
+ method public android.content.pm.ShortcutInfo.Builder setRank(int);
+ method public android.content.pm.ShortcutInfo.Builder setShortLabel(java.lang.CharSequence);
+ }
+
+ public class ShortcutManager {
+ method public boolean addDynamicShortcuts(java.util.List);
+ method public void disableShortcuts(java.util.List);
+ method public void disableShortcuts(java.util.List, java.lang.CharSequence);
+ method public void enableShortcuts(java.util.List);
+ method public java.util.List getDynamicShortcuts();
+ method public int getIconMaxHeight();
+ method public int getIconMaxWidth();
+ method public java.util.List getManifestShortcuts();
+ method public int getMaxShortcutCountPerActivity();
+ method public java.util.List getPinnedShortcuts();
+ method public boolean isRateLimitingActive();
+ method public void removeAllDynamicShortcuts();
+ method public void removeDynamicShortcuts(java.util.List);
+ method public void reportShortcutUsed(java.lang.String);
+ method public boolean setDynamicShortcuts(java.util.List);
+ method public boolean updateShortcuts(java.util.List);
+ }
+
public class Signature implements android.os.Parcelable {
ctor public Signature(byte[]);
ctor public Signature(java.lang.String);
@@ -10664,7 +10772,7 @@ package android.content.res {
}
public class Resources {
- ctor public Resources(android.content.res.AssetManager, android.util.DisplayMetrics, android.content.res.Configuration);
+ ctor public deprecated Resources(android.content.res.AssetManager, android.util.DisplayMetrics, android.content.res.Configuration);
method public final void finishPreloading();
method public final void flushLayoutCache();
method public android.content.res.XmlResourceParser getAnimation(int) throws android.content.res.Resources.NotFoundException;
@@ -10715,7 +10823,7 @@ package android.content.res {
method public android.content.res.AssetFileDescriptor openRawResourceFd(int) throws android.content.res.Resources.NotFoundException;
method public void parseBundleExtra(java.lang.String, android.util.AttributeSet, android.os.Bundle) throws org.xmlpull.v1.XmlPullParserException;
method public void parseBundleExtras(android.content.res.XmlResourceParser, android.os.Bundle) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
- method public void updateConfiguration(android.content.res.Configuration, android.util.DisplayMetrics);
+ method public deprecated void updateConfiguration(android.content.res.Configuration, android.util.DisplayMetrics);
}
public static class Resources.NotFoundException extends java.lang.RuntimeException {
@@ -21064,6 +21172,7 @@ package android.media {
field public static final android.os.Parcelable.Creator CREATOR;
field public static final int ENCODING_AC3 = 5; // 0x5
field public static final int ENCODING_DEFAULT = 1; // 0x1
+ field public static final int ENCODING_DOLBY_TRUEHD = 14; // 0xe
field public static final int ENCODING_DTS = 7; // 0x7
field public static final int ENCODING_DTS_HD = 8; // 0x8
field public static final int ENCODING_E_AC3 = 6; // 0x6
@@ -25916,6 +26025,33 @@ package android.net.http {
package android.net.metrics {
+ public final class ApfProgramEvent implements android.os.Parcelable {
+ method public int describeContents();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator CREATOR;
+ field public static final int FLAG_HAS_IPV4_ADDRESS = 1; // 0x1
+ field public static final int FLAG_MULTICAST_FILTER_ON = 0; // 0x0
+ field public final int currentRas;
+ field public final int filteredRas;
+ field public final int flags;
+ field public final long lifetime;
+ field public final int programLength;
+ }
+
+ public final class ApfStats implements android.os.Parcelable {
+ method public int describeContents();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator CREATOR;
+ field public final int droppedRas;
+ field public final long durationMs;
+ field public final int matchingRas;
+ field public final int maxProgramSize;
+ field public final int parseErrors;
+ field public final int programUpdates;
+ field public final int receivedRas;
+ field public final int zeroLifetimeRas;
+ }
+
public final class DefaultNetworkEvent implements android.os.Parcelable {
method public int describeContents();
method public static void logEvent(int, int[], int, boolean, boolean);
@@ -25933,6 +26069,7 @@ package android.net.metrics {
method public static void logStateEvent(java.lang.String, java.lang.String);
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator CREATOR;
+ field public final int durationMs;
field public final java.lang.String ifName;
field public final java.lang.String msg;
}
@@ -26024,6 +26161,18 @@ package android.net.metrics {
field public final int netId;
}
+ public final class RaEvent implements android.os.Parcelable {
+ method public int describeContents();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator CREATOR;
+ field public final long dnsslLifetime;
+ field public final long prefixPreferredLifetime;
+ field public final long prefixValidLifetime;
+ field public final long rdnssLifetime;
+ field public final long routeInfoLifetime;
+ field public final long routerLifetime;
+ }
+
public final class ValidationProbeEvent implements android.os.Parcelable {
method public int describeContents();
method public static void logEvent(int, long, int, int);
@@ -30709,6 +30858,7 @@ package android.os {
field public static final int LOLLIPOP_MR1 = 22; // 0x16
field public static final int M = 23; // 0x17
field public static final int N = 24; // 0x18
+ field public static final int N_MR1 = 25; // 0x19
}
public final class Bundle extends android.os.BaseBundle implements java.lang.Cloneable android.os.Parcelable {
@@ -31544,6 +31694,7 @@ package android.os {
method public static void installPackage(android.content.Context, java.io.File, boolean) throws java.io.IOException;
method public static void processPackage(android.content.Context, java.io.File, android.os.RecoverySystem.ProgressListener, android.os.Handler) throws java.io.IOException;
method public static void processPackage(android.content.Context, java.io.File, android.os.RecoverySystem.ProgressListener) throws java.io.IOException;
+ method public static void rebootWipeAb(android.content.Context, java.io.File, java.lang.String) throws java.io.IOException;
method public static void rebootWipeCache(android.content.Context) throws java.io.IOException;
method public static void rebootWipeUserData(android.content.Context) throws java.io.IOException;
method public static void scheduleUpdateOnBoot(android.content.Context, java.io.File) throws java.io.IOException;
@@ -31784,6 +31935,7 @@ package android.os {
method public android.os.Bundle getUserRestrictions();
method public android.os.Bundle getUserRestrictions(android.os.UserHandle);
method public boolean hasUserRestriction(java.lang.String);
+ method public boolean isDemoUser();
method public boolean isManagedProfile();
method public boolean isManagedProfile(int);
method public boolean isQuietModeEnabled(android.os.UserHandle);
@@ -32032,6 +32184,7 @@ package android.os.storage {
method public boolean isObbMounted(java.lang.String);
method public boolean mountObb(java.lang.String, java.lang.String, android.os.storage.OnObbStateChangeListener);
method public boolean unmountObb(java.lang.String, boolean, android.os.storage.OnObbStateChangeListener);
+ field public static final java.lang.String ACTION_MANAGE_STORAGE = "android.os.storage.action.MANAGE_STORAGE";
}
public final class StorageVolume implements android.os.Parcelable {
@@ -33213,6 +33366,7 @@ package android.provider {
public static class CallLog.Calls implements android.provider.BaseColumns {
ctor public CallLog.Calls();
method public static java.lang.String getLastOutgoingCall(android.content.Context);
+ field public static final int ANSWERED_EXTERNALLY_TYPE = 7; // 0x7
field public static final int BLOCKED_TYPE = 6; // 0x6
field public static final java.lang.String CACHED_FORMATTED_NUMBER = "formatted_number";
field public static final java.lang.String CACHED_LOOKUP_URI = "lookup_uri";
@@ -33235,6 +33389,7 @@ package android.provider {
field public static final java.lang.String DURATION = "duration";
field public static final java.lang.String EXTRA_CALL_TYPE_FILTER = "android.provider.extra.CALL_TYPE_FILTER";
field public static final java.lang.String FEATURES = "features";
+ field public static final int FEATURES_PULLED_EXTERNALLY = 2; // 0x2
field public static final int FEATURES_VIDEO = 1; // 0x1
field public static final java.lang.String GEOCODED_LOCATION = "geocoded_location";
field public static final int INCOMING_TYPE = 1; // 0x1
@@ -35072,6 +35227,7 @@ package android.provider {
field public static final java.lang.String DATA_ROAMING = "data_roaming";
field public static final java.lang.String DEBUG_APP = "debug_app";
field public static final java.lang.String DEVELOPMENT_SETTINGS_ENABLED = "development_settings_enabled";
+ field public static final java.lang.String DEVICE_NAME = "device_name";
field public static final java.lang.String DEVICE_PROVISIONED = "device_provisioned";
field public static final java.lang.String HTTP_PROXY = "http_proxy";
field public static final deprecated java.lang.String INSTALL_NON_MARKET_APPS = "install_non_market_apps";
@@ -35660,6 +35816,7 @@ package android.provider {
field public static final java.lang.String ACTION_NEW_VOICEMAIL = "android.intent.action.NEW_VOICEMAIL";
field public static final java.lang.String ACTION_SYNC_VOICEMAIL = "android.provider.action.SYNC_VOICEMAIL";
field public static final java.lang.String AUTHORITY = "com.android.voicemail";
+ field public static final java.lang.String EXTRA_PHONE_ACCOUNT_HANDLE = "android.provider.extra.PHONE_ACCOUNT_HANDLE";
field public static final java.lang.String EXTRA_SELF_CHANGE = "com.android.voicemail.extra.SELF_CHANGE";
field public static final java.lang.String PARAM_KEY_SOURCE_PACKAGE = "source_package";
}
@@ -35668,6 +35825,9 @@ package android.provider {
method public static android.net.Uri buildSourceUri(java.lang.String);
field public static final java.lang.String CONFIGURATION_STATE = "configuration_state";
field public static final int CONFIGURATION_STATE_CAN_BE_CONFIGURED = 2; // 0x2
+ field public static final int CONFIGURATION_STATE_CONFIGURING = 3; // 0x3
+ field public static final int CONFIGURATION_STATE_DISABLED = 5; // 0x5
+ field public static final int CONFIGURATION_STATE_FAILED = 4; // 0x4
field public static final int CONFIGURATION_STATE_NOT_CONFIGURED = 1; // 0x1
field public static final int CONFIGURATION_STATE_OK = 0; // 0x0
field public static final android.net.Uri CONTENT_URI;
@@ -35692,6 +35852,7 @@ package android.provider {
field public static final int QUOTA_UNAVAILABLE = -1; // 0xffffffff
field public static final java.lang.String SETTINGS_URI = "settings_uri";
field public static final java.lang.String SOURCE_PACKAGE = "source_package";
+ field public static final java.lang.String SOURCE_TYPE = "source_type";
field public static final java.lang.String VOICEMAIL_ACCESS_URI = "voicemail_access_uri";
}
@@ -38772,10 +38933,15 @@ package android.telecom {
method public void phoneAccountSelected(android.telecom.PhoneAccountHandle, boolean);
method public void playDtmfTone(char);
method public void postDialContinue(boolean);
+ method public void pullExternalCall();
+ method public final void putExtras(android.os.Bundle);
method public void registerCallback(android.telecom.Call.Callback);
method public void registerCallback(android.telecom.Call.Callback, android.os.Handler);
method public void reject(boolean, java.lang.String);
+ method public final void removeExtras(java.util.List);
+ method public final void removeExtras(java.lang.String...);
method public deprecated void removeListener(android.telecom.Call.Listener);
+ method public void sendCallEvent(java.lang.String, android.os.Bundle);
method public void splitFromConference();
method public void stopDtmfTone();
method public void swapConference();
@@ -38790,6 +38956,7 @@ package android.telecom {
field public static final int STATE_HOLDING = 3; // 0x3
field public static final int STATE_NEW = 0; // 0x0
field public static final deprecated int STATE_PRE_DIAL_WAIT = 8; // 0x8
+ field public static final int STATE_PULLING_CALL = 11; // 0xb
field public static final int STATE_RINGING = 2; // 0x2
field public static final int STATE_SELECT_PHONE_ACCOUNT = 8; // 0x8
}
@@ -38800,6 +38967,7 @@ package android.telecom {
method public void onCannedTextResponsesLoaded(android.telecom.Call, java.util.List);
method public void onChildrenChanged(android.telecom.Call, java.util.List);
method public void onConferenceableCallsChanged(android.telecom.Call, java.util.List);
+ method public void onConnectionEvent(android.telecom.Call, java.lang.String, android.os.Bundle);
method public void onDetailsChanged(android.telecom.Call, android.telecom.Call.Details);
method public void onParentChanged(android.telecom.Call, android.telecom.Call);
method public void onPostDialWait(android.telecom.Call, java.lang.String);
@@ -38830,6 +38998,7 @@ package android.telecom {
method public static java.lang.String propertiesToString(int);
field public static final int CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO = 4194304; // 0x400000
field public static final int CAPABILITY_CAN_PAUSE_VIDEO = 1048576; // 0x100000
+ field public static final int CAPABILITY_CAN_PULL_CALL = 8388608; // 0x800000
field public static final int CAPABILITY_DISCONNECT_FROM_CONFERENCE = 8192; // 0x2000
field public static final int CAPABILITY_HOLD = 1; // 0x1
field public static final int CAPABILITY_MANAGE_CONFERENCE = 128; // 0x80
@@ -38849,7 +39018,9 @@ package android.telecom {
field public static final int PROPERTY_EMERGENCY_CALLBACK_MODE = 4; // 0x4
field public static final int PROPERTY_ENTERPRISE_CALL = 32; // 0x20
field public static final int PROPERTY_GENERIC_CONFERENCE = 2; // 0x2
+ field public static final int PROPERTY_HAS_CDMA_VOICE_PRIVACY = 128; // 0x80
field public static final int PROPERTY_HIGH_DEF_AUDIO = 16; // 0x10
+ field public static final int PROPERTY_IS_EXTERNAL_CALL = 64; // 0x40
field public static final int PROPERTY_WIFI = 8; // 0x8
}
@@ -38906,6 +39077,7 @@ package android.telecom {
method public final java.util.List getConferenceableConnections();
method public final deprecated long getConnectTimeMillis();
method public final int getConnectionCapabilities();
+ method public final int getConnectionProperties();
method public final long getConnectionTime();
method public final java.util.List getConnections();
method public final android.telecom.DisconnectCause getDisconnectCause();
@@ -38920,6 +39092,7 @@ package android.telecom {
method public void onCallAudioStateChanged(android.telecom.CallAudioState);
method public void onConnectionAdded(android.telecom.Connection);
method public void onDisconnect();
+ method public void onExtrasChanged(android.os.Bundle);
method public void onHold();
method public void onMerge(android.telecom.Connection);
method public void onMerge();
@@ -38928,11 +39101,15 @@ package android.telecom {
method public void onStopDtmfTone();
method public void onSwap();
method public void onUnhold();
+ method public final void putExtras(android.os.Bundle);
method public final void removeConnection(android.telecom.Connection);
+ method public final void removeExtras(java.util.List);
+ method public final void removeExtras(java.lang.String...);
method public final void setActive();
method public final void setConferenceableConnections(java.util.List);
method public final deprecated void setConnectTimeMillis(long);
method public final void setConnectionCapabilities(int);
+ method public final void setConnectionProperties(int);
method public final void setConnectionTime(long);
method public final void setDialing();
method public final void setDisconnected(android.telecom.DisconnectCause);
@@ -38963,6 +39140,7 @@ package android.telecom {
method public final android.telecom.Conference getConference();
method public final java.util.List getConferenceables();
method public final int getConnectionCapabilities();
+ method public final int getConnectionProperties();
method public final android.telecom.DisconnectCause getDisconnectCause();
method public final android.os.Bundle getExtras();
method public final int getState();
@@ -38974,16 +39152,24 @@ package android.telecom {
method public void onAnswer();
method public deprecated void onAudioStateChanged(android.telecom.AudioState);
method public void onCallAudioStateChanged(android.telecom.CallAudioState);
+ method public void onCallEvent(java.lang.String, android.os.Bundle);
method public void onDisconnect();
+ method public void onExtrasChanged(android.os.Bundle);
method public void onHold();
method public void onPlayDtmfTone(char);
method public void onPostDialContinue(boolean);
+ method public void onPullExternalCall();
method public void onReject();
method public void onReject(java.lang.String);
method public void onSeparate();
method public void onStateChanged(int);
method public void onStopDtmfTone();
method public void onUnhold();
+ method public static java.lang.String propertiesToString(int);
+ method public final void putExtras(android.os.Bundle);
+ method public final void removeExtras(java.util.List);
+ method public final void removeExtras(java.lang.String...);
+ method public void sendConnectionEvent(java.lang.String, android.os.Bundle);
method public final void setActive();
method public final void setAddress(android.net.Uri, int);
method public final void setAudioModeIsVoip(boolean);
@@ -38991,6 +39177,7 @@ package android.telecom {
method public final void setConferenceableConnections(java.util.List);
method public final void setConferenceables(java.util.List);
method public final void setConnectionCapabilities(int);
+ method public final void setConnectionProperties(int);
method public final void setDialing();
method public final void setDisconnected(android.telecom.DisconnectCause);
method public final void setExtras(android.os.Bundle);
@@ -38999,6 +39186,7 @@ package android.telecom {
method public final void setNextPostDialChar(char);
method public final void setOnHold();
method public final void setPostDialWait(java.lang.String);
+ method public final void setPulling();
method public final void setRingbackRequested(boolean);
method public final void setRinging();
method public final void setStatusHints(android.telecom.StatusHints);
@@ -39007,6 +39195,7 @@ package android.telecom {
method public static java.lang.String stateToString(int);
field public static final int CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO = 8388608; // 0x800000
field public static final int CAPABILITY_CAN_PAUSE_VIDEO = 1048576; // 0x100000
+ field public static final int CAPABILITY_CAN_PULL_CALL = 16777216; // 0x1000000
field public static final int CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION = 4194304; // 0x400000
field public static final int CAPABILITY_CAN_UPGRADE_TO_VIDEO = 524288; // 0x80000
field public static final int CAPABILITY_DISCONNECT_FROM_CONFERENCE = 8192; // 0x2000
@@ -39024,15 +39213,21 @@ package android.telecom {
field public static final int CAPABILITY_SUPPORTS_VT_REMOTE_TX = 2048; // 0x800
field public static final int CAPABILITY_SUPPORT_HOLD = 2; // 0x2
field public static final int CAPABILITY_SWAP_CONFERENCE = 8; // 0x8
+ field public static final java.lang.String EVENT_CALL_MERGE_FAILED = "android.telecom.event.CALL_MERGE_FAILED";
+ field public static final java.lang.String EVENT_CALL_PULL_FAILED = "android.telecom.event.CALL_PULL_FAILED";
+ field public static final java.lang.String EXTRA_ANSWERING_DROPS_FG_CALL = "android.telecom.extra.ANSWERING_DROPS_FG_CALL";
field public static final java.lang.String EXTRA_CALL_SUBJECT = "android.telecom.extra.CALL_SUBJECT";
field public static final java.lang.String EXTRA_CHILD_ADDRESS = "android.telecom.extra.CHILD_ADDRESS";
field public static final java.lang.String EXTRA_LAST_FORWARDED_NUMBER = "android.telecom.extra.LAST_FORWARDED_NUMBER";
+ field public static final int PROPERTY_HAS_CDMA_VOICE_PRIVACY = 32; // 0x20
+ field public static final int PROPERTY_IS_EXTERNAL_CALL = 16; // 0x10
field public static final int STATE_ACTIVE = 4; // 0x4
field public static final int STATE_DIALING = 3; // 0x3
field public static final int STATE_DISCONNECTED = 6; // 0x6
field public static final int STATE_HOLDING = 5; // 0x5
field public static final int STATE_INITIALIZING = 0; // 0x0
field public static final int STATE_NEW = 1; // 0x1
+ field public static final int STATE_PULLING_CALL = 7; // 0x7
field public static final int STATE_RINGING = 2; // 0x2
}
@@ -39110,7 +39305,9 @@ package android.telecom {
method public java.lang.String getReason();
method public int getTone();
method public void writeToParcel(android.os.Parcel, int);
+ field public static final int ANSWERED_ELSEWHERE = 11; // 0xb
field public static final int BUSY = 7; // 0x7
+ field public static final int CALL_PULLED = 12; // 0xc
field public static final int CANCELED = 4; // 0x4
field public static final int CONNECTION_MANAGER_NOT_SUPPORTED = 10; // 0xa
field public static final android.os.Parcelable.Creator CREATOR;
@@ -39147,6 +39344,7 @@ package android.telecom {
method public void onCallAudioStateChanged(android.telecom.CallAudioState);
method public void onCallRemoved(android.telecom.Call);
method public void onCanAddCallChanged(boolean);
+ method public void onConnectionEvent(android.telecom.Call, java.lang.String, android.os.Bundle);
method public deprecated void onPhoneCreated(android.telecom.Phone);
method public deprecated void onPhoneDestroyed(android.telecom.Phone);
method public void onSilenceRinger();
@@ -39184,14 +39382,16 @@ package android.telecom {
}
public class ParcelableCallAnalytics implements android.os.Parcelable {
- ctor public ParcelableCallAnalytics(long, long, int, boolean, boolean, int, int, boolean, java.lang.String, boolean);
+ ctor public ParcelableCallAnalytics(long, long, int, boolean, boolean, int, int, boolean, java.lang.String, boolean, java.util.List, java.util.List);
ctor public ParcelableCallAnalytics(android.os.Parcel);
+ method public java.util.List analyticsEvents();
method public int describeContents();
method public long getCallDurationMillis();
method public int getCallTechnologies();
method public int getCallTerminationCode();
method public int getCallType();
method public java.lang.String getConnectionService();
+ method public java.util.List getEventTimings();
method public long getStartTimeMillis();
method public boolean isAdditionalCall();
method public boolean isCreatedFromExistingConnection();
@@ -39212,6 +39412,73 @@ package android.telecom {
field public static final int THIRD_PARTY_PHONE = 16; // 0x10
}
+ public static final class ParcelableCallAnalytics.AnalyticsEvent implements android.os.Parcelable {
+ ctor public ParcelableCallAnalytics.AnalyticsEvent(int, long);
+ method public int describeContents();
+ method public int getEventName();
+ method public long getTimeSinceLastEvent();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final int AUDIO_ROUTE_BT = 204; // 0xcc
+ field public static final int AUDIO_ROUTE_EARPIECE = 205; // 0xcd
+ field public static final int AUDIO_ROUTE_HEADSET = 206; // 0xce
+ field public static final int AUDIO_ROUTE_SPEAKER = 207; // 0xcf
+ field public static final int BIND_CS = 5; // 0x5
+ field public static final int BLOCK_CHECK_FINISHED = 105; // 0x69
+ field public static final int BLOCK_CHECK_INITIATED = 104; // 0x68
+ field public static final int CONFERENCE_WITH = 300; // 0x12c
+ field public static final android.os.Parcelable.Creator CREATOR;
+ field public static final int CS_BOUND = 6; // 0x6
+ field public static final int DIRECT_TO_VM_FINISHED = 103; // 0x67
+ field public static final int DIRECT_TO_VM_INITIATED = 102; // 0x66
+ field public static final int FILTERING_COMPLETED = 107; // 0x6b
+ field public static final int FILTERING_INITIATED = 106; // 0x6a
+ field public static final int FILTERING_TIMED_OUT = 108; // 0x6c
+ field public static final int MUTE = 202; // 0xca
+ field public static final int REMOTELY_HELD = 402; // 0x192
+ field public static final int REMOTELY_UNHELD = 403; // 0x193
+ field public static final int REQUEST_ACCEPT = 7; // 0x7
+ field public static final int REQUEST_HOLD = 400; // 0x190
+ field public static final int REQUEST_PULL = 500; // 0x1f4
+ field public static final int REQUEST_REJECT = 8; // 0x8
+ field public static final int REQUEST_UNHOLD = 401; // 0x191
+ field public static final int SCREENING_COMPLETED = 101; // 0x65
+ field public static final int SCREENING_SENT = 100; // 0x64
+ field public static final int SET_ACTIVE = 1; // 0x1
+ field public static final int SET_DIALING = 4; // 0x4
+ field public static final int SET_DISCONNECTED = 2; // 0x2
+ field public static final int SET_HOLD = 404; // 0x194
+ field public static final int SET_PARENT = 302; // 0x12e
+ field public static final int SET_SELECT_PHONE_ACCOUNT = 0; // 0x0
+ field public static final int SILENCE = 201; // 0xc9
+ field public static final int SKIP_RINGING = 200; // 0xc8
+ field public static final int SPLIT_CONFERENCE = 301; // 0x12d
+ field public static final int START_CONNECTION = 3; // 0x3
+ field public static final int SWAP = 405; // 0x195
+ field public static final int UNMUTE = 203; // 0xcb
+ }
+
+ public static final class ParcelableCallAnalytics.EventTiming implements android.os.Parcelable {
+ ctor public ParcelableCallAnalytics.EventTiming(int, long);
+ method public int describeContents();
+ method public int getName();
+ method public long getTime();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final int ACCEPT_TIMING = 0; // 0x0
+ field public static final int BIND_CS_TIMING = 6; // 0x6
+ field public static final int BLOCK_CHECK_FINISHED_TIMING = 9; // 0x9
+ field public static final android.os.Parcelable.Creator CREATOR;
+ field public static final int DIRECT_TO_VM_FINISHED_TIMING = 8; // 0x8
+ field public static final int DISCONNECT_TIMING = 2; // 0x2
+ field public static final int FILTERING_COMPLETED_TIMING = 10; // 0xa
+ field public static final int FILTERING_TIMED_OUT_TIMING = 11; // 0xb
+ field public static final int HOLD_TIMING = 3; // 0x3
+ field public static final int INVALID = 999999; // 0xf423f
+ field public static final int OUTGOING_TIME_TO_DIALING_TIMING = 5; // 0x5
+ field public static final int REJECT_TIMING = 1; // 0x1
+ field public static final int SCREENING_COMPLETED_TIMING = 7; // 0x7
+ field public static final int UNHOLD_TIMING = 4; // 0x4
+ }
+
public final deprecated class Phone {
method public final void addListener(android.telecom.Phone.Listener);
method public final boolean canAddCall();
@@ -39324,6 +39591,7 @@ package android.telecom {
method public void onConferenceableConnectionsChanged(android.telecom.RemoteConference, java.util.List);
method public void onConnectionAdded(android.telecom.RemoteConference, android.telecom.RemoteConnection);
method public void onConnectionCapabilitiesChanged(android.telecom.RemoteConference, int);
+ method public void onConnectionPropertiesChanged(android.telecom.RemoteConference, int);
method public void onConnectionRemoved(android.telecom.RemoteConference, android.telecom.RemoteConnection);
method public void onDestroyed(android.telecom.RemoteConference);
method public void onDisconnected(android.telecom.RemoteConference, android.telecom.DisconnectCause);
@@ -39342,6 +39610,7 @@ package android.telecom {
method public android.telecom.RemoteConference getConference();
method public java.util.List getConferenceableConnections();
method public int getConnectionCapabilities();
+ method public int getConnectionProperties();
method public android.telecom.DisconnectCause getDisconnectCause();
method public final android.os.Bundle getExtras();
method public int getState();
@@ -39353,6 +39622,7 @@ package android.telecom {
method public boolean isVoipAudioMode();
method public void playDtmfTone(char);
method public void postDialContinue(boolean);
+ method public void pullExternalCall();
method public void registerCallback(android.telecom.RemoteConnection.Callback);
method public void registerCallback(android.telecom.RemoteConnection.Callback, android.os.Handler);
method public void reject();
@@ -39370,6 +39640,8 @@ package android.telecom {
method public void onConferenceChanged(android.telecom.RemoteConnection, android.telecom.RemoteConference);
method public void onConferenceableConnectionsChanged(android.telecom.RemoteConnection, java.util.List);
method public void onConnectionCapabilitiesChanged(android.telecom.RemoteConnection, int);
+ method public void onConnectionEvent(android.telecom.RemoteConnection, java.lang.String, android.os.Bundle);
+ method public void onConnectionPropertiesChanged(android.telecom.RemoteConnection, int);
method public void onDestroyed(android.telecom.RemoteConnection);
method public void onDisconnected(android.telecom.RemoteConnection, android.telecom.DisconnectCause);
method public void onExtrasChanged(android.telecom.RemoteConnection, android.os.Bundle);
@@ -39423,6 +39695,41 @@ package android.telecom {
field public static final android.os.Parcelable.Creator CREATOR;
}
+ public final class TelecomAnalytics implements android.os.Parcelable {
+ ctor public TelecomAnalytics(java.util.List, java.util.List);
+ method public int describeContents();
+ method public java.util.List getCallAnalytics();
+ method public java.util.List getSessionTimings();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator CREATOR;
+ }
+
+ public static final class TelecomAnalytics.SessionTiming implements android.os.Parcelable {
+ ctor public TelecomAnalytics.SessionTiming(int, long);
+ method public int describeContents();
+ method public java.lang.Integer getKey();
+ method public long getTime();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator CREATOR;
+ field public static final int CSW_ADD_CONFERENCE_CALL = 108; // 0x6c
+ field public static final int CSW_HANDLE_CREATE_CONNECTION_COMPLETE = 100; // 0x64
+ field public static final int CSW_REMOVE_CALL = 106; // 0x6a
+ field public static final int CSW_SET_ACTIVE = 101; // 0x65
+ field public static final int CSW_SET_DIALING = 103; // 0x67
+ field public static final int CSW_SET_DISCONNECTED = 104; // 0x68
+ field public static final int CSW_SET_IS_CONFERENCED = 107; // 0x6b
+ field public static final int CSW_SET_ON_HOLD = 105; // 0x69
+ field public static final int CSW_SET_RINGING = 102; // 0x66
+ field public static final int ICA_ANSWER_CALL = 1; // 0x1
+ field public static final int ICA_CONFERENCE = 8; // 0x8
+ field public static final int ICA_DISCONNECT_CALL = 3; // 0x3
+ field public static final int ICA_HOLD_CALL = 4; // 0x4
+ field public static final int ICA_MUTE = 6; // 0x6
+ field public static final int ICA_REJECT_CALL = 2; // 0x2
+ field public static final int ICA_SET_AUDIO_ROUTE = 7; // 0x7
+ field public static final int ICA_UNHOLD_CALL = 5; // 0x5
+ }
+
public class TelecomManager {
method public void acceptRingingCall();
method public void acceptRingingCall(int);
@@ -39432,7 +39739,7 @@ package android.telecom {
method public deprecated void clearAccounts();
method public void clearPhoneAccounts();
method public android.content.Intent createManageBlockedNumbersIntent();
- method public java.util.List dumpAnalytics();
+ method public android.telecom.TelecomAnalytics dumpAnalytics();
method public void enablePhoneAccount(android.telecom.PhoneAccountHandle, boolean);
method public boolean endCall();
method public android.net.Uri getAdnUriForPhoneAccount(android.telecom.PhoneAccountHandle);
@@ -39493,6 +39800,7 @@ package android.telecom {
field public static final java.lang.String EXTRA_START_CALL_WITH_VIDEO_STATE = "android.telecom.extra.START_CALL_WITH_VIDEO_STATE";
field public static final java.lang.String GATEWAY_ORIGINAL_ADDRESS = "android.telecom.extra.GATEWAY_ORIGINAL_ADDRESS";
field public static final java.lang.String GATEWAY_PROVIDER_PACKAGE = "android.telecom.extra.GATEWAY_PROVIDER_PACKAGE";
+ field public static final java.lang.String METADATA_INCLUDE_EXTERNAL_CALLS = "android.telecom.INCLUDE_EXTERNAL_CALLS";
field public static final java.lang.String METADATA_IN_CALL_SERVICE_RINGING = "android.telecom.IN_CALL_SERVICE_RINGING";
field public static final java.lang.String METADATA_IN_CALL_SERVICE_UI = "android.telecom.IN_CALL_SERVICE_UI";
field public static final int PRESENTATION_ALLOWED = 1; // 0x1
@@ -39549,9 +39857,11 @@ package android.telephony {
field public static final java.lang.String ACTION_CARRIER_CONFIG_CHANGED = "android.telephony.action.CARRIER_CONFIG_CHANGED";
field public static final java.lang.String KEY_ADDITIONAL_CALL_SETTING_BOOL = "additional_call_setting_bool";
field public static final java.lang.String KEY_ALLOW_ADDING_APNS_BOOL = "allow_adding_apns_bool";
+ field public static final java.lang.String KEY_ALLOW_ADD_CALL_DURING_VIDEO_CALL_BOOL = "allow_add_call_during_video_call";
field public static final java.lang.String KEY_ALLOW_EMERGENCY_NUMBERS_IN_CALL_LOG_BOOL = "allow_emergency_numbers_in_call_log_bool";
field public static final java.lang.String KEY_ALLOW_EMERGENCY_VIDEO_CALLS_BOOL = "allow_emergency_video_calls_bool";
field public static final java.lang.String KEY_ALLOW_LOCAL_DTMF_TONES_BOOL = "allow_local_dtmf_tones_bool";
+ field public static final java.lang.String KEY_ALLOW_MERGE_WIFI_CALLS_WHEN_VOWIFI_OFF_BOOL = "allow_merge_wifi_calls_when_vowifi_off_bool";
field public static final java.lang.String KEY_ALLOW_NON_EMERGENCY_CALLS_IN_ECM_BOOL = "allow_non_emergency_calls_in_ecm_bool";
field public static final java.lang.String KEY_ALWAYS_SHOW_EMERGENCY_ALERT_ONOFF_BOOL = "always_show_emergency_alert_onoff_bool";
field public static final java.lang.String KEY_APN_EXPAND_BOOL = "apn_expand_bool";
@@ -39583,6 +39893,7 @@ package android.telephony {
field public static final java.lang.String KEY_CSP_ENABLED_BOOL = "csp_enabled_bool";
field public static final java.lang.String KEY_DEFAULT_SIM_CALL_MANAGER_STRING = "default_sim_call_manager_string";
field public static final java.lang.String KEY_DISABLE_CDMA_ACTIVATION_CODE_BOOL = "disable_cdma_activation_code_bool";
+ field public static final java.lang.String KEY_DROP_VIDEO_CALL_WHEN_ANSWERING_AUDIO_CALL_BOOL = "drop_video_call_when_answering_audio_call_bool";
field public static final java.lang.String KEY_DTMF_TYPE_ENABLED_BOOL = "dtmf_type_enabled_bool";
field public static final java.lang.String KEY_DURATION_BLOCKING_DISABLED_AFTER_EMERGENCY_INT = "duration_blocking_disabled_after_emergency_int";
field public static final java.lang.String KEY_EDITABLE_ENHANCED_4G_LTE_BOOL = "editable_enhanced_4g_lte_bool";
@@ -39640,6 +39951,7 @@ package android.telephony {
field public static final java.lang.String KEY_SUPPORT_CONFERENCE_CALL_BOOL = "support_conference_call_bool";
field public static final java.lang.String KEY_SUPPORT_PAUSE_IMS_VIDEO_CALLS_BOOL = "support_pause_ims_video_calls_bool";
field public static final java.lang.String KEY_SUPPORT_SWAP_AFTER_MERGE_BOOL = "support_swap_after_merge_bool";
+ field public static final java.lang.String KEY_TREAT_DOWNGRADED_VIDEO_CALLS_AS_VIDEO_CALLS_BOOL = "treat_downgraded_video_calls_as_video_calls_bool";
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_USE_RCS_PRESENCE_BOOL = "use_rcs_presence_bool";
@@ -40135,6 +40447,26 @@ package android.telephony {
method public void onSubscriptionsChanged();
}
+ public final class TelephonyHistogram implements android.os.Parcelable {
+ ctor public TelephonyHistogram(int, int, int);
+ ctor public TelephonyHistogram(android.telephony.TelephonyHistogram);
+ ctor public TelephonyHistogram(android.os.Parcel);
+ method public void addTimeTaken(int);
+ method public int describeContents();
+ method public int getAverageTime();
+ method public int getBucketCount();
+ method public int[] getBucketCounters();
+ method public int[] getBucketEndPoints();
+ method public int getCategory();
+ method public int getId();
+ method public int getMaxTime();
+ method public int getMinTime();
+ method public int getSampleCount();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator CREATOR;
+ field public static final int TELEPHONY_CATEGORY_RIL = 1; // 0x1
+ }
+
public class TelephonyManager {
method public void answerRingingCall();
method public void call(java.lang.String, java.lang.String);
@@ -40184,6 +40516,7 @@ package android.telephony {
method public java.lang.String getSimSerialNumber();
method public int getSimState();
method public java.lang.String getSubscriberId();
+ method public java.util.List getTelephonyHistograms();
method public java.lang.String getVoiceMailAlphaTag();
method public java.lang.String getVoiceMailNumber();
method public int getVoiceNetworkType();
@@ -40207,6 +40540,7 @@ package android.telephony {
method public boolean isSmsCapable();
method public boolean isTtyModeSupported();
method public boolean isVideoCallingEnabled();
+ method public boolean isVisualVoicemailEnabled(android.telecom.PhoneAccountHandle);
method public boolean isVoiceCapable();
method public boolean isVoicemailVibrationEnabled(android.telecom.PhoneAccountHandle);
method public boolean isWorldPhone();
@@ -40220,6 +40554,7 @@ package android.telephony {
method public boolean setPreferredNetworkTypeToGlobal();
method public boolean setRadio(boolean);
method public boolean setRadioPower(boolean);
+ method public void setVisualVoicemailEnabled(android.telecom.PhoneAccountHandle, boolean);
method public boolean setVoiceMailNumber(java.lang.String, java.lang.String);
method public void silenceRinger();
method public boolean supplyPin(java.lang.String);
@@ -40272,12 +40607,15 @@ package android.telephony {
field public static final int NETWORK_TYPE_EVDO_A = 6; // 0x6
field public static final int NETWORK_TYPE_EVDO_B = 12; // 0xc
field public static final int NETWORK_TYPE_GPRS = 1; // 0x1
+ field public static final int NETWORK_TYPE_GSM = 16; // 0x10
field public static final int NETWORK_TYPE_HSDPA = 8; // 0x8
field public static final int NETWORK_TYPE_HSPA = 10; // 0xa
field public static final int NETWORK_TYPE_HSPAP = 15; // 0xf
field public static final int NETWORK_TYPE_HSUPA = 9; // 0x9
field public static final int NETWORK_TYPE_IDEN = 11; // 0xb
+ field public static final int NETWORK_TYPE_IWLAN = 18; // 0x12
field public static final int NETWORK_TYPE_LTE = 13; // 0xd
+ field public static final int NETWORK_TYPE_TD_SCDMA = 17; // 0x11
field public static final int NETWORK_TYPE_UMTS = 3; // 0x3
field public static final int NETWORK_TYPE_UNKNOWN = 0; // 0x0
field public static final int PHONE_TYPE_CDMA = 2; // 0x2
@@ -43095,7 +43433,10 @@ package android.util {
method public boolean equals(android.util.DisplayMetrics);
method public void setTo(android.util.DisplayMetrics);
method public void setToDefaults();
+ field public static final int DENSITY_260 = 260; // 0x104
field public static final int DENSITY_280 = 280; // 0x118
+ field public static final int DENSITY_300 = 300; // 0x12c
+ field public static final int DENSITY_340 = 340; // 0x154
field public static final int DENSITY_360 = 360; // 0x168
field public static final int DENSITY_400 = 400; // 0x190
field public static final int DENSITY_420 = 420; // 0x1a4
@@ -44425,6 +44766,10 @@ package android.view {
field public static final int KEYCODE_SWITCH_CHARSET = 95; // 0x5f
field public static final int KEYCODE_SYM = 63; // 0x3f
field public static final int KEYCODE_SYSRQ = 120; // 0x78
+ field public static final int KEYCODE_SYSTEM_NAVIGATION_DOWN = 281; // 0x119
+ field public static final int KEYCODE_SYSTEM_NAVIGATION_LEFT = 282; // 0x11a
+ field public static final int KEYCODE_SYSTEM_NAVIGATION_RIGHT = 283; // 0x11b
+ field public static final int KEYCODE_SYSTEM_NAVIGATION_UP = 280; // 0x118
field public static final int KEYCODE_T = 48; // 0x30
field public static final int KEYCODE_TAB = 61; // 0x3d
field public static final int KEYCODE_TV = 170; // 0xaa
@@ -45307,6 +45652,7 @@ package android.view {
method public float getPivotY();
method public android.view.PointerIcon getPointerIcon();
method public android.content.res.Resources getResources();
+ method public final boolean getRevealOnFocusHint();
method public final int getRight();
method protected float getRightFadingEdgeStrength();
method protected int getRightPaddingOffset();
@@ -45594,6 +45940,7 @@ package android.view {
method public void setPivotY(float);
method public void setPointerIcon(android.view.PointerIcon);
method public void setPressed(boolean);
+ method public final void setRevealOnFocusHint(boolean);
method public final void setRight(int);
method public void setRotation(float);
method public void setRotationX(float);
@@ -46746,6 +47093,7 @@ package android.view {
field public static final int TYPE_APPLICATION_SUB_PANEL = 1002; // 0x3ea
field public static final int TYPE_BASE_APPLICATION = 1; // 0x1
field public static final int TYPE_CHANGED = 2; // 0x2
+ field public static final int TYPE_DRAWN_APPLICATION = 4; // 0x4
field public static final int TYPE_INPUT_METHOD = 2011; // 0x7db
field public static final int TYPE_INPUT_METHOD_DIALOG = 2012; // 0x7dc
field public static final int TYPE_KEYGUARD_DIALOG = 2009; // 0x7d9
@@ -47518,6 +47866,7 @@ package android.view.inputmethod {
method public boolean clearMetaKeyStates(int);
method public void closeConnection();
method public boolean commitCompletion(android.view.inputmethod.CompletionInfo);
+ method public boolean commitContent(android.view.inputmethod.InputContentInfo, int, android.os.Bundle);
method public boolean commitCorrection(android.view.inputmethod.CorrectionInfo);
method public boolean commitText(java.lang.CharSequence, int);
method public boolean deleteSurroundingText(int, int);
@@ -47627,6 +47976,7 @@ package android.view.inputmethod {
field public static final int IME_NULL = 0; // 0x0
field public int actionId;
field public java.lang.CharSequence actionLabel;
+ field public java.lang.String[] contentMimeTypes;
field public android.os.Bundle extras;
field public int fieldId;
field public java.lang.String fieldName;
@@ -47686,6 +48036,7 @@ package android.view.inputmethod {
method public abstract boolean clearMetaKeyStates(int);
method public abstract void closeConnection();
method public abstract boolean commitCompletion(android.view.inputmethod.CompletionInfo);
+ method public abstract boolean commitContent(android.view.inputmethod.InputContentInfo, int, android.os.Bundle);
method public abstract boolean commitCorrection(android.view.inputmethod.CorrectionInfo);
method public abstract boolean commitText(java.lang.CharSequence, int);
method public abstract boolean deleteSurroundingText(int, int);
@@ -47711,6 +48062,7 @@ package android.view.inputmethod {
field public static final int CURSOR_UPDATE_MONITOR = 2; // 0x2
field public static final int GET_EXTRACTED_TEXT_MONITOR = 1; // 0x1
field public static final int GET_TEXT_WITH_STYLES = 1; // 0x1
+ field public static final int INPUT_CONTENT_GRANT_READ_URI_PERMISSION = 1; // 0x1
}
public class InputConnectionWrapper implements android.view.inputmethod.InputConnection {
@@ -47719,6 +48071,7 @@ package android.view.inputmethod {
method public boolean clearMetaKeyStates(int);
method public void closeConnection();
method public boolean commitCompletion(android.view.inputmethod.CompletionInfo);
+ method public boolean commitContent(android.view.inputmethod.InputContentInfo, int, android.os.Bundle);
method public boolean commitCorrection(android.view.inputmethod.CorrectionInfo);
method public boolean commitText(java.lang.CharSequence, int);
method public boolean deleteSurroundingText(int, int);
@@ -47743,6 +48096,19 @@ package android.view.inputmethod {
method public void setTarget(android.view.inputmethod.InputConnection);
}
+ public final class InputContentInfo implements android.os.Parcelable {
+ ctor public InputContentInfo(android.net.Uri, android.content.ClipDescription);
+ ctor public InputContentInfo(android.net.Uri, android.content.ClipDescription, android.net.Uri);
+ method public int describeContents();
+ method public android.net.Uri getContentUri();
+ method public android.content.ClipDescription getDescription();
+ method public android.net.Uri getLinkUri();
+ method public void releasePermission();
+ method public void requestPermission();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator CREATOR;
+ }
+
public abstract interface InputMethod {
method public abstract void attachToken(android.os.IBinder);
method public abstract void bindInput(android.view.inputmethod.InputBinding);
diff --git a/api/test-current.txt b/api/test-current.txt
index a70e9e3f7e19ead077bfdadf6e121325c51273a3..3b5c2231ccf2ac281668bd86d75ba12024fcb36e 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -397,6 +397,7 @@ package android {
field public static final int colorPressedHighlight = 16843661; // 0x101038d
field public static final int colorPrimary = 16843827; // 0x1010433
field public static final int colorPrimaryDark = 16843828; // 0x1010434
+ field public static final int colorSecondary = 16844080; // 0x1010530
field public static final int columnCount = 16843639; // 0x1010377
field public static final int columnDelay = 16843215; // 0x10101cf
field public static final int columnOrderPreserved = 16843640; // 0x1010378
@@ -420,7 +421,9 @@ package android {
field public static final int contentInsetStart = 16843859; // 0x1010453
field public static final int contentInsetStartWithNavigation = 16844066; // 0x1010522
field public static final int contextClickable = 16844007; // 0x10104e7
+ field public static final int contextDescription = 16844078; // 0x101052e
field public static final int contextPopupMenuStyle = 16844033; // 0x1010501
+ field public static final int contextUri = 16844077; // 0x101052d
field public static final int controlX1 = 16843772; // 0x10103fc
field public static final int controlX2 = 16843774; // 0x10103fe
field public static final int controlY1 = 16843773; // 0x10103fd
@@ -1039,6 +1042,7 @@ package android {
field public static final int rotation = 16843558; // 0x1010326
field public static final int rotationX = 16843559; // 0x1010327
field public static final int rotationY = 16843560; // 0x1010328
+ field public static final int roundIcon = 16844076; // 0x101052c
field public static final int rowCount = 16843637; // 0x1010375
field public static final int rowDelay = 16843216; // 0x10101d0
field public static final int rowEdgeFlags = 16843329; // 0x1010241
@@ -1106,11 +1110,16 @@ package android {
field public static final int shareInterpolator = 16843195; // 0x10101bb
field public static final int sharedUserId = 16842763; // 0x101000b
field public static final int sharedUserLabel = 16843361; // 0x1010261
+ field public static final int shortcutDisabledMessage = 16844075; // 0x101052b
+ field public static final int shortcutId = 16844072; // 0x1010528
+ field public static final int shortcutLongLabel = 16844074; // 0x101052a
+ field public static final int shortcutShortLabel = 16844073; // 0x1010529
field public static final int shouldDisableView = 16843246; // 0x10101ee
field public static final int showAsAction = 16843481; // 0x10102d9
field public static final int showDefault = 16843258; // 0x10101fa
field public static final int showDividers = 16843561; // 0x1010329
field public static final int showForAllUsers = 16844015; // 0x10104ef
+ field public static final int showMetadataInPreview = 16844079; // 0x101052f
field public static final deprecated int showOnLockScreen = 16843721; // 0x10103c9
field public static final int showSilent = 16843259; // 0x10101fb
field public static final int showText = 16843949; // 0x10104ad
@@ -3696,6 +3705,7 @@ package android.app {
method public void moveTaskToFront(int, int);
method public void moveTaskToFront(int, int, android.os.Bundle);
method public deprecated void restartPackage(java.lang.String);
+ method public static void setVrThread(int);
method public void setWatchHeapLimit(long);
field public static final java.lang.String ACTION_REPORT_HEAP_LIMIT = "android.app.action.REPORT_HEAP_LIMIT";
field public static final int LOCK_TASK_MODE_LOCKED = 1; // 0x1
@@ -5038,12 +5048,14 @@ package android.app {
method public android.app.Notification.Action.Builder extend(android.app.Notification.Action.Builder);
method public java.lang.CharSequence getCancelLabel();
method public java.lang.CharSequence getConfirmLabel();
+ method public boolean getHintDisplayActionInline();
method public boolean getHintLaunchesActivity();
method public java.lang.CharSequence getInProgressLabel();
method public boolean isAvailableOffline();
method public android.app.Notification.Action.WearableExtender setAvailableOffline(boolean);
method public android.app.Notification.Action.WearableExtender setCancelLabel(java.lang.CharSequence);
method public android.app.Notification.Action.WearableExtender setConfirmLabel(java.lang.CharSequence);
+ method public android.app.Notification.Action.WearableExtender setHintDisplayActionInline(boolean);
method public android.app.Notification.Action.WearableExtender setHintLaunchesActivity(boolean);
method public android.app.Notification.Action.WearableExtender setInProgressLabel(java.lang.CharSequence);
}
@@ -5762,7 +5774,10 @@ package android.app {
method public android.content.pm.ServiceInfo getServiceInfo();
method public java.lang.String getServiceName();
method public java.lang.String getSettingsActivity();
+ method public boolean getShowMetadataInPreview();
method public java.lang.CharSequence loadAuthor(android.content.pm.PackageManager) throws android.content.res.Resources.NotFoundException;
+ method public java.lang.CharSequence loadContextDescription(android.content.pm.PackageManager) throws android.content.res.Resources.NotFoundException;
+ method public android.net.Uri loadContextUri(android.content.pm.PackageManager) throws android.content.res.Resources.NotFoundException;
method public java.lang.CharSequence loadDescription(android.content.pm.PackageManager) throws android.content.res.Resources.NotFoundException;
method public android.graphics.drawable.Drawable loadIcon(android.content.pm.PackageManager);
method public java.lang.CharSequence loadLabel(android.content.pm.PackageManager);
@@ -6490,11 +6505,13 @@ package android.app.usage {
method public android.content.res.Configuration getConfiguration();
method public int getEventType();
method public java.lang.String getPackageName();
+ method public java.lang.String getShortcutId();
method public long getTimeStamp();
field public static final int CONFIGURATION_CHANGE = 5; // 0x5
field public static final int MOVE_TO_BACKGROUND = 2; // 0x2
field public static final int MOVE_TO_FOREGROUND = 1; // 0x1
field public static final int NONE = 0; // 0x0
+ field public static final int SHORTCUT_INVOCATION = 8; // 0x8
field public static final int USER_INTERACTION = 7; // 0x7
}
@@ -8199,6 +8216,7 @@ package android.content {
field public static final java.lang.String RESTRICTIONS_SERVICE = "restrictions";
field public static final java.lang.String SEARCH_SERVICE = "search";
field public static final java.lang.String SENSOR_SERVICE = "sensor";
+ field public static final java.lang.String SHORTCUT_SERVICE = "shortcut";
field public static final java.lang.String STORAGE_SERVICE = "storage";
field public static final java.lang.String SYSTEM_HEALTH_SERVICE = "systemhealth";
field public static final java.lang.String TELECOM_SERVICE = "telecom";
@@ -9512,13 +9530,20 @@ package android.content.pm {
public class LauncherApps {
ctor public LauncherApps(android.content.Context);
method public java.util.List getActivityList(java.lang.String, android.os.UserHandle);
+ method public android.graphics.drawable.Drawable getShortcutBadgedIconDrawable(android.content.pm.ShortcutInfo, int);
+ method public android.graphics.drawable.Drawable getShortcutIconDrawable(android.content.pm.ShortcutInfo, int);
+ method public java.util.List getShortcuts(android.content.pm.LauncherApps.ShortcutQuery, android.os.UserHandle);
+ method public boolean hasShortcutHostPermission();
method public boolean isActivityEnabled(android.content.ComponentName, android.os.UserHandle);
method public boolean isPackageEnabled(java.lang.String, android.os.UserHandle);
+ method public void pinShortcuts(java.lang.String, java.util.List, android.os.UserHandle);
method public void registerCallback(android.content.pm.LauncherApps.Callback);
method public void registerCallback(android.content.pm.LauncherApps.Callback, android.os.Handler);
method public android.content.pm.LauncherActivityInfo resolveActivity(android.content.Intent, android.os.UserHandle);
method public void startAppDetailsActivity(android.content.ComponentName, android.os.UserHandle, android.graphics.Rect, android.os.Bundle);
method public void startMainActivity(android.content.ComponentName, android.os.UserHandle, android.graphics.Rect, android.os.Bundle);
+ method public void startShortcut(java.lang.String, java.lang.String, android.graphics.Rect, android.os.Bundle, android.os.UserHandle);
+ method public void startShortcut(android.content.pm.ShortcutInfo, android.graphics.Rect, android.os.Bundle);
method public void unregisterCallback(android.content.pm.LauncherApps.Callback);
}
@@ -9531,6 +9556,20 @@ package android.content.pm {
method public void onPackagesSuspended(java.lang.String[], android.os.UserHandle);
method public abstract void onPackagesUnavailable(java.lang.String[], android.os.UserHandle, boolean);
method public void onPackagesUnsuspended(java.lang.String[], android.os.UserHandle);
+ method public void onShortcutsChanged(java.lang.String, java.util.List, android.os.UserHandle);
+ }
+
+ public static class LauncherApps.ShortcutQuery {
+ ctor public LauncherApps.ShortcutQuery();
+ method public android.content.pm.LauncherApps.ShortcutQuery setActivity(android.content.ComponentName);
+ method public android.content.pm.LauncherApps.ShortcutQuery setChangedSince(long);
+ method public android.content.pm.LauncherApps.ShortcutQuery setPackage(java.lang.String);
+ method public android.content.pm.LauncherApps.ShortcutQuery setQueryFlags(int);
+ method public android.content.pm.LauncherApps.ShortcutQuery setShortcutIds(java.util.List);
+ field public static final int FLAG_GET_KEY_FIELDS_ONLY = 4; // 0x4
+ field public static final int FLAG_MATCH_DYNAMIC = 1; // 0x1
+ field public static final int FLAG_MATCH_MANIFEST = 8; // 0x8
+ field public static final int FLAG_MATCH_PINNED = 2; // 0x2
}
public class PackageInfo implements android.os.Parcelable {
@@ -10032,6 +10071,67 @@ package android.content.pm {
field public java.lang.String permission;
}
+ public final class ShortcutInfo implements android.os.Parcelable {
+ method public int describeContents();
+ method public android.content.ComponentName getActivity();
+ method public java.util.Set getCategories();
+ method public java.lang.CharSequence getDisabledMessage();
+ method public android.os.PersistableBundle getExtras();
+ method public java.lang.String getId();
+ method public android.content.Intent getIntent();
+ method public android.content.Intent[] getIntents();
+ method public long getLastChangedTimestamp();
+ method public java.lang.CharSequence getLongLabel();
+ method public java.lang.String getPackage();
+ method public int getRank();
+ method public java.lang.CharSequence getShortLabel();
+ method public android.os.UserHandle getUserHandle();
+ method public boolean hasKeyFieldsOnly();
+ method public boolean isDeclaredInManifest();
+ method public boolean isDynamic();
+ method public boolean isEnabled();
+ method public boolean isImmutable();
+ method public boolean isPinned();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator CREATOR;
+ field public static final java.lang.String SHORTCUT_CATEGORY_CONVERSATION = "android.shortcut.conversation";
+ }
+
+ public static class ShortcutInfo.Builder {
+ ctor public ShortcutInfo.Builder(android.content.Context, java.lang.String);
+ method public android.content.pm.ShortcutInfo build();
+ method public android.content.pm.ShortcutInfo.Builder setActivity(android.content.ComponentName);
+ method public android.content.pm.ShortcutInfo.Builder setCategories(java.util.Set);
+ method public android.content.pm.ShortcutInfo.Builder setDisabledMessage(java.lang.CharSequence);
+ method public android.content.pm.ShortcutInfo.Builder setExtras(android.os.PersistableBundle);
+ method public android.content.pm.ShortcutInfo.Builder setIcon(android.graphics.drawable.Icon);
+ method public android.content.pm.ShortcutInfo.Builder setIntent(android.content.Intent);
+ method public android.content.pm.ShortcutInfo.Builder setIntents(android.content.Intent[]);
+ method public android.content.pm.ShortcutInfo.Builder setLongLabel(java.lang.CharSequence);
+ method public android.content.pm.ShortcutInfo.Builder setRank(int);
+ method public android.content.pm.ShortcutInfo.Builder setShortLabel(java.lang.CharSequence);
+ }
+
+ public class ShortcutManager {
+ ctor public ShortcutManager(android.content.Context);
+ method public boolean addDynamicShortcuts(java.util.List);
+ method public void disableShortcuts(java.util.List);
+ method public void disableShortcuts(java.util.List, java.lang.CharSequence);
+ method public void enableShortcuts(java.util.List);
+ method public java.util.List getDynamicShortcuts();
+ method public int getIconMaxHeight();
+ method public int getIconMaxWidth();
+ method public java.util.List getManifestShortcuts();
+ method public int getMaxShortcutCountPerActivity();
+ method public java.util.List getPinnedShortcuts();
+ method public boolean isRateLimitingActive();
+ method public void removeAllDynamicShortcuts();
+ method public void removeDynamicShortcuts(java.util.List);
+ method public void reportShortcutUsed(java.lang.String);
+ method public boolean setDynamicShortcuts(java.util.List);
+ method public boolean updateShortcuts(java.util.List);
+ }
+
public class Signature implements android.os.Parcelable {
ctor public Signature(byte[]);
ctor public Signature(java.lang.String);
@@ -10238,7 +10338,7 @@ package android.content.res {
}
public class Resources {
- ctor public Resources(android.content.res.AssetManager, android.util.DisplayMetrics, android.content.res.Configuration);
+ ctor public deprecated Resources(android.content.res.AssetManager, android.util.DisplayMetrics, android.content.res.Configuration);
method public final void finishPreloading();
method public final void flushLayoutCache();
method public android.content.res.XmlResourceParser getAnimation(int) throws android.content.res.Resources.NotFoundException;
@@ -10289,7 +10389,7 @@ package android.content.res {
method public android.content.res.AssetFileDescriptor openRawResourceFd(int) throws android.content.res.Resources.NotFoundException;
method public void parseBundleExtra(java.lang.String, android.util.AttributeSet, android.os.Bundle) throws org.xmlpull.v1.XmlPullParserException;
method public void parseBundleExtras(android.content.res.XmlResourceParser, android.os.Bundle) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
- method public void updateConfiguration(android.content.res.Configuration, android.util.DisplayMetrics);
+ method public deprecated void updateConfiguration(android.content.res.Configuration, android.util.DisplayMetrics);
}
public static class Resources.NotFoundException extends java.lang.RuntimeException {
@@ -19625,6 +19725,7 @@ package android.media {
field public static final android.os.Parcelable.Creator CREATOR;
field public static final int ENCODING_AC3 = 5; // 0x5
field public static final int ENCODING_DEFAULT = 1; // 0x1
+ field public static final int ENCODING_DOLBY_TRUEHD = 14; // 0xe
field public static final int ENCODING_DTS = 7; // 0x7
field public static final int ENCODING_DTS_HD = 8; // 0x8
field public static final int ENCODING_E_AC3 = 6; // 0x6
@@ -28337,6 +28438,7 @@ package android.os {
field public static final int LOLLIPOP_MR1 = 22; // 0x16
field public static final int M = 23; // 0x17
field public static final int N = 24; // 0x18
+ field public static final int N_MR1 = 25; // 0x19
}
public final class Bundle extends android.os.BaseBundle implements java.lang.Cloneable android.os.Parcelable {
@@ -29126,6 +29228,7 @@ package android.os {
method public static final long getStartElapsedRealtime();
method public static final long getStartUptimeMillis();
method public static final int getThreadPriority(int) throws java.lang.IllegalArgumentException;
+ method public static final int getThreadScheduler(int) throws java.lang.IllegalArgumentException;
method public static final int getUidForName(java.lang.String);
method public static final boolean is64Bit();
method public static boolean isApplicationUid(int);
@@ -29329,6 +29432,7 @@ package android.os {
method public android.os.Bundle getUserRestrictions();
method public android.os.Bundle getUserRestrictions(android.os.UserHandle);
method public boolean hasUserRestriction(java.lang.String);
+ method public boolean isDemoUser();
method public boolean isQuietModeEnabled(android.os.UserHandle);
method public boolean isSystemUser();
method public boolean isUserAGoat();
@@ -29568,6 +29672,7 @@ package android.os.storage {
method public boolean isObbMounted(java.lang.String);
method public boolean mountObb(java.lang.String, java.lang.String, android.os.storage.OnObbStateChangeListener);
method public boolean unmountObb(java.lang.String, boolean, android.os.storage.OnObbStateChangeListener);
+ field public static final java.lang.String ACTION_MANAGE_STORAGE = "android.os.storage.action.MANAGE_STORAGE";
}
public final class StorageVolume implements android.os.Parcelable {
@@ -30713,6 +30818,7 @@ package android.provider {
public static class CallLog.Calls implements android.provider.BaseColumns {
ctor public CallLog.Calls();
method public static java.lang.String getLastOutgoingCall(android.content.Context);
+ field public static final int ANSWERED_EXTERNALLY_TYPE = 7; // 0x7
field public static final int BLOCKED_TYPE = 6; // 0x6
field public static final java.lang.String CACHED_FORMATTED_NUMBER = "formatted_number";
field public static final java.lang.String CACHED_LOOKUP_URI = "lookup_uri";
@@ -30735,6 +30841,7 @@ package android.provider {
field public static final java.lang.String DURATION = "duration";
field public static final java.lang.String EXTRA_CALL_TYPE_FILTER = "android.provider.extra.CALL_TYPE_FILTER";
field public static final java.lang.String FEATURES = "features";
+ field public static final int FEATURES_PULLED_EXTERNALLY = 2; // 0x2
field public static final int FEATURES_VIDEO = 1; // 0x1
field public static final java.lang.String GEOCODED_LOCATION = "geocoded_location";
field public static final int INCOMING_TYPE = 1; // 0x1
@@ -32440,6 +32547,7 @@ package android.provider {
field public static final java.lang.String DATA_ROAMING = "data_roaming";
field public static final java.lang.String DEBUG_APP = "debug_app";
field public static final java.lang.String DEVELOPMENT_SETTINGS_ENABLED = "development_settings_enabled";
+ field public static final java.lang.String DEVICE_NAME = "device_name";
field public static final java.lang.String DEVICE_PROVISIONED = "device_provisioned";
field public static final java.lang.String HTTP_PROXY = "http_proxy";
field public static final deprecated java.lang.String INSTALL_NON_MARKET_APPS = "install_non_market_apps";
@@ -33028,6 +33136,7 @@ package android.provider {
field public static final java.lang.String ACTION_NEW_VOICEMAIL = "android.intent.action.NEW_VOICEMAIL";
field public static final java.lang.String ACTION_SYNC_VOICEMAIL = "android.provider.action.SYNC_VOICEMAIL";
field public static final java.lang.String AUTHORITY = "com.android.voicemail";
+ field public static final java.lang.String EXTRA_PHONE_ACCOUNT_HANDLE = "android.provider.extra.PHONE_ACCOUNT_HANDLE";
field public static final java.lang.String EXTRA_SELF_CHANGE = "com.android.voicemail.extra.SELF_CHANGE";
field public static final java.lang.String PARAM_KEY_SOURCE_PACKAGE = "source_package";
}
@@ -33036,6 +33145,9 @@ package android.provider {
method public static android.net.Uri buildSourceUri(java.lang.String);
field public static final java.lang.String CONFIGURATION_STATE = "configuration_state";
field public static final int CONFIGURATION_STATE_CAN_BE_CONFIGURED = 2; // 0x2
+ field public static final int CONFIGURATION_STATE_CONFIGURING = 3; // 0x3
+ field public static final int CONFIGURATION_STATE_DISABLED = 5; // 0x5
+ field public static final int CONFIGURATION_STATE_FAILED = 4; // 0x4
field public static final int CONFIGURATION_STATE_NOT_CONFIGURED = 1; // 0x1
field public static final int CONFIGURATION_STATE_OK = 0; // 0x0
field public static final android.net.Uri CONTENT_URI;
@@ -33060,6 +33172,7 @@ package android.provider {
field public static final int QUOTA_UNAVAILABLE = -1; // 0xffffffff
field public static final java.lang.String SETTINGS_URI = "settings_uri";
field public static final java.lang.String SOURCE_PACKAGE = "source_package";
+ field public static final java.lang.String SOURCE_TYPE = "source_type";
field public static final java.lang.String VOICEMAIL_ACCESS_URI = "voicemail_access_uri";
}
@@ -36013,9 +36126,14 @@ package android.telecom {
method public void phoneAccountSelected(android.telecom.PhoneAccountHandle, boolean);
method public void playDtmfTone(char);
method public void postDialContinue(boolean);
+ method public void pullExternalCall();
+ method public final void putExtras(android.os.Bundle);
method public void registerCallback(android.telecom.Call.Callback);
method public void registerCallback(android.telecom.Call.Callback, android.os.Handler);
method public void reject(boolean, java.lang.String);
+ method public final void removeExtras(java.util.List);
+ method public final void removeExtras(java.lang.String...);
+ method public void sendCallEvent(java.lang.String, android.os.Bundle);
method public void splitFromConference();
method public void stopDtmfTone();
method public void swapConference();
@@ -36029,6 +36147,7 @@ package android.telecom {
field public static final int STATE_DISCONNECTING = 10; // 0xa
field public static final int STATE_HOLDING = 3; // 0x3
field public static final int STATE_NEW = 0; // 0x0
+ field public static final int STATE_PULLING_CALL = 11; // 0xb
field public static final int STATE_RINGING = 2; // 0x2
field public static final int STATE_SELECT_PHONE_ACCOUNT = 8; // 0x8
}
@@ -36039,6 +36158,7 @@ package android.telecom {
method public void onCannedTextResponsesLoaded(android.telecom.Call, java.util.List);
method public void onChildrenChanged(android.telecom.Call, java.util.List);
method public void onConferenceableCallsChanged(android.telecom.Call, java.util.List);
+ method public void onConnectionEvent(android.telecom.Call, java.lang.String, android.os.Bundle);
method public void onDetailsChanged(android.telecom.Call, android.telecom.Call.Details);
method public void onParentChanged(android.telecom.Call, android.telecom.Call);
method public void onPostDialWait(android.telecom.Call, java.lang.String);
@@ -36069,6 +36189,7 @@ package android.telecom {
method public static java.lang.String propertiesToString(int);
field public static final int CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO = 4194304; // 0x400000
field public static final int CAPABILITY_CAN_PAUSE_VIDEO = 1048576; // 0x100000
+ field public static final int CAPABILITY_CAN_PULL_CALL = 8388608; // 0x800000
field public static final int CAPABILITY_DISCONNECT_FROM_CONFERENCE = 8192; // 0x2000
field public static final int CAPABILITY_HOLD = 1; // 0x1
field public static final int CAPABILITY_MANAGE_CONFERENCE = 128; // 0x80
@@ -36088,7 +36209,9 @@ package android.telecom {
field public static final int PROPERTY_EMERGENCY_CALLBACK_MODE = 4; // 0x4
field public static final int PROPERTY_ENTERPRISE_CALL = 32; // 0x20
field public static final int PROPERTY_GENERIC_CONFERENCE = 2; // 0x2
+ field public static final int PROPERTY_HAS_CDMA_VOICE_PRIVACY = 128; // 0x80
field public static final int PROPERTY_HIGH_DEF_AUDIO = 16; // 0x10
+ field public static final int PROPERTY_IS_EXTERNAL_CALL = 64; // 0x40
field public static final int PROPERTY_WIFI = 8; // 0x8
}
@@ -36139,6 +36262,7 @@ package android.telecom {
method public final android.telecom.CallAudioState getCallAudioState();
method public final java.util.List getConferenceableConnections();
method public final int getConnectionCapabilities();
+ method public final int getConnectionProperties();
method public final long getConnectionTime();
method public final java.util.List getConnections();
method public final android.telecom.DisconnectCause getDisconnectCause();
@@ -36151,6 +36275,7 @@ package android.telecom {
method public void onCallAudioStateChanged(android.telecom.CallAudioState);
method public void onConnectionAdded(android.telecom.Connection);
method public void onDisconnect();
+ method public void onExtrasChanged(android.os.Bundle);
method public void onHold();
method public void onMerge(android.telecom.Connection);
method public void onMerge();
@@ -36159,10 +36284,14 @@ package android.telecom {
method public void onStopDtmfTone();
method public void onSwap();
method public void onUnhold();
+ method public final void putExtras(android.os.Bundle);
method public final void removeConnection(android.telecom.Connection);
+ method public final void removeExtras(java.util.List);
+ method public final void removeExtras(java.lang.String...);
method public final void setActive();
method public final void setConferenceableConnections(java.util.List);
method public final void setConnectionCapabilities(int);
+ method public final void setConnectionProperties(int);
method public final void setConnectionTime(long);
method public final void setDialing();
method public final void setDisconnected(android.telecom.DisconnectCause);
@@ -36192,6 +36321,7 @@ package android.telecom {
method public final android.telecom.Conference getConference();
method public final java.util.List getConferenceables();
method public final int getConnectionCapabilities();
+ method public final int getConnectionProperties();
method public final android.telecom.DisconnectCause getDisconnectCause();
method public final android.os.Bundle getExtras();
method public final int getState();
@@ -36202,16 +36332,24 @@ package android.telecom {
method public void onAnswer(int);
method public void onAnswer();
method public void onCallAudioStateChanged(android.telecom.CallAudioState);
+ method public void onCallEvent(java.lang.String, android.os.Bundle);
method public void onDisconnect();
+ method public void onExtrasChanged(android.os.Bundle);
method public void onHold();
method public void onPlayDtmfTone(char);
method public void onPostDialContinue(boolean);
+ method public void onPullExternalCall();
method public void onReject();
method public void onReject(java.lang.String);
method public void onSeparate();
method public void onStateChanged(int);
method public void onStopDtmfTone();
method public void onUnhold();
+ method public static java.lang.String propertiesToString(int);
+ method public final void putExtras(android.os.Bundle);
+ method public final void removeExtras(java.util.List);
+ method public final void removeExtras(java.lang.String...);
+ method public void sendConnectionEvent(java.lang.String, android.os.Bundle);
method public final void setActive();
method public final void setAddress(android.net.Uri, int);
method public final void setAudioModeIsVoip(boolean);
@@ -36219,6 +36357,7 @@ package android.telecom {
method public final void setConferenceableConnections(java.util.List);
method public final void setConferenceables(java.util.List);
method public final void setConnectionCapabilities(int);
+ method public final void setConnectionProperties(int);
method public final void setDialing();
method public final void setDisconnected(android.telecom.DisconnectCause);
method public final void setExtras(android.os.Bundle);
@@ -36227,6 +36366,7 @@ package android.telecom {
method public final void setNextPostDialChar(char);
method public final void setOnHold();
method public final void setPostDialWait(java.lang.String);
+ method public final void setPulling();
method public final void setRingbackRequested(boolean);
method public final void setRinging();
method public final void setStatusHints(android.telecom.StatusHints);
@@ -36235,6 +36375,7 @@ package android.telecom {
method public static java.lang.String stateToString(int);
field public static final int CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO = 8388608; // 0x800000
field public static final int CAPABILITY_CAN_PAUSE_VIDEO = 1048576; // 0x100000
+ field public static final int CAPABILITY_CAN_PULL_CALL = 16777216; // 0x1000000
field public static final int CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION = 4194304; // 0x400000
field public static final int CAPABILITY_CAN_UPGRADE_TO_VIDEO = 524288; // 0x80000
field public static final int CAPABILITY_DISCONNECT_FROM_CONFERENCE = 8192; // 0x2000
@@ -36252,15 +36393,21 @@ package android.telecom {
field public static final int CAPABILITY_SUPPORTS_VT_REMOTE_TX = 2048; // 0x800
field public static final int CAPABILITY_SUPPORT_HOLD = 2; // 0x2
field public static final int CAPABILITY_SWAP_CONFERENCE = 8; // 0x8
+ field public static final java.lang.String EVENT_CALL_MERGE_FAILED = "android.telecom.event.CALL_MERGE_FAILED";
+ field public static final java.lang.String EVENT_CALL_PULL_FAILED = "android.telecom.event.CALL_PULL_FAILED";
+ field public static final java.lang.String EXTRA_ANSWERING_DROPS_FG_CALL = "android.telecom.extra.ANSWERING_DROPS_FG_CALL";
field public static final java.lang.String EXTRA_CALL_SUBJECT = "android.telecom.extra.CALL_SUBJECT";
field public static final java.lang.String EXTRA_CHILD_ADDRESS = "android.telecom.extra.CHILD_ADDRESS";
field public static final java.lang.String EXTRA_LAST_FORWARDED_NUMBER = "android.telecom.extra.LAST_FORWARDED_NUMBER";
+ field public static final int PROPERTY_HAS_CDMA_VOICE_PRIVACY = 32; // 0x20
+ field public static final int PROPERTY_IS_EXTERNAL_CALL = 16; // 0x10
field public static final int STATE_ACTIVE = 4; // 0x4
field public static final int STATE_DIALING = 3; // 0x3
field public static final int STATE_DISCONNECTED = 6; // 0x6
field public static final int STATE_HOLDING = 5; // 0x5
field public static final int STATE_INITIALIZING = 0; // 0x0
field public static final int STATE_NEW = 1; // 0x1
+ field public static final int STATE_PULLING_CALL = 7; // 0x7
field public static final int STATE_RINGING = 2; // 0x2
}
@@ -36338,7 +36485,9 @@ package android.telecom {
method public java.lang.String getReason();
method public int getTone();
method public void writeToParcel(android.os.Parcel, int);
+ field public static final int ANSWERED_ELSEWHERE = 11; // 0xb
field public static final int BUSY = 7; // 0x7
+ field public static final int CALL_PULLED = 12; // 0xc
field public static final int CANCELED = 4; // 0x4
field public static final int CONNECTION_MANAGER_NOT_SUPPORTED = 10; // 0xa
field public static final android.os.Parcelable.Creator CREATOR;
@@ -36374,6 +36523,7 @@ package android.telecom {
method public void onCallAudioStateChanged(android.telecom.CallAudioState);
method public void onCallRemoved(android.telecom.Call);
method public void onCanAddCallChanged(boolean);
+ method public void onConnectionEvent(android.telecom.Call, java.lang.String, android.os.Bundle);
method public void onSilenceRinger();
method public final void setAudioRoute(int);
method public final void setMuted(boolean);
@@ -36496,6 +36646,7 @@ package android.telecom {
method public void onConferenceableConnectionsChanged(android.telecom.RemoteConference, java.util.List);
method public void onConnectionAdded(android.telecom.RemoteConference, android.telecom.RemoteConnection);
method public void onConnectionCapabilitiesChanged(android.telecom.RemoteConference, int);
+ method public void onConnectionPropertiesChanged(android.telecom.RemoteConference, int);
method public void onConnectionRemoved(android.telecom.RemoteConference, android.telecom.RemoteConnection);
method public void onDestroyed(android.telecom.RemoteConference);
method public void onDisconnected(android.telecom.RemoteConference, android.telecom.DisconnectCause);
@@ -36514,6 +36665,7 @@ package android.telecom {
method public android.telecom.RemoteConference getConference();
method public java.util.List getConferenceableConnections();
method public int getConnectionCapabilities();
+ method public int getConnectionProperties();
method public android.telecom.DisconnectCause getDisconnectCause();
method public final android.os.Bundle getExtras();
method public int getState();
@@ -36525,6 +36677,7 @@ package android.telecom {
method public boolean isVoipAudioMode();
method public void playDtmfTone(char);
method public void postDialContinue(boolean);
+ method public void pullExternalCall();
method public void registerCallback(android.telecom.RemoteConnection.Callback);
method public void registerCallback(android.telecom.RemoteConnection.Callback, android.os.Handler);
method public void reject();
@@ -36541,6 +36694,8 @@ package android.telecom {
method public void onConferenceChanged(android.telecom.RemoteConnection, android.telecom.RemoteConference);
method public void onConferenceableConnectionsChanged(android.telecom.RemoteConnection, java.util.List);
method public void onConnectionCapabilitiesChanged(android.telecom.RemoteConnection, int);
+ method public void onConnectionEvent(android.telecom.RemoteConnection, java.lang.String, android.os.Bundle);
+ method public void onConnectionPropertiesChanged(android.telecom.RemoteConnection, int);
method public void onDestroyed(android.telecom.RemoteConnection);
method public void onDisconnected(android.telecom.RemoteConnection, android.telecom.DisconnectCause);
method public void onExtrasChanged(android.telecom.RemoteConnection, android.os.Bundle);
@@ -36637,6 +36792,7 @@ package android.telecom {
field public static final java.lang.String EXTRA_START_CALL_WITH_VIDEO_STATE = "android.telecom.extra.START_CALL_WITH_VIDEO_STATE";
field public static final java.lang.String GATEWAY_ORIGINAL_ADDRESS = "android.telecom.extra.GATEWAY_ORIGINAL_ADDRESS";
field public static final java.lang.String GATEWAY_PROVIDER_PACKAGE = "android.telecom.extra.GATEWAY_PROVIDER_PACKAGE";
+ field public static final java.lang.String METADATA_INCLUDE_EXTERNAL_CALLS = "android.telecom.INCLUDE_EXTERNAL_CALLS";
field public static final java.lang.String METADATA_IN_CALL_SERVICE_RINGING = "android.telecom.IN_CALL_SERVICE_RINGING";
field public static final java.lang.String METADATA_IN_CALL_SERVICE_UI = "android.telecom.IN_CALL_SERVICE_UI";
field public static final int PRESENTATION_ALLOWED = 1; // 0x1
@@ -36691,9 +36847,11 @@ package android.telephony {
field public static final java.lang.String ACTION_CARRIER_CONFIG_CHANGED = "android.telephony.action.CARRIER_CONFIG_CHANGED";
field public static final java.lang.String KEY_ADDITIONAL_CALL_SETTING_BOOL = "additional_call_setting_bool";
field public static final java.lang.String KEY_ALLOW_ADDING_APNS_BOOL = "allow_adding_apns_bool";
+ field public static final java.lang.String KEY_ALLOW_ADD_CALL_DURING_VIDEO_CALL_BOOL = "allow_add_call_during_video_call";
field public static final java.lang.String KEY_ALLOW_EMERGENCY_NUMBERS_IN_CALL_LOG_BOOL = "allow_emergency_numbers_in_call_log_bool";
field public static final java.lang.String KEY_ALLOW_EMERGENCY_VIDEO_CALLS_BOOL = "allow_emergency_video_calls_bool";
field public static final java.lang.String KEY_ALLOW_LOCAL_DTMF_TONES_BOOL = "allow_local_dtmf_tones_bool";
+ field public static final java.lang.String KEY_ALLOW_MERGE_WIFI_CALLS_WHEN_VOWIFI_OFF_BOOL = "allow_merge_wifi_calls_when_vowifi_off_bool";
field public static final java.lang.String KEY_ALLOW_NON_EMERGENCY_CALLS_IN_ECM_BOOL = "allow_non_emergency_calls_in_ecm_bool";
field public static final java.lang.String KEY_ALWAYS_SHOW_EMERGENCY_ALERT_ONOFF_BOOL = "always_show_emergency_alert_onoff_bool";
field public static final java.lang.String KEY_APN_EXPAND_BOOL = "apn_expand_bool";
@@ -36725,6 +36883,7 @@ package android.telephony {
field public static final java.lang.String KEY_CSP_ENABLED_BOOL = "csp_enabled_bool";
field public static final java.lang.String KEY_DEFAULT_SIM_CALL_MANAGER_STRING = "default_sim_call_manager_string";
field public static final java.lang.String KEY_DISABLE_CDMA_ACTIVATION_CODE_BOOL = "disable_cdma_activation_code_bool";
+ field public static final java.lang.String KEY_DROP_VIDEO_CALL_WHEN_ANSWERING_AUDIO_CALL_BOOL = "drop_video_call_when_answering_audio_call_bool";
field public static final java.lang.String KEY_DTMF_TYPE_ENABLED_BOOL = "dtmf_type_enabled_bool";
field public static final java.lang.String KEY_DURATION_BLOCKING_DISABLED_AFTER_EMERGENCY_INT = "duration_blocking_disabled_after_emergency_int";
field public static final java.lang.String KEY_EDITABLE_ENHANCED_4G_LTE_BOOL = "editable_enhanced_4g_lte_bool";
@@ -36782,6 +36941,7 @@ package android.telephony {
field public static final java.lang.String KEY_SUPPORT_CONFERENCE_CALL_BOOL = "support_conference_call_bool";
field public static final java.lang.String KEY_SUPPORT_PAUSE_IMS_VIDEO_CALLS_BOOL = "support_pause_ims_video_calls_bool";
field public static final java.lang.String KEY_SUPPORT_SWAP_AFTER_MERGE_BOOL = "support_swap_after_merge_bool";
+ field public static final java.lang.String KEY_TREAT_DOWNGRADED_VIDEO_CALLS_AS_VIDEO_CALLS_BOOL = "treat_downgraded_video_calls_as_video_calls_bool";
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_USE_RCS_PRESENCE_BOOL = "use_rcs_presence_bool";
@@ -37366,12 +37526,15 @@ package android.telephony {
field public static final int NETWORK_TYPE_EVDO_A = 6; // 0x6
field public static final int NETWORK_TYPE_EVDO_B = 12; // 0xc
field public static final int NETWORK_TYPE_GPRS = 1; // 0x1
+ field public static final int NETWORK_TYPE_GSM = 16; // 0x10
field public static final int NETWORK_TYPE_HSDPA = 8; // 0x8
field public static final int NETWORK_TYPE_HSPA = 10; // 0xa
field public static final int NETWORK_TYPE_HSPAP = 15; // 0xf
field public static final int NETWORK_TYPE_HSUPA = 9; // 0x9
field public static final int NETWORK_TYPE_IDEN = 11; // 0xb
+ field public static final int NETWORK_TYPE_IWLAN = 18; // 0x12
field public static final int NETWORK_TYPE_LTE = 13; // 0xd
+ field public static final int NETWORK_TYPE_TD_SCDMA = 17; // 0x11
field public static final int NETWORK_TYPE_UMTS = 3; // 0x3
field public static final int NETWORK_TYPE_UNKNOWN = 0; // 0x0
field public static final int PHONE_TYPE_CDMA = 2; // 0x2
@@ -40174,7 +40337,10 @@ package android.util {
method public boolean equals(android.util.DisplayMetrics);
method public void setTo(android.util.DisplayMetrics);
method public void setToDefaults();
+ field public static final int DENSITY_260 = 260; // 0x104
field public static final int DENSITY_280 = 280; // 0x118
+ field public static final int DENSITY_300 = 300; // 0x12c
+ field public static final int DENSITY_340 = 340; // 0x154
field public static final int DENSITY_360 = 360; // 0x168
field public static final int DENSITY_400 = 400; // 0x190
field public static final int DENSITY_420 = 420; // 0x1a4
@@ -41504,6 +41670,10 @@ package android.view {
field public static final int KEYCODE_SWITCH_CHARSET = 95; // 0x5f
field public static final int KEYCODE_SYM = 63; // 0x3f
field public static final int KEYCODE_SYSRQ = 120; // 0x78
+ field public static final int KEYCODE_SYSTEM_NAVIGATION_DOWN = 281; // 0x119
+ field public static final int KEYCODE_SYSTEM_NAVIGATION_LEFT = 282; // 0x11a
+ field public static final int KEYCODE_SYSTEM_NAVIGATION_RIGHT = 283; // 0x11b
+ field public static final int KEYCODE_SYSTEM_NAVIGATION_UP = 280; // 0x118
field public static final int KEYCODE_T = 48; // 0x30
field public static final int KEYCODE_TAB = 61; // 0x3d
field public static final int KEYCODE_TV = 170; // 0xaa
@@ -42386,6 +42556,7 @@ package android.view {
method public float getPivotY();
method public android.view.PointerIcon getPointerIcon();
method public android.content.res.Resources getResources();
+ method public final boolean getRevealOnFocusHint();
method public final int getRight();
method protected float getRightFadingEdgeStrength();
method protected int getRightPaddingOffset();
@@ -42673,6 +42844,7 @@ package android.view {
method public void setPivotY(float);
method public void setPointerIcon(android.view.PointerIcon);
method public void setPressed(boolean);
+ method public final void setRevealOnFocusHint(boolean);
method public final void setRight(int);
method public void setRotation(float);
method public void setRotationX(float);
@@ -43822,6 +43994,7 @@ package android.view {
field public static final int TYPE_APPLICATION_SUB_PANEL = 1002; // 0x3ea
field public static final int TYPE_BASE_APPLICATION = 1; // 0x1
field public static final int TYPE_CHANGED = 2; // 0x2
+ field public static final int TYPE_DRAWN_APPLICATION = 4; // 0x4
field public static final int TYPE_INPUT_METHOD = 2011; // 0x7db
field public static final int TYPE_INPUT_METHOD_DIALOG = 2012; // 0x7dc
field public static final int TYPE_KEYGUARD_DIALOG = 2009; // 0x7d9
@@ -44594,6 +44767,7 @@ package android.view.inputmethod {
method public boolean clearMetaKeyStates(int);
method public void closeConnection();
method public boolean commitCompletion(android.view.inputmethod.CompletionInfo);
+ method public boolean commitContent(android.view.inputmethod.InputContentInfo, int, android.os.Bundle);
method public boolean commitCorrection(android.view.inputmethod.CorrectionInfo);
method public boolean commitText(java.lang.CharSequence, int);
method public boolean deleteSurroundingText(int, int);
@@ -44703,6 +44877,7 @@ package android.view.inputmethod {
field public static final int IME_NULL = 0; // 0x0
field public int actionId;
field public java.lang.CharSequence actionLabel;
+ field public java.lang.String[] contentMimeTypes;
field public android.os.Bundle extras;
field public int fieldId;
field public java.lang.String fieldName;
@@ -44762,6 +44937,7 @@ package android.view.inputmethod {
method public abstract boolean clearMetaKeyStates(int);
method public abstract void closeConnection();
method public abstract boolean commitCompletion(android.view.inputmethod.CompletionInfo);
+ method public abstract boolean commitContent(android.view.inputmethod.InputContentInfo, int, android.os.Bundle);
method public abstract boolean commitCorrection(android.view.inputmethod.CorrectionInfo);
method public abstract boolean commitText(java.lang.CharSequence, int);
method public abstract boolean deleteSurroundingText(int, int);
@@ -44787,6 +44963,7 @@ package android.view.inputmethod {
field public static final int CURSOR_UPDATE_MONITOR = 2; // 0x2
field public static final int GET_EXTRACTED_TEXT_MONITOR = 1; // 0x1
field public static final int GET_TEXT_WITH_STYLES = 1; // 0x1
+ field public static final int INPUT_CONTENT_GRANT_READ_URI_PERMISSION = 1; // 0x1
}
public class InputConnectionWrapper implements android.view.inputmethod.InputConnection {
@@ -44795,6 +44972,7 @@ package android.view.inputmethod {
method public boolean clearMetaKeyStates(int);
method public void closeConnection();
method public boolean commitCompletion(android.view.inputmethod.CompletionInfo);
+ method public boolean commitContent(android.view.inputmethod.InputContentInfo, int, android.os.Bundle);
method public boolean commitCorrection(android.view.inputmethod.CorrectionInfo);
method public boolean commitText(java.lang.CharSequence, int);
method public boolean deleteSurroundingText(int, int);
@@ -44819,6 +44997,19 @@ package android.view.inputmethod {
method public void setTarget(android.view.inputmethod.InputConnection);
}
+ public final class InputContentInfo implements android.os.Parcelable {
+ ctor public InputContentInfo(android.net.Uri, android.content.ClipDescription);
+ ctor public InputContentInfo(android.net.Uri, android.content.ClipDescription, android.net.Uri);
+ method public int describeContents();
+ method public android.net.Uri getContentUri();
+ method public android.content.ClipDescription getDescription();
+ method public android.net.Uri getLinkUri();
+ method public void releasePermission();
+ method public void requestPermission();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator CREATOR;
+ }
+
public abstract interface InputMethod {
method public abstract void attachToken(android.os.IBinder);
method public abstract void bindInput(android.view.inputmethod.InputBinding);
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index 8ccd5d2ebcbadf28589b4f57f10bac98a4703f7e..d6c00589e7c2ab414b58d587d909cd36f001236d 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -723,10 +723,10 @@ public class Am extends BaseCommand {
System.out.println("Complete");
}
mRepeat--;
- if (mRepeat > 1) {
+ if (mRepeat > 0) {
mAm.unhandledBack();
}
- } while (mRepeat > 1);
+ } while (mRepeat > 0);
}
private void runForceStop() throws Exception {
diff --git a/cmds/bootanimation/Android.mk b/cmds/bootanimation/Android.mk
index 7f03eaf65e335b44e30639421ee6193e566a87dd..e9d1b6083b0184b9dc6e4740f95b3cae0dce5459 100644
--- a/cmds/bootanimation/Android.mk
+++ b/cmds/bootanimation/Android.mk
@@ -3,14 +3,16 @@ include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
bootanimation_main.cpp \
- AudioPlayer.cpp \
+ audioplay.cpp \
BootAnimation.cpp
LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code
-LOCAL_C_INCLUDES += external/tinyalsa/include
+LOCAL_C_INCLUDES += \
+ external/tinyalsa/include \
+ frameworks/wilhelm/include
LOCAL_SHARED_LIBRARIES := \
libcutils \
@@ -23,6 +25,7 @@ LOCAL_SHARED_LIBRARIES := \
libEGL \
libGLESv1_CM \
libgui \
+ libOpenSLES \
libtinyalsa \
libregionalization
diff --git a/cmds/bootanimation/AudioPlayer.cpp b/cmds/bootanimation/AudioPlayer.cpp
deleted file mode 100644
index 293213008d582ca6d5048a1a585da9fb4f570d62..0000000000000000000000000000000000000000
--- a/cmds/bootanimation/AudioPlayer.cpp
+++ /dev/null
@@ -1,313 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_NDEBUG 0
-#define LOG_TAG "BootAnim_AudioPlayer"
-
-#include "AudioPlayer.h"
-
-#include
-#include
-#include
-#include
-
-#define ID_RIFF 0x46464952
-#define ID_WAVE 0x45564157
-#define ID_FMT 0x20746d66
-#define ID_DATA 0x61746164
-
-// Maximum line length for audio_conf.txt
-// We only accept lines less than this length to avoid overflows using sscanf()
-#define MAX_LINE_LENGTH 1024
-
-struct riff_wave_header {
- uint32_t riff_id;
- uint32_t riff_sz;
- uint32_t wave_id;
-};
-
-struct chunk_header {
- uint32_t id;
- uint32_t sz;
-};
-
-struct chunk_fmt {
- uint16_t audio_format;
- uint16_t num_channels;
- uint32_t sample_rate;
- uint32_t byte_rate;
- uint16_t block_align;
- uint16_t bits_per_sample;
-};
-
-
-namespace android {
-
-AudioPlayer::AudioPlayer()
- : mCard(-1),
- mDevice(-1),
- mPeriodSize(0),
- mPeriodCount(0),
- mCurrentFile(NULL)
-{
-}
-
-AudioPlayer::~AudioPlayer() {
-}
-
-static bool setMixerValue(struct mixer* mixer, const char* name, const char* values)
-{
- if (!mixer) {
- ALOGE("no mixer in setMixerValue");
- return false;
- }
- struct mixer_ctl *ctl = mixer_get_ctl_by_name(mixer, name);
- if (!ctl) {
- ALOGE("mixer_get_ctl_by_name failed for %s", name);
- return false;
- }
-
- enum mixer_ctl_type type = mixer_ctl_get_type(ctl);
- int numValues = mixer_ctl_get_num_values(ctl);
- int intValue;
- char stringValue[MAX_LINE_LENGTH];
-
- for (int i = 0; i < numValues && values; i++) {
- // strip leading space
- while (*values == ' ') values++;
- if (*values == 0) break;
-
- switch (type) {
- case MIXER_CTL_TYPE_BOOL:
- case MIXER_CTL_TYPE_INT:
- if (sscanf(values, "%d", &intValue) == 1) {
- if (mixer_ctl_set_value(ctl, i, intValue) != 0) {
- ALOGE("mixer_ctl_set_value failed for %s %d", name, intValue);
- }
- } else {
- ALOGE("Could not parse %s as int for %s", values, name);
- }
- break;
- case MIXER_CTL_TYPE_ENUM:
- if (sscanf(values, "%s", stringValue) == 1) {
- if (mixer_ctl_set_enum_by_string(ctl, stringValue) != 0) {
- ALOGE("mixer_ctl_set_enum_by_string failed for %s %s", name, stringValue);
- }
- } else {
- ALOGE("Could not parse %s as enum for %s", values, name);
- }
- break;
- default:
- ALOGE("unsupported mixer type %d for %s", type, name);
- break;
- }
-
- values = strchr(values, ' ');
- }
-
- return true;
-}
-
-
-/*
- * Parse the audio configuration file.
- * The file is named audio_conf.txt and must begin with the following header:
- *
- * card=
- * device=
- * period_size=
- * period_count=
- *
- * This header is followed by zero or more mixer settings, each with the format:
- * mixer "" =
- * Since mixer names can contain spaces, the name must be enclosed in double quotes.
- * The values in the value list can be integers, booleans (represented by 0 or 1)
- * or strings for enum values.
- */
-bool AudioPlayer::init(const char* config)
-{
- int tempInt;
- struct mixer* mixer = NULL;
- char name[MAX_LINE_LENGTH];
-
- for (;;) {
- const char* endl = strstr(config, "\n");
- if (!endl) break;
- String8 line(config, endl - config);
- if (line.length() >= MAX_LINE_LENGTH) {
- ALOGE("Line too long in audio_conf.txt");
- return false;
- }
- const char* l = line.string();
-
- if (sscanf(l, "card=%d", &tempInt) == 1) {
- ALOGD("card=%d", tempInt);
- mCard = tempInt;
-
- mixer = mixer_open(mCard);
- if (!mixer) {
- ALOGE("could not open mixer for card %d", mCard);
- return false;
- }
- } else if (sscanf(l, "device=%d", &tempInt) == 1) {
- ALOGD("device=%d", tempInt);
- mDevice = tempInt;
- } else if (sscanf(l, "period_size=%d", &tempInt) == 1) {
- ALOGD("period_size=%d", tempInt);
- mPeriodSize = tempInt;
- } else if (sscanf(l, "period_count=%d", &tempInt) == 1) {
- ALOGD("period_count=%d", tempInt);
- mPeriodCount = tempInt;
- } else if (sscanf(l, "mixer \"%[0-9a-zA-Z _]s\"", name) == 1) {
- const char* values = strchr(l, '=');
- if (values) {
- values++; // skip '='
- ALOGD("name: \"%s\" = %s", name, values);
- setMixerValue(mixer, name, values);
- } else {
- ALOGE("values missing for name: \"%s\"", name);
- }
- }
- config = ++endl;
- }
-
- mixer_close(mixer);
-
- if (mCard >= 0 && mDevice >= 0) {
- return true;
- }
-
- return false;
-}
-
-void AudioPlayer::playFile(FileMap* fileMap) {
- // stop any currently playing sound
- requestExitAndWait();
-
- mCurrentFile = fileMap;
- run("bootanim audio", PRIORITY_URGENT_AUDIO);
-}
-
-bool AudioPlayer::threadLoop()
-{
- struct pcm_config config;
- struct pcm *pcm = NULL;
- bool moreChunks = true;
- const struct chunk_fmt* chunkFmt = NULL;
- int bufferSize;
- const uint8_t* wavData;
- size_t wavLength;
- const struct riff_wave_header* wavHeader;
-
- if (mCurrentFile == NULL) {
- ALOGE("mCurrentFile is NULL");
- return false;
- }
-
- wavData = (const uint8_t *)mCurrentFile->getDataPtr();
- if (!wavData) {
- ALOGE("Could not access WAV file data");
- goto exit;
- }
- wavLength = mCurrentFile->getDataLength();
-
- wavHeader = (const struct riff_wave_header *)wavData;
- if (wavLength < sizeof(*wavHeader) || (wavHeader->riff_id != ID_RIFF) ||
- (wavHeader->wave_id != ID_WAVE)) {
- ALOGE("Error: audio file is not a riff/wave file\n");
- goto exit;
- }
- wavData += sizeof(*wavHeader);
- wavLength -= sizeof(*wavHeader);
-
- do {
- const struct chunk_header* chunkHeader = (const struct chunk_header*)wavData;
- if (wavLength < sizeof(*chunkHeader)) {
- ALOGE("EOF reading chunk headers");
- goto exit;
- }
-
- wavData += sizeof(*chunkHeader);
- wavLength -= sizeof(*chunkHeader);
-
- switch (chunkHeader->id) {
- case ID_FMT:
- chunkFmt = (const struct chunk_fmt *)wavData;
- wavData += chunkHeader->sz;
- wavLength -= chunkHeader->sz;
- break;
- case ID_DATA:
- /* Stop looking for chunks */
- moreChunks = 0;
- break;
- default:
- /* Unknown chunk, skip bytes */
- wavData += chunkHeader->sz;
- wavLength -= chunkHeader->sz;
- }
- } while (moreChunks);
-
- if (!chunkFmt) {
- ALOGE("format not found in WAV file");
- goto exit;
- }
-
-
- memset(&config, 0, sizeof(config));
- config.channels = chunkFmt->num_channels;
- config.rate = chunkFmt->sample_rate;
- config.period_size = mPeriodSize;
- config.period_count = mPeriodCount;
- config.start_threshold = mPeriodSize / 4;
- config.stop_threshold = INT_MAX;
- config.avail_min = config.start_threshold;
- if (chunkFmt->bits_per_sample != 16) {
- ALOGE("only 16 bit WAV files are supported");
- goto exit;
- }
- config.format = PCM_FORMAT_S16_LE;
-
- pcm = pcm_open(mCard, mDevice, PCM_OUT, &config);
- if (!pcm || !pcm_is_ready(pcm)) {
- ALOGE("Unable to open PCM device (%s)\n", pcm_get_error(pcm));
- goto exit;
- }
-
- bufferSize = pcm_frames_to_bytes(pcm, pcm_get_buffer_size(pcm));
-
- while (wavLength > 0) {
- if (exitPending()) goto exit;
- size_t count = bufferSize;
- if (count > wavLength)
- count = wavLength;
-
- if (pcm_write(pcm, wavData, count)) {
- ALOGE("pcm_write failed (%s)", pcm_get_error(pcm));
- goto exit;
- }
- wavData += count;
- wavLength -= count;
- }
-
-exit:
- if (pcm)
- pcm_close(pcm);
- delete mCurrentFile;
- mCurrentFile = NULL;
- return false;
-}
-
-} // namespace android
diff --git a/cmds/bootanimation/AudioPlayer.h b/cmds/bootanimation/AudioPlayer.h
deleted file mode 100644
index 1def0aeac8d12d28bee7aadfc10c296ca6bd971e..0000000000000000000000000000000000000000
--- a/cmds/bootanimation/AudioPlayer.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef _BOOTANIMATION_AUDIOPLAYER_H
-#define _BOOTANIMATION_AUDIOPLAYER_H
-
-#include
-#include
-
-namespace android {
-
-class AudioPlayer : public Thread
-{
-public:
- AudioPlayer();
- virtual ~AudioPlayer();
- bool init(const char* config);
-
- void playFile(FileMap* fileMap);
-
-private:
- virtual bool threadLoop();
-
-private:
- int mCard; // ALSA card to use
- int mDevice; // ALSA device to use
- int mPeriodSize;
- int mPeriodCount;
-
- FileMap* mCurrentFile;
-};
-
-} // namespace android
-
-#endif // _BOOTANIMATION_AUDIOPLAYER_H
diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp
index b8bd60776688bb257aa3c46fdaa1f969dbc5d547..7fd6347130b8e75094d6ed896f8e819b6365fe07 100644
--- a/cmds/bootanimation/BootAnimation.cpp
+++ b/cmds/bootanimation/BootAnimation.cpp
@@ -18,6 +18,9 @@
#define LOG_TAG "BootAnimation"
#include
+#include
+#include
+#include
#include
#include
#include
@@ -56,7 +59,7 @@
#include
#include "BootAnimation.h"
-#include "AudioPlayer.h"
+#include "audioplay.h"
#include
@@ -68,7 +71,29 @@
namespace android {
+static const char OEM_BOOTANIMATION_FILE[] = "/oem/media/bootanimation.zip";
+static const char SYSTEM_BOOTANIMATION_FILE[] = "/system/media/bootanimation.zip";
+static const char SYSTEM_ENCRYPTED_BOOTANIMATION_FILE[] = "/system/media/bootanimation-encrypted.zip";
+static const char SYSTEM_DATA_DIR_PATH[] = "/data/system";
+static const char SYSTEM_TIME_DIR_NAME[] = "time";
+static const char SYSTEM_TIME_DIR_PATH[] = "/data/system/time";
+static const char LAST_TIME_CHANGED_FILE_NAME[] = "last_time_change";
+static const char LAST_TIME_CHANGED_FILE_PATH[] = "/data/system/time/last_time_change";
+static const char ACCURATE_TIME_FLAG_FILE_NAME[] = "time_is_accurate";
+static const char ACCURATE_TIME_FLAG_FILE_PATH[] = "/data/system/time/time_is_accurate";
+// Java timestamp format. Don't show the clock if the date is before 2000-01-01 00:00:00.
+static const long long ACCURATE_TIME_EPOCH = 946684800000;
+static const char EXIT_PROP_NAME[] = "service.bootanim.exit";
+static const char PLAY_SOUND_PROP_NAME[] = "persist.sys.bootanim.play_sound";
static const int ANIM_ENTRY_NAME_MAX = 256;
+static const char BOOT_COMPLETED_PROP_NAME[] = "sys.boot_completed";
+static const char BOOTREASON_PROP_NAME[] = "ro.boot.bootreason";
+// bootreasons list in "system/core/bootstat/bootstat.cpp".
+static const std::vector PLAY_SOUND_BOOTREASON_BLACKLIST {
+ "kernel_panic",
+ "Panic",
+ "Watchdog",
+};
// ---------------------------------------------------------------------------
@@ -128,13 +153,16 @@ static unsigned long getFreeMemory(void)
return numFound > 0 ? mem : -1;
}
-BootAnimation::BootAnimation() : Thread(false), mClockEnabled(true) {
+BootAnimation::BootAnimation() : Thread(false), mClockEnabled(true), mTimeIsAccurate(false),
+ mTimeCheckThread(NULL) {
mSession = new SurfaceComposerClient();
-}
-BootAnimation::~BootAnimation() {
+ // If the system has already booted, the animation is not being used for a boot.
+ mSystemBoot = !property_get_bool(BOOT_COMPLETED_PROP_NAME, 0);
}
+BootAnimation::~BootAnimation() {}
+
void BootAnimation::onFirstRef() {
status_t err = mSession->linkToComposerDeath(this);
ALOGE_IF(err, "linkToComposerDeath failed (%s) ", strerror(-err));
@@ -157,9 +185,7 @@ void BootAnimation::binderDied(const wp&)
// might be blocked on a condition variable that will never be updated.
kill( getpid(), SIGKILL );
requestExit();
- if (mAudioPlayer != NULL) {
- mAudioPlayer->requestExit();
- }
+ audioplay::destroy();
}
status_t BootAnimation::initTexture(Texture* texture, AssetManager& assets,
@@ -262,25 +288,25 @@ status_t BootAnimation::initTexture(SkBitmap *bitmap)
switch (bitmap->colorType()) {
case kN32_SkColorType:
- if (tw != w || th != h) {
+ if (!mUseNpotTextures && (tw != w || th != h)) {
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tw, th, 0, GL_RGBA,
GL_UNSIGNED_BYTE, 0);
glTexSubImage2D(GL_TEXTURE_2D, 0,
0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, p);
} else {
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tw, th, 0, GL_RGBA,
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA,
GL_UNSIGNED_BYTE, p);
}
break;
case kRGB_565_SkColorType:
- if (tw != w || th != h) {
+ if (!mUseNpotTextures && (tw != w || th != h)) {
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, tw, th, 0, GL_RGB,
GL_UNSIGNED_SHORT_5_6_5, 0);
glTexSubImage2D(GL_TEXTURE_2D, 0,
0, 0, w, h, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, p);
} else {
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, tw, th, 0, GL_RGB,
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_RGB,
GL_UNSIGNED_SHORT_5_6_5, p);
}
break;
@@ -518,9 +544,6 @@ void BootAnimation::checkExit() {
int exitnow = atoi(value);
if (exitnow) {
requestExit();
- if (mAudioPlayer != NULL) {
- mAudioPlayer->requestExit();
- }
}
}
@@ -642,16 +665,6 @@ bool BootAnimation::parseAnimationDesc(Animation& animation)
}
char const* s = desString.string();
- // Create and initialize an AudioPlayer if we have an audio_conf.txt file
- String8 audioConf;
- if (readFile(animation.zip, "audio_conf.txt", audioConf)) {
- mAudioPlayer = new AudioPlayer;
- if (!mAudioPlayer->init(audioConf.string())) {
- ALOGE("mAudioPlayer.init failed");
- mAudioPlayer = NULL;
- }
- }
-
// Parse the description file
for (;;) {
const char* endl = strstr(s, "\n");
@@ -682,7 +695,7 @@ bool BootAnimation::parseAnimationDesc(Animation& animation)
part.pause = pause;
part.path = path;
part.clockPosY = clockPosY;
- part.audioFile = NULL;
+ part.audioData = NULL;
part.animation = NULL;
if (!parseColor(color, part.backgroundColor)) {
ALOGE("> invalid color '#%s'", color);
@@ -698,7 +711,7 @@ bool BootAnimation::parseAnimationDesc(Animation& animation)
part.playUntilComplete = false;
part.count = 1;
part.pause = 0;
- part.audioFile = NULL;
+ part.audioData = NULL;
part.animation = loadAnimation(String8(SYSTEM_BOOTANIMATION_FILE));
if (part.animation != NULL)
animation.parts.add(part);
@@ -714,15 +727,16 @@ bool BootAnimation::preloadZip(Animation& animation)
// read all the data structures
const size_t pcount = animation.parts.size();
void *cookie = NULL;
- ZipFileRO* mZip = animation.zip;
- if (!mZip->startIteration(&cookie)) {
+ ZipFileRO* zip = animation.zip;
+ if (!zip->startIteration(&cookie)) {
return false;
}
+ Animation::Part* partWithAudio = NULL;
ZipEntryRO entry;
char name[ANIM_ENTRY_NAME_MAX];
- while ((entry = mZip->nextEntry(cookie)) != NULL) {
- const int foundEntryName = mZip->getEntryFileName(entry, name, ANIM_ENTRY_NAME_MAX);
+ while ((entry = zip->nextEntry(cookie)) != NULL) {
+ const int foundEntryName = zip->getEntryFileName(entry, name, ANIM_ENTRY_NAME_MAX);
if (foundEntryName > ANIM_ENTRY_NAME_MAX || foundEntryName == -1) {
ALOGE("Error fetching entry file name");
continue;
@@ -732,25 +746,36 @@ bool BootAnimation::preloadZip(Animation& animation)
const String8 path(entryName.getPathDir());
const String8 leaf(entryName.getPathLeaf());
if (leaf.size() > 0) {
- for (size_t j=0 ; jgetEntryInfo(entry, &method, NULL, NULL, NULL, NULL, NULL)) {
+ if (zip->getEntryInfo(entry, &method, NULL, NULL, NULL, NULL, NULL)) {
if (method == ZipFileRO::kCompressStored) {
- FileMap* map = mZip->createEntryFileMap(entry);
+ FileMap* map = zip->createEntryFileMap(entry);
if (map) {
Animation::Part& part(animation.parts.editItemAt(j));
if (leaf == "audio.wav") {
// a part may have at most one audio file
- part.audioFile = map;
+ part.audioData = (uint8_t *)map->getDataPtr();
+ part.audioLength = map->getDataLength();
+ partWithAudio = ∂
+ } else if (leaf == "trim.txt") {
+ part.trimData.setTo((char const*)map->getDataPtr(),
+ map->getDataLength());
} else {
Animation::Frame frame;
frame.name = leaf;
frame.map = map;
+ frame.trimWidth = animation.width;
+ frame.trimHeight = animation.height;
+ frame.trimX = 0;
+ frame.trimY = 0;
part.frames.add(frame);
}
}
+ } else {
+ ALOGE("bootanimation.zip is compressed; must be only stored");
}
}
}
@@ -758,18 +783,76 @@ bool BootAnimation::preloadZip(Animation& animation)
}
}
- mZip->endIteration(cookie);
+ // If there is trimData present, override the positioning defaults.
+ for (Animation::Part& part : animation.parts) {
+ const char* trimDataStr = part.trimData.string();
+ for (size_t frameIdx = 0; frameIdx < part.frames.size(); frameIdx++) {
+ const char* endl = strstr(trimDataStr, "\n");
+ // No more trimData for this part.
+ if (endl == NULL) {
+ break;
+ }
+ String8 line(trimDataStr, endl - trimDataStr);
+ const char* lineStr = line.string();
+ trimDataStr = ++endl;
+ int width = 0, height = 0, x = 0, y = 0;
+ if (sscanf(lineStr, "%dx%d+%d+%d", &width, &height, &x, &y) == 4) {
+ Animation::Frame& frame(part.frames.editItemAt(frameIdx));
+ frame.trimWidth = width;
+ frame.trimHeight = height;
+ frame.trimX = x;
+ frame.trimY = y;
+ } else {
+ ALOGE("Error parsing trim.txt, line: %s", lineStr);
+ break;
+ }
+ }
+ }
+
+ // Create and initialize audioplay if there is a wav file in any of the animations.
+ if (partWithAudio != NULL) {
+ ALOGD("found audio.wav, creating playback engine");
+ if (!audioplay::create(partWithAudio->audioData, partWithAudio->audioLength)) {
+ return false;
+ }
+ }
+
+ zip->endIteration(cookie);
return true;
}
bool BootAnimation::movie()
{
-
Animation* animation = loadAnimation(mZipFileName);
if (animation == NULL)
return false;
+ bool anyPartHasClock = false;
+ for (size_t i=0; i < animation->parts.size(); i++) {
+ if(animation->parts[i].clockPosY >= 0) {
+ anyPartHasClock = true;
+ break;
+ }
+ }
+ if (!anyPartHasClock) {
+ mClockEnabled = false;
+ }
+
+ // Check if npot textures are supported
+ mUseNpotTextures = false;
+ String8 gl_extensions;
+ const char* exts = reinterpret_cast(glGetString(GL_EXTENSIONS));
+ if (!exts) {
+ glGetError();
+ } else {
+ gl_extensions.setTo(exts);
+ if ((gl_extensions.find("GL_ARB_texture_non_power_of_two") != -1) ||
+ (gl_extensions.find("GL_OES_texture_npot") != -1)) {
+ mUseNpotTextures = true;
+ }
+ }
+
// Blend required to draw time on top of animation frames.
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glShadeModel(GL_FLAT);
@@ -791,7 +874,18 @@ bool BootAnimation::movie()
mClockEnabled = clockTextureInitialized;
}
+ if (mClockEnabled && !updateIsTimeAccurate()) {
+ mTimeCheckThread = new TimeCheckThread(this);
+ mTimeCheckThread->run("BootAnimation::TimeCheckThread", PRIORITY_NORMAL);
+ }
+
playAnimation(*animation);
+
+ if (mTimeCheckThread != NULL) {
+ mTimeCheckThread->requestExit();
+ mTimeCheckThread = NULL;
+ }
+
releaseAnimation(animation);
if (clockTextureInitialized) {
@@ -804,12 +898,9 @@ bool BootAnimation::movie()
bool BootAnimation::playAnimation(const Animation& animation)
{
const size_t pcount = animation.parts.size();
- const int xc = (mWidth - animation.width) / 2;
- const int yc = ((mHeight - animation.height) / 2);
nsecs_t frameDuration = s2ns(1) / animation.fps;
-
- Region clearReg(Rect(mWidth, mHeight));
- clearReg.subtractSelf(Rect(xc, yc, xc+animation.width, yc+animation.height));
+ const int animationX = (mWidth - animation.width) / 2;
+ const int animationY = (mHeight - animation.height) / 2;
for (size_t i=0 ; iplayFile(part.audioFile);
+ if (r == 0 && part.audioData && playSoundsAllowed()) {
+ ALOGD("playing clip for part%d, size=%d", (int) i, part.audioLength);
+ audioplay::playClip(part.audioData, part.audioLength);
}
glClearColor(
@@ -894,23 +986,26 @@ bool BootAnimation::playAnimation(const Animation& animation)
#endif
}
+ const int xc = animationX + frame.trimX;
+ const int yc = animationY + frame.trimY;
+ Region clearReg(Rect(mWidth, mHeight));
+ clearReg.subtractSelf(Rect(xc, yc, xc+frame.trimWidth, yc+frame.trimHeight));
if (!clearReg.isEmpty()) {
Region::const_iterator head(clearReg.begin());
Region::const_iterator tail(clearReg.end());
glEnable(GL_SCISSOR_TEST);
while (head != tail) {
const Rect& r2(*head++);
- glScissor(r2.left, mHeight - r2.bottom,
- r2.width(), r2.height());
+ glScissor(r2.left, mHeight - r2.bottom, r2.width(), r2.height());
glClear(GL_COLOR_BUFFER_BIT);
}
glDisable(GL_SCISSOR_TEST);
}
- // specify the y center as ceiling((mHeight - animation.height) / 2)
- // which is equivalent to mHeight - (yc + animation.height)
- glDrawTexiOES(xc, mHeight - (yc + animation.height),
- 0, animation.width, animation.height);
- if (mClockEnabled && part.clockPosY >= 0) {
+ // specify the y center as ceiling((mHeight - frame.trimHeight) / 2)
+ // which is equivalent to mHeight - (yc + frame.trimHeight)
+ glDrawTexiOES(xc, mHeight - (yc + frame.trimHeight),
+ 0, frame.trimWidth, frame.trimHeight);
+ if (mClockEnabled && mTimeIsAccurate && part.clockPosY >= 0) {
drawTime(mClock, part.clockPosY);
}
@@ -947,9 +1042,13 @@ bool BootAnimation::playAnimation(const Animation& animation)
break;
}
- // free the textures for this part
- if (!needSaveMem && part.count != 1) {
- for (size_t j=0 ; jfileName);
parseAnimationDesc(*animation);
- preloadZip(*animation);
+ if (!preloadZip(*animation)) {
+ return NULL;
+ }
+
mLoadedFiles.remove(fn);
return animation;
@@ -1111,6 +1218,156 @@ bool FrameManager::DecodeThread::threadLoop()
}
#endif
+bool BootAnimation::playSoundsAllowed() const {
+ // Only play sounds for system boots, not runtime restarts.
+ if (!mSystemBoot) {
+ return false;
+ }
+
+ // Read the system property to see if we should play the sound.
+ // If it's not present, default to allowed.
+ if (!property_get_bool(PLAY_SOUND_PROP_NAME, 1)) {
+ return false;
+ }
+
+ // Don't play sounds if this is a reboot due to an error.
+ char bootreason[PROPERTY_VALUE_MAX];
+ if (property_get(BOOTREASON_PROP_NAME, bootreason, nullptr) > 0) {
+ for (const auto& str : PLAY_SOUND_BOOTREASON_BLACKLIST) {
+ if (strcasecmp(str.c_str(), bootreason) == 0) {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+bool BootAnimation::updateIsTimeAccurate() {
+ static constexpr long long MAX_TIME_IN_PAST = 60000LL * 60LL * 24LL * 30LL; // 30 days
+ static constexpr long long MAX_TIME_IN_FUTURE = 60000LL * 90LL; // 90 minutes
+
+ if (mTimeIsAccurate) {
+ return true;
+ }
+
+ struct stat statResult;
+ if(stat(ACCURATE_TIME_FLAG_FILE_PATH, &statResult) == 0) {
+ mTimeIsAccurate = true;
+ return true;
+ }
+
+ FILE* file = fopen(LAST_TIME_CHANGED_FILE_PATH, "r");
+ if (file != NULL) {
+ long long lastChangedTime = 0;
+ fscanf(file, "%lld", &lastChangedTime);
+ fclose(file);
+ if (lastChangedTime > 0) {
+ struct timespec now;
+ clock_gettime(CLOCK_REALTIME, &now);
+ // Match the Java timestamp format
+ long long rtcNow = (now.tv_sec * 1000LL) + (now.tv_nsec / 1000000LL);
+ if (ACCURATE_TIME_EPOCH < rtcNow
+ && lastChangedTime > (rtcNow - MAX_TIME_IN_PAST)
+ && lastChangedTime < (rtcNow + MAX_TIME_IN_FUTURE)) {
+ mTimeIsAccurate = true;
+ }
+ }
+ }
+
+ return mTimeIsAccurate;
+}
+
+BootAnimation::TimeCheckThread::TimeCheckThread(BootAnimation* bootAnimation) : Thread(false),
+ mInotifyFd(-1), mSystemWd(-1), mTimeWd(-1), mBootAnimation(bootAnimation) {}
+
+BootAnimation::TimeCheckThread::~TimeCheckThread() {
+ // mInotifyFd may be -1 but that's ok since we're not at risk of attempting to close a valid FD.
+ close(mInotifyFd);
+}
+
+bool BootAnimation::TimeCheckThread::threadLoop() {
+ bool shouldLoop = doThreadLoop() && !mBootAnimation->mTimeIsAccurate
+ && mBootAnimation->mClockEnabled;
+ if (!shouldLoop) {
+ close(mInotifyFd);
+ mInotifyFd = -1;
+ }
+ return shouldLoop;
+}
+
+bool BootAnimation::TimeCheckThread::doThreadLoop() {
+ static constexpr int BUFF_LEN (10 * (sizeof(struct inotify_event) + NAME_MAX + 1));
+
+ // Poll instead of doing a blocking read so the Thread can exit if requested.
+ struct pollfd pfd = { mInotifyFd, POLLIN, 0 };
+ ssize_t pollResult = poll(&pfd, 1, 1000);
+
+ if (pollResult == 0) {
+ return true;
+ } else if (pollResult < 0) {
+ ALOGE("Could not poll inotify events");
+ return false;
+ }
+
+ char buff[BUFF_LEN] __attribute__ ((aligned(__alignof__(struct inotify_event))));;
+ ssize_t length = read(mInotifyFd, buff, BUFF_LEN);
+ if (length == 0) {
+ return true;
+ } else if (length < 0) {
+ ALOGE("Could not read inotify events");
+ return false;
+ }
+
+ const struct inotify_event *event;
+ for (char* ptr = buff; ptr < buff + length; ptr += sizeof(struct inotify_event) + event->len) {
+ event = (const struct inotify_event *) ptr;
+ if (event->wd == mSystemWd && strcmp(SYSTEM_TIME_DIR_NAME, event->name) == 0) {
+ addTimeDirWatch();
+ } else if (event->wd == mTimeWd && (strcmp(LAST_TIME_CHANGED_FILE_NAME, event->name) == 0
+ || strcmp(ACCURATE_TIME_FLAG_FILE_NAME, event->name) == 0)) {
+ return !mBootAnimation->updateIsTimeAccurate();
+ }
+ }
+
+ return true;
+}
+
+void BootAnimation::TimeCheckThread::addTimeDirWatch() {
+ mTimeWd = inotify_add_watch(mInotifyFd, SYSTEM_TIME_DIR_PATH,
+ IN_CLOSE_WRITE | IN_MOVED_TO | IN_ATTRIB);
+ if (mTimeWd > 0) {
+ // No need to watch for the time directory to be created if it already exists
+ inotify_rm_watch(mInotifyFd, mSystemWd);
+ mSystemWd = -1;
+ }
+}
+
+status_t BootAnimation::TimeCheckThread::readyToRun() {
+ mInotifyFd = inotify_init();
+ if (mInotifyFd < 0) {
+ ALOGE("Could not initialize inotify fd");
+ return NO_INIT;
+ }
+
+ mSystemWd = inotify_add_watch(mInotifyFd, SYSTEM_DATA_DIR_PATH, IN_CREATE | IN_ATTRIB);
+ if (mSystemWd < 0) {
+ close(mInotifyFd);
+ mInotifyFd = -1;
+ ALOGE("Could not add watch for %s", SYSTEM_DATA_DIR_PATH);
+ return NO_INIT;
+ }
+
+ addTimeDirWatch();
+
+ if (mBootAnimation->updateIsTimeAccurate()) {
+ close(mInotifyFd);
+ mInotifyFd = -1;
+ return ALREADY_EXISTS;
+ }
+
+ return NO_ERROR;
+}
+
// ---------------------------------------------------------------------------
}
diff --git a/cmds/bootanimation/BootAnimation.h b/cmds/bootanimation/BootAnimation.h
index 5856e9e7433b43b1e133cc74837c94eb7c5749b4..b70cc0eed2675df26f5e4675d8a93e53dc809d5d 100644
--- a/cmds/bootanimation/BootAnimation.h
+++ b/cmds/bootanimation/BootAnimation.h
@@ -32,7 +32,6 @@ class SkBitmap;
namespace android {
-class AudioPlayer;
class Surface;
class SurfaceComposerClient;
class SurfaceControl;
@@ -59,6 +58,24 @@ private:
virtual void onFirstRef();
virtual void binderDied(const wp& who);
+ bool updateIsTimeAccurate();
+
+ class TimeCheckThread : public Thread {
+ public:
+ TimeCheckThread(BootAnimation* bootAnimation);
+ virtual ~TimeCheckThread();
+ private:
+ virtual status_t readyToRun();
+ virtual bool threadLoop();
+ bool doThreadLoop();
+ void addTimeDirWatch();
+
+ int mInotifyFd;
+ int mSystemWd;
+ int mTimeWd;
+ BootAnimation* mBootAnimation;
+ };
+
struct Texture {
GLint w;
GLint h;
@@ -69,6 +86,10 @@ private:
struct Frame {
String8 name;
FileMap* map;
+ int trimX;
+ int trimY;
+ int trimWidth;
+ int trimHeight;
mutable GLuint tid;
bool operator < (const Frame& rhs) const {
return name < rhs.name;
@@ -80,10 +101,12 @@ private:
int clockPosY; // The y position of the clock, in pixels, from the bottom of the
// display (the clock is centred horizontally). -1 to disable the clock
String8 path;
+ String8 trimData;
SortedVector frames;
bool playUntilComplete;
float backgroundColor[3];
- FileMap* audioFile;
+ uint8_t* audioData;
+ int audioLength;
Animation* animation;
};
int fps;
@@ -113,26 +136,30 @@ private:
void releaseAnimation(Animation*) const;
bool parseAnimationDesc(Animation&);
bool preloadZip(Animation &animation);
+ bool playSoundsAllowed() const;
void checkExit();
static SkBitmap *decode(const Animation::Frame& frame);
sp mSession;
- sp mAudioPlayer;
AssetManager mAssets;
Texture mAndroid[2];
Texture mClock;
int mWidth;
int mHeight;
+ bool mUseNpotTextures = false;
EGLDisplay mDisplay;
EGLDisplay mContext;
EGLDisplay mSurface;
sp mFlingerSurfaceControl;
sp mFlingerSurface;
bool mClockEnabled;
+ bool mTimeIsAccurate;
+ bool mSystemBoot;
String8 mZipFileName;
SortedVector mLoadedFiles;
+ sp mTimeCheckThread;
};
#ifdef MULTITHREAD_DECODE
diff --git a/cmds/bootanimation/FORMAT.md b/cmds/bootanimation/FORMAT.md
new file mode 100644
index 0000000000000000000000000000000000000000..9ea6fea966f2521489c4abade4c1d1b3e3192fc4
--- /dev/null
+++ b/cmds/bootanimation/FORMAT.md
@@ -0,0 +1,101 @@
+# bootanimation format
+
+## zipfile paths
+
+The system selects a boot animation zipfile from the following locations, in order:
+
+ /system/media/bootanimation-encrypted.zip (if getprop("vold.decrypt") = '1')
+ /system/media/bootanimation.zip
+ /oem/media/bootanimation.zip
+
+## zipfile layout
+
+The `bootanimation.zip` archive file includes:
+
+ desc.txt - a text file
+ part0 \
+ part1 \ directories full of PNG frames
+ ... /
+ partN /
+
+## desc.txt format
+
+The first line defines the general parameters of the animation:
+
+ WIDTH HEIGHT FPS
+
+ * **WIDTH:** animation width (pixels)
+ * **HEIGHT:** animation height (pixels)
+ * **FPS:** frames per second, e.g. 60
+
+It is followed by a number of rows of the form:
+
+ TYPE COUNT PAUSE PATH [#RGBHEX CLOCK]
+
+ * **TYPE:** a single char indicating what type of animation segment this is:
+ + `p` -- this part will play unless interrupted by the end of the boot
+ + `c` -- this part will play to completion, no matter what
+ * **COUNT:** how many times to play the animation, or 0 to loop forever until boot is complete
+ * **PAUSE:** number of FRAMES to delay after this part ends
+ * **PATH:** directory in which to find the frames for this part (e.g. `part0`)
+ * **RGBHEX:** _(OPTIONAL)_ a background color, specified as `#RRGGBB`
+ * **CLOCK:** _(OPTIONAL)_ the y-coordinate at which to draw the current time (for watches)
+
+There is also a special TYPE, `$SYSTEM`, that loads `/system/media/bootanimation.zip`
+and plays that.
+
+## loading and playing frames
+
+Each part is scanned and loaded directly from the zip archive. Within a part directory, every file
+(except `trim.txt` and `audio.wav`; see next sections) is expected to be a PNG file that represents
+one frame in that part (at the specified resolution). For this reason it is important that frames be
+named sequentially (e.g. `part000.png`, `part001.png`, ...) and added to the zip archive in that
+order.
+
+## trim.txt
+
+To save on memory, textures may be trimmed by their background color. trim.txt sequentially lists
+the trim output for each frame in its directory, so the frames may be properly positioned.
+Output should be of the form: `WxH+X+Y`. Example:
+
+ 713x165+388+914
+ 708x152+388+912
+ 707x139+388+911
+ 649x92+388+910
+
+If the file is not present, each frame is assumed to be the same size as the animation.
+
+## audio.wav
+
+Each part may optionally play a `wav` sample when it starts. To enable this, add a file
+with the name `audio.wav` in the part directory.
+
+## exiting
+
+The system will end the boot animation (first completing any incomplete or even entirely unplayed
+parts that are of type `c`) when the system is finished booting. (This is accomplished by setting
+the system property `service.bootanim.exit` to a nonzero string.)
+
+## protips
+
+### PNG compression
+
+Use `zopflipng` if you have it, otherwise `pngcrush` will do. e.g.:
+
+ for fn in *.png ; do
+ zopflipng -m ${fn}s ${fn}s.new && mv -f ${fn}s.new ${fn}
+ # or: pngcrush -q ....
+ done
+
+Some animations benefit from being reduced to 256 colors:
+
+ pngquant --force --ext .png *.png
+ # alternatively: mogrify -colors 256 anim-tmp/*/*.png
+
+### creating the ZIP archive
+
+ cd
+ zip -0qry -i \*.txt \*.png \*.wav @ ../bootanimation.zip *.txt part*
+
+Note that the ZIP archive is not actually compressed! The PNG files are already as compressed
+as they can reasonably get, and there is unlikely to be any redundancy between files.
diff --git a/cmds/bootanimation/audioplay.cpp b/cmds/bootanimation/audioplay.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..4983b9ac4236e65f28d00c41e18395ddfa41b544
--- /dev/null
+++ b/cmds/bootanimation/audioplay.cpp
@@ -0,0 +1,386 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// cribbed from samples/native-audio
+
+#include "audioplay.h"
+
+#define CHATTY ALOGD
+#define LOG_TAG "audioplay"
+
+#include
+
+#include
+
+// for native audio
+#include
+#include
+
+namespace audioplay {
+namespace {
+
+// engine interfaces
+static SLObjectItf engineObject = NULL;
+static SLEngineItf engineEngine;
+
+// output mix interfaces
+static SLObjectItf outputMixObject = NULL;
+
+// buffer queue player interfaces
+static SLObjectItf bqPlayerObject = NULL;
+static SLPlayItf bqPlayerPlay;
+static SLAndroidSimpleBufferQueueItf bqPlayerBufferQueue;
+static SLMuteSoloItf bqPlayerMuteSolo;
+static SLVolumeItf bqPlayerVolume;
+
+// pointer and size of the next player buffer to enqueue, and number of remaining buffers
+static const uint8_t* nextBuffer;
+static unsigned nextSize;
+
+static const uint32_t ID_RIFF = 0x46464952;
+static const uint32_t ID_WAVE = 0x45564157;
+static const uint32_t ID_FMT = 0x20746d66;
+static const uint32_t ID_DATA = 0x61746164;
+
+struct RiffWaveHeader {
+ uint32_t riff_id;
+ uint32_t riff_sz;
+ uint32_t wave_id;
+};
+
+struct ChunkHeader {
+ uint32_t id;
+ uint32_t sz;
+};
+
+struct ChunkFormat {
+ uint16_t audio_format;
+ uint16_t num_channels;
+ uint32_t sample_rate;
+ uint32_t byte_rate;
+ uint16_t block_align;
+ uint16_t bits_per_sample;
+};
+
+// this callback handler is called every time a buffer finishes playing
+void bqPlayerCallback(SLAndroidSimpleBufferQueueItf bq, void *context) {
+ (void)bq;
+ (void)context;
+ audioplay::setPlaying(false);
+}
+
+bool hasPlayer() {
+ return (engineObject != NULL && bqPlayerObject != NULL);
+}
+
+// create the engine and output mix objects
+bool createEngine() {
+ SLresult result;
+
+ // create engine
+ result = slCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL);
+ if (result != SL_RESULT_SUCCESS) {
+ ALOGE("slCreateEngine failed with result %d", result);
+ return false;
+ }
+ (void)result;
+
+ // realize the engine
+ result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE);
+ if (result != SL_RESULT_SUCCESS) {
+ ALOGE("sl engine Realize failed with result %d", result);
+ return false;
+ }
+ (void)result;
+
+ // get the engine interface, which is needed in order to create other objects
+ result = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine);
+ if (result != SL_RESULT_SUCCESS) {
+ ALOGE("sl engine GetInterface failed with result %d", result);
+ return false;
+ }
+ (void)result;
+
+ // create output mix
+ result = (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, 0, NULL, NULL);
+ if (result != SL_RESULT_SUCCESS) {
+ ALOGE("sl engine CreateOutputMix failed with result %d", result);
+ return false;
+ }
+ (void)result;
+
+ // realize the output mix
+ result = (*outputMixObject)->Realize(outputMixObject, SL_BOOLEAN_FALSE);
+ if (result != SL_RESULT_SUCCESS) {
+ ALOGE("sl outputMix Realize failed with result %d", result);
+ return false;
+ }
+ (void)result;
+
+ return true;
+}
+
+// create buffer queue audio player
+bool createBufferQueueAudioPlayer(const ChunkFormat* chunkFormat) {
+ SLresult result;
+
+ // configure audio source
+ SLDataLocator_AndroidSimpleBufferQueue loc_bufq = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 1};
+
+ SLDataFormat_PCM format_pcm = {
+ SL_DATAFORMAT_PCM,
+ chunkFormat->num_channels,
+ chunkFormat->sample_rate * 1000, // convert to milliHz
+ chunkFormat->bits_per_sample,
+ 16,
+ SL_SPEAKER_FRONT_CENTER,
+ SL_BYTEORDER_LITTLEENDIAN
+ };
+ SLDataSource audioSrc = {&loc_bufq, &format_pcm};
+
+ // configure audio sink
+ SLDataLocator_OutputMix loc_outmix = {SL_DATALOCATOR_OUTPUTMIX, outputMixObject};
+ SLDataSink audioSnk = {&loc_outmix, NULL};
+
+ // create audio player
+ const SLInterfaceID ids[3] = {SL_IID_BUFFERQUEUE, SL_IID_VOLUME, SL_IID_ANDROIDCONFIGURATION};
+ const SLboolean req[3] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE};
+ result = (*engineEngine)->CreateAudioPlayer(engineEngine, &bqPlayerObject, &audioSrc, &audioSnk,
+ 3, ids, req);
+ if (result != SL_RESULT_SUCCESS) {
+ ALOGE("sl CreateAudioPlayer failed with result %d", result);
+ return false;
+ }
+ (void)result;
+
+ // Use the System stream for boot sound playback.
+ SLAndroidConfigurationItf playerConfig;
+ result = (*bqPlayerObject)->GetInterface(bqPlayerObject,
+ SL_IID_ANDROIDCONFIGURATION, &playerConfig);
+ if (result != SL_RESULT_SUCCESS) {
+ ALOGE("config GetInterface failed with result %d", result);
+ return false;
+ }
+ SLint32 streamType = SL_ANDROID_STREAM_SYSTEM;
+ result = (*playerConfig)->SetConfiguration(playerConfig,
+ SL_ANDROID_KEY_STREAM_TYPE, &streamType, sizeof(SLint32));
+ if (result != SL_RESULT_SUCCESS) {
+ ALOGE("SetConfiguration failed with result %d", result);
+ return false;
+ }
+ // use normal performance mode as low latency is not needed. This is not mandatory so
+ // do not bail if we fail
+ SLuint32 performanceMode = SL_ANDROID_PERFORMANCE_NONE;
+ result = (*playerConfig)->SetConfiguration(
+ playerConfig, SL_ANDROID_KEY_PERFORMANCE_MODE, &performanceMode, sizeof(SLuint32));
+ ALOGW_IF(result != SL_RESULT_SUCCESS,
+ "could not set performance mode on player, error %d", result);
+ (void)result;
+
+ // realize the player
+ result = (*bqPlayerObject)->Realize(bqPlayerObject, SL_BOOLEAN_FALSE);
+ if (result != SL_RESULT_SUCCESS) {
+ ALOGE("sl player Realize failed with result %d", result);
+ return false;
+ }
+ (void)result;
+
+ // get the play interface
+ result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_PLAY, &bqPlayerPlay);
+ if (result != SL_RESULT_SUCCESS) {
+ ALOGE("sl player GetInterface failed with result %d", result);
+ return false;
+ }
+ (void)result;
+
+ // get the buffer queue interface
+ result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_BUFFERQUEUE,
+ &bqPlayerBufferQueue);
+ if (result != SL_RESULT_SUCCESS) {
+ ALOGE("sl playberBufferQueue GetInterface failed with result %d", result);
+ return false;
+ }
+ (void)result;
+
+ // register callback on the buffer queue
+ result = (*bqPlayerBufferQueue)->RegisterCallback(bqPlayerBufferQueue, bqPlayerCallback, NULL);
+ if (result != SL_RESULT_SUCCESS) {
+ ALOGE("sl bqPlayerBufferQueue RegisterCallback failed with result %d", result);
+ return false;
+ }
+ (void)result;
+
+ // get the volume interface
+ result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_VOLUME, &bqPlayerVolume);
+ if (result != SL_RESULT_SUCCESS) {
+ ALOGE("sl volume GetInterface failed with result %d", result);
+ return false;
+ }
+ (void)result;
+
+ // set the player's state to playing
+ audioplay::setPlaying(true);
+ CHATTY("Created buffer queue player: %p", bqPlayerBufferQueue);
+ return true;
+}
+
+bool parseClipBuf(const uint8_t* clipBuf, int clipBufSize, const ChunkFormat** oChunkFormat,
+ const uint8_t** oSoundBuf, unsigned* oSoundBufSize) {
+ *oSoundBuf = clipBuf;
+ *oSoundBufSize = clipBufSize;
+ *oChunkFormat = NULL;
+ const RiffWaveHeader* wavHeader = (const RiffWaveHeader*)*oSoundBuf;
+ if (*oSoundBufSize < sizeof(*wavHeader) || (wavHeader->riff_id != ID_RIFF) ||
+ (wavHeader->wave_id != ID_WAVE)) {
+ ALOGE("Error: audio file is not a riff/wave file\n");
+ return false;
+ }
+ *oSoundBuf += sizeof(*wavHeader);
+ *oSoundBufSize -= sizeof(*wavHeader);
+
+ while (true) {
+ const ChunkHeader* chunkHeader = (const ChunkHeader*)*oSoundBuf;
+ if (*oSoundBufSize < sizeof(*chunkHeader)) {
+ ALOGE("EOF reading chunk headers");
+ return false;
+ }
+
+ *oSoundBuf += sizeof(*chunkHeader);
+ *oSoundBufSize -= sizeof(*chunkHeader);
+
+ bool endLoop = false;
+ switch (chunkHeader->id) {
+ case ID_FMT:
+ *oChunkFormat = (const ChunkFormat*)*oSoundBuf;
+ *oSoundBuf += chunkHeader->sz;
+ *oSoundBufSize -= chunkHeader->sz;
+ break;
+ case ID_DATA:
+ /* Stop looking for chunks */
+ *oSoundBufSize = chunkHeader->sz;
+ endLoop = true;
+ break;
+ default:
+ /* Unknown chunk, skip bytes */
+ *oSoundBuf += chunkHeader->sz;
+ *oSoundBufSize -= chunkHeader->sz;
+ }
+ if (endLoop) {
+ break;
+ }
+ }
+
+ if (*oChunkFormat == NULL) {
+ ALOGE("format not found in WAV file");
+ return false;
+ }
+ return true;
+}
+
+} // namespace
+
+bool create(const uint8_t* exampleClipBuf, int exampleClipBufSize) {
+ if (!createEngine()) {
+ return false;
+ }
+
+ // Parse the example clip.
+ const ChunkFormat* chunkFormat;
+ const uint8_t* soundBuf;
+ unsigned soundBufSize;
+ if (!parseClipBuf(exampleClipBuf, exampleClipBufSize, &chunkFormat, &soundBuf, &soundBufSize)) {
+ return false;
+ }
+
+ // Initialize the BufferQueue based on this clip's format.
+ if (!createBufferQueueAudioPlayer(chunkFormat)) {
+ return false;
+ }
+ return true;
+}
+
+bool playClip(const uint8_t* buf, int size) {
+ // Parse the WAV header
+ const ChunkFormat* chunkFormat;
+ if (!parseClipBuf(buf, size, &chunkFormat, &nextBuffer, &nextSize)) {
+ return false;
+ }
+
+ if (!hasPlayer()) {
+ ALOGD("cannot play clip %p without a player", buf);
+ return false;
+ }
+
+ CHATTY("playClip on player %p: buf=%p size=%d nextSize %d",
+ bqPlayerBufferQueue, buf, size, nextSize);
+
+ if (nextSize > 0) {
+ // here we only enqueue one buffer because it is a long clip,
+ // but for streaming playback we would typically enqueue at least 2 buffers to start
+ SLresult result;
+ result = (*bqPlayerBufferQueue)->Enqueue(bqPlayerBufferQueue, nextBuffer, nextSize);
+ if (SL_RESULT_SUCCESS != result) {
+ return false;
+ }
+ audioplay::setPlaying(true);
+ }
+
+ return true;
+}
+
+// set the playing state for the buffer queue audio player
+void setPlaying(bool isPlaying) {
+ if (!hasPlayer()) return;
+
+ SLresult result;
+
+ if (NULL != bqPlayerPlay) {
+ // set the player's state
+ result = (*bqPlayerPlay)->SetPlayState(bqPlayerPlay,
+ isPlaying ? SL_PLAYSTATE_PLAYING : SL_PLAYSTATE_STOPPED);
+ }
+
+}
+
+void destroy() {
+ // destroy buffer queue audio player object, and invalidate all associated interfaces
+ if (bqPlayerObject != NULL) {
+ CHATTY("destroying audio player");
+ (*bqPlayerObject)->Destroy(bqPlayerObject);
+ bqPlayerObject = NULL;
+ bqPlayerPlay = NULL;
+ bqPlayerBufferQueue = NULL;
+ bqPlayerMuteSolo = NULL;
+ bqPlayerVolume = NULL;
+ }
+
+ // destroy output mix object, and invalidate all associated interfaces
+ if (outputMixObject != NULL) {
+ (*outputMixObject)->Destroy(outputMixObject);
+ outputMixObject = NULL;
+ }
+
+ // destroy engine object, and invalidate all associated interfaces
+ if (engineObject != NULL) {
+ CHATTY("destroying audio engine");
+ (*engineObject)->Destroy(engineObject);
+ engineObject = NULL;
+ engineEngine = NULL;
+ }
+}
+
+} // namespace audioplay
diff --git a/cmds/bootanimation/audioplay.h b/cmds/bootanimation/audioplay.h
new file mode 100644
index 0000000000000000000000000000000000000000..0e5705af0ad03513d0dc800790c5b2764e1828a7
--- /dev/null
+++ b/cmds/bootanimation/audioplay.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef AUDIOPLAY_H_
+#define AUDIOPLAY_H_
+
+#include
+
+namespace audioplay {
+
+// Initializes the engine with an example of the type of WAV clip to play.
+// All buffers passed to playClip are assumed to be in the same format.
+bool create(const uint8_t* exampleClipBuf, int exampleClipBufSize);
+
+// Plays a WAV contained in buf.
+// Should not be called while a clip is still playing.
+bool playClip(const uint8_t* buf, int size);
+void setPlaying(bool isPlaying);
+void destroy();
+
+}
+
+#endif // AUDIOPLAY_H_
diff --git a/cmds/bootanimation/bootanim.rc b/cmds/bootanimation/bootanim.rc
index ee0d0b8c042f199082d285611b11812456a986f4..7344ba74f70b643fa0fefab4551fa3ce87f825dd 100644
--- a/cmds/bootanimation/bootanim.rc
+++ b/cmds/bootanimation/bootanim.rc
@@ -4,3 +4,4 @@ service bootanim /system/bin/bootanimation
group graphics audio
disabled
oneshot
+ writepid /dev/stune/top-app/tasks
\ No newline at end of file
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index c6834f940554797962ef6c5b6159f8b53c2f9fc7..32a8088e9c4e618d3a313633e5fee3db1b855b92 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -922,6 +922,8 @@ public final class Pm {
flags |= UserInfo.FLAG_EPHEMERAL;
} else if ("--guest".equals(opt)) {
flags |= UserInfo.FLAG_GUEST;
+ } else if ("--demo".equals(opt)) {
+ flags |= UserInfo.FLAG_DEMO;
} else {
System.err.println("Error: unknown option " + opt);
return showUsage();
diff --git a/core/java/android/animation/AnimatorSet.java b/core/java/android/animation/AnimatorSet.java
index 7841d29b5700dc9f59897121394040826e5290dd..053ba7d5fa0ad276c10c5641d2a716eaebab7e23 100644
--- a/core/java/android/animation/AnimatorSet.java
+++ b/core/java/android/animation/AnimatorSet.java
@@ -1064,15 +1064,15 @@ public final class AnimatorSet extends Animator {
/**
* @hide
* TODO: For animatorSet defined in XML, we can use a flag to indicate what the play order
- * if defined (i.e. sequential or together), then we can use the flag instead of calculate
- * dynamically.
+ * if defined (i.e. sequential or together), then we can use the flag instead of calculating
+ * dynamically. Note that when AnimatorSet is empty this method returns true.
* @return whether all the animators in the set are supposed to play together
*/
public boolean shouldPlayTogether() {
updateAnimatorsDuration();
createDependencyGraph();
// All the child nodes are set out to play right after the delay animation
- return mRootNode.mChildNodes.size() == mNodes.size() - 1;
+ return mRootNode.mChildNodes == null || mRootNode.mChildNodes.size() == mNodes.size() - 1;
}
@Override
diff --git a/core/java/android/animation/ObjectAnimator.java b/core/java/android/animation/ObjectAnimator.java
index 5c4b979ccb3cb1159634758feb2b1778fe3a82c5..9a2aa302a4bafe34435e97257da1c1a11b9c76f2 100644
--- a/core/java/android/animation/ObjectAnimator.java
+++ b/core/java/android/animation/ObjectAnimator.java
@@ -977,7 +977,7 @@ public final class ObjectAnimator extends ValueAnimator {
@Override
void animateValue(float fraction) {
final Object target = getTarget();
- if (mTarget != null && target == null) {
+ if (target == null) {
// We lost the target reference, cancel and clean up.
cancel();
return;
diff --git a/core/java/android/animation/PropertyValuesHolder.java b/core/java/android/animation/PropertyValuesHolder.java
index 224823ee2ff11afc9aef9d9876a25716c22667de..ba16e673ea6991f0f5b6a6a73163cf5655a01f9e 100644
--- a/core/java/android/animation/PropertyValuesHolder.java
+++ b/core/java/android/animation/PropertyValuesHolder.java
@@ -1095,8 +1095,12 @@ public class PropertyValuesHolder implements Cloneable {
}
// TODO: We need a better way to get data out of keyframes.
if (mKeyframes instanceof PathKeyframes.FloatKeyframesBase
- || mKeyframes instanceof PathKeyframes.IntKeyframesBase) {
- // property values will animate based on external data source (e.g. Path)
+ || mKeyframes instanceof PathKeyframes.IntKeyframesBase
+ || (mKeyframes.getKeyframes() != null && mKeyframes.getKeyframes().size() > 2)) {
+ // When a pvh has more than 2 keyframes, that means there are intermediate values in
+ // addition to start/end values defined for animators. Another case where such
+ // intermediate values are defined is when animator has a path to animate along. In
+ // these cases, a data source is needed to capture these intermediate values.
values.dataSource = new PropertyValues.DataSource() {
@Override
public Object getValueAtFraction(float fraction) {
@@ -1108,6 +1112,13 @@ public class PropertyValuesHolder implements Cloneable {
}
}
+ /**
+ * @hide
+ */
+ public Class getValueType() {
+ return mValueType;
+ }
+
@Override
public String toString() {
return mPropertyName + ": " + mKeyframes.toString();
@@ -1177,6 +1188,15 @@ public class PropertyValuesHolder implements Cloneable {
}
}
+ @Override
+ public void setProperty(Property property) {
+ if (property instanceof IntProperty) {
+ mIntProperty = (IntProperty) property;
+ } else {
+ super.setProperty(property);
+ }
+ }
+
@Override
public void setIntValues(int... values) {
super.setIntValues(values);
@@ -1315,6 +1335,15 @@ public class PropertyValuesHolder implements Cloneable {
}
}
+ @Override
+ public void setProperty(Property property) {
+ if (property instanceof FloatProperty) {
+ mFloatProperty = (FloatProperty) property;
+ } else {
+ super.setProperty(property);
+ }
+ }
+
@Override
public void setFloatValues(float... values) {
super.setFloatValues(values);
@@ -1516,7 +1545,7 @@ public class PropertyValuesHolder implements Cloneable {
}
propertyMap.put(mPropertyName, mJniSetter);
}
- }
+ }
}
}
diff --git a/core/java/android/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java
index 0c7ee2c8c2fec4453a325748e499121a0d0ab3bf..e3f8fa49f9dde472486438a967286d5ee92c68da 100644
--- a/core/java/android/animation/ValueAnimator.java
+++ b/core/java/android/animation/ValueAnimator.java
@@ -982,6 +982,7 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio
mStarted = true;
mPaused = false;
mRunning = false;
+ mAnimationEndRequested = false;
// Resets mLastFrameTime when start() is called, so that if the animation was running,
// calling start() would put the animation in the
// started-but-not-yet-reached-the-first-frame phase.
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index ae3e0ce201a4856904827f7a104dd85d3898e54d..e4880b0f6a43b817c18585a1492c23b9249b8058 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -175,11 +175,11 @@ import java.util.List;
* part of the platform's application model. For a detailed perspective on the structure of an
* Android application and how activities behave, please read the
* Application Fundamentals and
- * Tasks and Back Stack
+ * Tasks and Back Stack
* developer guides.
*
*
You can also find a detailed discussion about how to create activities in the
- * Activities
+ * Activities
* developer guide.
*
*
@@ -3366,7 +3366,7 @@ public class Activity extends ContextThemeWrapper
* should override the method {@link #onPrepareNavigateUpTaskStack(TaskStackBuilder)}
* to supply those arguments.
*
- *
*/
public abstract class FragmentTransaction {
@@ -25,17 +26,17 @@ public abstract class FragmentTransaction {
* Calls {@link #add(int, Fragment, String)} with a 0 containerViewId.
*/
public abstract FragmentTransaction add(Fragment fragment, String tag);
-
+
/**
* Calls {@link #add(int, Fragment, String)} with a null tag.
*/
public abstract FragmentTransaction add(@IdRes int containerViewId, Fragment fragment);
-
+
/**
* Add a fragment to the activity state. This fragment may optionally
* also have its view (if {@link Fragment#onCreateView Fragment.onCreateView}
* returns non-null) inserted into a container view of the activity.
- *
+ *
* @param containerViewId Optional identifier of the container this fragment is
* to be placed in. If 0, it will not be placed in a container.
* @param fragment The fragment to be added. This fragment must not already
@@ -43,64 +44,64 @@ public abstract class FragmentTransaction {
* @param tag Optional tag name for the fragment, to later retrieve the
* fragment with {@link FragmentManager#findFragmentByTag(String)
* FragmentManager.findFragmentByTag(String)}.
- *
+ *
* @return Returns the same FragmentTransaction instance.
*/
public abstract FragmentTransaction add(@IdRes int containerViewId, Fragment fragment,
String tag);
-
+
/**
* Calls {@link #replace(int, Fragment, String)} with a null tag.
*/
public abstract FragmentTransaction replace(@IdRes int containerViewId, Fragment fragment);
-
+
/**
* Replace an existing fragment that was added to a container. This is
* essentially the same as calling {@link #remove(Fragment)} for all
* currently added fragments that were added with the same containerViewId
* and then {@link #add(int, Fragment, String)} with the same arguments
* given here.
- *
+ *
* @param containerViewId Identifier of the container whose fragment(s) are
* to be replaced.
* @param fragment The new fragment to place in the container.
* @param tag Optional tag name for the fragment, to later retrieve the
* fragment with {@link FragmentManager#findFragmentByTag(String)
* FragmentManager.findFragmentByTag(String)}.
- *
+ *
* @return Returns the same FragmentTransaction instance.
*/
public abstract FragmentTransaction replace(@IdRes int containerViewId, Fragment fragment,
String tag);
-
+
/**
* Remove an existing fragment. If it was added to a container, its view
* is also removed from that container.
- *
+ *
* @param fragment The fragment to be removed.
- *
+ *
* @return Returns the same FragmentTransaction instance.
*/
public abstract FragmentTransaction remove(Fragment fragment);
-
+
/**
* Hides an existing fragment. This is only relevant for fragments whose
* views have been added to a container, as this will cause the view to
* be hidden.
- *
+ *
* @param fragment The fragment to be hidden.
- *
+ *
* @return Returns the same FragmentTransaction instance.
*/
public abstract FragmentTransaction hide(Fragment fragment);
-
+
/**
* Shows a previously hidden fragment. This is only relevant for fragments whose
* views have been added to a container, as this will cause the view to
* be shown.
- *
+ *
* @param fragment The fragment to be shown.
- *
+ *
* @return Returns the same FragmentTransaction instance.
*/
public abstract FragmentTransaction show(Fragment fragment);
@@ -135,17 +136,17 @@ public abstract class FragmentTransaction {
* false otherwise.
*/
public abstract boolean isEmpty();
-
+
/**
* Bit mask that is set for all enter transitions.
*/
public static final int TRANSIT_ENTER_MASK = 0x1000;
-
+
/**
* Bit mask that is set for all exit transitions.
*/
public static final int TRANSIT_EXIT_MASK = 0x2000;
-
+
/** Not set up for a transition. */
public static final int TRANSIT_UNSET = -1;
/** No animation for transition. */
@@ -202,7 +203,7 @@ public abstract class FragmentTransaction {
* animations.
*/
public abstract FragmentTransaction setTransitionStyle(@StyleRes int styleRes);
-
+
/**
* Add this transaction to the back stack. This means that the transaction
* will be remembered after it is committed, and will reverse its operation
@@ -269,7 +270,7 @@ public abstract class FragmentTransaction {
* because the state after the commit can be lost if the activity needs to
* be restored from its state. See {@link #commitAllowingStateLoss()} for
* situations where it may be okay to lose the commit.
- *
+ *
* @return Returns the identifier of this transaction's back stack entry,
* if {@link #addToBackStack(String)} had been called. Otherwise, returns
* a negative number.
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 80ba3eb02233e78c2f9bc8cd4b840a2a1512c2f5..e411e03a8a949da41a83c5ec6fe17f96836d64de 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -512,7 +512,8 @@ public interface IActivityManager extends IInterface {
public int getLaunchedFromUid(IBinder activityToken) throws RemoteException;
public String getLaunchedFromPackage(IBinder activityToken) throws RemoteException;
- public void registerUserSwitchObserver(IUserSwitchObserver observer) throws RemoteException;
+ public void registerUserSwitchObserver(IUserSwitchObserver observer,
+ String name) throws RemoteException;
public void unregisterUserSwitchObserver(IUserSwitchObserver observer) throws RemoteException;
public void requestBugReport(int bugreportType) throws RemoteException;
@@ -657,6 +658,19 @@ public interface IActivityManager extends IInterface {
IIntentReceiver finishedReceiver, String requiredPermission, Bundle options)
throws RemoteException;
+ public void setVrThread(int tid) throws RemoteException;
+ public void setRenderThread(int tid) throws RemoteException;
+
+ /**
+ * Lets activity manager know whether the calling process is currently showing "top-level" UI
+ * that is not an activity, i.e. windows on the screen the user is currently interacting with.
+ *
+ *
This flag can only be set for persistent processes.
+ *
+ * @param hasTopUi Whether the calling process has "top-level" UI.
+ */
+ public void setHasTopUi(boolean hasTopUi) throws RemoteException;
+
/*
* Private non-Binder interfaces
*/
@@ -1043,4 +1057,9 @@ public interface IActivityManager extends IInterface {
int START_CONFIRM_DEVICE_CREDENTIAL_INTENT = IBinder.FIRST_CALL_TRANSACTION + 374;
int SEND_IDLE_JOB_TRIGGER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 375;
int SEND_INTENT_SENDER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 376;
+
+ // Start of N MR1 transactions
+ int SET_VR_THREAD_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 377;
+ int SET_RENDER_THREAD_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 378;
+ int SET_HAS_TOP_UI = IBinder.FIRST_CALL_TRANSACTION + 379;
}
diff --git a/core/java/com/android/internal/app/IEphemeralResolver.aidl b/core/java/android/app/IEphemeralResolver.aidl
similarity index 88%
rename from core/java/com/android/internal/app/IEphemeralResolver.aidl
rename to core/java/android/app/IEphemeralResolver.aidl
index 40429ee2cccbf725bf46921180f669c61249205d..ee869eaa79365190e61be012a34f4d25438b2b1f 100644
--- a/core/java/com/android/internal/app/IEphemeralResolver.aidl
+++ b/core/java/android/app/IEphemeralResolver.aidl
@@ -14,11 +14,12 @@
* limitations under the License.
*/
-package com.android.internal.app;
+package android.app;
-import android.content.Intent;
import android.os.IRemoteCallback;
+/** @hide */
oneway interface IEphemeralResolver {
- void getEphemeralResolveInfoList(IRemoteCallback callback, int digestPrefix, int sequence);
+ void getEphemeralResolveInfoList(IRemoteCallback callback, in int[] digestPrefix,
+ int prefixMask, int sequence);
}
diff --git a/core/java/android/app/IWallpaperManager.aidl b/core/java/android/app/IWallpaperManager.aidl
index a0762b94a040144d89e0226837c9ef10c1dd71a7..75a5bf7f77a2201df48b6999de45e0be22109173 100644
--- a/core/java/android/app/IWallpaperManager.aidl
+++ b/core/java/android/app/IWallpaperManager.aidl
@@ -44,12 +44,12 @@ interface IWallpaperManager {
*/
ParcelFileDescriptor setWallpaper(String name, in String callingPackage,
in Rect cropHint, boolean allowBackup, out Bundle extras, int which,
- IWallpaperManagerCallback completion);
+ IWallpaperManagerCallback completion, int userId);
/**
* Set the live wallpaper. This only affects the system wallpaper.
*/
- void setWallpaperComponentChecked(in ComponentName name, in String callingPackage);
+ void setWallpaperComponentChecked(in ComponentName name, in String callingPackage, int userId);
/**
* Set the live wallpaper. This only affects the system wallpaper.
@@ -72,7 +72,7 @@ interface IWallpaperManager {
* information about that wallpaper. Otherwise, if it is a static image,
* simply return null.
*/
- WallpaperInfo getWallpaperInfo();
+ WallpaperInfo getWallpaperInfo(int userId);
/**
* Clear the system wallpaper.
@@ -128,7 +128,7 @@ interface IWallpaperManager {
/*
* Backup: is the current system wallpaper image eligible for off-device backup?
*/
- boolean isWallpaperBackupEligible(int userId);
+ boolean isWallpaperBackupEligible(int which, int userId);
/*
* Keyguard: register a callback for being notified that lock-state relevant
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index 0745f16135e944d506b3fb673924f3335d669630..7ef84f45252de6380624023de10f3989f7b10bd2 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -1396,18 +1396,6 @@ public final class LoadedApk {
}
public void death(ComponentName name, IBinder service) {
- ServiceDispatcher.ConnectionInfo old;
-
- synchronized (this) {
- old = mActiveConnections.remove(name);
- if (old == null || old.binder != service) {
- // Death for someone different than who we last
- // reported... just ignore it.
- return;
- }
- old.binder.unlinkToDeath(old.deathMonitor, 0);
- }
-
if (mActivityThread != null) {
mActivityThread.post(new RunConnection(name, service, 1));
} else {
@@ -1456,7 +1444,7 @@ public final class LoadedApk {
}
}
- // If there was an old service, it is not disconnected.
+ // If there was an old service, it is now disconnected.
if (old != null) {
mConnection.onServiceDisconnected(name);
}
@@ -1467,6 +1455,17 @@ public final class LoadedApk {
}
public void doDeath(ComponentName name, IBinder service) {
+ synchronized (this) {
+ ConnectionInfo old = mActiveConnections.get(name);
+ if (old == null || old.binder != service) {
+ // Death for someone different than who we last
+ // reported... just ignore it.
+ return;
+ }
+ mActiveConnections.remove(name);
+ old.binder.unlinkToDeath(old.deathMonitor, 0);
+ }
+
mConnection.onServiceDisconnected(name);
}
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 1c2a6aecca24e3780012fcb872d2e6f0f7e24e0f..7c28664b386d2a390d5f987b6d03a888a2300449 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -39,7 +39,6 @@ import android.media.AudioManager;
import android.media.session.MediaSession;
import android.net.Uri;
import android.os.BadParcelableException;
-import android.os.BaseBundle;
import android.os.Build;
import android.os.Bundle;
import android.os.Parcel;
@@ -51,7 +50,9 @@ import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.TextUtils;
import android.text.style.AbsoluteSizeSpan;
+import android.text.style.BackgroundColorSpan;
import android.text.style.CharacterStyle;
+import android.text.style.ForegroundColorSpan;
import android.text.style.RelativeSizeSpan;
import android.text.style.TextAppearanceSpan;
import android.util.ArraySet;
@@ -73,7 +74,6 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Set;
@@ -1314,6 +1314,7 @@ public class Notification implements Parcelable
// Flags bitwise-ored to mFlags
private static final int FLAG_AVAILABLE_OFFLINE = 0x1;
private static final int FLAG_HINT_LAUNCHES_ACTIVITY = 1 << 1;
+ private static final int FLAG_HINT_DISPLAY_INLINE = 1 << 2;
// Default value for flags integer
private static final int DEFAULT_FLAGS = FLAG_AVAILABLE_OFFLINE;
@@ -1500,6 +1501,29 @@ public class Notification implements Parcelable
public boolean getHintLaunchesActivity() {
return (mFlags & FLAG_HINT_LAUNCHES_ACTIVITY) != 0;
}
+
+ /**
+ * Set a hint that this Action should be displayed inline.
+ *
+ * @param hintDisplayInline {@code true} if action should be displayed inline, false
+ * otherwise
+ * @return this object for method chaining
+ */
+ public WearableExtender setHintDisplayActionInline(
+ boolean hintDisplayInline) {
+ setFlag(FLAG_HINT_DISPLAY_INLINE, hintDisplayInline);
+ return this;
+ }
+
+ /**
+ * Get a hint that this Action should be displayed inline.
+ *
+ * @return {@code true} if the Action should be displayed inline, {@code false}
+ * otherwise. The default value is {@code false} if this was never set.
+ */
+ public boolean getHintDisplayActionInline() {
+ return (mFlags & FLAG_HINT_DISPLAY_INLINE) != 0;
+ }
}
}
@@ -3239,7 +3263,8 @@ public class Notification implements Parcelable
* Resets the notification header to its original state
*/
private void resetNotificationHeader(RemoteViews contentView) {
- contentView.setImageViewResource(R.id.icon, 0);
+ // Small icon doesn't need to be reset, as it's always set. Resetting would prevent
+ // re-using the drawable when the notification is updated.
contentView.setBoolean(R.id.notification_header, "setExpanded", false);
contentView.setTextViewText(R.id.app_name_text, null);
contentView.setViewVisibility(R.id.chronometer, View.GONE);
@@ -3457,6 +3482,8 @@ public class Notification implements Parcelable
mN.mSmallIcon = Icon.createWithResource(mContext, mN.icon);
}
contentView.setImageViewIcon(R.id.icon, mN.mSmallIcon);
+ contentView.setDrawableParameters(R.id.icon, false /* targetBackground */,
+ -1 /* alpha */, -1 /* colorFilter */, null /* mode */, mN.iconLevel);
processSmallIconColor(mN.mSmallIcon, contentView);
}
@@ -3502,6 +3529,8 @@ public class Notification implements Parcelable
boolean validRemoteInput = false;
int N = mActions.size();
+ boolean emphazisedMode = mN.fullScreenIntent != null;
+ big.setBoolean(R.id.actions, "setEmphasizedMode", emphazisedMode);
if (N > 0) {
big.setViewVisibility(R.id.actions_container, View.VISIBLE);
big.setViewVisibility(R.id.actions, View.VISIBLE);
@@ -3512,7 +3541,8 @@ public class Notification implements Parcelable
Action action = mActions.get(i);
validRemoteInput |= hasValidRemoteInput(action);
- final RemoteViews button = generateActionButton(action);
+ final RemoteViews button = generateActionButton(action, emphazisedMode,
+ i % 2 != 0);
big.addView(R.id.actions, button);
}
} else {
@@ -3677,13 +3707,13 @@ public class Notification implements Parcelable
- private RemoteViews generateActionButton(Action action) {
+ private RemoteViews generateActionButton(Action action, boolean emphazisedMode,
+ boolean oddAction) {
final boolean tombstone = (action.actionIntent == null);
RemoteViews button = new BuilderRemoteViews(mContext.getApplicationInfo(),
- tombstone ? getActionTombstoneLayoutResource()
- : getActionLayoutResource());
- final Icon ai = action.getIcon();
- button.setTextViewText(R.id.action0, processLegacyText(action.title));
+ emphazisedMode ? getEmphasizedActionLayoutResource()
+ : tombstone ? getActionTombstoneLayoutResource()
+ : getActionLayoutResource());
if (!tombstone) {
button.setOnClickPendingIntent(R.id.action0, action.actionIntent);
}
@@ -3691,12 +3721,143 @@ public class Notification implements Parcelable
if (action.mRemoteInputs != null) {
button.setRemoteInputs(R.id.action0, action.mRemoteInputs);
}
- if (mN.color != COLOR_DEFAULT) {
- button.setTextColor(R.id.action0, resolveContrastColor());
+ if (emphazisedMode) {
+ // change the background bgColor
+ int bgColor = mContext.getColor(oddAction ? R.color.notification_action_list
+ : R.color.notification_action_list_dark);
+ button.setDrawableParameters(R.id.button_holder, true, -1, bgColor,
+ PorterDuff.Mode.SRC_ATOP, -1);
+ CharSequence title = action.title;
+ ColorStateList[] outResultColor = null;
+ if (isLegacy()) {
+ title = clearColorSpans(title);
+ } else {
+ outResultColor = new ColorStateList[1];
+ title = ensureColorSpanContrast(title, bgColor, outResultColor);
+ }
+ button.setTextViewText(R.id.action0, title);
+ if (outResultColor != null && outResultColor[0] != null) {
+ // We need to set the text color as well since changing a text to uppercase
+ // clears its spans.
+ button.setTextColor(R.id.action0, outResultColor[0]);
+ } else if (mN.color != COLOR_DEFAULT) {
+ button.setTextColor(R.id.action0,resolveContrastColor());
+ }
+ } else {
+ button.setTextViewText(R.id.action0, processLegacyText(action.title));
+ if (mN.color != COLOR_DEFAULT) {
+ button.setTextColor(R.id.action0, resolveContrastColor());
+ }
}
return button;
}
+ /**
+ * Clears all color spans of a text
+ * @param charSequence the input text
+ * @return the same text but without color spans
+ */
+ private CharSequence clearColorSpans(CharSequence charSequence) {
+ if (charSequence instanceof Spanned) {
+ Spanned ss = (Spanned) charSequence;
+ Object[] spans = ss.getSpans(0, ss.length(), Object.class);
+ SpannableStringBuilder builder = new SpannableStringBuilder(ss.toString());
+ for (Object span : spans) {
+ Object resultSpan = span;
+ if (resultSpan instanceof CharacterStyle) {
+ resultSpan = ((CharacterStyle) span).getUnderlying();
+ }
+ if (resultSpan instanceof TextAppearanceSpan) {
+ TextAppearanceSpan originalSpan = (TextAppearanceSpan) resultSpan;
+ if (originalSpan.getTextColor() != null) {
+ resultSpan = new TextAppearanceSpan(
+ originalSpan.getFamily(),
+ originalSpan.getTextStyle(),
+ originalSpan.getTextSize(),
+ null,
+ originalSpan.getLinkTextColor());
+ }
+ } else if (resultSpan instanceof ForegroundColorSpan
+ || (resultSpan instanceof BackgroundColorSpan)) {
+ continue;
+ } else {
+ resultSpan = span;
+ }
+ builder.setSpan(resultSpan, ss.getSpanStart(span), ss.getSpanEnd(span),
+ ss.getSpanFlags(span));
+ }
+ return builder;
+ }
+ return charSequence;
+ }
+
+ /**
+ * Ensures contrast on color spans against a background color. also returns the color of the
+ * text if a span was found that spans over the whole text.
+ *
+ * @param charSequence the charSequence on which the spans are
+ * @param background the background color to ensure the contrast against
+ * @param outResultColor an array in which a color will be returned as the first element if
+ * there exists a full length color span.
+ * @return the contrasted charSequence
+ */
+ private CharSequence ensureColorSpanContrast(CharSequence charSequence, int background,
+ ColorStateList[] outResultColor) {
+ if (charSequence instanceof Spanned) {
+ Spanned ss = (Spanned) charSequence;
+ Object[] spans = ss.getSpans(0, ss.length(), Object.class);
+ SpannableStringBuilder builder = new SpannableStringBuilder(ss.toString());
+ for (Object span : spans) {
+ Object resultSpan = span;
+ int spanStart = ss.getSpanStart(span);
+ int spanEnd = ss.getSpanEnd(span);
+ boolean fullLength = (spanEnd - spanStart) == charSequence.length();
+ if (resultSpan instanceof CharacterStyle) {
+ resultSpan = ((CharacterStyle) span).getUnderlying();
+ }
+ if (resultSpan instanceof TextAppearanceSpan) {
+ TextAppearanceSpan originalSpan = (TextAppearanceSpan) resultSpan;
+ ColorStateList textColor = originalSpan.getTextColor();
+ if (textColor != null) {
+ int[] colors = textColor.getColors();
+ int[] newColors = new int[colors.length];
+ for (int i = 0; i < newColors.length; i++) {
+ newColors[i] = NotificationColorUtil.ensureLargeTextContrast(
+ colors[i], background);
+ }
+ textColor = new ColorStateList(textColor.getStates().clone(),
+ newColors);
+ resultSpan = new TextAppearanceSpan(
+ originalSpan.getFamily(),
+ originalSpan.getTextStyle(),
+ originalSpan.getTextSize(),
+ textColor,
+ originalSpan.getLinkTextColor());
+ if (fullLength) {
+ outResultColor[0] = new ColorStateList(
+ textColor.getStates().clone(), newColors);
+ }
+ }
+ } else if (resultSpan instanceof ForegroundColorSpan) {
+ ForegroundColorSpan originalSpan = (ForegroundColorSpan) resultSpan;
+ int foregroundColor = originalSpan.getForegroundColor();
+ foregroundColor = NotificationColorUtil.ensureLargeTextContrast(
+ foregroundColor, background);
+ resultSpan = new ForegroundColorSpan(foregroundColor);
+ if (fullLength) {
+ outResultColor[0] = ColorStateList.valueOf(foregroundColor);
+ }
+ } else {
+ resultSpan = span;
+ }
+
+ builder.setSpan(resultSpan, spanStart, spanEnd, ss.getSpanFlags(span));
+ }
+ return builder;
+ }
+ return charSequence;
+ }
+
/**
* @return Whether we are currently building a notification from a legacy (an app that
* doesn't create material notifications by itself) app.
@@ -3962,6 +4123,10 @@ public class Notification implements Parcelable
return R.layout.notification_material_action;
}
+ private int getEmphasizedActionLayoutResource() {
+ return R.layout.notification_material_action_emphasized;
+ }
+
private int getActionTombstoneLayoutResource() {
return R.layout.notification_material_action_tombstone;
}
@@ -4267,9 +4432,15 @@ public class Notification implements Parcelable
// mN.mLargeIcon
// 2. !mBigLargeIconSet -> mN.mLargeIcon applies
Icon oldLargeIcon = null;
+ Bitmap largeIconLegacy = null;
if (mBigLargeIconSet) {
oldLargeIcon = mBuilder.mN.mLargeIcon;
mBuilder.mN.mLargeIcon = mBigLargeIcon;
+ // The legacy largeIcon might not allow us to clear the image, as it's taken in
+ // replacement if the other one is null. Because we're restoring these legacy icons
+ // for old listeners, this is in general non-null.
+ largeIconLegacy = mBuilder.mN.largeIcon;
+ mBuilder.mN.largeIcon = null;
}
RemoteViews contentView = getStandardView(mBuilder.getBigPictureLayoutResource());
@@ -4281,6 +4452,7 @@ public class Notification implements Parcelable
if (mBigLargeIconSet) {
mBuilder.mN.mLargeIcon = oldLargeIcon;
+ mBuilder.mN.largeIcon = largeIconLegacy;
}
contentView.setImageViewBitmap(R.id.big_picture, mPicture);
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index 18b72e29e0e610253a00c6a73269674f5e222bcf..ff514bd7c81b7792a8b0e5aade2c8376f1a20666 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -312,8 +312,8 @@ public class NotificationManager
try {
service.enqueueNotificationWithTag(pkg, mContext.getOpPackageName(), tag, id,
copy, idOut, user.getIdentifier());
- if (id != idOut[0]) {
- Log.w(TAG, "notify: id corrupted: sent " + id + ", got back " + idOut[0]);
+ if (localLOGV && id != idOut[0]) {
+ Log.v(TAG, "notify: id corrupted: sent " + id + ", got back " + idOut[0]);
}
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java
index c4673a3b0b4cd3c10e65af7286eaa25a19ee943f..d2e032721022b774766016b14901be03e9a93d14 100644
--- a/core/java/android/app/ResourcesManager.java
+++ b/core/java/android/app/ResourcesManager.java
@@ -242,7 +242,7 @@ public class ResourcesManager {
* @return a new AssetManager.
*/
@VisibleForTesting
- protected @NonNull AssetManager createAssetManager(@NonNull final ResourcesKey key) {
+ protected @Nullable AssetManager createAssetManager(@NonNull final ResourcesKey key) {
AssetManager assets = new AssetManager();
// resDir can be null if the 'android' package is creating a new Resources object.
@@ -250,15 +250,16 @@ public class ResourcesManager {
// already.
if (key.mResDir != null) {
if (assets.addAssetPath(key.mResDir) == 0) {
- throw new Resources.NotFoundException("failed to add asset path " + key.mResDir);
+ Log.e(TAG, "failed to add asset path " + key.mResDir);
+ return null;
}
}
if (key.mSplitResDirs != null) {
for (final String splitResDir : key.mSplitResDirs) {
if (assets.addAssetPath(splitResDir) == 0) {
- throw new Resources.NotFoundException(
- "failed to add split asset path " + splitResDir);
+ Log.e(TAG, "failed to add split asset path " + splitResDir);
+ return null;
}
}
}
@@ -303,11 +304,15 @@ public class ResourcesManager {
return config;
}
- private @NonNull ResourcesImpl createResourcesImpl(@NonNull ResourcesKey key) {
+ private @Nullable ResourcesImpl createResourcesImpl(@NonNull ResourcesKey key) {
final DisplayAdjustments daj = new DisplayAdjustments(key.mOverrideConfiguration);
daj.setCompatibilityInfo(key.mCompatInfo);
final AssetManager assets = createAssetManager(key);
+ if (assets == null) {
+ return null;
+ }
+
final DisplayMetrics dm = getDisplayMetrics(key.mDisplayId, daj);
final Configuration config = generateConfig(key, dm);
final ResourcesImpl impl = new ResourcesImpl(assets, dm, config, daj);
@@ -323,7 +328,7 @@ public class ResourcesManager {
* @param key The key to match.
* @return a ResourcesImpl if the key matches a cache entry, null otherwise.
*/
- private ResourcesImpl findResourcesImplForKeyLocked(@NonNull ResourcesKey key) {
+ private @Nullable ResourcesImpl findResourcesImplForKeyLocked(@NonNull ResourcesKey key) {
WeakReference weakImplRef = mResourceImpls.get(key);
ResourcesImpl impl = weakImplRef != null ? weakImplRef.get() : null;
if (impl != null && impl.getAssets().isUpToDate()) {
@@ -338,12 +343,14 @@ public class ResourcesManager {
* @param key The key to match.
* @return a ResourcesImpl object matching the key.
*/
- private @NonNull ResourcesImpl findOrCreateResourcesImplForKeyLocked(
+ private @Nullable ResourcesImpl findOrCreateResourcesImplForKeyLocked(
@NonNull ResourcesKey key) {
ResourcesImpl impl = findResourcesImplForKeyLocked(key);
if (impl == null) {
impl = createResourcesImpl(key);
- mResourceImpls.put(key, new WeakReference<>(impl));
+ if (impl != null) {
+ mResourceImpls.put(key, new WeakReference<>(impl));
+ }
}
return impl;
}
@@ -352,7 +359,8 @@ public class ResourcesManager {
* Find the ResourcesKey that this ResourcesImpl object is associated with.
* @return the ResourcesKey or null if none was found.
*/
- private ResourcesKey findKeyForResourceImplLocked(@NonNull ResourcesImpl resourceImpl) {
+ private @Nullable ResourcesKey findKeyForResourceImplLocked(
+ @NonNull ResourcesImpl resourceImpl) {
final int refCount = mResourceImpls.size();
for (int i = 0; i < refCount; i++) {
WeakReference weakImplRef = mResourceImpls.valueAt(i);
@@ -364,6 +372,26 @@ public class ResourcesManager {
return null;
}
+ /**
+ * Check if activity resources have same override config as the provided on.
+ * @param activityToken The Activity that resources should be associated with.
+ * @param overrideConfig The override configuration to be checked for equality with.
+ * @return true if activity resources override config matches the provided one or they are both
+ * null, false otherwise.
+ */
+ boolean isSameResourcesOverrideConfig(@Nullable IBinder activityToken,
+ @Nullable Configuration overrideConfig) {
+ synchronized (this) {
+ final ActivityResources activityResources
+ = activityToken != null ? mActivityResourceReferences.get(activityToken) : null;
+ if (activityResources == null) {
+ return overrideConfig == null;
+ } else {
+ return Objects.equals(activityResources.overrideConfig, overrideConfig);
+ }
+ }
+ }
+
private ActivityResources getOrCreateActivityResourcesStructLocked(
@NonNull IBinder activityToken) {
ActivityResources activityResources = mActivityResourceReferences.get(activityToken);
@@ -460,7 +488,7 @@ public class ResourcesManager {
* {@link ClassLoader#getSystemClassLoader()} is used.
* @return a Resources object from which to access resources.
*/
- public @NonNull Resources createBaseActivityResources(@NonNull IBinder activityToken,
+ public @Nullable Resources createBaseActivityResources(@NonNull IBinder activityToken,
@Nullable String resDir,
@Nullable String[] splitResDirs,
@Nullable String[] overlayDirs,
@@ -514,7 +542,7 @@ public class ResourcesManager {
* {@link #applyConfigurationToResourcesLocked(Configuration, CompatibilityInfo)}
* is called.
*/
- private @NonNull Resources getOrCreateResources(@Nullable IBinder activityToken,
+ private @Nullable Resources getOrCreateResources(@Nullable IBinder activityToken,
@NonNull ResourcesKey key, @NonNull ClassLoader classLoader) {
synchronized (this) {
if (DEBUG) {
@@ -569,6 +597,9 @@ public class ResourcesManager {
// If we're here, we didn't find a suitable ResourcesImpl to use, so create one now.
ResourcesImpl resourcesImpl = createResourcesImpl(key);
+ if (resourcesImpl == null) {
+ return null;
+ }
synchronized (this) {
ResourcesImpl existingResourcesImpl = findResourcesImplForKeyLocked(key);
@@ -622,7 +653,7 @@ public class ResourcesManager {
* {@link ClassLoader#getSystemClassLoader()} is used.
* @return a Resources object from which to access resources.
*/
- public @NonNull Resources getResources(@Nullable IBinder activityToken,
+ public @Nullable Resources getResources(@Nullable IBinder activityToken,
@Nullable String resDir,
@Nullable String[] splitResDirs,
@Nullable String[] overlayDirs,
@@ -745,10 +776,12 @@ public class ResourcesManager {
ResourcesImpl resourcesImpl = findResourcesImplForKeyLocked(newKey);
if (resourcesImpl == null) {
resourcesImpl = createResourcesImpl(newKey);
- mResourceImpls.put(newKey, new WeakReference<>(resourcesImpl));
+ if (resourcesImpl != null) {
+ mResourceImpls.put(newKey, new WeakReference<>(resourcesImpl));
+ }
}
- if (resourcesImpl != resources.getImpl()) {
+ if (resourcesImpl != null && resourcesImpl != resources.getImpl()) {
// Set the ResourcesImpl, updating it for all users of this Resources
// object.
resources.setImpl(resourcesImpl);
@@ -890,7 +923,11 @@ public class ResourcesManager {
if (r != null) {
final ResourcesKey key = updatedResourceKeys.get(r.getImpl());
if (key != null) {
- r.setImpl(findOrCreateResourcesImplForKeyLocked(key));
+ final ResourcesImpl impl = findOrCreateResourcesImplForKeyLocked(key);
+ if (impl == null) {
+ throw new Resources.NotFoundException("failed to load " + libAsset);
+ }
+ r.setImpl(impl);
}
}
}
@@ -903,7 +940,11 @@ public class ResourcesManager {
if (r != null) {
final ResourcesKey key = updatedResourceKeys.get(r.getImpl());
if (key != null) {
- r.setImpl(findOrCreateResourcesImplForKeyLocked(key));
+ final ResourcesImpl impl = findOrCreateResourcesImplForKeyLocked(key);
+ if (impl == null) {
+ throw new Resources.NotFoundException("failed to load " + libAsset);
+ }
+ r.setImpl(impl);
}
}
}
diff --git a/core/java/android/app/RetailDemoModeServiceInternal.java b/core/java/android/app/RetailDemoModeServiceInternal.java
new file mode 100644
index 0000000000000000000000000000000000000000..7ca214aae60265712129a7f5b17a84109f5bf603
--- /dev/null
+++ b/core/java/android/app/RetailDemoModeServiceInternal.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.app;
+
+/**
+ * Retail Demo Mode Service interface to be used locally inside system server
+ *
+ * @hide Only for use inside system server
+ */
+public interface RetailDemoModeServiceInternal {
+ /**
+ * Used to notify RetailDemoModeService of any user activity.
+ */
+ public void onUserActivity();
+}
\ No newline at end of file
diff --git a/core/java/android/app/TabActivity.java b/core/java/android/app/TabActivity.java
index 882e55a89a74b1e4fe029d5bc17301b63ecf4d93..637c8c19aef5eeb6ff5fb2586e6882709fe94777 100644
--- a/core/java/android/app/TabActivity.java
+++ b/core/java/android/app/TabActivity.java
@@ -28,23 +28,6 @@ import android.widget.TextView;
* {@link ActionBar#newTab() ActionBar.newTab()} and
* related APIs for placing tabs within their action bar area.
*
- *
A replacement for TabActivity can also be implemented by directly using
- * TabHost. You will need to define a layout that correctly uses a TabHost
- * with a TabWidget as well as an area in which to display your tab content.
- * A typical example would be:
The implementation needs to take over responsibility for switching
- * the shown content when the user switches between tabs.
- *
- * {@sample development/samples/Support4Demos/src/com/example/android/supportv4/app/FragmentTabs.java
- * complete}
- *
- *
Also see the
- * Fragment Tabs Pager sample for an example of using the support library's ViewPager to
- * allow the user to swipe the content to switch between tabs.
- *
* @deprecated New applications should use Fragments instead of this class;
* to continue to run on older devices, you can use the v4 support library
* which provides a version of the Fragment API that is compatible down to
diff --git a/core/java/android/app/WallpaperInfo.java b/core/java/android/app/WallpaperInfo.java
index 7db9fa8fed65993d2ea3cbf2d88f91db8b9ba430..9d40381fcefd2527c1db3c327dda1d2607380329 100644
--- a/core/java/android/app/WallpaperInfo.java
+++ b/core/java/android/app/WallpaperInfo.java
@@ -31,6 +31,7 @@ import android.content.res.Resources;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
import android.graphics.drawable.Drawable;
+import android.net.Uri;
import android.os.Parcel;
import android.os.Parcelable;
import android.service.wallpaper.WallpaperService;
@@ -72,6 +73,10 @@ public final class WallpaperInfo implements Parcelable {
*/
final int mDescriptionResource;
+ final int mContextUriResource;
+ final int mContextDescriptionResource;
+ final boolean mShowMetadataInPreview;
+
/**
* Constructor.
*
@@ -89,7 +94,10 @@ public final class WallpaperInfo implements Parcelable {
int thumbnailRes = -1;
int authorRes = -1;
int descriptionRes = -1;
-
+ int contextUriRes = -1;
+ int contextDescriptionRes = -1;
+ boolean showMetadataInPreview = false;
+
XmlResourceParser parser = null;
try {
parser = si.loadXmlMetaData(pm, WallpaperService.SERVICE_META_DATA);
@@ -127,6 +135,15 @@ public final class WallpaperInfo implements Parcelable {
descriptionRes = sa.getResourceId(
com.android.internal.R.styleable.Wallpaper_description,
-1);
+ contextUriRes = sa.getResourceId(
+ com.android.internal.R.styleable.Wallpaper_contextUri,
+ -1);
+ contextDescriptionRes = sa.getResourceId(
+ com.android.internal.R.styleable.Wallpaper_contextDescription,
+ -1);
+ showMetadataInPreview = sa.getBoolean(
+ com.android.internal.R.styleable.Wallpaper_showMetadataInPreview,
+ false);
sa.recycle();
} catch (NameNotFoundException e) {
@@ -140,6 +157,9 @@ public final class WallpaperInfo implements Parcelable {
mThumbnailResource = thumbnailRes;
mAuthorResource = authorRes;
mDescriptionResource = descriptionRes;
+ mContextUriResource = contextUriRes;
+ mContextDescriptionResource = contextDescriptionRes;
+ mShowMetadataInPreview = showMetadataInPreview;
}
WallpaperInfo(Parcel source) {
@@ -147,6 +167,9 @@ public final class WallpaperInfo implements Parcelable {
mThumbnailResource = source.readInt();
mAuthorResource = source.readInt();
mDescriptionResource = source.readInt();
+ mContextUriResource = source.readInt();
+ mContextDescriptionResource = source.readInt();
+ mShowMetadataInPreview = source.readInt() != 0;
mService = ResolveInfo.CREATOR.createFromParcel(source);
}
@@ -248,7 +271,60 @@ public final class WallpaperInfo implements Parcelable {
return pm.getText(packageName, mDescriptionResource,
mService.serviceInfo.applicationInfo);
}
-
+
+ /**
+ * Returns an URI that specifies a link for further context about this wallpaper.
+ *
+ * @param pm An instance of {@link PackageManager} to retrieve the URI.
+ * @return The URI.
+ */
+ public Uri loadContextUri(PackageManager pm) throws NotFoundException {
+ if (mContextUriResource <= 0) throw new NotFoundException();
+ String packageName = mService.resolvePackageName;
+ ApplicationInfo applicationInfo = null;
+ if (packageName == null) {
+ packageName = mService.serviceInfo.packageName;
+ applicationInfo = mService.serviceInfo.applicationInfo;
+ }
+ String contextUriString = pm.getText(
+ packageName, mContextUriResource, applicationInfo).toString();
+ if (contextUriString == null) {
+ return null;
+ }
+ return Uri.parse(contextUriString);
+ }
+
+ /**
+ * Retrieves a title of the URI that specifies a link for further context about this wallpaper.
+ *
+ * @param pm An instance of {@link PackageManager} to retrieve the title.
+ * @return The title.
+ */
+ public CharSequence loadContextDescription(PackageManager pm) throws NotFoundException {
+ if (mContextDescriptionResource <= 0) throw new NotFoundException();
+ String packageName = mService.resolvePackageName;
+ ApplicationInfo applicationInfo = null;
+ if (packageName == null) {
+ packageName = mService.serviceInfo.packageName;
+ applicationInfo = mService.serviceInfo.applicationInfo;
+ }
+ return pm.getText(packageName, mContextDescriptionResource, applicationInfo).toString();
+ }
+
+ /**
+ * Queries whether any metadata should be shown when previewing the wallpaper. If this value is
+ * set to true, any component that shows a preview of this live wallpaper should also show
+ * accompanying information like {@link #loadLabel},
+ * {@link #loadDescription}, {@link #loadAuthor} and
+ * {@link #loadContextDescription(PackageManager)}, so the user gets to know further information
+ * about this wallpaper.
+ *
+ * @return Whether any metadata should be shown when previewing the wallpaper.
+ */
+ public boolean getShowMetadataInPreview() {
+ return mShowMetadataInPreview;
+ }
+
/**
* Return the class name of an activity that provides a settings UI for
* the wallpaper. You can launch this activity be starting it with
@@ -287,6 +363,9 @@ public final class WallpaperInfo implements Parcelable {
dest.writeInt(mThumbnailResource);
dest.writeInt(mAuthorResource);
dest.writeInt(mDescriptionResource);
+ dest.writeInt(mContextUriResource);
+ dest.writeInt(mContextDescriptionResource);
+ dest.writeInt(mShowMetadataInPreview ? 1 : 0);
mService.writeToParcel(dest, flags);
}
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index 7f467f0585c8faf8671ce84d5bc0246b928c8066..219afea02c48d6f30811e293df8b6a1b1eb5f07c 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -48,9 +48,11 @@ import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.ParcelFileDescriptor;
+import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemProperties;
+import android.os.UserHandle;
import android.text.TextUtils;
import android.util.Log;
import android.view.WindowManagerGlobal;
@@ -265,7 +267,7 @@ public class WallpaperManager {
}
static class Globals extends IWallpaperManagerCallback.Stub {
- private IWallpaperManager mService;
+ private final IWallpaperManager mService;
private Bitmap mCachedWallpaper;
private int mCachedWallpaperUserId;
private Bitmap mDefaultWallpaper;
@@ -292,16 +294,16 @@ public class WallpaperManager {
public Bitmap peekWallpaperBitmap(Context context, boolean returnDefault,
@SetWallpaperFlags int which, int userId) {
- synchronized (this) {
- if (mService != null) {
- try {
- if (!mService.isWallpaperSupported(context.getOpPackageName())) {
- return null;
- }
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
+ if (mService != null) {
+ try {
+ if (!mService.isWallpaperSupported(context.getOpPackageName())) {
+ return null;
}
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
+ }
+ synchronized (this) {
if (mCachedWallpaper != null && mCachedWallpaperUserId == userId) {
return mCachedWallpaper;
}
@@ -316,17 +318,21 @@ public class WallpaperManager {
if (mCachedWallpaper != null) {
return mCachedWallpaper;
}
- if (returnDefault) {
- if (mDefaultWallpaper == null) {
- mDefaultWallpaper = getDefaultWallpaperLocked(context, which);
+ }
+ if (returnDefault) {
+ Bitmap defaultWallpaper = mDefaultWallpaper;
+ if (defaultWallpaper == null) {
+ defaultWallpaper = getDefaultWallpaper(context, which);
+ synchronized (this) {
+ mDefaultWallpaper = defaultWallpaper;
}
- return mDefaultWallpaper;
}
- return null;
+ return defaultWallpaper;
}
+ return null;
}
- public void forgetLoadedWallpaper() {
+ void forgetLoadedWallpaper() {
synchronized (this) {
mCachedWallpaper = null;
mCachedWallpaperUserId = 0;
@@ -361,7 +367,7 @@ public class WallpaperManager {
return null;
}
- private Bitmap getDefaultWallpaperLocked(Context context, @SetWallpaperFlags int which) {
+ private Bitmap getDefaultWallpaper(Context context, @SetWallpaperFlags int which) {
InputStream is = openDefaultWallpaper(context, which);
if (is != null) {
try {
@@ -412,8 +418,14 @@ public class WallpaperManager {
* This is returned as an
* abstract Drawable that you can install in a View to display whatever
* wallpaper the user has currently set.
- *
- * @return Returns a Drawable object that will draw the wallpaper.
+ *
+ * This method can return null if there is no system wallpaper available, if
+ * wallpapers are not supported in the current user, or if the calling app is not
+ * permitted to access the system wallpaper.
+ *
+ * @return Returns a Drawable object that will draw the system wallpaper,
+ * or {@code null} if no system wallpaper exists or if the calling application
+ * is not able to access the wallpaper.
*/
public Drawable getDrawable() {
Bitmap bm = sGlobals.peekWallpaperBitmap(mContext, true, FLAG_SYSTEM);
@@ -783,7 +795,7 @@ public class WallpaperManager {
Log.w(TAG, "WallpaperService not running");
throw new RuntimeException(new DeadSystemException());
} else {
- return sGlobals.mService.getWallpaperInfo();
+ return sGlobals.mService.getWallpaperInfo(UserHandle.myUserId());
}
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -928,7 +940,8 @@ public class WallpaperManager {
/* Set the wallpaper to the default values */
ParcelFileDescriptor fd = sGlobals.mService.setWallpaper(
"res:" + resources.getResourceName(resid),
- mContext.getOpPackageName(), null, false, result, which, completion);
+ mContext.getOpPackageName(), null, false, result, which, completion,
+ UserHandle.myUserId());
if (fd != null) {
FileOutputStream fos = null;
boolean ok = false;
@@ -1029,6 +1042,19 @@ public class WallpaperManager {
public int setBitmap(Bitmap fullImage, Rect visibleCropHint,
boolean allowBackup, @SetWallpaperFlags int which)
throws IOException {
+ return setBitmap(fullImage, visibleCropHint, allowBackup, which,
+ UserHandle.myUserId());
+ }
+
+ /**
+ * Like {@link #setBitmap(Bitmap, Rect, boolean, int)}, but allows to pass in an explicit user
+ * id. If the user id doesn't match the user id the process is running under, calling this
+ * requires permission {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL}.
+ * @hide
+ */
+ public int setBitmap(Bitmap fullImage, Rect visibleCropHint,
+ boolean allowBackup, @SetWallpaperFlags int which, int userId)
+ throws IOException {
validateRect(visibleCropHint);
if (sGlobals.mService == null) {
Log.w(TAG, "WallpaperService not running");
@@ -1039,7 +1065,7 @@ public class WallpaperManager {
try {
ParcelFileDescriptor fd = sGlobals.mService.setWallpaper(null,
mContext.getOpPackageName(), visibleCropHint, allowBackup,
- result, which, completion);
+ result, which, completion, userId);
if (fd != null) {
FileOutputStream fos = null;
try {
@@ -1165,7 +1191,7 @@ public class WallpaperManager {
try {
ParcelFileDescriptor fd = sGlobals.mService.setWallpaper(null,
mContext.getOpPackageName(), visibleCropHint, allowBackup,
- result, which, completion);
+ result, which, completion, UserHandle.myUserId());
if (fd != null) {
FileOutputStream fos = null;
try {
@@ -1399,12 +1425,26 @@ public class WallpaperManager {
*/
@SystemApi
public boolean setWallpaperComponent(ComponentName name) {
+ return setWallpaperComponent(name, UserHandle.myUserId());
+ }
+
+ /**
+ * Set the live wallpaper.
+ *
+ * This can only be called by packages with android.permission.SET_WALLPAPER_COMPONENT
+ * permission. The caller must hold the INTERACT_ACROSS_USERS_FULL permission to change
+ * another user's wallpaper.
+ *
+ * @hide
+ */
+ public boolean setWallpaperComponent(ComponentName name, int userId) {
if (sGlobals.mService == null) {
Log.w(TAG, "WallpaperService not running");
throw new RuntimeException(new DeadSystemException());
}
try {
- sGlobals.mService.setWallpaperComponentChecked(name, mContext.getOpPackageName());
+ sGlobals.mService.setWallpaperComponentChecked(name, mContext.getOpPackageName(),
+ userId);
return true;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -1655,13 +1695,13 @@ public class WallpaperManager {
* Only the OS itself may use this method.
* @hide
*/
- public boolean isWallpaperBackupEligible() {
+ public boolean isWallpaperBackupEligible(int which) {
if (sGlobals.mService == null) {
Log.w(TAG, "WallpaperService not running");
throw new RuntimeException(new DeadSystemException());
}
try {
- return sGlobals.mService.isWallpaperBackupEligible(mContext.getUserId());
+ return sGlobals.mService.isWallpaperBackupEligible(which, mContext.getUserId());
} catch (RemoteException e) {
Log.e(TAG, "Exception querying wallpaper backup eligibility: " + e.getMessage());
}
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 269037698408cf2be0568471d5ab5f4cb32d436d..46a5a8c73a19faa7dadf1c8834fa02253ee1cccf 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -1315,7 +1315,7 @@ public class DevicePolicyManager {
/**
* Retrieve the current minimum password quality for a particular admin or all admins that set
- * retrictions on this user and its participating profiles. Restrictions on profiles that have
+ * restrictions on this user and its participating profiles. Restrictions on profiles that have
* a separate challenge are not taken into account.
*
*
This method can be called on the {@link DevicePolicyManager} instance
@@ -1379,7 +1379,7 @@ public class DevicePolicyManager {
/**
* Retrieve the current minimum password length for a particular admin or all admins that set
- * retrictions on this user and its participating profiles. Restrictions on profiles that have
+ * restrictions on this user and its participating profiles. Restrictions on profiles that have
* a separate challenge are not taken into account.
*
*
This method can be called on the {@link DevicePolicyManager} instance
@@ -1442,7 +1442,7 @@ public class DevicePolicyManager {
/**
* Retrieve the current number of upper case letters required in the password
- * for a particular admin or all admins that set retrictions on this user and
+ * for a particular admin or all admins that set restrictions on this user and
* its participating profiles. Restrictions on profiles that have a separate challenge
* are not taken into account.
* This is the same value as set by
@@ -1511,7 +1511,7 @@ public class DevicePolicyManager {
/**
* Retrieve the current number of lower case letters required in the password
- * for a particular admin or all admins that set retrictions on this user
+ * for a particular admin or all admins that set restrictions on this user
* and its participating profiles. Restrictions on profiles that have
* a separate challenge are not taken into account.
* This is the same value as set by
@@ -1580,7 +1580,7 @@ public class DevicePolicyManager {
/**
* Retrieve the current number of letters required in the password
- * for a particular admin or all admins that set retrictions on this user
+ * for a particular admin or all admins that set restrictions on this user
* and its participating profiles. Restrictions on profiles that have
* a separate challenge are not taken into account.
* This is the same value as set by
@@ -1648,7 +1648,7 @@ public class DevicePolicyManager {
/**
* Retrieve the current number of numerical digits required in the password
- * for a particular admin or all admins that set retrictions on this user
+ * for a particular admin or all admins that set restrictions on this user
* and its participating profiles. Restrictions on profiles that have
* a separate challenge are not taken into account.
* This is the same value as set by
@@ -1716,7 +1716,7 @@ public class DevicePolicyManager {
/**
* Retrieve the current number of symbols required in the password
- * for a particular admin or all admins that set retrictions on this user
+ * for a particular admin or all admins that set restrictions on this user
* and its participating profiles. Restrictions on profiles that have
* a separate challenge are not taken into account. This is the same value as
* set by {@link #setPasswordMinimumSymbols(ComponentName, int)}
@@ -1783,7 +1783,7 @@ public class DevicePolicyManager {
/**
* Retrieve the current number of non-letter characters required in the password
- * for a particular admin or all admins that set retrictions on this user
+ * for a particular admin or all admins that set restrictions on this user
* and its participating profiles. Restrictions on profiles that have
* a separate challenge are not taken into account.
* This is the same value as set by
@@ -1915,7 +1915,7 @@ public class DevicePolicyManager {
/**
* Get the current password expiration time for a particular admin or all admins that set
- * retrictions on this user and its participating profiles. Restrictions on profiles that have
+ * restrictions on this user and its participating profiles. Restrictions on profiles that have
* a separate challenge are not taken into account. If admin is {@code null}, then a composite
* of all expiration times is returned - which will be the minimum of all of them.
*
@@ -1939,7 +1939,7 @@ public class DevicePolicyManager {
/**
* Retrieve the current password history length for a particular admin or all admins that
- * set retrictions on this user and its participating profiles. Restrictions on profiles that
+ * set restrictions on this user and its participating profiles. Restrictions on profiles that
* have a separate challenge are not taken into account.
*
*
This method can be called on the {@link DevicePolicyManager} instance
@@ -2121,7 +2121,7 @@ public class DevicePolicyManager {
/**
* Retrieve the current maximum number of login attempts that are allowed before the device
- * or profile is wiped, for a particular admin or all admins that set retrictions on this user
+ * or profile is wiped, for a particular admin or all admins that set restrictions on this user
* and its participating profiles. Restrictions on profiles that have a separate challenge are
* not taken into account.
*
@@ -2262,7 +2262,7 @@ public class DevicePolicyManager {
/**
* Retrieve the current maximum time to unlock for a particular admin or all admins that set
- * retrictions on this user and its participating profiles. Restrictions on profiles that have
+ * restrictions on this user and its participating profiles. Restrictions on profiles that have
* a separate challenge are not taken into account.
*
*
This method can be called on the {@link DevicePolicyManager} instance
@@ -2510,6 +2510,8 @@ public class DevicePolicyManager {
/**
* Result code for {@link #setStorageEncryption} and {@link #getStorageEncryptionStatus}:
* indicating that encryption is active.
+ *
+ * Also see {@link #ENCRYPTION_STATUS_ACTIVE_PER_USER}.
*/
public static final int ENCRYPTION_STATUS_ACTIVE = 3;
@@ -2522,7 +2524,11 @@ public class DevicePolicyManager {
/**
* Result code for {@link #getStorageEncryptionStatus}:
- * indicating that encryption is active and the encryption key is tied to the user.
+ * indicating that encryption is active and the encryption key is tied to the user or profile.
+ *
+ * This value is only returned to apps targeting API level 24 and above. For apps targeting
+ * earlier API levels, {@link #ENCRYPTION_STATUS_ACTIVE} is returned, even if the
+ * encryption key is specific to the user or profile.
*/
public static final int ENCRYPTION_STATUS_ACTIVE_PER_USER = 5;
@@ -2649,7 +2655,7 @@ public class DevicePolicyManager {
/**
* Called by an application that is administering the device to
* determine the current encryption status of the device.
- *
+ *
* Depending on the returned status code, the caller may proceed in different
* ways. If the result is {@link #ENCRYPTION_STATUS_UNSUPPORTED}, the
* storage system does not support encryption. If the
@@ -2657,13 +2663,14 @@ public class DevicePolicyManager {
* #ACTION_START_ENCRYPTION} to begin the process of encrypting or decrypting the
* storage. If the result is {@link #ENCRYPTION_STATUS_ACTIVE_DEFAULT_KEY}, the
* storage system has enabled encryption but no password is set so further action
- * may be required. If the result is {@link #ENCRYPTION_STATUS_ACTIVATING} or
- * {@link #ENCRYPTION_STATUS_ACTIVE}, no further action is required.
+ * may be required. If the result is {@link #ENCRYPTION_STATUS_ACTIVATING},
+ * {@link #ENCRYPTION_STATUS_ACTIVE} or {@link #ENCRYPTION_STATUS_ACTIVE_PER_USER},
+ * no further action is required.
*
* @return current status of encryption. The value will be one of
* {@link #ENCRYPTION_STATUS_UNSUPPORTED}, {@link #ENCRYPTION_STATUS_INACTIVE},
* {@link #ENCRYPTION_STATUS_ACTIVATING}, {@link #ENCRYPTION_STATUS_ACTIVE_DEFAULT_KEY},
- * or {@link #ENCRYPTION_STATUS_ACTIVE}.
+ * {@link #ENCRYPTION_STATUS_ACTIVE}, or {@link #ENCRYPTION_STATUS_ACTIVE_PER_USER}.
*/
public int getStorageEncryptionStatus() {
throwIfParentInstance("getStorageEncryptionStatus");
@@ -3341,7 +3348,7 @@ public class DevicePolicyManager {
/**
* Determine whether or not features have been disabled in keyguard either by the calling
- * admin, if specified, or all admins that set retrictions on this user and its participating
+ * admin, if specified, or all admins that set restrictions on this user and its participating
* profiles. Restrictions on profiles that have a separate challenge are not taken into account.
*
*
This method can be called on the {@link DevicePolicyManager} instance
@@ -6416,6 +6423,43 @@ public class DevicePolicyManager {
}
}
+ /**
+ * @hide
+ * @return whether {@link android.provider.Settings.Global#DEVICE_PROVISIONED} has ever been set
+ * to 1.
+ */
+ public boolean isDeviceProvisioned() {
+ try {
+ return mService.isDeviceProvisioned();
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * @hide
+ * Writes that the provisioning configuration has been applied.
+ */
+ public void setDeviceProvisioningConfigApplied() {
+ try {
+ mService.setDeviceProvisioningConfigApplied();
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * @hide
+ * @return whether the provisioning configuration has been applied.
+ */
+ public boolean isDeviceProvisioningConfigApplied() {
+ try {
+ return mService.isDeviceProvisioningConfigApplied();
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
+
private void throwIfParentInstance(String functionName) {
if (mParentInstance) {
throw new SecurityException(functionName + " cannot be called on the parent instance");
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index a1d7635f7e69e8f1e30730ea026bbf67841a0d79..8693041c1309804632f01db4c82949bebac2757f 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -302,5 +302,9 @@ interface IDevicePolicyManager {
boolean isUninstallInQueue(String packageName);
void uninstallPackageWithActiveAdmins(String packageName);
+ boolean isDeviceProvisioned();
+ boolean isDeviceProvisioningConfigApplied();
+ void setDeviceProvisioningConfigApplied();
+
boolean requireSecureKeyguard(int userHandle);
}
diff --git a/core/java/android/app/backup/FullBackup.java b/core/java/android/app/backup/FullBackup.java
index 478024d7d27cd5c5dab1e717e81f04dc01ca31cb..76828eeba78567bbb0c8aa9018a7b31e7aee964f 100644
--- a/core/java/android/app/backup/FullBackup.java
+++ b/core/java/android/app/backup/FullBackup.java
@@ -21,6 +21,8 @@ import android.content.pm.PackageManager;
import android.content.res.XmlResourceParser;
import android.os.ParcelFileDescriptor;
import android.os.Process;
+import android.os.storage.StorageManager;
+import android.os.storage.StorageVolume;
import android.system.ErrnoException;
import android.system.Os;
import android.text.TextUtils;
@@ -223,8 +225,12 @@ public class FullBackup {
final int mFullBackupContent;
final PackageManager mPackageManager;
+ final StorageManager mStorageManager;
final String mPackageName;
+ // lazy initialized, only when needed
+ private StorageVolume[] mVolumes = null;
+
/**
* Parse out the semantic domains into the correct physical location.
*/
@@ -260,16 +266,41 @@ public class FullBackup {
} else {
return null;
}
+ } else if (domainToken.startsWith(FullBackup.SHARED_PREFIX)) {
+ return sharedDomainToPath(domainToken);
}
// Not a supported location
Log.i(TAG, "Unrecognized domain " + domainToken);
return null;
- } catch (IOException e) {
+ } catch (Exception e) {
Log.i(TAG, "Error reading directory for domain: " + domainToken);
return null;
}
}
+
+ private String sharedDomainToPath(String domain) throws IOException {
+ // already known to start with SHARED_PREFIX, so we just look after that
+ final String volume = domain.substring(FullBackup.SHARED_PREFIX.length());
+ final StorageVolume[] volumes = getVolumeList();
+ final int volNum = Integer.parseInt(volume);
+ if (volNum < mVolumes.length) {
+ return volumes[volNum].getPathFile().getCanonicalPath();
+ }
+ return null;
+ }
+
+ private StorageVolume[] getVolumeList() {
+ if (mStorageManager != null) {
+ if (mVolumes == null) {
+ mVolumes = mStorageManager.getVolumeList();
+ }
+ } else {
+ Log.e(TAG, "Unable to access Storage Manager");
+ }
+ return mVolumes;
+ }
+
/**
* A map of domain -> list of canonical file names in that domain that are to be included.
* We keep track of the domain so that we can go through the file system in order later on.
@@ -283,6 +314,7 @@ public class FullBackup {
BackupScheme(Context context) {
mFullBackupContent = context.getApplicationInfo().fullBackupContent;
+ mStorageManager = (StorageManager) context.getSystemService(Context.STORAGE_SERVICE);
mPackageManager = context.getPackageManager();
mPackageName = context.getPackageName();
diff --git a/core/java/android/app/backup/WallpaperBackupHelper.java b/core/java/android/app/backup/WallpaperBackupHelper.java
index f256a9536061b1e3426dcdd1bcb87e3f19d3f06c..f9874685167860be38fb0e5aa117dff18e0179b4 100644
--- a/core/java/android/app/backup/WallpaperBackupHelper.java
+++ b/core/java/android/app/backup/WallpaperBackupHelper.java
@@ -42,7 +42,7 @@ public class WallpaperBackupHelper extends FileBackupHelperBase implements Backu
// If 'true', then apply an acceptable-size heuristic at restore time, dropping back
// to the factory default wallpaper if the restored one differs "too much" from the
// device's preferred wallpaper image dimensions.
- private static final boolean REJECT_OUTSIZED_RESTORE = true;
+ private static final boolean REJECT_OUTSIZED_RESTORE = false;
// When outsized restore rejection is enabled, this is the maximum ratio between the
// source and target image heights that will be permitted. The ratio is checked both
@@ -60,6 +60,9 @@ public class WallpaperBackupHelper extends FileBackupHelperBase implements Backu
public static final String WALLPAPER_IMAGE =
new File(Environment.getUserSystemDirectory(UserHandle.USER_SYSTEM),
"wallpaper").getAbsolutePath();
+ public static final String WALLPAPER_ORIG_IMAGE =
+ new File(Environment.getUserSystemDirectory(UserHandle.USER_SYSTEM),
+ "wallpaper_orig").getAbsolutePath();
public static final String WALLPAPER_INFO =
new File(Environment.getUserSystemDirectory(UserHandle.USER_SYSTEM),
"wallpaper_info.xml").getAbsolutePath();
@@ -199,7 +202,7 @@ public class WallpaperBackupHelper extends FileBackupHelperBase implements Backu
// since it does not exist anywhere other than the private wallpaper
// file.
Slog.d(TAG, "Applying restored wallpaper image.");
- f.renameTo(new File(WALLPAPER_IMAGE));
+ f.renameTo(new File(WALLPAPER_ORIG_IMAGE));
}
}
}
diff --git a/core/java/android/app/job/JobInfo.java b/core/java/android/app/job/JobInfo.java
index 5823abf9d78fd8495538dde277b401641a205d95..734bf6917eca4d92b27086fa048c8c6194966395 100644
--- a/core/java/android/app/job/JobInfo.java
+++ b/core/java/android/app/job/JobInfo.java
@@ -165,6 +165,9 @@ public class JobInfo implements Parcelable {
* network restrictions for the requesting app. Note that this flag alone
* doesn't actually place your {@link JobService} in the foreground; you
* still need to post the notification yourself.
+ *
+ * To use this flag, the caller must hold the
+ * {@link android.Manifest.permission#CONNECTIVITY_INTERNAL} permission.
*
* @hide
*/
diff --git a/core/java/android/app/usage/UsageEvents.java b/core/java/android/app/usage/UsageEvents.java
index 24647f388fc128a3fd1a867a10654cc1d3fa772a..a0da258bdf1cd7f8aa5ffeb72f432e0936f67977 100644
--- a/core/java/android/app/usage/UsageEvents.java
+++ b/core/java/android/app/usage/UsageEvents.java
@@ -78,6 +78,13 @@ public final class UsageEvents implements Parcelable {
*/
public static final int USER_INTERACTION = 7;
+ /**
+ * An event type denoting that an action equivalent to a ShortcutInfo is taken by the user.
+ *
+ * @see android.content.pm.ShortcutManager#reportShortcutUsed(String)
+ */
+ public static final int SHORTCUT_INVOCATION = 8;
+
/**
* {@hide}
*/
@@ -104,6 +111,13 @@ public final class UsageEvents implements Parcelable {
*/
public Configuration mConfiguration;
+ /**
+ * ID of the shortcut.
+ * Only present for {@link #SHORTCUT_INVOCATION} event types.
+ * {@hide}
+ */
+ public String mShortcutId;
+
/**
* The package name of the source of this event.
*/
@@ -145,6 +159,16 @@ public final class UsageEvents implements Parcelable {
public Configuration getConfiguration() {
return mConfiguration;
}
+
+ /**
+ * Returns the ID of a {@link android.content.pm.ShortcutInfo} for this event
+ * if the event is of type {@link #SHORTCUT_INVOCATION}, otherwise it returns null.
+ *
+ * @see android.content.pm.ShortcutManager#reportShortcutUsed(String)
+ */
+ public String getShortcutId() {
+ return mShortcutId;
+ }
}
// Only used when creating the resulting events. Not used for reading/unparceling.
@@ -276,8 +300,13 @@ public final class UsageEvents implements Parcelable {
p.writeInt(event.mEventType);
p.writeLong(event.mTimeStamp);
- if (event.mEventType == Event.CONFIGURATION_CHANGE) {
- event.mConfiguration.writeToParcel(p, flags);
+ switch (event.mEventType) {
+ case Event.CONFIGURATION_CHANGE:
+ event.mConfiguration.writeToParcel(p, flags);
+ break;
+ case Event.SHORTCUT_INVOCATION:
+ p.writeString(event.mShortcutId);
+ break;
}
}
@@ -301,11 +330,18 @@ public final class UsageEvents implements Parcelable {
eventOut.mEventType = p.readInt();
eventOut.mTimeStamp = p.readLong();
- // Extract the configuration for configuration change events.
- if (eventOut.mEventType == Event.CONFIGURATION_CHANGE) {
- eventOut.mConfiguration = Configuration.CREATOR.createFromParcel(p);
- } else {
- eventOut.mConfiguration = null;
+ // Fill out the event-dependant fields.
+ eventOut.mConfiguration = null;
+ eventOut.mShortcutId = null;
+
+ switch (eventOut.mEventType) {
+ case Event.CONFIGURATION_CHANGE:
+ // Extract the configuration for configuration change events.
+ eventOut.mConfiguration = Configuration.CREATOR.createFromParcel(p);
+ break;
+ case Event.SHORTCUT_INVOCATION:
+ eventOut.mShortcutId = p.readString();
+ break;
}
}
diff --git a/core/java/android/app/usage/UsageStatsManagerInternal.java b/core/java/android/app/usage/UsageStatsManagerInternal.java
index b6f1567568c29048ad6417cd4bedceb6d758fc67..a6f91fe1722758d7b620d42bd68a03ab91254265 100644
--- a/core/java/android/app/usage/UsageStatsManagerInternal.java
+++ b/core/java/android/app/usage/UsageStatsManagerInternal.java
@@ -55,6 +55,17 @@ public abstract class UsageStatsManagerInternal {
*/
public abstract void reportConfigurationChange(Configuration config, int userId);
+ /**
+ * Reports that an action equivalent to a ShortcutInfo is taken by the user.
+ *
+ * @param packageName The package name of the shortcut publisher
+ * @param shortcutId The ID of the shortcut in question
+ * @param userId The user in which the content provider was accessed.
+ *
+ * @see android.content.pm.ShortcutManager#reportShortcutUsed(String)
+ */
+ public abstract void reportShortcutUsage(String packageName, String shortcutId, int userId);
+
/**
* Reports that a content provider has been accessed by a foreground app.
* @param name The authority of the content provider
diff --git a/core/java/android/appwidget/AppWidgetHost.java b/core/java/android/appwidget/AppWidgetHost.java
index 2d9f4a71b0054845ad07b7aa38f933a80a47bae2..cd144695a989dd744faf1fc99f9db073aa5c886a 100644
--- a/core/java/android/appwidget/AppWidgetHost.java
+++ b/core/java/android/appwidget/AppWidgetHost.java
@@ -34,7 +34,6 @@ import android.os.Message;
import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
-import android.os.SystemClock;
import android.util.DisplayMetrics;
import android.util.SparseArray;
import android.util.TypedValue;
@@ -187,19 +186,28 @@ public class AppWidgetHost {
idsToUpdate[i] = mViews.keyAt(i);
}
}
- List updatedViews;
- int[] updatedIds = new int[idsToUpdate.length];
+ List updates;
try {
- updatedViews = sService.startListening(
- mCallbacks, mContextOpPackageName, mHostId, idsToUpdate, updatedIds).getList();
+ updates = sService.startListening(
+ mCallbacks, mContextOpPackageName, mHostId, idsToUpdate).getList();
}
catch (RemoteException e) {
throw new RuntimeException("system server dead?", e);
}
- int N = updatedViews.size();
+ int N = updates.size();
for (int i = 0; i < N; i++) {
- updateAppWidgetView(updatedIds[i], updatedViews.get(i));
+ PendingHostUpdate update = updates.get(i);
+ switch (update.type) {
+ case PendingHostUpdate.TYPE_VIEWS_UPDATE:
+ updateAppWidgetView(update.appWidgetId, update.views);
+ break;
+ case PendingHostUpdate.TYPE_PROVIDER_CHANGED:
+ onProviderChanged(update.appWidgetId, update.widgetInfo);
+ break;
+ case PendingHostUpdate.TYPE_VIEW_DATA_CHANGED:
+ viewDataChanged(update.appWidgetId, update.viewId);
+ }
}
}
diff --git a/core/java/android/appwidget/PendingHostUpdate.java b/core/java/android/appwidget/PendingHostUpdate.java
new file mode 100644
index 0000000000000000000000000000000000000000..578031908f52e3ff935870b469d4da1619457f94
--- /dev/null
+++ b/core/java/android/appwidget/PendingHostUpdate.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.appwidget;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.widget.RemoteViews;
+
+/**
+ * @hide
+ */
+public class PendingHostUpdate implements Parcelable {
+
+ static final int TYPE_VIEWS_UPDATE = 0;
+ static final int TYPE_PROVIDER_CHANGED = 1;
+ static final int TYPE_VIEW_DATA_CHANGED = 2;
+
+ final int appWidgetId;
+ final int type;
+ RemoteViews views;
+ AppWidgetProviderInfo widgetInfo;
+ int viewId;
+
+ public static PendingHostUpdate updateAppWidget(int appWidgetId, RemoteViews views) {
+ PendingHostUpdate update = new PendingHostUpdate(appWidgetId, TYPE_VIEWS_UPDATE);
+ update.views = views;
+ return update;
+ }
+
+ public static PendingHostUpdate providerChanged(int appWidgetId, AppWidgetProviderInfo info) {
+ PendingHostUpdate update = new PendingHostUpdate(appWidgetId, TYPE_PROVIDER_CHANGED);
+ update.widgetInfo = info;
+ return update;
+ }
+
+ public static PendingHostUpdate viewDataChanged(int appWidgetId, int viewId) {
+ PendingHostUpdate update = new PendingHostUpdate(appWidgetId, TYPE_VIEW_DATA_CHANGED);
+ update.viewId = viewId;
+ return update;
+ }
+
+ private PendingHostUpdate(int appWidgetId, int type) {
+ this.appWidgetId = appWidgetId;
+ this.type = type;
+ }
+
+ private PendingHostUpdate(Parcel in) {
+ appWidgetId = in.readInt();
+ type = in.readInt();
+
+ switch (type) {
+ case TYPE_VIEWS_UPDATE:
+ if (0 != in.readInt()) {
+ views = new RemoteViews(in);
+ }
+ break;
+ case TYPE_PROVIDER_CHANGED:
+ if (0 != in.readInt()) {
+ widgetInfo = new AppWidgetProviderInfo(in);
+ }
+ break;
+ case TYPE_VIEW_DATA_CHANGED:
+ viewId = in.readInt();
+ }
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(appWidgetId);
+ dest.writeInt(type);
+ switch (type) {
+ case TYPE_VIEWS_UPDATE:
+ writeNullParcelable(views, dest, flags);
+ break;
+ case TYPE_PROVIDER_CHANGED:
+ writeNullParcelable(widgetInfo, dest, flags);
+ break;
+ case TYPE_VIEW_DATA_CHANGED:
+ dest.writeInt(viewId);
+ break;
+ }
+ }
+
+ private void writeNullParcelable(Parcelable p, Parcel dest, int flags) {
+ if (p != null) {
+ dest.writeInt(1);
+ p.writeToParcel(dest, flags);
+ } else {
+ dest.writeInt(0);
+ }
+ }
+
+ /**
+ * Parcelable.Creator that instantiates PendingHostUpdate objects
+ */
+ public static final Parcelable.Creator CREATOR
+ = new Parcelable.Creator() {
+ public PendingHostUpdate createFromParcel(Parcel parcel) {
+ return new PendingHostUpdate(parcel);
+ }
+
+ public PendingHostUpdate[] newArray(int size) {
+ return new PendingHostUpdate[size];
+ }
+ };
+}
diff --git a/core/java/android/bluetooth/BluetoothA2dp.java b/core/java/android/bluetooth/BluetoothA2dp.java
index f66b5ff466c3f790d84aabe3b330edc4b60ae8ad..353c6400ffd74d8ee1446df58660b7eb7979b290 100644
--- a/core/java/android/bluetooth/BluetoothA2dp.java
+++ b/core/java/android/bluetooth/BluetoothA2dp.java
@@ -30,8 +30,11 @@ import android.os.ParcelUuid;
import android.os.RemoteException;
import android.util.Log;
+import com.android.internal.annotations.GuardedBy;
+
import java.util.ArrayList;
import java.util.List;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
/**
@@ -114,7 +117,8 @@ public final class BluetoothA2dp implements BluetoothProfile {
private Context mContext;
private ServiceListener mServiceListener;
- private IBluetoothA2dp mService;
+ private final ReentrantReadWriteLock mServiceLock = new ReentrantReadWriteLock();
+ @GuardedBy("mServiceLock") private IBluetoothA2dp mService;
private BluetoothAdapter mAdapter;
final private IBluetoothStateChangeCallback mBluetoothStateChangeCallback =
@@ -122,25 +126,27 @@ public final class BluetoothA2dp implements BluetoothProfile {
public void onBluetoothStateChange(boolean up) {
if (DBG) Log.d(TAG, "onBluetoothStateChange: up=" + up);
if (!up) {
- if (VDBG) Log.d(TAG,"Unbinding service...");
- synchronized (mConnection) {
- try {
- mService = null;
- mContext.unbindService(mConnection);
- } catch (Exception re) {
- Log.e(TAG,"",re);
- }
+ if (VDBG) Log.d(TAG, "Unbinding service...");
+ try {
+ mServiceLock.writeLock().lock();
+ mService = null;
+ mContext.unbindService(mConnection);
+ } catch (Exception re) {
+ Log.e(TAG, "", re);
+ } finally {
+ mServiceLock.writeLock().unlock();
}
} else {
- synchronized (mConnection) {
- try {
- if (mService == null) {
- if (VDBG) Log.d(TAG,"Binding service...");
- doBind();
- }
- } catch (Exception re) {
- Log.e(TAG,"",re);
+ try {
+ mServiceLock.readLock().lock();
+ if (mService == null) {
+ if (VDBG) Log.d(TAG,"Binding service...");
+ doBind();
}
+ } catch (Exception re) {
+ Log.e(TAG,"",re);
+ } finally {
+ mServiceLock.readLock().unlock();
}
}
}
@@ -189,15 +195,16 @@ public final class BluetoothA2dp implements BluetoothProfile {
}
}
- synchronized (mConnection) {
+ try {
+ mServiceLock.writeLock().lock();
if (mService != null) {
- try {
- mService = null;
- mContext.unbindService(mConnection);
- } catch (Exception re) {
- Log.e(TAG,"",re);
- }
+ mService = null;
+ mContext.unbindService(mConnection);
}
+ } catch (Exception re) {
+ Log.e(TAG, "", re);
+ } finally {
+ mServiceLock.writeLock().unlock();
}
}
@@ -229,17 +236,20 @@ public final class BluetoothA2dp implements BluetoothProfile {
*/
public boolean connect(BluetoothDevice device) {
if (DBG) log("connect(" + device + ")");
- if (mService != null && isEnabled() &&
- isValidDevice(device)) {
- try {
+ try {
+ mServiceLock.readLock().lock();
+ if (mService != null && isEnabled() &&
+ isValidDevice(device)) {
return mService.connect(device);
- } catch (RemoteException e) {
- Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
- return false;
}
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return false;
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return false;
+ } finally {
+ mServiceLock.readLock().unlock();
}
- if (mService == null) Log.w(TAG, "Proxy not attached to service");
- return false;
}
/**
@@ -270,17 +280,20 @@ public final class BluetoothA2dp implements BluetoothProfile {
*/
public boolean disconnect(BluetoothDevice device) {
if (DBG) log("disconnect(" + device + ")");
- if (mService != null && isEnabled() &&
- isValidDevice(device)) {
- try {
+ try {
+ mServiceLock.readLock().lock();
+ if (mService != null && isEnabled() &&
+ isValidDevice(device)) {
return mService.disconnect(device);
- } catch (RemoteException e) {
- Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
- return false;
}
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return false;
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return false;
+ } finally {
+ mServiceLock.readLock().unlock();
}
- if (mService == null) Log.w(TAG, "Proxy not attached to service");
- return false;
}
/**
@@ -288,16 +301,19 @@ public final class BluetoothA2dp implements BluetoothProfile {
*/
public List getConnectedDevices() {
if (VDBG) log("getConnectedDevices()");
- if (mService != null && isEnabled()) {
- try {
+ try {
+ mServiceLock.readLock().lock();
+ if (mService != null && isEnabled()) {
return mService.getConnectedDevices();
- } catch (RemoteException e) {
- Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
- return new ArrayList();
}
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return new ArrayList();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return new ArrayList();
+ } finally {
+ mServiceLock.readLock().unlock();
}
- if (mService == null) Log.w(TAG, "Proxy not attached to service");
- return new ArrayList();
}
/**
@@ -305,16 +321,19 @@ public final class BluetoothA2dp implements BluetoothProfile {
*/
public List getDevicesMatchingConnectionStates(int[] states) {
if (VDBG) log("getDevicesMatchingStates()");
- if (mService != null && isEnabled()) {
- try {
+ try {
+ mServiceLock.readLock().lock();
+ if (mService != null && isEnabled()) {
return mService.getDevicesMatchingConnectionStates(states);
- } catch (RemoteException e) {
- Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
- return new ArrayList();
}
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return new ArrayList();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return new ArrayList();
+ } finally {
+ mServiceLock.readLock().unlock();
}
- if (mService == null) Log.w(TAG, "Proxy not attached to service");
- return new ArrayList();
}
/**
@@ -322,17 +341,20 @@ public final class BluetoothA2dp implements BluetoothProfile {
*/
public int getConnectionState(BluetoothDevice device) {
if (VDBG) log("getState(" + device + ")");
- if (mService != null && isEnabled()
- && isValidDevice(device)) {
- try {
+ try {
+ mServiceLock.readLock().lock();
+ if (mService != null && isEnabled()
+ && isValidDevice(device)) {
return mService.getConnectionState(device);
- } catch (RemoteException e) {
- Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
- return BluetoothProfile.STATE_DISCONNECTED;
}
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return BluetoothProfile.STATE_DISCONNECTED;
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return BluetoothProfile.STATE_DISCONNECTED;
+ } finally {
+ mServiceLock.readLock().unlock();
}
- if (mService == null) Log.w(TAG, "Proxy not attached to service");
- return BluetoothProfile.STATE_DISCONNECTED;
}
/**
@@ -352,21 +374,24 @@ public final class BluetoothA2dp implements BluetoothProfile {
*/
public boolean setPriority(BluetoothDevice device, int priority) {
if (DBG) log("setPriority(" + device + ", " + priority + ")");
- if (mService != null && isEnabled()
- && isValidDevice(device)) {
- if (priority != BluetoothProfile.PRIORITY_OFF &&
- priority != BluetoothProfile.PRIORITY_ON){
- return false;
- }
- try {
+ try {
+ mServiceLock.readLock().lock();
+ if (mService != null && isEnabled()
+ && isValidDevice(device)) {
+ if (priority != BluetoothProfile.PRIORITY_OFF &&
+ priority != BluetoothProfile.PRIORITY_ON) {
+ return false;
+ }
return mService.setPriority(device, priority);
- } catch (RemoteException e) {
- Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
- return false;
}
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return false;
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return false;
+ } finally {
+ mServiceLock.readLock().unlock();
}
- if (mService == null) Log.w(TAG, "Proxy not attached to service");
- return false;
}
/**
@@ -385,17 +410,20 @@ public final class BluetoothA2dp implements BluetoothProfile {
@RequiresPermission(Manifest.permission.BLUETOOTH)
public int getPriority(BluetoothDevice device) {
if (VDBG) log("getPriority(" + device + ")");
- if (mService != null && isEnabled()
- && isValidDevice(device)) {
- try {
+ try {
+ mServiceLock.readLock().lock();
+ if (mService != null && isEnabled()
+ && isValidDevice(device)) {
return mService.getPriority(device);
- } catch (RemoteException e) {
- Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
- return BluetoothProfile.PRIORITY_OFF;
}
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return BluetoothProfile.PRIORITY_OFF;
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return BluetoothProfile.PRIORITY_OFF;
+ } finally {
+ mServiceLock.readLock().unlock();
}
- if (mService == null) Log.w(TAG, "Proxy not attached to service");
- return BluetoothProfile.PRIORITY_OFF;
}
/**
@@ -406,16 +434,19 @@ public final class BluetoothA2dp implements BluetoothProfile {
*/
public boolean isAvrcpAbsoluteVolumeSupported() {
if (DBG) Log.d(TAG, "isAvrcpAbsoluteVolumeSupported");
- if (mService != null && isEnabled()) {
- try {
+ try {
+ mServiceLock.readLock().lock();
+ if (mService != null && isEnabled()) {
return mService.isAvrcpAbsoluteVolumeSupported();
- } catch (RemoteException e) {
- Log.e(TAG, "Error talking to BT service in isAvrcpAbsoluteVolumeSupported()", e);
- return false;
}
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return false;
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error talking to BT service in isAvrcpAbsoluteVolumeSupported()", e);
+ return false;
+ } finally {
+ mServiceLock.readLock().unlock();
}
- if (mService == null) Log.w(TAG, "Proxy not attached to service");
- return false;
}
/**
@@ -433,16 +464,17 @@ public final class BluetoothA2dp implements BluetoothProfile {
*/
public void adjustAvrcpAbsoluteVolume(int direction) {
if (DBG) Log.d(TAG, "adjustAvrcpAbsoluteVolume");
- if (mService != null && isEnabled()) {
- try {
+ try {
+ mServiceLock.readLock().lock();
+ if (mService != null && isEnabled()) {
mService.adjustAvrcpAbsoluteVolume(direction);
- return;
- } catch (RemoteException e) {
- Log.e(TAG, "Error talking to BT service in adjustAvrcpAbsoluteVolume()", e);
- return;
}
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error talking to BT service in adjustAvrcpAbsoluteVolume()", e);
+ } finally {
+ mServiceLock.readLock().unlock();
}
- if (mService == null) Log.w(TAG, "Proxy not attached to service");
}
/**
@@ -453,16 +485,17 @@ public final class BluetoothA2dp implements BluetoothProfile {
*/
public void setAvrcpAbsoluteVolume(int volume) {
if (DBG) Log.d(TAG, "setAvrcpAbsoluteVolume");
- if (mService != null && isEnabled()) {
- try {
+ try {
+ mServiceLock.readLock().lock();
+ if (mService != null && isEnabled()) {
mService.setAvrcpAbsoluteVolume(volume);
- return;
- } catch (RemoteException e) {
- Log.e(TAG, "Error talking to BT service in setAvrcpAbsoluteVolume()", e);
- return;
}
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error talking to BT service in setAvrcpAbsoluteVolume()", e);
+ } finally {
+ mServiceLock.readLock().unlock();
}
- if (mService == null) Log.w(TAG, "Proxy not attached to service");
}
/**
@@ -473,17 +506,20 @@ public final class BluetoothA2dp implements BluetoothProfile {
* @param device BluetoothDevice device
*/
public boolean isA2dpPlaying(BluetoothDevice device) {
- if (mService != null && isEnabled()
- && isValidDevice(device)) {
- try {
+ try {
+ mServiceLock.readLock().lock();
+ if (mService != null && isEnabled()
+ && isValidDevice(device)) {
return mService.isA2dpPlaying(device);
- } catch (RemoteException e) {
- Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
- return false;
}
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return false;
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return false;
+ } finally {
+ mServiceLock.readLock().unlock();
}
- if (mService == null) Log.w(TAG, "Proxy not attached to service");
- return false;
}
/**
@@ -534,7 +570,12 @@ public final class BluetoothA2dp implements BluetoothProfile {
private final ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
if (DBG) Log.d(TAG, "Proxy object connected");
- mService = IBluetoothA2dp.Stub.asInterface(service);
+ try {
+ mServiceLock.writeLock().lock();
+ mService = IBluetoothA2dp.Stub.asInterface(service);
+ } finally {
+ mServiceLock.writeLock().unlock();
+ }
if (mServiceListener != null) {
mServiceListener.onServiceConnected(BluetoothProfile.A2DP, BluetoothA2dp.this);
@@ -542,7 +583,12 @@ public final class BluetoothA2dp implements BluetoothProfile {
}
public void onServiceDisconnected(ComponentName className) {
if (DBG) Log.d(TAG, "Proxy object disconnected");
- mService = null;
+ try {
+ mServiceLock.writeLock().lock();
+ mService = null;
+ } finally {
+ mServiceLock.writeLock().unlock();
+ }
if (mServiceListener != null) {
mServiceListener.onServiceDisconnected(BluetoothProfile.A2DP);
}
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index ad628a42017b0204c1ccccdcb3258c9f981cd129..6f2c207a59576c6291984bfa4908ca60b54917af 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -92,8 +92,11 @@ import java.util.concurrent.locks.ReentrantReadWriteLock;
*
*
*
Developer Guides
- *
For more information about using Bluetooth, read the
- * Bluetooth developer guide.
+ *
+ * For more information about using Bluetooth, read the Bluetooth developer
+ * guide.
+ *
For more information about using Bluetooth, read the
- * Bluetooth developer guide.
+ *
+ * For more information about using Bluetooth, read the Bluetooth developer
+ * guide.
+ *
*
*
* {@see BluetoothAdapter}
diff --git a/core/java/android/bluetooth/BluetoothHeadset.java b/core/java/android/bluetooth/BluetoothHeadset.java
index da810329aa60ed45940da50ab672221a992a94cf..c7c9c3f2a43855b95d1361d5fe7f5dca2e2fc122 100644
--- a/core/java/android/bluetooth/BluetoothHeadset.java
+++ b/core/java/android/bluetooth/BluetoothHeadset.java
@@ -241,6 +241,46 @@ public final class BluetoothHeadset implements BluetoothProfile {
* {@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} of
* {@link #ACTION_AUDIO_STATE_CHANGED} intent.
*/
+
+ /**
+ * Intent used to broadcast the headset's indicator status
+ *
+ *
This intent will have 3 extras:
+ *
+ *
{@link #EXTRA_IND_ID} - The Assigned number of headset Indicator which is supported by
+ the headset ( as indicated by AT+BIND
+ command in the SLC sequence).or whose value
+ is changed (indicated by AT+BIEV command)
+ *
{@link #EXTRA_IND_VALUE}- The updated value of headset indicator.
+ *
{@link BluetoothDevice#EXTRA_DEVICE} - The remote device.
+ *
+ *
{@link #EXTRA_IND_ID} is defined by Bluetooth SIG and each of the indicators are
+ * given an assigned number. Below shows the assigned number of Indicator added so far
+ * - Enhanced Safety - 1
+ *
Requires {@link android.Manifest.permission#BLUETOOTH} permission to
+ * receive.
+ * @hide
+ */
+ public static final String ACTION_HF_INDICATORS_VALUE_CHANGED =
+ "android.bluetooth.headset.action.HF_INDICATORS_VALUE_CHANGED";
+
+ /**
+ * A String extra field in {@link #ACTION_HF_INDICATORS_VALUE_CHANGED}
+ * intents that contains the UUID of the headset indicator (as defined by Bluetooth SIG)
+ * that is being sent.
+ * @hide
+ */
+ public static final String EXTRA_HF_INDICATORS_IND_ID =
+ "android.bluetooth.headset.extra.HF_INDICATORS_IND_ID";
+
+ /**
+ * A int extra field in {@link #ACTION_HF_INDICATORS_VALUE_CHANGED}
+ * intents that contains the value of the Headset indicator that is being sent.
+ * @hide
+ */
+ public static final String EXTRA_HF_INDICATORS_IND_VALUE =
+ "android.bluetooth.headset.extra.HF_INDICATORS_IND_VALUE";
+
public static final int STATE_AUDIO_CONNECTED = 12;
@@ -994,7 +1034,32 @@ public final class BluetoothHeadset implements BluetoothProfile {
return false;
}
- private final ServiceConnection mConnection = new ServiceConnection() {
+ /**
+ * Send Headset the BIND response from AG to report change in the status of the
+ * HF indicators to the headset
+ *
+ * @param ind_id Assigned Number of the indicator (defined by SIG)
+ * @param ind_status
+ * possible values- false-Indicator is disabled, no value changes shall be sent for this indicator
+ * true-Indicator is enabled, value changes may be sent for this indicator
+ * @hide
+ */
+ public void bindResponse(int ind_id, boolean ind_status) {
+ if (mService != null && isEnabled()) {
+ try {
+ mService.bindResponse(ind_id, ind_status);
+ } catch (RemoteException e) {
+ Log.e(TAG, e.toString());
+ }
+ } else {
+ Log.w(TAG, "Proxy not attached to service");
+ if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
+ }
+ }
+
+ private final IBluetoothProfileServiceConnection mConnection
+ = new IBluetoothProfileServiceConnection.Stub() {
+ @Override
public void onServiceConnected(ComponentName className, IBinder service) {
if (DBG) Log.d(TAG, "Proxy object connected");
mService = IBluetoothHeadset.Stub.asInterface(service);
diff --git a/core/java/android/bluetooth/BluetoothManager.java b/core/java/android/bluetooth/BluetoothManager.java
index 35437a1fd7078a99ed39f6eb65fb1e123ec86939..00058a979094f3a13dda2773e434fe54e49bdc83 100644
--- a/core/java/android/bluetooth/BluetoothManager.java
+++ b/core/java/android/bluetooth/BluetoothManager.java
@@ -38,8 +38,11 @@ import java.util.List;
*
*
*
Developer Guides
- *
For more information about using BLUETOOTH, read the
- * Bluetooth developer guide.
+ *
+ * For more information about using BLUETOOTH, read the Bluetooth developer
+ * guide.
+ *
*
*
* @see Context#getSystemService
diff --git a/core/java/android/bluetooth/BluetoothSap.java b/core/java/android/bluetooth/BluetoothSap.java
index 014cb22c57b389698ef670b1a04407c790cef177..e70c936e253e1b8bcf2ea91ab751290bd335e39b 100644
--- a/core/java/android/bluetooth/BluetoothSap.java
+++ b/core/java/android/bluetooth/BluetoothSap.java
@@ -138,7 +138,7 @@ public final class BluetoothSap implements BluetoothProfile {
}
boolean doBind() {
- Intent intent = new Intent(IBluetoothMap.class.getName());
+ Intent intent = new Intent(IBluetoothSap.class.getName());
ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
intent.setComponent(comp);
if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0,
diff --git a/core/java/android/bluetooth/BluetoothSocket.java b/core/java/android/bluetooth/BluetoothSocket.java
index eae6e8db0a650f83492414c06048a727cf684a57..63009688a09c6fa8cc84411960bc49912faba6c1 100644
--- a/core/java/android/bluetooth/BluetoothSocket.java
+++ b/core/java/android/bluetooth/BluetoothSocket.java
@@ -588,22 +588,19 @@ public final class BluetoothSocket implements Closeable {
if(length <= mMaxTxPacketSize) {
mSocketOS.write(b, offset, length);
} else {
- int tmpOffset = offset;
- int tmpLength = mMaxTxPacketSize;
- int endIndex = offset + length;
- boolean done = false;
if(DBG) Log.w(TAG, "WARNING: Write buffer larger than L2CAP packet size!\n"
+ "Packet will be divided into SDU packets of size "
+ mMaxTxPacketSize);
- do{
+ int tmpOffset = offset;
+ int bytesToWrite = length;
+ while (bytesToWrite > 0) {
+ int tmpLength = (bytesToWrite > mMaxTxPacketSize)
+ ? mMaxTxPacketSize
+ : bytesToWrite;
mSocketOS.write(b, tmpOffset, tmpLength);
- tmpOffset += mMaxTxPacketSize;
- if((tmpOffset + mMaxTxPacketSize) > endIndex) {
- tmpLength = endIndex - tmpOffset;
- done = true;
- }
- } while(!done);
-
+ tmpOffset += tmpLength;
+ bytesToWrite -= tmpLength;
+ }
}
} else {
mSocketOS.write(b, offset, length);
diff --git a/core/java/android/bluetooth/IBluetoothHeadset.aidl b/core/java/android/bluetooth/IBluetoothHeadset.aidl
index 0bb4088f62c9359cbc454b1edc08b13cc29be986..6ad442b6138d8cae33b2b206517b2efaf1bff852 100755
--- a/core/java/android/bluetooth/IBluetoothHeadset.aidl
+++ b/core/java/android/bluetooth/IBluetoothHeadset.aidl
@@ -59,4 +59,5 @@ interface IBluetoothHeadset {
String number, int type);
boolean enableWBS();
boolean disableWBS();
+ void bindResponse(int ind_id, boolean ind_status);
}
diff --git a/core/java/android/bluetooth/IBluetoothManager.aidl b/core/java/android/bluetooth/IBluetoothManager.aidl
index bd8c6c9687f1aea6f2cc2e609f59d29e620e51a9..592e6b305e21ee02f61578363d8b11e5de1b2546 100644
--- a/core/java/android/bluetooth/IBluetoothManager.aidl
+++ b/core/java/android/bluetooth/IBluetoothManager.aidl
@@ -36,6 +36,7 @@ interface IBluetoothManager
boolean enable(String callingPackage);
boolean enableNoAutoConnect();
boolean disable(boolean persist);
+ int getState();
IBluetoothGatt getBluetoothGatt();
String getAddress();
diff --git a/core/java/android/content/ClipData.java b/core/java/android/content/ClipData.java
index c365e9ee9549417a27e5d53a85a32137fed67c55..d9816a64db3a7a5f0719ded6aea5fe8369d1bf22 100644
--- a/core/java/android/content/ClipData.java
+++ b/core/java/android/content/ClipData.java
@@ -191,6 +191,14 @@ public class ClipData implements Parcelable {
final Intent mIntent;
Uri mUri;
+ /** @hide */
+ public Item(Item other) {
+ mText = other.mText;
+ mHtmlText = other.mHtmlText;
+ mIntent = other.mIntent;
+ mUri = other.mUri;
+ }
+
/**
* Create an Item consisting of a single block of (possibly styled) text.
*/
@@ -816,6 +824,11 @@ public class ClipData implements Parcelable {
return mItems.get(index);
}
+ /** @hide */
+ public void setItemAt(int index, Item item) {
+ mItems.set(index, item);
+ }
+
/**
* Prepare this {@link ClipData} to leave an app process.
*
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index f1f71950e3326ca5aa88592892cbae8fbf1bf2f9..1c8c69ff61ad8b3dd1019f269b5e64d2bf5b066a 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -34,6 +34,7 @@ import android.database.CrossProcessCursorWrapper;
import android.database.Cursor;
import android.database.IContentObserver;
import android.graphics.Point;
+import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
import android.os.CancellationSignal;
@@ -51,6 +52,7 @@ import android.util.EventLog;
import android.util.Log;
import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.MimeIconUtils;
import com.android.internal.util.Preconditions;
import dalvik.system.CloseGuard;
@@ -2696,4 +2698,9 @@ public abstract class ContentResolver {
public int resolveUserId(Uri uri) {
return ContentProvider.getUserIdFromUri(uri, mContext.getUserId());
}
+
+ /** @hide */
+ public Drawable getTypeDrawable(String mimeType) {
+ return MimeIconUtils.loadMimeIcon(mContext, mimeType);
+ }
}
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index bdf888f59715119ba48c865ffcd97b3a624945e7..3f18ea91c99a3e9482f289fbd36742b651be2f8d 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -3615,12 +3615,11 @@ public abstract class Context {
public static final String HARDWARE_PROPERTIES_SERVICE = "hardware_properties";
/**
- * TODO Javadoc
+ * Use with {@link #getSystemService} to retrieve a
+ * {@link android.content.pm.ShortcutManager} for accessing the launcher shortcut service.
*
* @see #getSystemService
* @see android.content.pm.ShortcutManager
- *
- * @hide
*/
public static final String SHORTCUT_SERVICE = "shortcut";
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 7a721083fe4b693f6278a445d49e89537f388230..659cd689417c71322c09c68b7bfee96ab2bda960 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -2227,6 +2227,22 @@ public class Intent implements Parcelable, Cloneable {
public static final String ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE =
"android.intent.action.EXTERNAL_APPLICATIONS_UNAVAILABLE";
+ /**
+ * Broadcast Action: preferred activities have changed *explicitly*.
+ *
+ *
Note there are cases where a preferred activity is invalidated *implicitly*, e.g.
+ * when an app is installed or uninstalled, but in such cases this broadcast will *not*
+ * be sent.
+ *
+ * {@link #EXTRA_USER_HANDLE} contains the user ID in question.
+ *
+ * @hide
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_PREFERRED_ACTIVITY_CHANGED =
+ "android.intent.action.ACTION_PREFERRED_ACTIVITY_CHANGED";
+
+
/**
* Broadcast Action: The current system wallpaper has changed. See
* {@link android.app.WallpaperManager} for retrieving the new wallpaper.
@@ -3189,6 +3205,14 @@ public class Intent implements Parcelable, Cloneable {
/** {@hide} */
public static final String ACTION_MASTER_CLEAR = "android.intent.action.MASTER_CLEAR";
+ /**
+ * Boolean intent extra to be used with {@link ACTION_MASTER_CLEAR} in order to force a factory
+ * reset even if {@link android.os.UserManager.DISALLOW_FACTORY_RESET} is set.
+ * @hide
+ */
+ public static final String EXTRA_FORCE_MASTER_CLEAR =
+ "android.intent.extra.FORCE_MASTER_CLEAR";
+
/**
* Broadcast action: report that a settings element is being restored from backup. The intent
* contains three extras: EXTRA_SETTING_NAME is a string naming the restored setting,
diff --git a/core/java/android/content/Loader.java b/core/java/android/content/Loader.java
index c5e0ea727869217d971e7ff641c596762e526577..3faf13b601ad3b3be2d15f4944aad1c973e53370 100644
--- a/core/java/android/content/Loader.java
+++ b/core/java/android/content/Loader.java
@@ -44,7 +44,7 @@ import java.io.PrintWriter;
*
*
Developer Guides
*
For more information about using loaders, read the
- * Loaders developer guide.
*
* @param The result returned when the load is complete
diff --git a/core/java/android/content/SharedPreferences.java b/core/java/android/content/SharedPreferences.java
index 7f9e17641a19fbd4dc64613924e8a6c7cc8a3863..4b09feda21736bb090bebdc0f07e85b9f5200137 100644
--- a/core/java/android/content/SharedPreferences.java
+++ b/core/java/android/content/SharedPreferences.java
@@ -72,7 +72,9 @@ public interface SharedPreferences {
* {@link #commit} or {@link #apply} are called.
*
* @param key The name of the preference to modify.
- * @param value The new value for the preference.
+ * @param value The new value for the preference. Passing {@code null}
+ * for this argument is equivalent to calling {@link #remove(String)} with
+ * this key.
*
* @return Returns a reference to the same Editor object, so you can
* chain put calls together.
diff --git a/core/java/android/content/pm/EphemeralResolveInfo.java b/core/java/android/content/pm/EphemeralResolveInfo.java
index afb4c30d6a996369c9e695cf2f17e8b1990a47d1..fc3b95850d21e055e4d11508cad309c98c5202d3 100644
--- a/core/java/android/content/pm/EphemeralResolveInfo.java
+++ b/core/java/android/content/pm/EphemeralResolveInfo.java
@@ -27,6 +27,7 @@ import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.List;
+import java.util.Locale;
/**
* Information about an ephemeral application.
@@ -37,10 +38,7 @@ public final class EphemeralResolveInfo implements Parcelable {
/** Algorithm that will be used to generate the domain digest */
public static final String SHA_ALGORITHM = "SHA-256";
- /** Full digest of the domain hash */
- private final byte[] mDigestBytes;
- /** The first 4 bytes of the domain hash */
- private final int mDigestPrefix;
+ private final EphemeralDigest mDigest;
private final String mPackageName;
/** The filters used to match domain */
private final List mFilters = new ArrayList();
@@ -55,29 +53,23 @@ public final class EphemeralResolveInfo implements Parcelable {
throw new IllegalArgumentException();
}
- mDigestBytes = generateDigest(uri);
- mDigestPrefix =
- mDigestBytes[0] << 24
- | mDigestBytes[1] << 16
- | mDigestBytes[2] << 8
- | mDigestBytes[3] << 0;
+ mDigest = new EphemeralDigest(uri, 0xFFFFFFFF, -1);
mFilters.addAll(filters);
mPackageName = packageName;
}
EphemeralResolveInfo(Parcel in) {
- mDigestBytes = in.createByteArray();
- mDigestPrefix = in.readInt();
+ mDigest = in.readParcelable(null /*loader*/);
mPackageName = in.readString();
in.readList(mFilters, null /*loader*/);
}
public byte[] getDigestBytes() {
- return mDigestBytes;
+ return mDigest.getDigestBytes()[0];
}
public int getDigestPrefix() {
- return mDigestPrefix;
+ return mDigest.getDigestPrefix()[0];
}
public String getPackageName() {
@@ -88,16 +80,6 @@ public final class EphemeralResolveInfo implements Parcelable {
return mFilters;
}
- private static byte[] generateDigest(Uri uri) {
- try {
- final MessageDigest digest = MessageDigest.getInstance(SHA_ALGORITHM);
- final byte[] hostBytes = uri.getHost().getBytes();
- return digest.digest(hostBytes);
- } catch (NoSuchAlgorithmException e) {
- throw new IllegalStateException("could not find digest algorithm");
- }
- }
-
@Override
public int describeContents() {
return 0;
@@ -105,8 +87,7 @@ public final class EphemeralResolveInfo implements Parcelable {
@Override
public void writeToParcel(Parcel out, int flags) {
- out.writeByteArray(mDigestBytes);
- out.writeInt(mDigestPrefix);
+ out.writeParcelable(mDigest, flags);
out.writeString(mPackageName);
out.writeList(mFilters);
}
@@ -136,4 +117,121 @@ public final class EphemeralResolveInfo implements Parcelable {
return mResolveInfo;
}
}
+
+ /**
+ * Helper class to generate and store each of the digests and prefixes
+ * sent to the Ephemeral Resolver.
+ *
+ * Since intent filters may want to handle multiple hosts within a
+ * domain [eg “*.google.com”], the resolver is presented with multiple
+ * hash prefixes. For example, "a.b.c.d.e" generates digests for
+ * "d.e", "c.d.e", "b.c.d.e" and "a.b.c.d.e".
+ *
+ * @hide
+ */
+ public static final class EphemeralDigest implements Parcelable {
+ /** Full digest of the domain hashes */
+ private final byte[][] mDigestBytes;
+ /** The first 4 bytes of the domain hashes */
+ private final int[] mDigestPrefix;
+
+ public EphemeralDigest(@NonNull Uri uri, int digestMask, int maxDigests) {
+ if (uri == null) {
+ throw new IllegalArgumentException();
+ }
+ mDigestBytes = generateDigest(uri, maxDigests);
+ mDigestPrefix = new int[mDigestBytes.length];
+ for (int i = 0; i < mDigestBytes.length; i++) {
+ mDigestPrefix[i] =
+ ((mDigestBytes[i][0] & 0xFF) << 24
+ | (mDigestBytes[i][1] & 0xFF) << 16
+ | (mDigestBytes[i][2] & 0xFF) << 8
+ | (mDigestBytes[i][3] & 0xFF) << 0)
+ & digestMask;
+ }
+ }
+
+ private static byte[][] generateDigest(Uri uri, int maxDigests) {
+ ArrayList digests = new ArrayList<>();
+ try {
+ final String host = uri.getHost().toLowerCase(Locale.ENGLISH);
+ final MessageDigest digest = MessageDigest.getInstance(SHA_ALGORITHM);
+ if (maxDigests <= 0) {
+ final byte[] hostBytes = host.getBytes();
+ digests.add(digest.digest(hostBytes));
+ } else {
+ int prevDot = host.lastIndexOf('.');
+ prevDot = host.lastIndexOf('.', prevDot - 1);
+ // shortcut for short URLs
+ if (prevDot < 0) {
+ digests.add(digest.digest(host.getBytes()));
+ } else {
+ byte[] hostBytes = host.substring(prevDot + 1, host.length()).getBytes();
+ digests.add(digest.digest(hostBytes));
+ int digestCount = 1;
+ while (prevDot >= 0 && digestCount < maxDigests) {
+ prevDot = host.lastIndexOf('.', prevDot - 1);
+ hostBytes = host.substring(prevDot + 1, host.length()).getBytes();
+ digests.add(digest.digest(hostBytes));
+ digestCount++;
+ }
+ }
+ }
+ } catch (NoSuchAlgorithmException e) {
+ throw new IllegalStateException("could not find digest algorithm");
+ }
+ return digests.toArray(new byte[digests.size()][]);
+ }
+
+ EphemeralDigest(Parcel in) {
+ final int digestCount = in.readInt();
+ if (digestCount == -1) {
+ mDigestBytes = null;
+ } else {
+ mDigestBytes = new byte[digestCount][];
+ for (int i = 0; i < digestCount; i++) {
+ mDigestBytes[i] = in.createByteArray();
+ }
+ }
+ mDigestPrefix = in.createIntArray();
+ }
+
+ public byte[][] getDigestBytes() {
+ return mDigestBytes;
+ }
+
+ public int[] getDigestPrefix() {
+ return mDigestPrefix;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ if (mDigestBytes == null) {
+ out.writeInt(-1);
+ } else {
+ out.writeInt(mDigestBytes.length);
+ for (int i = 0; i < mDigestBytes.length; i++) {
+ out.writeByteArray(mDigestBytes[i]);
+ }
+ }
+ out.writeIntArray(mDigestPrefix);
+ }
+
+ @SuppressWarnings("hiding")
+ public static final Parcelable.Creator CREATOR =
+ new Parcelable.Creator() {
+ public EphemeralDigest createFromParcel(Parcel in) {
+ return new EphemeralDigest(in);
+ }
+
+ public EphemeralDigest[] newArray(int size) {
+ return new EphemeralDigest[size];
+ }
+ };
+ }
}
diff --git a/core/java/android/content/pm/IOtaDexopt.aidl b/core/java/android/content/pm/IOtaDexopt.aidl
index 8f38d6f90a7dee961cd0b91530732cce276fef77..467bd5f5e82bddfe34a76a8d7abeed9f41b3e1fc 100644
--- a/core/java/android/content/pm/IOtaDexopt.aidl
+++ b/core/java/android/content/pm/IOtaDexopt.aidl
@@ -41,9 +41,22 @@ interface IOtaDexopt {
*/
boolean isDone();
+ /**
+ * Return the progress (0..1) made in this session. When {@link #isDone() isDone} returns
+ * true, the progress value will be 1.
+ */
+ float getProgress();
+
/**
* Optimize the next package. Note: this command is synchronous, that is, only returns after
* the package has been dexopted (or dexopting failed).
+ *
+ * Note: this will be removed after a transition period. Use nextDexoptCommand instead.
*/
void dexoptNextPackage();
+
+ /**
+ * Get the optimization parameters for the next package.
+ */
+ String nextDexoptCommand();
}
diff --git a/core/java/android/content/pm/IShortcutService.aidl b/core/java/android/content/pm/IShortcutService.aidl
index 2ba24f6eecdbaa4e2e2633bbcf12b89ea3340e70..1bf2ab0abbadafe0aad65f7232201ea413305642 100644
--- a/core/java/android/content/pm/IShortcutService.aidl
+++ b/core/java/android/content/pm/IShortcutService.aidl
@@ -28,6 +28,8 @@ interface IShortcutService {
ParceledListSlice getDynamicShortcuts(String packageName, int userId);
+ ParceledListSlice getManifestShortcuts(String packageName, int userId);
+
boolean addDynamicShortcuts(String packageName, in ParceledListSlice shortcutInfoList,
int userId);
@@ -39,7 +41,12 @@ interface IShortcutService {
boolean updateShortcuts(String packageName, in ParceledListSlice shortcuts, int userId);
- int getMaxDynamicShortcutCount(String packageName, int userId);
+ void disableShortcuts(String packageName, in List shortcutIds, CharSequence disabledMessage,
+ int disabledMessageResId, int userId);
+
+ void enableShortcuts(String packageName, in List shortcutIds, int userId);
+
+ int getMaxShortcutCountPerActivity(String packageName, int userId);
int getRemainingCallCount(String packageName, int userId);
@@ -47,6 +54,8 @@ interface IShortcutService {
int getIconMaxDimensions(String packageName, int userId);
+ void reportShortcutUsed(String packageName, String shortcutId, int userId);
+
void resetThrottling(); // system only API for developer opsions
void onApplicationActive(String packageName, int userId); // system only API for sysUI
diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java
index 8ca27c5e0087905763530df33f53acad750c3b7f..6b23da93bb8623a3e866a702557f97e7433900b3 100644
--- a/core/java/android/content/pm/LauncherApps.java
+++ b/core/java/android/content/pm/LauncherApps.java
@@ -20,11 +20,18 @@ import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.TestApi;
+import android.content.ActivityNotFoundException;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager.ApplicationInfoFlags;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
import android.graphics.Rect;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
@@ -34,8 +41,10 @@ import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
import android.os.UserManager;
+import android.util.DisplayMetrics;
import android.util.Log;
+import java.io.IOException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
@@ -156,18 +165,19 @@ public class LauncherApps {
}
/**
- * Indicates that one or more shortcuts (which may be dynamic and/or pinned)
+ * Indicates that one or more shortcuts of any kind (dynamic, pinned, or manifest)
* have been added, updated or removed.
*
*
Only the applications that are allowed to access the shortcut information,
* as defined in {@link #hasShortcutHostPermission()}, will receive it.
*
* @param packageName The name of the package that has the shortcuts.
- * @param shortcuts all shortcuts from the package (dynamic and/or pinned). Only "key"
- * information will be provided, as defined in {@link ShortcutInfo#hasKeyFieldsOnly()}.
+ * @param shortcuts All shortcuts from the package (dynamic, manifest and/or pinned).
+ * Only "key" information will be provided, as defined in
+ * {@link ShortcutInfo#hasKeyFieldsOnly()}.
* @param user The UserHandle of the profile that generated the change.
*
- * @hide
+ * @see ShortcutManager
*/
public void onShortcutsChanged(@NonNull String packageName,
@NonNull List shortcuts, @NonNull UserHandle user) {
@@ -176,31 +186,68 @@ public class LauncherApps {
/**
* Represents a query passed to {@link #getShortcuts(ShortcutQuery, UserHandle)}.
- *
- * @hide
*/
public static class ShortcutQuery {
/**
* Include dynamic shortcuts in the result.
*/
- public static final int FLAG_GET_DYNAMIC = 1 << 0;
+ public static final int FLAG_MATCH_DYNAMIC = 1 << 0;
+
+ /** @hide kept for unit tests */
+ @Deprecated
+ public static final int FLAG_GET_DYNAMIC = FLAG_MATCH_DYNAMIC;
/**
* Include pinned shortcuts in the result.
*/
- public static final int FLAG_GET_PINNED = 1 << 1;
+ public static final int FLAG_MATCH_PINNED = 1 << 1;
+
+ /** @hide kept for unit tests */
+ @Deprecated
+ public static final int FLAG_GET_PINNED = FLAG_MATCH_PINNED;
/**
- * Requests "key" fields only. See {@link ShortcutInfo#hasKeyFieldsOnly()} for which
- * fields are available.
+ * Include manifest shortcuts in the result.
+ */
+ public static final int FLAG_MATCH_MANIFEST = 1 << 3;
+
+ /** @hide kept for unit tests */
+ @Deprecated
+ public static final int FLAG_GET_MANIFEST = FLAG_MATCH_MANIFEST;
+
+ /** @hide */
+ public static final int FLAG_MATCH_ALL_KINDS =
+ FLAG_GET_DYNAMIC | FLAG_GET_PINNED | FLAG_GET_MANIFEST;
+
+ /** @hide kept for unit tests */
+ @Deprecated
+ public static final int FLAG_GET_ALL_KINDS = FLAG_MATCH_ALL_KINDS;
+
+ /**
+ * Requests "key" fields only. See {@link ShortcutInfo#hasKeyFieldsOnly()}'s javadoc to
+ * see which fields fields "key".
+ * This allows quicker access to shortcut information in order to
+ * determine whether the caller's in-memory cache needs to be updated.
+ *
+ *
Typically, launcher applications cache all or most shortcut information
+ * in memory in order to show shortcuts without a delay.
+ *
+ * When a given launcher application wants to update its cache, such as when its process
+ * restarts, it can fetch shortcut information with this flag.
+ * The application can then check {@link ShortcutInfo#getLastChangedTimestamp()} for each
+ * shortcut, fetching a shortcut's non-key information only if that shortcut has been
+ * updated.
+ *
+ * @see ShortcutManager
*/
public static final int FLAG_GET_KEY_FIELDS_ONLY = 1 << 2;
/** @hide */
@IntDef(flag = true,
value = {
- FLAG_GET_DYNAMIC,
- FLAG_GET_PINNED,
+ FLAG_MATCH_DYNAMIC,
+ FLAG_MATCH_PINNED,
+ FLAG_MATCH_MANIFEST,
FLAG_GET_KEY_FIELDS_ONLY,
})
@Retention(RetentionPolicy.SOURCE)
@@ -224,40 +271,56 @@ public class LauncherApps {
}
/**
- * If non-zero, returns only shortcuts that have been added or updated since the timestamp,
- * which is a milliseconds since the Epoch.
+ * If non-zero, returns only shortcuts that have been added or updated
+ * since the given timestamp, expressed in milliseconds since the Epoch—see
+ * {@link System#currentTimeMillis()}.
*/
- public void setChangedSince(long changedSince) {
+ public ShortcutQuery setChangedSince(long changedSince) {
mChangedSince = changedSince;
+ return this;
}
/**
* If non-null, returns only shortcuts from the package.
*/
- public void setPackage(@Nullable String packageName) {
+ public ShortcutQuery setPackage(@Nullable String packageName) {
mPackage = packageName;
+ return this;
}
/**
* If non-null, return only the specified shortcuts by ID. When setting this field,
- * a packange name must also be set with {@link #setPackage}.
+ * a package name must also be set with {@link #setPackage}.
*/
- public void setShortcutIds(@Nullable List shortcutIds) {
+ public ShortcutQuery setShortcutIds(@Nullable List shortcutIds) {
mShortcutIds = shortcutIds;
+ return this;
}
/**
- * If non-null, returns only shortcuts associated with the activity.
+ * If non-null, returns only shortcuts associated with the activity; i.e.
+ * {@link ShortcutInfo}s whose {@link ShortcutInfo#getActivity()} are equal
+ * to {@code activity}.
*/
- public void setActivity(@Nullable ComponentName activity) {
+ public ShortcutQuery setActivity(@Nullable ComponentName activity) {
mActivity = activity;
+ return this;
}
/**
- * Set query options.
+ * Set query options. At least one of the {@code MATCH} flags should be set. Otherwise,
+ * no shortcuts will be returned.
+ *
+ *
+ *
{@link #FLAG_MATCH_DYNAMIC}
+ *
{@link #FLAG_MATCH_PINNED}
+ *
{@link #FLAG_MATCH_MANIFEST}
+ *
{@link #FLAG_GET_KEY_FIELDS_ONLY}
+ *
*/
- public void setQueryFlags(@QueryFlags int queryFlags) {
+ public ShortcutQuery setQueryFlags(@QueryFlags int queryFlags) {
mQueryFlags = queryFlags;
+ return this;
}
}
@@ -422,12 +485,16 @@ public class LauncherApps {
*
*
Only the default launcher can access the shortcut information.
*
- *
Note when this method returns {@code false}, that may be a temporary situation because
+ *
Note when this method returns {@code false}, it may be a temporary situation because
* the user is trying a new launcher application. The user may decide to change the default
- * launcher to the calling application again, so even if a launcher application loses
+ * launcher back to the calling application again, so even if a launcher application loses
* this permission, it does not have to purge pinned shortcut information.
+ * If the calling launcher application contains pinned shortcuts, they will still work,
+ * even though the caller no longer has the shortcut host permission.
*
- * @hide
+ * @throws IllegalStateException when the user is locked.
+ *
+ * @see ShortcutManager
*/
public boolean hasShortcutHostPermission() {
try {
@@ -438,7 +505,7 @@ public class LauncherApps {
}
/**
- * Returns the IDs of {@link ShortcutInfo}s that match {@code query}.
+ * Returns {@link ShortcutInfo}s that match {@code query}.
*
*
Callers must be allowed to access the shortcut information, as defined in {@link
* #hasShortcutHostPermission()}.
@@ -447,8 +514,10 @@ public class LauncherApps {
* @param user The UserHandle of the profile.
*
* @return the IDs of {@link ShortcutInfo}s that match the query.
+ * @throws IllegalStateException when the user is locked, or when the {@code user} user
+ * is locked or not running.
*
- * @hide
+ * @see ShortcutManager
*/
@Nullable
public List getShortcuts(@NonNull ShortcutQuery query,
@@ -467,12 +536,13 @@ public class LauncherApps {
* @hide // No longer used. Use getShortcuts() instead. Kept for unit tests.
*/
@Nullable
+ @Deprecated
public List getShortcutInfo(@NonNull String packageName,
@NonNull List ids, @NonNull UserHandle user) {
final ShortcutQuery q = new ShortcutQuery();
q.setPackage(packageName);
q.setShortcutIds(ids);
- q.setQueryFlags(ShortcutQuery.FLAG_GET_DYNAMIC | ShortcutQuery.FLAG_GET_PINNED);
+ q.setQueryFlags(ShortcutQuery.FLAG_GET_ALL_KINDS);
return getShortcuts(q, user);
}
@@ -482,14 +552,16 @@ public class LauncherApps {
*
This API is NOT cumulative; this will replace all pinned shortcuts for the package.
* However, different launchers may have different set of pinned shortcuts.
*
- *
Callers must be allowed to access the shortcut information, as defined in {@link
- * #hasShortcutHostPermission()}.
+ *
The calling launcher application must be allowed to access the shortcut information,
+ * as defined in {@link #hasShortcutHostPermission()}.
*
* @param packageName The target package name.
* @param shortcutIds The IDs of the shortcut to be pinned.
* @param user The UserHandle of the profile.
+ * @throws IllegalStateException when the user is locked, or when the {@code user} user
+ * is locked or not running.
*
- * @hide
+ * @see ShortcutManager
*/
public void pinShortcuts(@NonNull String packageName, @NonNull List shortcutIds,
@NonNull UserHandle user) {
@@ -503,6 +575,7 @@ public class LauncherApps {
/**
* @hide kept for testing.
*/
+ @Deprecated
public int getShortcutIconResId(@NonNull ShortcutInfo shortcut) {
return shortcut.getIconResourceId();
}
@@ -510,46 +583,29 @@ public class LauncherApps {
/**
* @hide kept for testing.
*/
+ @Deprecated
public int getShortcutIconResId(@NonNull String packageName, @NonNull String shortcutId,
@NonNull UserHandle user) {
final ShortcutQuery q = new ShortcutQuery();
q.setPackage(packageName);
q.setShortcutIds(Arrays.asList(shortcutId));
- q.setQueryFlags(ShortcutQuery.FLAG_GET_DYNAMIC | ShortcutQuery.FLAG_GET_PINNED);
+ q.setQueryFlags(ShortcutQuery.FLAG_GET_ALL_KINDS);
final List shortcuts = getShortcuts(q, user);
return shortcuts.size() > 0 ? shortcuts.get(0).getIconResourceId() : 0;
}
/**
- * Return the icon as {@link ParcelFileDescriptor}, when it's stored as a file
- * (i.e. when {@link ShortcutInfo#hasIconFile()} returns {@code true}).
- *
- *
Callers must be allowed to access the shortcut information, as defined in {@link
- * #hasShortcutHostPermission()}.
- *
- * @param shortcut The target shortcut.
- *
- * @hide
+ * @hide internal/unit tests only
*/
public ParcelFileDescriptor getShortcutIconFd(
@NonNull ShortcutInfo shortcut) {
- return getShortcutIconFd(shortcut.getPackageName(), shortcut.getId(),
+ return getShortcutIconFd(shortcut.getPackage(), shortcut.getId(),
shortcut.getUserId());
}
/**
- * Return the icon as {@link ParcelFileDescriptor}, when it's stored as a file
- * (i.e. when {@link ShortcutInfo#hasIconFile()} returns {@code true}).
- *
- *
Callers must be allowed to access the shortcut information, as defined in {@link
- * #hasShortcutHostPermission()}.
- *
- * @param packageName The target package name.
- * @param shortcutId The ID of the shortcut to lad rom.
- * @param user The UserHandle of the profile.
- *
- * @hide
+ * @hide internal/unit tests only
*/
public ParcelFileDescriptor getShortcutIconFd(
@NonNull String packageName, @NonNull String shortcutId, @NonNull UserHandle user) {
@@ -567,55 +623,133 @@ public class LauncherApps {
}
/**
- * Launches a shortcut.
+ * Returns the icon for this shortcut, without any badging for the profile.
*
- *
Callers must be allowed to access the shortcut information, as defined in {@link
- * #hasShortcutHostPermission()}.
+ *
The calling launcher application must be allowed to access the shortcut information,
+ * as defined in {@link #hasShortcutHostPermission()}.
+ *
+ * @param density The preferred density of the icon, zero for default density. Use
+ * density DPI values from {@link DisplayMetrics}.
+ *
+ * @return The drawable associated with the shortcut.
+ * @throws IllegalStateException when the user is locked, or when the {@code user} user
+ * is locked or not running.
+ *
+ * @see ShortcutManager
+ * @see #getShortcutBadgedIconDrawable(ShortcutInfo, int)
+ * @see DisplayMetrics
+ */
+ public Drawable getShortcutIconDrawable(@NonNull ShortcutInfo shortcut, int density) {
+ if (shortcut.hasIconFile()) {
+ final ParcelFileDescriptor pfd = getShortcutIconFd(shortcut);
+ if (pfd == null) {
+ return null;
+ }
+ try {
+ final Bitmap bmp = BitmapFactory.decodeFileDescriptor(pfd.getFileDescriptor());
+ return (bmp == null) ? null : new BitmapDrawable(mContext.getResources(), bmp);
+ } finally {
+ try {
+ pfd.close();
+ } catch (IOException ignore) {
+ }
+ }
+ } else if (shortcut.hasIconResource()) {
+ try {
+ final int resId = shortcut.getIconResourceId();
+ if (resId == 0) {
+ return null; // Shouldn't happen but just in case.
+ }
+ final ApplicationInfo ai = getApplicationInfo(shortcut.getPackage(),
+ /* flags =*/ 0, shortcut.getUserHandle());
+ final Resources res = mContext.getPackageManager().getResourcesForApplication(ai);
+ return res.getDrawableForDensity(resId, density);
+ } catch (NameNotFoundException | Resources.NotFoundException e) {
+ return null;
+ }
+ } else {
+ return null; // Has no icon.
+ }
+ }
+
+ /**
+ * Returns the shortcut icon with badging appropriate for the profile.
+ *
+ *
The calling launcher application must be allowed to access the shortcut information,
+ * as defined in {@link #hasShortcutHostPermission()}.
+ *
+ * @param density Optional density for the icon, or 0 to use the default density. Use
+ * @return A badged icon for the shortcut.
+ * @throws IllegalStateException when the user is locked, or when the {@code user} user
+ * is locked or not running.
+ *
+ * @see ShortcutManager
+ * @see #getShortcutIconDrawable(ShortcutInfo, int)
+ * @see DisplayMetrics
+ */
+ public Drawable getShortcutBadgedIconDrawable(ShortcutInfo shortcut, int density) {
+ final Drawable originalIcon = getShortcutIconDrawable(shortcut, density);
+
+ return (originalIcon == null) ? null : mContext.getPackageManager().getUserBadgedIcon(
+ originalIcon, shortcut.getUserHandle());
+ }
+
+ /**
+ * Starts a shortcut.
+ *
+ *
The calling launcher application must be allowed to access the shortcut information,
+ * as defined in {@link #hasShortcutHostPermission()}.
*
* @param packageName The target shortcut package name.
* @param shortcutId The target shortcut ID.
* @param sourceBounds The Rect containing the source bounds of the clicked icon.
* @param startActivityOptions Options to pass to startActivity.
* @param user The UserHandle of the profile.
- * @return {@code false} when the shortcut is no longer valid (e.g. the creator application
- * has been uninstalled). {@code true} when the shortcut is still valid.
+ * @throws IllegalStateException when the user is locked, or when the {@code user} user
+ * is locked or not running.
*
- * @hide
+ * @throws android.content.ActivityNotFoundException failed to start shortcut. (e.g.
+ * the shortcut no longer exists, is disabled, the intent receiver activity doesn't exist, etc)
*/
- public boolean startShortcut(@NonNull String packageName, @NonNull String shortcutId,
+ public void startShortcut(@NonNull String packageName, @NonNull String shortcutId,
@Nullable Rect sourceBounds, @Nullable Bundle startActivityOptions,
@NonNull UserHandle user) {
- return startShortcut(packageName, shortcutId, sourceBounds, startActivityOptions,
+ startShortcut(packageName, shortcutId, sourceBounds, startActivityOptions,
user.getIdentifier());
}
/**
* Launches a shortcut.
*
- *
Callers must be allowed to access the shortcut information, as defined in {@link
- * #hasShortcutHostPermission()}.
+ *
The calling launcher application must be allowed to access the shortcut information,
+ * as defined in {@link #hasShortcutHostPermission()}.
*
* @param shortcut The target shortcut.
* @param sourceBounds The Rect containing the source bounds of the clicked icon.
* @param startActivityOptions Options to pass to startActivity.
- * @return {@code false} when the shortcut is no longer valid (e.g. the creator application
- * has been uninstalled). {@code true} when the shortcut is still valid.
+ * @throws IllegalStateException when the user is locked, or when the {@code user} user
+ * is locked or not running.
*
- * @hide
+ * @throws android.content.ActivityNotFoundException failed to start shortcut. (e.g.
+ * the shortcut no longer exists, is disabled, the intent receiver activity doesn't exist, etc)
*/
- public boolean startShortcut(@NonNull ShortcutInfo shortcut,
+ public void startShortcut(@NonNull ShortcutInfo shortcut,
@Nullable Rect sourceBounds, @Nullable Bundle startActivityOptions) {
- return startShortcut(shortcut.getPackageName(), shortcut.getId(),
+ startShortcut(shortcut.getPackage(), shortcut.getId(),
sourceBounds, startActivityOptions,
shortcut.getUserId());
}
- private boolean startShortcut(@NonNull String packageName, @NonNull String shortcutId,
+ private void startShortcut(@NonNull String packageName, @NonNull String shortcutId,
@Nullable Rect sourceBounds, @Nullable Bundle startActivityOptions,
int userId) {
try {
- return mService.startShortcut(mContext.getPackageName(), packageName, shortcutId,
+ final boolean success =
+ mService.startShortcut(mContext.getPackageName(), packageName, shortcutId,
sourceBounds, startActivityOptions, userId);
+ if (!success) {
+ throw new ActivityNotFoundException("Shortcut could not be started");
+ }
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index dc349bf9b8d903dc17e60a6b705bbbf3c9c6e7e7..3e84a8179e633c4c4592a93dbc7a50238023ead6 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -132,6 +132,9 @@ public abstract class PackageManager {
MATCH_SYSTEM_ONLY,
MATCH_FACTORY_ONLY,
MATCH_DEBUG_TRIAGED_MISSING,
+ GET_DISABLED_COMPONENTS,
+ GET_DISABLED_UNTIL_USED_COMPONENTS,
+ GET_UNINSTALLED_PACKAGES,
})
@Retention(RetentionPolicy.SOURCE)
public @interface PackageInfoFlags {}
@@ -143,6 +146,9 @@ public abstract class PackageManager {
MATCH_UNINSTALLED_PACKAGES,
MATCH_SYSTEM_ONLY,
MATCH_DEBUG_TRIAGED_MISSING,
+ MATCH_DISABLED_UNTIL_USED_COMPONENTS,
+ GET_DISABLED_UNTIL_USED_COMPONENTS,
+ GET_UNINSTALLED_PACKAGES,
})
@Retention(RetentionPolicy.SOURCE)
public @interface ApplicationInfoFlags {}
@@ -160,6 +166,9 @@ public abstract class PackageManager {
MATCH_DIRECT_BOOT_UNAWARE,
MATCH_SYSTEM_ONLY,
MATCH_UNINSTALLED_PACKAGES,
+ GET_DISABLED_COMPONENTS,
+ GET_DISABLED_UNTIL_USED_COMPONENTS,
+ GET_UNINSTALLED_PACKAGES,
})
@Retention(RetentionPolicy.SOURCE)
public @interface ComponentInfoFlags {}
@@ -178,6 +187,9 @@ public abstract class PackageManager {
MATCH_DIRECT_BOOT_UNAWARE,
MATCH_SYSTEM_ONLY,
MATCH_UNINSTALLED_PACKAGES,
+ GET_DISABLED_COMPONENTS,
+ GET_DISABLED_UNTIL_USED_COMPONENTS,
+ GET_UNINSTALLED_PACKAGES,
})
@Retention(RetentionPolicy.SOURCE)
public @interface ResolveInfoFlags {}
@@ -2883,6 +2895,7 @@ public abstract class PackageManager {
*
* @see #GET_META_DATA
* @see #GET_SHARED_LIBRARY_FILES
+ * @see #MATCH_DISABLED_UNTIL_USED_COMPONENTS
* @see #MATCH_SYSTEM_ONLY
* @see #MATCH_UNINSTALLED_PACKAGES
*/
@@ -3511,6 +3524,7 @@ public abstract class PackageManager {
*
* @see #GET_META_DATA
* @see #GET_SHARED_LIBRARY_FILES
+ * @see #MATCH_DISABLED_UNTIL_USED_COMPONENTS
* @see #MATCH_SYSTEM_ONLY
* @see #MATCH_UNINSTALLED_PACKAGES
*/
diff --git a/core/java/android/content/pm/PackageManagerInternal.java b/core/java/android/content/pm/PackageManagerInternal.java
index 14f7727e61a02daaeb5ac9bbfd08789b35098812..d208fe7c10ca1c5f8bac3b1daba4d68313866ad1 100644
--- a/core/java/android/content/pm/PackageManagerInternal.java
+++ b/core/java/android/content/pm/PackageManagerInternal.java
@@ -157,7 +157,7 @@ public abstract class PackageManagerInternal {
int deviceOwnerUserId, String deviceOwner, SparseArray profileOwners);
/**
- * Whether a package's data be cleared.
+ * Returns {@code true} if a given package can't be wiped. Otherwise, returns {@code false}.
*/
- public abstract boolean canPackageBeWiped(int userId, String packageName);
+ public abstract boolean isPackageDataProtected(int userId, String packageName);
}
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index a4601d2ccf3324449d72aee362b75e755be5c0d5..f2e3333b67da98d79de3b0f8473425f53c4d0e9c 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -274,6 +274,7 @@ public class PackageParser {
final int nameRes;
final int labelRes;
final int iconRes;
+ final int roundIconRes;
final int logoRes;
final int bannerRes;
@@ -281,7 +282,8 @@ public class PackageParser {
TypedArray sa;
ParsePackageItemArgs(Package _owner, String[] _outError,
- int _nameRes, int _labelRes, int _iconRes, int _logoRes, int _bannerRes) {
+ int _nameRes, int _labelRes, int _iconRes, int _roundIconRes, int _logoRes,
+ int _bannerRes) {
owner = _owner;
outError = _outError;
nameRes = _nameRes;
@@ -289,6 +291,7 @@ public class PackageParser {
iconRes = _iconRes;
logoRes = _logoRes;
bannerRes = _bannerRes;
+ roundIconRes = _roundIconRes;
}
}
@@ -300,10 +303,12 @@ public class PackageParser {
int flags;
ParseComponentArgs(Package _owner, String[] _outError,
- int _nameRes, int _labelRes, int _iconRes, int _logoRes, int _bannerRes,
+ int _nameRes, int _labelRes, int _iconRes, int _roundIconRes, int _logoRes,
+ int _bannerRes,
String[] _sepProcesses, int _processRes,
int _descriptionRes, int _enabledRes) {
- super(_owner, _outError, _nameRes, _labelRes, _iconRes, _logoRes, _bannerRes);
+ super(_owner, _outError, _nameRes, _labelRes, _iconRes, _roundIconRes, _logoRes,
+ _bannerRes);
sepProcesses = _sepProcesses;
processRes = _processRes;
descriptionRes = _descriptionRes;
@@ -2338,11 +2343,7 @@ public class PackageParser {
b.append(cls);
return b.toString().intern();
}
- if (c >= 'a' && c <= 'z') {
- return cls.intern();
- }
- outError[0] = "Bad class name " + cls + " in package " + pkg;
- return null;
+ return cls.intern();
}
private static String buildCompoundName(String pkg,
@@ -2556,12 +2557,12 @@ public class PackageParser {
TypedArray sa = res.obtainAttributes(parser,
com.android.internal.R.styleable.AndroidManifestPermissionGroup);
-
if (!parsePackageItemInfo(owner, perm.info, outError,
- "", sa,
+ "", sa, true /*nameRequired*/,
com.android.internal.R.styleable.AndroidManifestPermissionGroup_name,
com.android.internal.R.styleable.AndroidManifestPermissionGroup_label,
com.android.internal.R.styleable.AndroidManifestPermissionGroup_icon,
+ com.android.internal.R.styleable.AndroidManifestPermissionGroup_roundIcon,
com.android.internal.R.styleable.AndroidManifestPermissionGroup_logo,
com.android.internal.R.styleable.AndroidManifestPermissionGroup_banner)) {
sa.recycle();
@@ -2602,10 +2603,11 @@ public class PackageParser {
com.android.internal.R.styleable.AndroidManifestPermission);
if (!parsePackageItemInfo(owner, perm.info, outError,
- "", sa,
+ "", sa, true /*nameRequired*/,
com.android.internal.R.styleable.AndroidManifestPermission_name,
com.android.internal.R.styleable.AndroidManifestPermission_label,
com.android.internal.R.styleable.AndroidManifestPermission_icon,
+ com.android.internal.R.styleable.AndroidManifestPermission_roundIcon,
com.android.internal.R.styleable.AndroidManifestPermission_logo,
com.android.internal.R.styleable.AndroidManifestPermission_banner)) {
sa.recycle();
@@ -2675,10 +2677,11 @@ public class PackageParser {
com.android.internal.R.styleable.AndroidManifestPermissionTree);
if (!parsePackageItemInfo(owner, perm.info, outError,
- "", sa,
+ "", sa, true /*nameRequired*/,
com.android.internal.R.styleable.AndroidManifestPermissionTree_name,
com.android.internal.R.styleable.AndroidManifestPermissionTree_label,
com.android.internal.R.styleable.AndroidManifestPermissionTree_icon,
+ com.android.internal.R.styleable.AndroidManifestPermissionTree_roundIcon,
com.android.internal.R.styleable.AndroidManifestPermissionTree_logo,
com.android.internal.R.styleable.AndroidManifestPermissionTree_banner)) {
sa.recycle();
@@ -2725,6 +2728,7 @@ public class PackageParser {
com.android.internal.R.styleable.AndroidManifestInstrumentation_name,
com.android.internal.R.styleable.AndroidManifestInstrumentation_label,
com.android.internal.R.styleable.AndroidManifestInstrumentation_icon,
+ com.android.internal.R.styleable.AndroidManifestInstrumentation_roundIcon,
com.android.internal.R.styleable.AndroidManifestInstrumentation_logo,
com.android.internal.R.styleable.AndroidManifestInstrumentation_banner);
mParseInstrumentationArgs.tag = "";
@@ -2790,15 +2794,21 @@ public class PackageParser {
TypedArray sa = res.obtainAttributes(parser,
com.android.internal.R.styleable.AndroidManifestApplication);
- String name = sa.getNonConfigurationString(
- com.android.internal.R.styleable.AndroidManifestApplication_name, 0);
- if (name != null) {
- ai.className = buildClassName(pkgName, name, outError);
- if (ai.className == null) {
- sa.recycle();
- mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
- return false;
- }
+ if (!parsePackageItemInfo(owner, ai, outError,
+ "", sa, false /*nameRequired*/,
+ com.android.internal.R.styleable.AndroidManifestApplication_name,
+ com.android.internal.R.styleable.AndroidManifestApplication_label,
+ com.android.internal.R.styleable.AndroidManifestApplication_icon,
+ com.android.internal.R.styleable.AndroidManifestApplication_roundIcon,
+ com.android.internal.R.styleable.AndroidManifestApplication_logo,
+ com.android.internal.R.styleable.AndroidManifestApplication_banner)) {
+ sa.recycle();
+ mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
+ return false;
+ }
+
+ if (ai.name != null) {
+ ai.className = ai.name;
}
String manageSpaceActivity = sa.getNonConfigurationString(
@@ -2864,18 +2874,6 @@ public class PackageParser {
}
}
- TypedValue v = sa.peekValue(
- com.android.internal.R.styleable.AndroidManifestApplication_label);
- if (v != null && (ai.labelRes=v.resourceId) == 0) {
- ai.nonLocalizedLabel = v.coerceToString();
- }
-
- ai.icon = sa.getResourceId(
- com.android.internal.R.styleable.AndroidManifestApplication_icon, 0);
- ai.logo = sa.getResourceId(
- com.android.internal.R.styleable.AndroidManifestApplication_logo, 0);
- ai.banner = sa.getResourceId(
- com.android.internal.R.styleable.AndroidManifestApplication_banner, 0);
ai.theme = sa.getResourceId(
com.android.internal.R.styleable.AndroidManifestApplication_theme, 0);
ai.descriptionRes = sa.getResourceId(
@@ -3389,25 +3387,35 @@ public class PackageParser {
return true;
}
- private boolean parsePackageItemInfo(Package owner, PackageItemInfo outInfo,
- String[] outError, String tag, TypedArray sa,
- int nameRes, int labelRes, int iconRes, int logoRes, int bannerRes) {
+ private static boolean parsePackageItemInfo(Package owner, PackageItemInfo outInfo,
+ String[] outError, String tag, TypedArray sa, boolean nameRequired,
+ int nameRes, int labelRes, int iconRes, int roundIconRes, int logoRes, int bannerRes) {
String name = sa.getNonConfigurationString(nameRes, 0);
if (name == null) {
- outError[0] = tag + " does not specify android:name";
- return false;
- }
-
- outInfo.name
- = buildClassName(owner.applicationInfo.packageName, name, outError);
- if (outInfo.name == null) {
- return false;
+ if (nameRequired) {
+ outError[0] = tag + " does not specify android:name";
+ return false;
+ }
+ } else {
+ outInfo.name
+ = buildClassName(owner.applicationInfo.packageName, name, outError);
+ if (outInfo.name == null) {
+ return false;
+ }
}
- int iconVal = sa.getResourceId(iconRes, 0);
- if (iconVal != 0) {
- outInfo.icon = iconVal;
+ final boolean useRoundIcon =
+ Resources.getSystem().getBoolean(com.android.internal.R.bool.config_useRoundIcon);
+ int roundIconVal = useRoundIcon ? sa.getResourceId(roundIconRes, 0) : 0;
+ if (roundIconVal != 0) {
+ outInfo.icon = roundIconVal;
outInfo.nonLocalizedLabel = null;
+ } else {
+ int iconVal = sa.getResourceId(iconRes, 0);
+ if (iconVal != 0) {
+ outInfo.icon = iconVal;
+ outInfo.nonLocalizedLabel = null;
+ }
}
int logoVal = sa.getResourceId(logoRes, 0);
@@ -3441,6 +3449,7 @@ public class PackageParser {
R.styleable.AndroidManifestActivity_name,
R.styleable.AndroidManifestActivity_label,
R.styleable.AndroidManifestActivity_icon,
+ R.styleable.AndroidManifestActivity_roundIcon,
R.styleable.AndroidManifestActivity_logo,
R.styleable.AndroidManifestActivity_banner,
mSeparateProcesses,
@@ -3815,6 +3824,7 @@ public class PackageParser {
com.android.internal.R.styleable.AndroidManifestActivityAlias_name,
com.android.internal.R.styleable.AndroidManifestActivityAlias_label,
com.android.internal.R.styleable.AndroidManifestActivityAlias_icon,
+ com.android.internal.R.styleable.AndroidManifestActivityAlias_roundIcon,
com.android.internal.R.styleable.AndroidManifestActivityAlias_logo,
com.android.internal.R.styleable.AndroidManifestActivityAlias_banner,
mSeparateProcesses,
@@ -3969,6 +3979,7 @@ public class PackageParser {
com.android.internal.R.styleable.AndroidManifestProvider_name,
com.android.internal.R.styleable.AndroidManifestProvider_label,
com.android.internal.R.styleable.AndroidManifestProvider_icon,
+ com.android.internal.R.styleable.AndroidManifestProvider_roundIcon,
com.android.internal.R.styleable.AndroidManifestProvider_logo,
com.android.internal.R.styleable.AndroidManifestProvider_banner,
mSeparateProcesses,
@@ -4288,6 +4299,7 @@ public class PackageParser {
com.android.internal.R.styleable.AndroidManifestService_name,
com.android.internal.R.styleable.AndroidManifestService_label,
com.android.internal.R.styleable.AndroidManifestService_icon,
+ com.android.internal.R.styleable.AndroidManifestService_roundIcon,
com.android.internal.R.styleable.AndroidManifestService_logo,
com.android.internal.R.styleable.AndroidManifestService_banner,
mSeparateProcesses,
@@ -4604,8 +4616,16 @@ public class PackageParser {
outInfo.nonLocalizedLabel = v.coerceToString();
}
- outInfo.icon = sa.getResourceId(
- com.android.internal.R.styleable.AndroidManifestIntentFilter_icon, 0);
+ final boolean useRoundIcon =
+ Resources.getSystem().getBoolean(com.android.internal.R.bool.config_useRoundIcon);
+ int roundIconVal = useRoundIcon ? sa.getResourceId(
+ com.android.internal.R.styleable.AndroidManifestIntentFilter_roundIcon, 0) : 0;
+ if (roundIconVal != 0) {
+ outInfo.icon = roundIconVal;
+ } else {
+ outInfo.icon = sa.getResourceId(
+ com.android.internal.R.styleable.AndroidManifestIntentFilter_icon, 0);
+ }
outInfo.logo = sa.getResourceId(
com.android.internal.R.styleable.AndroidManifestIntentFilter_logo, 0);
@@ -5237,45 +5257,13 @@ public class PackageParser {
public Component(final ParsePackageItemArgs args, final PackageItemInfo outInfo) {
owner = args.owner;
intents = new ArrayList(0);
- String name = args.sa.getNonConfigurationString(args.nameRes, 0);
- if (name == null) {
- className = null;
- args.outError[0] = args.tag + " does not specify android:name";
- return;
- }
-
- outInfo.name
- = buildClassName(owner.applicationInfo.packageName, name, args.outError);
- if (outInfo.name == null) {
+ if (parsePackageItemInfo(args.owner, outInfo, args.outError, args.tag, args.sa,
+ true /*nameRequired*/, args.nameRes, args.labelRes, args.iconRes,
+ args.roundIconRes, args.logoRes, args.bannerRes)) {
+ className = outInfo.name;
+ } else {
className = null;
- args.outError[0] = args.tag + " does not have valid android:name";
- return;
}
-
- className = outInfo.name;
-
- int iconVal = args.sa.getResourceId(args.iconRes, 0);
- if (iconVal != 0) {
- outInfo.icon = iconVal;
- outInfo.nonLocalizedLabel = null;
- }
-
- int logoVal = args.sa.getResourceId(args.logoRes, 0);
- if (logoVal != 0) {
- outInfo.logo = logoVal;
- }
-
- int bannerVal = args.sa.getResourceId(args.bannerRes, 0);
- if (bannerVal != 0) {
- outInfo.banner = bannerVal;
- }
-
- TypedValue v = args.sa.peekValue(args.labelRes);
- if (v != null && (outInfo.labelRes=v.resourceId) == 0) {
- outInfo.nonLocalizedLabel = v.coerceToString();
- }
-
- outInfo.packageName = owner.packageName;
}
public Component(final ParseComponentArgs args, final ComponentInfo outInfo) {
diff --git a/core/java/android/content/pm/RegisteredServicesCache.java b/core/java/android/content/pm/RegisteredServicesCache.java
index 6162d1aeeceb7676ab00d9432d3e27cec3d232a1..a1103838280c0826f14c978be2c1ffa117867ab8 100644
--- a/core/java/android/content/pm/RegisteredServicesCache.java
+++ b/core/java/android/content/pm/RegisteredServicesCache.java
@@ -30,6 +30,7 @@ import android.os.UserHandle;
import android.os.UserManager;
import android.util.AtomicFile;
import android.util.AttributeSet;
+import android.util.IntArray;
import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
@@ -54,6 +55,7 @@ import java.io.InputStream;
import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
@@ -344,6 +346,47 @@ public abstract class RegisteredServicesCache {
}
}
+ public void updateServices(int userId) {
+ if (DEBUG) {
+ Slog.d(TAG, "updateServices u" + userId);
+ }
+ List> allServices;
+ synchronized (mServicesLock) {
+ final UserServices user = findOrCreateUserLocked(userId);
+ // If services haven't been initialized yet - no updates required
+ if (user.services == null) {
+ return;
+ }
+ allServices = new ArrayList<>(user.services.values());
+ }
+ IntArray updatedUids = null;
+ for (ServiceInfo service : allServices) {
+ int versionCode = service.componentInfo.applicationInfo.versionCode;
+ String pkg = service.componentInfo.packageName;
+ ApplicationInfo newAppInfo = null;
+ try {
+ newAppInfo = mContext.getPackageManager().getApplicationInfoAsUser(pkg, 0, userId);
+ } catch (NameNotFoundException e) {
+ // Package uninstalled - treat as null app info
+ }
+ // If package updated or removed
+ if ((newAppInfo == null) || (newAppInfo.versionCode != versionCode)) {
+ if (DEBUG) {
+ Slog.d(TAG, "Package " + pkg + " uid=" + service.uid
+ + " updated. New appInfo: " + newAppInfo);
+ }
+ if (updatedUids == null) {
+ updatedUids = new IntArray();
+ }
+ updatedUids.add(service.uid);
+ }
+ }
+ if (updatedUids != null && updatedUids.size() > 0) {
+ int[] updatedUidsArray = updatedUids.toArray();
+ generateServicesMap(updatedUidsArray, userId);
+ }
+ }
+
@VisibleForTesting
protected boolean inSystemImage(int callerUid) {
String[] packages = mContext.getPackageManager().getPackagesForUid(callerUid);
@@ -379,10 +422,11 @@ public abstract class RegisteredServicesCache {
*/
private void generateServicesMap(int[] changedUids, int userId) {
if (DEBUG) {
- Slog.d(TAG, "generateServicesMap() for " + userId + ", changed UIDs = " + changedUids);
+ Slog.d(TAG, "generateServicesMap() for " + userId + ", changed UIDs = "
+ + Arrays.toString(changedUids));
}
- final ArrayList> serviceInfos = new ArrayList>();
+ final ArrayList> serviceInfos = new ArrayList<>();
final List resolveInfos = queryIntentServices(userId);
for (ResolveInfo resolveInfo : resolveInfos) {
try {
diff --git a/core/java/android/content/pm/ShortcutInfo.java b/core/java/android/content/pm/ShortcutInfo.java
index 4340d04cee69fab8ae3e34ec397a32aced99eb48..ed0ac53861764dc4f2d6b0814a8f60f19f34bf9b 100644
--- a/core/java/android/content/pm/ShortcutInfo.java
+++ b/core/java/android/content/pm/ShortcutInfo.java
@@ -19,56 +19,78 @@ import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
+import android.app.TaskStackBuilder;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.LauncherApps.ShortcutQuery;
+import android.content.res.Resources;
+import android.content.res.Resources.NotFoundException;
+import android.graphics.Bitmap;
import android.graphics.drawable.Icon;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.PersistableBundle;
import android.os.UserHandle;
+import android.text.TextUtils;
import android.util.ArraySet;
+import android.util.Log;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.Preconditions;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.List;
import java.util.Set;
-// TODO Enhance javadoc
/**
+ * Represents a "launcher shortcut" that can be published via {@link ShortcutManager}.
*
- * Represents a shortcut from an application.
- *
- *
Notes about icons:
- *
- *
If an {@link Icon} is a resource, the system keeps the package name and the resource ID.
- * Otherwise, the bitmap is fetched when it's registered to ShortcutManager,
- * then shrunk if necessary, and persisted.
- *
The system disallows byte[] icons, because they can easily go over the binder size limit.
- *
- *
- * @see {@link ShortcutManager}.
- *
- * @hide
+ * @see ShortcutManager
*/
public final class ShortcutInfo implements Parcelable {
- /* @hide */
+ static final String TAG = "Shortcut";
+
+ private static final String RES_TYPE_STRING = "string";
+
+ private static final String ANDROID_PACKAGE_NAME = "android";
+
+ private static final int IMPLICIT_RANK_MASK = 0x7fffffff;
+
+ private static final int RANK_CHANGED_BIT = ~IMPLICIT_RANK_MASK;
+
+ /** @hide */
+ public static final int RANK_NOT_SET = Integer.MAX_VALUE;
+
+ /** @hide */
public static final int FLAG_DYNAMIC = 1 << 0;
- /* @hide */
+ /** @hide */
public static final int FLAG_PINNED = 1 << 1;
- /* @hide */
+ /** @hide */
public static final int FLAG_HAS_ICON_RES = 1 << 2;
- /* @hide */
+ /** @hide */
public static final int FLAG_HAS_ICON_FILE = 1 << 3;
- /* @hide */
+ /** @hide */
public static final int FLAG_KEY_FIELDS_ONLY = 1 << 4;
+ /** @hide */
+ public static final int FLAG_MANIFEST = 1 << 5;
+
+ /** @hide */
+ public static final int FLAG_DISABLED = 1 << 6;
+
+ /** @hide */
+ public static final int FLAG_STRINGS_RESOLVED = 1 << 7;
+
+ /** @hide */
+ public static final int FLAG_IMMUTABLE = 1 << 8;
+
/** @hide */
@IntDef(flag = true,
value = {
@@ -77,26 +99,34 @@ public final class ShortcutInfo implements Parcelable {
FLAG_HAS_ICON_RES,
FLAG_HAS_ICON_FILE,
FLAG_KEY_FIELDS_ONLY,
+ FLAG_MANIFEST,
+ FLAG_DISABLED,
+ FLAG_STRINGS_RESOLVED,
+ FLAG_IMMUTABLE,
})
@Retention(RetentionPolicy.SOURCE)
public @interface ShortcutFlags {}
// Cloning options.
- /* @hide */
+ /** @hide */
private static final int CLONE_REMOVE_ICON = 1 << 0;
- /* @hide */
+ /** @hide */
private static final int CLONE_REMOVE_INTENT = 1 << 1;
- /* @hide */
+ /** @hide */
public static final int CLONE_REMOVE_NON_KEY_INFO = 1 << 2;
- /* @hide */
- public static final int CLONE_REMOVE_FOR_CREATOR = CLONE_REMOVE_ICON;
+ /** @hide */
+ public static final int CLONE_REMOVE_RES_NAMES = 1 << 3;
+
+ /** @hide */
+ public static final int CLONE_REMOVE_FOR_CREATOR = CLONE_REMOVE_ICON | CLONE_REMOVE_RES_NAMES;
- /* @hide */
- public static final int CLONE_REMOVE_FOR_LAUNCHER = CLONE_REMOVE_ICON | CLONE_REMOVE_INTENT;
+ /** @hide */
+ public static final int CLONE_REMOVE_FOR_LAUNCHER = CLONE_REMOVE_ICON | CLONE_REMOVE_INTENT
+ | CLONE_REMOVE_RES_NAMES;
/** @hide */
@IntDef(flag = true,
@@ -104,6 +134,7 @@ public final class ShortcutInfo implements Parcelable {
CLONE_REMOVE_ICON,
CLONE_REMOVE_INTENT,
CLONE_REMOVE_NON_KEY_INFO,
+ CLONE_REMOVE_RES_NAMES,
CLONE_REMOVE_FOR_CREATOR,
CLONE_REMOVE_FOR_LAUNCHER
})
@@ -111,7 +142,7 @@ public final class ShortcutInfo implements Parcelable {
public @interface CloneFlags {}
/**
- * Shortcut category for
+ * Shortcut category for messaging related actions, such as chat.
*/
public static final String SHORTCUT_CATEGORY_CONVERSATION = "android.shortcut.conversation";
@@ -121,33 +152,57 @@ public final class ShortcutInfo implements Parcelable {
private final String mPackageName;
@Nullable
- private ComponentName mActivityComponent;
+ private ComponentName mActivity;
@Nullable
private Icon mIcon;
- @NonNull
- private String mTitle;
+ private int mTitleResId;
+
+ private String mTitleResName;
@Nullable
- private String mText;
+ private CharSequence mTitle;
- @NonNull
+ private int mTextResId;
+
+ private String mTextResName;
+
+ @Nullable
+ private CharSequence mText;
+
+ private int mDisabledMessageResId;
+
+ private String mDisabledMessageResName;
+
+ @Nullable
+ private CharSequence mDisabledMessage;
+
+ @Nullable
private ArraySet mCategories;
/**
- * Intent *with extras removed*.
+ * Intents *with extras removed*.
*/
- @NonNull
- private Intent mIntent;
+ @Nullable
+ private Intent[] mIntents;
/**
- * Extras for the intent.
+ * Extras for the intents.
*/
- @NonNull
- private PersistableBundle mIntentPersistableExtras;
+ @Nullable
+ private PersistableBundle[] mIntentPersistableExtrases;
- private int mWeight;
+ private int mRank;
+
+ /**
+ * Internally used for auto-rank-adjustment.
+ *
+ * RANK_CHANGED_BIT is used to denote that the rank of a shortcut is changing.
+ * The rest of the bits are used to denote the order in which shortcuts are passed to
+ * APIs, which is used to preserve the argument order when ranks are tie.
+ */
+ private int mImplicitRank;
@Nullable
private PersistableBundle mExtras;
@@ -159,7 +214,9 @@ public final class ShortcutInfo implements Parcelable {
private int mFlags;
// Internal use only.
- private int mIconResourceId;
+ private int mIconResId;
+
+ private String mIconResName;
// Internal use only.
@Nullable
@@ -175,26 +232,81 @@ public final class ShortcutInfo implements Parcelable {
// Note we can't do other null checks here because SM.updateShortcuts() takes partial
// information.
mPackageName = b.mContext.getPackageName();
- mActivityComponent = b.mActivityComponent;
+ mActivity = b.mActivity;
mIcon = b.mIcon;
mTitle = b.mTitle;
+ mTitleResId = b.mTitleResId;
mText = b.mText;
- mCategories = clone(b.mCategories);
- mIntent = b.mIntent;
- if (mIntent != null) {
- final Bundle intentExtras = mIntent.getExtras();
- if (intentExtras != null) {
- mIntent.replaceExtras((Bundle) null);
- mIntentPersistableExtras = new PersistableBundle(intentExtras);
- }
- }
- mWeight = b.mWeight;
+ mTextResId = b.mTextResId;
+ mDisabledMessage = b.mDisabledMessage;
+ mDisabledMessageResId = b.mDisabledMessageResId;
+ mCategories = cloneCategories(b.mCategories);
+ mIntents = cloneIntents(b.mIntents);
+ fixUpIntentExtras();
+ mRank = b.mRank;
mExtras = b.mExtras;
updateTimestamp();
}
- private ArraySet clone(Set source) {
- return (source == null) ? null : new ArraySet<>(source);
+ /**
+ * Extract extras from {@link #mIntents} and set them to {@link #mIntentPersistableExtrases}
+ * as {@link PersistableBundle}, and remove extras from the original intents.
+ */
+ private void fixUpIntentExtras() {
+ if (mIntents == null) {
+ mIntentPersistableExtrases = null;
+ return;
+ }
+ mIntentPersistableExtrases = new PersistableBundle[mIntents.length];
+ for (int i = 0; i < mIntents.length; i++) {
+ final Intent intent = mIntents[i];
+ final Bundle extras = intent.getExtras();
+ if (extras == null) {
+ mIntentPersistableExtrases[i] = null;
+ } else {
+ mIntentPersistableExtrases[i] = new PersistableBundle(extras);
+ intent.replaceExtras((Bundle) null);
+ }
+ }
+ }
+
+ private static ArraySet cloneCategories(Set source) {
+ if (source == null) {
+ return null;
+ }
+ final ArraySet ret = new ArraySet<>(source.size());
+ for (CharSequence s : source) {
+ if (!TextUtils.isEmpty(s)) {
+ ret.add(s.toString().intern());
+ }
+ }
+ return ret;
+ }
+
+ private static Intent[] cloneIntents(Intent[] intents) {
+ if (intents == null) {
+ return null;
+ }
+ final Intent[] ret = new Intent[intents.length];
+ for (int i = 0; i < ret.length; i++) {
+ if (intents[i] != null) {
+ ret[i] = new Intent(intents[i]);
+ }
+ }
+ return ret;
+ }
+
+ private static PersistableBundle[] clonePersistableBundle(PersistableBundle[] bundle) {
+ if (bundle == null) {
+ return null;
+ }
+ final PersistableBundle[] ret = new PersistableBundle[bundle.length];
+ for (int i = 0; i < ret.length; i++) {
+ if (bundle[i] != null) {
+ ret[i] = new PersistableBundle(bundle[i]);
+ }
+ }
+ return ret;
}
/**
@@ -204,8 +316,12 @@ public final class ShortcutInfo implements Parcelable {
*/
public void enforceMandatoryFields() {
Preconditions.checkStringNotEmpty(mId, "Shortcut ID must be provided");
- Preconditions.checkStringNotEmpty(mTitle, "Shortcut title must be provided");
- Preconditions.checkNotNull(mIntent, "Shortcut Intent must be provided");
+ Preconditions.checkNotNull(mActivity, "Activity must be provided");
+ if (mTitle == null && mTitleResId == 0) {
+ throw new IllegalArgumentException("Short label must be provided");
+ }
+ Preconditions.checkNotNull(mIntents, "Shortcut Intent must be provided");
+ Preconditions.checkArgument(mIntents.length > 0, "Shortcut Intent must be provided");
}
/**
@@ -215,14 +331,14 @@ public final class ShortcutInfo implements Parcelable {
mUserId = source.mUserId;
mId = source.mId;
mPackageName = source.mPackageName;
+ mActivity = source.mActivity;
mFlags = source.mFlags;
mLastChangedTimestamp = source.mLastChangedTimestamp;
// Just always keep it since it's cheep.
- mIconResourceId = source.mIconResourceId;
+ mIconResId = source.mIconResId;
if ((cloneFlags & CLONE_REMOVE_NON_KEY_INFO) == 0) {
- mActivityComponent = source.mActivityComponent;
if ((cloneFlags & CLONE_REMOVE_ICON) == 0) {
mIcon = source.mIcon;
@@ -230,20 +346,247 @@ public final class ShortcutInfo implements Parcelable {
}
mTitle = source.mTitle;
+ mTitleResId = source.mTitleResId;
mText = source.mText;
- mCategories = clone(source.mCategories);
+ mTextResId = source.mTextResId;
+ mDisabledMessage = source.mDisabledMessage;
+ mDisabledMessageResId = source.mDisabledMessageResId;
+ mCategories = cloneCategories(source.mCategories);
if ((cloneFlags & CLONE_REMOVE_INTENT) == 0) {
- mIntent = source.mIntent;
- mIntentPersistableExtras = source.mIntentPersistableExtras;
+ mIntents = cloneIntents(source.mIntents);
+ mIntentPersistableExtrases =
+ clonePersistableBundle(source.mIntentPersistableExtrases);
}
- mWeight = source.mWeight;
+ mRank = source.mRank;
mExtras = source.mExtras;
+
+ if ((cloneFlags & CLONE_REMOVE_RES_NAMES) == 0) {
+ mTitleResName = source.mTitleResName;
+ mTextResName = source.mTextResName;
+ mDisabledMessageResName = source.mDisabledMessageResName;
+ mIconResName = source.mIconResName;
+ }
} else {
// Set this bit.
mFlags |= FLAG_KEY_FIELDS_ONLY;
}
}
+ /**
+ * Load a string resource from the publisher app.
+ *
+ * @param resId resource ID
+ * @param defValue default value to be returned when the specified resource isn't found.
+ */
+ private CharSequence getResourceString(Resources res, int resId, CharSequence defValue) {
+ try {
+ return res.getString(resId);
+ } catch (NotFoundException e) {
+ Log.e(TAG, "Resource for ID=" + resId + " not found in package " + mPackageName);
+ return defValue;
+ }
+ }
+
+ /**
+ * Load the string resources for the text fields and set them to the actual value fields.
+ * This will set {@link #FLAG_STRINGS_RESOLVED}.
+ *
+ * @param res {@link Resources} for the publisher. Must have been loaded with
+ * {@link PackageManager#getResourcesForApplicationAsUser}.
+ *
+ * @hide
+ */
+ public void resolveResourceStrings(@NonNull Resources res) {
+ mFlags |= FLAG_STRINGS_RESOLVED;
+
+ if ((mTitleResId == 0) && (mTextResId == 0) && (mDisabledMessageResId == 0)) {
+ return; // Bail early.
+ }
+
+ if (mTitleResId != 0) {
+ mTitle = getResourceString(res, mTitleResId, mTitle);
+ }
+ if (mTextResId != 0) {
+ mText = getResourceString(res, mTextResId, mText);
+ }
+ if (mDisabledMessageResId != 0) {
+ mDisabledMessage = getResourceString(res, mDisabledMessageResId, mDisabledMessage);
+ }
+ }
+
+ /**
+ * Look up resource name for a given resource ID.
+ *
+ * @return a simple resource name (e.g. "text_1") when {@code withType} is false, or with the
+ * type (e.g. "string/text_1").
+ *
+ * @hide
+ */
+ @VisibleForTesting
+ public static String lookUpResourceName(@NonNull Resources res, int resId, boolean withType,
+ @NonNull String packageName) {
+ if (resId == 0) {
+ return null;
+ }
+ try {
+ final String fullName = res.getResourceName(resId);
+
+ if (ANDROID_PACKAGE_NAME.equals(getResourcePackageName(fullName))) {
+ // If it's a framework resource, the value won't change, so just return the ID
+ // value as a string.
+ return String.valueOf(resId);
+ }
+ return withType ? getResourceTypeAndEntryName(fullName)
+ : getResourceEntryName(fullName);
+ } catch (NotFoundException e) {
+ Log.e(TAG, "Resource name for ID=" + resId + " not found in package " + packageName
+ + ". Resource IDs may change when the application is upgraded, and the system"
+ + " may not be able to find the correct resource.");
+ return null;
+ }
+ }
+
+ /**
+ * Extract the package name from a fully-donated resource name.
+ * e.g. "com.android.app1:drawable/icon1" -> "com.android.app1"
+ * @hide
+ */
+ @VisibleForTesting
+ public static String getResourcePackageName(@NonNull String fullResourceName) {
+ final int p1 = fullResourceName.indexOf(':');
+ if (p1 < 0) {
+ return null;
+ }
+ return fullResourceName.substring(0, p1);
+ }
+
+ /**
+ * Extract the type name from a fully-donated resource name.
+ * e.g. "com.android.app1:drawable/icon1" -> "drawable"
+ * @hide
+ */
+ @VisibleForTesting
+ public static String getResourceTypeName(@NonNull String fullResourceName) {
+ final int p1 = fullResourceName.indexOf(':');
+ if (p1 < 0) {
+ return null;
+ }
+ final int p2 = fullResourceName.indexOf('/', p1 + 1);
+ if (p2 < 0) {
+ return null;
+ }
+ return fullResourceName.substring(p1 + 1, p2);
+ }
+
+ /**
+ * Extract the type name + the entry name from a fully-donated resource name.
+ * e.g. "com.android.app1:drawable/icon1" -> "drawable/icon1"
+ * @hide
+ */
+ @VisibleForTesting
+ public static String getResourceTypeAndEntryName(@NonNull String fullResourceName) {
+ final int p1 = fullResourceName.indexOf(':');
+ if (p1 < 0) {
+ return null;
+ }
+ return fullResourceName.substring(p1 + 1);
+ }
+
+ /**
+ * Extract the entry name from a fully-donated resource name.
+ * e.g. "com.android.app1:drawable/icon1" -> "icon1"
+ * @hide
+ */
+ @VisibleForTesting
+ public static String getResourceEntryName(@NonNull String fullResourceName) {
+ final int p1 = fullResourceName.indexOf('/');
+ if (p1 < 0) {
+ return null;
+ }
+ return fullResourceName.substring(p1 + 1);
+ }
+
+ /**
+ * Return the resource ID for a given resource ID.
+ *
+ * Basically its' a wrapper over {@link Resources#getIdentifier(String, String, String)}, except
+ * if {@code resourceName} is an integer then it'll just return its value. (Which also the
+ * aforementioned method would do internally, but not documented, so doing here explicitly.)
+ *
+ * @param res {@link Resources} for the publisher. Must have been loaded with
+ * {@link PackageManager#getResourcesForApplicationAsUser}.
+ *
+ * @hide
+ */
+ @VisibleForTesting
+ public static int lookUpResourceId(@NonNull Resources res, @Nullable String resourceName,
+ @Nullable String resourceType, String packageName) {
+ if (resourceName == null) {
+ return 0;
+ }
+ try {
+ try {
+ // It the name can be parsed as an integer, just use it.
+ return Integer.parseInt(resourceName);
+ } catch (NumberFormatException ignore) {
+ }
+
+ return res.getIdentifier(resourceName, resourceType, packageName);
+ } catch (NotFoundException e) {
+ Log.e(TAG, "Resource ID for name=" + resourceName + " not found in package "
+ + packageName);
+ return 0;
+ }
+ }
+
+ /**
+ * Look up resource names from the resource IDs for the icon res and the text fields, and fill
+ * in the resource name fields.
+ *
+ * @param res {@link Resources} for the publisher. Must have been loaded with
+ * {@link PackageManager#getResourcesForApplicationAsUser}.
+ *
+ * @hide
+ */
+ public void lookupAndFillInResourceNames(@NonNull Resources res) {
+ if ((mTitleResId == 0) && (mTextResId == 0) && (mDisabledMessageResId == 0)
+ && (mIconResId == 0)) {
+ return; // Bail early.
+ }
+
+ // We don't need types for strings because their types are always "string".
+ mTitleResName = lookUpResourceName(res, mTitleResId, /*withType=*/ false, mPackageName);
+ mTextResName = lookUpResourceName(res, mTextResId, /*withType=*/ false, mPackageName);
+ mDisabledMessageResName = lookUpResourceName(res, mDisabledMessageResId,
+ /*withType=*/ false, mPackageName);
+
+ // But icons have multiple possible types, so include the type.
+ mIconResName = lookUpResourceName(res, mIconResId, /*withType=*/ true, mPackageName);
+ }
+
+ /**
+ * Look up resource IDs from the resource names for the icon res and the text fields, and fill
+ * in the resource ID fields.
+ *
+ * This is called when an app is updated.
+ *
+ * @hide
+ */
+ public void lookupAndFillInResourceIds(@NonNull Resources res) {
+ if ((mTitleResName == null) && (mTextResName == null) && (mDisabledMessageResName == null)
+ && (mIconResName == null)) {
+ return; // Bail early.
+ }
+
+ mTitleResId = lookUpResourceId(res, mTitleResName, RES_TYPE_STRING, mPackageName);
+ mTextResId = lookUpResourceId(res, mTextResName, RES_TYPE_STRING, mPackageName);
+ mDisabledMessageResId = lookUpResourceId(res, mDisabledMessageResName, RES_TYPE_STRING,
+ mPackageName);
+
+ // mIconResName already contains the type, so the third argument is not needed.
+ mIconResId = lookUpResourceId(res, mIconResName, null, mPackageName);
+ }
+
/**
* Copy a {@link ShortcutInfo}, optionally removing fields.
* @hide
@@ -252,50 +595,86 @@ public final class ShortcutInfo implements Parcelable {
return new ShortcutInfo(this, cloneFlags);
}
+ /**
+ * @hide
+ */
+ public void ensureUpdatableWith(ShortcutInfo source) {
+ Preconditions.checkState(mUserId == source.mUserId, "Owner User ID must match");
+ Preconditions.checkState(mId.equals(source.mId), "ID must match");
+ Preconditions.checkState(mPackageName.equals(source.mPackageName),
+ "Package name must match");
+ Preconditions.checkState(!isImmutable(), "Target ShortcutInfo is immutable");
+ }
+
/**
* Copy non-null/zero fields from another {@link ShortcutInfo}. Only "public" information
- * will be overwritten. The timestamp will be updated.
+ * will be overwritten. The timestamp will *not* be updated to be consistent with other
+ * setters (and also the clock is not injectable in this file).
*
* - Flags will not change
* - mBitmapPath will not change
* - Current time will be set to timestamp
*
+ * @throws IllegalStateException if source is not compatible.
+ *
* @hide
*/
public void copyNonNullFieldsFrom(ShortcutInfo source) {
- Preconditions.checkState(mUserId == source.mUserId, "Owner User ID must match");
- Preconditions.checkState(mId.equals(source.mId), "ID must match");
- Preconditions.checkState(mPackageName.equals(source.mPackageName),
- "Package name must match");
+ ensureUpdatableWith(source);
- if (source.mActivityComponent != null) {
- mActivityComponent = source.mActivityComponent;
+ if (source.mActivity != null) {
+ mActivity = source.mActivity;
}
if (source.mIcon != null) {
mIcon = source.mIcon;
+
+ mIconResId = 0;
+ mIconResName = null;
+ mBitmapPath = null;
}
if (source.mTitle != null) {
mTitle = source.mTitle;
+ mTitleResId = 0;
+ mTitleResName = null;
+ } else if (source.mTitleResId != 0) {
+ mTitle = null;
+ mTitleResId = source.mTitleResId;
+ mTitleResName = null;
}
+
if (source.mText != null) {
mText = source.mText;
+ mTextResId = 0;
+ mTextResName = null;
+ } else if (source.mTextResId != 0) {
+ mText = null;
+ mTextResId = source.mTextResId;
+ mTextResName = null;
+ }
+ if (source.mDisabledMessage != null) {
+ mDisabledMessage = source.mDisabledMessage;
+ mDisabledMessageResId = 0;
+ mDisabledMessageResName = null;
+ } else if (source.mDisabledMessageResId != 0) {
+ mDisabledMessage = null;
+ mDisabledMessageResId = source.mDisabledMessageResId;
+ mDisabledMessageResName = null;
}
if (source.mCategories != null) {
- mCategories = clone(source.mCategories);
+ mCategories = cloneCategories(source.mCategories);
}
- if (source.mIntent != null) {
- mIntent = source.mIntent;
- mIntentPersistableExtras = source.mIntentPersistableExtras;
+ if (source.mIntents != null) {
+ mIntents = cloneIntents(source.mIntents);
+ mIntentPersistableExtrases =
+ clonePersistableBundle(source.mIntentPersistableExtrases);
}
- if (source.mWeight != 0) {
- mWeight = source.mWeight;
+ if (source.mRank != RANK_NOT_SET) {
+ mRank = source.mRank;
}
if (source.mExtras != null) {
mExtras = source.mExtras;
}
-
- updateTimestamp();
}
/**
@@ -310,7 +689,6 @@ public final class ShortcutInfo implements Parcelable {
throw getInvalidIconException();
}
if (icon.hasTint()) {
- // TODO support it
throw new IllegalArgumentException("Icons with tints are not supported");
}
@@ -320,77 +698,123 @@ public final class ShortcutInfo implements Parcelable {
/** @hide */
public static IllegalArgumentException getInvalidIconException() {
return new IllegalArgumentException("Unsupported icon type:"
- +" only bitmap, resource and content URI are supported");
+ +" only the bitmap and resource types are supported");
}
/**
* Builder class for {@link ShortcutInfo} objects.
+ *
+ * @see ShortcutManager
*/
public static class Builder {
private final Context mContext;
private String mId;
- private ComponentName mActivityComponent;
+ private ComponentName mActivity;
private Icon mIcon;
- private String mTitle;
+ private int mTitleResId;
+
+ private CharSequence mTitle;
+
+ private int mTextResId;
+
+ private CharSequence mText;
- private String mText;
+ private int mDisabledMessageResId;
+
+ private CharSequence mDisabledMessage;
private Set mCategories;
- private Intent mIntent;
+ private Intent[] mIntents;
- private int mWeight;
+ private int mRank = RANK_NOT_SET;
private PersistableBundle mExtras;
- /** Constructor. */
+ /**
+ * Old style constructor.
+ * @hide
+ */
+ @Deprecated
public Builder(Context context) {
mContext = context;
}
/**
- * Sets the ID of the shortcut. This is a mandatory field.
+ * Used with the old style constructor, kept for unit tests.
+ * @hide
*/
@NonNull
+ @Deprecated
public Builder setId(@NonNull String id) {
- mId = Preconditions.checkStringNotEmpty(id, "id");
+ mId = Preconditions.checkStringNotEmpty(id, "id cannot be empty");
return this;
}
/**
- * Optionally sets the target activity. If it's not set, and if the caller application
- * has multiple launcher icons, this shortcut will be shown on all those icons.
- * If it's set, this shortcut will be only shown on this activity.
+ * Constructor.
+ *
+ * @param context Client context.
+ * @param id ID of the shortcut.
+ */
+ public Builder(Context context, String id) {
+ mContext = context;
+ mId = Preconditions.checkStringNotEmpty(id, "id cannot be empty");
+ }
+
+ /**
+ * Sets the target activity. A shortcut will be shown along with this activity's icon
+ * on the launcher.
+ *
+ * When selecting a target activity, keep the following in mind:
+ *
+ *
All dynamic shortcuts must have a target activity. When a shortcut with no target
+ * activity is published using
+ * {@link ShortcutManager#addDynamicShortcuts(List)} or
+ * {@link ShortcutManager#setDynamicShortcuts(List)},
+ * the first main activity defined in the application's AndroidManifest.xml
+ * file is used.
*
- *
The package name of the target activity must match the package name of the shortcut
- * publisher.
+ *
Only "main" activities—ones that define the {@link Intent#ACTION_MAIN}
+ * and {@link Intent#CATEGORY_LAUNCHER} intent filters—can be target
+ * activities.
*
- *
This has nothing to do with the activity that this shortcut will launch. This is
- * a hint to the launcher app about which launcher icon to associate this shortcut with.
+ *
By default, the first main activity defined in the application manifest is
+ * the target activity.
+ *
+ *
A target activity must belong to the publisher application.
+ *
+ *
+ * @see ShortcutInfo#getActivity()
*/
@NonNull
- public Builder setActivityComponent(@NonNull ComponentName activityComponent) {
- mActivityComponent = Preconditions.checkNotNull(activityComponent, "activityComponent");
+ public Builder setActivity(@NonNull ComponentName activity) {
+ mActivity = Preconditions.checkNotNull(activity, "activity cannot be null");
return this;
}
/**
- * Optionally sets an icon.
+ * Sets an icon of a shortcut.
*
- *
- *
Tints set by {@link Icon#setTint} or {@link Icon#setTintList} are not supported.
- *
Bitmaps and resources are supported, but "content:" URIs are not supported.
- *
+ *
Icons are not available on {@link ShortcutInfo} instances
+ * returned by {@link ShortcutManager} or {@link LauncherApps}. The default launcher
+ * application can use {@link LauncherApps#getShortcutIconDrawable(ShortcutInfo, int)}
+ * or {@link LauncherApps#getShortcutBadgedIconDrawable(ShortcutInfo, int)} to fetch
+ * shortcut icons.
+ *
+ *
Tints set with {@link Icon#setTint} or {@link Icon#setTintList} are not supported
+ * and will be ignored.
*
- *
For performance reasons, icons will NOT be available on instances
- * returned by {@link ShortcutManager} or {@link LauncherApps}. Launcher applications
- * can use {@link ShortcutInfo#getIconResourceId()} if {@link #hasIconResource()} is true.
- * Otherwise, if {@link #hasIconFile()} is true, use
- * {@link LauncherApps#getShortcutIconFd} to load the image.
+ *
Only icons created with {@link Icon#createWithBitmap(Bitmap)} and
+ * {@link Icon#createWithResource} are supported.
+ * Other types, such as URI-based icons, are not supported.
+ *
+ * @see LauncherApps#getShortcutIconDrawable(ShortcutInfo, int)
+ * @see LauncherApps#getShortcutBadgedIconDrawable(ShortcutInfo, int)
*/
@NonNull
public Builder setIcon(Icon icon) {
@@ -399,26 +823,112 @@ public final class ShortcutInfo implements Parcelable {
}
/**
- * Sets the title of a shortcut. This is a mandatory field.
+ * @hide We don't support resource strings for dynamic shortcuts for now. (But unit tests
+ * use it.)
+ */
+ @Deprecated
+ public Builder setShortLabelResId(int shortLabelResId) {
+ Preconditions.checkState(mTitle == null, "shortLabel already set");
+ mTitleResId = shortLabelResId;
+ return this;
+ }
+
+ /**
+ * Sets the short title of a shortcut.
+ *
+ *
This is a mandatory field when publishing a new shortcut with
+ * {@link ShortcutManager#addDynamicShortcuts(List)} or
+ * {@link ShortcutManager#setDynamicShortcuts(List)}.
+ *
+ *
This field is intended to be a concise description of a shortcut.
+ *
+ *
The recommended maximum length is 10 characters.
*
- *
This field is intended for a concise description of a shortcut displayed under
- * an icon. The recommend max length is 10 characters.
+ * @see ShortcutInfo#getShortLabel()
*/
@NonNull
- public Builder setTitle(@NonNull String title) {
- mTitle = Preconditions.checkStringNotEmpty(title, "title");
+ public Builder setShortLabel(@NonNull CharSequence shortLabel) {
+ Preconditions.checkState(mTitleResId == 0, "shortLabelResId already set");
+ mTitle = Preconditions.checkStringNotEmpty(shortLabel, "shortLabel cannot be empty");
+ return this;
+ }
+
+ /**
+ * @hide We don't support resource strings for dynamic shortcuts for now. (But unit tests
+ * use it.)
+ */
+ @Deprecated
+ public Builder setLongLabelResId(int longLabelResId) {
+ Preconditions.checkState(mText == null, "longLabel already set");
+ mTextResId = longLabelResId;
return this;
}
/**
- * Sets the text of a shortcut. This is an optional field.
+ * Sets the text of a shortcut.
+ *
+ *
This field is intended to be more descriptive than the shortcut title. The launcher
+ * shows this instead of the short title when it has enough space.
+ *
+ *
The recommend maximum length is 25 characters.
*
- *
This field is intended to be more descriptive than the shortcut title.
- * The recommend max length is 25 characters.
+ * @see ShortcutInfo#getLongLabel()
*/
@NonNull
- public Builder setText(@NonNull String text) {
- mText = Preconditions.checkStringNotEmpty(text, "text");
+ public Builder setLongLabel(@NonNull CharSequence longLabel) {
+ Preconditions.checkState(mTextResId == 0, "longLabelResId already set");
+ mText = Preconditions.checkStringNotEmpty(longLabel, "longLabel cannot be empty");
+ return this;
+ }
+
+ /** @hide -- old signature, the internal code still uses it. */
+ @Deprecated
+ public Builder setTitle(@NonNull CharSequence value) {
+ return setShortLabel(value);
+ }
+
+ /** @hide -- old signature, the internal code still uses it. */
+ @Deprecated
+ public Builder setTitleResId(int value) {
+ return setShortLabelResId(value);
+ }
+
+ /** @hide -- old signature, the internal code still uses it. */
+ @Deprecated
+ public Builder setText(@NonNull CharSequence value) {
+ return setLongLabel(value);
+ }
+
+ /** @hide -- old signature, the internal code still uses it. */
+ @Deprecated
+ public Builder setTextResId(int value) {
+ return setLongLabelResId(value);
+ }
+
+ /**
+ * @hide We don't support resource strings for dynamic shortcuts for now. (But unit tests
+ * use it.)
+ */
+ @Deprecated
+ public Builder setDisabledMessageResId(int disabledMessageResId) {
+ Preconditions.checkState(mDisabledMessage == null, "disabledMessage already set");
+ mDisabledMessageResId = disabledMessageResId;
+ return this;
+ }
+
+ /**
+ * Sets the message that should be shown when the user attempts to start a shortcut that
+ * is disabled.
+ *
+ * @see ShortcutInfo#getDisabledMessage()
+ */
+ @NonNull
+ public Builder setDisabledMessage(@NonNull CharSequence disabledMessage) {
+ Preconditions.checkState(
+ mDisabledMessageResId == 0, "disabledMessageResId already set");
+ mDisabledMessage =
+ Preconditions.checkStringNotEmpty(disabledMessage,
+ "disabledMessage cannot be empty");
return this;
}
@@ -427,6 +937,7 @@ public final class ShortcutInfo implements Parcelable {
* categorise shortcuts.
*
* @see #SHORTCUT_CATEGORY_CONVERSATION
+ * @see ShortcutInfo#getCategories()
*/
@NonNull
public Builder setCategories(Set categories) {
@@ -435,28 +946,70 @@ public final class ShortcutInfo implements Parcelable {
}
/**
- * Sets the intent of a shortcut. This is a mandatory field. The extras must only contain
- * persistable information. (See {@link PersistableBundle}).
+ * Sets the intent of a shortcut. Alternatively, {@link #setIntents(Intent[])} can be used
+ * to launch an activity with other activities in the back stack.
+ *
+ *
This is a mandatory field when publishing a new shortcut with
+ * {@link ShortcutManager#addDynamicShortcuts(List)} or
+ * {@link ShortcutManager#setDynamicShortcuts(List)}.
+ *
+ *
A shortcut can launch any intent that the publisher application has permission to
+ * launch. For example, a shortcut can launch an unexported activity within the publisher
+ * application. A shortcut intent doesn't have to point at the target activity.
+ *
+ *
The given {@code intent} can contain extras, but these extras must contain values
+ * of primitive types in order for the system to persist these values.
+ *
+ * @see ShortcutInfo#getIntent()
+ * @see #setIntents(Intent[])
*/
@NonNull
public Builder setIntent(@NonNull Intent intent) {
- mIntent = Preconditions.checkNotNull(intent, "intent");
+ return setIntents(new Intent[]{intent});
+ }
+
+ /**
+ * Sets multiple intents instead of a single intent, in order to launch an activity with
+ * other activities in back stack. Use {@link TaskStackBuilder} to build intents.
+ * See the {@link ShortcutManager} javadoc for details.
+ *
+ * @see Builder#setIntent(Intent)
+ * @see ShortcutInfo#getIntents()
+ * @see Context#startActivities(Intent[])
+ * @see TaskStackBuilder
+ */
+ @NonNull
+ public Builder setIntents(@NonNull Intent[] intents) {
+ Preconditions.checkNotNull(intents, "intents cannot be null");
+ Preconditions.checkNotNull(intents.length, "intents cannot be empty");
+ for (Intent intent : intents) {
+ Preconditions.checkNotNull(intent, "intents cannot contain null");
+ Preconditions.checkNotNull(intent.getAction(), "intent's action must be set");
+ }
+ // Make sure always clone incoming intents.
+ mIntents = cloneIntents(intents);
return this;
}
/**
- * Optionally sets the weight of a shortcut, which will be used by the launcher for sorting.
- * The larger the weight, the more "important" a shortcut is.
+ * "Rank" of a shortcut, which is a non-negative value that's used by the launcher app
+ * to sort shortcuts.
+ *
+ * See {@link ShortcutInfo#getRank()} for details.
*/
@NonNull
- public Builder setWeight(int weight) {
- mWeight = weight;
+ public Builder setRank(int rank) {
+ Preconditions.checkArgument((0 <= rank),
+ "Rank cannot be negative or bigger than MAX_RANK");
+ mRank = rank;
return this;
}
/**
- * Optional values that applications can set. Applications can store any meta-data of
- * shortcuts in this, and retrieve later from {@link ShortcutInfo#getExtras()}.
+ * Extras that application can set for any purpose.
+ *
+ *
Applications can store arbitrary shortcut metadata in extras and retrieve the
+ * metadata later using {@link ShortcutInfo#getExtras()}.
*/
@NonNull
public Builder setExtras(@NonNull PersistableBundle extras) {
@@ -474,7 +1027,11 @@ public final class ShortcutInfo implements Parcelable {
}
/**
- * Return the ID of the shortcut.
+ * Returns the ID of a shortcut.
+ *
+ *
Shortcut IDs are unique within each publisher application and must be stable across
+ * devices so that shortcuts will still be valid when restored on a different device.
+ * See {@link ShortcutManager} for details.
*/
@NonNull
public String getId() {
@@ -482,33 +1039,34 @@ public final class ShortcutInfo implements Parcelable {
}
/**
- * Return the package name of the creator application.
+ * Return the package name of the publisher application.
*/
@NonNull
- public String getPackageName() {
+ public String getPackage() {
return mPackageName;
}
/**
- * Return the target activity, which may be null, in which case the shortcut is not associated
- * with a specific activity.
+ * Return the target activity.
*
- *
This has nothing to do with the activity that this shortcut will launch. This is
- * a hint to the launcher app that on which launcher icon this shortcut should be shown.
+ *
This has nothing to do with the activity that this shortcut will launch.
+ * Launcher applications should show the launcher icon for the returned activity alongside
+ * this shortcut.
*
- * @see Builder#setActivityComponent
+ * @see Builder#setActivity
*/
@Nullable
- public ComponentName getActivityComponent() {
- return mActivityComponent;
+ public ComponentName getActivity() {
+ return mActivity;
+ }
+
+ /** @hide */
+ public void setActivity(ComponentName activity) {
+ mActivity = activity;
}
/**
- * Icon.
- *
- * For performance reasons, this will NOT be available when an instance is returned
- * by {@link ShortcutManager} or {@link LauncherApps}. A launcher application needs to use
- * other APIs in LauncherApps to fetch the bitmap.
+ * Returns the shortcut icon.
*
* @hide
*/
@@ -517,27 +1075,82 @@ public final class ShortcutInfo implements Parcelable {
return mIcon;
}
+ /** @hide -- old signature, the internal code still uses it. */
+ @Nullable
+ @Deprecated
+ public CharSequence getTitle() {
+ return mTitle;
+ }
+
+ /** @hide -- old signature, the internal code still uses it. */
+ @Deprecated
+ public int getTitleResId() {
+ return mTitleResId;
+ }
+
+ /** @hide -- old signature, the internal code still uses it. */
+ @Nullable
+ @Deprecated
+ public CharSequence getText() {
+ return mText;
+ }
+
+ /** @hide -- old signature, the internal code still uses it. */
+ @Deprecated
+ public int getTextResId() {
+ return mTextResId;
+ }
+
/**
- * Return the shortcut title.
+ * Return the shorter description of a shortcut.
*
- *
All shortcuts must have a non-empty title, but this method will return null when
- * {@link #hasKeyFieldsOnly()} is true.
+ * @see Builder#setShortLabel(CharSequence)
*/
@Nullable
- public String getTitle() {
+ public CharSequence getShortLabel() {
return mTitle;
}
+ /** @hide */
+ public int getShortLabelResourceId() {
+ return mTitleResId;
+ }
+
/**
- * Return the shortcut text.
+ * Return the longer description of a shortcut.
+ *
+ * @see Builder#setLongLabel(CharSequence)
*/
@Nullable
- public String getText() {
+ public CharSequence getLongLabel() {
return mText;
}
+ /** @hide */
+ public int getLongLabelResourceId() {
+ return mTextResId;
+ }
+
+ /**
+ * Return the message that should be shown when the user attempts to start a shortcut
+ * that is disabled.
+ *
+ * @see Builder#setDisabledMessage(CharSequence)
+ */
+ @Nullable
+ public CharSequence getDisabledMessage() {
+ return mDisabledMessage;
+ }
+
+ /** @hide */
+ public int getDisabledMessageResourceId() {
+ return mDisabledMessageResId;
+ }
+
/**
- * Return the categories.
+ * Return the shortcut's categories.
+ *
+ * @see Builder#setCategories(Set)
*/
@Nullable
public Set getCategories() {
@@ -545,55 +1158,125 @@ public final class ShortcutInfo implements Parcelable {
}
/**
- * Return the intent.
+ * Returns the intent that is executed when the user selects this shortcut.
+ * If setIntents() was used, then return the last intent in the array.
*
- *
All shortcuts must have an intent, but this method will return null when
- * {@link #hasKeyFieldsOnly()} is true.
+ *
Launcher applications cannot see the intent. If a {@link ShortcutInfo} is
+ * obtained via {@link LauncherApps}, then this method will always return null.
+ * Launchers can only start a shortcut intent with {@link LauncherApps#startShortcut}.
*
- *
Launcher apps cannot see the intent. If a {@link ShortcutInfo} is obtained via
- * {@link LauncherApps}, then this method will always return null. Launcher apps can only
- * start a shortcut intent with {@link LauncherApps#startShortcut}.
+ * @see Builder#setIntent(Intent)
*/
@Nullable
public Intent getIntent() {
- if (mIntent == null) {
+ if (mIntents == null || mIntents.length == 0) {
return null;
}
- final Intent intent = new Intent(mIntent);
- intent.replaceExtras(
- mIntentPersistableExtras != null ? new Bundle(mIntentPersistableExtras) : null);
- return intent;
+ final int last = mIntents.length - 1;
+ final Intent intent = new Intent(mIntents[last]);
+ return setIntentExtras(intent, mIntentPersistableExtrases[last]);
}
/**
- * Return "raw" intent, which is the original intent without the extras.
+ * Return the intent set with {@link Builder#setIntents(Intent[])}.
+ *
+ *
Launcher applications cannot see the intents. If a {@link ShortcutInfo} is
+ * obtained via {@link LauncherApps}, then this method will always return null.
+ * Launchers can only start a shortcut intent with {@link LauncherApps#startShortcut}.
+ *
+ * @see Builder#setIntents(Intent[])
+ */
+ @Nullable
+ public Intent[] getIntents() {
+ final Intent[] ret = new Intent[mIntents.length];
+
+ for (int i = 0; i < ret.length; i++) {
+ ret[i] = new Intent(mIntents[i]);
+ setIntentExtras(ret[i], mIntentPersistableExtrases[i]);
+ }
+
+ return ret;
+ }
+
+ /**
+ * Return "raw" intents, which is the original intents without the extras.
* @hide
*/
@Nullable
- public Intent getIntentNoExtras() {
- return mIntent;
+ public Intent[] getIntentsNoExtras() {
+ return mIntents;
}
/**
- * The extras in the intent. We convert extras into {@link PersistableBundle} so we can
+ * The extras in the intents. We convert extras into {@link PersistableBundle} so we can
* persist them.
* @hide
*/
@Nullable
- public PersistableBundle getIntentPersistableExtras() {
- return mIntentPersistableExtras;
+ public PersistableBundle[] getIntentPersistableExtrases() {
+ return mIntentPersistableExtrases;
}
/**
- * Return the weight of a shortcut, which will be used by Launcher for sorting.
- * The larger the weight, the more "important" a shortcut is.
+ * "Rank" of a shortcut, which is a non-negative, sequential value that's unique for each
+ * {@link #getActivity} for each of the two kinds, dynamic shortcuts and manifest shortcuts.
+ *
+ *
Because manifest shortcuts and dynamic shortcuts have overlapping ranks,
+ * when a launcher application shows shortcuts for an activity, it should first show
+ * the manifest shortcuts followed by the dynamic shortcuts. Within each of those categories,
+ * shortcuts should be sorted by rank in ascending order.
+ *
+ *
"Floating" shortcuts (i.e. shortcuts that are neither dynamic nor manifest) will all
+ * have rank 0, because there's no sorting for them.
+ *
+ * See the {@link ShortcutManager}'s class javadoc for details.
+ *
+ * @see Builder#setRank(int)
*/
- public int getWeight() {
- return mWeight;
+ public int getRank() {
+ return mRank;
+ }
+
+ /** @hide */
+ public boolean hasRank() {
+ return mRank != RANK_NOT_SET;
+ }
+
+ /** @hide */
+ public void setRank(int rank) {
+ mRank = rank;
+ }
+
+ /** @hide */
+ public void clearImplicitRankAndRankChangedFlag() {
+ mImplicitRank = 0;
+ }
+
+ /** @hide */
+ public void setImplicitRank(int rank) {
+ // Make sure to keep RANK_CHANGED_BIT.
+ mImplicitRank = (mImplicitRank & RANK_CHANGED_BIT) | (rank & IMPLICIT_RANK_MASK);
+ }
+
+ /** @hide */
+ public int getImplicitRank() {
+ return mImplicitRank & IMPLICIT_RANK_MASK;
+ }
+
+ /** @hide */
+ public void setRankChanged() {
+ mImplicitRank |= RANK_CHANGED_BIT;
+ }
+
+ /** @hide */
+ public boolean isRankChanged() {
+ return (mImplicitRank & RANK_CHANGED_BIT) != 0;
}
/**
- * Optional values that application can set.
+ * Extras that application can set to any purposes.
+ *
+ * @see Builder#setExtras(PersistableBundle)
*/
@Nullable
public PersistableBundle getExtras() {
@@ -606,7 +1289,7 @@ public final class ShortcutInfo implements Parcelable {
}
/**
- * {@link UserHandle} on which the publisher created shortcuts.
+ * {@link UserHandle} on which the publisher created this shortcut.
*/
public UserHandle getUserHandle() {
return UserHandle.of(mUserId);
@@ -655,19 +1338,94 @@ public final class ShortcutInfo implements Parcelable {
return hasFlags(FLAG_PINNED);
}
+ /**
+ * Return whether a shortcut is published from AndroidManifest.xml or not. If {@code true},
+ * it's also {@link #isImmutable()}.
+ *
+ *
When an app is upgraded and a shortcut is no longer published from AndroidManifest.xml,
+ * this will be set to {@code false}. If the shortcut is not pinned, then it'll just disappear.
+ * However, if it's pinned, it will still be alive, and {@link #isEnabled()} will be
+ * {@code false} and {@link #isImmutable()} will be {@code true}.
+ */
+ public boolean isDeclaredInManifest() {
+ return hasFlags(FLAG_MANIFEST);
+ }
+
+ /** @hide kept for unit tests */
+ @Deprecated
+ public boolean isManifestShortcut() {
+ return isDeclaredInManifest();
+ }
+
+ /**
+ * @return true if pinned but neither dynamic nor manifest.
+ * @hide
+ */
+ public boolean isFloating() {
+ return isPinned() && !(isDynamic() || isManifestShortcut());
+ }
+
+ /** @hide */
+ public boolean isOriginallyFromManifest() {
+ return hasFlags(FLAG_IMMUTABLE);
+ }
+
+ /**
+ * Return if a shortcut is immutable, in which case it cannot be modified with any of
+ * {@link ShortcutManager} APIs.
+ *
+ *
All manifest shortcuts are immutable. When a manifest shortcut is pinned and then
+ * disabled because the app is upgraded and its AndroidManifest.xml no longer publishes it,
+ * {@link #isDeclaredInManifest()} returns {@code false}, but it is still immutable.
+ *
+ *
All shortcuts originally published via the {@link ShortcutManager} APIs
+ * are all mutable.
+ */
+ public boolean isImmutable() {
+ return hasFlags(FLAG_IMMUTABLE);
+ }
+
+ /**
+ * Returns {@code false} if a shortcut is disabled with
+ * {@link ShortcutManager#disableShortcuts}.
+ */
+ public boolean isEnabled() {
+ return !hasFlags(FLAG_DISABLED);
+ }
+
+ /** @hide */
+ public boolean isAlive() {
+ return hasFlags(FLAG_PINNED) || hasFlags(FLAG_DYNAMIC) || hasFlags(FLAG_MANIFEST);
+ }
+
+ /** @hide */
+ public boolean usesQuota() {
+ return hasFlags(FLAG_DYNAMIC) || hasFlags(FLAG_MANIFEST);
+ }
+
/**
* Return whether a shortcut's icon is a resource in the owning package.
*
- * @see LauncherApps#getShortcutIconResId(ShortcutInfo)
+ * @hide internal/unit tests only
*/
public boolean hasIconResource() {
return hasFlags(FLAG_HAS_ICON_RES);
}
+ /** @hide */
+ public boolean hasStringResources() {
+ return (mTitleResId != 0) || (mTextResId != 0) || (mDisabledMessageResId != 0);
+ }
+
+ /** @hide */
+ public boolean hasAnyResources() {
+ return hasIconResource() || hasStringResources();
+ }
+
/**
* Return whether a shortcut's icon is stored as a file.
*
- * @see LauncherApps#getShortcutIconFd(ShortcutInfo)
+ * @hide internal/unit tests only
*/
public boolean hasIconFile() {
return hasFlags(FLAG_HAS_ICON_FILE);
@@ -678,18 +1436,32 @@ public final class ShortcutInfo implements Parcelable {
* following fields are available.
*
*
{@link #getId()}
- *
{@link #getPackageName()}
+ *
{@link #getPackage()}
+ *
{@link #getActivity()}
*
{@link #getLastChangedTimestamp()}
*
{@link #isDynamic()}
*
{@link #isPinned()}
- *
{@link #hasIconResource()}
- *
{@link #hasIconFile()}
+ *
{@link #isDeclaredInManifest()}
+ *
{@link #isImmutable()}
+ *
{@link #isEnabled()}
+ *
{@link #getUserHandle()}
*
+ *
+ *
For performance reasons, shortcuts passed to
+ * {@link LauncherApps.Callback#onShortcutsChanged(String, List, UserHandle)} as well as those
+ * returned from {@link LauncherApps#getShortcuts(ShortcutQuery, UserHandle)}
+ * while using the {@link ShortcutQuery#FLAG_GET_KEY_FIELDS_ONLY} option contain only key
+ * information.
*/
public boolean hasKeyFieldsOnly() {
return hasFlags(FLAG_KEY_FIELDS_ONLY);
}
+ /** @hide */
+ public boolean hasStringResourcesResolved() {
+ return hasFlags(FLAG_STRINGS_RESOLVED);
+ }
+
/** @hide */
public void updateTimestamp() {
mLastChangedTimestamp = System.currentTimeMillis();
@@ -708,14 +1480,18 @@ public final class ShortcutInfo implements Parcelable {
/** @hide */
public void setIconResourceId(int iconResourceId) {
- mIconResourceId = iconResourceId;
+ if (mIconResId != iconResourceId) {
+ mIconResName = null;
+ }
+ mIconResId = iconResourceId;
}
/**
* Get the resource ID for the icon, valid only when {@link #hasIconResource()} } is true.
+ * @hide internal / tests only.
*/
public int getIconResourceId() {
- return mIconResourceId;
+ return mIconResId;
}
/** @hide */
@@ -728,25 +1504,129 @@ public final class ShortcutInfo implements Parcelable {
mBitmapPath = bitmapPath;
}
+ /** @hide */
+ public void setDisabledMessageResId(int disabledMessageResId) {
+ if (mDisabledMessageResId != disabledMessageResId) {
+ mDisabledMessageResName = null;
+ }
+ mDisabledMessageResId = disabledMessageResId;
+ mDisabledMessage = null;
+ }
+
+ /** @hide */
+ public void setDisabledMessage(String disabledMessage) {
+ mDisabledMessage = disabledMessage;
+ mDisabledMessageResId = 0;
+ mDisabledMessageResName = null;
+ }
+
+ /** @hide */
+ public String getTitleResName() {
+ return mTitleResName;
+ }
+
+ /** @hide */
+ public void setTitleResName(String titleResName) {
+ mTitleResName = titleResName;
+ }
+
+ /** @hide */
+ public String getTextResName() {
+ return mTextResName;
+ }
+
+ /** @hide */
+ public void setTextResName(String textResName) {
+ mTextResName = textResName;
+ }
+
+ /** @hide */
+ public String getDisabledMessageResName() {
+ return mDisabledMessageResName;
+ }
+
+ /** @hide */
+ public void setDisabledMessageResName(String disabledMessageResName) {
+ mDisabledMessageResName = disabledMessageResName;
+ }
+
+ /** @hide */
+ public String getIconResName() {
+ return mIconResName;
+ }
+
+ /** @hide */
+ public void setIconResName(String iconResName) {
+ mIconResName = iconResName;
+ }
+
+ /**
+ * Replaces the intent
+ *
+ * @throws IllegalArgumentException when extra is not compatible with {@link PersistableBundle}.
+ *
+ * @hide
+ */
+ public void setIntents(Intent[] intents) throws IllegalArgumentException {
+ Preconditions.checkNotNull(intents);
+ Preconditions.checkArgument(intents.length > 0);
+
+ mIntents = cloneIntents(intents);
+ fixUpIntentExtras();
+ }
+
+ /** @hide */
+ public static Intent setIntentExtras(Intent intent, PersistableBundle extras) {
+ if (extras == null) {
+ intent.replaceExtras((Bundle) null);
+ } else {
+ intent.replaceExtras(new Bundle(extras));
+ }
+ return intent;
+ }
+
+ /**
+ * Replaces the categories.
+ *
+ * @hide
+ */
+ public void setCategories(Set categories) {
+ mCategories = cloneCategories(categories);
+ }
+
private ShortcutInfo(Parcel source) {
final ClassLoader cl = getClass().getClassLoader();
mUserId = source.readInt();
mId = source.readString();
mPackageName = source.readString();
- mActivityComponent = source.readParcelable(cl);
+ mActivity = source.readParcelable(cl);
+ mFlags = source.readInt();
+ mIconResId = source.readInt();
+ mLastChangedTimestamp = source.readLong();
+
+ if (source.readInt() == 0) {
+ return; // key information only.
+ }
+
mIcon = source.readParcelable(cl);
- mTitle = source.readString();
- mText = source.readString();
- mIntent = source.readParcelable(cl);
- mIntentPersistableExtras = source.readParcelable(cl);
- mWeight = source.readInt();
+ mTitle = source.readCharSequence();
+ mTitleResId = source.readInt();
+ mText = source.readCharSequence();
+ mTextResId = source.readInt();
+ mDisabledMessage = source.readCharSequence();
+ mDisabledMessageResId = source.readInt();
+ mIntents = source.readParcelableArray(cl, Intent.class);
+ mIntentPersistableExtrases = source.readParcelableArray(cl, PersistableBundle.class);
+ mRank = source.readInt();
mExtras = source.readParcelable(cl);
- mLastChangedTimestamp = source.readLong();
- mFlags = source.readInt();
- mIconResourceId = source.readInt();
mBitmapPath = source.readString();
+ mIconResName = source.readString();
+ mTitleResName = source.readString();
+ mTextResName = source.readString();
+ mDisabledMessageResName = source.readString();
+
int N = source.readInt();
if (N == 0) {
mCategories = null;
@@ -763,20 +1643,36 @@ public final class ShortcutInfo implements Parcelable {
dest.writeInt(mUserId);
dest.writeString(mId);
dest.writeString(mPackageName);
- dest.writeParcelable(mActivityComponent, flags);
- dest.writeParcelable(mIcon, flags);
- dest.writeString(mTitle);
- dest.writeString(mText);
+ dest.writeParcelable(mActivity, flags);
+ dest.writeInt(mFlags);
+ dest.writeInt(mIconResId);
+ dest.writeLong(mLastChangedTimestamp);
- dest.writeParcelable(mIntent, flags);
- dest.writeParcelable(mIntentPersistableExtras, flags);
- dest.writeInt(mWeight);
+ if (hasKeyFieldsOnly()) {
+ dest.writeInt(0);
+ return;
+ }
+ dest.writeInt(1);
+
+ dest.writeParcelable(mIcon, flags);
+ dest.writeCharSequence(mTitle);
+ dest.writeInt(mTitleResId);
+ dest.writeCharSequence(mText);
+ dest.writeInt(mTextResId);
+ dest.writeCharSequence(mDisabledMessage);
+ dest.writeInt(mDisabledMessageResId);
+
+ dest.writeParcelableArray(mIntents, flags);
+ dest.writeParcelableArray(mIntentPersistableExtrases, flags);
+ dest.writeInt(mRank);
dest.writeParcelable(mExtras, flags);
- dest.writeLong(mLastChangedTimestamp);
- dest.writeInt(mFlags);
- dest.writeInt(mIconResourceId);
dest.writeString(mBitmapPath);
+ dest.writeString(mIconResName);
+ dest.writeString(mTitleResName);
+ dest.writeString(mTextResName);
+ dest.writeString(mDisabledMessageResName);
+
if (mCategories != null) {
final int N = mCategories.size();
dest.writeInt(N);
@@ -823,24 +1719,67 @@ public final class ShortcutInfo implements Parcelable {
sb.append("id=");
sb.append(secure ? "***" : mId);
- sb.append(", packageName=");
- sb.append(mPackageName);
-
+ sb.append(", flags=0x");
+ sb.append(Integer.toHexString(mFlags));
+ sb.append(" [");
+ if (!isEnabled()) {
+ sb.append("X");
+ }
+ if (isImmutable()) {
+ sb.append("Im");
+ }
+ if (isManifestShortcut()) {
+ sb.append("M");
+ }
if (isDynamic()) {
- sb.append(", dynamic");
+ sb.append("D");
}
if (isPinned()) {
- sb.append(", pinned");
+ sb.append("P");
+ }
+ if (hasIconFile()) {
+ sb.append("If");
+ }
+ if (hasIconResource()) {
+ sb.append("Ir");
+ }
+ if (hasKeyFieldsOnly()) {
+ sb.append("K");
}
+ if (hasStringResourcesResolved()) {
+ sb.append("Sr");
+ }
+ sb.append("]");
+
+ sb.append(", packageName=");
+ sb.append(mPackageName);
sb.append(", activity=");
- sb.append(mActivityComponent);
+ sb.append(mActivity);
- sb.append(", title=");
+ sb.append(", shortLabel=");
sb.append(secure ? "***" : mTitle);
+ sb.append(", resId=");
+ sb.append(mTitleResId);
+ sb.append("[");
+ sb.append(mTitleResName);
+ sb.append("]");
- sb.append(", text=");
+ sb.append(", longLabel=");
sb.append(secure ? "***" : mText);
+ sb.append(", resId=");
+ sb.append(mTextResId);
+ sb.append("[");
+ sb.append(mTextResName);
+ sb.append("]");
+
+ sb.append(", disabledMessage=");
+ sb.append(secure ? "***" : mDisabledMessage);
+ sb.append(", resId=");
+ sb.append(mDisabledMessageResId);
+ sb.append("[");
+ sb.append(mDisabledMessageResName);
+ sb.append("]");
sb.append(", categories=");
sb.append(mCategories);
@@ -848,28 +1787,44 @@ public final class ShortcutInfo implements Parcelable {
sb.append(", icon=");
sb.append(mIcon);
- sb.append(", weight=");
- sb.append(mWeight);
+ sb.append(", rank=");
+ sb.append(mRank);
sb.append(", timestamp=");
sb.append(mLastChangedTimestamp);
- sb.append(", intent=");
- sb.append(mIntent);
-
- sb.append(", intentExtras=");
- sb.append(secure ? "***" : mIntentPersistableExtras);
+ sb.append(", intents=");
+ if (mIntents == null) {
+ sb.append("null");
+ } else {
+ if (secure) {
+ sb.append("size:");
+ sb.append(mIntents.length);
+ } else {
+ final int size = mIntents.length;
+ sb.append("[");
+ String sep = "";
+ for (int i = 0; i < size; i++) {
+ sb.append(sep);
+ sep = ", ";
+ sb.append(mIntents[i]);
+ sb.append("/");
+ sb.append(mIntentPersistableExtrases[i]);
+ }
+ sb.append("]");
+ }
+ }
sb.append(", extras=");
sb.append(mExtras);
- sb.append(", flags=");
- sb.append(mFlags);
-
if (includeInternalData) {
sb.append(", iconRes=");
- sb.append(mIconResourceId);
+ sb.append(mIconResId);
+ sb.append("[");
+ sb.append(mIconResName);
+ sb.append("]");
sb.append(", bitmapPath=");
sb.append(mBitmapPath);
@@ -881,26 +1836,36 @@ public final class ShortcutInfo implements Parcelable {
/** @hide */
public ShortcutInfo(
- @UserIdInt int userId, String id, String packageName, ComponentName activityComponent,
- Icon icon, String title, String text, Set categories, Intent intent,
- PersistableBundle intentPersistableExtras,
- int weight, PersistableBundle extras, long lastChangedTimestamp,
- int flags, int iconResId, String bitmapPath) {
+ @UserIdInt int userId, String id, String packageName, ComponentName activity,
+ Icon icon, CharSequence title, int titleResId, String titleResName,
+ CharSequence text, int textResId, String textResName,
+ CharSequence disabledMessage, int disabledMessageResId, String disabledMessageResName,
+ Set categories, Intent[] intentsWithExtras, int rank, PersistableBundle extras,
+ long lastChangedTimestamp,
+ int flags, int iconResId, String iconResName, String bitmapPath) {
mUserId = userId;
mId = id;
mPackageName = packageName;
- mActivityComponent = activityComponent;
+ mActivity = activity;
mIcon = icon;
mTitle = title;
+ mTitleResId = titleResId;
+ mTitleResName = titleResName;
mText = text;
- mCategories = clone(categories);
- mIntent = intent;
- mIntentPersistableExtras = intentPersistableExtras;
- mWeight = weight;
+ mTextResId = textResId;
+ mTextResName = textResName;
+ mDisabledMessage = disabledMessage;
+ mDisabledMessageResId = disabledMessageResId;
+ mDisabledMessageResName = disabledMessageResName;
+ mCategories = cloneCategories(categories);
+ mIntents = cloneIntents(intentsWithExtras);
+ fixUpIntentExtras();
+ mRank = rank;
mExtras = extras;
mLastChangedTimestamp = lastChangedTimestamp;
mFlags = flags;
- mIconResourceId = iconResId;
+ mIconResId = iconResId;
+ mIconResName = iconResName;
mBitmapPath = bitmapPath;
}
}
diff --git a/core/java/android/content/pm/ShortcutManager.java b/core/java/android/content/pm/ShortcutManager.java
index 16486e13e5279450819f8f9c02744fecaa80b1cc..cd248ea4e981ac2653b6f63bd62fc2073b07ced5 100644
--- a/core/java/android/content/pm/ShortcutManager.java
+++ b/core/java/android/content/pm/ShortcutManager.java
@@ -17,8 +17,11 @@ package android.content.pm;
import android.annotation.NonNull;
import android.annotation.TestApi;
+import android.annotation.UserIdInt;
+import android.app.Activity;
+import android.app.usage.UsageStatsManager;
import android.content.Context;
-import android.os.IBinder;
+import android.content.Intent;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
@@ -27,69 +30,416 @@ import com.android.internal.annotations.VisibleForTesting;
import java.util.List;
-// TODO Enhance javadoc
/**
- * {@link ShortcutManager} manages shortcuts created by applications.
+ * The ShortcutManager manages "launcher shortcuts" (or simply "shortcuts"). Shortcuts provide
+ * users
+ * with quick access to activities other than an application's main activity in the currently-active
+ * launcher. For example,
+ * an email application may publish the "compose new email" action, which will directly open the
+ * compose activity. The {@link ShortcutInfo} class contains information about each of the
+ * shortcuts themselves.
*
- *
Dynamic shortcuts and pinned shortcuts
+ *
Dynamic Shortcuts and Manifest Shortcuts
*
- * An application can publish shortcuts with {@link #setDynamicShortcuts(List)} and
- * {@link #addDynamicShortcuts(List)}. There can be at most
- * {@link #getMaxDynamicShortcutCount()} number of dynamic shortcuts at a time from the same
+ * There are two ways to publish shortcuts: manifest shortcuts and dynamic shortcuts.
+ *
+ *
+ *
Manifest shortcuts are declared in a resource
+ * XML, which is referenced in the publisher application's AndroidManifest.xml file.
+ * Manifest shortcuts are published when an application is installed,
+ * and the details of these shortcuts change when an application is upgraded with an updated XML
+ * file.
+ * Manifest shortcuts are immutable, and their
+ * definitions, such as icons and labels, cannot be changed dynamically without upgrading the
+ * publisher application.
+ *
+ *
Dynamic shortcuts are published at runtime using the {@link ShortcutManager} APIs.
+ * Applications can publish, update, and remove dynamic shortcuts at runtime.
+ *
+ *
+ *
Only "main" activities—activities that handle the {@code MAIN} action and the
+ * {@code LAUNCHER} category—can have shortcuts.
+ * If an application has multiple main activities, these activities will have different sets
+ * of shortcuts.
+ *
+ *
Dynamic shortcuts and manifest shortcuts are shown in the currently active launcher when
+ * the user long-presses on an application launcher icon. The actual gesture may be different
+ * depending on the launcher application.
+ *
+ *
Each launcher icon can have at most {@link #getMaxShortcutCountPerActivity()} number of
+ * dynamic and manifest shortcuts combined.
+ *
+ *
+ *
Pinning Shortcuts
+ *
+ * Launcher applications allow users to "pin" shortcuts so they're easier to access. Both manifest
+ * and dynamic shortcuts can be pinned.
+ * Pinned shortcuts cannot be removed by publisher
+ * applications; they're removed only when the user removes them,
+ * when the publisher application is uninstalled, or when the
+ * user performs the "clear data" action on the publisher application from the device's Settings
* application.
- * A dynamic shortcut can be deleted with {@link #removeDynamicShortcuts(List)}, and apps
- * can also use {@link #removeAllDynamicShortcuts()} to delete all dynamic shortcuts.
*
- *
The shortcuts that are currently published by the above APIs are called "dynamic", because
- * they can be removed by the creator application at any time. The user may "pin" dynamic shortcuts
- * on Launcher to make "pinned" shortcuts. Pinned shortcuts cannot be removed by the creator
- * app. An application can obtain all pinned shortcuts from itself with
- * {@link #getPinnedShortcuts()}. Applications should keep the pinned shortcut information
- * up-to-date using {@link #updateShortcuts(List)}.
+ *
However, the publisher application can disable pinned shortcuts so they cannot be
+ * started. See the following sections for details.
+ *
+ *
+ *
Updating and Disabling Shortcuts
+ *
+ *
When a dynamic shortcut is pinned, even when the publisher removes it as a dynamic shortcut,
+ * the pinned shortcut will still be visible and launchable. This allows an application to have
+ * more than {@link #getMaxShortcutCountPerActivity()} number of shortcuts.
+ *
+ *
For example, suppose {@link #getMaxShortcutCountPerActivity()} is 5:
+ *
+ *
A chat application publishes 5 dynamic shortcuts for the 5 most recent
+ * conversations, "c1" - "c5".
+ *
+ *
The user pins all 5 of the shortcuts.
+ *
+ *
Later, the user has started 3 additional conversations ("c6", "c7", and "c8"),
+ * so the publisher application
+ * re-publishes its dynamic shortcuts. The new dynamic shortcut list is:
+ * "c4", "c5", "c6", "c7", and "c8".
+ * The publisher application has to remove "c1", "c2", and "c3" because it can't have more than
+ * 5 dynamic shortcuts.
+ *
+ *
However, even though "c1", "c2" and "c3" are no longer dynamic shortcuts, the pinned
+ * shortcuts for these conversations are still available and launchable.
+ *
+ *
At this point, the user can access a total of 8 shortcuts that link to activities in
+ * the publisher application, including the 3 pinned
+ * shortcuts, even though it's allowed to have at most 5 dynamic shortcuts.
+ *
+ *
The application can use {@link #updateShortcuts(List)} to update any of the existing
+ * 8 shortcuts, when, for example, the chat peers' icons have changed.
+ *
+ * The {@link #addDynamicShortcuts(List)} and {@link #setDynamicShortcuts(List)} methods
+ * can also be used
+ * to update existing shortcuts with the same IDs, but they cannot be used
+ * for updating non-dynamic, pinned shortcuts because these two methods try to convert the given
+ * lists of shortcuts to dynamic shortcuts.
+ *
+ *
+ *
Disabling Manifest Shortcuts
+ * When an application is upgraded and the new version
+ * no longer uses a manifest shortcut that appeared in the previous version, this deprecated
+ * shortcut will no longer be published as a manifest shortcut.
+ *
+ *
If the deprecated shortcut is pinned, then the pinned shortcut will remain on the launcher,
+ * but it will be disabled automatically.
+ * Note that, in this case, the pinned shortcut is no longer a manifest shortcut, but it's
+ * still immutable and cannot be updated using the {@link ShortcutManager} APIs.
+ *
+ *
+ *
Disabling Dynamic Shortcuts
+ * Sometimes pinned shortcuts become obsolete and may not be usable. For example, a pinned shortcut
+ * to a group chat will be unusable when the associated group chat is deleted. In cases like this,
+ * applications should use {@link #disableShortcuts(List)}, which will remove the specified dynamic
+ * shortcuts and also make any specified pinned shortcuts un-launchable.
+ * The {@link #disableShortcuts(List, CharSequence)} method can also be used to disabled shortcuts
+ * and show users a custom error message when they attempt to launch the disabled shortcuts.
+ *
+ *
+ *
Publishing Manifest Shortcuts
+ *
+ * In order to add manifest shortcuts to your application, first add
+ * {@code } to your main activity in
+ * AndroidManifest.xml:
+ *
+ *
+ * Then, define your application's manifest shortcuts in the res/xml/shortcuts.xml
+ * file:
+ *
+ * <shortcuts xmlns:android="http://schemas.android.com/apk/res/android" >
+ * <shortcut
+ * android:shortcutId="compose"
+ * android:enabled="true"
+ * android:icon="@drawable/compose_icon"
+ * android:shortcutShortLabel="@string/compose_shortcut_short_label1"
+ * android:shortcutLongLabel="@string/compose_shortcut_long_label1"
+ * android:shortcutDisabledMessage="@string/compose_disabled_message1"
+ * >
+ * <intent
+ * android:action="android.intent.action.VIEW"
+ * android:targetPackage="com.example.myapplication"
+ * android:targetClass="com.example.myapplication.ComposeActivity" />
+ * <!-- more intents can go here; see below -->
+ * <categories android:name="android.shortcut.conversation" />
+ * </shortcut>
+ * <!-- more shortcuts can go here -->
+ * </shortcuts>
+ *
+ *
+ * The following list includes descriptions for the different attributes within a manifest shortcut:
+ *
+ *
android:shortcutId
+ *
Mandatory shortcut ID
+ *
+ *
android:enabled
+ *
Default is {@code true}. Can be set to {@code false} in order
+ * to disable a manifest shortcut that was published in a previous version and and set a custom
+ * disabled message. If a custom disabled message is not needed, then a manifest shortcut can
+ * be simply removed from the XML file rather than keeping it with {@code enabled="false"}.
+ *
+ *
android:icon
+ *
Shortcut icon.
+ *
+ *
android:shortcutShortLabel
+ *
Mandatory shortcut short label.
+ * See {@link ShortcutInfo.Builder#setShortLabel(CharSequence)}.
+ *
+ *
android:shortcutLongLabel
+ *
Shortcut long label.
+ * See {@link ShortcutInfo.Builder#setLongLabel(CharSequence)}.
+ *
+ *
android:shortcutDisabledMessage
+ *
When {@code android:enabled} is set to
+ * {@code false}, this attribute is used to display a custom disabled message.
+ *
+ *
intent
+ *
Intent to launch when the user selects the shortcut.
+ * {@code android:action} is mandatory.
+ * See Using intents for the
+ * other supported tags.
+ * You can provide multiple intents for a single shortcut so that an activity is launched
+ * with other activities in the back stack. See {@link android.app.TaskStackBuilder} for details.
+ *
+ *
categories
+ *
Specify shortcut categories. Currently only
+ * {@link ShortcutInfo#SHORTCUT_CATEGORY_CONVERSATION} is defined in the framework.
+ *
+ *
+ *
+ *
Publishing Dynamic Shortcuts
+ *
+ * Applications can publish dynamic shortcuts with {@link #setDynamicShortcuts(List)}
+ * or {@link #addDynamicShortcuts(List)}. The {@link #updateShortcuts(List)} method can also be
+ * used to update existing, mutable shortcuts.
+ * Use {@link #removeDynamicShortcuts(List)} or {@link #removeAllDynamicShortcuts()} to remove
+ * dynamic shortcuts.
+ *
+ *
+ * Dynamic shortcuts can be published with any set of {@link Intent#addFlags Intent} flags.
+ * Typically, {@link Intent#FLAG_ACTIVITY_CLEAR_TASK} is specified, possibly along with other
+ * flags; otherwise, if the application is already running, the application is simply brought to
+ * the foreground, and the target activity may not appear.
+ *
+ *
The {@link ShortcutInfo.Builder#setIntents(Intent[])} method can be used instead of
+ * {@link ShortcutInfo.Builder#setIntent(Intent)} with {@link android.app.TaskStackBuilder}
+ * in order to launch an activity with other activities in the back stack.
+ * When the user selects a shortcut to load an activity with a back stack,
+ * then presses the back key, a "parent" activity will be shown instead of the user being
+ * navigated back to the launcher.
+ *
+ *
Manifest shortcuts can also have multiple intents to achieve the same effect.
+ * In order to associate multiple {@link Intent} objects with a shortcut, simply list multiple
+ * <intent> elements within a single <shortcut> element.
+ * The last intent specifies what the user will see when they launch a shortcut.
+ *
+ *
Manifest shortcuts cannot have custom intent flags.
+ * The first intent of a manifest shortcut will always have {@link Intent#FLAG_ACTIVITY_NEW_TASK}
+ * and {@link Intent#FLAG_ACTIVITY_CLEAR_TASK} set.
+ * This means, when the application is already running, all the existing activities will be
+ * destroyed when a manifest shortcut is launched.
+ * If this behavior is not desirable, you can use a trampoline activity,
+ * or an invisible activity that starts another activity in {@link Activity#onCreate},
+ * then calls {@link Activity#finish()}.
+ * The first activity should include an attribute setting
+ * of {@code android:taskAffinity=""} in the application's AndroidManifest.xml
+ * file, and the intent within the manifest shortcut should point at this first activity.
+ *
+ *
+ *
Showing New Information in a Shortcut
+ * In order to avoid confusion, you should not use {@link #updateShortcuts(List)} to update
+ * a shortcut so that it contains conceptually different information.
+ *
+ *
For example, a phone application may publish the most frequently called contact as a dynamic
+ * shortcut. Over time, this contact may change; when it does, the application should
+ * represent the changed contact with a new shortcut that contains a different ID, using either
+ * {@link #setDynamicShortcuts(List)} or {@link #addDynamicShortcuts(List)}, rather than updating
+ * the existing shortcut with {@link #updateShortcuts(List)}.
+ * This is because when the shortcut is pinned, changing
+ * it to reference a different contact will likely confuse the user.
+ *
+ *
On the other hand, when the
+ * contact's information has changed, such as the name or picture, the application should
+ * use {@link #updateShortcuts(List)} so that the pinned shortcut is updated too.
*
- *
The number of pinned shortcuts does not affect the number of dynamic shortcuts that can be
- * published by an application at a time.
- * No matter how many pinned shortcuts that Launcher has for an application, the
- * application can still always publish {@link #getMaxDynamicShortcutCount()} number of dynamic
- * shortcuts.
*
- *
Shortcut IDs
+ *
Shortcut Display Order
+ * When the launcher displays the shortcuts that are associated with a particular launcher icon,
+ * the shortcuts should appear in the following order:
+ *
+ *
First show manifest shortcuts
+ * (if {@link ShortcutInfo#isDeclaredInManifest()} is {@code true}),
+ * and then show dynamic shortcuts (if {@link ShortcutInfo#isDynamic()} is {@code true}).
+ *
Within each category of shortcuts (manifest and dynamic), sort the shortcuts in order
+ * of increasing rank according to {@link ShortcutInfo#getRank()}.
+ *
+ *
Shortcut ranks are non-negative sequential integers
+ * that determine the order in which shortcuts appear, assuming that the shortcuts are all in
+ * the same category.
+ * Ranks of existing shortcuts can be updated with
+ * {@link #updateShortcuts(List)}; you can use {@link #addDynamicShortcuts(List)} and
+ * {@link #setDynamicShortcuts(List)}, too.
*
- * Each shortcut must have an ID, which must be unique within each application. When a shortcut is
- * published, existing shortcuts with the same ID will be updated. Note this may include a
- * pinned shortcut.
+ *
Ranks are auto-adjusted so that they're unique for each target activity in each category
+ * (dynamic or manifest). For example, if there are 3 dynamic shortcuts with ranks 0, 1 and 2,
+ * adding another dynamic shortcut with a rank of 1 represents a request to place this shortcut at
+ * the second position.
+ * In response, the third and fourth shortcuts move closer to the bottom of the shortcut list,
+ * with their ranks changing to 2 and 3, respectively.
*
- *
Rate limiting
+ *
Rate Limiting
*
- * Calls to {@link #setDynamicShortcuts(List)}, {@link #addDynamicShortcuts(List)},
- * and {@link #updateShortcuts(List)} from background applications will be
- * rate-limited. An application can call these methods at most
- * {@link #getRemainingCallCount()} times until the rate-limiting counter is reset,
- * which happens at a certain time every day.
+ * Calls to {@link #setDynamicShortcuts(List)}, {@link #addDynamicShortcuts(List)}, and
+ * {@link #updateShortcuts(List)} may be rate-limited when called by background applications, or
+ * applications with no foreground activity or service. When you attempt to call these methods
+ * from a background application after exceeding the rate limit, these APIs return {@code false}.
*
- *
An application can use {@link #getRateLimitResetTime()} to get the next reset time.
+ *
Applications with a foreground activity or service are not rate-limited.
*
- *
Foreground applications (i.e. ones with a foreground activity or a foreground services)
- * will not be throttled. Also, when an application comes to foreground,
- * {@link #getRemainingCallCount()} will be reset to the initial value.
+ *
Rate-limiting will be reset upon certain events, so that even background applications
+ * can call these APIs again until they are rate limit is reached again.
+ * These events include the following:
+ *
+ *
When an application comes to the foreground.
+ *
When the system locale changes.
+ *
When the user performs an "inline reply" action on a notification.
+ *
+ *
+ *
When rate-limiting is active, {@link #isRateLimitingActive()} returns {@code true}.
+ *
+ *
Resetting rate-limiting for testing
+ *
+ * If your application is rate-limited during development or testing, you can use the
+ * "Reset ShortcutManager rate-limiting" development option or the following adb command to reset
+ * it:
+ *
+ *
+ * Applications should update dynamic and pinned shortcuts when the system locale changes
+ * using the {@link Intent#ACTION_LOCALE_CHANGED} broadcast.
+ *
+ *
When the system locale changes, rate-limiting is reset, so even background applications
+ * can set dynamic shortcuts, add dynamic shortcuts, and update shortcuts until the rate limit
+ * is reached again.
*
- *
For testing purposes, use "Developer Options" (found in the Settings menu) to reset the
- * internal rate-limiting counter. Automated tests can use the following ADB shell command to
- * achieve the same effect:
- *
adb shell cmd shortcut reset-throttling
*
*
Backup and Restore
*
- * Shortcuts will be backed up and restored across devices. This means all information, including
- * IDs, must be meaningful on a different device.
+ * When an application has the {@code android:allowBackup="true"} attribute assignment included
+ * in its AndroidManifest.xml file, pinned shortcuts are
+ * backed up automatically and are restored when the user sets up a new device.
+ *
+ *
Categories of Shortcuts that are Backed Up
+ *
+ *
+ *
Pinned shortcuts are backed up. Bitmap icons are not backed up by the system,
+ * but launcher applications should back them up and restore them so that the user still sees icons
+ * for pinned shortcuts on the launcher. Applications can always use
+ * {@link #updateShortcuts(List)} to re-publish icons.
+ *
+ *
Manifest shortcuts are not backed up, but when an application is re-installed on a new
+ * device, they are re-published from the AndroidManifest.xml file, anyway.
+ *
+ *
Dynamic shortcuts are not backed up.
+ *
+ *
+ *
Because dynamic shortcuts are not restored, it is recommended that applications check
+ * currently-published dynamic shortcuts using {@link #getDynamicShortcuts()}
+ * each time they are launched, and they should re-publish
+ * dynamic shortcuts when necessary.
+ *
+ *
+ * public class MainActivity extends Activity {
+ * public void onCreate(Bundle savedInstanceState) {
+ * super.onCreate(savedInstanceState);
+ *
+ * ShortcutManager shortcutManager = getSystemService(ShortcutManager.class);
+ *
+ * if (shortcutManager.getDynamicShortcuts().size() == 0) {
+ * // Application restored; re-publish dynamic shortcuts.
+ *
+ * if (shortcutManager.getPinnedShortcuts().size() > 0) {
+ * // Pinned shortcuts have been restored. Use updateShortcuts() to make sure
+ * // they have up-to-date information.
+ * }
+ * }
+ * }
+ * :
+ *
+ * }
+ *
+ *
+ *
+ *
Backup/restore and shortcut IDs
+ *
+ * Because pinned shortcuts are backed up and restored on new devices, shortcut IDs should be
+ * meaningful across devices; that is, IDs should contain either stable, constant strings
+ * or server-side identifiers,
+ * rather than identifiers generated locally that might not make sense on other devices.
+ *
+ *
+ *
Report Shortcut Usage and Prediction
+ *
+ * Launcher applications may be capable of predicting which shortcuts will most likely be
+ * used at a given time by examining the shortcut usage history data.
+ *
+ *
In order to provide launchers with such data, publisher applications should
+ * report the shortcuts that are used with {@link #reportShortcutUsed(String)}
+ * when a shortcut is selected,
+ * or when an action equivalent to a shortcut is taken by the user even if it wasn't started
+ * with the shortcut.
*
- *
APIs for launcher
+ *
For example, suppose a GPS navigation application supports "navigate to work" as a shortcut.
+ * It should then report when the user selects this shortcut and when the user chooses
+ * to navigate to work within the application itself.
+ * This helps the launcher application
+ * learn that the user wants to navigate to work at a certain time every
+ * weekday, and it can then show this shortcut in a suggestion list at the right time.
*
- * Launcher applications should use {@link LauncherApps} to get shortcuts that are published from
- * applications. Launcher applications can also pin shortcuts with
- * {@link LauncherApps#pinShortcuts(String, List, UserHandle)}.
+ *
Launcher API
*
- * @hide
+ * The {@link LauncherApps} class provides APIs for launcher applications to access shortcuts.
+ *
+ *
+ *
Direct Boot and Shortcuts
+ *
+ * All shortcut information is stored in credential encrypted storage, so no shortcuts can be
+ * accessed when the user is locked.
*/
public class ShortcutManager {
private static final String TAG = "ShortcutManager";
@@ -115,15 +465,18 @@ public class ShortcutManager {
}
/**
- * Publish a list of shortcuts. All existing dynamic shortcuts from the caller application
- * will be replaced.
+ * Publish the list of shortcuts. All existing dynamic shortcuts from the caller application
+ * will be replaced. If there are already pinned shortcuts with the same IDs,
+ * the mutable pinned shortcuts are updated.
*
*
This API will be rate-limited.
*
* @return {@code true} if the call has succeeded. {@code false} if the call is rate-limited.
*
- * @throws IllegalArgumentException if {@code shortcutInfoList} contains more than
- * {@link #getMaxDynamicShortcutCount()} shortcuts.
+ * @throws IllegalArgumentException if {@link #getMaxShortcutCountPerActivity()} is exceeded,
+ * or when trying to update immutable shortcuts.
+ *
+ * @throws IllegalStateException when the user is locked.
*/
public boolean setDynamicShortcuts(@NonNull List shortcutInfoList) {
try {
@@ -135,8 +488,9 @@ public class ShortcutManager {
}
/**
- * Return all dynamic shortcuts from the caller application. The number of result items
- * will not exceed the value returned by {@link #getMaxDynamicShortcutCount()}.
+ * Return all dynamic shortcuts from the caller application.
+ *
+ * @throws IllegalStateException when the user is locked.
*/
@NonNull
public List getDynamicShortcuts() {
@@ -149,15 +503,32 @@ public class ShortcutManager {
}
/**
- * Publish a single dynamic shortcut. If there's already dynamic or pinned shortcuts with
- * the same ID, they will all be updated.
+ * Return all manifest shortcuts from the caller application.
+ *
+ * @throws IllegalStateException when the user is locked.
+ */
+ @NonNull
+ public List getManifestShortcuts() {
+ try {
+ return mService.getManifestShortcuts(mContext.getPackageName(), injectMyUserId())
+ .getList();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Publish the list of dynamic shortcuts. If there are already dynamic or pinned shortcuts with
+ * the same IDs, each mutable shortcut is updated.
*
*
This API will be rate-limited.
*
* @return {@code true} if the call has succeeded. {@code false} if the call is rate-limited.
*
- * @throws IllegalArgumentException if the caller application has already published the
- * max number of dynamic shortcuts.
+ * @throws IllegalArgumentException if {@link #getMaxShortcutCountPerActivity()} is exceeded,
+ * or when trying to update immutable shortcuts.
+ *
+ * @throws IllegalStateException when the user is locked.
*/
public boolean addDynamicShortcuts(@NonNull List shortcutInfoList) {
try {
@@ -169,7 +540,9 @@ public class ShortcutManager {
}
/**
- * Delete a single dynamic shortcut by ID.
+ * Delete dynamic shortcuts by ID.
+ *
+ * @throws IllegalStateException when the user is locked.
*/
public void removeDynamicShortcuts(@NonNull List shortcutIds) {
try {
@@ -182,6 +555,8 @@ public class ShortcutManager {
/**
* Delete all dynamic shortcuts from the caller application.
+ *
+ * @throws IllegalStateException when the user is locked.
*/
public void removeAllDynamicShortcuts() {
try {
@@ -193,6 +568,8 @@ public class ShortcutManager {
/**
* Return all pinned shortcuts from the caller application.
+ *
+ * @throws IllegalStateException when the user is locked.
*/
@NonNull
public List getPinnedShortcuts() {
@@ -205,11 +582,16 @@ public class ShortcutManager {
}
/**
- * Update all existing shortcuts with the same IDs. Shortcuts may be pinned and/or dynamic.
+ * Update all existing shortcuts with the same IDs. Target shortcuts may be pinned and/or
+ * dynamic, but they must not be immutable.
*
*
This API will be rate-limited.
*
* @return {@code true} if the call has succeeded. {@code false} if the call is rate-limited.
+ *
+ * @throws IllegalArgumentException If trying to update immutable shortcuts.
+ *
+ * @throws IllegalStateException when the user is locked.
*/
public boolean updateShortcuts(List shortcutInfoList) {
try {
@@ -221,11 +603,94 @@ public class ShortcutManager {
}
/**
- * Return the max number of dynamic shortcuts that each application can have at a time.
+ * Disable pinned shortcuts. For more details, see the Javadoc for the {@link ShortcutManager}
+ * class.
+ *
+ * @throws IllegalArgumentException If trying to disable immutable shortcuts.
+ *
+ * @throws IllegalStateException when the user is locked.
+ */
+ public void disableShortcuts(@NonNull List shortcutIds) {
+ try {
+ mService.disableShortcuts(mContext.getPackageName(), shortcutIds,
+ /* disabledMessage =*/ null, /* disabledMessageResId =*/ 0,
+ injectMyUserId());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * @hide old signature, kept for unit testing.
*/
- public int getMaxDynamicShortcutCount() {
+ public void disableShortcuts(@NonNull List shortcutIds, int disabledMessageResId) {
try {
- return mService.getMaxDynamicShortcutCount(mContext.getPackageName(), injectMyUserId());
+ mService.disableShortcuts(mContext.getPackageName(), shortcutIds,
+ /* disabledMessage =*/ null, disabledMessageResId,
+ injectMyUserId());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * @hide old signature, kept for unit testing.
+ */
+ public void disableShortcuts(@NonNull List shortcutIds, String disabledMessage) {
+ disableShortcuts(shortcutIds, (CharSequence) disabledMessage);
+ }
+
+ /**
+ * Disable pinned shortcuts, showing the user a custom error message when they try to select
+ * the disabled shortcuts.
+ * For more details, see the Javadoc for the {@link ShortcutManager} class.
+ *
+ * @throws IllegalArgumentException If trying to disable immutable shortcuts.
+ *
+ * @throws IllegalStateException when the user is locked.
+ */
+ public void disableShortcuts(@NonNull List shortcutIds, CharSequence disabledMessage) {
+ try {
+ mService.disableShortcuts(mContext.getPackageName(), shortcutIds,
+ disabledMessage, /* disabledMessageResId =*/ 0,
+ injectMyUserId());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Re-enable pinned shortcuts that were previously disabled. If the target shortcuts
+ * already enabled, this method does nothing.
+ *
+ * @throws IllegalArgumentException If trying to enable immutable shortcuts.
+ *
+ * @throws IllegalStateException when the user is locked.
+ */
+ public void enableShortcuts(@NonNull List shortcutIds) {
+ try {
+ mService.enableShortcuts(mContext.getPackageName(), shortcutIds, injectMyUserId());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+
+ /**
+ * @hide old signature, kept for unit testing.
+ */
+ public int getMaxShortcutCountForActivity() {
+ return getMaxShortcutCountPerActivity();
+ }
+
+ /**
+ * Return the maximum number of dynamic and manifest shortcuts that each launcher icon
+ * can have at a time.
+ */
+ public int getMaxShortcutCountPerActivity() {
+ try {
+ return mService.getMaxShortcutCountPerActivity(
+ mContext.getPackageName(), injectMyUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -236,6 +701,8 @@ public class ShortcutManager {
* before the rate limit counter is reset.
*
* @see #getRateLimitResetTime()
+ *
+ * @hide
*/
public int getRemainingCallCount() {
try {
@@ -250,6 +717,8 @@ public class ShortcutManager {
*
* @see #getRemainingCallCount()
* @see System#currentTimeMillis()
+ *
+ * @hide
*/
public long getRateLimitResetTime() {
try {
@@ -260,16 +729,82 @@ public class ShortcutManager {
}
/**
- * Return the max width and height for icons, in pixels.
+ * Return {@code true} when rate-limiting is active for the caller application.
+ *
+ *
See the class level javadoc for details.
+ *
+ * @throws IllegalStateException when the user is locked.
+ */
+ public boolean isRateLimitingActive() {
+ try {
+ return mService.getRemainingCallCount(mContext.getPackageName(), injectMyUserId())
+ == 0;
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Return the max width for icons, in pixels.
+ */
+ public int getIconMaxWidth() {
+ try {
+ // TODO Implement it properly using xdpi.
+ return mService.getIconMaxDimensions(mContext.getPackageName(), injectMyUserId());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Return the max height for icons, in pixels.
*/
- public int getIconMaxDimensions() {
+ public int getIconMaxHeight() {
try {
+ // TODO Implement it properly using ydpi.
return mService.getIconMaxDimensions(mContext.getPackageName(), injectMyUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
+ /**
+ * Applications that publish shortcuts should call this method
+ * whenever the user selects the shortcut containing the given ID or when the user completes
+ * an action in the application that is equivalent to selecting the shortcut.
+ * For more details, see the Javadoc for the {@link ShortcutManager} class
+ *
+ *
The information is accessible via {@link UsageStatsManager#queryEvents}
+ * Typically, launcher applications use this information to build a prediction model
+ * so that they can promote the shortcuts that are likely to be used at the moment.
+ *
+ * @throws IllegalStateException when the user is locked.
+ */
+ public void reportShortcutUsed(String shortcutId) {
+ try {
+ mService.reportShortcutUsed(mContext.getPackageName(), shortcutId,
+ injectMyUserId());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Called internally when an application is considered to have come to foreground
+ * even when technically it's not. This method resets the throttling for this package.
+ * For example, when the user sends an "inline reply" on an notification, the system UI will
+ * call it.
+ *
+ * @hide
+ */
+ public void onApplicationActive(@NonNull String packageName, @UserIdInt int userId) {
+ try {
+ mService.onApplicationActive(packageName, userId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
/** @hide injection point */
@VisibleForTesting
protected int injectMyUserId() {
diff --git a/core/java/android/content/pm/ShortcutServiceInternal.java b/core/java/android/content/pm/ShortcutServiceInternal.java
index 3f8bad15035bfe08834c675f18a2ee704db96d23..af5610570f70ed260bfed84e4a7f35f73cdf55ee 100644
--- a/core/java/android/content/pm/ShortcutServiceInternal.java
+++ b/core/java/android/content/pm/ShortcutServiceInternal.java
@@ -53,7 +53,8 @@ public abstract class ShortcutServiceInternal {
@NonNull String callingPackage, @NonNull String packageName,
@NonNull List shortcutIds, int userId);
- public abstract Intent createShortcutIntent(int launcherUserId, @NonNull String callingPackage,
+ public abstract Intent[] createShortcutIntents(
+ int launcherUserId, @NonNull String callingPackage,
@NonNull String packageName, @NonNull String shortcutId, int userId);
public abstract void addListener(@NonNull ShortcutChangeListener listener);
@@ -67,10 +68,4 @@ public abstract class ShortcutServiceInternal {
public abstract boolean hasShortcutHostPermission(int launcherUserId,
@NonNull String callingPackage);
-
- /**
- * Called by AM when the system locale changes *within the AM lock*. ABSOLUTELY do not take
- * any locks in this method.
- */
- public abstract void onSystemLocaleChangedNoLock();
}
diff --git a/core/java/android/content/pm/UserInfo.java b/core/java/android/content/pm/UserInfo.java
index dd3a36c7996c5e08670b452e1c743e158ca58025..6cd84033da8c137955e138e3c8b323ce3d24882f 100644
--- a/core/java/android/content/pm/UserInfo.java
+++ b/core/java/android/content/pm/UserInfo.java
@@ -28,8 +28,8 @@ import android.os.UserManager;
*/
public class UserInfo implements Parcelable {
- /** 8 bits for user type */
- public static final int FLAG_MASK_USER_TYPE = 0x000000FF;
+ /** 16 bits for user type */
+ public static final int FLAG_MASK_USER_TYPE = 0x0000FFFF;
/**
* *************************** NOTE ***************************
@@ -87,6 +87,11 @@ public class UserInfo implements Parcelable {
*/
public static final int FLAG_EPHEMERAL = 0x00000100;
+ /**
+ * User is for demo purposes only and can be removed at any time.
+ */
+ public static final int FLAG_DEMO = 0x00000200;
+
public static final int NO_PROFILE_GROUP_ID = UserHandle.USER_NULL;
public int id;
@@ -153,6 +158,10 @@ public class UserInfo implements Parcelable {
return (flags & FLAG_INITIALIZED) == FLAG_INITIALIZED;
}
+ public boolean isDemo() {
+ return (flags & FLAG_DEMO) == FLAG_DEMO;
+ }
+
/**
* Returns true if the user is a split system user.
*
If {@link UserManager#isSplitSystemUser split system user mode} is not enabled,
diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java
index 6f43d99ecb9583e4f1f192624d44d27ef3b027ad..b2d518c56ca0a4fc68746673f82effd305666d79 100644
--- a/core/java/android/content/res/Configuration.java
+++ b/core/java/android/content/res/Configuration.java
@@ -1543,27 +1543,41 @@ public final class Configuration implements Parcelable, Comparable
- * When it returns, the array values is filled with the result:
+ * When it returns, the array values are as follows:
*
- *
values[0]: azimuth, rotation around the -Z axis,
- * i.e. the opposite direction of Z axis.
- *
values[1]: pitch, rotation around the -X axis,
- * i.e the opposite direction of X axis.
- *
values[2]: roll, rotation around the Y axis.
+ *
values[0]: Azimuth, angle of rotation about the -z axis.
+ * This value represents the angle between the device's y
+ * axis and the magnetic north pole. When facing north, this
+ * angle is 0, when facing south, this angle is π.
+ * Likewise, when facing east, this angle is π/2, and
+ * when facing west, this angle is -π/2. The range of
+ * values is -π to π.
+ *
values[1]: Pitch, angle of rotation about the x axis.
+ * This value represents the angle between a plane parallel
+ * to the device's screen and a plane parallel to the ground.
+ * Assuming that the bottom edge of the device faces the
+ * user and that the screen is face-up, tilting the top edge
+ * of the device toward the ground creates a positive pitch
+ * angle. The range of values is -π to π.
+ *
values[2]: Roll, angle of rotation about the y axis. This
+ * value represents the angle between a plane perpendicular
+ * to the device's screen and a plane perpendicular to the
+ * ground. Assuming that the bottom edge of the device faces
+ * the user and that the screen is face-up, tilting the left
+ * edge of the device toward the ground creates a positive
+ * roll angle. The range of values is -π/2 to π/2.
*
*
- * Applying these three intrinsic rotations in azimuth, pitch and roll order transforms
- * identity matrix to the rotation matrix given in input R.
- * All three angles above are in radians and positive in the
- * counter-clockwise direction. Range of output is: azimuth from -π to π,
- * pitch from -π/2 to π/2 and roll from -π to π.
+ * Applying these three rotations in the azimuth, pitch, roll order
+ * transforms an identity matrix to the rotation matrix passed into this
+ * method. Also, note that all three orientation angles are expressed in
+ * radians.
*
* @param R
* rotation matrix see {@link #getRotationMatrix}.
diff --git a/core/java/android/hardware/camera2/CameraCaptureSession.java b/core/java/android/hardware/camera2/CameraCaptureSession.java
index 38279a47f2a9b7040b702c38c5f74311be0e3c5c..4b211873598365768517aff397ac055a3130cf87 100644
--- a/core/java/android/hardware/camera2/CameraCaptureSession.java
+++ b/core/java/android/hardware/camera2/CameraCaptureSession.java
@@ -18,6 +18,7 @@ package android.hardware.camera2;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.hardware.camera2.params.OutputConfiguration;
import android.os.Handler;
import android.view.Surface;
@@ -219,6 +220,53 @@ public abstract class CameraCaptureSession implements AutoCloseable {
*/
public abstract void tearDown(@NonNull Surface surface) throws CameraAccessException;
+ /**
+ *
+ * Finish the deferred output configurations where the output Surface was not configured before.
+ *
+ *
+ * For camera use cases where a preview and other output configurations need to be configured,
+ * it can take some time for the preview Surface to be ready (e.g., if the preview Surface is
+ * obtained from {@link android.view.SurfaceView}, the SurfaceView is ready after the UI layout
+ * is done, then it takes some time to get the preview Surface).
+ *
+ *
+ * To speed up camera startup time, the application can configure the
+ * {@link CameraCaptureSession} with the desired preview size, and defer the preview output
+ * configuration until the Surface is ready. After the {@link CameraCaptureSession} is created
+ * successfully with this deferred configuration and other normal configurations, the
+ * application can submit requests that don't include deferred output Surfaces. Once the
+ * deferred Surface is ready, the application can set the Surface to the same deferred output
+ * configuration with the {@link OutputConfiguration#setDeferredSurface} method, and then finish
+ * the deferred output configuration via this method, before it can submit requests with this
+ * output target.
+ *
+ *
+ * The output Surfaces included by this list of deferred {@link OutputConfiguration
+ * OutputConfigurations} can be used as {@link CaptureRequest} targets as soon as this call
+ * returns;
+ *
+ *
+ * This method is not supported by Legacy devices.
+ *
+ *
+ * @param deferredOutputConfigs a list of {@link OutputConfiguration OutputConfigurations} that
+ * have had {@link OutputConfiguration#setDeferredSurface setDeferredSurface} invoked
+ * with a valid output Surface.
+ * @throws CameraAccessException if the camera device is no longer connected or has encountered
+ * a fatal error.
+ * @throws IllegalStateException if this session is no longer active, either because the session
+ * was explicitly closed, a new session has been created or the camera device has
+ * been closed. Or if this output configuration was already finished with the
+ * included surface before.
+ * @throws IllegalArgumentException for invalid output configurations, including ones where the
+ * source of the Surface is no longer valid or the Surface is from a unsupported
+ * source.
+ * @hide
+ */
+ public abstract void finishDeferredConfiguration(
+ List deferredOutputConfigs) throws CameraAccessException;
+
/**
*
Submit a request for an image to be captured by the camera device.
*
diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java
index 3917bfa6beea58657b2faa204b01761970008900..145b1d076e80789309f8fbae58ee953518cad181 100644
--- a/core/java/android/hardware/camera2/CameraManager.java
+++ b/core/java/android/hardware/camera2/CameraManager.java
@@ -267,6 +267,10 @@ public final class CameraManager {
* @param cameraId The unique identifier of the camera device to open
* @param callback The callback for the camera. Must not be null.
* @param handler The handler to invoke the callback on. Must not be null.
+ * @param uid The UID of the application actually opening the camera.
+ * Must be USE_CALLING_UID unless the caller is a service
+ * that is trusted to open the device on behalf of an
+ * application and to forward the real UID.
*
* @throws CameraAccessException if the camera is disabled by device policy,
* too many camera devices are already open, or the cameraId does not match
@@ -281,7 +285,7 @@ public final class CameraManager {
* @see android.app.admin.DevicePolicyManager#setCameraDisabled
*/
private CameraDevice openCameraDeviceUserAsync(String cameraId,
- CameraDevice.StateCallback callback, Handler handler)
+ CameraDevice.StateCallback callback, Handler handler, final int uid)
throws CameraAccessException {
CameraCharacteristics characteristics = getCameraCharacteristics(cameraId);
CameraDevice device = null;
@@ -317,7 +321,7 @@ public final class CameraManager {
"Camera service is currently unavailable");
}
cameraUser = cameraService.connectDevice(callbacks, id,
- mContext.getOpPackageName(), USE_CALLING_UID);
+ mContext.getOpPackageName(), uid);
} else {
// Use legacy camera implementation for HAL1 devices
Log.i(TAG, "Using legacy camera HAL.");
@@ -434,6 +438,29 @@ public final class CameraManager {
@NonNull final CameraDevice.StateCallback callback, @Nullable Handler handler)
throws CameraAccessException {
+ openCameraForUid(cameraId, callback, handler, USE_CALLING_UID);
+ }
+
+ /**
+ * Open a connection to a camera with the given ID, on behalf of another application
+ * specified by clientUid.
+ *
+ *
The behavior of this method matches that of {@link #openCamera}, except that it allows
+ * the caller to specify the UID to use for permission/etc verification. This can only be
+ * done by services trusted by the camera subsystem to act on behalf of applications and
+ * to forward the real UID.
+ *
+ * @param clientUid
+ * The UID of the application on whose behalf the camera is being opened.
+ * Must be USE_CALLING_UID unless the caller is a trusted service.
+ *
+ * @hide
+ */
+ public void openCameraForUid(@NonNull String cameraId,
+ @NonNull final CameraDevice.StateCallback callback, @Nullable Handler handler,
+ int clientUid)
+ throws CameraAccessException {
+
if (cameraId == null) {
throw new IllegalArgumentException("cameraId was null");
} else if (callback == null) {
@@ -447,7 +474,7 @@ public final class CameraManager {
}
}
- openCameraDeviceUserAsync(cameraId, callback, handler);
+ openCameraDeviceUserAsync(cameraId, callback, handler, clientUid);
}
/**
diff --git a/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
index 6736d3466e2cd80e13e174f5a9a8972a99e79f52..b10c341eb5ec7e4117f09bd1dbc8951380d0b283 100644
--- a/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
@@ -24,6 +24,7 @@ import android.hardware.camera2.dispatch.BroadcastDispatcher;
import android.hardware.camera2.dispatch.DuckTypingDispatcher;
import android.hardware.camera2.dispatch.HandlerDispatcher;
import android.hardware.camera2.dispatch.InvokeDispatcher;
+import android.hardware.camera2.params.OutputConfiguration;
import android.hardware.camera2.utils.TaskDrainer;
import android.hardware.camera2.utils.TaskSingleDrainer;
import android.os.Handler;
@@ -155,6 +156,12 @@ public class CameraCaptureSessionImpl extends CameraCaptureSession
mDeviceImpl.tearDown(surface);
}
+ @Override
+ public void finishDeferredConfiguration(
+ List deferredOutputConfigs) throws CameraAccessException {
+ mDeviceImpl.finishDeferredConfig(deferredOutputConfigs);
+ }
+
@Override
public synchronized int capture(CaptureRequest request, CaptureCallback callback,
Handler handler) throws CameraAccessException {
@@ -279,23 +286,29 @@ public class CameraCaptureSessionImpl extends CameraCaptureSession
}
@Override
- public synchronized void abortCaptures() throws CameraAccessException {
- checkNotClosed();
+ public void abortCaptures() throws CameraAccessException {
+ synchronized (this) {
+ checkNotClosed();
- if (DEBUG) {
- Log.v(TAG, mIdString + "abortCaptures");
- }
+ if (DEBUG) {
+ Log.v(TAG, mIdString + "abortCaptures");
+ }
- if (mAborting) {
- Log.w(TAG, mIdString + "abortCaptures - Session is already aborting; doing nothing");
- return;
- }
+ if (mAborting) {
+ Log.w(TAG, mIdString + "abortCaptures - Session is already aborting; doing nothing");
+ return;
+ }
- mAborting = true;
- mAbortDrainer.taskStarted();
+ mAborting = true;
+ mAbortDrainer.taskStarted();
+ }
- mDeviceImpl.flush();
- // The next BUSY -> IDLE set of transitions will mark the end of the abort.
+ synchronized (mDeviceImpl.mInterfaceLock) {
+ synchronized (this) {
+ mDeviceImpl.flush();
+ // The next BUSY -> IDLE set of transitions will mark the end of the abort.
+ }
+ }
}
@Override
@@ -323,78 +336,86 @@ public class CameraCaptureSessionImpl extends CameraCaptureSession
* @see CameraCaptureSession#close
*/
@Override
- public synchronized void replaceSessionClose() {
- /*
- * In order for creating new sessions to be fast, the new session should be created
- * before the old session is closed.
- *
- * Otherwise the old session will always unconfigure if there is no new session to
- * replace it.
- *
- * Unconfiguring could add hundreds of milliseconds of delay. We could race and attempt
- * to skip unconfigure if a new session is created before the captures are all drained,
- * but this would introduce nondeterministic behavior.
- */
-
- if (DEBUG) Log.v(TAG, mIdString + "replaceSessionClose");
-
- // Set up fast shutdown. Possible alternative paths:
- // - This session is active, so close() below starts the shutdown drain
- // - This session is mid-shutdown drain, and hasn't yet reached the idle drain listener.
- // - This session is already closed and has executed the idle drain listener, and
- // configureOutputsChecked(null) has already been called.
- //
- // Do not call configureOutputsChecked(null) going forward, since it would race with the
- // configuration for the new session. If it was already called, then we don't care, since it
- // won't get called again.
- mSkipUnconfigure = true;
+ public void replaceSessionClose() {
+ synchronized (this) {
+ /*
+ * In order for creating new sessions to be fast, the new session should be created
+ * before the old session is closed.
+ *
+ * Otherwise the old session will always unconfigure if there is no new session to
+ * replace it.
+ *
+ * Unconfiguring could add hundreds of milliseconds of delay. We could race and attempt
+ * to skip unconfigure if a new session is created before the captures are all drained,
+ * but this would introduce nondeterministic behavior.
+ */
+ if (DEBUG) Log.v(TAG, mIdString + "replaceSessionClose");
+
+ // Set up fast shutdown. Possible alternative paths:
+ // - This session is active, so close() below starts the shutdown drain
+ // - This session is mid-shutdown drain, and hasn't yet reached the idle drain listener.
+ // - This session is already closed and has executed the idle drain listener, and
+ // configureOutputsChecked(null) has already been called.
+ //
+ // Do not call configureOutputsChecked(null) going forward, since it would race with the
+ // configuration for the new session. If it was already called, then we don't care,
+ // since it won't get called again.
+ mSkipUnconfigure = true;
+ }
close();
}
@Override
- public synchronized void close() {
-
- if (mClosed) {
- if (DEBUG) Log.v(TAG, mIdString + "close - reentering");
- return;
- }
+ public void close() {
+ synchronized (this) {
+ if (mClosed) {
+ if (DEBUG) Log.v(TAG, mIdString + "close - reentering");
+ return;
+ }
- if (DEBUG) Log.v(TAG, mIdString + "close - first time");
+ if (DEBUG) Log.v(TAG, mIdString + "close - first time");
- mClosed = true;
+ mClosed = true;
+ }
- /*
- * Flush out any repeating request. Since camera is closed, no new requests
- * can be queued, and eventually the entire request queue will be drained.
- *
- * If the camera device was already closed, short circuit and do nothing; since
- * no more internal device callbacks will fire anyway.
- *
- * Otherwise, once stopRepeating is done, wait for camera to idle, then unconfigure the
- * camera. Once that's done, fire #onClosed.
- */
- try {
- mDeviceImpl.stopRepeating();
- } catch (IllegalStateException e) {
- // OK: Camera device may already be closed, nothing else to do
+ synchronized (mDeviceImpl.mInterfaceLock) {
+ synchronized (this) {
+ /*
+ * Flush out any repeating request. Since camera is closed, no new requests
+ * can be queued, and eventually the entire request queue will be drained.
+ *
+ * If the camera device was already closed, short circuit and do nothing; since
+ * no more internal device callbacks will fire anyway.
+ *
+ * Otherwise, once stopRepeating is done, wait for camera to idle, then unconfigure
+ * the camera. Once that's done, fire #onClosed.
+ */
+ try {
+ mDeviceImpl.stopRepeating();
+ } catch (IllegalStateException e) {
+ // OK: Camera device may already be closed, nothing else to do
- // TODO: Fire onClosed anytime we get the device onClosed or the ISE?
- // or just suppress the ISE only and rely onClosed.
- // Also skip any of the draining work if this is already closed.
+ // TODO: Fire onClosed anytime we get the device onClosed or the ISE?
+ // or just suppress the ISE only and rely onClosed.
+ // Also skip any of the draining work if this is already closed.
- // Short-circuit; queue callback immediately and return
- mStateCallback.onClosed(this);
- return;
- } catch (CameraAccessException e) {
- // OK: close does not throw checked exceptions.
- Log.e(TAG, mIdString + "Exception while stopping repeating: ", e);
+ // Short-circuit; queue callback immediately and return
+ mStateCallback.onClosed(this);
+ return;
+ } catch (CameraAccessException e) {
+ // OK: close does not throw checked exceptions.
+ Log.e(TAG, mIdString + "Exception while stopping repeating: ", e);
- // TODO: call onError instead of onClosed if this happens
+ // TODO: call onError instead of onClosed if this happens
+ }
+ }
}
- // If no sequences are pending, fire #onClosed immediately
- mSequenceDrainer.beginDrain();
+ synchronized (this) {
+ // If no sequences are pending, fire #onClosed immediately
+ mSequenceDrainer.beginDrain();
+ }
}
/**
diff --git a/core/java/android/hardware/camera2/impl/CameraConstrainedHighSpeedCaptureSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraConstrainedHighSpeedCaptureSessionImpl.java
index 8cd1da50c58a3da848f518730b0121c3c3dcdf78..1c8e124331124d13429b1f2bf823167012ce7579 100644
--- a/core/java/android/hardware/camera2/impl/CameraConstrainedHighSpeedCaptureSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraConstrainedHighSpeedCaptureSessionImpl.java
@@ -21,6 +21,7 @@ import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraConstrainedHighSpeedCaptureSession;
import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.params.OutputConfiguration;
import android.hardware.camera2.params.StreamConfigurationMap;
import android.hardware.camera2.utils.SurfaceUtils;
import android.os.Handler;
@@ -256,6 +257,12 @@ public class CameraConstrainedHighSpeedCaptureSessionImpl
return mSessionImpl.isAborting();
}
+ @Override
+ public void finishDeferredConfiguration(List deferredOutputConfigs)
+ throws CameraAccessException {
+ mSessionImpl.finishDeferredConfiguration(deferredOutputConfigs);
+ }
+
private class WrapperCallback extends StateCallback {
private final StateCallback mCallback;
@@ -263,26 +270,32 @@ public class CameraConstrainedHighSpeedCaptureSessionImpl
mCallback = callback;
}
+ @Override
public void onConfigured(CameraCaptureSession session) {
mCallback.onConfigured(CameraConstrainedHighSpeedCaptureSessionImpl.this);
}
+ @Override
public void onConfigureFailed(CameraCaptureSession session) {
mCallback.onConfigureFailed(CameraConstrainedHighSpeedCaptureSessionImpl.this);
}
+ @Override
public void onReady(CameraCaptureSession session) {
mCallback.onReady(CameraConstrainedHighSpeedCaptureSessionImpl.this);
}
+ @Override
public void onActive(CameraCaptureSession session) {
mCallback.onActive(CameraConstrainedHighSpeedCaptureSessionImpl.this);
}
+ @Override
public void onClosed(CameraCaptureSession session) {
mCallback.onClosed(CameraConstrainedHighSpeedCaptureSessionImpl.this);
}
+ @Override
public void onSurfacePrepared(CameraCaptureSession session, Surface surface) {
mCallback.onSurfacePrepared(CameraConstrainedHighSpeedCaptureSessionImpl.this,
surface);
diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
index 0cee11445246c84606d5b520749a9ca935eab419..ee8a6d7720372b6ef1bf6038095416ed531c77f9 100644
--- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
@@ -407,7 +407,10 @@ public class CameraDeviceImpl extends CameraDevice
int streamId = mConfiguredOutputs.keyAt(i);
OutputConfiguration outConfig = mConfiguredOutputs.valueAt(i);
- if (!outputs.contains(outConfig)) {
+ if (!outputs.contains(outConfig) || outConfig.isDeferredConfiguration()) {
+ // Always delete the deferred output configuration when the session
+ // is created, as the deferred output configuration doesn't have unique surface
+ // related identifies.
deleteList.add(streamId);
} else {
addSet.remove(outConfig); // Don't create a stream previously created
@@ -744,6 +747,37 @@ public class CameraDeviceImpl extends CameraDevice
}
}
+ public void finishDeferredConfig(List deferredConfigs)
+ throws CameraAccessException {
+ if (deferredConfigs == null || deferredConfigs.size() == 0) {
+ throw new IllegalArgumentException("deferred config is null or empty");
+ }
+
+ synchronized(mInterfaceLock) {
+ for (OutputConfiguration config : deferredConfigs) {
+ int streamId = -1;
+ for (int i = 0; i < mConfiguredOutputs.size(); i++) {
+ // Have to use equal here, as createCaptureSessionByOutputConfigurations() and
+ // createReprocessableCaptureSessionByConfigurations() do a copy of the configs.
+ if (config.equals(mConfiguredOutputs.valueAt(i))) {
+ streamId = mConfiguredOutputs.keyAt(i);
+ break;
+ }
+ }
+ if (streamId == -1) {
+ throw new IllegalArgumentException("Deferred config is not part of this "
+ + "session");
+ }
+
+ if (config.getSurface() == null) {
+ throw new IllegalArgumentException("The deferred config for stream " + streamId
+ + " must have a non-null surface");
+ }
+ mRemoteDevice.setDeferredConfiguration(streamId, config);
+ }
+ }
+ }
+
public int capture(CaptureRequest request, CaptureCallback callback, Handler handler)
throws CameraAccessException {
if (DEBUG) {
@@ -2005,6 +2039,7 @@ public class CameraDeviceImpl extends CameraDevice
*
*
Handle binder death for ICameraDeviceUser. Trigger onError.
*/
+ @Override
public void binderDied() {
Log.w(TAG, "CameraDevice " + mCameraId + " died unexpectedly");
diff --git a/core/java/android/hardware/camera2/impl/ICameraDeviceUserWrapper.java b/core/java/android/hardware/camera2/impl/ICameraDeviceUserWrapper.java
index ef5f6d71b8b6e0f6da5a4122298c81808e2e0687..d77f60bf0953d31b9c837660ee98ad8dbc9c5c7c 100644
--- a/core/java/android/hardware/camera2/impl/ICameraDeviceUserWrapper.java
+++ b/core/java/android/hardware/camera2/impl/ICameraDeviceUserWrapper.java
@@ -215,5 +215,14 @@ public class ICameraDeviceUserWrapper {
}
}
+ public void setDeferredConfiguration(int streamId, OutputConfiguration deferredConfig)
+ throws CameraAccessException {
+ try {
+ mRemoteDevice.setDeferredConfiguration(streamId, deferredConfig);
+ } catch (Throwable t) {
+ CameraManager.throwAsPublicException(t);
+ throw new UnsupportedOperationException("Unexpected exception", t);
+ }
+ }
}
diff --git a/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java b/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java
index acbf214942c52458ced2b12a40fc8217fe3d8a45..b9e75eec1a34c77ca5f39c8bb06ca152aa7532ac 100644
--- a/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java
+++ b/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java
@@ -566,6 +566,13 @@ public class CameraDeviceUserShim implements ICameraDeviceUser {
}
}
+ @Override
+ public void setDeferredConfiguration(int steamId, OutputConfiguration config) {
+ String err = "Set deferred configuration is not supported on legacy devices";
+ Log.e(TAG, err);
+ throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION, err);
+ }
+
@Override
public int createInputStream(int width, int height, int format) {
String err = "Creating input stream is not supported on legacy devices";
diff --git a/core/java/android/hardware/camera2/params/OutputConfiguration.java b/core/java/android/hardware/camera2/params/OutputConfiguration.java
index 61b534bf22deb6c28367eeb9426bb408a5e9ded3..69c00e9873021a54313cacdca55a5c7f9f82872a 100644
--- a/core/java/android/hardware/camera2/params/OutputConfiguration.java
+++ b/core/java/android/hardware/camera2/params/OutputConfiguration.java
@@ -20,6 +20,8 @@ package android.hardware.camera2.params;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
+import android.graphics.ImageFormat;
+import android.hardware.camera2.CameraCaptureSession;
import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.utils.HashCodeHelpers;
import android.hardware.camera2.utils.SurfaceUtils;
@@ -94,6 +96,21 @@ public final class OutputConfiguration implements Parcelable {
this(SURFACE_GROUP_ID_NONE, surface, ROTATION_0);
}
+ /**
+ * Unknown surface source type.
+ */
+ private final int SURFACE_TYPE_UNKNOWN = -1;
+
+ /**
+ * The surface is obtained from {@link android.view.SurfaceView}.
+ */
+ private final int SURFACE_TYPE_SURFACE_VIEW = 0;
+
+ /**
+ * The surface is obtained from {@link android.graphics.SurfaceTexture}.
+ */
+ private final int SURFACE_TYPE_SURFACE_TEXTURE = 1;
+
/**
* Create a new {@link OutputConfiguration} instance with a {@link Surface},
* with a surface group ID.
@@ -179,12 +196,110 @@ public final class OutputConfiguration implements Parcelable {
checkNotNull(surface, "Surface must not be null");
checkArgumentInRange(rotation, ROTATION_0, ROTATION_270, "Rotation constant");
mSurfaceGroupId = surfaceGroupId;
+ mSurfaceType = SURFACE_TYPE_UNKNOWN;
mSurface = surface;
mRotation = rotation;
mConfiguredSize = SurfaceUtils.getSurfaceSize(surface);
mConfiguredFormat = SurfaceUtils.getSurfaceFormat(surface);
mConfiguredDataspace = SurfaceUtils.getSurfaceDataspace(surface);
mConfiguredGenerationId = surface.getGenerationId();
+ mIsDeferredConfig = false;
+ }
+
+ /**
+ * Create a new {@link OutputConfiguration} instance, with desired Surface size and Surface
+ * source class.
+ *
+ * This constructor takes an argument for desired Surface size and the Surface source class
+ * without providing the actual output Surface. This is used to setup a output configuration
+ * with a deferred Surface. The application can use this output configuration to create a
+ * session.
+ *
+ *
+ * However, the actual output Surface must be set via {@link #setDeferredSurface} and finish the
+ * deferred Surface configuration via {@link CameraCaptureSession#finishDeferredConfiguration}
+ * before submitting a request with this Surface target. The deferred Surface can only be
+ * obtained from either from {@link android.view.SurfaceView} by calling
+ * {@link android.view.SurfaceHolder#getSurface}, or from
+ * {@link android.graphics.SurfaceTexture} via
+ * {@link android.view.Surface#Surface(android.graphics.SurfaceTexture)}).
+ *
+ *
+ * @param surfaceSize Size for the deferred surface.
+ * @param klass a non-{@code null} {@link Class} object reference that indicates the source of
+ * this surface. Only {@link android.view.SurfaceHolder SurfaceHolder.class} and
+ * {@link android.graphics.SurfaceTexture SurfaceTexture.class} are supported.
+ * @hide
+ */
+ public OutputConfiguration(@NonNull Size surfaceSize, @NonNull Class klass) {
+ checkNotNull(klass, "surfaceSize must not be null");
+ checkNotNull(klass, "klass must not be null");
+ if (klass == android.view.SurfaceHolder.class) {
+ mSurfaceType = SURFACE_TYPE_SURFACE_VIEW;
+ } else if (klass == android.graphics.SurfaceTexture.class) {
+ mSurfaceType = SURFACE_TYPE_SURFACE_TEXTURE;
+ } else {
+ mSurfaceType = SURFACE_TYPE_UNKNOWN;
+ throw new IllegalArgumentException("Unknow surface source class type");
+ }
+
+ mSurfaceGroupId = SURFACE_GROUP_ID_NONE;
+ mSurface = null;
+ mRotation = ROTATION_0;
+ mConfiguredSize = surfaceSize;
+ mConfiguredFormat = StreamConfigurationMap.imageFormatToInternal(ImageFormat.PRIVATE);
+ mConfiguredDataspace = StreamConfigurationMap.imageFormatToDataspace(ImageFormat.PRIVATE);
+ mConfiguredGenerationId = 0;
+ mIsDeferredConfig = true;
+ }
+
+ /**
+ * Check if this configuration has deferred configuration.
+ *
+ *
This will return true if the output configuration was constructed with surface deferred.
+ * It will return true even after the deferred surface is set later.
+ *
+ * @return true if this configuration has deferred surface.
+ * @hide
+ */
+ public boolean isDeferredConfiguration() {
+ return mIsDeferredConfig;
+ }
+
+ /**
+ * Set the deferred surface to this OutputConfiguration.
+ *
+ *
+ * The deferred surface must be obtained from either from {@link android.view.SurfaceView} by
+ * calling {@link android.view.SurfaceHolder#getSurface}, or from
+ * {@link android.graphics.SurfaceTexture} via
+ * {@link android.view.Surface#Surface(android.graphics.SurfaceTexture)}). After the deferred
+ * surface is set, the application must finish the deferred surface configuration via
+ * {@link CameraCaptureSession#finishDeferredConfiguration} before submitting a request with
+ * this surface target.
+ *
+ *
+ * @param surface The deferred surface to be set.
+ * @throws IllegalArgumentException if the Surface is invalid.
+ * @throws IllegalStateException if a Surface was already set to this deferred
+ * OutputConfiguration.
+ * @hide
+ */
+ public void setDeferredSurface(@NonNull Surface surface) {
+ checkNotNull(surface, "Surface must not be null");
+ if (mSurface != null) {
+ throw new IllegalStateException("Deferred surface is already set!");
+ }
+
+ // This will throw IAE is the surface was abandoned.
+ Size surfaceSize = SurfaceUtils.getSurfaceSize(surface);
+ if (!surfaceSize.equals(mConfiguredSize)) {
+ Log.w(TAG, "Deferred surface size " + surfaceSize +
+ " is different with pre-configured size " + mConfiguredSize +
+ ", the pre-configured size will be used.");
+ }
+
+ mSurface = surface;
}
/**
@@ -203,10 +318,12 @@ public final class OutputConfiguration implements Parcelable {
this.mSurface = other.mSurface;
this.mRotation = other.mRotation;
this.mSurfaceGroupId = other.mSurfaceGroupId;
+ this.mSurfaceType = other.mSurfaceType;
this.mConfiguredDataspace = other.mConfiguredDataspace;
this.mConfiguredFormat = other.mConfiguredFormat;
this.mConfiguredSize = other.mConfiguredSize;
this.mConfiguredGenerationId = other.mConfiguredGenerationId;
+ this.mIsDeferredConfig = other.mIsDeferredConfig;
}
/**
@@ -215,16 +332,30 @@ public final class OutputConfiguration implements Parcelable {
private OutputConfiguration(@NonNull Parcel source) {
int rotation = source.readInt();
int surfaceSetId = source.readInt();
+ int surfaceType = source.readInt();
+ int width = source.readInt();
+ int height = source.readInt();
Surface surface = Surface.CREATOR.createFromParcel(source);
- checkNotNull(surface, "Surface must not be null");
checkArgumentInRange(rotation, ROTATION_0, ROTATION_270, "Rotation constant");
mSurfaceGroupId = surfaceSetId;
mSurface = surface;
mRotation = rotation;
- mConfiguredSize = SurfaceUtils.getSurfaceSize(mSurface);
- mConfiguredFormat = SurfaceUtils.getSurfaceFormat(mSurface);
- mConfiguredDataspace = SurfaceUtils.getSurfaceDataspace(mSurface);
- mConfiguredGenerationId = mSurface.getGenerationId();
+ if (surface != null) {
+ mSurfaceType = SURFACE_TYPE_UNKNOWN;
+ mConfiguredSize = SurfaceUtils.getSurfaceSize(mSurface);
+ mConfiguredFormat = SurfaceUtils.getSurfaceFormat(mSurface);
+ mConfiguredDataspace = SurfaceUtils.getSurfaceDataspace(mSurface);
+ mConfiguredGenerationId = mSurface.getGenerationId();
+ mIsDeferredConfig = true;
+ } else {
+ mSurfaceType = surfaceType;
+ mConfiguredSize = new Size(width, height);
+ mConfiguredFormat = StreamConfigurationMap.imageFormatToInternal(ImageFormat.PRIVATE);
+ mConfiguredGenerationId = 0;
+ mConfiguredDataspace =
+ StreamConfigurationMap.imageFormatToDataspace(ImageFormat.PRIVATE);
+ mIsDeferredConfig = false;
+ }
}
/**
@@ -291,7 +422,12 @@ public final class OutputConfiguration implements Parcelable {
}
dest.writeInt(mRotation);
dest.writeInt(mSurfaceGroupId);
- mSurface.writeToParcel(dest, flags);
+ dest.writeInt(mSurfaceType);
+ dest.writeInt(mConfiguredSize.getWidth());
+ dest.writeInt(mConfiguredSize.getHeight());
+ if (mSurface != null) {
+ mSurface.writeToParcel(dest, flags);
+ }
}
/**
@@ -311,13 +447,20 @@ public final class OutputConfiguration implements Parcelable {
return true;
} else if (obj instanceof OutputConfiguration) {
final OutputConfiguration other = (OutputConfiguration) obj;
+ boolean iSSurfaceEqual = mSurface == other.mSurface &&
+ mConfiguredGenerationId == other.mConfiguredGenerationId ;
+ if (mIsDeferredConfig) {
+ Log.i(TAG, "deferred config has the same surface");
+ iSSurfaceEqual = true;
+ }
return mRotation == other.mRotation &&
- mSurface == other.mSurface &&
- mConfiguredGenerationId == other.mConfiguredGenerationId &&
+ iSSurfaceEqual&&
mConfiguredSize.equals(other.mConfiguredSize) &&
mConfiguredFormat == other.mConfiguredFormat &&
mConfiguredDataspace == other.mConfiguredDataspace &&
- mSurfaceGroupId == other.mSurfaceGroupId;
+ mSurfaceGroupId == other.mSurfaceGroupId &&
+ mSurfaceType == other.mSurfaceType &&
+ mIsDeferredConfig == other.mIsDeferredConfig;
}
return false;
}
@@ -327,15 +470,26 @@ public final class OutputConfiguration implements Parcelable {
*/
@Override
public int hashCode() {
+ // Need ensure that the hashcode remains unchanged after set a deferred surface. Otherwise
+ // The deferred output configuration will be lost in the camera streammap after the deferred
+ // surface is set.
+ if (mIsDeferredConfig) {
+ return HashCodeHelpers.hashCode(
+ mRotation, mConfiguredSize.hashCode(), mConfiguredFormat, mConfiguredDataspace,
+ mSurfaceGroupId, mSurfaceType);
+ }
+
return HashCodeHelpers.hashCode(
mRotation, mSurface.hashCode(), mConfiguredGenerationId,
mConfiguredSize.hashCode(), mConfiguredFormat, mConfiguredDataspace, mSurfaceGroupId);
}
private static final String TAG = "OutputConfiguration";
- private final Surface mSurface;
+ private Surface mSurface;
private final int mRotation;
- private int mSurfaceGroupId;
+ private final int mSurfaceGroupId;
+ // Surface source type, this is only used by the deferred surface configuration objects.
+ private final int mSurfaceType;
// The size, format, and dataspace of the surface when OutputConfiguration is created.
private final Size mConfiguredSize;
@@ -343,4 +497,6 @@ public final class OutputConfiguration implements Parcelable {
private final int mConfiguredDataspace;
// Surface generation ID to distinguish changes to Surface native internals
private final int mConfiguredGenerationId;
+ // Flag indicating if this config has deferred surface.
+ private final boolean mIsDeferredConfig;
}
diff --git a/core/java/android/hardware/display/DisplayManagerGlobal.java b/core/java/android/hardware/display/DisplayManagerGlobal.java
index 93da3e5af4e941f1595c3b1e44c2dfde8d6f16a5..826eb74aef65f54e2bb452b8f3688b2fb627ec65 100644
--- a/core/java/android/hardware/display/DisplayManagerGlobal.java
+++ b/core/java/android/hardware/display/DisplayManagerGlobal.java
@@ -354,9 +354,9 @@ public final class DisplayManagerGlobal {
}
}
- public void requestColorTransform(int displayId, int colorTransformId) {
+ public void requestColorMode(int displayId, int colorMode) {
try {
- mDm.requestColorTransform(displayId, colorTransformId);
+ mDm.requestColorMode(displayId, colorMode);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
diff --git a/core/java/android/hardware/display/IDisplayManager.aidl b/core/java/android/hardware/display/IDisplayManager.aidl
index 8a1abf18602ada2de4e21fadd5afdc1cf66d3962..f696c8d154463f00e65ba3e9e39221885974798a 100644
--- a/core/java/android/hardware/display/IDisplayManager.aidl
+++ b/core/java/android/hardware/display/IDisplayManager.aidl
@@ -59,8 +59,8 @@ interface IDisplayManager {
// No permissions required.
WifiDisplayStatus getWifiDisplayStatus();
- // Requires CONFIGURE_DISPLAY_COLOR_TRANSFORM
- void requestColorTransform(int displayId, int colorTransformId);
+ // Requires CONFIGURE_DISPLAY_COLOR_MODE
+ void requestColorMode(int displayId, int colorMode);
// Requires CAPTURE_VIDEO_OUTPUT, CAPTURE_SECURE_VIDEO_OUTPUT, or an appropriate
// MediaProjection token for certain combinations of flags.
diff --git a/core/java/android/hardware/input/InputManagerInternal.java b/core/java/android/hardware/input/InputManagerInternal.java
index 10fc8e6e366ab4e1f2bdd5fadb9cb71fc8189236..01a540484f1a94a1e9be6de16a93dff5ccea437f 100644
--- a/core/java/android/hardware/input/InputManagerInternal.java
+++ b/core/java/android/hardware/input/InputManagerInternal.java
@@ -59,4 +59,9 @@ public abstract class InputManagerInternal {
* @param deviceId The id of input device.
*/
public abstract void toggleCapsLock(int deviceId);
+
+ /**
+ * Set whether the input stack should deliver pulse gesture events when the device is asleep.
+ */
+ public abstract void setPulseGestureEnabled(boolean enabled);
}
diff --git a/core/java/android/hardware/location/ContextHubService.java b/core/java/android/hardware/location/ContextHubService.java
index 43e596fe5566ba525f8e8f69bb2190d1d37d08fb..062c9580c1e42160c33c928d3627a404e720600c 100644
--- a/core/java/android/hardware/location/ContextHubService.java
+++ b/core/java/android/hardware/location/ContextHubService.java
@@ -16,6 +16,11 @@
package android.hardware.location;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.HashMap;
+
import android.Manifest;
import android.content.Context;
import android.content.pm.PackageManager;
@@ -53,10 +58,14 @@ public class ContextHubService extends IContextHubService.Stub {
private static final int PRE_LOADED_APP_MEM_REQ = 0;
private static final int MSG_HEADER_SIZE = 4;
- private static final int MSG_FIELD_TYPE = 0;
- private static final int MSG_FIELD_VERSION = 1;
- private static final int MSG_FIELD_HUB_HANDLE = 2;
- private static final int MSG_FIELD_APP_INSTANCE = 3;
+ private static final int HEADER_FIELD_MSG_TYPE = 0;
+ private static final int HEADER_FIELD_MSG_VERSION = 1;
+ private static final int HEADER_FIELD_HUB_HANDLE = 2;
+ private static final int HEADER_FIELD_APP_INSTANCE = 3;
+
+ private static final int HEADER_FIELD_LOAD_APP_ID_LO = MSG_HEADER_SIZE;
+ private static final int HEADER_FIELD_LOAD_APP_ID_HI = MSG_HEADER_SIZE + 1;
+ private static final int MSG_LOAD_APP_HEADER_SIZE = MSG_HEADER_SIZE + 2;
private static final int OS_APP_INSTANCE = -1;
@@ -146,15 +155,23 @@ public class ContextHubService extends IContextHubService.Stub {
return -1;
}
- int[] msgHeader = new int[MSG_HEADER_SIZE];
- msgHeader[MSG_FIELD_HUB_HANDLE] = contextHubHandle;
- msgHeader[MSG_FIELD_APP_INSTANCE] = OS_APP_INSTANCE;
- msgHeader[MSG_FIELD_VERSION] = 0;
- msgHeader[MSG_FIELD_TYPE] = MSG_LOAD_NANO_APP;
+ int[] msgHeader = new int[MSG_LOAD_APP_HEADER_SIZE];
+ msgHeader[HEADER_FIELD_HUB_HANDLE] = contextHubHandle;
+ msgHeader[HEADER_FIELD_APP_INSTANCE] = OS_APP_INSTANCE;
+ msgHeader[HEADER_FIELD_MSG_VERSION] = 0;
+ msgHeader[HEADER_FIELD_MSG_TYPE] = MSG_LOAD_NANO_APP;
+
+ long appId = app.getAppId();
- if (nativeSendMessage(msgHeader, app.getAppBinary()) != 0) {
+ msgHeader[HEADER_FIELD_LOAD_APP_ID_LO] = (int)(appId & 0xFFFFFFFF);
+ msgHeader[HEADER_FIELD_LOAD_APP_ID_HI] = (int)((appId >> 32) & 0xFFFFFFFF);
+
+ int errVal = nativeSendMessage(msgHeader, app.getAppBinary());
+ if (errVal != 0) {
+ Log.e(TAG, "Send Message returns error" + contextHubHandle);
return -1;
}
+
// Do not add an entry to mNanoAppInstance Hash yet. The HAL may reject the app
return 0;
}
@@ -169,12 +186,14 @@ public class ContextHubService extends IContextHubService.Stub {
// Call Native interface here
int[] msgHeader = new int[MSG_HEADER_SIZE];
- msgHeader[MSG_FIELD_HUB_HANDLE] = ANY_HUB;
- msgHeader[MSG_FIELD_APP_INSTANCE] = OS_APP_INSTANCE;
- msgHeader[MSG_FIELD_VERSION] = 0;
- msgHeader[MSG_FIELD_TYPE] = MSG_UNLOAD_NANO_APP;
+ msgHeader[HEADER_FIELD_HUB_HANDLE] = ANY_HUB;
+ msgHeader[HEADER_FIELD_APP_INSTANCE] = nanoAppInstanceHandle;
+ msgHeader[HEADER_FIELD_MSG_VERSION] = 0;
+ msgHeader[HEADER_FIELD_MSG_TYPE] = MSG_UNLOAD_NANO_APP;
- if (nativeSendMessage(msgHeader, null) != 0) {
+ byte msg[] = new byte[0];
+
+ if (nativeSendMessage(msgHeader, msg) != 0) {
return -1;
}
@@ -222,10 +241,10 @@ public class ContextHubService extends IContextHubService.Stub {
checkPermissions();
int[] msgHeader = new int[MSG_HEADER_SIZE];
- msgHeader[MSG_FIELD_HUB_HANDLE] = hubHandle;
- msgHeader[MSG_FIELD_APP_INSTANCE] = nanoAppHandle;
- msgHeader[MSG_FIELD_VERSION] = msg.getVersion();
- msgHeader[MSG_FIELD_TYPE] = msg.getMsgType();
+ msgHeader[HEADER_FIELD_HUB_HANDLE] = hubHandle;
+ msgHeader[HEADER_FIELD_APP_INSTANCE] = nanoAppHandle;
+ msgHeader[HEADER_FIELD_MSG_VERSION] = msg.getVersion();
+ msgHeader[HEADER_FIELD_MSG_TYPE] = msg.getMsgType();
return nativeSendMessage(msgHeader, msg.getData());
}
@@ -269,15 +288,17 @@ public class ContextHubService extends IContextHubService.Stub {
Log.v(TAG, "No message callbacks registered.");
return 0;
}
- ContextHubMessage message =
- new ContextHubMessage(header[MSG_FIELD_TYPE], header[MSG_FIELD_VERSION], data);
+
+ ContextHubMessage msg = new ContextHubMessage(header[HEADER_FIELD_MSG_TYPE],
+ header[HEADER_FIELD_MSG_VERSION],
+ data);
for (int i = 0; i < callbacksCount; ++i) {
IContextHubCallback callback = mCallbacksList.getBroadcastItem(i);
try {
callback.onMessageReceipt(
- header[MSG_FIELD_HUB_HANDLE],
- header[MSG_FIELD_APP_INSTANCE],
- message);
+ header[HEADER_FIELD_HUB_HANDLE],
+ header[HEADER_FIELD_APP_INSTANCE],
+ msg);
} catch (RemoteException e) {
Log.i(TAG, "Exception (" + e + ") calling remote callback (" + callback + ").");
continue;
@@ -308,12 +329,20 @@ public class ContextHubService extends IContextHubService.Stub {
return 0;
}
+ private int deleteAppInstance(int appInstanceHandle) {
+ if (mNanoAppHash.remove(appInstanceHandle) == null) {
+ return -1;
+ }
+
+ return 0;
+ }
+
private void sendVrStateChangeMessageToApp(NanoAppInstanceInfo app, boolean vrModeEnabled) {
int[] msgHeader = new int[MSG_HEADER_SIZE];
- msgHeader[MSG_FIELD_TYPE] = 0;
- msgHeader[MSG_FIELD_VERSION] = 0;
- msgHeader[MSG_FIELD_HUB_HANDLE] = ANY_HUB;
- msgHeader[MSG_FIELD_APP_INSTANCE] = app.getHandle();
+ msgHeader[HEADER_FIELD_MSG_TYPE] = 0;
+ msgHeader[HEADER_FIELD_MSG_VERSION] = 0;
+ msgHeader[HEADER_FIELD_HUB_HANDLE] = ANY_HUB;
+ msgHeader[HEADER_FIELD_APP_INSTANCE] = app.getHandle();
byte[] data = new byte[1];
data[0] = (byte) ((vrModeEnabled) ? 1 : 0);
diff --git a/core/java/android/hardware/usb/UsbManager.java b/core/java/android/hardware/usb/UsbManager.java
index f9a7d192b5bb394435f7b86fe38ee50b1366168c..629db06a30e37dd5e10c66a92632ef7e251394e0 100644
--- a/core/java/android/hardware/usb/UsbManager.java
+++ b/core/java/android/hardware/usb/UsbManager.java
@@ -21,6 +21,7 @@ import com.android.internal.util.Preconditions;
import android.app.PendingIntent;
import android.content.Context;
+import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Bundle;
import android.os.ParcelFileDescriptor;
import android.os.Process;
@@ -42,7 +43,7 @@ import java.util.HashMap;
*
*
Developer Guides
*
For more information about communicating with USB hardware, read the
- * USB developer guide.
*/
public class UsbManager {
@@ -475,6 +476,26 @@ public class UsbManager {
}
}
+ /**
+ * Grants permission to specified package for USB device without showing system dialog.
+ * Only system components can call this function, as it requires the MANAGE_USB permission.
+ * @param device to request permissions for
+ * @param packageName of package to grant permissions
+ *
+ * {@hide}
+ */
+ public void grantPermission(UsbDevice device, String packageName) {
+ try {
+ int uid = mContext.getPackageManager()
+ .getPackageUidAsUser(packageName, mContext.getUserId());
+ mService.grantDevicePermission(device, uid);
+ } catch (NameNotFoundException e) {
+ Log.e(TAG, "Package " + packageName + " not found.", e);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
/**
* Returns true if the specified USB function is currently enabled when in device mode.
*
diff --git a/core/java/android/inputmethodservice/AbstractInputMethodService.java b/core/java/android/inputmethodservice/AbstractInputMethodService.java
index 3531926d347ca313145ede6e15031b1ecf4ea8f2..29177b6b47cf81a7aeb122c69bb2ea2b721e96e7 100644
--- a/core/java/android/inputmethodservice/AbstractInputMethodService.java
+++ b/core/java/android/inputmethodservice/AbstractInputMethodService.java
@@ -16,11 +16,14 @@
package android.inputmethodservice;
+import android.annotation.NonNull;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.view.KeyEvent;
import android.view.MotionEvent;
+import android.view.inputmethod.InputConnection;
+import android.view.inputmethod.InputContentInfo;
import android.view.inputmethod.InputMethod;
import android.view.inputmethod.InputMethodSession;
@@ -208,7 +211,7 @@ public abstract class AbstractInputMethodService extends Service
*
* @param event The motion event being received.
* @return True if the event was handled in this function, false otherwise.
- * @see View#onTrackballEvent
+ * @see android.view.View#onTrackballEvent(MotionEvent)
*/
public boolean onTrackballEvent(MotionEvent event) {
return false;
@@ -219,9 +222,30 @@ public abstract class AbstractInputMethodService extends Service
*
* @param event The motion event being received.
* @return True if the event was handled in this function, false otherwise.
- * @see View#onGenericMotionEvent
+ * @see android.view.View#onGenericMotionEvent(MotionEvent)
*/
public boolean onGenericMotionEvent(MotionEvent event) {
return false;
}
+
+ /**
+ * Allow the receiver of {@link InputContentInfo} to obtain a temporary read-only access
+ * permission to the content.
+ *
+ *
Default implementation does nothing.
+ *
+ * @param inputContentInfo Content to be temporarily exposed from the input method to the
+ * application.
+ * This cannot be {@code null}.
+ * @param inputConnection {@link InputConnection} with which
+ * {@link InputConnection#commitContent(InputContentInfo, int, android.os.Bundle)} will be
+ * called.
+ * @return {@code false} if we cannot allow a temporary access permission.
+ * @hide
+ */
+ public void exposeContent(@NonNull InputContentInfo inputContentInfo,
+ @NonNull InputConnection inputConnection) {
+ return;
+ }
+
}
diff --git a/core/java/android/inputmethodservice/IInputMethodWrapper.java b/core/java/android/inputmethodservice/IInputMethodWrapper.java
index cc71a9c24bfbcc82f7b674018c1d89cc8af2179a..167d5a09a2dc42e3c37d920c3daec8d4f069c51f 100644
--- a/core/java/android/inputmethodservice/IInputMethodWrapper.java
+++ b/core/java/android/inputmethodservice/IInputMethodWrapper.java
@@ -168,7 +168,7 @@ class IInputMethodWrapper extends IInputMethod.Stub
int missingMethods = msg.arg1;
IInputContext inputContext = (IInputContext)args.arg1;
InputConnection ic = inputContext != null
- ? new InputConnectionWrapper(inputContext, missingMethods) : null;
+ ? new InputConnectionWrapper(mTarget, inputContext, missingMethods) : null;
EditorInfo info = (EditorInfo)args.arg2;
info.makeCompatible(mTargetSdkVersion);
inputMethod.startInput(ic, info);
@@ -180,7 +180,7 @@ class IInputMethodWrapper extends IInputMethod.Stub
int missingMethods = msg.arg1;
IInputContext inputContext = (IInputContext)args.arg1;
InputConnection ic = inputContext != null
- ? new InputConnectionWrapper(inputContext, missingMethods) : null;
+ ? new InputConnectionWrapper(mTarget, inputContext, missingMethods) : null;
EditorInfo info = (EditorInfo)args.arg2;
info.makeCompatible(mTargetSdkVersion);
inputMethod.restartInput(ic, info);
@@ -251,7 +251,7 @@ class IInputMethodWrapper extends IInputMethod.Stub
public void bindInput(InputBinding binding) {
// This IInputContext is guaranteed to implement all the methods.
final int missingMethodFlags = 0;
- InputConnection ic = new InputConnectionWrapper(
+ InputConnection ic = new InputConnectionWrapper(mTarget,
IInputContext.Stub.asInterface(binding.getConnectionToken()), missingMethodFlags);
InputBinding nu = new InputBinding(ic, binding);
mCaller.executeOrSendMessage(mCaller.obtainMessageO(DO_SET_INPUT_CONTEXT, nu));
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 963a21b1faf054202721b625c107b7ce0ddc589d..353eb885fa6aa4c6bfc735ef63510f3e108d3b60 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -23,6 +23,7 @@ import android.annotation.CallSuper;
import android.annotation.DrawableRes;
import android.annotation.IntDef;
import android.annotation.MainThread;
+import android.annotation.NonNull;
import android.app.ActivityManager;
import android.app.Dialog;
import android.content.Context;
@@ -65,6 +66,7 @@ import android.view.inputmethod.ExtractedText;
import android.view.inputmethod.ExtractedTextRequest;
import android.view.inputmethod.InputBinding;
import android.view.inputmethod.InputConnection;
+import android.view.inputmethod.InputContentInfo;
import android.view.inputmethod.InputMethod;
import android.view.inputmethod.InputMethodManager;
import android.view.inputmethod.InputMethodSubtype;
@@ -2631,6 +2633,29 @@ public class InputMethodService extends AbstractInputMethodService {
return mImm.getInputMethodWindowVisibleHeight();
}
+ /**
+ * Allow the receiver of {@link InputContentInfo} to obtain a temporary read-only access
+ * permission to the content.
+ *
+ * @param inputContentInfo Content to be temporarily exposed from the input method to the
+ * application.
+ * This cannot be {@code null}.
+ * @param inputConnection {@link InputConnection} with which
+ * {@link InputConnection#commitContent(InputContentInfo, Bundle)} will be called.
+ * @hide
+ */
+ @Override
+ public final void exposeContent(@NonNull InputContentInfo inputContentInfo,
+ @NonNull InputConnection inputConnection) {
+ if (inputConnection == null) {
+ return;
+ }
+ if (getCurrentInputConnection() != inputConnection) {
+ return;
+ }
+ mImm.exposeContent(mToken, inputContentInfo, getCurrentInputEditorInfo());
+ }
+
/**
* Performs a dump of the InputMethodService's internal state. Override
* to add your own information to the dump.
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index a45e6f51d8030e7fa5fcb1415d66e74a7ef861f3..b9e9b283106f98dd6c2dfe27538551bbe0b734bc 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -342,6 +342,15 @@ public class ConnectivityManager {
*/
public static final String ACTION_PROMPT_UNVALIDATED = "android.net.conn.PROMPT_UNVALIDATED";
+ /**
+ * Action used to display a dialog that asks the user whether to avoid a network that is no
+ * longer validated. This intent is used to start the dialog in settings via startActivity.
+ *
+ * @hide
+ */
+ public static final String ACTION_PROMPT_LOST_VALIDATION =
+ "android.net.conn.PROMPT_LOST_VALIDATION";
+
/**
* Invalid tethering type.
* @see #startTethering(int, OnStartTetheringCallback, boolean)
@@ -1034,6 +1043,26 @@ public class ConnectivityManager {
}
}
+ /**
+ * Request that this callback be invoked at ConnectivityService's earliest
+ * convenience with the current satisfying network's LinkProperties.
+ * If no such network exists no callback invocation is performed.
+ *
+ * The callback must have been registered with #requestNetwork() or
+ * #registerDefaultNetworkCallback(); callbacks registered with
+ * registerNetworkCallback() are not specific to any particular Network so
+ * do not cause any updates.
+ *
+ * @hide
+ */
+ public void requestLinkProperties(NetworkCallback networkCallback) {
+ try {
+ mService.requestLinkProperties(networkCallback.networkRequest);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
/**
* Get the {@link android.net.NetworkCapabilities} for the given {@link Network}. This
* will return {@code null} if the network is unknown.
@@ -1051,6 +1080,26 @@ public class ConnectivityManager {
}
}
+ /**
+ * Request that this callback be invoked at ConnectivityService's earliest
+ * convenience with the current satisfying network's NetworkCapabilities.
+ * If no such network exists no callback invocation is performed.
+ *
+ * The callback must have been registered with #requestNetwork() or
+ * #registerDefaultNetworkCallback(); callbacks registered with
+ * registerNetworkCallback() are not specific to any particular Network so
+ * do not cause any updates.
+ *
+ * @hide
+ */
+ public void requestNetworkCapabilities(NetworkCallback networkCallback) {
+ try {
+ mService.requestNetworkCapabilities(networkCallback.networkRequest);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
/**
* Gets the URL that should be used for resolving whether a captive portal is present.
* 1. This URL should respond with a 204 response to a GET request to indicate no captive
@@ -3103,14 +3152,11 @@ public class ConnectivityManager {
throw new IllegalArgumentException("Invalid NetworkCallback");
}
try {
+ // CallbackHandler will release callback when receiving CALLBACK_RELEASED.
mService.releaseNetworkRequest(networkCallback.networkRequest);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
-
- synchronized (sNetworkCallback) {
- sNetworkCallback.remove(networkCallback.networkRequest);
- }
}
/**
@@ -3151,6 +3197,27 @@ public class ConnectivityManager {
}
}
+ /**
+ * Informs the system to penalize {@code network}'s score when it becomes unvalidated. This is
+ * only meaningful if the system is configured not to penalize such networks, e.g., if the
+ * {@code config_networkAvoidBadWifi} configuration variable is set to 0 and the {@code
+ * NETWORK_AVOID_BAD_WIFI setting is unset}.
+ *
+ *
This method requires the caller to hold the permission
+ * {@link android.Manifest.permission#CONNECTIVITY_INTERNAL}
+ *
+ * @param network The network to accept.
+ *
+ * @hide
+ */
+ public void setAvoidUnvalidated(Network network) {
+ try {
+ mService.setAvoidUnvalidated(network);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
/**
* Resets all connectivity manager settings back to factory defaults.
* @hide
diff --git a/core/java/android/net/ConnectivityMetricsLogger.java b/core/java/android/net/ConnectivityMetricsLogger.java
index d8cdde94a2f189bef8fef99c9c1ee27cfd20c6c1..9a2d4e0a31242a01bf3b0a0f014d65eec2cd9cda 100644
--- a/core/java/android/net/ConnectivityMetricsLogger.java
+++ b/core/java/android/net/ConnectivityMetricsLogger.java
@@ -23,6 +23,8 @@ import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.Log;
+import com.android.internal.annotations.VisibleForTesting;
+
/** {@hide} */
@SystemApi
public class ConnectivityMetricsLogger {
@@ -33,28 +35,58 @@ public class ConnectivityMetricsLogger {
// Component Tags
public static final int COMPONENT_TAG_CONNECTIVITY = 0;
- public static final int COMPONENT_TAG_BLUETOOTH = 1;
- public static final int COMPONENT_TAG_WIFI = 2;
- public static final int COMPONENT_TAG_TELECOM = 3;
- public static final int COMPONENT_TAG_TELEPHONY = 4;
-
- public static final int NUMBER_OF_COMPONENTS = 5;
+ public static final int COMPONENT_TAG_BLUETOOTH = 1;
+ public static final int COMPONENT_TAG_WIFI = 2;
+ public static final int COMPONENT_TAG_TELECOM = 3;
+ public static final int COMPONENT_TAG_TELEPHONY = 4;
+ public static final int NUMBER_OF_COMPONENTS = 5;
// Event Tag
public static final int TAG_SKIPPED_EVENTS = -1;
public static final String DATA_KEY_EVENTS_COUNT = "count";
- private IConnectivityMetricsLogger mService;
-
- private long mServiceUnblockedTimestampMillis = 0;
- private int mNumSkippedEvents = 0;
+ /** {@hide} */ protected IConnectivityMetricsLogger mService;
+ /** {@hide} */ protected volatile long mServiceUnblockedTimestampMillis;
+ private int mNumSkippedEvents;
public ConnectivityMetricsLogger() {
- mService = IConnectivityMetricsLogger.Stub.asInterface(ServiceManager.getService(
- CONNECTIVITY_METRICS_LOGGER_SERVICE));
+ // TODO: consider not initializing mService in constructor
+ this(IConnectivityMetricsLogger.Stub.asInterface(
+ ServiceManager.getService(CONNECTIVITY_METRICS_LOGGER_SERVICE)));
+ }
+
+ /** {@hide} */
+ @VisibleForTesting
+ public ConnectivityMetricsLogger(IConnectivityMetricsLogger service) {
+ mService = service;
}
+ /** {@hide} */
+ protected boolean checkLoggerService() {
+ if (mService != null) {
+ return true;
+ }
+ // Two threads racing here will write the same pointer because getService
+ // is idempotent once MetricsLoggerService is initialized.
+ mService = IConnectivityMetricsLogger.Stub.asInterface(
+ ServiceManager.getService(CONNECTIVITY_METRICS_LOGGER_SERVICE));
+ return mService != null;
+ }
+
+ /**
+ * Log a ConnectivityMetricsEvent.
+ *
+ * This method keeps track of skipped events when MetricsLoggerService throttles input events.
+ * It skips logging when MetricsLoggerService is active. When throttling ends, it logs a
+ * meta-event containing the number of events dropped. It is not safe to call this method
+ * concurrently from different threads.
+ *
+ * @param timestamp is the epoch timestamp of the event in ms.
+ * @param componentTag is the COMPONENT_* constant the event belongs to.
+ * @param eventTag is an event type constant whose meaning is specific to the component tag.
+ * @param data is a Parcelable instance representing the event.
+ */
public void logEvent(long timestamp, int componentTag, int eventTag, Parcelable data) {
if (mService == null) {
if (DBG) {
@@ -77,6 +109,12 @@ public class ConnectivityMetricsLogger {
// Log number of skipped events
Bundle b = new Bundle();
b.putInt(DATA_KEY_EVENTS_COUNT, mNumSkippedEvents);
+
+ // Log the skipped event.
+ // TODO: Note that some of the clients push all states events into the server,
+ // If we lose some states logged here, we might mess up the statistics happened at the
+ // backend. One of the options is to introduce a non-skippable flag for important events
+ // that are logged.
skippedEventsEvent = new ConnectivityMetricsEvent(mServiceUnblockedTimestampMillis,
componentTag, TAG_SKIPPED_EVENTS, b);
@@ -104,7 +142,7 @@ public class ConnectivityMetricsLogger {
}
}
} catch (RemoteException e) {
- Log.e(TAG, "Error logging event " + e.getMessage());
+ Log.e(TAG, "Error logging event", e);
}
}
@@ -121,8 +159,8 @@ public class ConnectivityMetricsLogger {
public ConnectivityMetricsEvent[] getEvents(ConnectivityMetricsEvent.Reference reference) {
try {
return mService.getEvents(reference);
- } catch (RemoteException ex) {
- Log.e(TAG, "IConnectivityMetricsLogger.getEvents: " + ex);
+ } catch (RemoteException e) {
+ Log.e(TAG, "IConnectivityMetricsLogger.getEvents", e);
return null;
}
}
@@ -133,8 +171,8 @@ public class ConnectivityMetricsLogger {
public boolean register(PendingIntent newEventsIntent) {
try {
return mService.register(newEventsIntent);
- } catch (RemoteException ex) {
- Log.e(TAG, "IConnectivityMetricsLogger.register: " + ex);
+ } catch (RemoteException e) {
+ Log.e(TAG, "IConnectivityMetricsLogger.register", e);
return false;
}
}
@@ -142,11 +180,10 @@ public class ConnectivityMetricsLogger {
public boolean unregister(PendingIntent newEventsIntent) {
try {
mService.unregister(newEventsIntent);
- } catch (RemoteException ex) {
- Log.e(TAG, "IConnectivityMetricsLogger.unregister: " + ex);
+ return true;
+ } catch (RemoteException e) {
+ Log.e(TAG, "IConnectivityMetricsLogger.unregister", e);
return false;
}
-
- return true;
}
}
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index 0d518cc14049a51d2fefa325ce2977d0424739a2..4aabda9eb09d217df491518f53e645faad277b6c 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -156,9 +156,12 @@ interface IConnectivityManager
void pendingListenForNetwork(in NetworkCapabilities networkCapabilities,
in PendingIntent operation);
+ void requestLinkProperties(in NetworkRequest networkRequest);
+ void requestNetworkCapabilities(in NetworkRequest networkRequest);
void releaseNetworkRequest(in NetworkRequest networkRequest);
void setAcceptUnvalidated(in Network network, boolean accept, boolean always);
+ void setAvoidUnvalidated(in Network network);
int getRestoreDefaultNetworkDelay(int networkType);
diff --git a/core/java/android/net/LinkAddress.java b/core/java/android/net/LinkAddress.java
index 384ab1c8f50cc97208fc5eedf4b21e2b44265645..6e74f14bd138a9944d3ce5af1b9b12bf70e122cb 100644
--- a/core/java/android/net/LinkAddress.java
+++ b/core/java/android/net/LinkAddress.java
@@ -103,7 +103,7 @@ public class LinkAddress implements Parcelable {
private boolean isIPv6ULA() {
if (address != null && address instanceof Inet6Address) {
byte[] bytes = address.getAddress();
- return ((bytes[0] & (byte)0xfc) == (byte)0xfc);
+ return ((bytes[0] & (byte)0xfe) == (byte)0xfc);
}
return false;
}
diff --git a/core/java/android/net/NetworkMisc.java b/core/java/android/net/NetworkMisc.java
index 5511a248b6aa9d47921847fc2bc085099b3709f5..69f50a272af0c8aa5c28d5b569aba87e8199c89f 100644
--- a/core/java/android/net/NetworkMisc.java
+++ b/core/java/android/net/NetworkMisc.java
@@ -51,6 +51,15 @@ public class NetworkMisc implements Parcelable {
*/
public boolean acceptUnvalidated;
+ /**
+ * Set to avoid surfacing the "Sign in to network" notification.
+ * if carrier receivers/apps are registered to handle the carrier-specific provisioning
+ * procedure, a carrier specific provisioning notification will be placed.
+ * only one notification should be displayed. This field is set based on
+ * which notification should be used for provisioning.
+ */
+ public boolean provisioningNotificationDisabled;
+
/**
* For mobile networks, this is the subscriber ID (such as IMSI).
*/
@@ -65,6 +74,7 @@ public class NetworkMisc implements Parcelable {
explicitlySelected = nm.explicitlySelected;
acceptUnvalidated = nm.acceptUnvalidated;
subscriberId = nm.subscriberId;
+ provisioningNotificationDisabled = nm.provisioningNotificationDisabled;
}
}
@@ -79,6 +89,7 @@ public class NetworkMisc implements Parcelable {
out.writeInt(explicitlySelected ? 1 : 0);
out.writeInt(acceptUnvalidated ? 1 : 0);
out.writeString(subscriberId);
+ out.writeInt(provisioningNotificationDisabled ? 1 : 0);
}
public static final Creator CREATOR = new Creator() {
@@ -89,6 +100,7 @@ public class NetworkMisc implements Parcelable {
networkMisc.explicitlySelected = in.readInt() != 0;
networkMisc.acceptUnvalidated = in.readInt() != 0;
networkMisc.subscriberId = in.readString();
+ networkMisc.provisioningNotificationDisabled = in.readInt() != 0;
return networkMisc;
}
diff --git a/core/java/android/net/NetworkPolicyManager.java b/core/java/android/net/NetworkPolicyManager.java
index 51c45e056092ae343683129ee925e74d9acb3dda..11b861aef5aa3898843f2d193ebb20965389aee3 100644
--- a/core/java/android/net/NetworkPolicyManager.java
+++ b/core/java/android/net/NetworkPolicyManager.java
@@ -18,7 +18,6 @@ package android.net;
import static android.content.pm.PackageManager.GET_SIGNATURES;
import static android.net.NetworkPolicy.CYCLE_NONE;
-import static android.text.format.Time.MONTH_DAY;
import android.content.Context;
import android.content.Intent;
@@ -27,12 +26,13 @@ import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.Signature;
import android.os.RemoteException;
import android.os.UserHandle;
-import android.text.format.Time;
import android.util.DebugUtils;
import com.google.android.collect.Sets;
+import java.util.Calendar;
import java.util.HashSet;
+import java.util.TimeZone;
/**
* Manager for creating and modifying network policy rules.
@@ -253,28 +253,18 @@ public class NetworkPolicyManager {
throw new IllegalArgumentException("Unable to compute boundary without cycleDay");
}
- final Time now = new Time(policy.cycleTimezone);
- now.set(currentTime);
-
- // first, find cycle boundary for current month
- final Time cycle = new Time(now);
- cycle.hour = cycle.minute = cycle.second = 0;
- snapToCycleDay(cycle, policy.cycleDay);
-
- if (Time.compare(cycle, now) >= 0) {
- // cycle boundary is beyond now, use last cycle boundary; start by
- // pushing ourselves squarely into last month.
- final Time lastMonth = new Time(now);
- lastMonth.hour = lastMonth.minute = lastMonth.second = 0;
- lastMonth.monthDay = 1;
- lastMonth.month -= 1;
- lastMonth.normalize(true);
-
- cycle.set(lastMonth);
- snapToCycleDay(cycle, policy.cycleDay);
+ final Calendar cal = Calendar.getInstance(TimeZone.getTimeZone(policy.cycleTimezone));
+ cal.setTimeInMillis(currentTime);
+ snapToCycleDay(cal, policy.cycleDay);
+
+ if (cal.getTimeInMillis() >= currentTime) {
+ // Cycle boundary is beyond now, use last cycle boundary
+ cal.set(Calendar.DAY_OF_MONTH, 1);
+ cal.add(Calendar.MONTH, -1);
+ snapToCycleDay(cal, policy.cycleDay);
}
- return cycle.toMillis(true);
+ return cal.getTimeInMillis();
}
/** {@hide} */
@@ -283,28 +273,18 @@ public class NetworkPolicyManager {
throw new IllegalArgumentException("Unable to compute boundary without cycleDay");
}
- final Time now = new Time(policy.cycleTimezone);
- now.set(currentTime);
-
- // first, find cycle boundary for current month
- final Time cycle = new Time(now);
- cycle.hour = cycle.minute = cycle.second = 0;
- snapToCycleDay(cycle, policy.cycleDay);
-
- if (Time.compare(cycle, now) <= 0) {
- // cycle boundary is before now, use next cycle boundary; start by
- // pushing ourselves squarely into next month.
- final Time nextMonth = new Time(now);
- nextMonth.hour = nextMonth.minute = nextMonth.second = 0;
- nextMonth.monthDay = 1;
- nextMonth.month += 1;
- nextMonth.normalize(true);
-
- cycle.set(nextMonth);
- snapToCycleDay(cycle, policy.cycleDay);
+ final Calendar cal = Calendar.getInstance(TimeZone.getTimeZone(policy.cycleTimezone));
+ cal.setTimeInMillis(currentTime);
+ snapToCycleDay(cal, policy.cycleDay);
+
+ if (cal.getTimeInMillis() <= currentTime) {
+ // Cycle boundary is before now, use next cycle boundary
+ cal.set(Calendar.DAY_OF_MONTH, 1);
+ cal.add(Calendar.MONTH, 1);
+ snapToCycleDay(cal, policy.cycleDay);
}
- return cycle.toMillis(true);
+ return cal.getTimeInMillis();
}
/**
@@ -313,16 +293,17 @@ public class NetworkPolicyManager {
*
* @hide
*/
- public static void snapToCycleDay(Time time, int cycleDay) {
- if (cycleDay > time.getActualMaximum(MONTH_DAY)) {
- // cycle day isn't valid this month; snap to last second of month
- time.month += 1;
- time.monthDay = 1;
- time.second = -1;
+ public static void snapToCycleDay(Calendar cal, int cycleDay) {
+ cal.set(Calendar.HOUR_OF_DAY, 0);
+ cal.set(Calendar.MINUTE, 0);
+ cal.set(Calendar.SECOND, 0);
+ if (cycleDay > cal.getActualMaximum(Calendar.DAY_OF_MONTH)) {
+ cal.set(Calendar.DAY_OF_MONTH, 1);
+ cal.add(Calendar.MONTH, 1);
+ cal.add(Calendar.SECOND, -1);
} else {
- time.monthDay = cycleDay;
+ cal.set(Calendar.DAY_OF_MONTH, cycleDay);
}
- time.normalize(true);
}
/**
diff --git a/core/java/android/net/NetworkRequest.java b/core/java/android/net/NetworkRequest.java
index f1edcbe30df65305749051d9f2ef4d12c3b22e76..4501f7b089b96c1ccb62c3da438076ae180ebce7 100644
--- a/core/java/android/net/NetworkRequest.java
+++ b/core/java/android/net/NetworkRequest.java
@@ -19,6 +19,8 @@ package android.net;
import android.os.Parcel;
import android.os.Parcelable;
+import java.util.Objects;
+
/**
* Defines a request for a network, made through {@link NetworkRequest.Builder} and used
* to request a network via {@link ConnectivityManager#requestNetwork} or listen for changes
@@ -47,15 +49,55 @@ public class NetworkRequest implements Parcelable {
public final int legacyType;
/**
+ * A NetworkRequest as used by the system can be one of three types:
+ *
+ * - LISTEN, for which the framework will issue callbacks about any
+ * and all networks that match the specified NetworkCapabilities,
+ *
+ * - REQUEST, capable of causing a specific network to be created
+ * first (e.g. a telephony DUN request), the framework will issue
+ * callbacks about the single, highest scoring current network
+ * (if any) that matches the specified NetworkCapabilities, or
+ *
+ * - TRACK_DEFAULT, a hybrid of the two designed such that the
+ * framework will issue callbacks for the single, highest scoring
+ * current network (if any) that matches the capabilities of the
+ * default Internet request (mDefaultRequest), but which cannot cause
+ * the framework to either create or retain the existence of any
+ * specific network.
+ *
+ * - The value NONE is used only by applications. When an application
+ * creates a NetworkRequest, it does not have a type; the type is set
+ * by the system depending on the method used to file the request
+ * (requestNetwork, registerNetworkCallback, etc.).
+ *
+ * @hide
+ */
+ public static enum Type {
+ NONE,
+ LISTEN,
+ TRACK_DEFAULT,
+ REQUEST
+ };
+
+ /**
+ * The type of the request. This is only used by the system and is always NONE elsewhere.
+ *
* @hide
*/
- public NetworkRequest(NetworkCapabilities nc, int legacyType, int rId) {
+ public final Type type;
+
+ /**
+ * @hide
+ */
+ public NetworkRequest(NetworkCapabilities nc, int legacyType, int rId, Type type) {
if (nc == null) {
throw new NullPointerException();
}
requestId = rId;
networkCapabilities = nc;
this.legacyType = legacyType;
+ this.type = type;
}
/**
@@ -65,6 +107,7 @@ public class NetworkRequest implements Parcelable {
networkCapabilities = new NetworkCapabilities(that.networkCapabilities);
requestId = that.requestId;
this.legacyType = that.legacyType;
+ this.type = that.type;
}
/**
@@ -90,7 +133,7 @@ public class NetworkRequest implements Parcelable {
final NetworkCapabilities nc = new NetworkCapabilities(mNetworkCapabilities);
nc.maybeMarkCapabilitiesRestricted();
return new NetworkRequest(nc, ConnectivityManager.TYPE_NONE,
- ConnectivityManager.REQUEST_ID_UNSET);
+ ConnectivityManager.REQUEST_ID_UNSET, Type.NONE);
}
/**
@@ -223,6 +266,7 @@ public class NetworkRequest implements Parcelable {
dest.writeParcelable(networkCapabilities, flags);
dest.writeInt(legacyType);
dest.writeInt(requestId);
+ dest.writeString(type.name());
}
public static final Creator CREATOR =
new Creator() {
@@ -230,7 +274,8 @@ public class NetworkRequest implements Parcelable {
NetworkCapabilities nc = (NetworkCapabilities)in.readParcelable(null);
int legacyType = in.readInt();
int requestId = in.readInt();
- NetworkRequest result = new NetworkRequest(nc, legacyType, requestId);
+ Type type = Type.valueOf(in.readString()); // IllegalArgumentException if invalid.
+ NetworkRequest result = new NetworkRequest(nc, legacyType, requestId, type);
return result;
}
public NetworkRequest[] newArray(int size) {
@@ -238,8 +283,36 @@ public class NetworkRequest implements Parcelable {
}
};
+ /**
+ * Returns true iff. the contained NetworkRequest is of type LISTEN.
+ *
+ * @hide
+ */
+ public boolean isListen() {
+ return type == Type.LISTEN;
+ }
+
+ /**
+ * Returns true iff. the contained NetworkRequest is one that:
+ *
+ * - should be associated with at most one satisfying network
+ * at a time;
+ *
+ * - should cause a network to be kept up if it is the best network
+ * which can satisfy the NetworkRequest.
+ *
+ * For full detail of how isRequest() is used for pairing Networks with
+ * NetworkRequests read rematchNetworkAndRequests().
+ *
+ * @hide
+ */
+ public boolean isRequest() {
+ return type == Type.TRACK_DEFAULT || type == Type.REQUEST;
+ }
+
public String toString() {
- return "NetworkRequest [ id=" + requestId + ", legacyType=" + legacyType +
+ return "NetworkRequest [ " + type + " id=" + requestId +
+ (legacyType != ConnectivityManager.TYPE_NONE ? ", legacyType=" + legacyType : "") +
", " + networkCapabilities.toString() + " ]";
}
@@ -248,13 +321,11 @@ public class NetworkRequest implements Parcelable {
NetworkRequest that = (NetworkRequest)obj;
return (that.legacyType == this.legacyType &&
that.requestId == this.requestId &&
- ((that.networkCapabilities == null && this.networkCapabilities == null) ||
- (that.networkCapabilities != null &&
- that.networkCapabilities.equals(this.networkCapabilities))));
+ that.type == this.type &&
+ Objects.equals(that.networkCapabilities, this.networkCapabilities));
}
public int hashCode() {
- return requestId + (legacyType * 1013) +
- (networkCapabilities.hashCode() * 1051);
+ return Objects.hash(requestId, legacyType, networkCapabilities, type);
}
}
diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java
index 141af3d4956337e3bdcbed01f842bdd49a629827..35e3065b078f05cc418181bdfb47fba9784f2042 100644
--- a/core/java/android/net/NetworkUtils.java
+++ b/core/java/android/net/NetworkUtils.java
@@ -45,12 +45,19 @@ public class NetworkUtils {
public native static void attachDhcpFilter(FileDescriptor fd) throws SocketException;
/**
- * Attaches a socket filter that accepts ICMP6 router advertisement packets to the given socket.
+ * Attaches a socket filter that accepts ICMPv6 router advertisements to the given socket.
* @param fd the socket's {@link FileDescriptor}.
* @param packetType the hardware address type, one of ARPHRD_*.
*/
public native static void attachRaFilter(FileDescriptor fd, int packetType) throws SocketException;
+ /**
+ * Configures a socket for receiving ICMPv6 router solicitations and sending advertisements.
+ * @param fd the socket's {@link FileDescriptor}.
+ * @param ifIndex the interface index.
+ */
+ public native static void setupRaSocket(FileDescriptor fd, int ifIndex) throws SocketException;
+
/**
* Binds the current process to the network designated by {@code netId}. All sockets created
* in the future (and not explicitly bound via a bound {@link SocketFactory} (see
diff --git a/core/java/android/net/metrics/ApfProgramEvent.java b/core/java/android/net/metrics/ApfProgramEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..258d8e13951fadee7e731587f4361f559f913b97
--- /dev/null
+++ b/core/java/android/net/metrics/ApfProgramEvent.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.metrics;
+
+import android.annotation.IntDef;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.text.TextUtils;
+import android.util.SparseArray;
+
+import com.android.internal.util.MessageUtils;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.BitSet;
+import java.util.List;
+
+/**
+ * An event logged when there is a change or event that requires updating the
+ * the APF program in place with a new APF program.
+ * {@hide}
+ */
+@SystemApi
+public final class ApfProgramEvent implements Parcelable {
+
+ // Bitflag constants describing what an Apf program filters.
+ // Bits are indexeds from LSB to MSB, starting at index 0.
+ public static final int FLAG_MULTICAST_FILTER_ON = 0;
+ public static final int FLAG_HAS_IPV4_ADDRESS = 1;
+
+ /** {@hide} */
+ @IntDef(flag = true, value = {FLAG_MULTICAST_FILTER_ON, FLAG_HAS_IPV4_ADDRESS})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Flags {}
+
+ public final long lifetime; // Lifetime of the program in seconds
+ public final int filteredRas; // Number of RAs filtered by the APF program
+ public final int currentRas; // Total number of current RAs at generation time
+ public final int programLength; // Length of the APF program in bytes
+ public final int flags; // Bitfield compound of FLAG_* constants
+
+ /** {@hide} */
+ public ApfProgramEvent(
+ long lifetime, int filteredRas, int currentRas, int programLength, @Flags int flags) {
+ this.lifetime = lifetime;
+ this.filteredRas = filteredRas;
+ this.currentRas = currentRas;
+ this.programLength = programLength;
+ this.flags = flags;
+ }
+
+ private ApfProgramEvent(Parcel in) {
+ this.lifetime = in.readLong();
+ this.filteredRas = in.readInt();
+ this.currentRas = in.readInt();
+ this.programLength = in.readInt();
+ this.flags = in.readInt();
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeLong(lifetime);
+ out.writeInt(filteredRas);
+ out.writeInt(currentRas);
+ out.writeInt(programLength);
+ out.writeInt(flags);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public String toString() {
+ String lifetimeString = (lifetime < Long.MAX_VALUE) ? lifetime + "s" : "forever";
+ return String.format("ApfProgramEvent(%d/%d RAs %dB %s %s)",
+ filteredRas, currentRas, programLength, lifetimeString, namesOf(flags));
+ }
+
+ public static final Parcelable.Creator CREATOR
+ = new Parcelable.Creator() {
+ public ApfProgramEvent createFromParcel(Parcel in) {
+ return new ApfProgramEvent(in);
+ }
+
+ public ApfProgramEvent[] newArray(int size) {
+ return new ApfProgramEvent[size];
+ }
+ };
+
+ /** {@hide} */
+ public static @Flags int flagsFor(boolean hasIPv4, boolean multicastFilterOn) {
+ int bitfield = 0;
+ if (hasIPv4) {
+ bitfield |= (1 << FLAG_HAS_IPV4_ADDRESS);
+ }
+ if (multicastFilterOn) {
+ bitfield |= (1 << FLAG_MULTICAST_FILTER_ON);
+ }
+ return bitfield;
+ }
+
+ private static String namesOf(@Flags int bitfield) {
+ List names = new ArrayList<>(Integer.bitCount(bitfield));
+ BitSet set = BitSet.valueOf(new long[]{bitfield & Integer.MAX_VALUE});
+ // Only iterate over flag bits which are set.
+ for (int bit = set.nextSetBit(0); bit >= 0; bit = set.nextSetBit(bit+1)) {
+ names.add(Decoder.constants.get(bit));
+ }
+ return TextUtils.join("|", names);
+ }
+
+ final static class Decoder {
+ static final SparseArray constants =
+ MessageUtils.findMessageNames(
+ new Class[]{ApfProgramEvent.class}, new String[]{"FLAG_"});
+ }
+}
diff --git a/core/java/android/net/metrics/ApfStats.java b/core/java/android/net/metrics/ApfStats.java
new file mode 100644
index 0000000000000000000000000000000000000000..8451e539a7f677beb71c293a1c5d0d321c4fbbed
--- /dev/null
+++ b/core/java/android/net/metrics/ApfStats.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.metrics;
+
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * An event logged for an interface with APF capabilities when its IpManager state machine exits.
+ * {@hide}
+ */
+@SystemApi
+public final class ApfStats implements Parcelable {
+
+ public final long durationMs; // time interval in milliseconds these stastistics covers
+ public final int receivedRas; // number of received RAs
+ public final int matchingRas; // number of received RAs matching a known RA
+ public final int droppedRas; // number of received RAs ignored due to the MAX_RAS limit
+ public final int zeroLifetimeRas; // number of received RAs with a minimum lifetime of 0
+ public final int parseErrors; // number of received RAs that could not be parsed
+ public final int programUpdates; // number of APF program updates
+ public final int maxProgramSize; // maximum APF program size advertised by hardware
+
+ /** {@hide} */
+ public ApfStats(long durationMs, int receivedRas, int matchingRas, int droppedRas,
+ int zeroLifetimeRas, int parseErrors, int programUpdates, int maxProgramSize) {
+ this.durationMs = durationMs;
+ this.receivedRas = receivedRas;
+ this.matchingRas = matchingRas;
+ this.droppedRas = droppedRas;
+ this.zeroLifetimeRas = zeroLifetimeRas;
+ this.parseErrors = parseErrors;
+ this.programUpdates = programUpdates;
+ this.maxProgramSize = maxProgramSize;
+ }
+
+ private ApfStats(Parcel in) {
+ this.durationMs = in.readLong();
+ this.receivedRas = in.readInt();
+ this.matchingRas = in.readInt();
+ this.droppedRas = in.readInt();
+ this.zeroLifetimeRas = in.readInt();
+ this.parseErrors = in.readInt();
+ this.programUpdates = in.readInt();
+ this.maxProgramSize = in.readInt();
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeLong(durationMs);
+ out.writeInt(receivedRas);
+ out.writeInt(matchingRas);
+ out.writeInt(droppedRas);
+ out.writeInt(zeroLifetimeRas);
+ out.writeInt(parseErrors);
+ out.writeInt(programUpdates);
+ out.writeInt(maxProgramSize);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public String toString() {
+ return new StringBuilder("ApfStats(")
+ .append(String.format("%dms ", durationMs))
+ .append(String.format("%dB RA: {", maxProgramSize))
+ .append(String.format("%d received, ", receivedRas))
+ .append(String.format("%d matching, ", matchingRas))
+ .append(String.format("%d dropped, ", droppedRas))
+ .append(String.format("%d zero lifetime, ", zeroLifetimeRas))
+ .append(String.format("%d parse errors, ", parseErrors))
+ .append(String.format("%d program updates})", programUpdates))
+ .toString();
+ }
+
+ public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
+ public ApfStats createFromParcel(Parcel in) {
+ return new ApfStats(in);
+ }
+
+ public ApfStats[] newArray(int size) {
+ return new ApfStats[size];
+ }
+ };
+}
diff --git a/core/java/android/net/metrics/DefaultNetworkEvent.java b/core/java/android/net/metrics/DefaultNetworkEvent.java
index f8b59925cb9105b76610e107faf1672ca7b0dd27..9f0bad7ee9fe2d96d564f9462cac628425871d42 100644
--- a/core/java/android/net/metrics/DefaultNetworkEvent.java
+++ b/core/java/android/net/metrics/DefaultNetworkEvent.java
@@ -22,10 +22,11 @@ import android.os.Parcel;
import android.os.Parcelable;
/**
+ * An event recorded by ConnectivityService when there is a change in the default network.
* {@hide}
*/
@SystemApi
-public final class DefaultNetworkEvent extends IpConnectivityEvent implements Parcelable {
+public final class DefaultNetworkEvent implements Parcelable {
// The ID of the network that has become the new default or NETID_UNSET if none.
public final int netId;
// The list of transport types of the new default network, for example TRANSPORT_WIFI, as
@@ -37,7 +38,8 @@ public final class DefaultNetworkEvent extends IpConnectivityEvent implements Pa
public final boolean prevIPv4;
public final boolean prevIPv6;
- private DefaultNetworkEvent(int netId, int[] transportTypes,
+ /** {@hide} */
+ public DefaultNetworkEvent(int netId, int[] transportTypes,
int prevNetId, boolean prevIPv4, boolean prevIPv6) {
this.netId = netId;
this.transportTypes = transportTypes;
@@ -54,6 +56,7 @@ public final class DefaultNetworkEvent extends IpConnectivityEvent implements Pa
this.prevIPv6 = (in.readByte() > 0);
}
+ @Override
public void writeToParcel(Parcel out, int flags) {
out.writeInt(netId);
out.writeIntArray(transportTypes);
@@ -62,6 +65,7 @@ public final class DefaultNetworkEvent extends IpConnectivityEvent implements Pa
out.writeByte(prevIPv6 ? (byte) 1 : (byte) 0);
}
+ @Override
public int describeContents() {
return 0;
}
@@ -105,6 +109,5 @@ public final class DefaultNetworkEvent extends IpConnectivityEvent implements Pa
public static void logEvent(
int netId, int[] transports, int prevNetId, boolean hadIPv4, boolean hadIPv6) {
- logEvent(new DefaultNetworkEvent(netId, transports, prevNetId, hadIPv4, hadIPv6));
}
-};
+}
diff --git a/core/java/android/net/metrics/DhcpClientEvent.java b/core/java/android/net/metrics/DhcpClientEvent.java
index ec560bf64ccc3d2ac250a39728d2798f8a00594c..4a9ff051124699380047033cde83df45295618e3 100644
--- a/core/java/android/net/metrics/DhcpClientEvent.java
+++ b/core/java/android/net/metrics/DhcpClientEvent.java
@@ -21,35 +21,50 @@ import android.os.Parcel;
import android.os.Parcelable;
/**
+ * An event recorded when a DhcpClient state machine transitions to a new state.
* {@hide}
*/
@SystemApi
-public final class DhcpClientEvent extends IpConnectivityEvent implements Parcelable {
+public final class DhcpClientEvent implements Parcelable {
+
+ // Names for recording DhcpClient pseudo-state transitions.
+ /** {@hide} Represents transitions from DhcpInitState to DhcpBoundState */
+ public static final String INITIAL_BOUND = "InitialBoundState";
+ /** {@hide} Represents transitions from and to DhcpBoundState via DhcpRenewingState */
+ public static final String RENEWING_BOUND = "RenewingBoundState";
+
public final String ifName;
public final String msg;
+ public final int durationMs;
- private DhcpClientEvent(String ifName, String msg) {
+ /** {@hide} */
+ public DhcpClientEvent(String ifName, String msg, int durationMs) {
this.ifName = ifName;
this.msg = msg;
+ this.durationMs = durationMs;
}
private DhcpClientEvent(Parcel in) {
this.ifName = in.readString();
this.msg = in.readString();
+ this.durationMs = in.readInt();
}
+ @Override
public void writeToParcel(Parcel out, int flags) {
out.writeString(ifName);
out.writeString(msg);
+ out.writeInt(durationMs);
}
+ @Override
public int describeContents() {
return 0;
}
@Override
public String toString() {
- return String.format("DhcpClientEvent(%s, %s)", ifName, msg);
+ return String.format("DhcpClientEvent(%s, %s, %dms)", ifName, msg, durationMs);
}
public static final Parcelable.Creator CREATOR
@@ -64,6 +79,5 @@ public final class DhcpClientEvent extends IpConnectivityEvent implements Parcel
};
public static void logStateEvent(String ifName, String state) {
- logEvent(new DhcpClientEvent(ifName, state));
}
-};
+}
diff --git a/core/java/android/net/metrics/DhcpErrorEvent.java b/core/java/android/net/metrics/DhcpErrorEvent.java
index 84795b89bb6b0369ef4b0c87514f2b14f7429fa1..59c5fb61b2116725cfd39277ceecc97a8847eb57 100644
--- a/core/java/android/net/metrics/DhcpErrorEvent.java
+++ b/core/java/android/net/metrics/DhcpErrorEvent.java
@@ -24,10 +24,11 @@ import android.util.SparseArray;
import com.android.internal.util.MessageUtils;
/**
- * {@hide} Event class used to record error events when parsing DHCP response packets.
+ * Event class used to record error events when parsing DHCP response packets.
+ * {@hide}
*/
@SystemApi
-public final class DhcpErrorEvent extends IpConnectivityEvent implements Parcelable {
+public final class DhcpErrorEvent implements Parcelable {
public static final int L2_ERROR = 1;
public static final int L3_ERROR = 2;
public static final int L4_ERROR = 3;
@@ -61,7 +62,8 @@ public final class DhcpErrorEvent extends IpConnectivityEvent implements Parcela
// byte 3: optional code
public final int errorCode;
- private DhcpErrorEvent(String ifName, int errorCode) {
+ /** {@hide} */
+ public DhcpErrorEvent(String ifName, int errorCode) {
this.ifName = ifName;
this.errorCode = errorCode;
}
@@ -71,11 +73,13 @@ public final class DhcpErrorEvent extends IpConnectivityEvent implements Parcela
this.errorCode = in.readInt();
}
+ @Override
public void writeToParcel(Parcel out, int flags) {
out.writeString(ifName);
out.writeInt(errorCode);
}
+ @Override
public int describeContents() {
return 0;
}
@@ -92,11 +96,9 @@ public final class DhcpErrorEvent extends IpConnectivityEvent implements Parcela
};
public static void logParseError(String ifName, int errorCode) {
- logEvent(new DhcpErrorEvent(ifName, errorCode));
}
public static void logReceiveError(String ifName) {
- logEvent(new DhcpErrorEvent(ifName, RECEIVE_ERROR));
}
public static int errorCodeWithOption(int errorCode, int option) {
diff --git a/core/java/android/net/metrics/DnsEvent.java b/core/java/android/net/metrics/DnsEvent.java
index b94dda079cd8efddabc235e05f7f9f4fc697c9df..4fc6b7aaf8425815d8a7db460812d048bd52a20f 100644
--- a/core/java/android/net/metrics/DnsEvent.java
+++ b/core/java/android/net/metrics/DnsEvent.java
@@ -21,10 +21,11 @@ import android.os.Parcel;
import android.os.Parcelable;
/**
+ * An event recorded by DnsEventListenerService.
* {@hide}
*/
@SystemApi
-final public class DnsEvent extends IpConnectivityEvent implements Parcelable {
+final public class DnsEvent implements Parcelable {
public final int netId;
// The event type is currently only 1 or 2, so we store it as a byte.
@@ -37,7 +38,8 @@ final public class DnsEvent extends IpConnectivityEvent implements Parcelable {
// queries.
public final int[] latenciesMs;
- private DnsEvent(int netId, byte[] eventTypes, byte[] returnCodes, int[] latenciesMs) {
+ /** {@hide} */
+ public DnsEvent(int netId, byte[] eventTypes, byte[] returnCodes, int[] latenciesMs) {
this.netId = netId;
this.eventTypes = eventTypes;
this.returnCodes = returnCodes;
@@ -59,6 +61,7 @@ final public class DnsEvent extends IpConnectivityEvent implements Parcelable {
out.writeIntArray(latenciesMs);
}
+ @Override
public int describeContents() {
return 0;
}
@@ -82,6 +85,5 @@ final public class DnsEvent extends IpConnectivityEvent implements Parcelable {
public static void logEvent(
int netId, byte[] eventTypes, byte[] returnCodes, int[] latenciesMs) {
- logEvent(new DnsEvent(netId, eventTypes, returnCodes, latenciesMs));
}
}
diff --git a/core/java/android/net/metrics/IpConnectivityEvent.java b/core/java/android/net/metrics/IpConnectivityEvent.java
deleted file mode 100644
index 95576c2853dde713fd6312ddd816a3a85ab5af76..0000000000000000000000000000000000000000
--- a/core/java/android/net/metrics/IpConnectivityEvent.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.metrics;
-
-import android.net.ConnectivityMetricsLogger;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-/**
- * {@hide}
- */
-public abstract class IpConnectivityEvent {
- private static final int COMPONENT_TAG = ConnectivityMetricsLogger.COMPONENT_TAG_CONNECTIVITY;
-
- private static final ConnectivityMetricsLogger sMetricsLogger = new ConnectivityMetricsLogger();
-
- public static void logEvent(T event) {
- // TODO: consider using different component for DNS event.
- sMetricsLogger.logEvent(System.currentTimeMillis(), COMPONENT_TAG, 0, event);
- }
-};
diff --git a/core/java/android/net/metrics/IpConnectivityLog.java b/core/java/android/net/metrics/IpConnectivityLog.java
new file mode 100644
index 0000000000000000000000000000000000000000..dd7bd1b915b852e84478620c5dab851c9bf66640
--- /dev/null
+++ b/core/java/android/net/metrics/IpConnectivityLog.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.metrics;
+
+import android.net.ConnectivityMetricsEvent;
+import android.net.ConnectivityMetricsLogger;
+import android.net.IConnectivityMetricsLogger;
+import android.os.Parcelable;
+import android.os.RemoteException;
+import android.util.Log;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+/**
+ * Specialization of the ConnectivityMetricsLogger class for recording IP connectivity events.
+ * {@hide}
+ */
+public class IpConnectivityLog extends ConnectivityMetricsLogger {
+ private static String TAG = "IpConnectivityMetricsLogger";
+ private static final boolean DBG = true;
+
+ public IpConnectivityLog() {
+ // mService initialized in super constructor.
+ }
+
+ @VisibleForTesting
+ public IpConnectivityLog(IConnectivityMetricsLogger service) {
+ super(service);
+ }
+
+ /**
+ * Log an IpConnectivity event. Contrary to logEvent(), this method does not
+ * keep track of skipped events and is thread-safe for callers.
+ *
+ * @param timestamp is the epoch timestamp of the event in ms.
+ * @param data is a Parcelable instance representing the event.
+ *
+ * @return true if the event was successfully logged.
+ */
+ public boolean log(long timestamp, Parcelable data) {
+ if (!checkLoggerService()) {
+ if (DBG) {
+ Log.d(TAG, CONNECTIVITY_METRICS_LOGGER_SERVICE + " service was not ready");
+ }
+ return false;
+ }
+
+ if (System.currentTimeMillis() < mServiceUnblockedTimestampMillis) {
+ if (DBG) {
+ Log.d(TAG, "skipping logging due to throttling for IpConnectivity component");
+ }
+ return false;
+ }
+
+ try {
+ final ConnectivityMetricsEvent event =
+ new ConnectivityMetricsEvent(timestamp, COMPONENT_TAG_CONNECTIVITY, 0, data);
+ final long result = mService.logEvent(event);
+ if (result >= 0) {
+ mServiceUnblockedTimestampMillis = result;
+ }
+ return (result == 0);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error logging event", e);
+ return false;
+ }
+ }
+
+ public void log(Parcelable event) {
+ log(System.currentTimeMillis(), event);
+ }
+}
diff --git a/core/java/android/net/metrics/IpManagerEvent.java b/core/java/android/net/metrics/IpManagerEvent.java
index 0940bd06c3d34587923dacbeb093b7c6b9b0e7d7..a5b4eb5aff86f7920c3e28bb5de7b770e5317333 100644
--- a/core/java/android/net/metrics/IpManagerEvent.java
+++ b/core/java/android/net/metrics/IpManagerEvent.java
@@ -16,6 +16,7 @@
package android.net.metrics;
+import android.annotation.IntDef;
import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
@@ -23,21 +24,32 @@ import android.util.SparseArray;
import com.android.internal.util.MessageUtils;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
/**
+ * An event recorded by IpManager when IP provisioning completes for a network or
+ * when a network disconnects.
* {@hide}
*/
@SystemApi
-public final class IpManagerEvent extends IpConnectivityEvent implements Parcelable {
+public final class IpManagerEvent implements Parcelable {
public static final int PROVISIONING_OK = 1;
public static final int PROVISIONING_FAIL = 2;
public static final int COMPLETE_LIFECYCLE = 3;
+ /** {@hide} */
+ @IntDef(value = {PROVISIONING_OK, PROVISIONING_FAIL, COMPLETE_LIFECYCLE})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface EventType {}
+
public final String ifName;
- public final int eventType;
+ public final @EventType int eventType;
public final long durationMs;
- private IpManagerEvent(String ifName, int eventType, long duration) {
+ /** {@hide} */
+ public IpManagerEvent(String ifName, @EventType int eventType, long duration) {
this.ifName = ifName;
this.eventType = eventType;
this.durationMs = duration;
@@ -49,12 +61,14 @@ public final class IpManagerEvent extends IpConnectivityEvent implements Parcela
this.durationMs = in.readLong();
}
+ @Override
public void writeToParcel(Parcel out, int flags) {
out.writeString(ifName);
out.writeInt(eventType);
out.writeLong(durationMs);
}
+ @Override
public int describeContents() {
return 0;
}
@@ -71,7 +85,6 @@ public final class IpManagerEvent extends IpConnectivityEvent implements Parcela
};
public static void logEvent(int eventType, String ifName, long durationMs) {
- logEvent(new IpManagerEvent(ifName, eventType, durationMs));
}
@Override
@@ -84,4 +97,4 @@ public final class IpManagerEvent extends IpConnectivityEvent implements Parcela
static final SparseArray constants = MessageUtils.findMessageNames(
new Class[]{IpManagerEvent.class}, new String[]{"PROVISIONING_", "COMPLETE_"});
}
-};
+}
diff --git a/core/java/android/net/metrics/IpReachabilityEvent.java b/core/java/android/net/metrics/IpReachabilityEvent.java
index d40389c03986712c6ca9953081cdc9066242c274..ee09e229266164b301742de36590d9ba5d6c1ad1 100644
--- a/core/java/android/net/metrics/IpReachabilityEvent.java
+++ b/core/java/android/net/metrics/IpReachabilityEvent.java
@@ -24,24 +24,35 @@ import android.util.SparseArray;
import com.android.internal.util.MessageUtils;
/**
+ * An event recorded when IpReachabilityMonitor sends a neighbor probe or receives
+ * a neighbor probe result.
* {@hide}
*/
@SystemApi
-public final class IpReachabilityEvent extends IpConnectivityEvent implements Parcelable {
-
- public static final int PROBE = 1 << 8;
- public static final int NUD_FAILED = 2 << 8;
- public static final int PROVISIONING_LOST = 3 << 8;
+public final class IpReachabilityEvent implements Parcelable {
+
+ // Event types.
+ /** A probe forced by IpReachabilityMonitor. */
+ public static final int PROBE = 1 << 8;
+ /** Neighbor unreachable after a forced probe. */
+ public static final int NUD_FAILED = 2 << 8;
+ /** Neighbor unreachable after a forced probe, IP provisioning is also lost. */
+ public static final int PROVISIONING_LOST = 3 << 8;
+ /** {@hide} Neighbor unreachable notification from kernel. */
+ public static final int NUD_FAILED_ORGANIC = 4 << 8;
+ /** {@hide} Neighbor unreachable notification from kernel, IP provisioning is also lost. */
+ public static final int PROVISIONING_LOST_ORGANIC = 5 << 8;
public final String ifName;
// eventType byte format (MSB to LSB):
// byte 0: unused
// byte 1: unused
// byte 2: type of event: PROBE, NUD_FAILED, PROVISIONING_LOST
- // byte 3: kernel errno from RTNetlink or IpReachabilityMonitor
+ // byte 3: when byte 2 == PROBE, errno code from RTNetlink or IpReachabilityMonitor.
public final int eventType;
- private IpReachabilityEvent(String ifName, int eventType) {
+ /** {@hide} */
+ public IpReachabilityEvent(String ifName, int eventType) {
this.ifName = ifName;
this.eventType = eventType;
}
@@ -51,11 +62,13 @@ public final class IpReachabilityEvent extends IpConnectivityEvent implements Pa
this.eventType = in.readInt();
}
+ @Override
public void writeToParcel(Parcel out, int flags) {
out.writeString(ifName);
out.writeInt(eventType);
}
+ @Override
public int describeContents() {
return 0;
}
@@ -72,21 +85,32 @@ public final class IpReachabilityEvent extends IpConnectivityEvent implements Pa
};
public static void logProbeEvent(String ifName, int nlErrorCode) {
- logEvent(new IpReachabilityEvent(ifName, PROBE | (nlErrorCode & 0xFF)));
}
public static void logNudFailed(String ifName) {
- logEvent(new IpReachabilityEvent(ifName, NUD_FAILED));
}
public static void logProvisioningLost(String ifName) {
- logEvent(new IpReachabilityEvent(ifName, PROVISIONING_LOST));
+ }
+
+ /**
+ * Returns the NUD failure event type code corresponding to the given conditions.
+ * {@hide}
+ */
+ public static int nudFailureEventType(boolean isFromProbe, boolean isProvisioningLost) {
+ if (isFromProbe) {
+ return isProvisioningLost ? PROVISIONING_LOST : NUD_FAILED;
+ } else {
+ return isProvisioningLost ? PROVISIONING_LOST_ORGANIC : NUD_FAILED_ORGANIC;
+ }
}
@Override
public String toString() {
- return String.format("IpReachabilityEvent(%s, %s)", ifName,
- Decoder.constants.get(eventType));
+ int hi = eventType & 0xff00;
+ int lo = eventType & 0x00ff;
+ String eventName = Decoder.constants.get(hi);
+ return String.format("IpReachabilityEvent(%s, %s:%02x)", ifName, eventName, lo);
}
final static class Decoder {
@@ -94,4 +118,4 @@ public final class IpReachabilityEvent extends IpConnectivityEvent implements Pa
MessageUtils.findMessageNames(new Class[]{IpReachabilityEvent.class},
new String[]{"PROBE", "PROVISIONING_", "NUD_"});
}
-};
+}
diff --git a/core/java/android/net/metrics/NetworkEvent.java b/core/java/android/net/metrics/NetworkEvent.java
index 08c9c758bbc8696aa04b76626c8b9719413a971e..3b3fa6976fc982181a7ee57103b47b62ef00bf93 100644
--- a/core/java/android/net/metrics/NetworkEvent.java
+++ b/core/java/android/net/metrics/NetworkEvent.java
@@ -16,6 +16,7 @@
package android.net.metrics;
+import android.annotation.IntDef;
import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
@@ -23,11 +24,14 @@ import android.util.SparseArray;
import com.android.internal.util.MessageUtils;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
/**
* {@hide}
*/
@SystemApi
-public final class NetworkEvent extends IpConnectivityEvent implements Parcelable {
+public final class NetworkEvent implements Parcelable {
public static final int NETWORK_CONNECTED = 1;
public static final int NETWORK_VALIDATED = 2;
@@ -37,28 +41,49 @@ public final class NetworkEvent extends IpConnectivityEvent implements Parcelabl
public static final int NETWORK_UNLINGER = 6;
public static final int NETWORK_DISCONNECTED = 7;
+ /** {@hide} */
+ @IntDef(value = {
+ NETWORK_CONNECTED,
+ NETWORK_VALIDATED,
+ NETWORK_VALIDATION_FAILED,
+ NETWORK_CAPTIVE_PORTAL_FOUND,
+ NETWORK_LINGER,
+ NETWORK_UNLINGER,
+ NETWORK_DISCONNECTED,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface EventType {}
+
public final int netId;
- public final int eventType;
+ public final @EventType int eventType;
public final long durationMs;
- private NetworkEvent(int netId, int eventType, long durationMs) {
+ /** {@hide} */
+ public NetworkEvent(int netId, @EventType int eventType, long durationMs) {
this.netId = netId;
this.eventType = eventType;
this.durationMs = durationMs;
}
+ /** {@hide} */
+ public NetworkEvent(int netId, @EventType int eventType) {
+ this(netId, eventType, 0);
+ }
+
private NetworkEvent(Parcel in) {
netId = in.readInt();
eventType = in.readInt();
durationMs = in.readLong();
}
+ @Override
public void writeToParcel(Parcel out, int flags) {
out.writeInt(netId);
out.writeInt(eventType);
out.writeLong(durationMs);
}
+ @Override
public int describeContents() {
return 0;
}
@@ -75,15 +100,12 @@ public final class NetworkEvent extends IpConnectivityEvent implements Parcelabl
};
public static void logEvent(int netId, int eventType) {
- logEvent(new NetworkEvent(netId, eventType, 0));
}
public static void logValidated(int netId, long durationMs) {
- logEvent(new NetworkEvent(netId, NETWORK_VALIDATED, durationMs));
}
public static void logCaptivePortalFound(int netId, long durationMs) {
- logEvent(new NetworkEvent(netId, NETWORK_CAPTIVE_PORTAL_FOUND, durationMs));
}
@Override
@@ -96,4 +118,4 @@ public final class NetworkEvent extends IpConnectivityEvent implements Parcelabl
static final SparseArray constants = MessageUtils.findMessageNames(
new Class[]{NetworkEvent.class}, new String[]{"NETWORK_"});
}
-};
+}
diff --git a/core/java/android/net/metrics/RaEvent.java b/core/java/android/net/metrics/RaEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..91bd023cd56cb19033a1337139747db98130702b
--- /dev/null
+++ b/core/java/android/net/metrics/RaEvent.java
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.metrics;
+
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * An event logged when the APF packet socket receives an RA packet.
+ * {@hide}
+ */
+@SystemApi
+public final class RaEvent implements Parcelable {
+
+ /** {@hide} */
+ public static final long NO_LIFETIME = -1L;
+
+ // Lifetime in seconds of options found in a single RA packet.
+ // When an option is not set, the value of the associated field is -1;
+ public final long routerLifetime;
+ public final long prefixValidLifetime;
+ public final long prefixPreferredLifetime;
+ public final long routeInfoLifetime;
+ public final long rdnssLifetime;
+ public final long dnsslLifetime;
+
+ /** {@hide} */
+ public RaEvent(long routerLifetime, long prefixValidLifetime, long prefixPreferredLifetime,
+ long routeInfoLifetime, long rdnssLifetime, long dnsslLifetime) {
+ this.routerLifetime = routerLifetime;
+ this.prefixValidLifetime = prefixValidLifetime;
+ this.prefixPreferredLifetime = prefixPreferredLifetime;
+ this.routeInfoLifetime = routeInfoLifetime;
+ this.rdnssLifetime = rdnssLifetime;
+ this.dnsslLifetime = dnsslLifetime;
+ }
+
+ private RaEvent(Parcel in) {
+ routerLifetime = in.readLong();
+ prefixValidLifetime = in.readLong();
+ prefixPreferredLifetime = in.readLong();
+ routeInfoLifetime = in.readLong();
+ rdnssLifetime = in.readLong();
+ dnsslLifetime = in.readLong();
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeLong(routerLifetime);
+ out.writeLong(prefixValidLifetime);
+ out.writeLong(prefixPreferredLifetime);
+ out.writeLong(routeInfoLifetime);
+ out.writeLong(rdnssLifetime);
+ out.writeLong(dnsslLifetime);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public String toString() {
+ return new StringBuilder("RaEvent(lifetimes: ")
+ .append(String.format("router=%ds, ", routerLifetime))
+ .append(String.format("prefix_valid=%ds, ", prefixValidLifetime))
+ .append(String.format("prefix_preferred=%ds, ", prefixPreferredLifetime))
+ .append(String.format("route_info=%ds, ", routeInfoLifetime))
+ .append(String.format("rdnss=%ds, ", rdnssLifetime))
+ .append(String.format("dnssl=%ds)", dnsslLifetime))
+ .toString();
+ }
+
+ public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
+ public RaEvent createFromParcel(Parcel in) {
+ return new RaEvent(in);
+ }
+
+ public RaEvent[] newArray(int size) {
+ return new RaEvent[size];
+ }
+ };
+
+ /** {@hide} */
+ public static class Builder {
+
+ long routerLifetime = NO_LIFETIME;
+ long prefixValidLifetime = NO_LIFETIME;
+ long prefixPreferredLifetime = NO_LIFETIME;
+ long routeInfoLifetime = NO_LIFETIME;
+ long rdnssLifetime = NO_LIFETIME;
+ long dnsslLifetime = NO_LIFETIME;
+
+ public Builder() {
+ }
+
+ public RaEvent build() {
+ return new RaEvent(routerLifetime, prefixValidLifetime, prefixPreferredLifetime,
+ routeInfoLifetime, rdnssLifetime, dnsslLifetime);
+ }
+
+ public Builder updateRouterLifetime(long lifetime) {
+ routerLifetime = updateLifetime(routerLifetime, lifetime);
+ return this;
+ }
+
+ public Builder updatePrefixValidLifetime(long lifetime) {
+ prefixValidLifetime = updateLifetime(prefixValidLifetime, lifetime);
+ return this;
+ }
+
+ public Builder updatePrefixPreferredLifetime(long lifetime) {
+ prefixPreferredLifetime = updateLifetime(prefixPreferredLifetime, lifetime);
+ return this;
+ }
+
+ public Builder updateRouteInfoLifetime(long lifetime) {
+ routeInfoLifetime = updateLifetime(routeInfoLifetime, lifetime);
+ return this;
+ }
+
+ public Builder updateRdnssLifetime(long lifetime) {
+ rdnssLifetime = updateLifetime(rdnssLifetime, lifetime);
+ return this;
+ }
+
+ public Builder updateDnsslLifetime(long lifetime) {
+ dnsslLifetime = updateLifetime(dnsslLifetime, lifetime);
+ return this;
+ }
+
+ private long updateLifetime(long currentLifetime, long newLifetime) {
+ if (currentLifetime == RaEvent.NO_LIFETIME) {
+ return newLifetime;
+ }
+ return Math.min(currentLifetime, newLifetime);
+ }
+ }
+}
diff --git a/core/java/android/net/metrics/ValidationProbeEvent.java b/core/java/android/net/metrics/ValidationProbeEvent.java
index 751c35f8a1443c5a7c63d140fa1c81b0cc3c6cdf..331cf0cdd4ad7698534ecc268d77a02feea06397 100644
--- a/core/java/android/net/metrics/ValidationProbeEvent.java
+++ b/core/java/android/net/metrics/ValidationProbeEvent.java
@@ -16,6 +16,7 @@
package android.net.metrics;
+import android.annotation.IntDef;
import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
@@ -23,11 +24,15 @@ import android.util.SparseArray;
import com.android.internal.util.MessageUtils;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
/**
+ * An event recorded by NetworkMonitor when sending a probe for finding captive portals.
* {@hide}
*/
@SystemApi
-public final class ValidationProbeEvent extends IpConnectivityEvent implements Parcelable {
+public final class ValidationProbeEvent implements Parcelable {
public static final int PROBE_DNS = 0;
public static final int PROBE_HTTP = 1;
@@ -37,12 +42,24 @@ public final class ValidationProbeEvent extends IpConnectivityEvent implements P
public static final int DNS_FAILURE = 0;
public static final int DNS_SUCCESS = 1;
+ /** {@hide} */
+ @IntDef(value = {PROBE_DNS, PROBE_HTTP, PROBE_HTTPS, PROBE_PAC})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ProbeType {}
+
+ /** {@hide} */
+ @IntDef(value = {DNS_FAILURE, DNS_SUCCESS})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ReturnCode {}
+
public final int netId;
public final long durationMs;
- public final int probeType;
- public final int returnCode;
+ public final @ProbeType int probeType;
+ public final @ReturnCode int returnCode;
- private ValidationProbeEvent(int netId, long durationMs, int probeType, int returnCode) {
+ /** @hide */
+ public ValidationProbeEvent(
+ int netId, long durationMs, @ProbeType int probeType, @ReturnCode int returnCode) {
this.netId = netId;
this.durationMs = durationMs;
this.probeType = probeType;
@@ -56,6 +73,7 @@ public final class ValidationProbeEvent extends IpConnectivityEvent implements P
returnCode = in.readInt();
}
+ @Override
public void writeToParcel(Parcel out, int flags) {
out.writeInt(netId);
out.writeLong(durationMs);
@@ -63,6 +81,7 @@ public final class ValidationProbeEvent extends IpConnectivityEvent implements P
out.writeInt(returnCode);
}
+ @Override
public int describeContents() {
return 0;
}
@@ -84,7 +103,6 @@ public final class ValidationProbeEvent extends IpConnectivityEvent implements P
}
public static void logEvent(int netId, long durationMs, int probeType, int returnCode) {
- logEvent(new ValidationProbeEvent(netId, durationMs, probeType, returnCode));
}
@Override
@@ -97,4 +115,4 @@ public final class ValidationProbeEvent extends IpConnectivityEvent implements P
static final SparseArray constants = MessageUtils.findMessageNames(
new Class[]{ValidationProbeEvent.class}, new String[]{"PROBE_"});
}
-};
+}
diff --git a/core/java/android/net/network-policy-restrictions.md b/core/java/android/net/network-policy-restrictions.md
index fe13f7a5aab9883adfd3de2e2792e93a37d8992f..63ce1a2446430b675fb4e3bd6333305428c15184 100644
--- a/core/java/android/net/network-policy-restrictions.md
+++ b/core/java/android/net/network-policy-restrictions.md
@@ -29,8 +29,8 @@ More specifically:
| **DS** | *WL* | ok | blk | ok | ok |
| **ON** | *!WL* | blk | blk | blk | blk |
| | *BL* | blk | blk | blk | blk |
-| **DS** | *WL* | blk | ok | ok | ok |
-| **OFF** | *!WL* | blk | ok | ok | ok |
+| **DS** | *WL* | blk | blk | ok | ok |
+| **OFF** | *!WL* | blk | blk | ok | ok |
| | *BL* | blk | blk | blk | blk |
diff --git a/core/java/android/nfc/NfcAdapter.java b/core/java/android/nfc/NfcAdapter.java
index 41ff9fdf8382b9067c3188d630914bebf1e4ce2a..783c25aa4d08502df6b15cc3623cb994659b5136 100644
--- a/core/java/android/nfc/NfcAdapter.java
+++ b/core/java/android/nfc/NfcAdapter.java
@@ -290,6 +290,7 @@ public final class NfcAdapter {
// Guarded by NfcAdapter.class
static boolean sIsInitialized = false;
+ static boolean sHasNfcFeature;
// Final after first constructor, except for
// attemptDeadServiceRecovery() when NFC crashes - we accept a best effort
@@ -434,6 +435,26 @@ public final class NfcAdapter {
}
}
+ /**
+ * Helper to check if this device is NFC HCE capable, by checking for
+ * FEATURE_NFC_HOST_CARD_EMULATION and/or FEATURE_NFC_HOST_CARD_EMULATION_NFCF,
+ * but without using a context.
+ */
+ private static boolean hasNfcHceFeature() {
+ IPackageManager pm = ActivityThread.getPackageManager();
+ if (pm == null) {
+ Log.e(TAG, "Cannot get package manager, assuming no NFC feature");
+ return false;
+ }
+ try {
+ return pm.hasSystemFeature(PackageManager.FEATURE_NFC_HOST_CARD_EMULATION, 0)
+ || pm.hasSystemFeature(PackageManager.FEATURE_NFC_HOST_CARD_EMULATION_NFCF, 0);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Package manager query failed, assuming no NFC feature", e);
+ return false;
+ }
+ }
+
/**
* Returns the NfcAdapter for application context,
* or throws if NFC is not available.
@@ -441,36 +462,39 @@ public final class NfcAdapter {
*/
public static synchronized NfcAdapter getNfcAdapter(Context context) {
if (!sIsInitialized) {
+ sHasNfcFeature = hasNfcFeature();
+ boolean hasHceFeature = hasNfcHceFeature();
/* is this device meant to have NFC */
- if (!hasNfcFeature()) {
+ if (!sHasNfcFeature && !hasHceFeature) {
Log.v(TAG, "this device does not have NFC support");
throw new UnsupportedOperationException();
}
-
sService = getServiceInterface();
if (sService == null) {
Log.e(TAG, "could not retrieve NFC service");
throw new UnsupportedOperationException();
}
- try {
- sTagService = sService.getNfcTagInterface();
- } catch (RemoteException e) {
- Log.e(TAG, "could not retrieve NFC Tag service");
- throw new UnsupportedOperationException();
- }
-
- try {
- sCardEmulationService = sService.getNfcCardEmulationInterface();
- } catch (RemoteException e) {
- Log.e(TAG, "could not retrieve card emulation service");
- throw new UnsupportedOperationException();
+ if (sHasNfcFeature) {
+ try {
+ sTagService = sService.getNfcTagInterface();
+ } catch (RemoteException e) {
+ Log.e(TAG, "could not retrieve NFC Tag service");
+ throw new UnsupportedOperationException();
+ }
}
-
- try {
- sNfcFCardEmulationService = sService.getNfcFCardEmulationInterface();
- } catch (RemoteException e) {
- Log.e(TAG, "could not retrieve NFC-F card emulation service");
- throw new UnsupportedOperationException();
+ if (hasHceFeature) {
+ try {
+ sNfcFCardEmulationService = sService.getNfcFCardEmulationInterface();
+ } catch (RemoteException e) {
+ Log.e(TAG, "could not retrieve NFC-F card emulation service");
+ throw new UnsupportedOperationException();
+ }
+ try {
+ sCardEmulationService = sService.getNfcCardEmulationInterface();
+ } catch (RemoteException e) {
+ Log.e(TAG, "could not retrieve card emulation service");
+ throw new UnsupportedOperationException();
+ }
}
sIsInitialized = true;
@@ -838,8 +862,14 @@ public final class NfcAdapter {
*
* @param uris an array of Uri(s) to push over Android Beam
* @param activity activity for which the Uri(s) will be pushed
+ * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
*/
public void setBeamPushUris(Uri[] uris, Activity activity) {
+ synchronized (NfcAdapter.class) {
+ if (!sHasNfcFeature) {
+ throw new UnsupportedOperationException();
+ }
+ }
if (activity == null) {
throw new NullPointerException("activity cannot be null");
}
@@ -914,8 +944,14 @@ public final class NfcAdapter {
*
* @param callback callback, or null to disable
* @param activity activity for which the Uri(s) will be pushed
+ * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
*/
public void setBeamPushUrisCallback(CreateBeamUrisCallback callback, Activity activity) {
+ synchronized (NfcAdapter.class) {
+ if (!sHasNfcFeature) {
+ throw new UnsupportedOperationException();
+ }
+ }
if (activity == null) {
throw new NullPointerException("activity cannot be null");
}
@@ -992,9 +1028,15 @@ public final class NfcAdapter {
* @param activities optional additional activities, however we strongly recommend
* to only register one at a time, and to do so in that activity's
* {@link Activity#onCreate}
+ * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
*/
public void setNdefPushMessage(NdefMessage message, Activity activity,
Activity ... activities) {
+ synchronized (NfcAdapter.class) {
+ if (!sHasNfcFeature) {
+ throw new UnsupportedOperationException();
+ }
+ }
int targetSdkVersion = getSdkVersion();
try {
if (activity == null) {
@@ -1024,6 +1066,11 @@ public final class NfcAdapter {
*/
@SystemApi
public void setNdefPushMessage(NdefMessage message, Activity activity, int flags) {
+ synchronized (NfcAdapter.class) {
+ if (!sHasNfcFeature) {
+ throw new UnsupportedOperationException();
+ }
+ }
if (activity == null) {
throw new NullPointerException("activity cannot be null");
}
@@ -1094,9 +1141,15 @@ public final class NfcAdapter {
* @param activities optional additional activities, however we strongly recommend
* to only register one at a time, and to do so in that activity's
* {@link Activity#onCreate}
+ * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
*/
public void setNdefPushMessageCallback(CreateNdefMessageCallback callback, Activity activity,
Activity ... activities) {
+ synchronized (NfcAdapter.class) {
+ if (!sHasNfcFeature) {
+ throw new UnsupportedOperationException();
+ }
+ }
int targetSdkVersion = getSdkVersion();
try {
if (activity == null) {
@@ -1168,9 +1221,15 @@ public final class NfcAdapter {
* @param activities optional additional activities, however we strongly recommend
* to only register one at a time, and to do so in that activity's
* {@link Activity#onCreate}
+ * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
*/
public void setOnNdefPushCompleteCallback(OnNdefPushCompleteCallback callback,
Activity activity, Activity ... activities) {
+ synchronized (NfcAdapter.class) {
+ if (!sHasNfcFeature) {
+ throw new UnsupportedOperationException();
+ }
+ }
int targetSdkVersion = getSdkVersion();
try {
if (activity == null) {
@@ -1227,9 +1286,15 @@ public final class NfcAdapter {
* @param techLists the tech lists used to perform matching for dispatching of the
* {@link NfcAdapter#ACTION_TECH_DISCOVERED} intent
* @throws IllegalStateException if the Activity is not currently in the foreground
+ * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
*/
public void enableForegroundDispatch(Activity activity, PendingIntent intent,
IntentFilter[] filters, String[][] techLists) {
+ synchronized (NfcAdapter.class) {
+ if (!sHasNfcFeature) {
+ throw new UnsupportedOperationException();
+ }
+ }
if (activity == null || intent == null) {
throw new NullPointerException();
}
@@ -1263,8 +1328,14 @@ public final class NfcAdapter {
*
* @param activity the Activity to disable dispatch to
* @throws IllegalStateException if the Activity has already been paused
+ * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
*/
public void disableForegroundDispatch(Activity activity) {
+ synchronized (NfcAdapter.class) {
+ if (!sHasNfcFeature) {
+ throw new UnsupportedOperationException();
+ }
+ }
ActivityThread.currentActivityThread().unregisterOnActivityPausedListener(activity,
mForegroundDispatchListener);
disableForegroundDispatchInternal(activity, false);
@@ -1309,9 +1380,15 @@ public final class NfcAdapter {
* @param callback the callback to be called when a tag is discovered
* @param flags Flags indicating poll technologies and other optional parameters
* @param extras Additional extras for configuring reader mode.
+ * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
*/
public void enableReaderMode(Activity activity, ReaderCallback callback, int flags,
Bundle extras) {
+ synchronized (NfcAdapter.class) {
+ if (!sHasNfcFeature) {
+ throw new UnsupportedOperationException();
+ }
+ }
mNfcActivityManager.enableReaderMode(activity, callback, flags, extras);
}
@@ -1321,8 +1398,14 @@ public final class NfcAdapter {
* all supported tag technologies.
*
* @param activity the Activity that currently has reader mode enabled
+ * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
*/
public void disableReaderMode(Activity activity) {
+ synchronized (NfcAdapter.class) {
+ if (!sHasNfcFeature) {
+ throw new UnsupportedOperationException();
+ }
+ }
mNfcActivityManager.disableReaderMode(activity);
}
@@ -1349,8 +1432,14 @@ public final class NfcAdapter {
*
* @param activity the current foreground Activity that has registered data to share
* @return whether the Beam animation was successfully invoked
+ * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
*/
public boolean invokeBeam(Activity activity) {
+ synchronized (NfcAdapter.class) {
+ if (!sHasNfcFeature) {
+ throw new UnsupportedOperationException();
+ }
+ }
if (activity == null) {
throw new NullPointerException("activity may not be null.");
}
@@ -1404,10 +1493,16 @@ public final class NfcAdapter {
* @param activity foreground activity
* @param message a NDEF Message to push over NFC
* @throws IllegalStateException if the activity is not currently in the foreground
+ * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
* @deprecated use {@link #setNdefPushMessage} instead
*/
@Deprecated
public void enableForegroundNdefPush(Activity activity, NdefMessage message) {
+ synchronized (NfcAdapter.class) {
+ if (!sHasNfcFeature) {
+ throw new UnsupportedOperationException();
+ }
+ }
if (activity == null || message == null) {
throw new NullPointerException();
}
@@ -1432,10 +1527,16 @@ public final class NfcAdapter {
*
* @param activity the Foreground activity
* @throws IllegalStateException if the Activity has already been paused
+ * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
* @deprecated use {@link #setNdefPushMessage} instead
*/
@Deprecated
public void disableForegroundNdefPush(Activity activity) {
+ synchronized (NfcAdapter.class) {
+ if (!sHasNfcFeature) {
+ throw new UnsupportedOperationException();
+ }
+ }
if (activity == null) {
throw new NullPointerException();
}
@@ -1452,6 +1553,9 @@ public final class NfcAdapter {
*/
@SystemApi
public boolean enableNdefPush() {
+ if (!sHasNfcFeature) {
+ throw new UnsupportedOperationException();
+ }
try {
return sService.enableNdefPush();
} catch (RemoteException e) {
@@ -1467,6 +1571,11 @@ public final class NfcAdapter {
*/
@SystemApi
public boolean disableNdefPush() {
+ synchronized (NfcAdapter.class) {
+ if (!sHasNfcFeature) {
+ throw new UnsupportedOperationException();
+ }
+ }
try {
return sService.disableNdefPush();
} catch (RemoteException e) {
@@ -1497,8 +1606,14 @@ public final class NfcAdapter {
*
* @see android.provider.Settings#ACTION_NFCSHARING_SETTINGS
* @return true if NDEF Push feature is enabled
+ * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
*/
public boolean isNdefPushEnabled() {
+ synchronized (NfcAdapter.class) {
+ if (!sHasNfcFeature) {
+ throw new UnsupportedOperationException();
+ }
+ }
try {
return sService.isNdefPushEnabled();
} catch (RemoteException e) {
@@ -1623,6 +1738,11 @@ public final class NfcAdapter {
@SystemApi
public boolean addNfcUnlockHandler(final NfcUnlockHandler unlockHandler,
String[] tagTechnologies) {
+ synchronized (NfcAdapter.class) {
+ if (!sHasNfcFeature) {
+ throw new UnsupportedOperationException();
+ }
+ }
// If there are no tag technologies, don't bother adding unlock handler
if (tagTechnologies.length == 0) {
return false;
@@ -1666,6 +1786,11 @@ public final class NfcAdapter {
*/
@SystemApi
public boolean removeNfcUnlockHandler(NfcUnlockHandler unlockHandler) {
+ synchronized (NfcAdapter.class) {
+ if (!sHasNfcFeature) {
+ throw new UnsupportedOperationException();
+ }
+ }
try {
synchronized (mLock) {
if (mNfcUnlockHandlers.containsKey(unlockHandler)) {
diff --git a/core/java/android/os/AsyncTask.java b/core/java/android/os/AsyncTask.java
index 63f39c59b1b7f0010eab71aa1a80c0486b189100..4f4e7223acb98240e4c154e3e793101016596ce2 100644
--- a/core/java/android/os/AsyncTask.java
+++ b/core/java/android/os/AsyncTask.java
@@ -35,8 +35,8 @@ import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
/**
- *
AsyncTask enables proper and easy use of the UI thread. This class allows to
- * perform background operations and publish results on the UI thread without
+ *
AsyncTask enables proper and easy use of the UI thread. This class allows you
+ * to perform background operations and publish results on the UI thread without
* having to manipulate threads and/or handlers.
*
*
AsyncTask is designed to be a helper class around {@link Thread} and {@link Handler}
@@ -55,7 +55,7 @@ import java.util.concurrent.atomic.AtomicInteger;
*
*
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 4acb729b6a76026adfaf001c44ad7e1bc507a47e..a0c2efd407ba0387936c732bf175ab7ec5bd41b3 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -30,6 +30,8 @@ import android.content.pm.ApplicationInfo;
import android.telephony.SignalStrength;
import android.text.format.DateFormat;
import android.util.ArrayMap;
+import android.util.Log;
+import android.util.LongSparseArray;
import android.util.MutableBoolean;
import android.util.Pair;
import android.util.Printer;
@@ -47,6 +49,7 @@ import com.android.internal.os.BatteryStatsHelper;
* @hide
*/
public abstract class BatteryStats implements Parcelable {
+ private static final String TAG = "BatteryStats";
private static final boolean LOCAL_LOGV = false;
@@ -175,8 +178,11 @@ public abstract class BatteryStats implements Parcelable {
/**
* Current version of checkin data format.
+ *
+ * New in version 19:
+ * - Wakelock data (wl) gets current and max times.
*/
- static final String CHECKIN_VERSION = "18";
+ static final String CHECKIN_VERSION = "19";
/**
* Old version, we hit 9 and ran out of room, need to remove.
@@ -351,6 +357,32 @@ public abstract class BatteryStats implements Parcelable {
*/
public abstract long getTimeSinceMarkLocked(long elapsedRealtimeUs);
+ /**
+ * Returns the max duration if it is being tracked.
+ * Not all Timer subclasses track the max duration and the current duration.
+
+ */
+ public long getMaxDurationMsLocked(long elapsedRealtimeMs) {
+ return -1;
+ }
+
+ /**
+ * Returns the current time the timer has been active, if it is being tracked.
+ * Not all Timer subclasses track the max duration and the current duration.
+ */
+ public long getCurrentDurationMsLocked(long elapsedRealtimeMs) {
+ return -1;
+ }
+
+ /**
+ * Returns whether the timer is currently running. Some types of timers
+ * (e.g. BatchTimers) don't know whether the event is currently active,
+ * and report false.
+ */
+ public boolean isRunningLocked() {
+ return false;
+ }
+
/**
* Temporary for debugging.
*/
@@ -546,6 +578,20 @@ public abstract class BatteryStats implements Parcelable {
*/
public abstract long getTimeAtCpuSpeed(int cluster, int step, int which);
+ /**
+ * Returns the number of times this UID woke up the Application Processor to
+ * process a mobile radio packet.
+ * @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT.
+ */
+ public abstract long getMobileRadioApWakeupCount(int which);
+
+ /**
+ * Returns the number of times this UID woke up the Application Processor to
+ * process a WiFi packet.
+ * @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT.
+ */
+ public abstract long getWifiRadioApWakeupCount(int which);
+
public static abstract class Sensor {
/*
* FIXME: it's not correct to use this magic value because it
@@ -1285,9 +1331,14 @@ public abstract class BatteryStats implements Parcelable {
public static final int EVENT_TEMP_WHITELIST = 0x0011;
// Event for the screen waking up.
public static final int EVENT_SCREEN_WAKE_UP = 0x0012;
+ // Event for the UID that woke up the application processor.
+ // Used for wakeups coming from WiFi, modem, etc.
+ public static final int EVENT_WAKEUP_AP = 0x0013;
+ // Event for reporting that a specific partial wake lock has been held for a long duration.
+ public static final int EVENT_LONG_WAKE_LOCK = 0x0014;
// Number of event types.
- public static final int EVENT_COUNT = 0x0013;
+ public static final int EVENT_COUNT = 0x0015;
// Mask to extract out only the type part of the event.
public static final int EVENT_TYPE_MASK = ~(EVENT_FLAG_START|EVENT_FLAG_FINISH);
@@ -1315,6 +1366,10 @@ public abstract class BatteryStats implements Parcelable {
EVENT_TEMP_WHITELIST | EVENT_FLAG_START;
public static final int EVENT_TEMP_WHITELIST_FINISH =
EVENT_TEMP_WHITELIST | EVENT_FLAG_FINISH;
+ public static final int EVENT_LONG_WAKE_LOCK_START =
+ EVENT_LONG_WAKE_LOCK | EVENT_FLAG_START;
+ public static final int EVENT_LONG_WAKE_LOCK_FINISH =
+ EVENT_LONG_WAKE_LOCK | EVENT_FLAG_FINISH;
// For CMD_EVENT.
public int eventCode;
@@ -1979,13 +2034,13 @@ public abstract class BatteryStats implements Parcelable {
public static final String[] HISTORY_EVENT_NAMES = new String[] {
"null", "proc", "fg", "top", "sync", "wake_lock_in", "job", "user", "userfg", "conn",
"active", "pkginst", "pkgunin", "alarm", "stats", "inactive", "active", "tmpwhitelist",
- "screenwake",
+ "screenwake", "wakeupap", "longwake"
};
public static final String[] HISTORY_EVENT_CHECKIN_NAMES = new String[] {
"Enl", "Epr", "Efg", "Etp", "Esy", "Ewl", "Ejb", "Eur", "Euf", "Ecn",
"Eac", "Epi", "Epu", "Eal", "Est", "Eai", "Eaa", "Etw",
- "Esw",
+ "Esw", "Ewa", "Elw"
};
/**
@@ -2535,6 +2590,22 @@ public abstract class BatteryStats implements Parcelable {
sb.append('(');
sb.append(count);
sb.append(" times)");
+ final long maxDurationMs = timer.getMaxDurationMsLocked(elapsedRealtimeUs/1000);
+ if (maxDurationMs >= 0) {
+ sb.append(" max=");
+ sb.append(maxDurationMs);
+ }
+ if (timer.isRunningLocked()) {
+ final long currentMs = timer.getCurrentDurationMsLocked(elapsedRealtimeUs/1000);
+ if (currentMs >= 0) {
+ sb.append(" (running for ");
+ sb.append(currentMs);
+ sb.append("ms)");
+ } else {
+ sb.append(" (running)");
+ }
+ }
+
return ", ";
}
}
@@ -2542,6 +2613,7 @@ public abstract class BatteryStats implements Parcelable {
}
/**
+ * Prints details about a timer, if its total time was greater than 0.
*
* @param pw a PrintWriter object to print to.
* @param sb a StringBuilder object.
@@ -2550,24 +2622,40 @@ public abstract class BatteryStats implements Parcelable {
* @param which which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT.
* @param prefix a String to be prepended to each line of output.
* @param type the name of the timer.
+ * @return true if anything was printed.
*/
private static final boolean printTimer(PrintWriter pw, StringBuilder sb, Timer timer,
- long rawRealtime, int which, String prefix, String type) {
+ long rawRealtimeUs, int which, String prefix, String type) {
if (timer != null) {
// Convert from microseconds to milliseconds with rounding
- final long totalTime = (timer.getTotalTimeLocked(
- rawRealtime, which) + 500) / 1000;
+ final long totalTimeMs = (timer.getTotalTimeLocked(
+ rawRealtimeUs, which) + 500) / 1000;
final int count = timer.getCountLocked(which);
- if (totalTime != 0) {
+ if (totalTimeMs != 0) {
sb.setLength(0);
sb.append(prefix);
sb.append(" ");
sb.append(type);
sb.append(": ");
- formatTimeMs(sb, totalTime);
+ formatTimeMs(sb, totalTimeMs);
sb.append("realtime (");
sb.append(count);
sb.append(" times)");
+ final long maxDurationMs = timer.getMaxDurationMsLocked(rawRealtimeUs/1000);
+ if (maxDurationMs >= 0) {
+ sb.append(" max=");
+ sb.append(maxDurationMs);
+ }
+ if (timer.isRunningLocked()) {
+ final long currentMs = timer.getCurrentDurationMsLocked(rawRealtimeUs/1000);
+ if (currentMs >= 0) {
+ sb.append(" (running for ");
+ sb.append(currentMs);
+ sb.append("ms)");
+ } else {
+ sb.append(" (running)");
+ }
+ }
pw.println(sb.toString());
return true;
}
@@ -2590,15 +2678,23 @@ public abstract class BatteryStats implements Parcelable {
long elapsedRealtimeUs, String name, int which, String linePrefix) {
long totalTimeMicros = 0;
int count = 0;
+ long max = -1;
+ long current = -1;
if (timer != null) {
totalTimeMicros = timer.getTotalTimeLocked(elapsedRealtimeUs, which);
count = timer.getCountLocked(which);
+ current = timer.getCurrentDurationMsLocked(elapsedRealtimeUs/1000);
+ max = timer.getMaxDurationMsLocked(elapsedRealtimeUs/1000);
}
sb.append(linePrefix);
sb.append((totalTimeMicros + 500) / 1000); // microseconds to milliseconds with rounding
sb.append(',');
sb.append(name != null ? name + "," : "");
sb.append(count);
+ sb.append(',');
+ sb.append(current);
+ sb.append(',');
+ sb.append(max);
return ",";
}
@@ -3105,20 +3201,22 @@ public abstract class BatteryStats implements Parcelable {
final long mobilePacketsTx = u.getNetworkActivityPackets(NETWORK_MOBILE_TX_DATA, which);
final long mobileActiveTime = u.getMobileRadioActiveTime(which);
final int mobileActiveCount = u.getMobileRadioActiveCount(which);
+ final long mobileWakeup = u.getMobileRadioApWakeupCount(which);
final long wifiPacketsRx = u.getNetworkActivityPackets(NETWORK_WIFI_RX_DATA, which);
final long wifiPacketsTx = u.getNetworkActivityPackets(NETWORK_WIFI_TX_DATA, which);
+ final long wifiWakeup = u.getWifiRadioApWakeupCount(which);
final long btBytesRx = u.getNetworkActivityBytes(NETWORK_BT_RX_DATA, which);
final long btBytesTx = u.getNetworkActivityBytes(NETWORK_BT_TX_DATA, which);
if (mobileBytesRx > 0 || mobileBytesTx > 0 || wifiBytesRx > 0 || wifiBytesTx > 0
|| mobilePacketsRx > 0 || mobilePacketsTx > 0 || wifiPacketsRx > 0
|| wifiPacketsTx > 0 || mobileActiveTime > 0 || mobileActiveCount > 0
- || btBytesRx > 0 || btBytesTx > 0) {
+ || btBytesRx > 0 || btBytesTx > 0 || mobileWakeup > 0 || wifiWakeup > 0) {
dumpLine(pw, uid, category, NETWORK_DATA, mobileBytesRx, mobileBytesTx,
wifiBytesRx, wifiBytesTx,
mobilePacketsRx, mobilePacketsTx,
wifiPacketsRx, wifiPacketsTx,
mobileActiveTime, mobileActiveCount,
- btBytesRx, btBytesTx);
+ btBytesRx, btBytesTx, mobileWakeup, wifiWakeup);
}
// Dump modem controller data, per UID.
@@ -4125,6 +4223,9 @@ public abstract class BatteryStats implements Parcelable {
final int wifiScanCount = u.getWifiScanCount(which);
final long uidWifiRunningTime = u.getWifiRunningTime(rawRealtime, which);
+ final long mobileWakeup = u.getMobileRadioApWakeupCount(which);
+ final long wifiWakeup = u.getWifiRadioApWakeupCount(which);
+
if (mobileRxBytes > 0 || mobileTxBytes > 0
|| mobileRxPackets > 0 || mobileTxPackets > 0) {
pw.print(prefix); pw.print(" Mobile network: ");
@@ -4150,6 +4251,14 @@ public abstract class BatteryStats implements Parcelable {
pw.println(sb.toString());
}
+ if (mobileWakeup > 0) {
+ sb.setLength(0);
+ sb.append(prefix);
+ sb.append(" Mobile radio AP wakeups: ");
+ sb.append(mobileWakeup);
+ pw.println(sb.toString());
+ }
+
printControllerActivityIfInteresting(pw, sb, prefix + " ", "Modem",
u.getModemControllerActivity(), which);
@@ -4181,6 +4290,14 @@ public abstract class BatteryStats implements Parcelable {
pw.println(sb.toString());
}
+ if (wifiWakeup > 0) {
+ sb.setLength(0);
+ sb.append(prefix);
+ sb.append(" WiFi AP wakeups: ");
+ sb.append(wifiWakeup);
+ pw.println(sb.toString());
+ }
+
printControllerActivityIfInteresting(pw, sb, prefix + " ", "WiFi",
u.getWifiControllerActivity(), which);
@@ -4922,7 +5039,9 @@ public abstract class BatteryStats implements Parcelable {
pw.print(',');
pw.print(rec.stepDetails.statIdlTime);
pw.print(',');
- pw.print(rec.stepDetails.statPlatformIdleState);
+ if (rec.stepDetails.statPlatformIdleState != null) {
+ pw.print(rec.stepDetails.statPlatformIdleState);
+ }
pw.println();
}
}
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index dc7be6b5ad613f3a9c18c9fad08089e060e86955..3d3dc9cc3418ccb16ef9493cb8e7d9c4b5fa96b6 100644
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -669,9 +669,54 @@ public class Build {
public static final int M = 23;
/**
- * N is for ¯\_(ツ)_/¯.
+ * N is for Nougat.
+ *
+ *
Applications targeting this or a later release will get these
+ * new changes in behavior:
+ *
+ *
{@link android.app.DownloadManager.Request#setAllowedNetworkTypes
+ * DownloadManager.Request.setAllowedNetworkTypes}
+ * will disable "allow over metered" when specifying only
+ * {@link android.app.DownloadManager.Request#NETWORK_WIFI}.
+ *
{@link android.app.DownloadManager} no longer allows access to raw
+ * file paths.
+ *
{@link android.app.Notification.Builder#setShowWhen
+ * Notification.Builder.setShowWhen}
+ * must be called explicitly to have the time shown, and various other changes in
+ * {@link android.app.Notification.Builder Notification.Builder} to how notifications
+ * are shown.
+ *
{@link android.content.Context#MODE_WORLD_READABLE} and
+ * {@link android.content.Context#MODE_WORLD_WRITEABLE} are no longer supported.
+ *
{@link android.os.FileUriExposedException} will be thrown to applications.
+ *
Applications will see global drag and drops as per
+ * {@link android.view.View#DRAG_FLAG_GLOBAL}.
+ *
{@link android.webkit.WebView#evaluateJavascript WebView.evaluateJavascript}
+ * will not persist state from an empty WebView.
+ *
{@link android.animation.AnimatorSet} will not ignore calls to end() before
+ * start().
+ *
{@link android.app.AlarmManager#cancel(android.app.PendingIntent)
+ * AlarmManager.cancel} will throw a NullPointerException if given a null operation.
+ *
{@link android.app.FragmentManager} will ensure fragments have been created
+ * before being placed on the back stack.
+ *
{@link android.app.FragmentManager} restores fragments in
+ * {@link android.app.Fragment#onCreate Fragment.onCreate} rather than after the
+ * method returns.
+ *
{@link android.R.attr#resizeableActivity} defaults to true.
{@link android.view.ViewGroup.MarginLayoutParams} will no longer be dropped
+ * when converting between some types of layout params (such as
+ * {@link android.widget.LinearLayout.LayoutParams LinearLayout.LayoutParams} to
+ * {@link android.widget.RelativeLayout.LayoutParams RelativeLayout.LayoutParams}).
+ *
Your application processes will not be killed when the device density changes.
+ *
*/
public static final int N = 24;
+
+ /**
+ * N MR1: Nougat++.
+ */
+ public static final int N_MR1 = 25;
}
/** The type of build, like "user" or "eng". */
diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java
index d8be2b6dcc4c4f4064127fb2b2e1e564c395a0c7..4616af8f7768963dc31bbc9421e6ae5c2e7a5e70 100644
--- a/core/java/android/os/Environment.java
+++ b/core/java/android/os/Environment.java
@@ -285,6 +285,11 @@ public class Environment {
return buildPath(getDataDirectory(), "misc", "profiles", "cur", String.valueOf(userId));
}
+ /** {@hide} */
+ public static File getReferenceProfile(String packageName) {
+ return buildPath(getDataDirectory(), "misc", "profiles", "ref", packageName);
+ }
+
/** {@hide} */
public static File getDataProfilesDePackageDirectory(int userId, String packageName) {
return buildPath(getDataProfilesDeDirectory(userId), packageName);
@@ -339,6 +344,41 @@ public class Environment {
return new File(getDataUserDeDirectory(volumeUuid, userId), packageName);
}
+ /**
+ * Return preloads directory.
+ *
This directory may contain pre-loaded content such as
+ * {@link #getDataPreloadsDemoDirectory() demo videos} and
+ * {@link #getDataPreloadsAppsDirectory() APK files} .
+ * {@hide}
+ */
+ public static File getDataPreloadsDirectory() {
+ return new File(getDataDirectory(), "preloads");
+ }
+
+ /**
+ * @see #getDataPreloadsDirectory()
+ * {@hide}
+ */
+ public static File getDataPreloadsDemoDirectory() {
+ return new File(getDataPreloadsDirectory(), "demo");
+ }
+
+ /**
+ * @see #getDataPreloadsDirectory()
+ * {@hide}
+ */
+ public static File getDataPreloadsAppsDirectory() {
+ return new File(getDataPreloadsDirectory(), "apps");
+ }
+
+ /**
+ * @see #getDataPreloadsDirectory()
+ * {@hide}
+ */
+ public static File getDataPreloadsMediaDirectory() {
+ return new File(getDataPreloadsDirectory(), "media");
+ }
+
/**
* Return the primary shared/external storage directory. This directory may
* not currently be accessible if it has been mounted by the user on their
diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl
index e1f2eaf0d9710c0efb2d98f1139157047c2fefe5..b6d3655f4b1a3bc7b9b7d77d7d4c0caa72a06bee 100644
--- a/core/java/android/os/INetworkManagementService.aidl
+++ b/core/java/android/os/INetworkManagementService.aidl
@@ -18,6 +18,7 @@
package android.os;
import android.net.InterfaceConfiguration;
+import android.net.INetd;
import android.net.INetworkManagementEventObserver;
import android.net.Network;
import android.net.NetworkStats;
@@ -36,7 +37,7 @@ interface INetworkManagementService
**/
/**
- * Register an observer to receive events
+ * Register an observer to receive events.
*/
void registerObserver(INetworkManagementEventObserver obs);
@@ -45,6 +46,11 @@ interface INetworkManagementService
*/
void unregisterObserver(INetworkManagementEventObserver obs);
+ /**
+ * Retrieve an INetd to talk to netd.
+ */
+ INetd getNetdService();
+
/**
* Returns a list of currently known network interfaces
*/
@@ -446,6 +452,7 @@ interface INetworkManagementService
void addInterfaceToLocalNetwork(String iface, in List routes);
void removeInterfaceFromLocalNetwork(String iface);
+ int removeRoutesFromLocalNetwork(in List routes);
void setAllowOnlyVpnForUids(boolean enable, in UidRange[] uidRanges);
/**
diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl
index b27cb32bd4eb6216834c2593762361bb01ad2f6f..eeb641d33c20d4da561c1dc8f577e7b6e89b95a6 100644
--- a/core/java/android/os/IUserManager.aidl
+++ b/core/java/android/os/IUserManager.aidl
@@ -81,4 +81,5 @@ interface IUserManager {
void clearSeedAccountData();
boolean someUserHasSeedAccount(in String accountName, in String accountType);
boolean isManagedProfile(int userId);
+ boolean isDemoUser(int userId);
}
diff --git a/core/java/android/os/Looper.java b/core/java/android/os/Looper.java
index b58ff1fd4755afd2913763fede2d7f944ccf2637..d299672ea1d5e15b3d7375d888595c4e0a774435 100644
--- a/core/java/android/os/Looper.java
+++ b/core/java/android/os/Looper.java
@@ -147,7 +147,7 @@ public final class Looper {
}
final long traceTag = me.mTraceTag;
- if (traceTag != 0) {
+ if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
}
try {
diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java
index 74dcc0787b3bd91ed1009cd1bad48465c8a565df..f6e6ad6067bb0bae21b2aed51ac111e489e19f3e 100644
--- a/core/java/android/os/Parcel.java
+++ b/core/java/android/os/Parcel.java
@@ -36,6 +36,7 @@ import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.ObjectStreamClass;
import java.io.Serializable;
+import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
@@ -2571,6 +2572,20 @@ public final class Parcel {
return p;
}
+ /** @hide */
+ public final T[] readParcelableArray(ClassLoader loader,
+ Class clazz) {
+ int N = readInt();
+ if (N < 0) {
+ return null;
+ }
+ T[] p = (T[]) Array.newInstance(clazz, N);
+ for (int i = 0; i < N; i++) {
+ p[i] = readParcelable(loader);
+ }
+ return p;
+ }
+
/**
* Read and return a new Serializable object from the parcel.
* @return the Serializable object, or null if the Serializable name
diff --git a/core/java/android/os/PowerManagerInternal.java b/core/java/android/os/PowerManagerInternal.java
index 8104c69803fa3538afa8761bcc356aeabb5082d5..bbafb5662cd64de10655b6a4dd38bcf6e8b59973 100644
--- a/core/java/android/os/PowerManagerInternal.java
+++ b/core/java/android/os/PowerManagerInternal.java
@@ -57,14 +57,19 @@ public abstract class PowerManagerInternal {
/**
* Power hint:
* Interaction: The user is interacting with the device. The corresponding data field must be
- * the expected duration of the fling, or 0 if unknown.
+ * the expected duration of the interaction, or 0 if unknown.
*
- * Sustained Performance Mode: Enable/Disables Sustained Performance Mode.
+ * Sustained Performance Mode: The corresponding data field must be Enable/Disable
+ * Sustained Performance Mode.
+ *
+ * Launch: This is specific for activity launching. The corresponding data field must be
+ * the expected duration of the required boost, or 0 if unknown.
*
* These must be kept in sync with the values in hardware/libhardware/include/hardware/power.h
*/
public static final int POWER_HINT_INTERACTION = 2;
public static final int POWER_HINT_SUSTAINED_PERFORMANCE_MODE = 6;
+ public static final int POWER_HINT_LAUNCH = 8;
public static String wakefulnessToString(int wakefulness) {
switch (wakefulness) {
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index 21b3f6ed4582e3bffde05bc46e1cde4ae88fd9f4..e1b7fdad25e7dff4f30f3c9ca725e2ac36ae700e 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -16,9 +16,11 @@
package android.os;
+import android.annotation.TestApi;
import android.net.LocalSocket;
import android.net.LocalSocketAddress;
import android.system.Os;
+import android.system.OsConstants;
import android.util.Log;
import com.android.internal.os.Zygote;
import dalvik.system.VMRuntime;
@@ -322,6 +324,12 @@ public class Process {
*/
public static final int SCHED_IDLE = 5;
+ /**
+ * Reset scheduler choice on fork.
+ * @hide
+ */
+ public static final int SCHED_RESET_ON_FORK = 0x40000000;
+
// Keep in sync with SP_* constants of enum type SchedPolicy
// declared in system/core/include/cutils/sched_policy.h,
// except THREAD_GROUP_DEFAULT does not correspond to any SP_* value.
@@ -973,6 +981,9 @@ public class Process {
* priority.
* If the thread is a thread group leader, that is it's gettid() == getpid(),
* then the other threads in the same thread group are _not_ affected.
+ *
+ * Does not set cpuset for some historical reason, just calls
+ * libcutils::set_sched_policy().
*/
public static final native void setThreadGroup(int tid, int group)
throws IllegalArgumentException, SecurityException;
@@ -994,6 +1005,8 @@ public class Process {
* priority threads alone. group == THREAD_GROUP_BG_NONINTERACTIVE moves all
* threads, regardless of priority, to the background scheduling group.
* group == THREAD_GROUP_FOREGROUND is not allowed.
+ *
+ * Always sets cpusets.
*/
public static final native void setProcessGroup(int pid, int group)
throws IllegalArgumentException, SecurityException;
@@ -1064,6 +1077,24 @@ public class Process {
public static final native int getThreadPriority(int tid)
throws IllegalArgumentException;
+ /**
+ * Return the current scheduling policy of a thread, based on Linux.
+ *
+ * @param tid The identifier of the thread/process to get the scheduling policy.
+ *
+ * @throws IllegalArgumentException Throws IllegalArgumentException if
+ * tid does not exist, or if priority is out of range for the policy.
+ * @throws SecurityException Throws SecurityException if your process does
+ * not have permission to modify the given thread, or to use the given
+ * scheduling policy or priority.
+ *
+ * {@hide}
+ */
+
+ @TestApi
+ public static final native int getThreadScheduler(int tid)
+ throws IllegalArgumentException;
+
/**
* Set the scheduling policy and priority of a thread, based on Linux.
*
@@ -1079,6 +1110,7 @@ public class Process {
*
* {@hide}
*/
+
public static final native void setThreadScheduler(int tid, int policy, int priority)
throws IllegalArgumentException;
@@ -1252,4 +1284,26 @@ public class Process {
* @hide
*/
public static final native void removeAllProcessGroups();
+
+ /**
+ * Check to see if a thread belongs to a given process. This may require
+ * more permissions than apps generally have.
+ * @return true if this thread belongs to a process
+ * @hide
+ */
+ public static final boolean isThreadInProcess(int tid, int pid) {
+ StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
+ try {
+ if (Os.access("/proc/" + tid + "/task/" + pid, OsConstants.F_OK)) {
+ return true;
+ } else {
+ return false;
+ }
+ } catch (Exception e) {
+ return false;
+ } finally {
+ StrictMode.setThreadPolicy(oldPolicy);
+ }
+
+ }
}
diff --git a/core/java/android/os/RecoverySystem.java b/core/java/android/os/RecoverySystem.java
index dd7be53d98659c9fe7de4452a082db07d0dec567..507379baaa9495874a98d0640e0437dc8a54a180 100644
--- a/core/java/android/os/RecoverySystem.java
+++ b/core/java/android/os/RecoverySystem.java
@@ -570,18 +570,19 @@ public class RecoverySystem {
* @throws SecurityException if the current user is not allowed to wipe data.
*/
public static void rebootWipeUserData(Context context) throws IOException {
- rebootWipeUserData(context, false, context.getPackageName());
+ rebootWipeUserData(context, false /* shutdown */, context.getPackageName(),
+ false /* force */);
}
/** {@hide} */
public static void rebootWipeUserData(Context context, String reason) throws IOException {
- rebootWipeUserData(context, false, reason);
+ rebootWipeUserData(context, false /* shutdown */, reason, false /* force */);
}
/** {@hide} */
public static void rebootWipeUserData(Context context, boolean shutdown)
throws IOException {
- rebootWipeUserData(context, shutdown, context.getPackageName());
+ rebootWipeUserData(context, shutdown, context.getPackageName(), false /* force */);
}
/**
@@ -595,6 +596,9 @@ public class RecoverySystem {
* @param shutdown if true, the device will be powered down after
* the wipe completes, rather than being rebooted
* back to the regular system.
+ * @param reason the reason for the wipe that is visible in the logs
+ * @param force whether the {@link UserManager.DISALLOW_FACTORY_RESET} user restriction
+ * should be ignored
*
* @throws IOException if writing the recovery command file
* fails, or if the reboot itself fails.
@@ -602,10 +606,10 @@ public class RecoverySystem {
*
* @hide
*/
- public static void rebootWipeUserData(Context context, boolean shutdown, String reason)
- throws IOException {
+ public static void rebootWipeUserData(Context context, boolean shutdown, String reason,
+ boolean force) throws IOException {
UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE);
- if (um.hasUserRestriction(UserManager.DISALLOW_FACTORY_RESET)) {
+ if (!force && um.hasUserRestriction(UserManager.DISALLOW_FACTORY_RESET)) {
throw new SecurityException("Wiping data is not allowed for this user.");
}
final ConditionVariable condition = new ConditionVariable();
@@ -657,6 +661,31 @@ public class RecoverySystem {
bootCommand(context, "--wipe_cache", reasonArg, localeArg);
}
+ /**
+ * Reboot into recovery and wipe the A/B device.
+ *
+ * @param Context the Context to use.
+ * @param packageFile the wipe package to be applied.
+ * @param reason the reason to wipe.
+ *
+ * @throws IOException if something goes wrong.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static void rebootWipeAb(Context context, File packageFile, String reason)
+ throws IOException {
+ String reasonArg = null;
+ if (!TextUtils.isEmpty(reason)) {
+ reasonArg = "--reason=" + sanitizeArg(reason);
+ }
+
+ final String filename = packageFile.getCanonicalPath();
+ final String filenameArg = "--wipe_package=" + filename;
+ final String localeArg = "--locale=" + Locale.getDefault().toString();
+ bootCommand(context, "--wipe_ab", filenameArg, reasonArg, localeArg);
+ }
+
/**
* Reboot into the recovery system with the supplied argument.
* @param args to pass to the recovery utility.
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 388403809d66159436411cc9023fa15918b34c5f..9e778cf36970e8536992c71cf9e8daea3015a71c 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -580,6 +580,16 @@ public class UserManager {
*/
public static final String DISALLOW_CAMERA = "no_camera";
+ /**
+ * Specifies if a user is not allowed to unmute the device's master volume.
+ *
+ * @see DevicePolicyManager#setMasterVolumeMuted(ComponentName, boolean)
+ * @see DevicePolicyManager#clearUserRestriction(ComponentName, String)
+ * @see #getUserRestrictions()
+ * @hide
+ */
+ public static final String DISALLLOW_UNMUTE_DEVICE = "disallow_unmute_device";
+
/**
* Specifies if a user is not allowed to use cellular data when roaming. This can only be set by
* device owners. The default value is false.
@@ -603,6 +613,18 @@ public class UserManager {
*/
public static final String DISALLOW_SET_USER_ICON = "no_set_user_icon";
+ /**
+ * Specifies if a user is not allowed to enable the oem unlock setting. The default value is
+ * false. Setting this restriction has no effect if the bootloader is already
+ * unlocked.
+ *
+ * @see DevicePolicyManager#addUserRestriction(ComponentName, String)
+ * @see DevicePolicyManager#clearUserRestriction(ComponentName, String)
+ * @see #getUserRestrictions()
+ * @hide
+ */
+ public static final String DISALLOW_OEM_UNLOCK = "no_oem_unlock";
+
/**
* Allows apps in the parent profile to handle web links from the managed profile.
*
@@ -802,7 +824,7 @@ public class UserManager {
*/
public boolean isPrimaryUser() {
UserInfo user = getUserInfo(UserHandle.myUserId());
- return user != null ? user.isPrimary() : false;
+ return user != null && user.isPrimary();
}
/**
@@ -868,7 +890,21 @@ public class UserManager {
*/
public boolean isGuestUser() {
UserInfo user = getUserInfo(UserHandle.myUserId());
- return user != null ? user.isGuest() : false;
+ return user != null && user.isGuest();
+ }
+
+ /**
+ * Checks if the calling app is running in a demo user. When running in a demo user,
+ * apps can be more helpful to the user, or explain their features in more detail.
+ *
+ * @return whether the caller is a demo user.
+ */
+ public boolean isDemoUser() {
+ try {
+ return mService.isDemoUser(UserHandle.myUserId());
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
}
/**
@@ -1988,6 +2024,10 @@ public class UserManager {
if (!supportsMultipleUsers()) {
return false;
}
+ // If Demo Mode is on, don't show user switcher
+ if (isDeviceInDemoMode(mContext)) {
+ return false;
+ }
List users = getUsers(true);
if (users == null) {
return false;
@@ -2003,6 +2043,14 @@ public class UserManager {
return switchableUserCount > 1 || guestEnabled;
}
+ /**
+ * @hide
+ */
+ public static boolean isDeviceInDemoMode(Context context) {
+ return Settings.Global.getInt(context.getContentResolver(),
+ Settings.Global.DEVICE_DEMO_MODE, 0) > 0;
+ }
+
/**
* Returns a serial number on this device for a given userHandle. User handles can be recycled
* when deleting and creating users, but serial numbers are not reused until the device is wiped.
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 485bbd105603b23790a507fec5ce4f24f40f3e62..c5507b9841bc6b2694ff885dc1350a9db7d5d988 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -20,6 +20,7 @@ import static android.net.TrafficStats.MB_IN_BYTES;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.SdkConstant;
import android.app.ActivityThread;
import android.content.ContentResolver;
import android.content.Context;
@@ -45,8 +46,11 @@ import android.util.SparseArray;
import com.android.internal.os.SomeArgs;
import com.android.internal.util.Preconditions;
+import java.io.BufferedReader;
import java.io.File;
+import java.io.FileInputStream;
import java.io.IOException;
+import java.io.InputStreamReader;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Arrays;
@@ -92,6 +96,19 @@ public class StorageManager {
/** {@hide} */
public static final String UUID_PRIMARY_PHYSICAL = "primary_physical";
+
+ /**
+ * Activity Action: Allows the user to manage their storage. This activity provides the ability
+ * to free up space on the device by deleting data such as apps.
+ *
+ * Input: Nothing.
+ *
+ * Output: Nothing.
+ */
+ @SdkConstant(SdkConstant.SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_MANAGE_STORAGE
+ = "android.os.storage.action.MANAGE_STORAGE";
+
/** {@hide} */
public static final int DEBUG_FORCE_ADOPTABLE = 1 << 0;
/** {@hide} */
@@ -116,6 +133,15 @@ public class StorageManager {
private static volatile IMountService sMountService = null;
+ // TODO: the location of the primary storage block varies from device to device, so we need to
+ // try the most likely candidates - a long-term solution would be a device-specific vold
+ // function that returns the calculated size.
+ private static final String[] INTERNAL_STORAGE_SIZE_PATHS = {
+ "/sys/block/mmcblk0/size",
+ "/sys/block/sda/size"
+ };
+ private static final int INTERNAL_STORAGE_SECTOR_SIZE = 512;
+
private final Context mContext;
private final ContentResolver mResolver;
@@ -903,6 +929,27 @@ public class StorageManager {
return getVolumeList(UserHandle.myUserId(), FLAG_REAL_STATE | FLAG_INCLUDE_INVISIBLE)[0];
}
+ /** {@hide} */
+ public long getPrimaryStorageSize() {
+ for (String path : INTERNAL_STORAGE_SIZE_PATHS) {
+ final long numberBlocks = readLong(path);
+ if (numberBlocks > 0) {
+ return numberBlocks * INTERNAL_STORAGE_SECTOR_SIZE;
+ }
+ }
+ return 0;
+ }
+
+ private long readLong(String path) {
+ try (final FileInputStream fis = new FileInputStream(path);
+ final BufferedReader reader = new BufferedReader(new InputStreamReader(fis));) {
+ return Long.parseLong(reader.readLine());
+ } catch (Exception e) {
+ Slog.w(TAG, "Could not read " + path, e);
+ return 0;
+ }
+ }
+
/** @removed */
public @NonNull StorageVolume[] getVolumeList() {
return getVolumeList(mContext.getUserId(), 0);
diff --git a/core/java/android/preference/PreferenceFragment.java b/core/java/android/preference/PreferenceFragment.java
index 3e496b6eb550b9bd7630961e9967cd8ae843c3d9..73fa01e592011cca5bb4686bec29ce51ff02ed5a 100644
--- a/core/java/android/preference/PreferenceFragment.java
+++ b/core/java/android/preference/PreferenceFragment.java
@@ -27,12 +27,14 @@ import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
+import android.text.TextUtils;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnKeyListener;
import android.view.ViewGroup;
import android.widget.ListView;
+import android.widget.TextView;
/**
* Shows a hierarchy of {@link Preference} objects as
@@ -189,12 +191,10 @@ public abstract class PreferenceFragment extends Fragment implements
0);
ListView lv = (ListView) view.findViewById(android.R.id.list);
- if (lv != null) {
- Drawable divider =
- a.getDrawable(com.android.internal.R.styleable.PreferenceFragment_divider);
- if (divider != null) {
- lv.setDivider(divider);
- }
+ if (lv != null
+ && a.hasValueOrEmpty(com.android.internal.R.styleable.PreferenceFragment_divider)) {
+ lv.setDivider(
+ a.getDrawable(com.android.internal.R.styleable.PreferenceFragment_divider));
}
a.recycle();
@@ -368,6 +368,20 @@ public abstract class PreferenceFragment extends Fragment implements
private void bindPreferences() {
final PreferenceScreen preferenceScreen = getPreferenceScreen();
if (preferenceScreen != null) {
+ View root = getView();
+ if (root != null) {
+ View titleView = root.findViewById(android.R.id.title);
+ if (titleView instanceof TextView) {
+ CharSequence title = preferenceScreen.getTitle();
+ if (TextUtils.isEmpty(title)) {
+ titleView.setVisibility(View.GONE);
+ } else {
+ ((TextView) titleView).setText(title);
+ titleView.setVisibility(View.VISIBLE);
+ }
+ }
+ }
+
preferenceScreen.bind(getListView());
}
onBindPreferences();
diff --git a/core/java/android/preference/PreferenceScreen.java b/core/java/android/preference/PreferenceScreen.java
index b1317e656e3e4287d5cfe8b2618846d176d66b18..2305b0564e4995033ab4de326e8e81e2338af83a 100644
--- a/core/java/android/preference/PreferenceScreen.java
+++ b/core/java/android/preference/PreferenceScreen.java
@@ -19,6 +19,8 @@ package android.preference;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
+import android.content.res.TypedArray;
+import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
@@ -31,6 +33,7 @@ import android.widget.Adapter;
import android.widget.AdapterView;
import android.widget.ListAdapter;
import android.widget.ListView;
+import android.widget.TextView;
/**
* Represents a top-level {@link Preference} that
@@ -91,13 +94,33 @@ public final class PreferenceScreen extends PreferenceGroup implements AdapterVi
private Dialog mDialog;
private ListView mListView;
-
+
+ private int mLayoutResId = com.android.internal.R.layout.preference_list_fragment;
+ private Drawable mDividerDrawable;
+ private boolean mDividerSpecified;
+
/**
* Do NOT use this constructor, use {@link PreferenceManager#createPreferenceScreen(Context)}.
* @hide-
*/
public PreferenceScreen(Context context, AttributeSet attrs) {
super(context, attrs, com.android.internal.R.attr.preferenceScreenStyle);
+
+ TypedArray a = context.obtainStyledAttributes(null,
+ com.android.internal.R.styleable.PreferenceScreen,
+ com.android.internal.R.attr.preferenceScreenStyle,
+ 0);
+
+ mLayoutResId = a.getResourceId(
+ com.android.internal.R.styleable.PreferenceScreen_screenLayout,
+ mLayoutResId);
+ if (a.hasValueOrEmpty(com.android.internal.R.styleable.PreferenceScreen_divider)) {
+ mDividerDrawable =
+ a.getDrawable(com.android.internal.R.styleable.PreferenceScreen_divider);
+ mDividerSpecified = true;
+ }
+
+ a.recycle();
}
/**
@@ -163,18 +186,30 @@ public final class PreferenceScreen extends PreferenceGroup implements AdapterVi
LayoutInflater inflater = (LayoutInflater)
context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- View childPrefScreen = inflater.inflate(
- com.android.internal.R.layout.preference_list_fragment, null);
+ View childPrefScreen = inflater.inflate(mLayoutResId, null);
+ View titleView = childPrefScreen.findViewById(android.R.id.title);
mListView = (ListView) childPrefScreen.findViewById(android.R.id.list);
+ if (mDividerSpecified) {
+ mListView.setDivider(mDividerDrawable);
+ }
+
bind(mListView);
// Set the title bar if title is available, else no title bar
final CharSequence title = getTitle();
Dialog dialog = mDialog = new Dialog(context, context.getThemeResId());
if (TextUtils.isEmpty(title)) {
+ if (titleView != null) {
+ titleView.setVisibility(View.GONE);
+ }
dialog.getWindow().requestFeature(Window.FEATURE_NO_TITLE);
} else {
- dialog.setTitle(title);
+ if (titleView instanceof TextView) {
+ ((TextView) titleView).setText(title);
+ titleView.setVisibility(View.VISIBLE);
+ } else {
+ dialog.setTitle(title);
+ }
}
dialog.setContentView(childPrefScreen);
dialog.setOnDismissListener(this);
diff --git a/core/java/android/print/PrintServiceRecommendationsLoader.java b/core/java/android/print/PrintServiceRecommendationsLoader.java
index bb5d065c6430e59aa98ff47dcded0f03eb9e3d95..c6a4d5103a479f764b9f4137c6374641f9d4d73a 100644
--- a/core/java/android/print/PrintServiceRecommendationsLoader.java
+++ b/core/java/android/print/PrintServiceRecommendationsLoader.java
@@ -36,7 +36,7 @@ public class PrintServiceRecommendationsLoader extends Loader> {
private final @NonNull PrintManager mPrintManager;
/** Handler to sequentialize the delivery of the results to the main thread */
- private Handler mHandler;
+ private final @NonNull Handler mHandler;
/** Listens for updates to the data from the platform */
private PrintManager.PrintServicesChangeListener mListener;
@@ -54,6 +54,7 @@ public class PrintServicesLoader extends Loader> {
public PrintServicesLoader(@NonNull PrintManager printManager, @NonNull Context context,
int selectionFlags) {
super(Preconditions.checkNotNull(context));
+ mHandler = new MyHandler();
mPrintManager = Preconditions.checkNotNull(printManager);
mSelectionFlags = Preconditions.checkFlagsArgument(selectionFlags,
PrintManager.ALL_SERVICES);
@@ -75,7 +76,6 @@ public class PrintServicesLoader extends Loader> {
@Override
protected void onStartLoading() {
- mHandler = new MyHandler();
mListener = new PrintManager.PrintServicesChangeListener() {
@Override public void onPrintServicesChanged() {
queueNewResult();
@@ -95,10 +95,7 @@ public class PrintServicesLoader extends Loader> {
mListener = null;
}
- if (mHandler != null) {
- mHandler.removeMessages(0);
- mHandler = null;
- }
+ mHandler.removeMessages(0);
}
@Override
@@ -119,8 +116,6 @@ public class PrintServicesLoader extends Loader> {
@Override
public void handleMessage(Message msg) {
- super.handleMessage(msg);
-
if (isStarted()) {
deliverResult((List) msg.obj);
}
diff --git a/core/java/android/provider/CallLog.java b/core/java/android/provider/CallLog.java
index ee0db27ce66fa20c94b6c95112df017a9fd8841d..26e59ad839ffaf14d9108185f58721aa7920f6c4 100644
--- a/core/java/android/provider/CallLog.java
+++ b/core/java/android/provider/CallLog.java
@@ -179,6 +179,7 @@ public class CallLog {
*
{@link #VOICEMAIL_TYPE}
*
{@link #REJECTED_TYPE}
*
{@link #BLOCKED_TYPE}
+ *
{@link #ANSWERED_EXTERNALLY_TYPE}
*
*
*/
@@ -200,7 +201,6 @@ public class CallLog {
* Call log type for a call which was answered on another device. Used in situations where
* a call rings on multiple devices simultaneously and it ended up being answered on a
* device other than the current one.
- * @hide
*/
public static final int ANSWERED_EXTERNALLY_TYPE = 7;
@@ -234,10 +234,7 @@ public class CallLog {
/** Call had video. */
public static final int FEATURES_VIDEO = 0x1;
- /**
- * Call was pulled externally.
- * @hide
- */
+ /** Call was pulled externally. */
public static final int FEATURES_PULLED_EXTERNALLY = 0x2;
/**
diff --git a/core/java/android/provider/DocumentsContract.java b/core/java/android/provider/DocumentsContract.java
index 1158776f5fd1715af3f3399bd83039a85eabc7df..d587ba80a18c7dbfddfcbb2cf740af00d4a77452 100644
--- a/core/java/android/provider/DocumentsContract.java
+++ b/core/java/android/provider/DocumentsContract.java
@@ -235,7 +235,6 @@ public final class DocumentsContract {
* @see #FLAG_DIR_PREFERS_GRID
* @see #FLAG_DIR_PREFERS_LAST_MODIFIED
* @see #FLAG_VIRTUAL_DOCUMENT
- * @see #FLAG_ARCHIVE
* @see #FLAG_SUPPORTS_COPY
* @see #FLAG_SUPPORTS_MOVE
* @see #FLAG_SUPPORTS_REMOVE
@@ -326,7 +325,7 @@ public final class DocumentsContract {
* Flag indicating that a document can be renamed.
*
* @see #COLUMN_FLAGS
- * @see DocumentsContract#renameDocument(ContentProviderClient, Uri,
+ * @see DocumentsContract#renameDocument(ContentResolver, Uri,
* String)
* @see DocumentsProvider#renameDocument(String, String)
*/
@@ -337,7 +336,7 @@ public final class DocumentsContract {
* within the same document provider.
*
* @see #COLUMN_FLAGS
- * @see DocumentsContract#copyDocument(ContentProviderClient, Uri, Uri)
+ * @see DocumentsContract#copyDocument(ContentResolver, Uri, Uri)
* @see DocumentsProvider#copyDocument(String, String)
*/
public static final int FLAG_SUPPORTS_COPY = 1 << 7;
@@ -347,7 +346,7 @@ public final class DocumentsContract {
* within the same document provider.
*
* @see #COLUMN_FLAGS
- * @see DocumentsContract#moveDocument(ContentProviderClient, Uri, Uri, Uri)
+ * @see DocumentsContract#moveDocument(ContentResolver, Uri, Uri, Uri)
* @see DocumentsProvider#moveDocument(String, String, String)
*/
public static final int FLAG_SUPPORTS_MOVE = 1 << 8;
@@ -368,7 +367,7 @@ public final class DocumentsContract {
* Flag indicating that a document can be removed from a parent.
*
* @see #COLUMN_FLAGS
- * @see DocumentsContract#removeDocument(ContentProviderClient, Uri, Uri)
+ * @see DocumentsContract#removeDocument(ContentResolver, Uri, Uri)
* @see DocumentsProvider#removeDocument(String, String)
*/
public static final int FLAG_SUPPORTS_REMOVE = 1 << 10;
@@ -870,7 +869,7 @@ public final class DocumentsContract {
* Test if the given URI represents a {@link Document} tree.
*
* @see #buildTreeDocumentUri(String, String)
- * @see #getTreeDocumentId(Uri, String)
+ * @see #getTreeDocumentId(Uri)
*/
public static boolean isTreeUri(Uri uri) {
final List paths = uri.getPathSegments();
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 30e53f0dc76c1e09c9096daadeb9941c26216855..0645dd8af678d4d63dc3687a6e385c8e9f742fc7 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -442,6 +442,22 @@ public final class Settings {
public static final String ACTION_DISPLAY_SETTINGS =
"android.settings.DISPLAY_SETTINGS";
+ /**
+ * Activity Action: Show settings to allow configuration of Night display.
+ *
+ * In some cases, a matching Activity may not exist, so ensure you
+ * safeguard against this.
+ *
+ * Input: Nothing.
+ *
+ * Output: Nothing.
+ *
+ * @hide
+ */
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_NIGHT_DISPLAY_SETTINGS =
+ "android.settings.NIGHT_DISPLAY_SETTINGS";
+
/**
* Activity Action: Show settings to allow configuration of locale.
*
@@ -5478,15 +5494,6 @@ public final class Settings {
public static final String ACCESSIBILITY_DISPLAY_DALTONIZER =
"accessibility_display_daltonizer";
- /**
- * Float list that specifies the color matrix to apply to
- * the display. Valid values are defined in AccessibilityManager.
- *
- * @hide
- */
- public static final String ACCESSIBILITY_DISPLAY_COLOR_MATRIX =
- "accessibility_display_color_matrix";
-
/**
* Setting that specifies whether automatic click when the mouse pointer stops moving is
* enabled.
@@ -6195,6 +6202,17 @@ public final class Settings {
*/
public static final String ASSIST_SCREENSHOT_ENABLED = "assist_screenshot_enabled";
+ /**
+ * Specifies whether the screen will show an animation if screen contents are sent to the
+ * assist application (active voice interaction service).
+ *
+ * Note that the disclosure will be forced for third-party assistants or if the device
+ * does not support disabling it.
+ *
+ * @hide
+ */
+ public static final String ASSIST_DISCLOSURE_ENABLED = "assist_disclosure_enabled";
+
/**
* Names of the service components that the current user has explicitly allowed to
* see all of the user's notifications, separated by ':'.
@@ -6336,42 +6354,39 @@ public final class Settings {
"camera_double_tap_power_gesture_disabled";
/**
- * Behavior of twilight on the device.
- * One of {@link #TWILIGHT_MODE_LOCKED_OFF}, {@link #TWILIGHT_MODE_LOCKED_ON}
- * or {@link #TWILIGHT_MODE_AUTO}.
- * @hide
- */
- public static final String TWILIGHT_MODE = "twilight_mode";
-
- /**
- * Twilight mode always off.
+ * Whether the camera double twist gesture to flip between front and back mode should be
+ * enabled.
+ *
* @hide
*/
- public static final int TWILIGHT_MODE_LOCKED_OFF = 0;
+ public static final String CAMERA_DOUBLE_TWIST_TO_FLIP_ENABLED =
+ "camera_double_twist_to_flip_enabled";
/**
- * Twilight mode always on.
+ * Control whether Night display is currently activated.
* @hide
*/
- public static final int TWILIGHT_MODE_LOCKED_ON = 1;
+ public static final String NIGHT_DISPLAY_ACTIVATED = "night_display_activated";
/**
- * Twilight mode auto.
+ * Control whether Night display will automatically activate/deactivate.
* @hide
*/
- public static final int TWILIGHT_MODE_AUTO = 2;
+ public static final String NIGHT_DISPLAY_AUTO_MODE = "night_display_auto_mode";
/**
- * Twilight mode auto, temporarily overriden to on.
+ * Custom time when Night display is scheduled to activate.
+ * Represented as milliseconds from midnight (e.g. 79200000 == 10pm).
* @hide
*/
- public static final int TWILIGHT_MODE_AUTO_OVERRIDE_OFF = 3;
+ public static final String NIGHT_DISPLAY_CUSTOM_START_TIME = "night_display_custom_start_time";
/**
- * Twilight mode auto, temporarily overriden to off.
+ * Custom time when Night display is scheduled to deactivate.
+ * Represented as milliseconds from midnight (e.g. 21600000 == 6am).
* @hide
*/
- public static final int TWILIGHT_MODE_AUTO_OVERRIDE_ON = 4;
+ public static final String NIGHT_DISPLAY_CUSTOM_END_TIME = "night_display_custom_end_time";
/**
* Whether brightness should automatically adjust based on twilight state.
@@ -6414,6 +6429,20 @@ public final class Settings {
*/
public static final int VR_DISPLAY_MODE_OFF = 1;
+ /**
+ * Whether CarrierAppUtils#disableCarrierAppsUntilPrivileged has been executed at least
+ * once.
+ *
+ *
This is used to ensure that we only take one pass which will disable apps that are not
+ * privileged (if any). From then on, we only want to enable apps (when a matching SIM is
+ * inserted), to avoid disabling an app that the user might actively be using.
+ *
+ *
Will be set to 1 once executed.
+ *
+ * @hide
+ */
+ public static final String CARRIER_APPS_HANDLED = "carrier_apps_handled";
+
/**
* Whether parent user can access remote contact in managed profile.
*
@@ -6434,12 +6463,67 @@ public final class Settings {
*/
public static final String VOLUME_LINK_NOTIFICATION = "volume_link_notification";
+ /**
+ * Whether or not the automatic storage manager is enabled and should run on the device.
+ *
+ * @hide
+ */
+ public static final String AUTOMATIC_STORAGE_MANAGER_ENABLED =
+ "automatic_storage_manager_enabled";
+
+ /**
+ * How many days of information for the automatic storage manager to retain on the device.
+ *
+ * @hide
+ */
+ public static final String AUTOMATIC_STORAGE_MANAGER_DAYS_TO_RETAIN =
+ "automatic_storage_manager_days_to_retain";
+
+ /**
+ * Default number of days of information for the automatic storage manager to retain.
+ *
+ * @hide
+ */
+ public static final int AUTOMATIC_STORAGE_MANAGER_DAYS_TO_RETAIN_DEFAULT = 90;
+
+ /**
+ * How many bytes the automatic storage manager has cleared out.
+ *
+ * @hide
+ */
+ public static final String AUTOMATIC_STORAGE_MANAGER_BYTES_CLEARED =
+ "automatic_storage_manager_bytes_cleared";
+
+
+ /**
+ * Last run time for the automatic storage manager.
+ *
+ * @hide
+ */
+ public static final String AUTOMATIC_STORAGE_MANAGER_LAST_RUN =
+ "automatic_storage_manager_last_run";
+
+
+ /**
+ * Whether SystemUI navigation keys is enabled.
+ * @hide
+ */
+ public static final String SYSTEM_NAVIGATION_KEYS_ENABLED =
+ "system_navigation_keys_enabled";
+
/**
* Holds comma separated list of ordering of QS tiles.
* @hide
*/
public static final String QS_TILES = "sysui_qs_tiles";
+ /**
+ * Whether preloaded APKs have been installed for the user.
+ * @hide
+ */
+ public static final String DEMO_USER_SETUP_COMPLETE
+ = "demo_user_setup_complete";
+
/**
* This are the settings to be backed up.
*
@@ -6457,7 +6541,6 @@ public final class Settings {
USB_MASS_STORAGE_ENABLED, // moved to global
ACCESSIBILITY_DISPLAY_INVERSION_ENABLED,
ACCESSIBILITY_DISPLAY_DALTONIZER,
- ACCESSIBILITY_DISPLAY_COLOR_MATRIX,
ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED,
ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED,
ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE,
@@ -6516,7 +6599,14 @@ public final class Settings {
INCALL_POWER_BUTTON_BEHAVIOR,
WIFI_DISCONNECT_DELAY_DURATION,
ADVANCED_REBOOT,
- QS_TILES
+ NIGHT_DISPLAY_CUSTOM_START_TIME,
+ NIGHT_DISPLAY_CUSTOM_END_TIME,
+ NIGHT_DISPLAY_AUTO_MODE,
+ NIGHT_DISPLAY_ACTIVATED,
+ CAMERA_DOUBLE_TWIST_TO_FLIP_ENABLED,
+ CAMERA_DOUBLE_TAP_POWER_GESTURE_DISABLED,
+ SYSTEM_NAVIGATION_KEYS_ENABLED,
+ QS_TILES,
};
/**
@@ -7532,27 +7622,54 @@ public final class Settings {
public static final String WEBVIEW_DATA_REDUCTION_PROXY_KEY =
"webview_data_reduction_proxy_key";
- /**
- * Whether or not the WebView fallback mechanism should be enabled.
- * 0=disabled, 1=enabled.
- * @hide
- */
- public static final String WEBVIEW_FALLBACK_LOGIC_ENABLED =
- "webview_fallback_logic_enabled";
+ /**
+ * Whether or not the WebView fallback mechanism should be enabled.
+ * 0=disabled, 1=enabled.
+ * @hide
+ */
+ public static final String WEBVIEW_FALLBACK_LOGIC_ENABLED =
+ "webview_fallback_logic_enabled";
- /**
- * Name of the package used as WebView provider (if unset the provider is instead determined
- * by the system).
- * @hide
- */
- public static final String WEBVIEW_PROVIDER = "webview_provider";
+ /**
+ * Name of the package used as WebView provider (if unset the provider is instead determined
+ * by the system).
+ * @hide
+ */
+ public static final String WEBVIEW_PROVIDER = "webview_provider";
- /**
- * Developer setting to enable WebView multiprocess rendering.
- * @hide
- */
- @SystemApi
- public static final String WEBVIEW_MULTIPROCESS = "webview_multiprocess";
+ /**
+ * Developer setting to enable WebView multiprocess rendering.
+ * @hide
+ */
+ @SystemApi
+ public static final String WEBVIEW_MULTIPROCESS = "webview_multiprocess";
+
+ /**
+ * The maximum number of notifications shown in 24 hours when switching networks.
+ * @hide
+ */
+ public static final String NETWORK_SWITCH_NOTIFICATION_DAILY_LIMIT =
+ "network_switch_notification_daily_limit";
+
+ /**
+ * The minimum time in milliseconds between notifications when switching networks.
+ * @hide
+ */
+ public static final String NETWORK_SWITCH_NOTIFICATION_RATE_LIMIT_MILLIS =
+ "network_switch_notification_rate_limit_millis";
+
+ /**
+ * Whether to automatically switch away from wifi networks that lose Internet access.
+ * Only meaningful if config_networkAvoidBadWifi is set to 0, otherwise the system always
+ * avoids such networks. Valid values are:
+ *
+ * 0: Don't avoid bad wifi, don't prompt the user. Get stuck on bad wifi like it's 2013.
+ * null: Ask the user whether to switch away from bad wifi.
+ * 1: Avoid bad wifi.
+ *
+ * @hide
+ */
+ public static final String NETWORK_AVOID_BAD_WIFI = "network_avoid_bad_wifi";
/**
* Whether Wifi display is enabled/disabled
@@ -8721,8 +8838,6 @@ public final class Settings {
/**
* The name of the device
- *
- * @hide
*/
public static final String DEVICE_NAME = "device_name";
@@ -8805,6 +8920,24 @@ public final class Settings {
public static final String EPHEMERAL_COOKIE_MAX_SIZE_BYTES =
"ephemeral_cookie_max_size_bytes";
+ /**
+ * A mask applied to the ephemeral hash to generate the hash prefix.
+ *
+ * Type: int
+ *
+ * @hide
+ */
+ public static final String EPHEMERAL_HASH_PREFIX_MASK = "ephemeral_hash_prefix_mask";
+
+ /**
+ * Number of hash prefixes to send during ephemeral resolution.
+ *
+ * Type: int
+ *
+ * @hide
+ */
+ public static final String EPHEMERAL_HASH_PREFIX_COUNT = "ephemeral_hash_prefix_count";
+
/**
* The duration for caching uninstalled ephemeral apps.
*
@@ -8840,6 +8973,31 @@ public final class Settings {
*/
public static final String SAFE_BOOT_DISALLOWED = "safe_boot_disallowed";
+ /**
+ * Whether this device is currently in retail demo mode. If true, device
+ * usage is severely limited.
+ *
+ * Type: int (0 for false, 1 for true)
+ * @hide
+ */
+ public static final String DEVICE_DEMO_MODE = "device_demo_mode";
+
+ /**
+ * Retail mode specific settings. This is encoded as a key=value list, separated by commas.
+ * Ex: "user_inactivity_timeout_ms=30000,warning_dialog_timeout_ms=10000". The following
+ * keys are supported:
+ *
+ *
+ * Type: string
+ *
+ * @hide
+ */
+ public static final String RETAIL_DEMO_MODE_CONSTANTS = "retail_demo_mode_constants";
+
/**
* Settings to backup. This is here so that it's in the same place as the settings
* keys and easy to update.
@@ -9290,6 +9448,12 @@ public final class Settings {
* @hide
*/
public static final String MAX_NOTIFICATION_ENQUEUE_RATE = "max_notification_enqueue_rate";
+
+ /**
+ * Whether cell is enabled/disabled
+ * @hide
+ */
+ public static final String CELL_ON = "cell_on";
}
/**
diff --git a/core/java/android/provider/VoicemailContract.java b/core/java/android/provider/VoicemailContract.java
index 6a3cc0205f1812873336dbf08d29e180fb8e932e..5099eebf6eb1600000495e4ee17c6115f6282214 100644
--- a/core/java/android/provider/VoicemailContract.java
+++ b/core/java/android/provider/VoicemailContract.java
@@ -25,13 +25,11 @@ import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.database.ContentObserver;
-import android.database.Cursor;
import android.net.Uri;
import android.provider.CallLog.Calls;
import android.telecom.PhoneAccount;
import android.telecom.PhoneAccountHandle;
import android.telecom.Voicemail;
-
import java.util.List;
/**
@@ -106,12 +104,74 @@ public class VoicemailContract {
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_SYNC_VOICEMAIL = "android.provider.action.SYNC_VOICEMAIL";
+ /**
+ * Broadcast intent to inform a new visual voicemail SMS has been received. This intent will
+ * only be delivered to the voicemail client. The intent will have the following extra values:
+ *
+ *
+ *
{@link #EXTRA_VOICEMAIL_SMS_TYPE} - (String) The event type of the SMS. Common
+ * values are "SYNC" or "STATUS"
+ *
{@link #EXTRA_VOICEMAIL_SMS_DATA} - (Bundle) The fields sent by the SMS
+ *
{@link #EXTRA_VOICEMAIL_SMS_SUBID} - (Integer) The subscription ID of the
+ * phone account that received the SMS
+ *
+ */
+ /** @hide */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_VOICEMAIL_SMS_RECEIVED =
+ "android.intent.action.VOICEMAIL_SMS_RECEIVED";
+
+ /**
+ * Optional extra included in {@link #ACTION_VOICEMAIL_SMS_RECEIVED} broadcast intents to
+ * indicate the event type of the SMS. Common values are "SYNC" or "STATUS". The extra will not
+ * exist if the framework cannot parse the SMS as voicemail but the carrier pattern indicates
+ * it is.
+ */
+ /** @hide */
+ public static final String EXTRA_VOICEMAIL_SMS_PREFIX =
+ "com.android.voicemail.extra.VOICEMAIL_SMS_PREFIX";
+
+ /**
+ * Optional extra included in {@link #ACTION_VOICEMAIL_SMS_RECEIVED} broadcast intents to
+ * indicate the fields sent by the SMS. The extra will not exist if the framework cannot
+ * parse the SMS as voicemail but the carrier pattern indicates it is.
+ */
+ /** @hide */
+ public static final String EXTRA_VOICEMAIL_SMS_FIELDS =
+ "com.android.voicemail.extra.VOICEMAIL_SMS_FIELDS";
+
+ /**
+ * Extra included in {@link #ACTION_VOICEMAIL_SMS_RECEIVED} broadcast intents to indicate the
+ * message body of the SMS. This extra is included if the framework cannot
+ * parse the SMS as voicemail but the carrier pattern indicates it is.
+ */
+ /**
+ * @hide
+ */
+ public static final String EXTRA_VOICEMAIL_SMS_MESSAGE_BODY =
+ "com.android.voicemail.extra.VOICEMAIL_SMS_MESSAGE_BODY";
+
+ /**
+ * Extra included in {@link #ACTION_VOICEMAIL_SMS_RECEIVED} broadcast intents to indicate he
+ * subscription ID of the phone account that received the SMS.
+ */
+ /** @hide */
+ public static final String EXTRA_VOICEMAIL_SMS_SUBID =
+ "com.android.voicemail.extra.VOICEMAIL_SMS_SUBID";
+
/**
* Extra included in {@link Intent#ACTION_PROVIDER_CHANGED} broadcast intents to indicate if the
* receiving package made this change.
*/
public static final String EXTRA_SELF_CHANGE = "com.android.voicemail.extra.SELF_CHANGE";
+ /**
+ * Extra included in {@link #ACTION_SYNC_VOICEMAIL} broadcast intents to indicate which {@link
+ * PhoneAccountHandle} to sync.
+ */
+ public static final String EXTRA_PHONE_ACCOUNT_HANDLE =
+ "android.provider.extra.PHONE_ACCOUNT_HANDLE";
+
/**
* Name of the source package field, which must be same across all voicemail related tables.
* This is an internal field.
@@ -360,6 +420,20 @@ public class VoicemailContract {
*/
public static final String SOURCE_PACKAGE = SOURCE_PACKAGE_FIELD;
+ /**
+ * The type of the source, which determines how to interpret source-specific states.
+ * Typically this will be set to the same string as
+ * {@link android.telephony.CarrierConfigManager#KEY_VVM_TYPE_STRING}. For example,
+ * "vvm_type_omtp".
+ *
+ *
Type: TEXT
+ *
+ * @see #CONFIGURATION_STATE
+ * @see #DATA_CHANNEL_STATE
+ * @see #NOTIFICATION_CHANNEL_STATE
+ */
+ public static final String SOURCE_TYPE = "source_type";
+
// Note: Multiple entries may exist for a single source if they are differentiated by the
// PHONE_ACCOUNT_* fields.
@@ -392,21 +466,21 @@ public class VoicemailContract {
public static final String VOICEMAIL_ACCESS_URI = "voicemail_access_uri";
/**
* The configuration state of the voicemail source.
+ *
+ *
Negative values are reserved to the source for source-specific states, see
+ * {@link #SOURCE_TYPE}
+ *
*
*/
public static final String CONFIGURATION_STATE = "configuration_state";
- /**
- * Value of {@link #CONFIGURATION_STATE} passed into
- * {@link #setStatus(Context, PhoneAccountHandle, int, int, int)} to indicate that the
- * {@link #CONFIGURATION_STATE} field is not to be changed
- *
- * @hide
- */
- public static final int CONFIGURATION_STATE_IGNORE = -1;
+
/** Value of {@link #CONFIGURATION_STATE} to indicate an all OK configuration status. */
public static final int CONFIGURATION_STATE_OK = 0;
/**
@@ -421,9 +495,28 @@ public class VoicemailContract {
* upgraded to visual voicemail and would like to show a set up invitation message.
*/
public static final int CONFIGURATION_STATE_CAN_BE_CONFIGURED = 2;
+ /**
+ * Value of {@link #CONFIGURATION_STATE} to indicate that visual voicemail still is being
+ * configured.
+ */
+ public static final int CONFIGURATION_STATE_CONFIGURING = 3;
+ /**
+ * Value of {@link #CONFIGURATION_STATE} to indicate that visual voicemail has failed to
+ * be configured.
+ */
+ public static final int CONFIGURATION_STATE_FAILED = 4;
+ /**
+ * Value of {@link #CONFIGURATION_STATE} to indicate that visual voicemail is disabled by
+ * the user.
+ */
+ public static final int CONFIGURATION_STATE_DISABLED = 5;
/**
* The data channel state of the voicemail source. This the channel through which the source
* pulls voicemail data from a remote server.
+ *
+ *
Negative values are reserved to the source for source-specific states, see
+ * {@link #SOURCE_TYPE}
+ *
*
Possible values:
* {@link #DATA_CHANNEL_STATE_OK},
* {@link #DATA_CHANNEL_STATE_NO_CONNECTION}
@@ -431,14 +524,7 @@ public class VoicemailContract {
*
Type: INTEGER
*/
public static final String DATA_CHANNEL_STATE = "data_channel_state";
- /**
- * Value of {@link #DATA_CHANNEL_STATE} passed into
- * {@link #setStatus(Context, PhoneAccountHandle, int, int, int)} to indicate that the
- * {@link #DATA_CHANNEL_STATE} field is not to be changed
- *
- * @hide
- */
- public static final int DATA_CHANNEL_STATE_IGNORE = -1;
+
/**
* Value of {@link #DATA_CHANNEL_STATE} to indicate that data channel is working fine.
*/
@@ -478,6 +564,10 @@ public class VoicemailContract {
/**
* The notification channel state of the voicemail source. This is the channel through which
* the source gets notified of new voicemails on the remote server.
+ *
+ *
Negative values are reserved to the source for source-specific states, see
+ * {@link #SOURCE_TYPE}
+ *
*
Possible values:
* {@link #NOTIFICATION_CHANNEL_STATE_OK},
* {@link #NOTIFICATION_CHANNEL_STATE_NO_CONNECTION},
@@ -486,14 +576,7 @@ public class VoicemailContract {
*
Type: INTEGER
*/
public static final String NOTIFICATION_CHANNEL_STATE = "notification_channel_state";
- /**
- * Value of {@link #NOTIFICATION_CHANNEL_STATE} passed into
- * {@link #setStatus(Context, PhoneAccountHandle, int, int, int)} to indicate that the
- * {@link #NOTIFICATION_CHANNEL_STATE} field is not to be changed
- *
- * @hide
- */
- public static final int NOTIFICATION_CHANNEL_STATE_IGNORE = -1;
+
/**
* Value of {@link #NOTIFICATION_CHANNEL_STATE} to indicate that the notification channel is
* working fine.
@@ -543,67 +626,5 @@ public class VoicemailContract {
return Status.CONTENT_URI.buildUpon()
.appendQueryParameter(PARAM_KEY_SOURCE_PACKAGE, packageName).build();
}
-
- /**
- * A helper method to set the status of a voicemail source.
- *
- * @param context The context from the package calling the method. This will be the source.
- * @param accountHandle The handle for the account the source is associated with.
- * @param configurationState See {@link Status#CONFIGURATION_STATE}
- * @param dataChannelState See {@link Status#DATA_CHANNEL_STATE}
- * @param notificationChannelState See {@link Status#NOTIFICATION_CHANNEL_STATE}
- *
- * @hide
- */
- public static void setStatus(Context context, PhoneAccountHandle accountHandle,
- int configurationState, int dataChannelState, int notificationChannelState) {
- ContentValues values = new ContentValues();
- values.put(Status.PHONE_ACCOUNT_COMPONENT_NAME,
- accountHandle.getComponentName().flattenToString());
- values.put(Status.PHONE_ACCOUNT_ID, accountHandle.getId());
- if(configurationState != CONFIGURATION_STATE_IGNORE) {
- values.put(Status.CONFIGURATION_STATE, configurationState);
- }
- if(dataChannelState != DATA_CHANNEL_STATE_IGNORE) {
- values.put(Status.DATA_CHANNEL_STATE, dataChannelState);
- }
- if(notificationChannelState != NOTIFICATION_CHANNEL_STATE_IGNORE) {
- values.put(Status.NOTIFICATION_CHANNEL_STATE, notificationChannelState);
- }
- ContentResolver contentResolver = context.getContentResolver();
- Uri statusUri = buildSourceUri(context.getPackageName());
- contentResolver.insert(statusUri, values);
- }
-
- /**
- * A helper method to set the quota of a voicemail source. Unit is unspecified.
- *
- * @param context The context from the package calling the method. This will be the source.
- * @param accountHandle The handle for the account the source is associated with.
- * @param occupied See {@link Status#QUOTA_OCCUPIED}
- * @param total See {@link Status#QUOTA_TOTAL}
- *
- * @hide
- */
- public static void setQuota(Context context, PhoneAccountHandle accountHandle, int occupied,
- int total) {
- if (occupied == QUOTA_UNAVAILABLE && total == QUOTA_UNAVAILABLE) {
- return;
- }
- ContentValues values = new ContentValues();
- values.put(Status.PHONE_ACCOUNT_COMPONENT_NAME,
- accountHandle.getComponentName().flattenToString());
- values.put(Status.PHONE_ACCOUNT_ID, accountHandle.getId());
- if (occupied != QUOTA_UNAVAILABLE) {
- values.put(Status.QUOTA_OCCUPIED,occupied);
- }
- if (total != QUOTA_UNAVAILABLE) {
- values.put(Status.QUOTA_TOTAL,total);
- }
-
- ContentResolver contentResolver = context.getContentResolver();
- Uri statusUri = buildSourceUri(context.getPackageName());
- contentResolver.insert(statusUri, values);
- }
}
}
diff --git a/core/java/android/service/carrier/CarrierIdentifier.java b/core/java/android/service/carrier/CarrierIdentifier.java
index a70c24d6886b2fe697f13e6fe6ac71a873b105c0..b47e872d47f832a82cc569589ceb55345bb05ff0 100644
--- a/core/java/android/service/carrier/CarrierIdentifier.java
+++ b/core/java/android/service/carrier/CarrierIdentifier.java
@@ -126,4 +126,13 @@ public class CarrierIdentifier implements Parcelable {
mGid1 = in.readString();
mGid2 = in.readString();
}
+
+ /** @hide */
+ public interface MatchType {
+ int ALL = 0;
+ int SPN = 1;
+ int IMSI_PREFIX = 2;
+ int GID1 = 3;
+ int GID2 = 4;
+ }
}
diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java
index 6911b0161704745f00ec2cd6e159d75f6605990d..e90a3ba5435134091b170f549f6d10b99cd0b14e 100644
--- a/core/java/android/service/notification/ZenModeConfig.java
+++ b/core/java/android/service/notification/ZenModeConfig.java
@@ -20,6 +20,8 @@ import android.app.ActivityManager;
import android.app.NotificationManager.Policy;
import android.content.ComponentName;
import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.net.Uri;
import android.os.Parcel;
@@ -42,6 +44,7 @@ import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
+import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Locale;
import java.util.Objects;
@@ -118,6 +121,7 @@ public class ZenModeConfig implements Parcelable {
private static final String RULE_ATT_ZEN = "zen";
private static final String RULE_ATT_CONDITION_ID = "conditionId";
private static final String RULE_ATT_CREATION_TIME = "creationTime";
+ private static final String RULE_ATT_ENABLER = "enabler";
public boolean allowCalls = DEFAULT_ALLOW_CALLS;
public boolean allowRepeatCallers = DEFAULT_ALLOW_REPEAT_CALLERS;
@@ -502,6 +506,7 @@ public class ZenModeConfig implements Parcelable {
rt.conditionId = safeUri(parser, RULE_ATT_CONDITION_ID);
rt.component = safeComponentName(parser, RULE_ATT_COMPONENT);
rt.creationTime = safeLong(parser, RULE_ATT_CREATION_TIME, 0);
+ rt.enabler = parser.getAttributeValue(null, RULE_ATT_ENABLER);
rt.condition = readConditionXml(parser);
return rt;
}
@@ -520,6 +525,9 @@ public class ZenModeConfig implements Parcelable {
out.attribute(null, RULE_ATT_CONDITION_ID, rule.conditionId.toString());
}
out.attribute(null, RULE_ATT_CREATION_TIME, Long.toString(rule.creationTime));
+ if (rule.enabler != null) {
+ out.attribute(null, RULE_ATT_ENABLER, rule.enabler);
+ }
if (rule.condition != null) {
writeConditionXml(rule.condition, out);
}
@@ -889,9 +897,13 @@ public class ZenModeConfig implements Parcelable {
", endHour=" + endHour +
", endMinute=" + endMinute +
", exitAtAlarm=" + exitAtAlarm +
- ", nextAlarm=" + nextAlarm +
+ ", nextAlarm=" + ts(nextAlarm) +
'}';
}
+
+ protected static String ts(long time) {
+ return new Date(time) + " (" + time + ")";
+ }
}
// ==== Built-in system condition: event ====
@@ -989,6 +1001,25 @@ public class ZenModeConfig implements Parcelable {
return UUID.randomUUID().toString().replace("-", "");
}
+ private static String getOwnerCaption(Context context, String owner) {
+ final PackageManager pm = context.getPackageManager();
+ try {
+ final ApplicationInfo info = pm.getApplicationInfo(owner, 0);
+ if (info != null) {
+ final CharSequence seq = info.loadLabel(pm);
+ if (seq != null) {
+ final String str = seq.toString().trim();
+ if (str.length() > 0) {
+ return str;
+ }
+ }
+ }
+ } catch (Throwable e) {
+ Slog.w(TAG, "Error loading owner caption", e);
+ }
+ return "";
+ }
+
public static String getConditionSummary(Context context, ZenModeConfig config,
int userHandle, boolean shortVersion) {
return getConditionLine(context, config, userHandle, false /*useLine1*/, shortVersion);
@@ -997,23 +1028,28 @@ public class ZenModeConfig implements Parcelable {
private static String getConditionLine(Context context, ZenModeConfig config,
int userHandle, boolean useLine1, boolean shortVersion) {
if (config == null) return "";
+ String summary = "";
if (config.manualRule != null) {
final Uri id = config.manualRule.conditionId;
- if (id == null) {
- return context.getString(com.android.internal.R.string.zen_mode_forever);
- }
- final long time = tryParseCountdownConditionId(id);
- Condition c = config.manualRule.condition;
- if (time > 0) {
- final long now = System.currentTimeMillis();
- final long span = time - now;
- c = toTimeCondition(context, time, Math.round(span / (float) MINUTES_MS),
- userHandle, shortVersion);
+ if (config.manualRule.enabler != null) {
+ summary = getOwnerCaption(context, config.manualRule.enabler);
+ } else {
+ if (id == null) {
+ summary = context.getString(com.android.internal.R.string.zen_mode_forever);
+ } else {
+ final long time = tryParseCountdownConditionId(id);
+ Condition c = config.manualRule.condition;
+ if (time > 0) {
+ final long now = System.currentTimeMillis();
+ final long span = time - now;
+ c = toTimeCondition(context, time, Math.round(span / (float) MINUTES_MS),
+ userHandle, shortVersion);
+ }
+ final String rt = c == null ? "" : useLine1 ? c.line1 : c.summary;
+ summary = TextUtils.isEmpty(rt) ? "" : rt;
+ }
}
- final String rt = c == null ? "" : useLine1 ? c.line1 : c.summary;
- return TextUtils.isEmpty(rt) ? "" : rt;
}
- String summary = "";
for (ZenRule automaticRule : config.automaticRules.values()) {
if (automaticRule.isAutomaticActive()) {
if (summary.isEmpty()) {
@@ -1023,6 +1059,7 @@ public class ZenModeConfig implements Parcelable {
.getString(R.string.zen_mode_rule_name_combination, summary,
automaticRule.name);
}
+
}
}
return summary;
@@ -1038,6 +1075,7 @@ public class ZenModeConfig implements Parcelable {
public ComponentName component; // optional
public String id; // required for automatic (unique)
public long creationTime; // required for automatic
+ public String enabler; // package name, only used for manual rules.
public ZenRule() { }
@@ -1055,6 +1093,9 @@ public class ZenModeConfig implements Parcelable {
id = source.readString();
}
creationTime = source.readLong();
+ if (source.readInt() == 1) {
+ enabler = source.readString();
+ }
}
@Override
@@ -1083,6 +1124,12 @@ public class ZenModeConfig implements Parcelable {
dest.writeInt(0);
}
dest.writeLong(creationTime);
+ if (enabler != null) {
+ dest.writeInt(1);
+ dest.writeString(enabler);
+ } else {
+ dest.writeInt(0);
+ }
}
@Override
@@ -1097,6 +1144,7 @@ public class ZenModeConfig implements Parcelable {
.append(",component=").append(component)
.append(",id=").append(id)
.append(",creationTime=").append(creationTime)
+ .append(",enabler=").append(enabler)
.append(']').toString();
}
@@ -1143,6 +1191,9 @@ public class ZenModeConfig implements Parcelable {
if (creationTime != to.creationTime) {
d.addLine(item, "creationTime", creationTime, to.creationTime);
}
+ if (enabler != to.enabler) {
+ d.addLine(item, "enabler", enabler, to.enabler);
+ }
}
@Override
@@ -1158,13 +1209,14 @@ public class ZenModeConfig implements Parcelable {
&& Objects.equals(other.condition, condition)
&& Objects.equals(other.component, component)
&& Objects.equals(other.id, id)
- && other.creationTime == creationTime;
+ && other.creationTime == creationTime
+ && Objects.equals(other.enabler, enabler);
}
@Override
public int hashCode() {
return Objects.hash(enabled, snoozing, name, zenMode, conditionId, condition,
- component, id, creationTime);
+ component, id, creationTime, enabler);
}
public boolean isAutomaticActive() {
diff --git a/core/java/android/service/persistentdata/PersistentDataBlockManager.java b/core/java/android/service/persistentdata/PersistentDataBlockManager.java
index cfeed51da86f2bd3e6f3edc6792556582fcabe5f..0f92ed04a457b91786150dc30c4b2b339bc1d437 100644
--- a/core/java/android/service/persistentdata/PersistentDataBlockManager.java
+++ b/core/java/android/service/persistentdata/PersistentDataBlockManager.java
@@ -163,10 +163,9 @@ public class PersistentDataBlockManager {
/**
* Retrieves available information about this device's flash lock state.
*
- * @return FLASH_LOCK_STATE_LOCKED if device bootloader is locked,
- * FLASH_LOCK_STATE_UNLOCKED if device bootloader is unlocked,
- * or FLASH_LOCK_STATE unknown if this information cannot be ascertained
- * on this device.
+ * @return {@link #FLASH_LOCK_LOCKED} if device bootloader is locked,
+ * {@link #FLASH_LOCK_UNLOCKED} if device bootloader is unlocked, or {@link #FLASH_LOCK_UNKNOWN}
+ * if this information cannot be ascertained on this device.
*/
@FlashLockState
public int getFlashLockState() {
diff --git a/core/java/android/service/quicksettings/IQSService.aidl b/core/java/android/service/quicksettings/IQSService.aidl
index bf963570b040e036e0626c3571221442d2d1a10d..d03ff93be5ceefb1e3267b6fb02b701aa23cb5c2 100644
--- a/core/java/android/service/quicksettings/IQSService.aidl
+++ b/core/java/android/service/quicksettings/IQSService.aidl
@@ -23,16 +23,16 @@ import android.service.quicksettings.Tile;
* @hide
*/
interface IQSService {
- Tile getTile(in ComponentName component);
- void updateQsTile(in Tile tile);
- void updateStatusIcon(in Tile tile, in Icon icon,
+ Tile getTile(in IBinder tile);
+ void updateQsTile(in Tile tile, in IBinder service);
+ void updateStatusIcon(in IBinder tile, in Icon icon,
String contentDescription);
- void onShowDialog(in Tile tile);
- void onStartActivity(in Tile tile);
+ void onShowDialog(in IBinder tile);
+ void onStartActivity(in IBinder tile);
boolean isLocked();
boolean isSecure();
- void startUnlockAndRun(in Tile tile);
+ void startUnlockAndRun(in IBinder tile);
- void onDialogHidden(in Tile tile);
- void onStartSuccessful(in Tile tile);
+ void onDialogHidden(in IBinder tile);
+ void onStartSuccessful(in IBinder tile);
}
diff --git a/core/java/android/service/quicksettings/Tile.java b/core/java/android/service/quicksettings/Tile.java
index 3d7d53ea67e8a2bb9d6f5455ff7ae534bddb2e5c..4b81a726085227f32aef95fb8f53b08783a04cb1 100644
--- a/core/java/android/service/quicksettings/Tile.java
+++ b/core/java/android/service/quicksettings/Tile.java
@@ -15,8 +15,8 @@
*/
package android.service.quicksettings;
-import android.content.ComponentName;
import android.graphics.drawable.Icon;
+import android.os.IBinder;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.RemoteException;
@@ -59,7 +59,7 @@ public final class Tile implements Parcelable {
*/
public static final int STATE_ACTIVE = 2;
- private ComponentName mComponentName;
+ private IBinder mToken;
private Icon mIcon;
private CharSequence mLabel;
private CharSequence mContentDescription;
@@ -78,29 +78,15 @@ public final class Tile implements Parcelable {
/**
* @hide
*/
- public Tile(ComponentName componentName) {
- mComponentName = componentName;
+ public Tile() {
}
/**
* @hide
*/
- public void setService(IQSService service) {
+ public void setService(IQSService service, IBinder stub) {
mService = service;
- }
-
- /**
- * @hide
- */
- public ComponentName getComponentName() {
- return mComponentName;
- }
-
- /**
- * @hide
- */
- public IQSService getQsService() {
- return mService;
+ mToken = stub;
}
/**
@@ -193,7 +179,7 @@ public final class Tile implements Parcelable {
*/
public void updateTile() {
try {
- mService.updateQsTile(this);
+ mService.updateQsTile(this, mToken);
} catch (RemoteException e) {
Log.e(TAG, "Couldn't update tile");
}
@@ -201,12 +187,6 @@ public final class Tile implements Parcelable {
@Override
public void writeToParcel(Parcel dest, int flags) {
- if (mComponentName != null) {
- dest.writeByte((byte) 1);
- mComponentName.writeToParcel(dest, flags);
- } else {
- dest.writeByte((byte) 0);
- }
if (mIcon != null) {
dest.writeByte((byte) 1);
mIcon.writeToParcel(dest, flags);
@@ -219,11 +199,6 @@ public final class Tile implements Parcelable {
}
private void readFromParcel(Parcel source) {
- if (source.readByte() != 0) {
- mComponentName = ComponentName.CREATOR.createFromParcel(source);
- } else {
- mComponentName = null;
- }
if (source.readByte() != 0) {
mIcon = Icon.CREATOR.createFromParcel(source);
} else {
diff --git a/core/java/android/service/quicksettings/TileService.java b/core/java/android/service/quicksettings/TileService.java
index 50411ab7d15e926f1286ed4ed13073f20f2cfc35..887f4b6577b9171fb587cce22807dc3bf33b96ed 100644
--- a/core/java/android/service/quicksettings/TileService.java
+++ b/core/java/android/service/quicksettings/TileService.java
@@ -120,6 +120,11 @@ public class TileService extends Service {
*/
public static final String EXTRA_SERVICE = "service";
+ /**
+ * @hide
+ */
+ public static final String EXTRA_TOKEN = "token";
+
/**
* @hide
*/
@@ -132,6 +137,7 @@ public class TileService extends Service {
private IBinder mToken;
private IQSService mService;
private Runnable mUnlockRunnable;
+ private IBinder mTileToken;
@Override
public void onDestroy() {
@@ -197,7 +203,7 @@ public class TileService extends Service {
public final void setStatusIcon(Icon icon, String contentDescription) {
if (mService != null) {
try {
- mService.updateStatusIcon(mTile, icon, contentDescription);
+ mService.updateStatusIcon(mTileToken, icon, contentDescription);
} catch (RemoteException e) {
}
}
@@ -224,14 +230,14 @@ public class TileService extends Service {
@Override
public void onViewDetachedFromWindow(View v) {
try {
- mService.onDialogHidden(getQsTile());
+ mService.onDialogHidden(mTileToken);
} catch (RemoteException e) {
}
}
});
dialog.show();
try {
- mService.onShowDialog(mTile);
+ mService.onShowDialog(mTileToken);
} catch (RemoteException e) {
}
}
@@ -246,7 +252,7 @@ public class TileService extends Service {
public final void unlockAndRun(Runnable runnable) {
mUnlockRunnable = runnable;
try {
- mService.startUnlockAndRun(mTile);
+ mService.startUnlockAndRun(mTileToken);
} catch (RemoteException e) {
}
}
@@ -292,7 +298,7 @@ public class TileService extends Service {
public final void startActivityAndCollapse(Intent intent) {
startActivity(intent);
try {
- mService.onStartActivity(mTile);
+ mService.onStartActivity(mTileToken);
} catch (RemoteException e) {
}
}
@@ -311,14 +317,14 @@ public class TileService extends Service {
@Override
public IBinder onBind(Intent intent) {
mService = IQSService.Stub.asInterface(intent.getIBinderExtra(EXTRA_SERVICE));
+ mTileToken = intent.getIBinderExtra(EXTRA_TOKEN);
try {
- ComponentName component = intent.getParcelableExtra(EXTRA_COMPONENT);
- mTile = mService.getTile(component);
+ mTile = mService.getTile(mTileToken);
} catch (RemoteException e) {
throw new RuntimeException("Unable to reach IQSService", e);
}
if (mTile != null) {
- mTile.setService(mService);
+ mTile.setService(mService, mTileToken);
mHandler.sendEmptyMessage(H.MSG_START_SUCCESS);
}
return new IQSTileService.Stub() {
@@ -403,7 +409,7 @@ public class TileService extends Service {
break;
case MSG_START_SUCCESS:
try {
- mService.onStartSuccessful(mTile);
+ mService.onStartSuccessful(mTileToken);
} catch (RemoteException e) {
}
break;
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index de8133b33aa6fa6cf83a04b07d814310658fe98d..06d87f84699d1052f52a60d83e3747f9fe5173b3 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -55,6 +55,7 @@ import android.view.SurfaceHolder;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
+import android.view.WindowManager.LayoutParams;
import android.view.WindowManagerGlobal;
import java.io.FileDescriptor;
@@ -628,9 +629,9 @@ public abstract class WallpaperService extends Service {
mCurWindowFlags = mWindowFlags;
mLayout.flags = mWindowFlags
| WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
+ | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR
| WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
- | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
- ;
+ | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
mCurWindowPrivateFlags = mWindowPrivateFlags;
mLayout.privateFlags = mWindowPrivateFlags;
diff --git a/core/java/android/text/Emoji.java b/core/java/android/text/Emoji.java
index b62cc66b52690f8752f506d685da640361e47564..b6d720d453e9eebf6f7e9ada6533b20e68e56119 100644
--- a/core/java/android/text/Emoji.java
+++ b/core/java/android/text/Emoji.java
@@ -32,111 +32,112 @@ public class Emoji {
0x23EC, 0x23ED, 0x23EE, 0x23EF, 0x23F0, 0x23F1, 0x23F2, 0x23F3, 0x23F8, 0x23F9, 0x23FA,
0x24C2, 0x25AA, 0x25AB, 0x25B6, 0x25C0, 0x25FB, 0x25FC, 0x25FD, 0x25FE, 0x2600, 0x2601,
0x2602, 0x2603, 0x2604, 0x260E, 0x2611, 0x2614, 0x2615, 0x2618, 0x261D, 0x2620, 0x2622,
- 0x2623, 0x2626, 0x262A, 0x262E, 0x262F, 0x2638, 0x2639, 0x263A, 0x2648, 0x2649, 0x264A,
- 0x264B, 0x264C, 0x264D, 0x264E, 0x264F, 0x2650, 0x2651, 0x2652, 0x2653, 0x2660, 0x2663,
- 0x2665, 0x2666, 0x2668, 0x267B, 0x267F, 0x2692, 0x2693, 0x2694, 0x2696, 0x2697, 0x2699,
- 0x269B, 0x269C, 0x26A0, 0x26A1, 0x26AA, 0x26AB, 0x26B0, 0x26B1, 0x26BD, 0x26BE, 0x26C4,
- 0x26C5, 0x26C8, 0x26CE, 0x26CF, 0x26D1, 0x26D3, 0x26D4, 0x26E9, 0x26EA, 0x26F0, 0x26F1,
- 0x26F2, 0x26F3, 0x26F4, 0x26F5, 0x26F7, 0x26F8, 0x26F9, 0x26FA, 0x26FD, 0x2702, 0x2705,
- 0x2708, 0x2709, 0x270A, 0x270B, 0x270C, 0x270D, 0x270F, 0x2712, 0x2714, 0x2716, 0x271D,
- 0x2721, 0x2728, 0x2733, 0x2734, 0x2744, 0x2747, 0x274C, 0x274E, 0x2753, 0x2754, 0x2755,
- 0x2757, 0x2763, 0x2764, 0x2795, 0x2796, 0x2797, 0x27A1, 0x27B0, 0x27BF, 0x2934, 0x2935,
- 0x2B05, 0x2B06, 0x2B07, 0x2B1B, 0x2B1C, 0x2B50, 0x2B55, 0x3030, 0x303D, 0x3297, 0x3299,
- 0x1F004, 0x1F0CF, 0x1F170, 0x1F171, 0x1F17E, 0x1F17F, 0x1F18E, 0x1F191, 0x1F192, 0x1F193,
- 0x1F194, 0x1F195, 0x1F196, 0x1F197, 0x1F198, 0x1F199, 0x1F19A, 0x1F1E6, 0x1F1E7, 0x1F1E8,
- 0x1F1E9, 0x1F1EA, 0x1F1EB, 0x1F1EC, 0x1F1ED, 0x1F1EE, 0x1F1EF, 0x1F1F0, 0x1F1F1, 0x1F1F2,
- 0x1F1F3, 0x1F1F4, 0x1F1F5, 0x1F1F6, 0x1F1F7, 0x1F1F8, 0x1F1F9, 0x1F1FA, 0x1F1FB, 0x1F1FC,
- 0x1F1FD, 0x1F1FE, 0x1F1FF, 0x1F201, 0x1F202, 0x1F21A, 0x1F22F, 0x1F232, 0x1F233, 0x1F234,
- 0x1F235, 0x1F236, 0x1F237, 0x1F238, 0x1F239, 0x1F23A, 0x1F250, 0x1F251, 0x1F300, 0x1F301,
- 0x1F302, 0x1F303, 0x1F304, 0x1F305, 0x1F306, 0x1F307, 0x1F308, 0x1F309, 0x1F30A, 0x1F30B,
- 0x1F30C, 0x1F30D, 0x1F30E, 0x1F30F, 0x1F310, 0x1F311, 0x1F312, 0x1F313, 0x1F314, 0x1F315,
- 0x1F316, 0x1F317, 0x1F318, 0x1F319, 0x1F31A, 0x1F31B, 0x1F31C, 0x1F31D, 0x1F31E, 0x1F31F,
- 0x1F320, 0x1F321, 0x1F324, 0x1F325, 0x1F326, 0x1F327, 0x1F328, 0x1F329, 0x1F32A, 0x1F32B,
- 0x1F32C, 0x1F32D, 0x1F32E, 0x1F32F, 0x1F330, 0x1F331, 0x1F332, 0x1F333, 0x1F334, 0x1F335,
- 0x1F336, 0x1F337, 0x1F338, 0x1F339, 0x1F33A, 0x1F33B, 0x1F33C, 0x1F33D, 0x1F33E, 0x1F33F,
- 0x1F340, 0x1F341, 0x1F342, 0x1F343, 0x1F344, 0x1F345, 0x1F346, 0x1F347, 0x1F348, 0x1F349,
- 0x1F34A, 0x1F34B, 0x1F34C, 0x1F34D, 0x1F34E, 0x1F34F, 0x1F350, 0x1F351, 0x1F352, 0x1F353,
- 0x1F354, 0x1F355, 0x1F356, 0x1F357, 0x1F358, 0x1F359, 0x1F35A, 0x1F35B, 0x1F35C, 0x1F35D,
- 0x1F35E, 0x1F35F, 0x1F360, 0x1F361, 0x1F362, 0x1F363, 0x1F364, 0x1F365, 0x1F366, 0x1F367,
- 0x1F368, 0x1F369, 0x1F36A, 0x1F36B, 0x1F36C, 0x1F36D, 0x1F36E, 0x1F36F, 0x1F370, 0x1F371,
- 0x1F372, 0x1F373, 0x1F374, 0x1F375, 0x1F376, 0x1F377, 0x1F378, 0x1F379, 0x1F37A, 0x1F37B,
- 0x1F37C, 0x1F37D, 0x1F37E, 0x1F37F, 0x1F380, 0x1F381, 0x1F382, 0x1F383, 0x1F384, 0x1F385,
- 0x1F386, 0x1F387, 0x1F388, 0x1F389, 0x1F38A, 0x1F38B, 0x1F38C, 0x1F38D, 0x1F38E, 0x1F38F,
- 0x1F390, 0x1F391, 0x1F392, 0x1F393, 0x1F396, 0x1F397, 0x1F399, 0x1F39A, 0x1F39B, 0x1F39E,
- 0x1F39F, 0x1F3A0, 0x1F3A1, 0x1F3A2, 0x1F3A3, 0x1F3A4, 0x1F3A5, 0x1F3A6, 0x1F3A7, 0x1F3A8,
- 0x1F3A9, 0x1F3AA, 0x1F3AB, 0x1F3AC, 0x1F3AD, 0x1F3AE, 0x1F3AF, 0x1F3B0, 0x1F3B1, 0x1F3B2,
- 0x1F3B3, 0x1F3B4, 0x1F3B5, 0x1F3B6, 0x1F3B7, 0x1F3B8, 0x1F3B9, 0x1F3BA, 0x1F3BB, 0x1F3BC,
- 0x1F3BD, 0x1F3BE, 0x1F3BF, 0x1F3C0, 0x1F3C1, 0x1F3C2, 0x1F3C3, 0x1F3C4, 0x1F3C5, 0x1F3C6,
- 0x1F3C7, 0x1F3C8, 0x1F3C9, 0x1F3CA, 0x1F3CB, 0x1F3CC, 0x1F3CD, 0x1F3CE, 0x1F3CF, 0x1F3D0,
- 0x1F3D1, 0x1F3D2, 0x1F3D3, 0x1F3D4, 0x1F3D5, 0x1F3D6, 0x1F3D7, 0x1F3D8, 0x1F3D9, 0x1F3DA,
- 0x1F3DB, 0x1F3DC, 0x1F3DD, 0x1F3DE, 0x1F3DF, 0x1F3E0, 0x1F3E1, 0x1F3E2, 0x1F3E3, 0x1F3E4,
- 0x1F3E5, 0x1F3E6, 0x1F3E7, 0x1F3E8, 0x1F3E9, 0x1F3EA, 0x1F3EB, 0x1F3EC, 0x1F3ED, 0x1F3EE,
- 0x1F3EF, 0x1F3F0, 0x1F3F3, 0x1F3F4, 0x1F3F5, 0x1F3F7, 0x1F3F8, 0x1F3F9, 0x1F3FA, 0x1F3FB,
- 0x1F3FC, 0x1F3FD, 0x1F3FE, 0x1F3FF, 0x1F400, 0x1F401, 0x1F402, 0x1F403, 0x1F404, 0x1F405,
- 0x1F406, 0x1F407, 0x1F408, 0x1F409, 0x1F40A, 0x1F40B, 0x1F40C, 0x1F40D, 0x1F40E, 0x1F40F,
- 0x1F410, 0x1F411, 0x1F412, 0x1F413, 0x1F414, 0x1F415, 0x1F416, 0x1F417, 0x1F418, 0x1F419,
- 0x1F41A, 0x1F41B, 0x1F41C, 0x1F41D, 0x1F41E, 0x1F41F, 0x1F420, 0x1F421, 0x1F422, 0x1F423,
- 0x1F424, 0x1F425, 0x1F426, 0x1F427, 0x1F428, 0x1F429, 0x1F42A, 0x1F42B, 0x1F42C, 0x1F42D,
- 0x1F42E, 0x1F42F, 0x1F430, 0x1F431, 0x1F432, 0x1F433, 0x1F434, 0x1F435, 0x1F436, 0x1F437,
- 0x1F438, 0x1F439, 0x1F43A, 0x1F43B, 0x1F43C, 0x1F43D, 0x1F43E, 0x1F43F, 0x1F440, 0x1F441,
- 0x1F442, 0x1F443, 0x1F444, 0x1F445, 0x1F446, 0x1F447, 0x1F448, 0x1F449, 0x1F44A, 0x1F44B,
- 0x1F44C, 0x1F44D, 0x1F44E, 0x1F44F, 0x1F450, 0x1F451, 0x1F452, 0x1F453, 0x1F454, 0x1F455,
- 0x1F456, 0x1F457, 0x1F458, 0x1F459, 0x1F45A, 0x1F45B, 0x1F45C, 0x1F45D, 0x1F45E, 0x1F45F,
- 0x1F460, 0x1F461, 0x1F462, 0x1F463, 0x1F464, 0x1F465, 0x1F466, 0x1F467, 0x1F468, 0x1F469,
- 0x1F46A, 0x1F46B, 0x1F46C, 0x1F46D, 0x1F46E, 0x1F46F, 0x1F470, 0x1F471, 0x1F472, 0x1F473,
- 0x1F474, 0x1F475, 0x1F476, 0x1F477, 0x1F478, 0x1F479, 0x1F47A, 0x1F47B, 0x1F47C, 0x1F47D,
- 0x1F47E, 0x1F47F, 0x1F480, 0x1F481, 0x1F482, 0x1F483, 0x1F484, 0x1F485, 0x1F486, 0x1F487,
- 0x1F488, 0x1F489, 0x1F48A, 0x1F48B, 0x1F48C, 0x1F48D, 0x1F48E, 0x1F48F, 0x1F490, 0x1F491,
- 0x1F492, 0x1F493, 0x1F494, 0x1F495, 0x1F496, 0x1F497, 0x1F498, 0x1F499, 0x1F49A, 0x1F49B,
- 0x1F49C, 0x1F49D, 0x1F49E, 0x1F49F, 0x1F4A0, 0x1F4A1, 0x1F4A2, 0x1F4A3, 0x1F4A4, 0x1F4A5,
- 0x1F4A6, 0x1F4A7, 0x1F4A8, 0x1F4A9, 0x1F4AA, 0x1F4AB, 0x1F4AC, 0x1F4AD, 0x1F4AE, 0x1F4AF,
- 0x1F4B0, 0x1F4B1, 0x1F4B2, 0x1F4B3, 0x1F4B4, 0x1F4B5, 0x1F4B6, 0x1F4B7, 0x1F4B8, 0x1F4B9,
- 0x1F4BA, 0x1F4BB, 0x1F4BC, 0x1F4BD, 0x1F4BE, 0x1F4BF, 0x1F4C0, 0x1F4C1, 0x1F4C2, 0x1F4C3,
- 0x1F4C4, 0x1F4C5, 0x1F4C6, 0x1F4C7, 0x1F4C8, 0x1F4C9, 0x1F4CA, 0x1F4CB, 0x1F4CC, 0x1F4CD,
- 0x1F4CE, 0x1F4CF, 0x1F4D0, 0x1F4D1, 0x1F4D2, 0x1F4D3, 0x1F4D4, 0x1F4D5, 0x1F4D6, 0x1F4D7,
- 0x1F4D8, 0x1F4D9, 0x1F4DA, 0x1F4DB, 0x1F4DC, 0x1F4DD, 0x1F4DE, 0x1F4DF, 0x1F4E0, 0x1F4E1,
- 0x1F4E2, 0x1F4E3, 0x1F4E4, 0x1F4E5, 0x1F4E6, 0x1F4E7, 0x1F4E8, 0x1F4E9, 0x1F4EA, 0x1F4EB,
- 0x1F4EC, 0x1F4ED, 0x1F4EE, 0x1F4EF, 0x1F4F0, 0x1F4F1, 0x1F4F2, 0x1F4F3, 0x1F4F4, 0x1F4F5,
- 0x1F4F6, 0x1F4F7, 0x1F4F8, 0x1F4F9, 0x1F4FA, 0x1F4FB, 0x1F4FC, 0x1F4FD, 0x1F4FF, 0x1F500,
- 0x1F501, 0x1F502, 0x1F503, 0x1F504, 0x1F505, 0x1F506, 0x1F507, 0x1F508, 0x1F509, 0x1F50A,
- 0x1F50B, 0x1F50C, 0x1F50D, 0x1F50E, 0x1F50F, 0x1F510, 0x1F511, 0x1F512, 0x1F513, 0x1F514,
- 0x1F515, 0x1F516, 0x1F517, 0x1F518, 0x1F519, 0x1F51A, 0x1F51B, 0x1F51C, 0x1F51D, 0x1F51E,
- 0x1F51F, 0x1F520, 0x1F521, 0x1F522, 0x1F523, 0x1F524, 0x1F525, 0x1F526, 0x1F527, 0x1F528,
- 0x1F529, 0x1F52A, 0x1F52B, 0x1F52C, 0x1F52D, 0x1F52E, 0x1F52F, 0x1F530, 0x1F531, 0x1F532,
- 0x1F533, 0x1F534, 0x1F535, 0x1F536, 0x1F537, 0x1F538, 0x1F539, 0x1F53A, 0x1F53B, 0x1F53C,
- 0x1F53D, 0x1F549, 0x1F54A, 0x1F54B, 0x1F54C, 0x1F54D, 0x1F54E, 0x1F550, 0x1F551, 0x1F552,
- 0x1F553, 0x1F554, 0x1F555, 0x1F556, 0x1F557, 0x1F558, 0x1F559, 0x1F55A, 0x1F55B, 0x1F55C,
- 0x1F55D, 0x1F55E, 0x1F55F, 0x1F560, 0x1F561, 0x1F562, 0x1F563, 0x1F564, 0x1F565, 0x1F566,
- 0x1F567, 0x1F56F, 0x1F570, 0x1F573, 0x1F574, 0x1F575, 0x1F576, 0x1F577, 0x1F578, 0x1F579,
- 0x1F57A, 0x1F587, 0x1F58A, 0x1F58B, 0x1F58C, 0x1F58D, 0x1F590, 0x1F595, 0x1F596, 0x1F5A4,
- 0x1F5A5, 0x1F5A8, 0x1F5B1, 0x1F5B2, 0x1F5BC, 0x1F5C2, 0x1F5C3, 0x1F5C4, 0x1F5D1, 0x1F5D2,
- 0x1F5D3, 0x1F5DC, 0x1F5DD, 0x1F5DE, 0x1F5E1, 0x1F5E3, 0x1F5E8, 0x1F5EF, 0x1F5F3, 0x1F5FA,
- 0x1F5FB, 0x1F5FC, 0x1F5FD, 0x1F5FE, 0x1F5FF, 0x1F600, 0x1F601, 0x1F602, 0x1F603, 0x1F604,
- 0x1F605, 0x1F606, 0x1F607, 0x1F608, 0x1F609, 0x1F60A, 0x1F60B, 0x1F60C, 0x1F60D, 0x1F60E,
- 0x1F60F, 0x1F610, 0x1F611, 0x1F612, 0x1F613, 0x1F614, 0x1F615, 0x1F616, 0x1F617, 0x1F618,
- 0x1F619, 0x1F61A, 0x1F61B, 0x1F61C, 0x1F61D, 0x1F61E, 0x1F61F, 0x1F620, 0x1F621, 0x1F622,
- 0x1F623, 0x1F624, 0x1F625, 0x1F626, 0x1F627, 0x1F628, 0x1F629, 0x1F62A, 0x1F62B, 0x1F62C,
- 0x1F62D, 0x1F62E, 0x1F62F, 0x1F630, 0x1F631, 0x1F632, 0x1F633, 0x1F634, 0x1F635, 0x1F636,
- 0x1F637, 0x1F638, 0x1F639, 0x1F63A, 0x1F63B, 0x1F63C, 0x1F63D, 0x1F63E, 0x1F63F, 0x1F640,
- 0x1F641, 0x1F642, 0x1F643, 0x1F644, 0x1F645, 0x1F646, 0x1F647, 0x1F648, 0x1F649, 0x1F64A,
- 0x1F64B, 0x1F64C, 0x1F64D, 0x1F64E, 0x1F64F, 0x1F680, 0x1F681, 0x1F682, 0x1F683, 0x1F684,
- 0x1F685, 0x1F686, 0x1F687, 0x1F688, 0x1F689, 0x1F68A, 0x1F68B, 0x1F68C, 0x1F68D, 0x1F68E,
- 0x1F68F, 0x1F690, 0x1F691, 0x1F692, 0x1F693, 0x1F694, 0x1F695, 0x1F696, 0x1F697, 0x1F698,
- 0x1F699, 0x1F69A, 0x1F69B, 0x1F69C, 0x1F69D, 0x1F69E, 0x1F69F, 0x1F6A0, 0x1F6A1, 0x1F6A2,
- 0x1F6A3, 0x1F6A4, 0x1F6A5, 0x1F6A6, 0x1F6A7, 0x1F6A8, 0x1F6A9, 0x1F6AA, 0x1F6AB, 0x1F6AC,
- 0x1F6AD, 0x1F6AE, 0x1F6AF, 0x1F6B0, 0x1F6B1, 0x1F6B2, 0x1F6B3, 0x1F6B4, 0x1F6B5, 0x1F6B6,
- 0x1F6B7, 0x1F6B8, 0x1F6B9, 0x1F6BA, 0x1F6BB, 0x1F6BC, 0x1F6BD, 0x1F6BE, 0x1F6BF, 0x1F6C0,
- 0x1F6C1, 0x1F6C2, 0x1F6C3, 0x1F6C4, 0x1F6C5, 0x1F6CB, 0x1F6CC, 0x1F6CD, 0x1F6CE, 0x1F6CF,
- 0x1F6D0, 0x1F6D1, 0x1F6D2, 0x1F6E0, 0x1F6E1, 0x1F6E2, 0x1F6E3, 0x1F6E4, 0x1F6E5, 0x1F6E9,
- 0x1F6EB, 0x1F6EC, 0x1F6F0, 0x1F6F3, 0x1F6F4, 0x1F6F5, 0x1F6F6, 0x1F910, 0x1F911, 0x1F912,
- 0x1F913, 0x1F914, 0x1F915, 0x1F916, 0x1F917, 0x1F918, 0x1F919, 0x1F91A, 0x1F91B, 0x1F91C,
- 0x1F91D, 0x1F91E, 0x1F920, 0x1F921, 0x1F922, 0x1F923, 0x1F924, 0x1F925, 0x1F926, 0x1F927,
- 0x1F930, 0x1F933, 0x1F934, 0x1F935, 0x1F936, 0x1F937, 0x1F938, 0x1F939, 0x1F93A, 0x1F93B,
- 0x1F93C, 0x1F93D, 0x1F93E, 0x1F940, 0x1F941, 0x1F942, 0x1F943, 0x1F944, 0x1F945, 0x1F946,
- 0x1F947, 0x1F948, 0x1F949, 0x1F94A, 0x1F94B, 0x1F950, 0x1F951, 0x1F952, 0x1F953, 0x1F954,
- 0x1F955, 0x1F956, 0x1F957, 0x1F958, 0x1F959, 0x1F95A, 0x1F95B, 0x1F95C, 0x1F95D, 0x1F95E,
- 0x1F980, 0x1F981, 0x1F982, 0x1F983, 0x1F984, 0x1F985, 0x1F986, 0x1F987, 0x1F988, 0x1F989,
- 0x1F98A, 0x1F98B, 0x1F98C, 0x1F98D, 0x1F98E, 0x1F98F, 0x1F990, 0x1F991, 0x1F9C0
+ 0x2623, 0x2626, 0x262A, 0x262E, 0x262F, 0x2638, 0x2639, 0x263A, 0x2640, 0x2642, 0x2648,
+ 0x2649, 0x264A, 0x264B, 0x264C, 0x264D, 0x264E, 0x264F, 0x2650, 0x2651, 0x2652, 0x2653,
+ 0x2660, 0x2663, 0x2665, 0x2666, 0x2668, 0x267B, 0x267F, 0x2692, 0x2693, 0x2694, 0x2695,
+ 0x2696, 0x2697, 0x2699, 0x269B, 0x269C, 0x26A0, 0x26A1, 0x26AA, 0x26AB, 0x26B0, 0x26B1,
+ 0x26BD, 0x26BE, 0x26C4, 0x26C5, 0x26C8, 0x26CE, 0x26CF, 0x26D1, 0x26D3, 0x26D4, 0x26E9,
+ 0x26EA, 0x26F0, 0x26F1, 0x26F2, 0x26F3, 0x26F4, 0x26F5, 0x26F7, 0x26F8, 0x26F9, 0x26FA,
+ 0x26FD, 0x2702, 0x2705, 0x2708, 0x2709, 0x270A, 0x270B, 0x270C, 0x270D, 0x270F, 0x2712,
+ 0x2714, 0x2716, 0x271D, 0x2721, 0x2728, 0x2733, 0x2734, 0x2744, 0x2747, 0x274C, 0x274E,
+ 0x2753, 0x2754, 0x2755, 0x2757, 0x2763, 0x2764, 0x2795, 0x2796, 0x2797, 0x27A1, 0x27B0,
+ 0x27BF, 0x2934, 0x2935, 0x2B05, 0x2B06, 0x2B07, 0x2B1B, 0x2B1C, 0x2B50, 0x2B55, 0x3030,
+ 0x303D, 0x3297, 0x3299, 0x1F004, 0x1F0CF, 0x1F170, 0x1F171, 0x1F17E, 0x1F17F, 0x1F18E,
+ 0x1F191, 0x1F192, 0x1F193, 0x1F194, 0x1F195, 0x1F196, 0x1F197, 0x1F198, 0x1F199, 0x1F19A,
+ 0x1F1E6, 0x1F1E7, 0x1F1E8, 0x1F1E9, 0x1F1EA, 0x1F1EB, 0x1F1EC, 0x1F1ED, 0x1F1EE, 0x1F1EF,
+ 0x1F1F0, 0x1F1F1, 0x1F1F2, 0x1F1F3, 0x1F1F4, 0x1F1F5, 0x1F1F6, 0x1F1F7, 0x1F1F8, 0x1F1F9,
+ 0x1F1FA, 0x1F1FB, 0x1F1FC, 0x1F1FD, 0x1F1FE, 0x1F1FF, 0x1F201, 0x1F202, 0x1F21A, 0x1F22F,
+ 0x1F232, 0x1F233, 0x1F234, 0x1F235, 0x1F236, 0x1F237, 0x1F238, 0x1F239, 0x1F23A, 0x1F250,
+ 0x1F251, 0x1F300, 0x1F301, 0x1F302, 0x1F303, 0x1F304, 0x1F305, 0x1F306, 0x1F307, 0x1F308,
+ 0x1F309, 0x1F30A, 0x1F30B, 0x1F30C, 0x1F30D, 0x1F30E, 0x1F30F, 0x1F310, 0x1F311, 0x1F312,
+ 0x1F313, 0x1F314, 0x1F315, 0x1F316, 0x1F317, 0x1F318, 0x1F319, 0x1F31A, 0x1F31B, 0x1F31C,
+ 0x1F31D, 0x1F31E, 0x1F31F, 0x1F320, 0x1F321, 0x1F324, 0x1F325, 0x1F326, 0x1F327, 0x1F328,
+ 0x1F329, 0x1F32A, 0x1F32B, 0x1F32C, 0x1F32D, 0x1F32E, 0x1F32F, 0x1F330, 0x1F331, 0x1F332,
+ 0x1F333, 0x1F334, 0x1F335, 0x1F336, 0x1F337, 0x1F338, 0x1F339, 0x1F33A, 0x1F33B, 0x1F33C,
+ 0x1F33D, 0x1F33E, 0x1F33F, 0x1F340, 0x1F341, 0x1F342, 0x1F343, 0x1F344, 0x1F345, 0x1F346,
+ 0x1F347, 0x1F348, 0x1F349, 0x1F34A, 0x1F34B, 0x1F34C, 0x1F34D, 0x1F34E, 0x1F34F, 0x1F350,
+ 0x1F351, 0x1F352, 0x1F353, 0x1F354, 0x1F355, 0x1F356, 0x1F357, 0x1F358, 0x1F359, 0x1F35A,
+ 0x1F35B, 0x1F35C, 0x1F35D, 0x1F35E, 0x1F35F, 0x1F360, 0x1F361, 0x1F362, 0x1F363, 0x1F364,
+ 0x1F365, 0x1F366, 0x1F367, 0x1F368, 0x1F369, 0x1F36A, 0x1F36B, 0x1F36C, 0x1F36D, 0x1F36E,
+ 0x1F36F, 0x1F370, 0x1F371, 0x1F372, 0x1F373, 0x1F374, 0x1F375, 0x1F376, 0x1F377, 0x1F378,
+ 0x1F379, 0x1F37A, 0x1F37B, 0x1F37C, 0x1F37D, 0x1F37E, 0x1F37F, 0x1F380, 0x1F381, 0x1F382,
+ 0x1F383, 0x1F384, 0x1F385, 0x1F386, 0x1F387, 0x1F388, 0x1F389, 0x1F38A, 0x1F38B, 0x1F38C,
+ 0x1F38D, 0x1F38E, 0x1F38F, 0x1F390, 0x1F391, 0x1F392, 0x1F393, 0x1F396, 0x1F397, 0x1F399,
+ 0x1F39A, 0x1F39B, 0x1F39E, 0x1F39F, 0x1F3A0, 0x1F3A1, 0x1F3A2, 0x1F3A3, 0x1F3A4, 0x1F3A5,
+ 0x1F3A6, 0x1F3A7, 0x1F3A8, 0x1F3A9, 0x1F3AA, 0x1F3AB, 0x1F3AC, 0x1F3AD, 0x1F3AE, 0x1F3AF,
+ 0x1F3B0, 0x1F3B1, 0x1F3B2, 0x1F3B3, 0x1F3B4, 0x1F3B5, 0x1F3B6, 0x1F3B7, 0x1F3B8, 0x1F3B9,
+ 0x1F3BA, 0x1F3BB, 0x1F3BC, 0x1F3BD, 0x1F3BE, 0x1F3BF, 0x1F3C0, 0x1F3C1, 0x1F3C2, 0x1F3C3,
+ 0x1F3C4, 0x1F3C5, 0x1F3C6, 0x1F3C7, 0x1F3C8, 0x1F3C9, 0x1F3CA, 0x1F3CB, 0x1F3CC, 0x1F3CD,
+ 0x1F3CE, 0x1F3CF, 0x1F3D0, 0x1F3D1, 0x1F3D2, 0x1F3D3, 0x1F3D4, 0x1F3D5, 0x1F3D6, 0x1F3D7,
+ 0x1F3D8, 0x1F3D9, 0x1F3DA, 0x1F3DB, 0x1F3DC, 0x1F3DD, 0x1F3DE, 0x1F3DF, 0x1F3E0, 0x1F3E1,
+ 0x1F3E2, 0x1F3E3, 0x1F3E4, 0x1F3E5, 0x1F3E6, 0x1F3E7, 0x1F3E8, 0x1F3E9, 0x1F3EA, 0x1F3EB,
+ 0x1F3EC, 0x1F3ED, 0x1F3EE, 0x1F3EF, 0x1F3F0, 0x1F3F3, 0x1F3F4, 0x1F3F5, 0x1F3F7, 0x1F3F8,
+ 0x1F3F9, 0x1F3FA, 0x1F3FB, 0x1F3FC, 0x1F3FD, 0x1F3FE, 0x1F3FF, 0x1F400, 0x1F401, 0x1F402,
+ 0x1F403, 0x1F404, 0x1F405, 0x1F406, 0x1F407, 0x1F408, 0x1F409, 0x1F40A, 0x1F40B, 0x1F40C,
+ 0x1F40D, 0x1F40E, 0x1F40F, 0x1F410, 0x1F411, 0x1F412, 0x1F413, 0x1F414, 0x1F415, 0x1F416,
+ 0x1F417, 0x1F418, 0x1F419, 0x1F41A, 0x1F41B, 0x1F41C, 0x1F41D, 0x1F41E, 0x1F41F, 0x1F420,
+ 0x1F421, 0x1F422, 0x1F423, 0x1F424, 0x1F425, 0x1F426, 0x1F427, 0x1F428, 0x1F429, 0x1F42A,
+ 0x1F42B, 0x1F42C, 0x1F42D, 0x1F42E, 0x1F42F, 0x1F430, 0x1F431, 0x1F432, 0x1F433, 0x1F434,
+ 0x1F435, 0x1F436, 0x1F437, 0x1F438, 0x1F439, 0x1F43A, 0x1F43B, 0x1F43C, 0x1F43D, 0x1F43E,
+ 0x1F43F, 0x1F440, 0x1F441, 0x1F442, 0x1F443, 0x1F444, 0x1F445, 0x1F446, 0x1F447, 0x1F448,
+ 0x1F449, 0x1F44A, 0x1F44B, 0x1F44C, 0x1F44D, 0x1F44E, 0x1F44F, 0x1F450, 0x1F451, 0x1F452,
+ 0x1F453, 0x1F454, 0x1F455, 0x1F456, 0x1F457, 0x1F458, 0x1F459, 0x1F45A, 0x1F45B, 0x1F45C,
+ 0x1F45D, 0x1F45E, 0x1F45F, 0x1F460, 0x1F461, 0x1F462, 0x1F463, 0x1F464, 0x1F465, 0x1F466,
+ 0x1F467, 0x1F468, 0x1F469, 0x1F46A, 0x1F46B, 0x1F46C, 0x1F46D, 0x1F46E, 0x1F46F, 0x1F470,
+ 0x1F471, 0x1F472, 0x1F473, 0x1F474, 0x1F475, 0x1F476, 0x1F477, 0x1F478, 0x1F479, 0x1F47A,
+ 0x1F47B, 0x1F47C, 0x1F47D, 0x1F47E, 0x1F47F, 0x1F480, 0x1F481, 0x1F482, 0x1F483, 0x1F484,
+ 0x1F485, 0x1F486, 0x1F487, 0x1F488, 0x1F489, 0x1F48A, 0x1F48B, 0x1F48C, 0x1F48D, 0x1F48E,
+ 0x1F48F, 0x1F490, 0x1F491, 0x1F492, 0x1F493, 0x1F494, 0x1F495, 0x1F496, 0x1F497, 0x1F498,
+ 0x1F499, 0x1F49A, 0x1F49B, 0x1F49C, 0x1F49D, 0x1F49E, 0x1F49F, 0x1F4A0, 0x1F4A1, 0x1F4A2,
+ 0x1F4A3, 0x1F4A4, 0x1F4A5, 0x1F4A6, 0x1F4A7, 0x1F4A8, 0x1F4A9, 0x1F4AA, 0x1F4AB, 0x1F4AC,
+ 0x1F4AD, 0x1F4AE, 0x1F4AF, 0x1F4B0, 0x1F4B1, 0x1F4B2, 0x1F4B3, 0x1F4B4, 0x1F4B5, 0x1F4B6,
+ 0x1F4B7, 0x1F4B8, 0x1F4B9, 0x1F4BA, 0x1F4BB, 0x1F4BC, 0x1F4BD, 0x1F4BE, 0x1F4BF, 0x1F4C0,
+ 0x1F4C1, 0x1F4C2, 0x1F4C3, 0x1F4C4, 0x1F4C5, 0x1F4C6, 0x1F4C7, 0x1F4C8, 0x1F4C9, 0x1F4CA,
+ 0x1F4CB, 0x1F4CC, 0x1F4CD, 0x1F4CE, 0x1F4CF, 0x1F4D0, 0x1F4D1, 0x1F4D2, 0x1F4D3, 0x1F4D4,
+ 0x1F4D5, 0x1F4D6, 0x1F4D7, 0x1F4D8, 0x1F4D9, 0x1F4DA, 0x1F4DB, 0x1F4DC, 0x1F4DD, 0x1F4DE,
+ 0x1F4DF, 0x1F4E0, 0x1F4E1, 0x1F4E2, 0x1F4E3, 0x1F4E4, 0x1F4E5, 0x1F4E6, 0x1F4E7, 0x1F4E8,
+ 0x1F4E9, 0x1F4EA, 0x1F4EB, 0x1F4EC, 0x1F4ED, 0x1F4EE, 0x1F4EF, 0x1F4F0, 0x1F4F1, 0x1F4F2,
+ 0x1F4F3, 0x1F4F4, 0x1F4F5, 0x1F4F6, 0x1F4F7, 0x1F4F8, 0x1F4F9, 0x1F4FA, 0x1F4FB, 0x1F4FC,
+ 0x1F4FD, 0x1F4FF, 0x1F500, 0x1F501, 0x1F502, 0x1F503, 0x1F504, 0x1F505, 0x1F506, 0x1F507,
+ 0x1F508, 0x1F509, 0x1F50A, 0x1F50B, 0x1F50C, 0x1F50D, 0x1F50E, 0x1F50F, 0x1F510, 0x1F511,
+ 0x1F512, 0x1F513, 0x1F514, 0x1F515, 0x1F516, 0x1F517, 0x1F518, 0x1F519, 0x1F51A, 0x1F51B,
+ 0x1F51C, 0x1F51D, 0x1F51E, 0x1F51F, 0x1F520, 0x1F521, 0x1F522, 0x1F523, 0x1F524, 0x1F525,
+ 0x1F526, 0x1F527, 0x1F528, 0x1F529, 0x1F52A, 0x1F52B, 0x1F52C, 0x1F52D, 0x1F52E, 0x1F52F,
+ 0x1F530, 0x1F531, 0x1F532, 0x1F533, 0x1F534, 0x1F535, 0x1F536, 0x1F537, 0x1F538, 0x1F539,
+ 0x1F53A, 0x1F53B, 0x1F53C, 0x1F53D, 0x1F549, 0x1F54A, 0x1F54B, 0x1F54C, 0x1F54D, 0x1F54E,
+ 0x1F550, 0x1F551, 0x1F552, 0x1F553, 0x1F554, 0x1F555, 0x1F556, 0x1F557, 0x1F558, 0x1F559,
+ 0x1F55A, 0x1F55B, 0x1F55C, 0x1F55D, 0x1F55E, 0x1F55F, 0x1F560, 0x1F561, 0x1F562, 0x1F563,
+ 0x1F564, 0x1F565, 0x1F566, 0x1F567, 0x1F56F, 0x1F570, 0x1F573, 0x1F574, 0x1F575, 0x1F576,
+ 0x1F577, 0x1F578, 0x1F579, 0x1F57A, 0x1F587, 0x1F58A, 0x1F58B, 0x1F58C, 0x1F58D, 0x1F590,
+ 0x1F595, 0x1F596, 0x1F5A4, 0x1F5A5, 0x1F5A8, 0x1F5B1, 0x1F5B2, 0x1F5BC, 0x1F5C2, 0x1F5C3,
+ 0x1F5C4, 0x1F5D1, 0x1F5D2, 0x1F5D3, 0x1F5DC, 0x1F5DD, 0x1F5DE, 0x1F5E1, 0x1F5E3, 0x1F5E8,
+ 0x1F5EF, 0x1F5F3, 0x1F5FA, 0x1F5FB, 0x1F5FC, 0x1F5FD, 0x1F5FE, 0x1F5FF, 0x1F600, 0x1F601,
+ 0x1F602, 0x1F603, 0x1F604, 0x1F605, 0x1F606, 0x1F607, 0x1F608, 0x1F609, 0x1F60A, 0x1F60B,
+ 0x1F60C, 0x1F60D, 0x1F60E, 0x1F60F, 0x1F610, 0x1F611, 0x1F612, 0x1F613, 0x1F614, 0x1F615,
+ 0x1F616, 0x1F617, 0x1F618, 0x1F619, 0x1F61A, 0x1F61B, 0x1F61C, 0x1F61D, 0x1F61E, 0x1F61F,
+ 0x1F620, 0x1F621, 0x1F622, 0x1F623, 0x1F624, 0x1F625, 0x1F626, 0x1F627, 0x1F628, 0x1F629,
+ 0x1F62A, 0x1F62B, 0x1F62C, 0x1F62D, 0x1F62E, 0x1F62F, 0x1F630, 0x1F631, 0x1F632, 0x1F633,
+ 0x1F634, 0x1F635, 0x1F636, 0x1F637, 0x1F638, 0x1F639, 0x1F63A, 0x1F63B, 0x1F63C, 0x1F63D,
+ 0x1F63E, 0x1F63F, 0x1F640, 0x1F641, 0x1F642, 0x1F643, 0x1F644, 0x1F645, 0x1F646, 0x1F647,
+ 0x1F648, 0x1F649, 0x1F64A, 0x1F64B, 0x1F64C, 0x1F64D, 0x1F64E, 0x1F64F, 0x1F680, 0x1F681,
+ 0x1F682, 0x1F683, 0x1F684, 0x1F685, 0x1F686, 0x1F687, 0x1F688, 0x1F689, 0x1F68A, 0x1F68B,
+ 0x1F68C, 0x1F68D, 0x1F68E, 0x1F68F, 0x1F690, 0x1F691, 0x1F692, 0x1F693, 0x1F694, 0x1F695,
+ 0x1F696, 0x1F697, 0x1F698, 0x1F699, 0x1F69A, 0x1F69B, 0x1F69C, 0x1F69D, 0x1F69E, 0x1F69F,
+ 0x1F6A0, 0x1F6A1, 0x1F6A2, 0x1F6A3, 0x1F6A4, 0x1F6A5, 0x1F6A6, 0x1F6A7, 0x1F6A8, 0x1F6A9,
+ 0x1F6AA, 0x1F6AB, 0x1F6AC, 0x1F6AD, 0x1F6AE, 0x1F6AF, 0x1F6B0, 0x1F6B1, 0x1F6B2, 0x1F6B3,
+ 0x1F6B4, 0x1F6B5, 0x1F6B6, 0x1F6B7, 0x1F6B8, 0x1F6B9, 0x1F6BA, 0x1F6BB, 0x1F6BC, 0x1F6BD,
+ 0x1F6BE, 0x1F6BF, 0x1F6C0, 0x1F6C1, 0x1F6C2, 0x1F6C3, 0x1F6C4, 0x1F6C5, 0x1F6CB, 0x1F6CC,
+ 0x1F6CD, 0x1F6CE, 0x1F6CF, 0x1F6D0, 0x1F6D1, 0x1F6D2, 0x1F6E0, 0x1F6E1, 0x1F6E2, 0x1F6E3,
+ 0x1F6E4, 0x1F6E5, 0x1F6E9, 0x1F6EB, 0x1F6EC, 0x1F6F0, 0x1F6F3, 0x1F6F4, 0x1F6F5, 0x1F6F6,
+ 0x1F910, 0x1F911, 0x1F912, 0x1F913, 0x1F914, 0x1F915, 0x1F916, 0x1F917, 0x1F918, 0x1F919,
+ 0x1F91A, 0x1F91B, 0x1F91C, 0x1F91D, 0x1F91E, 0x1F920, 0x1F921, 0x1F922, 0x1F923, 0x1F924,
+ 0x1F925, 0x1F926, 0x1F927, 0x1F930, 0x1F933, 0x1F934, 0x1F935, 0x1F936, 0x1F937, 0x1F938,
+ 0x1F939, 0x1F93A, 0x1F93B, 0x1F93C, 0x1F93D, 0x1F93E, 0x1F940, 0x1F941, 0x1F942, 0x1F943,
+ 0x1F944, 0x1F945, 0x1F946, 0x1F947, 0x1F948, 0x1F949, 0x1F94A, 0x1F94B, 0x1F950, 0x1F951,
+ 0x1F952, 0x1F953, 0x1F954, 0x1F955, 0x1F956, 0x1F957, 0x1F958, 0x1F959, 0x1F95A, 0x1F95B,
+ 0x1F95C, 0x1F95D, 0x1F95E, 0x1F980, 0x1F981, 0x1F982, 0x1F983, 0x1F984, 0x1F985, 0x1F986,
+ 0x1F987, 0x1F988, 0x1F989, 0x1F98A, 0x1F98B, 0x1F98C, 0x1F98D, 0x1F98E, 0x1F98F, 0x1F990,
+ 0x1F991, 0x1F9C0
};
// See http://www.unicode.org/Public/emoji/3.0/emoji-data.txt
diff --git a/core/java/android/text/method/BaseKeyListener.java b/core/java/android/text/method/BaseKeyListener.java
index 3770a45d2172e9c39359b1fbceef359868a70993..2f327f3cb4950fc9387ab62840cb28fa7604b143 100644
--- a/core/java/android/text/method/BaseKeyListener.java
+++ b/core/java/android/text/method/BaseKeyListener.java
@@ -129,8 +129,8 @@ public abstract class BaseKeyListener extends MetaKeyKeyListener
// The offset is immediately before a variation selector.
final int STATE_BEFORE_VS = 6;
- // The offset is immediately before a ZWJ emoji.
- final int STATE_BEFORE_ZWJ_EMOJI = 7;
+ // The offset is immediately before an emoji.
+ final int STATE_BEFORE_EMOJI = 7;
// The offset is immediately before a ZWJ that were seen before a ZWJ emoji.
final int STATE_BEFORE_ZWJ = 8;
// The offset is immediately before a variation selector and a ZWJ that were seen before a
@@ -169,7 +169,7 @@ public abstract class BaseKeyListener extends MetaKeyKeyListener
} else if (codePoint == Emoji.COMBINING_ENCLOSING_KEYCAP) {
state = STATE_BEFORE_KEYCAP;
} else if (Emoji.isEmoji(codePoint)) {
- state = STATE_BEFORE_ZWJ_EMOJI;
+ state = STATE_BEFORE_EMOJI;
} else {
state = STATE_FINISHED;
}
@@ -232,7 +232,7 @@ public abstract class BaseKeyListener extends MetaKeyKeyListener
case STATE_BEFORE_VS:
if (Emoji.isEmoji(codePoint)) {
deleteCharCount += Character.charCount(codePoint);
- state = STATE_BEFORE_ZWJ_EMOJI;
+ state = STATE_BEFORE_EMOJI;
break;
}
@@ -242,7 +242,7 @@ public abstract class BaseKeyListener extends MetaKeyKeyListener
}
state = STATE_FINISHED;
break;
- case STATE_BEFORE_ZWJ_EMOJI:
+ case STATE_BEFORE_EMOJI:
if (codePoint == Emoji.ZERO_WIDTH_JOINER) {
state = STATE_BEFORE_ZWJ;
} else {
@@ -252,7 +252,8 @@ public abstract class BaseKeyListener extends MetaKeyKeyListener
case STATE_BEFORE_ZWJ:
if (Emoji.isEmoji(codePoint)) {
deleteCharCount += Character.charCount(codePoint) + 1; // +1 for ZWJ.
- state = STATE_BEFORE_ZWJ_EMOJI;
+ state = Emoji.isEmojiModifier(codePoint) ?
+ STATE_BEFORE_EMOJI_MODIFIER : STATE_BEFORE_EMOJI;
} else if (isVariationSelector(codePoint)) {
lastSeenVSCharCount = Character.charCount(codePoint);
state = STATE_BEFORE_VS_AND_ZWJ;
@@ -265,7 +266,7 @@ public abstract class BaseKeyListener extends MetaKeyKeyListener
// +1 for ZWJ.
deleteCharCount += lastSeenVSCharCount + 1 + Character.charCount(codePoint);
lastSeenVSCharCount = 0;
- state = STATE_BEFORE_ZWJ_EMOJI;
+ state = STATE_BEFORE_EMOJI;
} else {
state = STATE_FINISHED;
}
diff --git a/core/java/android/transition/Transition.java b/core/java/android/transition/Transition.java
index 316c7e3f6084408222c6c4ec6132b1af0e23f3f4..8823605c52b6ef251d2ca5e699bb0e86f05375e9 100644
--- a/core/java/android/transition/Transition.java
+++ b/core/java/android/transition/Transition.java
@@ -1940,6 +1940,26 @@ public abstract class Transition implements Cloneable {
}
}
+ /**
+ * Force the transition to move to its end state, ending all the animators.
+ *
+ * @hide
+ */
+ void forceToEnd(ViewGroup sceneRoot) {
+ ArrayMap runningAnimators = getRunningAnimators();
+ int numOldAnims = runningAnimators.size();
+ if (sceneRoot != null) {
+ WindowId windowId = sceneRoot.getWindowId();
+ for (int i = numOldAnims - 1; i >= 0; i--) {
+ AnimationInfo info = runningAnimators.valueAt(i);
+ if (info.view != null && windowId != null && windowId.equals(info.windowId)) {
+ Animator anim = runningAnimators.keyAt(i);
+ anim.end();
+ }
+ }
+ }
+ }
+
/**
* This method cancels a transition that is currently running.
*
diff --git a/core/java/android/transition/TransitionManager.java b/core/java/android/transition/TransitionManager.java
index 71c80991bb197c9bbd379c47b0cd7c7af6cf69ba..f2c871e3c718d77a425e613c5039451dec36b230 100644
--- a/core/java/android/transition/TransitionManager.java
+++ b/core/java/android/transition/TransitionManager.java
@@ -440,7 +440,7 @@ public class TransitionManager {
ArrayList copy = new ArrayList(runningTransitions);
for (int i = copy.size() - 1; i >= 0; i--) {
final Transition transition = copy.get(i);
- transition.end();
+ transition.forceToEnd(sceneRoot);
}
}
diff --git a/core/java/android/transition/TransitionSet.java b/core/java/android/transition/TransitionSet.java
index 583dc0f1ef2c4062fb367fb152ae130d262fde5d..a41fe64d0be10655b309795ab6a7fc9371f63acd 100644
--- a/core/java/android/transition/TransitionSet.java
+++ b/core/java/android/transition/TransitionSet.java
@@ -16,8 +16,6 @@
package android.transition;
-import com.android.internal.R;
-
import android.animation.TimeInterpolator;
import android.content.Context;
import android.content.res.TypedArray;
@@ -26,6 +24,8 @@ import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
+import com.android.internal.R;
+
import java.util.ArrayList;
/**
@@ -498,6 +498,16 @@ public class TransitionSet extends Transition {
}
}
+ /** @hide */
+ @Override
+ void forceToEnd(ViewGroup sceneRoot) {
+ super.forceToEnd(sceneRoot);
+ int numTransitions = mTransitions.size();
+ for (int i = 0; i < numTransitions; ++i) {
+ mTransitions.get(i).forceToEnd(sceneRoot);
+ }
+ }
+
@Override
TransitionSet setSceneRoot(ViewGroup sceneRoot) {
super.setSceneRoot(sceneRoot);
diff --git a/core/java/android/util/DisplayMetrics.java b/core/java/android/util/DisplayMetrics.java
index d201adef2d4d4e51e479985d40de8c4e44063b3d..f4db4d6611eaff35e44182a377d82ade4dbe652c 100644
--- a/core/java/android/util/DisplayMetrics.java
+++ b/core/java/android/util/DisplayMetrics.java
@@ -61,6 +61,13 @@ public class DisplayMetrics {
*/
public static final int DENSITY_HIGH = 240;
+ /**
+ * Intermediate density for screens that sit between {@link #DENSITY_HIGH} (240dpi) and
+ * {@link #DENSITY_XHIGH} (320dpi). This is not a density that applications should target,
+ * instead relying on the system to scale their {@link #DENSITY_XHIGH} assets for them.
+ */
+ public static final int DENSITY_260 = 260;
+
/**
* Intermediate density for screens that sit between {@link #DENSITY_HIGH} (240dpi) and
* {@link #DENSITY_XHIGH} (320dpi). This is not a density that applications should target,
@@ -68,11 +75,26 @@ public class DisplayMetrics {
*/
public static final int DENSITY_280 = 280;
+ /**
+ * Intermediate density for screens that sit between {@link #DENSITY_HIGH} (240dpi) and
+ * {@link #DENSITY_XHIGH} (320dpi). This is not a density that applications should target,
+ * instead relying on the system to scale their {@link #DENSITY_XHIGH} assets for them.
+ */
+ public static final int DENSITY_300 = 300;
+
/**
* Standard quantized DPI for extra-high-density screens.
*/
public static final int DENSITY_XHIGH = 320;
+ /**
+ * Intermediate density for screens that sit somewhere between
+ * {@link #DENSITY_XHIGH} (320 dpi) and {@link #DENSITY_XXHIGH} (480 dpi).
+ * This is not a density that applications should target, instead relying
+ * on the system to scale their {@link #DENSITY_XXHIGH} assets for them.
+ */
+ public static final int DENSITY_340 = 340;
+
/**
* Intermediate density for screens that sit somewhere between
* {@link #DENSITY_XHIGH} (320 dpi) and {@link #DENSITY_XXHIGH} (480 dpi).
diff --git a/core/java/android/view/Choreographer.java b/core/java/android/view/Choreographer.java
index d3db74d1ea249e27ccdcf3158441fa813b3e881c..3316f3aeb60b5b0ccde7b2f8e7e0c52b78a312ba 100644
--- a/core/java/android/view/Choreographer.java
+++ b/core/java/android/view/Choreographer.java
@@ -25,6 +25,7 @@ import android.os.SystemProperties;
import android.os.Trace;
import android.util.Log;
import android.util.TimeUtils;
+import android.view.animation.AnimationUtils;
import java.io.PrintWriter;
@@ -608,6 +609,7 @@ public final class Choreographer {
try {
Trace.traceBegin(Trace.TRACE_TAG_VIEW, "Choreographer#doFrame");
+ AnimationUtils.lockAnimationClock(frameTimeNanos / TimeUtils.NANOS_PER_MS);
mFrameInfo.markInputHandlingStart();
doCallbacks(Choreographer.CALLBACK_INPUT, frameTimeNanos);
@@ -620,6 +622,7 @@ public final class Choreographer {
doCallbacks(Choreographer.CALLBACK_COMMIT, frameTimeNanos);
} finally {
+ AnimationUtils.unlockAnimationClock();
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index 2f2fe57f68fa01db41d98ad3d9eb4e34424ebf43..85a4bf9d9e8f92e4b6d61b8e828c4e2fc0593604 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -36,7 +36,7 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Arrays;
-import static android.Manifest.permission.CONFIGURE_DISPLAY_COLOR_TRANSFORM;
+import static android.Manifest.permission.CONFIGURE_DISPLAY_COLOR_MODE;
/**
* Provides information about the size and density of a logical display.
@@ -284,6 +284,27 @@ public final class Display {
*/
public static final int STATE_DOZE_SUSPEND = 4;
+ /* The color mode constants defined below must be kept in sync with the ones in
+ * system/graphics.h */
+
+ /**
+ * Display color mode: The current color mode is unknown or invalid.
+ * @hide
+ */
+ public static final int COLOR_MODE_INVALID = -1;
+
+ /**
+ * Display color mode: The default or native gamut of the display.
+ * @hide
+ */
+ public static final int COLOR_MODE_DEFAULT = 0;
+
+ /**
+ * Display color mode: SRGB
+ * @hide
+ */
+ public static final int COLOR_MODE_SRGB = 7;
+
/**
* Internal method to create a display.
* Applications should use {@link android.view.WindowManager#getDefaultDisplay()}
@@ -463,20 +484,29 @@ public final class Display {
/**
* Gets the size of the display, in pixels.
+ * Value returned by this method does not necessarily represent the actual raw size
+ * (native resolution) of the display.
*
- * Note that this value should not be used for computing layouts,
- * since a device will typically have screen decoration (such as a status bar)
- * along the edges of the display that reduce the amount of application
- * space available from the size returned here. Layouts should instead use
- * the window size.
- *
- * The size is adjusted based on the current rotation of the display.
+ * 1. The returned size may be adjusted to exclude certain system decor elements
+ * that are always visible.
*
- * The size returned by this method does not necessarily represent the
- * actual raw size (native resolution) of the display. The returned size may
- * be adjusted to exclude certain system decoration elements that are always visible.
- * It may also be scaled to provide compatibility with older applications that
+ * 2. It may be scaled to provide compatibility with older applications that
* were originally designed for smaller displays.
+ *
+ * 3. It can be different depending on the WindowManager to which the display belongs.
+ *
+ * - If requested from non-Activity context (e.g. Application context via
+ * {@code (WindowManager) getApplicationContext().getSystemService(Context.WINDOW_SERVICE)})
+ * it will report the size of the entire display based on current rotation and with subtracted
+ * system decoration areas.
+ *
+ * - If requested from activity (either using {@code getWindowManager()} or
+ * {@code (WindowManager) getSystemService(Context.WINDOW_SERVICE)}) resulting size will
+ * correspond to current app window size. In this case it can be smaller than physical size in
+ * multi-window mode.
+ *
+ * Typically for the purposes of layout apps should make a request from activity context
+ * to obtain size available for the app content.
*
*
* @param outSize A {@link Point} object to receive the size information.
@@ -687,33 +717,22 @@ public final class Display {
}
/**
- * Request the display applies a color transform.
+ * Request the display applies a color mode.
* @hide
*/
- @RequiresPermission(CONFIGURE_DISPLAY_COLOR_TRANSFORM)
- public void requestColorTransform(ColorTransform colorTransform) {
- mGlobal.requestColorTransform(mDisplayId, colorTransform.getId());
+ @RequiresPermission(CONFIGURE_DISPLAY_COLOR_MODE)
+ public void requestColorMode(int colorMode) {
+ mGlobal.requestColorMode(mDisplayId, colorMode);
}
/**
- * Returns the active color transform of this display
+ * Returns the active color mode of this display
* @hide
*/
- public ColorTransform getColorTransform() {
+ public int getColorMode() {
synchronized (this) {
updateDisplayInfoLocked();
- return mDisplayInfo.getColorTransform();
- }
- }
-
- /**
- * Returns the default color transform of this display
- * @hide
- */
- public ColorTransform getDefaultColorTransform() {
- synchronized (this) {
- updateDisplayInfoLocked();
- return mDisplayInfo.getDefaultColorTransform();
+ return mDisplayInfo.colorMode;
}
}
@@ -728,14 +747,14 @@ public final class Display {
}
/**
- * Gets the supported color transforms of this device.
+ * Gets the supported color modes of this device.
* @hide
*/
- public ColorTransform[] getSupportedColorTransforms() {
+ public int[] getSupportedColorModes() {
synchronized (this) {
updateDisplayInfoLocked();
- ColorTransform[] transforms = mDisplayInfo.supportedColorTransforms;
- return Arrays.copyOf(transforms, transforms.length);
+ int[] colorModes = mDisplayInfo.supportedColorModes;
+ return Arrays.copyOf(colorModes, colorModes.length);
}
}
@@ -785,13 +804,16 @@ public final class Display {
* were originally designed for smaller displays.
*
* 3. It can be different depending on the WindowManager to which the display belongs.
- *
+ *
* - If requested from non-Activity context (e.g. Application context via
* {@code (WindowManager) getApplicationContext().getSystemService(Context.WINDOW_SERVICE)})
- * metrics will report real size of the display based on current rotation.
- * - If requested from activity resulting metrics will correspond to current window metrics.
- * In this case the size can be smaller than physical size in multi-window mode.
- *
+ * metrics will report the size of the entire display based on current rotation and with
+ * subtracted system decoration areas.
+ *
+ * - If requested from activity (either using {@code getWindowManager()} or
+ * {@code (WindowManager) getSystemService(Context.WINDOW_SERVICE)}) resulting metrics will
+ * correspond to current app window metrics. In this case the size can be smaller than physical
+ * size in multi-window mode.
*
*
* @param outMetrics A {@link DisplayMetrics} object to receive the metrics.
@@ -1205,6 +1227,33 @@ public final class Display {
return mMinLuminance;
}
+ @Override
+ public boolean equals(Object other) {
+ if (this == other) {
+ return true;
+ }
+
+ if (!(other instanceof HdrCapabilities)) {
+ return false;
+ }
+ HdrCapabilities that = (HdrCapabilities) other;
+
+ return Arrays.equals(mSupportedHdrTypes, that.mSupportedHdrTypes)
+ && mMaxLuminance == that.mMaxLuminance
+ && mMaxAverageLuminance == that.mMaxAverageLuminance
+ && mMinLuminance == that.mMinLuminance;
+ }
+
+ @Override
+ public int hashCode() {
+ int hash = 23;
+ hash = hash * 17 + Arrays.hashCode(mSupportedHdrTypes);
+ hash = hash * 17 + Float.floatToIntBits(mMaxLuminance);
+ hash = hash * 17 + Float.floatToIntBits(mMaxAverageLuminance);
+ hash = hash * 17 + Float.floatToIntBits(mMinLuminance);
+ return hash;
+ }
+
public static final Creator CREATOR = new Creator() {
@Override
public HdrCapabilities createFromParcel(Parcel source) {
@@ -1251,89 +1300,4 @@ public final class Display {
return 0;
}
}
-
- /**
- * A color transform supported by a given display.
- *
- * @see Display#getSupportedColorTransforms()
- * @hide
- */
- public static final class ColorTransform implements Parcelable {
- public static final ColorTransform[] EMPTY_ARRAY = new ColorTransform[0];
-
- private final int mId;
- private final int mColorTransform;
-
- public ColorTransform(int id, int colorTransform) {
- mId = id;
- mColorTransform = colorTransform;
- }
-
- public int getId() {
- return mId;
- }
-
- public int getColorTransform() {
- return mColorTransform;
- }
-
- @Override
- public boolean equals(Object other) {
- if (this == other) {
- return true;
- }
- if (!(other instanceof ColorTransform)) {
- return false;
- }
- ColorTransform that = (ColorTransform) other;
- return mId == that.mId
- && mColorTransform == that.mColorTransform;
- }
-
- @Override
- public int hashCode() {
- int hash = 1;
- hash = hash * 17 + mId;
- hash = hash * 17 + mColorTransform;
- return hash;
- }
-
- @Override
- public String toString() {
- return new StringBuilder("{")
- .append("id=").append(mId)
- .append(", colorTransform=").append(mColorTransform)
- .append("}")
- .toString();
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- private ColorTransform(Parcel in) {
- this(in.readInt(), in.readInt());
- }
-
- @Override
- public void writeToParcel(Parcel out, int parcelableFlags) {
- out.writeInt(mId);
- out.writeInt(mColorTransform);
- }
-
- @SuppressWarnings("hiding")
- public static final Parcelable.Creator CREATOR
- = new Parcelable.Creator() {
- @Override
- public ColorTransform createFromParcel(Parcel in) {
- return new ColorTransform(in);
- }
-
- @Override
- public ColorTransform[] newArray(int size) {
- return new ColorTransform[size];
- }
- };
- }
}
diff --git a/core/java/android/view/DisplayInfo.java b/core/java/android/view/DisplayInfo.java
index 8aeeffd906439527c6f2ec2a0cb41bec6034760e..bc40849a47bc03157fffde1f7f185fb517e147f9 100644
--- a/core/java/android/view/DisplayInfo.java
+++ b/core/java/android/view/DisplayInfo.java
@@ -169,14 +169,11 @@ public final class DisplayInfo implements Parcelable {
*/
public Display.Mode[] supportedModes = Display.Mode.EMPTY_ARRAY;
- /** The active color transform. */
- public int colorTransformId;
+ /** The active color mode. */
+ public int colorMode;
- /** The default color transform. */
- public int defaultColorTransformId;
-
- /** The list of supported color transforms */
- public Display.ColorTransform[] supportedColorTransforms = Display.ColorTransform.EMPTY_ARRAY;
+ /** The list of supported color modes */
+ public int[] supportedColorModes = { Display.COLOR_MODE_DEFAULT };
/** The display's HDR capabilities */
public Display.HdrCapabilities hdrCapabilities;
@@ -291,8 +288,8 @@ public final class DisplayInfo implements Parcelable {
&& rotation == other.rotation
&& modeId == other.modeId
&& defaultModeId == other.defaultModeId
- && colorTransformId == other.colorTransformId
- && defaultColorTransformId == other.defaultColorTransformId
+ && colorMode == other.colorMode
+ && Arrays.equals(supportedColorModes, other.supportedColorModes)
&& Objects.equal(hdrCapabilities, other.hdrCapabilities)
&& logicalDensityDpi == other.logicalDensityDpi
&& physicalXDpi == other.physicalXDpi
@@ -332,10 +329,9 @@ public final class DisplayInfo implements Parcelable {
modeId = other.modeId;
defaultModeId = other.defaultModeId;
supportedModes = Arrays.copyOf(other.supportedModes, other.supportedModes.length);
- colorTransformId = other.colorTransformId;
- defaultColorTransformId = other.defaultColorTransformId;
- supportedColorTransforms = Arrays.copyOf(
- other.supportedColorTransforms, other.supportedColorTransforms.length);
+ colorMode = other.colorMode;
+ supportedColorModes = Arrays.copyOf(
+ other.supportedColorModes, other.supportedColorModes.length);
hdrCapabilities = other.hdrCapabilities;
logicalDensityDpi = other.logicalDensityDpi;
physicalXDpi = other.physicalXDpi;
@@ -373,12 +369,11 @@ public final class DisplayInfo implements Parcelable {
for (int i = 0; i < nModes; i++) {
supportedModes[i] = Display.Mode.CREATOR.createFromParcel(source);
}
- colorTransformId = source.readInt();
- defaultColorTransformId = source.readInt();
- int nColorTransforms = source.readInt();
- supportedColorTransforms = new Display.ColorTransform[nColorTransforms];
- for (int i = 0; i < nColorTransforms; i++) {
- supportedColorTransforms[i] = Display.ColorTransform.CREATOR.createFromParcel(source);
+ colorMode = source.readInt();
+ int nColorModes = source.readInt();
+ supportedColorModes = new int[nColorModes];
+ for (int i = 0; i < nColorModes; i++) {
+ supportedColorModes[i] = source.readInt();
}
hdrCapabilities = source.readParcelable(null);
logicalDensityDpi = source.readInt();
@@ -418,11 +413,10 @@ public final class DisplayInfo implements Parcelable {
for (int i = 0; i < supportedModes.length; i++) {
supportedModes[i].writeToParcel(dest, flags);
}
- dest.writeInt(colorTransformId);
- dest.writeInt(defaultColorTransformId);
- dest.writeInt(supportedColorTransforms.length);
- for (int i = 0; i < supportedColorTransforms.length; i++) {
- supportedColorTransforms[i].writeToParcel(dest, flags);
+ dest.writeInt(colorMode);
+ dest.writeInt(supportedColorModes.length);
+ for (int i = 0; i < supportedColorModes.length; i++) {
+ dest.writeInt(supportedColorModes[i]);
}
dest.writeParcelable(hdrCapabilities, flags);
dest.writeInt(logicalDensityDpi);
@@ -496,24 +490,6 @@ public final class DisplayInfo implements Parcelable {
return result;
}
- public Display.ColorTransform getColorTransform() {
- return findColorTransform(colorTransformId);
- }
-
- public Display.ColorTransform getDefaultColorTransform() {
- return findColorTransform(defaultColorTransformId);
- }
-
- private Display.ColorTransform findColorTransform(int colorTransformId) {
- for (int i = 0; i < supportedColorTransforms.length; i++) {
- Display.ColorTransform colorTransform = supportedColorTransforms[i];
- if (colorTransform.getId() == colorTransformId) {
- return colorTransform;
- }
- }
- throw new IllegalStateException("Unable to locate color transform: " + colorTransformId);
- }
-
public void getAppMetrics(DisplayMetrics outMetrics) {
getAppMetrics(outMetrics, CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null);
}
@@ -615,12 +591,10 @@ public final class DisplayInfo implements Parcelable {
sb.append(defaultModeId);
sb.append(", modes ");
sb.append(Arrays.toString(supportedModes));
- sb.append(", colorTransformId ");
- sb.append(colorTransformId);
- sb.append(", defaultColorTransformId ");
- sb.append(defaultColorTransformId);
- sb.append(", supportedColorTransforms ");
- sb.append(Arrays.toString(supportedColorTransforms));
+ sb.append(", colorMode ");
+ sb.append(colorMode);
+ sb.append(", supportedColorModes ");
+ sb.append(Arrays.toString(supportedColorModes));
sb.append(", hdrCapabilities ");
sb.append(hdrCapabilities);
sb.append(", rotation ");
diff --git a/core/java/android/view/DragEvent.java b/core/java/android/view/DragEvent.java
index fb482b4e33ff5529c8f7c538e544961ad33b4fbf..b0f15b5f2329fceb11b5ac94e4592cce11afc760 100644
--- a/core/java/android/view/DragEvent.java
+++ b/core/java/android/view/DragEvent.java
@@ -102,8 +102,8 @@ import com.android.internal.view.IDragAndDropPermissions;
*
*
*
ACTION_DRAG_ENDED
- *
X
- *
X
+ *
+ *
*
*
*
@@ -359,7 +359,7 @@ public class DragEvent implements Parcelable {
* The drag handler or listener for a View can use the metadata in this object to decide if the
* View can accept the dragged View object's data.
*
- * This method returns valid data for all event actions.
+ * This method returns valid data for all event actions except for {@link #ACTION_DRAG_ENDED}.
* @return The ClipDescription that was part of the ClipData sent to the system by startDrag().
*/
public ClipDescription getClipDescription() {
@@ -377,7 +377,7 @@ public class DragEvent implements Parcelable {
* The object is intended to provide local information about the drag and drop operation. For
* example, it can indicate whether the drag and drop operation is a copy or a move.
*
- * This method returns valid data for all event actions.
+ * This method returns valid data for all event actions except for {@link #ACTION_DRAG_ENDED}.
*
* @return The local state object sent to the system by startDrag().
*/
diff --git a/core/java/android/view/FrameMetrics.java b/core/java/android/view/FrameMetrics.java
index 5c4450a4ed183b02477ded2b8217e2939a5be91b..2b938d0df7eb44104a03b1f07126bc36a0e9ed0e 100644
--- a/core/java/android/view/FrameMetrics.java
+++ b/core/java/android/view/FrameMetrics.java
@@ -198,7 +198,7 @@ public final class FrameMetrics {
int SWAP_BUFFERS = 12;
int FRAME_COMPLETED = 13;
- int FRAME_STATS_COUNT = 14; // must always be last
+ int FRAME_STATS_COUNT = 16; // must always be last
}
/*
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 7f21901bf68cf6ed84b39368d0b6078e7af344a9..cdd34aff3bcbdb4fa8d8cc2547f7b07b79c6b6fc 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -112,7 +112,7 @@ interface IWindowManager
int requestedOrientation, boolean fullscreen, boolean showWhenLocked, int userId,
int configChanges, boolean voiceInteraction, boolean launchTaskBehind,
in Rect taskBounds, in Configuration configuration, int taskResizeMode,
- boolean alwaysFocusable, boolean homeTask, int targetSdkVersion);
+ boolean alwaysFocusable, boolean homeTask, int targetSdkVersion, int rotationAnimationHint);
/**
*
* @param token The token we are adding to the input task Id.
@@ -173,7 +173,8 @@ interface IWindowManager
in CompatibilityInfo compatInfo, CharSequence nonLocalizedLabel, int labelRes,
int icon, int logo, int windowFlags, IBinder transferFrom, boolean createIfNeeded);
void setAppVisibility(IBinder token, boolean visible);
- void notifyAppStopped(IBinder token, boolean stopped);
+ void notifyAppResumed(IBinder token, boolean wasStopped, boolean allowSavedSurface);
+ void notifyAppStopped(IBinder token);
void startAppFreezingScreen(IBinder token, int configChanges);
void stopAppFreezingScreen(IBinder token, boolean force);
void removeAppToken(IBinder token);
@@ -305,6 +306,11 @@ interface IWindowManager
*/
boolean isRotationFrozen();
+ /**
+ * Screenshot the current wallpaper layer, including the whole screen.
+ */
+ Bitmap screenshotWallpaper();
+
/**
* Used only for assist -- request a screenshot of the current application.
*/
diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java
index 05c7fbf166e5dc8cac70adcf3677d261ca8b0787..38635c6ced4cd8c86b6494f714f48f65a8cca91f 100644
--- a/core/java/android/view/KeyEvent.java
+++ b/core/java/android/view/KeyEvent.java
@@ -796,8 +796,16 @@ public class KeyEvent extends InputEvent implements Parcelable {
public static final int KEYCODE_COPY = 278;
/** Key code constant: Paste key. */
public static final int KEYCODE_PASTE = 279;
+ /** Key code constant: Consumed by the system for navigation up */
+ public static final int KEYCODE_SYSTEM_NAVIGATION_UP = 280;
+ /** Key code constant: Consumed by the system for navigation down */
+ public static final int KEYCODE_SYSTEM_NAVIGATION_DOWN = 281;
+ /** Key code constant: Consumed by the system for navigation left*/
+ public static final int KEYCODE_SYSTEM_NAVIGATION_LEFT = 282;
+ /** Key code constant: Consumed by the system for navigation right */
+ public static final int KEYCODE_SYSTEM_NAVIGATION_RIGHT = 283;
- private static final int LAST_KEYCODE = KEYCODE_PASTE;
+ private static final int LAST_KEYCODE = KEYCODE_SYSTEM_NAVIGATION_RIGHT;
// NOTE: If you add a new keycode here you must also add it to:
// isSystem()
@@ -1844,6 +1852,10 @@ public class KeyEvent extends InputEvent implements Parcelable {
case KeyEvent.KEYCODE_BRIGHTNESS_DOWN:
case KeyEvent.KEYCODE_BRIGHTNESS_UP:
case KeyEvent.KEYCODE_MEDIA_AUDIO_TRACK:
+ case KeyEvent.KEYCODE_SYSTEM_NAVIGATION_UP:
+ case KeyEvent.KEYCODE_SYSTEM_NAVIGATION_DOWN:
+ case KeyEvent.KEYCODE_SYSTEM_NAVIGATION_LEFT:
+ case KeyEvent.KEYCODE_SYSTEM_NAVIGATION_RIGHT:
return true;
}
@@ -2934,11 +2946,13 @@ public class KeyEvent extends InputEvent implements Parcelable {
public static final Parcelable.Creator CREATOR
= new Parcelable.Creator() {
+ @Override
public KeyEvent createFromParcel(Parcel in) {
in.readInt(); // skip token, we already know this is a KeyEvent
return KeyEvent.createFromParcelBody(in);
}
+ @Override
public KeyEvent[] newArray(int size) {
return new KeyEvent[size];
}
@@ -2962,6 +2976,7 @@ public class KeyEvent extends InputEvent implements Parcelable {
mEventTime = in.readLong();
}
+ @Override
public void writeToParcel(Parcel out, int flags) {
out.writeInt(PARCEL_TOKEN_KEY_EVENT);
diff --git a/core/java/android/view/RenderNode.java b/core/java/android/view/RenderNode.java
index ab4cbcf21bed885bb06d45c1eef5abad73a8e504..0164fcd4f01673a1c3a347dab0fe28d7ba78359f 100644
--- a/core/java/android/view/RenderNode.java
+++ b/core/java/android/view/RenderNode.java
@@ -793,12 +793,12 @@ public class RenderNode {
return mOwningView != null && mOwningView.mAttachInfo != null;
}
- public void addAnimator(AnimatedVectorDrawable.VectorDrawableAnimatorRT animatorSet) {
+ public void registerVectorDrawableAnimator(
+ AnimatedVectorDrawable.VectorDrawableAnimatorRT animatorSet) {
if (mOwningView == null || mOwningView.mAttachInfo == null) {
throw new IllegalStateException("Cannot start this animator on a detached view!");
}
- nAddAnimator(mNativeRenderNode, animatorSet.getAnimatorNativePtr());
- mOwningView.mAttachInfo.mViewRootImpl.registerAnimatingRenderNode(this);
+ mOwningView.mAttachInfo.mViewRootImpl.registerVectorDrawableAnimator(animatorSet);
}
public void endAllAnimators() {
diff --git a/core/java/android/view/RoundScrollbarRenderer.java b/core/java/android/view/RoundScrollbarRenderer.java
new file mode 100644
index 0000000000000000000000000000000000000000..b77be8c00e697063609964029ed605d710559b8b
--- /dev/null
+++ b/core/java/android/view/RoundScrollbarRenderer.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.RectF;
+import android.graphics.Rect;
+
+/**
+ * Helper class for drawing round scroll bars on round Wear devices.
+ */
+class RoundScrollbarRenderer {
+ // The range of the scrollbar position represented as an angle in degrees.
+ private static final int SCROLLBAR_ANGLE_RANGE = 90;
+ private static final int MAX_SCROLLBAR_ANGLE_SWIPE = 16;
+ private static final int MIN_SCROLLBAR_ANGLE_SWIPE = 6;
+ private static final float WIDTH_PERCENTAGE = 0.02f;
+ private static final int DEFAULT_THUMB_COLOR = 0xFF757575;
+ private static final int DEFAULT_TRACK_COLOR = 0x21FFFFFF;
+
+ private final Paint mThumbPaint = new Paint();
+ private final Paint mTrackPaint = new Paint();
+ private final RectF mRect = new RectF();
+ private final View mParent;
+
+ public RoundScrollbarRenderer(View parent) {
+ // Paints for the round scrollbar.
+ // Set up the thumb paint
+ mThumbPaint.setAntiAlias(true);
+ mThumbPaint.setStrokeCap(Paint.Cap.ROUND);
+ mThumbPaint.setStyle(Paint.Style.STROKE);
+
+ // Set up the track paint
+ mTrackPaint.setAntiAlias(true);
+ mTrackPaint.setStrokeCap(Paint.Cap.ROUND);
+ mTrackPaint.setStyle(Paint.Style.STROKE);
+
+ mParent = parent;
+ }
+
+ public void drawRoundScrollbars(Canvas canvas, float alpha, Rect bounds) {
+ if (alpha == 0) {
+ return;
+ }
+ // Get information about the current scroll state of the parent view.
+ float maxScroll = mParent.computeVerticalScrollRange();
+ float scrollExtent = mParent.computeVerticalScrollExtent();
+ if (scrollExtent <= 0 || maxScroll <= scrollExtent) {
+ return;
+ }
+ float currentScroll = Math.max(0, mParent.computeVerticalScrollOffset());
+ float linearThumbLength = mParent.computeVerticalScrollExtent();
+ float thumbWidth = mParent.getWidth() * WIDTH_PERCENTAGE;
+ mThumbPaint.setStrokeWidth(thumbWidth);
+ mTrackPaint.setStrokeWidth(thumbWidth);
+
+ setThumbColor(applyAlpha(DEFAULT_THUMB_COLOR, alpha));
+ setTrackColor(applyAlpha(DEFAULT_TRACK_COLOR, alpha));
+
+ // Normalize the sweep angle for the scroll bar.
+ float sweepAngle = (linearThumbLength / maxScroll) * SCROLLBAR_ANGLE_RANGE;
+ sweepAngle = clamp(sweepAngle, MIN_SCROLLBAR_ANGLE_SWIPE, MAX_SCROLLBAR_ANGLE_SWIPE);
+ // Normalize the start angle so that it falls on the track.
+ float startAngle = (currentScroll * (SCROLLBAR_ANGLE_RANGE - sweepAngle))
+ / (maxScroll - linearThumbLength) - SCROLLBAR_ANGLE_RANGE / 2;
+ startAngle = clamp(startAngle, -SCROLLBAR_ANGLE_RANGE / 2,
+ SCROLLBAR_ANGLE_RANGE / 2 - sweepAngle);
+
+ // Draw the track and the scroll bar.
+ mRect.set(
+ bounds.left - thumbWidth / 2,
+ bounds.top,
+ bounds.right - thumbWidth / 2,
+ bounds.bottom);
+
+ canvas.drawArc(mRect, -SCROLLBAR_ANGLE_RANGE / 2, SCROLLBAR_ANGLE_RANGE, false,
+ mTrackPaint);
+ canvas.drawArc(mRect, startAngle, sweepAngle, false, mThumbPaint);
+ }
+
+ private static float clamp(float val, float min, float max) {
+ if (val < min) {
+ return min;
+ } else if (val > max) {
+ return max;
+ } else {
+ return val;
+ }
+ }
+
+ private static int applyAlpha(int color, float alpha) {
+ int alphaByte = (int) (Color.alpha(color) * alpha);
+ return Color.argb(alphaByte, Color.red(color), Color.green(color), Color.blue(color));
+ }
+
+ private void setThumbColor(int thumbColor) {
+ if (mThumbPaint.getColor() != thumbColor) {
+ mThumbPaint.setColor(thumbColor);
+ }
+ }
+
+ private void setTrackColor(int trackColor) {
+ if (mTrackPaint.getColor() != trackColor) {
+ mTrackPaint.setColor(trackColor);
+ }
+ }
+}
diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java
index 7da849a832e4d52d7b2ae8d52e43bef37d601cb2..286e0979d12b73b9ccdb3363fdbd6dea9d9787dc 100644
--- a/core/java/android/view/Surface.java
+++ b/core/java/android/view/Surface.java
@@ -58,6 +58,7 @@ public class Surface implements Parcelable {
private static native long nativeGetNextFrameNumber(long nativeObject);
private static native int nativeSetScalingMode(long nativeObject, int scalingMode);
+ private static native void nativeSetBuffersTransform(long nativeObject, long transform);
public static final Parcelable.Creator CREATOR =
new Parcelable.Creator() {
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 26d9135fee6c53fb2dec6b8dd1f5dd391d8242d7..6ace3049b5913d948761ec1ec07f030ad015803a 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -51,7 +51,7 @@ public class SurfaceControl {
private static native void nativeSetLayer(long nativeObject, int zorder);
private static native void nativeSetPosition(long nativeObject, float x, float y);
- private static native void nativeSetPositionAppliesWithResize(long nativeObject);
+ private static native void nativeSetGeometryAppliesWithResize(long nativeObject);
private static native void nativeSetSize(long nativeObject, int w, int h);
private static native void nativeSetTransparentRegionHint(long nativeObject, Region region);
private static native void nativeSetAlpha(long nativeObject, float alpha);
@@ -82,6 +82,10 @@ public class SurfaceControl {
IBinder displayToken);
private static native int nativeGetActiveConfig(IBinder displayToken);
private static native boolean nativeSetActiveConfig(IBinder displayToken, int id);
+ private static native int[] nativeGetDisplayColorModes(IBinder displayToken);
+ private static native int nativeGetActiveColorMode(IBinder displayToken);
+ private static native boolean nativeSetActiveColorMode(IBinder displayToken,
+ int colorMode);
private static native void nativeSetDisplayPowerMode(
IBinder displayToken, int mode);
private static native void nativeDeferTransactionUntil(long nativeObject,
@@ -89,6 +93,8 @@ public class SurfaceControl {
private static native void nativeSetOverrideScalingMode(long nativeObject,
int scalingMode);
private static native IBinder nativeGetHandle(long nativeObject);
+ private static native boolean nativeGetTransformToDisplayInverse(long nativeObject);
+
private static native Display.HdrCapabilities nativeGetHdrCapabilities(IBinder displayToken);
@@ -399,6 +405,10 @@ public class SurfaceControl {
return nativeGetHandle(mNativeObject);
}
+ public boolean getTransformToDisplayInverse() {
+ return nativeGetTransformToDisplayInverse(mNativeObject);
+ }
+
/** flag the transaction as an animation */
public static void setAnimationTransaction() {
nativeSetAnimationTransaction();
@@ -415,13 +425,15 @@ public class SurfaceControl {
}
/**
- * If the size changes in this transaction, position updates specified
+ * If the buffer size changes in this transaction, position and crop updates specified
* in this transaction will not complete until a buffer of the new size
- * arrives.
+ * arrives. As transform matrix and size are already frozen in this fashion,
+ * this enables totally freezing the surface until the resize has completed
+ * (at which point the geometry influencing aspects of this transaction will then occur)
*/
- public void setPositionAppliesWithResize() {
+ public void setGeometryAppliesWithResize() {
checkNotReleased();
- nativeSetPositionAppliesWithResize(mNativeObject);
+ nativeSetGeometryAppliesWithResize(mNativeObject);
}
public void setSize(int w, int h) {
@@ -545,7 +557,6 @@ public class SurfaceControl {
public boolean secure;
public long appVsyncOffsetNanos;
public long presentationDeadlineNanos;
- public int colorTransform;
public PhysicalDisplayInfo() {
}
@@ -569,8 +580,7 @@ public class SurfaceControl {
&& yDpi == other.yDpi
&& secure == other.secure
&& appVsyncOffsetNanos == other.appVsyncOffsetNanos
- && presentationDeadlineNanos == other.presentationDeadlineNanos
- && colorTransform == other.colorTransform;
+ && presentationDeadlineNanos == other.presentationDeadlineNanos;
}
@Override
@@ -588,7 +598,6 @@ public class SurfaceControl {
secure = other.secure;
appVsyncOffsetNanos = other.appVsyncOffsetNanos;
presentationDeadlineNanos = other.presentationDeadlineNanos;
- colorTransform = other.colorTransform;
}
// For debugging purposes
@@ -597,8 +606,7 @@ public class SurfaceControl {
return "PhysicalDisplayInfo{" + width + " x " + height + ", " + refreshRate + " fps, "
+ "density " + density + ", " + xDpi + " x " + yDpi + " dpi, secure " + secure
+ ", appVsyncOffset " + appVsyncOffsetNanos
- + ", bufferDeadline " + presentationDeadlineNanos
- + ", colorTransform " + colorTransform + "}";
+ + ", bufferDeadline " + presentationDeadlineNanos + "}";
}
}
@@ -630,6 +638,27 @@ public class SurfaceControl {
return nativeSetActiveConfig(displayToken, id);
}
+ public static int[] getDisplayColorModes(IBinder displayToken) {
+ if (displayToken == null) {
+ throw new IllegalArgumentException("displayToken must not be null");
+ }
+ return nativeGetDisplayColorModes(displayToken);
+ }
+
+ public static int getActiveColorMode(IBinder displayToken) {
+ if (displayToken == null) {
+ throw new IllegalArgumentException("displayToken must not be null");
+ }
+ return nativeGetActiveColorMode(displayToken);
+ }
+
+ public static boolean setActiveColorMode(IBinder displayToken, int colorMode) {
+ if (displayToken == null) {
+ throw new IllegalArgumentException("displayToken must not be null");
+ }
+ return nativeSetActiveColorMode(displayToken, colorMode);
+ }
+
public static void setDisplayProjection(IBinder displayToken,
int orientation, Rect layerStackRect, Rect displayRect) {
if (displayToken == null) {
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 203b82563ef86d3d308cf769e195763a57bc2be1..48189106f2c4a3b7d9621db6f6ab27dc6833d115 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -499,7 +499,7 @@ public class SurfaceView extends View {
| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
;
- if (!creating && !force && !mUpdateWindowNeeded && !sizeChanged) {
+ if (!creating && !force && !sizeChanged) {
mLayout.privateFlags |=
WindowManager.LayoutParams.PRIVATE_FLAG_PRESERVE_GEOMETRY;
} else {
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index e650d956915ac52afe53997b87d996bbecd73a85..2e0729be8b6368d075e8e5aaa29fb7ca24fa13fb 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -16,6 +16,7 @@
package android.view;
+import android.app.ActivityManagerNative;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.content.Context;
@@ -23,6 +24,7 @@ import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Point;
import android.graphics.Rect;
+import android.graphics.drawable.AnimatedVectorDrawable;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
@@ -517,16 +519,6 @@ public final class ThreadedRenderer {
}
}
- /**
- * This method should be invoked whenever the current hardware renderer
- * context should be reset.
- *
- * @param surface The surface to hardware accelerate
- */
- void invalidate(Surface surface) {
- updateSurface(surface);
- }
-
/**
* Detaches the layer's surface texture from the GL context and releases
* the texture id
@@ -881,6 +873,12 @@ public final class ThreadedRenderer {
nRegisterAnimatingRenderNode(mRootNode.mNativeRenderNode, animator.mNativeRenderNode);
}
+ void registerVectorDrawableAnimator(
+ AnimatedVectorDrawable.VectorDrawableAnimatorRT animator) {
+ nRegisterVectorDrawableAnimator(mRootNode.mNativeRenderNode,
+ animator.getAnimatorNativePtr());
+ }
+
public void serializeDisplayListTree() {
nSerializeDisplayListTree(mNativeProxy);
}
@@ -910,10 +908,20 @@ public final class ThreadedRenderer {
synchronized void init(Context context, long renderProxy) {
if (mInitialized) return;
mInitialized = true;
+ initSched(context, renderProxy);
initGraphicsStats(context, renderProxy);
initAssetAtlas(context, renderProxy);
}
+ private static void initSched(Context context, long renderProxy) {
+ try {
+ int tid = nGetRenderThreadTid(renderProxy);
+ ActivityManagerNative.getDefault().setRenderThread(tid);
+ } catch (Throwable t) {
+ Log.w(LOG_TAG, "Failed to set scheduler for RenderThread", t);
+ }
+ }
+
private static void initGraphicsStats(Context context, long renderProxy) {
try {
IBinder binder = ServiceManager.getService("graphicsstats");
@@ -972,6 +980,7 @@ public final class ThreadedRenderer {
private static native void nSetAtlas(long nativeProxy, GraphicBuffer buffer, long[] map);
private static native void nSetProcessStatsBuffer(long nativeProxy, int fd);
+ private static native int nGetRenderThreadTid(long nativeProxy);
private static native long nCreateRootRenderNode();
private static native long nCreateProxy(boolean translucent, long rootRenderNode);
@@ -992,6 +1001,7 @@ public final class ThreadedRenderer {
private static native int nSyncAndDrawFrame(long nativeProxy, long[] frameInfo, int size);
private static native void nDestroy(long nativeProxy, long rootRenderNode);
private static native void nRegisterAnimatingRenderNode(long rootRenderNode, long animatingNode);
+ private static native void nRegisterVectorDrawableAnimator(long rootRenderNode, long animator);
private static native void nInvokeFunctor(long functor, boolean waitForCompletion);
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index c9bb41288414ba00a329383957e6781ece631c0e..e757db7c22c31ae8e7f1fd9c5315fe55a42a60d8 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -40,6 +40,7 @@ import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
+import android.graphics.Color;
import android.graphics.Insets;
import android.graphics.Interpolator;
import android.graphics.LinearGradient;
@@ -819,6 +820,16 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*/
static boolean sTextureViewIgnoresDrawableSetters = false;
+ /**
+ * Prior to N, some ViewGroups would not convert LayoutParams properly even though both extend
+ * MarginLayoutParams. For instance, converting LinearLayout.LayoutParams to
+ * RelativeLayout.LayoutParams would lose margin information. This is fixed on N but target API
+ * check is implemented for backwards compatibility.
+ *
+ * {@hide}
+ */
+ protected static boolean sPreserveMarginParamsInLayoutParamConversion;
+
/**
* This view does not want keystrokes. Use with TAKES_FOCUS_MASK when
* calling setFlags.
@@ -2435,6 +2446,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* 1 PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE
* 1 PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED
* 1 PFLAG3_TEMPORARY_DETACH
+ * 1 PFLAG3_NO_REVEAL_ON_FOCUS
* |-------|-------|-------|-------|
*/
@@ -2676,6 +2688,16 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*/
static final int PFLAG3_TEMPORARY_DETACH = 0x2000000;
+ /**
+ * Flag indicating that the view does not wish to be revealed within its parent
+ * hierarchy when it gains focus. Expressed in the negative since the historical
+ * default behavior is to reveal on focus; this flag suppresses that behavior.
+ *
+ * @see #setRevealOnFocusHint(boolean)
+ * @see #getRevealOnFocusHint()
+ */
+ private static final int PFLAG3_NO_REVEAL_ON_FOCUS = 0x4000000;
+
/* End of masks for mPrivateFlags3 */
/**
@@ -3744,12 +3766,13 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
/**
* Flag indicating that a drag can cross window boundaries. When
* {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, int)} is called
- * with this flag set, all visible applications will be able to participate
+ * with this flag set, all visible applications with targetSdkVersion >=
+ * {@link android.os.Build.VERSION_CODES#N API 24} will be able to participate
* in the drag operation and receive the dragged content.
*
- * If this is the only flag set, then the drag recipient will only have access to text data
+ *
If this is the only flag set, then the drag recipient will only have access to text data
* and intents contained in the {@link ClipData} object. Access to URIs contained in the
- * {@link ClipData} is determined by other DRAG_FLAG_GLOBAL_* flags.
+ * {@link ClipData} is determined by other DRAG_FLAG_GLOBAL_* flags
*/
public static final int DRAG_FLAG_GLOBAL = 1 << 8; // 256
@@ -3979,6 +4002,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*/
String mStartActivityRequestWho;
+ @Nullable
+ private RoundScrollbarRenderer mRoundScrollbarRenderer;
+
/**
* Simple constructor to use when creating a view from code.
*
@@ -4036,6 +4062,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
// On N+, we throw, but that breaks compatibility with apps that use these methods.
sTextureViewIgnoresDrawableSetters = targetSdkVersion <= M;
+ // Prior to N, we would drop margins in LayoutParam conversions. The fix triggers bugs
+ // in apps so we target check it to avoid breaking existing apps.
+ sPreserveMarginParamsInLayoutParamConversion = targetSdkVersion >= N;
+
sCompatibilityDone = true;
}
}
@@ -4214,25 +4244,25 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
setAlpha(a.getFloat(attr, 1f));
break;
case com.android.internal.R.styleable.View_transformPivotX:
- setPivotX(a.getDimensionPixelOffset(attr, 0));
+ setPivotX(a.getDimension(attr, 0));
break;
case com.android.internal.R.styleable.View_transformPivotY:
- setPivotY(a.getDimensionPixelOffset(attr, 0));
+ setPivotY(a.getDimension(attr, 0));
break;
case com.android.internal.R.styleable.View_translationX:
- tx = a.getDimensionPixelOffset(attr, 0);
+ tx = a.getDimension(attr, 0);
transformSet = true;
break;
case com.android.internal.R.styleable.View_translationY:
- ty = a.getDimensionPixelOffset(attr, 0);
+ ty = a.getDimension(attr, 0);
transformSet = true;
break;
case com.android.internal.R.styleable.View_translationZ:
- tz = a.getDimensionPixelOffset(attr, 0);
+ tz = a.getDimension(attr, 0);
transformSet = true;
break;
case com.android.internal.R.styleable.View_elevation:
- elevation = a.getDimensionPixelOffset(attr, 0);
+ elevation = a.getDimension(attr, 0);
transformSet = true;
break;
case com.android.internal.R.styleable.View_rotation:
@@ -5939,6 +5969,47 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
}
+ /**
+ * Sets this view's preference for reveal behavior when it gains focus.
+ *
+ *
When set to true, this is a signal to ancestor views in the hierarchy that
+ * this view would prefer to be brought fully into view when it gains focus.
+ * For example, a text field that a user is meant to type into. Other views such
+ * as scrolling containers may prefer to opt-out of this behavior.
+ *
+ *
The default value for views is true, though subclasses may change this
+ * based on their preferred behavior.
+ *
+ * @param revealOnFocus true to request reveal on focus in ancestors, false otherwise
+ *
+ * @see #getRevealOnFocusHint()
+ */
+ public final void setRevealOnFocusHint(boolean revealOnFocus) {
+ if (revealOnFocus) {
+ mPrivateFlags3 &= ~PFLAG3_NO_REVEAL_ON_FOCUS;
+ } else {
+ mPrivateFlags3 |= PFLAG3_NO_REVEAL_ON_FOCUS;
+ }
+ }
+
+ /**
+ * Returns this view's preference for reveal behavior when it gains focus.
+ *
+ *
When this method returns true for a child view requesting focus, ancestor
+ * views responding to a focus change in {@link ViewParent#requestChildFocus(View, View)}
+ * should make a best effort to make the newly focused child fully visible to the user.
+ * When it returns false, ancestor views should preferably not disrupt scroll positioning or
+ * other properties affecting visibility to the user as part of the focus change.
+ *
+ * @return true if this view would prefer to become fully visible when it gains focus,
+ * false if it would prefer not to disrupt scroll positioning
+ *
+ * @see #setRevealOnFocusHint(boolean)
+ */
+ public final boolean getRevealOnFocusHint() {
+ return (mPrivateFlags3 & PFLAG3_NO_REVEAL_ON_FOCUS) == 0;
+ }
+
/**
* Populates outRect with the hotspot bounds. By default,
* the hotspot bounds are identical to the screen bounds.
@@ -9780,6 +9851,18 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
/**
+ * Tells whether the {@link View} is in the state between {@link #onStartTemporaryDetach()}
+ * and {@link #onFinishTemporaryDetach()}.
+ *
+ *
This method always returns {@code true} when called directly or indirectly from
+ * {@link #onStartTemporaryDetach()}. The return value when called directly or indirectly from
+ * {@link #onFinishTemporaryDetach()}, however, depends on the OS version.
+ *
+ *
{@code true} on {@link android.os.Build.VERSION_CODES#N API 24}
+ *
{@code false} on {@link android.os.Build.VERSION_CODES#N_MR1 API 25}} and later
+ *
+ *
+ *
* @return {@code true} when the View is in the state between {@link #onStartTemporaryDetach()}
* and {@link #onFinishTemporaryDetach()}.
*/
@@ -9814,8 +9897,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*/
@CallSuper
public void dispatchFinishTemporaryDetach() {
- onFinishTemporaryDetach();
mPrivateFlags3 &= ~PFLAG3_TEMPORARY_DETACH;
+ onFinishTemporaryDetach();
if (hasWindowFocus() && hasFocus()) {
InputMethodManager.getInstance().focusIn(this);
}
@@ -10302,7 +10385,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* ancestors or by window visibility
* @return true if this view is visible to the user, not counting clipping or overlapping
*/
- @Visibility boolean dispatchVisibilityAggregated(boolean isVisible) {
+ boolean dispatchVisibilityAggregated(boolean isVisible) {
final boolean thisVisible = getVisibility() == VISIBLE;
// If we're not visible but something is telling us we are, ignore it.
if (thisVisible || !isVisible) {
@@ -12309,6 +12392,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
public void setAlpha(@FloatRange(from=0.0, to=1.0) float alpha) {
ensureTransformationInfo();
if (mTransformationInfo.mAlpha != alpha) {
+ // Report visibility changes, which can affect children, to accessibility
+ if ((alpha == 0) ^ (mTransformationInfo.mAlpha == 0)) {
+ notifySubtreeAccessibilityStateChangedIfNeeded();
+ }
mTransformationInfo.mAlpha = alpha;
if (onSetAlpha((int) (alpha * 255))) {
mPrivateFlags |= PFLAG_ALPHA_SET;
@@ -12319,8 +12406,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
mPrivateFlags &= ~PFLAG_ALPHA_SET;
invalidateViewProperty(true, false);
mRenderNode.setAlpha(getFinalAlpha());
- notifyViewAccessibilityStateChangedIfNeeded(
- AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
}
}
}
@@ -14720,6 +14805,25 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
private void getVerticalScrollBarBounds(Rect bounds) {
+ if (mRoundScrollbarRenderer == null) {
+ getStraightVerticalScrollBarBounds(bounds);
+ } else {
+ getRoundVerticalScrollBarBounds(bounds);
+ }
+ }
+
+ private void getRoundVerticalScrollBarBounds(Rect bounds) {
+ final int width = mRight - mLeft;
+ final int height = mBottom - mTop;
+ // Do not take padding into account as we always want the scrollbars
+ // to hug the screen for round wearable devices.
+ bounds.left = mScrollX;
+ bounds.top = mScrollY;
+ bounds.right = bounds.left + width;
+ bounds.bottom = mScrollY + height;
+ }
+
+ private void getStraightVerticalScrollBarBounds(Rect bounds) {
final int inside = (mViewFlags & SCROLLBARS_OUTSIDE_MASK) == 0 ? ~0 : 0;
final int size = getVerticalScrollbarWidth();
int verticalScrollbarPosition = mVerticalScrollbarPosition;
@@ -14754,6 +14858,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
protected final void onDrawScrollBars(Canvas canvas) {
// scrollbars are drawn only when the animation is running
final ScrollabilityCache cache = mScrollCache;
+
if (cache != null) {
int state = cache.state;
@@ -14794,13 +14899,25 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
final boolean drawVerticalScrollBar = isVerticalScrollBarEnabled()
&& !isVerticalScrollBarHidden();
- if (drawVerticalScrollBar || drawHorizontalScrollBar) {
+ // Fork out the scroll bar drawing for round wearable devices.
+ if (mRoundScrollbarRenderer != null) {
+ if (drawVerticalScrollBar) {
+ final Rect bounds = cache.mScrollBarBounds;
+ getVerticalScrollBarBounds(bounds);
+ mRoundScrollbarRenderer.drawRoundScrollbars(
+ canvas, (float) cache.scrollBar.getAlpha() / 255f, bounds);
+ if (invalidate) {
+ invalidate();
+ }
+ }
+ // Do not draw horizontal scroll bars for round wearable devices.
+ } else if (drawVerticalScrollBar || drawHorizontalScrollBar) {
final ScrollBarDrawable scrollBar = cache.scrollBar;
if (drawHorizontalScrollBar) {
scrollBar.setParameters(computeHorizontalScrollRange(),
- computeHorizontalScrollOffset(),
- computeHorizontalScrollExtent(), false);
+ computeHorizontalScrollOffset(),
+ computeHorizontalScrollExtent(), false);
final Rect bounds = cache.mScrollBarBounds;
getHorizontalScrollBarBounds(bounds);
onDrawHorizontalScrollBar(canvas, scrollBar, bounds.left, bounds.top,
@@ -14812,8 +14929,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
if (drawVerticalScrollBar) {
scrollBar.setParameters(computeVerticalScrollRange(),
- computeVerticalScrollOffset(),
- computeVerticalScrollExtent(), true);
+ computeVerticalScrollOffset(),
+ computeVerticalScrollExtent(), true);
final Rect bounds = cache.mScrollBarBounds;
getVerticalScrollBarBounds(bounds);
onDrawVerticalScrollBar(canvas, scrollBar, bounds.left, bounds.top,
@@ -15414,7 +15531,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
if (vis != GONE) {
onWindowVisibilityChanged(vis);
if (isShown()) {
- // Calling onVisibilityChanged directly here since the subtree will also
+ // Calling onVisibilityAggregated directly here since the subtree will also
// receive dispatchAttachedToWindow and this same call
onVisibilityAggregated(vis == VISIBLE);
}
@@ -17524,6 +17641,15 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
if (changed || (mPrivateFlags & PFLAG_LAYOUT_REQUIRED) == PFLAG_LAYOUT_REQUIRED) {
onLayout(changed, l, t, r, b);
+
+ if (shouldDrawRoundScrollbar()) {
+ if(mRoundScrollbarRenderer == null) {
+ mRoundScrollbarRenderer = new RoundScrollbarRenderer(this);
+ }
+ } else {
+ mRoundScrollbarRenderer = null;
+ }
+
mPrivateFlags &= ~PFLAG_LAYOUT_REQUIRED;
ListenerInfo li = mListenerInfo;
@@ -20540,7 +20666,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*
@@ -22857,7 +22982,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
/**
* Last global system UI visibility reported by the window manager.
*/
- int mGlobalSystemUiVisibility;
+ int mGlobalSystemUiVisibility = -1;
/**
* True if a view in this hierarchy has an OnSystemUiVisibilityChangeListener
@@ -22904,7 +23029,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
final int[] mInvalidateChildLocation = new int[2];
/**
- * Global to the view hierarchy used as a temporary for dealng with
+ * Global to the view hierarchy used as a temporary for dealing with
* computing absolute on-screen location.
*/
final int[] mTmpLocation = new int[2];
@@ -23742,4 +23867,30 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
stream.addProperty("accessibility:labelFor", getLabelFor());
stream.addProperty("accessibility:importantForAccessibility", getImportantForAccessibility());
}
+
+ /**
+ * Determine if this view is rendered on a round wearable device and is the main view
+ * on the screen.
+ */
+ private boolean shouldDrawRoundScrollbar() {
+ if (!mResources.getConfiguration().isScreenRound()) {
+ return false;
+ }
+
+ final View rootView = getRootView();
+ final WindowInsets insets = getRootWindowInsets();
+
+ int height = getHeight();
+ int width = getWidth();
+ int displayHeight = rootView.getHeight();
+ int displayWidth = rootView.getWidth();
+
+ if (height != displayHeight || width != displayWidth) {
+ return false;
+ }
+
+ getLocationOnScreen(mAttachInfo.mTmpLocation);
+ return mAttachInfo.mTmpLocation[0] == insets.getStableInsetLeft()
+ && mAttachInfo.mTmpLocation[1] == insets.getStableInsetTop();
+ }
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 14eeadf662213c20fae86cf11ec8913eb96e1b4d..e7c613a0ca406e72d445e304854d6ae19a9adace 100755
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -44,6 +44,7 @@ import android.graphics.PointF;
import android.graphics.PorterDuff;
import android.graphics.Rect;
import android.graphics.Region;
+import android.graphics.drawable.AnimatedVectorDrawable;
import android.graphics.drawable.Drawable;
import android.hardware.display.DisplayManager;
import android.hardware.display.DisplayManager.DisplayListener;
@@ -822,6 +823,13 @@ public final class ViewRootImpl implements ViewParent,
}
}
+ public void registerVectorDrawableAnimator(
+ AnimatedVectorDrawable.VectorDrawableAnimatorRT animator) {
+ if (mAttachInfo.mHardwareRenderer != null) {
+ mAttachInfo.mHardwareRenderer.registerVectorDrawableAnimator(animator);
+ }
+ }
+
private void enableHardwareAcceleration(WindowManager.LayoutParams attrs) {
mAttachInfo.mHardwareAccelerated = false;
mAttachInfo.mHardwareAccelerationRequested = false;
@@ -1459,6 +1467,8 @@ public final class ViewRootImpl implements ViewParent,
final int viewVisibility = getHostVisibility();
final boolean viewVisibilityChanged = !mFirst
&& (mViewVisibility != viewVisibility || mNewSurfaceNeeded);
+ final boolean viewUserVisibilityChanged = !mFirst &&
+ ((mViewVisibility == View.VISIBLE) != (viewVisibility == View.VISIBLE));
WindowManager.LayoutParams params = null;
if (mWindowAttributesChanged) {
@@ -1532,7 +1542,9 @@ public final class ViewRootImpl implements ViewParent,
if (viewVisibilityChanged) {
mAttachInfo.mWindowVisibility = viewVisibility;
host.dispatchWindowVisibilityChanged(viewVisibility);
- host.dispatchVisibilityAggregated(viewVisibility == View.VISIBLE);
+ if (viewUserVisibilityChanged) {
+ host.dispatchVisibilityAggregated(viewVisibility == View.VISIBLE);
+ }
if (viewVisibility != View.VISIBLE || mNewSurfaceNeeded) {
endDragResizing();
destroyHardwareResources();
@@ -1723,7 +1735,7 @@ public final class ViewRootImpl implements ViewParent,
}
boolean hwInitialized = false;
- boolean framesChanged = false;
+ boolean contentInsetsChanged = false;
boolean hadSurface = mSurface.isValid();
try {
@@ -1763,7 +1775,7 @@ public final class ViewRootImpl implements ViewParent,
final boolean overscanInsetsChanged = !mPendingOverscanInsets.equals(
mAttachInfo.mOverscanInsets);
- boolean contentInsetsChanged = !mPendingContentInsets.equals(
+ contentInsetsChanged = !mPendingContentInsets.equals(
mAttachInfo.mContentInsets);
final boolean visibleInsetsChanged = !mPendingVisibleInsets.equals(
mAttachInfo.mVisibleInsets);
@@ -1813,19 +1825,6 @@ public final class ViewRootImpl implements ViewParent,
+ mAttachInfo.mVisibleInsets);
}
- // If any of the insets changed, do a forceLayout on the view so that the
- // measure cache is cleared. We might have a pending MSG_RESIZED_REPORT
- // that is supposed to take care of it, but since pending insets are
- // already modified here, it won't detect the frame change after this.
- framesChanged = overscanInsetsChanged
- || contentInsetsChanged
- || stableInsetsChanged
- || visibleInsetsChanged
- || outsetsChanged;
- if (mAdded && mView != null && framesChanged) {
- forceLayout(mView);
- }
-
if (!hadSurface) {
if (mSurface.isValid()) {
// If we are creating a new surface, then we need to
@@ -2009,7 +2008,7 @@ public final class ViewRootImpl implements ViewParent,
boolean focusChangedDueToTouchMode = ensureTouchModeLocally(
(relayoutResult&WindowManagerGlobal.RELAYOUT_RES_IN_TOUCH_MODE) != 0);
if (focusChangedDueToTouchMode || mWidth != host.getMeasuredWidth()
- || mHeight != host.getMeasuredHeight() || framesChanged ||
+ || mHeight != host.getMeasuredHeight() || contentInsetsChanged ||
updatedConfiguration) {
int childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width);
int childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height);
@@ -2018,7 +2017,7 @@ public final class ViewRootImpl implements ViewParent,
+ mWidth + " measuredWidth=" + host.getMeasuredWidth()
+ " mHeight=" + mHeight
+ " measuredHeight=" + host.getMeasuredHeight()
- + " framesChanged=" + framesChanged);
+ + " coveredInsetsChanged=" + contentInsetsChanged);
// Ask host how big it wants to be
performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
@@ -3178,7 +3177,7 @@ public final class ViewRootImpl implements ViewParent,
}
focusNode.recycle();
}
- if (mAccessibilityFocusedHost != null) {
+ if ((mAccessibilityFocusedHost != null) && (mAccessibilityFocusedHost != view)) {
// Clear accessibility focus in the view.
mAccessibilityFocusedHost.clearAccessibilityFocusNoCallbacks(
AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS);
@@ -5513,6 +5512,15 @@ public final class ViewRootImpl implements ViewParent,
if (mView != null && mAdded) {
final int what = event.mAction;
+ // Cache the drag description when the operation starts, then fill it in
+ // on subsequent calls as a convenience
+ if (what == DragEvent.ACTION_DRAG_STARTED) {
+ mCurrentDragView = null; // Start the current-recipient tracking
+ mDragDescription = event.mClipDescription;
+ } else {
+ event.mClipDescription = mDragDescription;
+ }
+
if (what == DragEvent.ACTION_DRAG_EXITED) {
// A direct EXITED event means that the window manager knows we've just crossed
// a window boundary, so the current drag target within this one must have
@@ -5520,15 +5528,6 @@ public final class ViewRootImpl implements ViewParent,
// for now.
mView.dispatchDragEvent(event);
} else {
- // Cache the drag description when the operation starts, then fill it in
- // on subsequent calls as a convenience
- if (what == DragEvent.ACTION_DRAG_STARTED) {
- mCurrentDragView = null; // Start the current-recipient tracking
- mDragDescription = event.mClipDescription;
- } else {
- event.mClipDescription = mDragDescription;
- }
-
// For events with a [screen] location, translate into window coordinates
if ((what == DragEvent.ACTION_DRAG_LOCATION) || (what == DragEvent.ACTION_DROP)) {
mDragPoint.set(event.mX, event.mY);
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 26803b8ce89e76c69f7c0e5d3794e5a9ca850a09..14f9fcc3c2e62a5d572685e361b0addb186159af 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -221,6 +221,7 @@ public interface WindowManager extends ViewManager {
* @see #TYPE_BASE_APPLICATION
* @see #TYPE_APPLICATION
* @see #TYPE_APPLICATION_STARTING
+ * @see #TYPE_DRAWN_APPLICATION
* @see #TYPE_APPLICATION_PANEL
* @see #TYPE_APPLICATION_MEDIA
* @see #TYPE_APPLICATION_SUB_PANEL
@@ -245,6 +246,7 @@ public interface WindowManager extends ViewManager {
@ViewDebug.IntToString(from = TYPE_BASE_APPLICATION, to = "TYPE_BASE_APPLICATION"),
@ViewDebug.IntToString(from = TYPE_APPLICATION, to = "TYPE_APPLICATION"),
@ViewDebug.IntToString(from = TYPE_APPLICATION_STARTING, to = "TYPE_APPLICATION_STARTING"),
+ @ViewDebug.IntToString(from = TYPE_DRAWN_APPLICATION, to = "TYPE_DRAWN_APPLICATION"),
@ViewDebug.IntToString(from = TYPE_APPLICATION_PANEL, to = "TYPE_APPLICATION_PANEL"),
@ViewDebug.IntToString(from = TYPE_APPLICATION_MEDIA, to = "TYPE_APPLICATION_MEDIA"),
@ViewDebug.IntToString(from = TYPE_APPLICATION_SUB_PANEL, to = "TYPE_APPLICATION_SUB_PANEL"),
@@ -316,6 +318,13 @@ public interface WindowManager extends ViewManager {
*/
public static final int TYPE_APPLICATION_STARTING = 3;
+ /**
+ * Window type: a variation on TYPE_APPLICATION that ensures the window
+ * manager will wait for this window to be drawn before the app is shown.
+ * In multiuser systems shows only on the owning user's window.
+ */
+ public static final int TYPE_DRAWN_APPLICATION = 4;
+
/**
* End of types of application windows.
*/
@@ -638,7 +647,7 @@ public interface WindowManager extends ViewManager {
/**
* Window type: shares similar characteristics with {@link #TYPE_DREAM}. The layer is
- * reserved for screenshot region selection.
+ * reserved for screenshot region selection. These windows must not take input focus.
* @hide
*/
public static final int TYPE_SCREENSHOT = FIRST_SYSTEM_WINDOW + 36;
@@ -1612,6 +1621,15 @@ public interface WindowManager extends ViewManager {
*/
public static final int ROTATION_ANIMATION_JUMPCUT = 2;
+ /**
+ * Value for {@link #rotationAnimation} to specify seamless rotation mode.
+ * This works like JUMPCUT but will fall back to CROSSFADE if rotation
+ * can't be applied without pausing the screen.
+ *
+ * @hide
+ */
+ public static final int ROTATION_ANIMATION_SEAMLESS = 3;
+
/**
* Define the exit and entry animations used on this window when the device is rotated.
* This only has an affect if the incoming and outgoing topmost
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index 11d4f93f7cdb51f28ee5e1362f25deae856215a9..8269be29dcc323caee66037998cedd8233a43b2e 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -135,6 +135,12 @@ public interface WindowManagerPolicy {
void registerShortcutKey(long shortcutCode, IShortcutService shortcutKeyReceiver)
throws RemoteException;
+ /**
+ * @return true if windows with FLAG_DISMISS_KEYGUARD should be allowed to show even if
+ * the keyguard is locked.
+ */
+ boolean canShowDismissingWindowWhileLockedLw();
+
/**
* Interface to the Window Manager state associated with a particular
* window. You can hold on to an instance of this interface from the call
@@ -416,6 +422,8 @@ public interface WindowManagerPolicy {
* screen with other application windows.
*/
public boolean isInMultiWindowMode();
+
+ public int getRotationAnimationHint();
}
/**
@@ -476,6 +484,7 @@ public interface WindowManagerPolicy {
public void switchInputMethod(boolean forwardDirection);
public void shutdown(boolean confirm);
+ public void reboot(boolean confirm);
public void rebootSafeMode(boolean confirm);
/**
@@ -1417,4 +1426,6 @@ public interface WindowManagerPolicy {
* Called when the configuration has changed, and it's safe to load new values from resources.
*/
public void onConfigurationChanged();
+
+ public boolean shouldRotateSeamlessly(int oldRotation, int newRotation);
}
diff --git a/core/java/android/view/accessibility/AccessibilityManager.java b/core/java/android/view/accessibility/AccessibilityManager.java
index 81ec3306c4c740fad4f78958803d89ef08537c9f..2dfa8cdd3db9e6850286607f6aa67f1307575df3 100644
--- a/core/java/android/view/accessibility/AccessibilityManager.java
+++ b/core/java/android/view/accessibility/AccessibilityManager.java
@@ -305,7 +305,18 @@ public final class AccessibilityManager {
return;
}
if (!mIsEnabled) {
- throw new IllegalStateException("Accessibility off. Did you forget to check that?");
+ Looper myLooper = Looper.myLooper();
+ if (myLooper == Looper.getMainLooper()) {
+ throw new IllegalStateException(
+ "Accessibility off. Did you forget to check that?");
+ } else {
+ // If we're not running on the thread with the main looper, it's possible for
+ // the state of accessibility to change between checking isEnabled and
+ // calling this method. So just log the error rather than throwing the
+ // exception.
+ Log.e(LOG_TAG, "AccessibilityEvent sent with accessibility disabled");
+ return;
+ }
}
userId = mUserId;
}
diff --git a/core/java/android/view/animation/AnimationUtils.java b/core/java/android/view/animation/AnimationUtils.java
index a54d94c5c2e322fe9c156745083549b01b2792a1..351b6dbd66162ad595ddef1a1dc4a7c9676e1b4a 100644
--- a/core/java/android/view/animation/AnimationUtils.java
+++ b/core/java/android/view/animation/AnimationUtils.java
@@ -44,6 +44,31 @@ public class AnimationUtils {
private static final int TOGETHER = 0;
private static final int SEQUENTIALLY = 1;
+ private static class AnimationState {
+ boolean animationClockLocked;
+ long currentVsyncTimeMillis;
+ long lastReportedTimeMillis;
+ };
+
+ private static ThreadLocal sAnimationState
+ = new ThreadLocal() {
+ @Override
+ protected AnimationState initialValue() {
+ return new AnimationState();
+ }
+ };
+
+ /** @hide */
+ public static void lockAnimationClock(long vsyncMillis) {
+ AnimationState state = sAnimationState.get();
+ state.animationClockLocked = true;
+ state.currentVsyncTimeMillis = vsyncMillis;
+ }
+
+ /** @hide */
+ public static void unlockAnimationClock() {
+ sAnimationState.get().animationClockLocked = false;
+ }
/**
* Returns the current animation time in milliseconds. This time should be used when invoking
@@ -56,7 +81,14 @@ public class AnimationUtils {
* @see android.os.SystemClock
*/
public static long currentAnimationTimeMillis() {
- return SystemClock.uptimeMillis();
+ AnimationState state = sAnimationState.get();
+ if (state.animationClockLocked) {
+ // It's important that time never rewinds
+ return Math.max(state.currentVsyncTimeMillis,
+ state.lastReportedTimeMillis);
+ }
+ state.lastReportedTimeMillis = SystemClock.uptimeMillis();
+ return state.lastReportedTimeMillis;
}
/**
diff --git a/core/java/android/view/inputmethod/BaseInputConnection.java b/core/java/android/view/inputmethod/BaseInputConnection.java
index 89dec2d22d7a74abf37d0833d72643ed0ef1ac6e..38962a36dd701155d2d39241dd873d4758adbb8f 100644
--- a/core/java/android/view/inputmethod/BaseInputConnection.java
+++ b/core/java/android/view/inputmethod/BaseInputConnection.java
@@ -851,4 +851,11 @@ public class BaseInputConnection implements InputConnection {
endBatchEdit();
}
+
+ /**
+ * The default implementation does nothing.
+ */
+ public boolean commitContent(InputContentInfo inputContentInfo, int flags, Bundle opts) {
+ return false;
+ }
}
diff --git a/core/java/android/view/inputmethod/EditorInfo.java b/core/java/android/view/inputmethod/EditorInfo.java
index 7b7ccae62dede0f5b6ab07b82d80e6d6687b249b..80380897fd398a6057ea1c960d27fa5278d14e3f 100644
--- a/core/java/android/view/inputmethod/EditorInfo.java
+++ b/core/java/android/view/inputmethod/EditorInfo.java
@@ -25,6 +25,8 @@ import android.text.InputType;
import android.text.TextUtils;
import android.util.Printer;
+import java.util.Arrays;
+
/**
* An EditorInfo describes several attributes of a text editing object
* that an input method is communicating with (typically an EditText), most
@@ -363,6 +365,18 @@ public class EditorInfo implements InputType, Parcelable {
@Nullable
public LocaleList hintLocales = null;
+
+ /**
+ * List of acceptable MIME types for
+ * {@link InputConnection#commitContent(InputContentInfo, int, Bundle)}.
+ *
+ *
{@code null} or an empty array means that
+ * {@link InputConnection#commitContent(InputContentInfo, int, Bundle)} is not supported in this
+ * editor.
+ */
+ @Nullable
+ public String[] contentMimeTypes = null;
+
/**
* Ensure that the data in this EditorInfo is compatible with an application
* that was developed against the given target API version. This can
@@ -418,6 +432,7 @@ public class EditorInfo implements InputType, Parcelable {
+ " fieldName=" + fieldName);
pw.println(prefix + "extras=" + extras);
pw.println(prefix + "hintLocales=" + hintLocales);
+ pw.println(prefix + "contentMimeTypes=" + Arrays.toString(contentMimeTypes));
}
/**
@@ -446,6 +461,7 @@ public class EditorInfo implements InputType, Parcelable {
} else {
LocaleList.getEmptyLocaleList().writeToParcel(dest, flags);
}
+ dest.writeStringArray(contentMimeTypes);
}
/**
@@ -471,6 +487,7 @@ public class EditorInfo implements InputType, Parcelable {
res.extras = source.readBundle();
LocaleList hintLocales = LocaleList.CREATOR.createFromParcel(source);
res.hintLocales = hintLocales.isEmpty() ? null : hintLocales;
+ res.contentMimeTypes = source.readStringArray();
return res;
}
diff --git a/core/java/android/view/inputmethod/InputConnection.java b/core/java/android/view/inputmethod/InputConnection.java
index 9f664293476835b2eb8f6f54d0340deb1b3d092b..07910b60df3fd0b872149783057a36264de56348 100644
--- a/core/java/android/view/inputmethod/InputConnection.java
+++ b/core/java/android/view/inputmethod/InputConnection.java
@@ -16,6 +16,8 @@
package android.view.inputmethod;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.os.Bundle;
import android.os.Handler;
import android.view.KeyCharacterMap;
@@ -836,4 +838,53 @@ public interface InputConnection {
*
Note: This does nothing when called from input methods.
*/
public void closeConnection();
+
+ /**
+ * When this flag is used, the editor will be able to request read access to the content URI
+ * contained in the {@link InputContentInfo} object.
+ *
+ *
Make sure that the content provider owning the Uri sets the
+ * {@link android.R.styleable#AndroidManifestProvider_grantUriPermissions
+ * grantUriPermissions} attribute in its manifest or included the
+ * {@link android.R.styleable#AndroidManifestGrantUriPermission
+ * <grant-uri-permissions>} tag. Otherwise {@link InputContentInfo#requestPermission()}
+ * can fail.
+ *
+ *
Although calling this API is allowed only for the IME that is currently selected, the
+ * client is able to request a temporary read-only access even after the current IME is switched
+ * to any other IME as long as the client keeps {@link InputContentInfo} object.
+ **/
+ public static int INPUT_CONTENT_GRANT_READ_URI_PERMISSION =
+ android.content.Intent.FLAG_GRANT_READ_URI_PERMISSION; // 0x00000001
+
+ /**
+ * Called by the input method to commit a content such as PNG image to the editor.
+ *
+ *
In order to avoid variety of compatibility issues, this focuses on a simple use case,
+ * where we expect editors and IMEs work cooperatively as follows:
+ *
+ *
Editor must keep {@link EditorInfo#contentMimeTypes} to be {@code null} if it does
+ * not support this method at all.
+ *
Editor can ignore this request when the MIME type specified in
+ * {@code inputContentInfo} does not match to any of {@link EditorInfo#contentMimeTypes}.
+ *
+ *
Editor can ignore the cursor position when inserting the provided context.
+ *
Editor can return {@code true} asynchronously, even before it starts loading the
+ * content.
+ *
Editor should provide a way to delete the content inserted by this method, or revert
+ * the effect caused by this method.
+ *
IME should not call this method when there is any composing text, in case calling
+ * this method causes focus change.
+ *
IME should grant a permission for the editor to read the content. See
+ * {@link EditorInfo#packageName} about how to obtain the package name of the editor.
+ *
+ *
+ * @param inputContentInfo Content to be inserted.
+ * @param flags {@code 0} or {@link #INPUT_CONTENT_GRANT_READ_URI_PERMISSION}.
+ * @param opts optional bundle data. This can be {@code null}.
+ * @return {@code true} if this request is accepted by the application, no matter if the request
+ * is already handled or still being handled in background.
+ */
+ public boolean commitContent(@NonNull InputContentInfo inputContentInfo, int flags,
+ @Nullable Bundle opts);
}
diff --git a/core/java/android/view/inputmethod/InputConnectionInspector.java b/core/java/android/view/inputmethod/InputConnectionInspector.java
index 118a61f8d571c3d447b694971144bffd5dcd6d85..2b292bbca84993c269c455379208365224b0bbbf 100644
--- a/core/java/android/view/inputmethod/InputConnectionInspector.java
+++ b/core/java/android/view/inputmethod/InputConnectionInspector.java
@@ -19,6 +19,7 @@ package android.view.inputmethod;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.os.Bundle;
import java.lang.annotation.Retention;
import java.lang.reflect.Method;
@@ -41,6 +42,8 @@ public final class InputConnectionInspector {
MissingMethodFlags.REQUEST_CURSOR_UPDATES,
MissingMethodFlags.DELETE_SURROUNDING_TEXT_IN_CODE_POINTS,
MissingMethodFlags.GET_HANDLER,
+ MissingMethodFlags.CLOSE_CONNECTION,
+ MissingMethodFlags.COMMIT_CONTENT,
})
public @interface MissingMethodFlags {
/**
@@ -78,6 +81,11 @@ public final class InputConnectionInspector {
* {@link android.os.Build.VERSION_CODES#N} and later.
*/
int CLOSE_CONNECTION = 1 << 6;
+ /**
+ * {@link InputConnection#commitContent(InputContentInfo, int, Bundle)} is available in
+ * {@link android.os.Build.VERSION_CODES#N} MR-1 and later.
+ */
+ int COMMIT_CONTENT = 1 << 7;
}
private static final Map sMissingMethodsMap = Collections.synchronizedMap(
@@ -127,6 +135,9 @@ public final class InputConnectionInspector {
if (!hasCloseConnection(clazz)) {
flags |= MissingMethodFlags.CLOSE_CONNECTION;
}
+ if (!hasCommitContent(clazz)) {
+ flags |= MissingMethodFlags.COMMIT_CONTENT;
+ }
sMissingMethodsMap.put(clazz, flags);
return flags;
}
@@ -195,6 +206,16 @@ public final class InputConnectionInspector {
}
}
+ private static boolean hasCommitContent(@NonNull final Class clazz) {
+ try {
+ final Method method = clazz.getMethod("commitContent", InputContentInfo.class,
+ int.class, Bundle.class);
+ return !Modifier.isAbstract(method.getModifiers());
+ } catch (NoSuchMethodException e) {
+ return false;
+ }
+ }
+
public static String getMissingMethodFlagsAsString(@MissingMethodFlags final int flags) {
final StringBuilder sb = new StringBuilder();
boolean isEmpty = true;
@@ -242,6 +263,12 @@ public final class InputConnectionInspector {
}
sb.append("closeConnection()");
}
+ if ((flags & MissingMethodFlags.COMMIT_CONTENT) != 0) {
+ if (!isEmpty) {
+ sb.append(",");
+ }
+ sb.append("commitContent(InputContentInfo, Bundle)");
+ }
return sb.toString();
}
}
diff --git a/core/java/android/view/inputmethod/InputConnectionWrapper.java b/core/java/android/view/inputmethod/InputConnectionWrapper.java
index e743f62a5a0a6df97288951d4acdc5e6e1d7f51b..317730ca092c6752bef971b15e2f97d52b0cd4b8 100644
--- a/core/java/android/view/inputmethod/InputConnectionWrapper.java
+++ b/core/java/android/view/inputmethod/InputConnectionWrapper.java
@@ -269,4 +269,12 @@ public class InputConnectionWrapper implements InputConnection {
public void closeConnection() {
mTarget.closeConnection();
}
+
+ /**
+ * {@inheritDoc}
+ * @throws NullPointerException if the target is {@code null}.
+ */
+ public boolean commitContent(InputContentInfo inputContentInfo, int flags, Bundle opts) {
+ return mTarget.commitContent(inputContentInfo, flags, opts);
+ }
}
diff --git a/core/java/android/view/inputmethod/InputContentInfo.aidl b/core/java/android/view/inputmethod/InputContentInfo.aidl
new file mode 100644
index 0000000000000000000000000000000000000000..1afeee3b4b245692e760e38229966456dddae54d
--- /dev/null
+++ b/core/java/android/view/inputmethod/InputContentInfo.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.inputmethod;
+
+parcelable InputContentInfo;
diff --git a/core/java/android/view/inputmethod/InputContentInfo.java b/core/java/android/view/inputmethod/InputContentInfo.java
new file mode 100644
index 0000000000000000000000000000000000000000..b39705e0b1fa686b1d6ceabc3ee9a1e10a5e27df
--- /dev/null
+++ b/core/java/android/view/inputmethod/InputContentInfo.java
@@ -0,0 +1,250 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package android.view.inputmethod;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.ClipDescription;
+import android.net.Uri;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.RemoteException;
+
+import com.android.internal.inputmethod.IInputContentUriToken;
+
+import java.security.InvalidParameterException;
+
+/**
+ * A container object with which input methods can send content files to the target application.
+ */
+public final class InputContentInfo implements Parcelable {
+
+ @NonNull
+ private final Uri mContentUri;
+ @NonNull
+ private final ClipDescription mDescription;
+ @Nullable
+ private final Uri mLinkUri;
+ @NonNull
+ private IInputContentUriToken mUriToken;
+
+ /**
+ * Constructs {@link InputContentInfo} object only with mandatory data.
+ *
+ * @param contentUri Content URI to be exported from the input method.
+ * This cannot be {@code null}.
+ * @param description A {@link ClipDescription} object that contains the metadata of
+ * {@code contentUri} such as MIME type(s). This object cannot be {@code null}. Also
+ * {@link ClipDescription#getLabel()} should be describing the content specified by
+ * {@code contentUri} for accessibility reasons.
+ */
+ public InputContentInfo(@NonNull Uri contentUri, @NonNull ClipDescription description) {
+ this(contentUri, description, null /* link Uri */);
+ }
+
+ /**
+ * Constructs {@link InputContentInfo} object with additional link URI.
+ *
+ * @param contentUri Content URI to be exported from the input method.
+ * This cannot be {@code null}.
+ * @param description A {@link ClipDescription} object that contains the metadata of
+ * {@code contentUri} such as MIME type(s). This object cannot be {@code null}. Also
+ * {@link ClipDescription#getLabel()} should be describing the content specified by
+ * {@code contentUri} for accessibility reasons.
+ * @param linkUri An optional {@code http} or {@code https} URI. The editor author may provide
+ * a way to navigate the user to the specified web page if this is not {@code null}.
+ * @throws InvalidParameterException if any invalid parameter is specified.
+ */
+ public InputContentInfo(@NonNull Uri contentUri, @NonNull ClipDescription description,
+ @Nullable Uri linkUri) {
+ validateInternal(contentUri, description, linkUri, true /* throwException */);
+ mContentUri = contentUri;
+ mDescription = description;
+ mLinkUri = linkUri;
+ }
+
+ /**
+ * @return {@code true} if all the fields are valid.
+ * @hide
+ */
+ public boolean validate() {
+ return validateInternal(mContentUri, mDescription, mLinkUri, false /* throwException */);
+ }
+
+ /**
+ * Constructs {@link InputContentInfo} object with additional link URI.
+ *
+ * @param contentUri Content URI to be exported from the input method.
+ * This cannot be {@code null}.
+ * @param description A {@link ClipDescription} object that contains the metadata of
+ * {@code contentUri} such as MIME type(s). This object cannot be {@code null}. Also
+ * {@link ClipDescription#getLabel()} should be describing the content specified by
+ * {@code contentUri} for accessibility reasons.
+ * @param linkUri An optional {@code http} or {@code https} URI. The editor author may provide
+ * a way to navigate the user to the specified web page if this is not {@code null}.
+ * @param throwException {@code true} if this method should throw an
+ * {@link InvalidParameterException}.
+ * @throws InvalidParameterException if any invalid parameter is specified.
+ */
+ private static boolean validateInternal(@NonNull Uri contentUri,
+ @NonNull ClipDescription description, @Nullable Uri linkUri, boolean throwException) {
+ if (contentUri == null) {
+ if (throwException) {
+ throw new NullPointerException("contentUri");
+ }
+ return false;
+ }
+ if (description == null) {
+ if (throwException) {
+ throw new NullPointerException("description");
+ }
+ return false;
+ }
+ final String contentUriScheme = contentUri.getScheme();
+ if (!"content".equals(contentUriScheme)) {
+ if (throwException) {
+ throw new InvalidParameterException("contentUri must have content scheme");
+ }
+ return false;
+ }
+ if (linkUri != null) {
+ final String scheme = linkUri.getScheme();
+ if (scheme == null ||
+ (!scheme.equalsIgnoreCase("http") && !scheme.equalsIgnoreCase("https"))) {
+ if (throwException) {
+ throw new InvalidParameterException(
+ "linkUri must have either http or https scheme");
+ }
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * @return Content URI with which the content can be obtained.
+ */
+ @NonNull
+ public Uri getContentUri() { return mContentUri; }
+
+ /**
+ * @return {@link ClipDescription} object that contains the metadata of {@code #getContentUri()}
+ * such as MIME type(s). {@link ClipDescription#getLabel()} can be used for accessibility
+ * purpose.
+ */
+ @NonNull
+ public ClipDescription getDescription() { return mDescription; }
+
+ /**
+ * @return An optional {@code http} or {@code https} URI that is related to this content.
+ */
+ @Nullable
+ public Uri getLinkUri() { return mLinkUri; }
+
+ void setUriToken(IInputContentUriToken token) {
+ if (mUriToken != null) {
+ throw new IllegalStateException("URI token is already set");
+ }
+ mUriToken = token;
+ }
+
+ /**
+ * Requests a temporary read-only access permission for content URI associated with this object.
+ *
+ *
Does nothing if the temporary permission is already granted.
+ */
+ public void requestPermission() {
+ if (mUriToken == null) {
+ return;
+ }
+ try {
+ mUriToken.take();
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Releases a temporary read-only access permission for content URI associated with this object.
+ *
+ *
Does nothing if the temporary permission is not granted.
+ */
+ public void releasePermission() {
+ if (mUriToken == null) {
+ return;
+ }
+ try {
+ mUriToken.release();
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Used to package this object into a {@link Parcel}.
+ *
+ * @param dest The {@link Parcel} to be written.
+ * @param flags The flags used for parceling.
+ */
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ Uri.writeToParcel(dest, mContentUri);
+ mDescription.writeToParcel(dest, flags);
+ Uri.writeToParcel(dest, mLinkUri);
+ if (mUriToken != null) {
+ dest.writeInt(1);
+ dest.writeStrongBinder(mUriToken.asBinder());
+ } else {
+ dest.writeInt(0);
+ }
+ }
+
+ private InputContentInfo(@NonNull Parcel source) {
+ mContentUri = Uri.CREATOR.createFromParcel(source);
+ mDescription = ClipDescription.CREATOR.createFromParcel(source);
+ mLinkUri = Uri.CREATOR.createFromParcel(source);
+ if (source.readInt() == 1) {
+ mUriToken = IInputContentUriToken.Stub.asInterface(source.readStrongBinder());
+ } else {
+ mUriToken = null;
+ }
+ }
+
+ /**
+ * Used to make this class parcelable.
+ */
+ public static final Parcelable.Creator CREATOR
+ = new Parcelable.Creator() {
+ @Override
+ public InputContentInfo createFromParcel(Parcel source) {
+ return new InputContentInfo(source);
+ }
+
+ @Override
+ public InputContentInfo[] newArray(int size) {
+ return new InputContentInfo[size];
+ }
+ };
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+}
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 4013b30fce06f4498ed675470cb88199fe93d96e..c0c8e64aacc8bdfee29ee40feca670cd48e717ab 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -16,6 +16,7 @@
package android.view.inputmethod;
+import com.android.internal.inputmethod.IInputContentUriToken;
import com.android.internal.os.SomeArgs;
import com.android.internal.view.IInputConnectionWrapper;
import com.android.internal.view.IInputContext;
@@ -30,6 +31,7 @@ import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.content.Context;
import android.graphics.Rect;
+import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
@@ -56,6 +58,7 @@ import android.view.ViewRootImpl;
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.security.InvalidParameterException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
@@ -2288,6 +2291,40 @@ public final class InputMethodManager {
}
}
+ /**
+ * Allow the receiver of {@link InputContentInfo} to obtain a temporary read-only access
+ * permission to the content.
+ *
+ *
See {@link android.inputmethodservice.InputMethodService#exposeContent(InputContentInfo, EditorInfo)}
+ * for details.
+ *
+ * @param token Supplies the identifying token given to an input method when it was started,
+ * which allows it to perform this operation on itself.
+ * @param inputContentInfo Content to be temporarily exposed from the input method to the
+ * application.
+ * This cannot be {@code null}.
+ * @param editorInfo The editor that receives {@link InputContentInfo}.
+ * @hide
+ */
+ public void exposeContent(@NonNull IBinder token, @NonNull InputContentInfo inputContentInfo,
+ @NonNull EditorInfo editorInfo) {
+ final IInputContentUriToken uriToken;
+ final Uri contentUri = inputContentInfo.getContentUri();
+ try {
+ uriToken = mService.createInputContentUriToken(token, contentUri,
+ editorInfo.packageName);
+ if (uriToken == null) {
+ return;
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "createInputContentAccessToken failed. contentUri=" + contentUri.toString()
+ + " packageName=" + editorInfo.packageName, e);
+ return;
+ }
+ inputContentInfo.setUriToken(uriToken);
+ return;
+ }
+
void doDump(FileDescriptor fd, PrintWriter fout, String[] args) {
final Printer p = new PrintWriterPrinter(fout);
p.println("Input method client state for " + this + ":");
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index bdbbe8e5704ab36ed27066faf42ccfd4ddd2982d..46da9d3c28b7f4b6f652c8bef9f0f5208a53f8db 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -75,6 +75,7 @@ import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.ExtractedText;
import android.view.inputmethod.ExtractedTextRequest;
import android.view.inputmethod.InputConnection;
+import android.view.inputmethod.InputContentInfo;
import android.view.inputmethod.InputMethodManager;
import android.widget.RemoteViews.OnClickHandler;
@@ -1545,7 +1546,7 @@ public abstract class AbsListView extends AdapterView implements Te
switch (action) {
case AccessibilityNodeInfo.ACTION_SCROLL_FORWARD:
case R.id.accessibilityActionScrollDown: {
- if (isEnabled() && getLastVisiblePosition() < getCount() - 1) {
+ if (isEnabled() && canScrollDown()) {
final int viewportHeight = getHeight() - mListPadding.top - mListPadding.bottom;
smoothScrollBy(viewportHeight, PositionScroller.SCROLL_DURATION);
return true;
@@ -1553,7 +1554,7 @@ public abstract class AbsListView extends AdapterView implements Te
} return false;
case AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD:
case R.id.accessibilityActionScrollUp: {
- if (isEnabled() && mFirstPosition > 0) {
+ if (isEnabled() && canScrollUp()) {
final int viewportHeight = getHeight() - mListPadding.top - mListPadding.bottom;
smoothScrollBy(-viewportHeight, PositionScroller.SCROLL_DURATION);
return true;
@@ -5983,6 +5984,11 @@ public abstract class AbsListView extends AdapterView implements Te
public void closeConnection() {
getTarget().closeConnection();
}
+
+ @Override
+ public boolean commitContent(InputContentInfo inputContentInfo, int flags, Bundle opts) {
+ return getTarget().commitContent(inputContentInfo, flags, opts);
+ }
}
/**
diff --git a/core/java/android/widget/DatePickerCalendarDelegate.java b/core/java/android/widget/DatePickerCalendarDelegate.java
index 2fd52b5f1230a360a5c218502a34360649de7a08..af22ec7bc755f37942833acb62f8202ee52f69d3 100755
--- a/core/java/android/widget/DatePickerCalendarDelegate.java
+++ b/core/java/android/widget/DatePickerCalendarDelegate.java
@@ -65,6 +65,8 @@ class DatePickerCalendarDelegate extends DatePicker.AbstractDatePickerDelegate {
private SimpleDateFormat mYearFormat;
private SimpleDateFormat mMonthDayFormat;
+ private SimpleDateFormat mAccessibilityEventFormat;
+
// Top-level container.
private ViewGroup mContainer;
@@ -307,6 +309,9 @@ class DatePickerCalendarDelegate extends DatePicker.AbstractDatePickerDelegate {
mMonthDayFormat.setContext(DisplayContext.CAPITALIZATION_FOR_STANDALONE);
mYearFormat = new SimpleDateFormat("y", locale);
+ // Clear out the lazily-initialized accessibility event formatter.
+ mAccessibilityEventFormat = null;
+
// Update the header text.
onCurrentDateChanged(false);
}
@@ -586,7 +591,12 @@ class DatePickerCalendarDelegate extends DatePicker.AbstractDatePickerDelegate {
@Override
public void onPopulateAccessibilityEvent(AccessibilityEvent event) {
- event.getText().add(mCurrentDate.getTime().toString());
+ if (mAccessibilityEventFormat == null) {
+ final String pattern = DateFormat.getBestDateTimePattern(mCurrentLocale, "EMMMMdy");
+ mAccessibilityEventFormat = new SimpleDateFormat(pattern);
+ }
+ final CharSequence text = mAccessibilityEventFormat.format(mCurrentDate.getTime());
+ event.getText().add(text);
}
public CharSequence getAccessibilityClassName() {
diff --git a/core/java/android/widget/ForwardingListener.java b/core/java/android/widget/ForwardingListener.java
index b383e1c55aada780f40b6d9d45de0b5801d0b599..a5fcbc7934122abff7b76148c88f31f35199747a 100644
--- a/core/java/android/widget/ForwardingListener.java
+++ b/core/java/android/widget/ForwardingListener.java
@@ -58,13 +58,14 @@ public abstract class ForwardingListener
public ForwardingListener(View src) {
mSrc = src;
+ src.setLongClickable(true);
+ src.addOnAttachStateChangeListener(this);
+
mScaledTouchSlop = ViewConfiguration.get(src.getContext()).getScaledTouchSlop();
mTapTimeout = ViewConfiguration.getTapTimeout();
// Use a medium-press timeout. Halfway between tap and long-press.
mLongPressTimeout = (mTapTimeout + ViewConfiguration.getLongPressTimeout()) / 2;
-
- src.addOnAttachStateChangeListener(this);
}
/**
diff --git a/core/java/android/widget/FrameLayout.java b/core/java/android/widget/FrameLayout.java
index 029313c539389a878364a70f90d3508684ebc583..b8c74d88b58079a14d990b3bd97e0b594c37eb9f 100644
--- a/core/java/android/widget/FrameLayout.java
+++ b/core/java/android/widget/FrameLayout.java
@@ -382,13 +382,14 @@ public class FrameLayout extends ViewGroup {
@Override
protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams lp) {
- if (lp instanceof LayoutParams) {
- return new LayoutParams((LayoutParams) lp);
- } else if (lp instanceof MarginLayoutParams) {
- return new LayoutParams((MarginLayoutParams) lp);
- } else {
- return new LayoutParams(lp);
+ if (sPreserveMarginParamsInLayoutParamConversion) {
+ if (lp instanceof LayoutParams) {
+ return new LayoutParams((LayoutParams) lp);
+ } else if (lp instanceof MarginLayoutParams) {
+ return new LayoutParams((MarginLayoutParams) lp);
+ }
}
+ return new LayoutParams(lp);
}
@Override
diff --git a/core/java/android/widget/GridLayout.java b/core/java/android/widget/GridLayout.java
index 726586ee8d5f305fcbc6610ff2958048dfd8298a..af2852cde22a124e87d3dea28a60325072717908 100644
--- a/core/java/android/widget/GridLayout.java
+++ b/core/java/android/widget/GridLayout.java
@@ -868,13 +868,14 @@ public class GridLayout extends ViewGroup {
@Override
protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams lp) {
- if (lp instanceof LayoutParams) {
- return new LayoutParams((LayoutParams) lp);
- } else if (lp instanceof MarginLayoutParams) {
- return new LayoutParams((MarginLayoutParams) lp);
- } else {
- return new LayoutParams(lp);
+ if (sPreserveMarginParamsInLayoutParamConversion) {
+ if (lp instanceof LayoutParams) {
+ return new LayoutParams((LayoutParams) lp);
+ } else if (lp instanceof MarginLayoutParams) {
+ return new LayoutParams((MarginLayoutParams) lp);
+ }
}
+ return new LayoutParams(lp);
}
// Draw grid
diff --git a/core/java/android/widget/ImageView.java b/core/java/android/widget/ImageView.java
index 222a040d2b3caf2cddbc888aa584370af70004ba..aa67c8215b0481198d90f937f0bcb3535a3ab326 100644
--- a/core/java/android/widget/ImageView.java
+++ b/core/java/android/widget/ImageView.java
@@ -22,7 +22,6 @@ import android.annotation.Nullable;
import android.content.ContentResolver;
import android.content.Context;
import android.content.res.ColorStateList;
-import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
@@ -115,11 +114,17 @@ public class ImageView extends View {
private int mBaseline = -1;
private boolean mBaselineAlignBottom = false;
- // AdjustViewBounds behavior will be in compatibility mode for older apps.
- private boolean mAdjustViewBoundsCompat = false;
+ /** Compatibility modes dependent on targetSdkVersion of the app. */
+ private static boolean sCompatDone;
+
+ /** AdjustViewBounds behavior will be in compatibility mode for older apps. */
+ private static boolean sCompatAdjustViewBounds;
/** Whether to pass Resources when creating the source from a stream. */
- private boolean mUseCorrectStreamDensity;
+ private static boolean sCompatUseCorrectStreamDensity;
+
+ /** Whether to use pre-Nougat drawable visibility dispatching conditions. */
+ private static boolean sCompatDrawableVisibilityDispatch;
private static final ScaleType[] sScaleTypeArray = {
ScaleType.MATRIX,
@@ -206,9 +211,13 @@ public class ImageView extends View {
mMatrix = new Matrix();
mScaleType = ScaleType.FIT_CENTER;
- final int targetSdkVersion = mContext.getApplicationInfo().targetSdkVersion;
- mAdjustViewBoundsCompat = targetSdkVersion <= Build.VERSION_CODES.JELLY_BEAN_MR1;
- mUseCorrectStreamDensity = targetSdkVersion > Build.VERSION_CODES.M;
+ if (!sCompatDone) {
+ final int targetSdkVersion = mContext.getApplicationInfo().targetSdkVersion;
+ sCompatAdjustViewBounds = targetSdkVersion <= Build.VERSION_CODES.JELLY_BEAN_MR1;
+ sCompatUseCorrectStreamDensity = targetSdkVersion > Build.VERSION_CODES.M;
+ sCompatDrawableVisibilityDispatch = targetSdkVersion < Build.VERSION_CODES.N;
+ sCompatDone = true;
+ }
}
@Override
@@ -545,6 +554,13 @@ public class ImageView extends View {
* Subsequent calls to {@link #setImageDrawable(Drawable)} will automatically
* mutate the drawable and apply the specified tint and tint mode using
* {@link Drawable#setTintList(ColorStateList)}.
+ *
+ * Note: The default tint mode used by this setter is NOT
+ * consistent with the default tint mode used by the
+ * {@link android.R.styleable#ImageView_tint android:tint}
+ * attribute. If the {@code android:tint} attribute is specified, the
+ * default tint mode will be set to {@link PorterDuff.Mode#SRC_ATOP} to
+ * ensure consistency with earlier versions of the platform.
*
* @param tint the tint to apply, may be {@code null} to clear tint
*
@@ -874,8 +890,8 @@ public class ImageView extends View {
InputStream stream = null;
try {
stream = mContext.getContentResolver().openInputStream(uri);
- return Drawable.createFromResourceStream(
- mUseCorrectStreamDensity ? getResources() : null, null, stream, null);
+ return Drawable.createFromResourceStream(sCompatUseCorrectStreamDensity
+ ? getResources() : null, null, stream, null);
} catch (Exception e) {
Log.w(LOG_TAG, "Unable to open content: " + uri, e);
} finally {
@@ -910,10 +926,13 @@ public class ImageView extends View {
mRecycleableBitmapDrawable.setBitmap(null);
}
+ boolean sameDrawable = false;
+
if (mDrawable != null) {
+ sameDrawable = mDrawable == d;
mDrawable.setCallback(null);
unscheduleDrawable(mDrawable);
- if (isAttachedToWindow()) {
+ if (!sCompatDrawableVisibilityDispatch && !sameDrawable && isAttachedToWindow()) {
mDrawable.setVisible(false, false);
}
}
@@ -926,8 +945,11 @@ public class ImageView extends View {
if (d.isStateful()) {
d.setState(getDrawableState());
}
- if (isAttachedToWindow()) {
- d.setVisible(getWindowVisibility() == VISIBLE && isShown(), true);
+ if (!sameDrawable || sCompatDrawableVisibilityDispatch) {
+ final boolean visible = sCompatDrawableVisibilityDispatch
+ ? getVisibility() == VISIBLE
+ : isAttachedToWindow() && getWindowVisibility() == VISIBLE && isShown();
+ d.setVisible(visible, true);
}
d.setLevel(mLevel);
mDrawableWidth = d.getIntrinsicWidth();
@@ -1051,7 +1073,7 @@ public class ImageView extends View {
pleft + pright;
// Allow the width to outgrow its original estimate if height is fixed.
- if (!resizeHeight && !mAdjustViewBoundsCompat) {
+ if (!resizeHeight && !sCompatAdjustViewBounds) {
widthSize = resolveAdjustedSize(newWidth, mMaxWidth, widthMeasureSpec);
}
@@ -1067,7 +1089,7 @@ public class ImageView extends View {
ptop + pbottom;
// Allow the height to outgrow its original estimate if width is fixed.
- if (!resizeWidth && !mAdjustViewBoundsCompat) {
+ if (!resizeWidth && !sCompatAdjustViewBounds) {
heightSize = resolveAdjustedSize(newHeight, mMaxHeight,
heightMeasureSpec);
}
@@ -1506,11 +1528,40 @@ public class ImageView extends View {
@Override
public void onVisibilityAggregated(boolean isVisible) {
super.onVisibilityAggregated(isVisible);
- if (mDrawable != null) {
+ // Only do this for new apps post-Nougat
+ if (mDrawable != null && !sCompatDrawableVisibilityDispatch) {
mDrawable.setVisible(isVisible, false);
}
}
+ @RemotableViewMethod
+ @Override
+ public void setVisibility(int visibility) {
+ super.setVisibility(visibility);
+ // Only do this for old apps pre-Nougat; new apps use onVisibilityAggregated
+ if (mDrawable != null && sCompatDrawableVisibilityDispatch) {
+ mDrawable.setVisible(visibility == VISIBLE, false);
+ }
+ }
+
+ @Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ // Only do this for old apps pre-Nougat; new apps use onVisibilityAggregated
+ if (mDrawable != null && sCompatDrawableVisibilityDispatch) {
+ mDrawable.setVisible(getVisibility() == VISIBLE, false);
+ }
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ // Only do this for old apps pre-Nougat; new apps use onVisibilityAggregated
+ if (mDrawable != null && sCompatDrawableVisibilityDispatch) {
+ mDrawable.setVisible(false, false);
+ }
+ }
+
@Override
public CharSequence getAccessibilityClassName() {
return ImageView.class.getName();
diff --git a/core/java/android/widget/LinearLayout.java b/core/java/android/widget/LinearLayout.java
index 38d7cd4acaf66e56bb53922f263b20427de62a17..f897372c1f01918288c37b6c9bb986e21d2ce71c 100644
--- a/core/java/android/widget/LinearLayout.java
+++ b/core/java/android/widget/LinearLayout.java
@@ -1844,13 +1844,14 @@ public class LinearLayout extends ViewGroup {
@Override
protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams lp) {
- if (lp instanceof LayoutParams) {
- return new LayoutParams((LayoutParams) lp);
- } else if (lp instanceof MarginLayoutParams) {
- return new LayoutParams((MarginLayoutParams) lp);
- } else {
- return new LayoutParams(lp);
+ if (sPreserveMarginParamsInLayoutParamConversion) {
+ if (lp instanceof LayoutParams) {
+ return new LayoutParams((LayoutParams) lp);
+ } else if (lp instanceof MarginLayoutParams) {
+ return new LayoutParams((MarginLayoutParams) lp);
+ }
}
+ return new LayoutParams(lp);
}
diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java
index b8b7c553a1db3dda2a08cf5b205b7bdb19a9ceb3..b0f19d7a0b49fce927f8818d397b45f6158c60fd 100644
--- a/core/java/android/widget/ListView.java
+++ b/core/java/android/widget/ListView.java
@@ -112,8 +112,8 @@ public class ListView extends AbsListView {
public boolean isSelectable;
}
- private ArrayList mHeaderViewInfos = Lists.newArrayList();
- private ArrayList mFooterViewInfos = Lists.newArrayList();
+ ArrayList mHeaderViewInfos = Lists.newArrayList();
+ ArrayList mFooterViewInfos = Lists.newArrayList();
Drawable mDivider;
int mDividerHeight;
@@ -279,7 +279,7 @@ public class ListView extends AbsListView {
// Wrap the adapter if it wasn't already wrapped.
if (mAdapter != null) {
if (!(mAdapter instanceof HeaderViewListAdapter)) {
- mAdapter = new HeaderViewListAdapter(mHeaderViewInfos, mFooterViewInfos, mAdapter);
+ wrapHeaderListAdapterInternal();
}
// In the case of re-adding a header view, or adding one later on,
@@ -373,7 +373,7 @@ public class ListView extends AbsListView {
// Wrap the adapter if it wasn't already wrapped.
if (mAdapter != null) {
if (!(mAdapter instanceof HeaderViewListAdapter)) {
- mAdapter = new HeaderViewListAdapter(mHeaderViewInfos, mFooterViewInfos, mAdapter);
+ wrapHeaderListAdapterInternal();
}
// In the case of re-adding a footer view, or adding one later on,
@@ -476,7 +476,7 @@ public class ListView extends AbsListView {
mRecycler.clear();
if (mHeaderViewInfos.size() > 0|| mFooterViewInfos.size() > 0) {
- mAdapter = new HeaderViewListAdapter(mHeaderViewInfos, mFooterViewInfos, adapter);
+ mAdapter = wrapHeaderListAdapterInternal(mHeaderViewInfos, mFooterViewInfos, adapter);
} else {
mAdapter = adapter;
}
@@ -2050,6 +2050,8 @@ public class ListView extends AbsListView {
p.recycledHeaderFooter = true;
}
addViewInLayout(child, flowDown ? -1 : 0, p, true);
+ // add view in layout will reset the RTL properties. We have to re-resolve them
+ child.resolveRtlPropertiesIfNeeded();
}
if (needToMeasure) {
@@ -2226,7 +2228,7 @@ public class ListView extends AbsListView {
* after the header views.
*/
public void setSelectionAfterHeaderView() {
- final int count = mHeaderViewInfos.size();
+ final int count = getHeaderViewsCount();
if (count > 0) {
mNextSelectedPosition = 0;
return;
@@ -3354,7 +3356,7 @@ public class ListView extends AbsListView {
bounds.right = mRight - mLeft - mPaddingRight;
final int count = getChildCount();
- final int headerCount = mHeaderViewInfos.size();
+ final int headerCount = getHeaderViewsCount();
final int itemCount = mItemCount;
final int footerLimit = (itemCount - mFooterViewInfos.size());
final boolean headerDividers = mHeaderDividersEnabled;
@@ -3938,7 +3940,7 @@ public class ListView extends AbsListView {
if (drawDividers) {
final boolean fillForMissingDividers = isOpaque() && !super.isOpaque();
final int itemCount = mItemCount;
- final int headerCount = mHeaderViewInfos.size();
+ final int headerCount = getHeaderViewsCount();
final int footerLimit = (itemCount - mFooterViewInfos.size());
final boolean isHeader = (itemIndex < headerCount);
final boolean isFooter = (itemIndex >= footerLimit);
@@ -4050,4 +4052,24 @@ public class ListView extends AbsListView {
encoder.addProperty("recycleOnMeasure", recycleOnMeasure());
}
+
+ /** @hide */
+ protected HeaderViewListAdapter wrapHeaderListAdapterInternal(
+ ArrayList headerViewInfos,
+ ArrayList footerViewInfos,
+ ListAdapter adapter) {
+ return new HeaderViewListAdapter(headerViewInfos, footerViewInfos, adapter);
+ }
+
+ /** @hide */
+ protected void wrapHeaderListAdapterInternal() {
+ mAdapter = wrapHeaderListAdapterInternal(mHeaderViewInfos, mFooterViewInfos, mAdapter);
+ }
+
+ /** @hide */
+ protected void dispatchDataSetObserverOnChangedInternal() {
+ if (mDataSetObserver != null) {
+ mDataSetObserver.onChanged();
+ }
+ }
}
diff --git a/core/java/android/widget/RadialTimePickerView.java b/core/java/android/widget/RadialTimePickerView.java
index 02ee2df18aafd2ecfc0fddc93d5d43df0ff5ed3d..6f198e78df8a1c5b41023a64ca2cca4ffb7b068a 100644
--- a/core/java/android/widget/RadialTimePickerView.java
+++ b/core/java/android/widget/RadialTimePickerView.java
@@ -16,7 +16,11 @@
package android.widget;
+import com.android.internal.R;
+import com.android.internal.widget.ExploreByTouchHelper;
+
import android.animation.ObjectAnimator;
+import android.annotation.IntDef;
import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.Resources;
@@ -43,9 +47,8 @@ import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
-import com.android.internal.R;
-import com.android.internal.widget.ExploreByTouchHelper;
-
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.Calendar;
import java.util.Locale;
@@ -55,11 +58,16 @@ import java.util.Locale;
* @hide
*/
public class RadialTimePickerView extends View {
-
private static final String TAG = "RadialTimePickerView";
public static final int HOURS = 0;
public static final int MINUTES = 1;
+
+ /** @hide */
+ @IntDef({HOURS, MINUTES})
+ @Retention(RetentionPolicy.SOURCE)
+ @interface PickerType {}
+
private static final int HOURS_INNER = 2;
private static final int SELECTOR_CIRCLE = 0;
@@ -185,8 +193,24 @@ public class RadialTimePickerView extends View {
private boolean mInputEnabled = true;
- public interface OnValueSelectedListener {
- void onValueSelected(int pickerIndex, int newValue, boolean autoAdvance);
+ interface OnValueSelectedListener {
+ /**
+ * Called when the selected value at a given picker index has changed.
+ *
+ * @param pickerType the type of value that has changed, one of:
+ *
+ *
{@link #MINUTES}
+ *
{@link #HOURS}
+ *
+ * @param newValue the new value as minute in hour (0-59) or hour in
+ * day (0-23)
+ * @param autoAdvance when the picker type is {@link #HOURS},
+ * {@code true} to switch to the {@link #MINUTES}
+ * picker or {@code false} to stay on the current
+ * picker. No effect when picker type is
+ * {@link #MINUTES}.
+ */
+ void onValueSelected(@PickerType int pickerType, int newValue, boolean autoAdvance);
}
/**
@@ -977,7 +1001,7 @@ public class RadialTimePickerView extends View {
// Ensure we're showing the correct picker.
animatePicker(mShowHours, ANIM_DURATION_TOUCH);
- final int type;
+ final @PickerType int type;
final int newValue;
final boolean valueChanged;
diff --git a/core/java/android/widget/RatingBar.java b/core/java/android/widget/RatingBar.java
index 223096116adbac74368812c846b550ffb5ceebb4..3ad05b5e7c01f9c428671470a4a74bf589e7eba1 100644
--- a/core/java/android/widget/RatingBar.java
+++ b/core/java/android/widget/RatingBar.java
@@ -110,8 +110,8 @@ public class RatingBar extends AbsSeekBar {
}
// A touch inside a star fill up to that fractional area (slightly more
- // than 1 so boundaries round up).
- mTouchProgressOffset = 1.1f;
+ // than 0.5 so boundaries round up).
+ mTouchProgressOffset = 0.6f;
}
public RatingBar(Context context, AttributeSet attrs) {
diff --git a/core/java/android/widget/RelativeLayout.java b/core/java/android/widget/RelativeLayout.java
index 0136542ef4ac867d34ec62ec1dace4a44161551c..a189d3c0cc9126bc2c2c5304c22b1a3dbda0d1e3 100644
--- a/core/java/android/widget/RelativeLayout.java
+++ b/core/java/android/widget/RelativeLayout.java
@@ -1104,13 +1104,14 @@ public class RelativeLayout extends ViewGroup {
@Override
protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams lp) {
- if (lp instanceof LayoutParams) {
- return new LayoutParams((LayoutParams) lp);
- } else if (lp instanceof MarginLayoutParams) {
- return new LayoutParams((MarginLayoutParams) lp);
- } else {
- return new LayoutParams(lp);
+ if (sPreserveMarginParamsInLayoutParamConversion) {
+ if (lp instanceof LayoutParams) {
+ return new LayoutParams((LayoutParams) lp);
+ } else if (lp instanceof MarginLayoutParams) {
+ return new LayoutParams((MarginLayoutParams) lp);
+ }
}
+ return new LayoutParams(lp);
}
/** @hide */
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 1f745185d01b16823dc43575a33bb194733106bc..d0d233ebe975e06bcd263873b41de12950856960 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -2787,6 +2787,18 @@ public class RemoteViews implements Parcelable, Filter {
setInt(viewId, "setTextColor", color);
}
+ /**
+ * @hide
+ * Equivalent to calling {@link android.widget.TextView#setTextColor(ColorStateList)}.
+ *
+ * @param viewId The id of the view whose text color should change
+ * @param colors the text colors to set
+ */
+ public void setTextColor(int viewId, @ColorInt ColorStateList colors) {
+ addAction(new ReflectionAction(viewId, "setTextColor", ReflectionAction.COLOR_STATE_LIST,
+ colors));
+ }
+
/**
* Equivalent to calling {@link android.widget.AbsListView#setRemoteViewsAdapter(Intent)}.
*
@@ -3195,7 +3207,9 @@ public class RemoteViews implements Parcelable, Filter {
// we don't add a filter to the static version returned by getSystemService.
inflater = inflater.cloneInContext(inflationContext);
inflater.setFilter(this);
- return inflater.inflate(rv.getLayoutId(), parent, false);
+ View v = inflater.inflate(rv.getLayoutId(), parent, false);
+ v.setTagInternal(R.id.widget_frame, rv.getLayoutId());
+ return v;
}
private static void loadTransitionOverride(Context context,
@@ -3373,7 +3387,7 @@ public class RemoteViews implements Parcelable, Filter {
// across orientation change, and has the RemoteViews re-applied in the new orientation,
// we throw an exception, since the layouts may be completely unrelated.
if (hasLandscapeAndPortraitLayouts()) {
- if (v.getId() != rvToApply.getLayoutId()) {
+ if ((Integer) v.getTag(R.id.widget_frame) != rvToApply.getLayoutId()) {
throw new RuntimeException("Attempting to re-apply RemoteViews to a view that" +
" that does not share the same root layout id.");
}
@@ -3409,7 +3423,7 @@ public class RemoteViews implements Parcelable, Filter {
// across orientation change, and has the RemoteViews re-applied in the new orientation,
// we throw an exception, since the layouts may be completely unrelated.
if (hasLandscapeAndPortraitLayouts()) {
- if (v.getId() != rvToApply.getLayoutId()) {
+ if ((Integer) v.getTag(R.id.widget_frame) != rvToApply.getLayoutId()) {
throw new RuntimeException("Attempting to re-apply RemoteViews to a view that" +
" that does not share the same root layout id.");
}
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 5cbd2841b57a30993d10847c3c737af7fefcdaf4..d3cb7425fe3584c17cd8746e60ef2fadd13b4648 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -3255,6 +3255,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
*
* @attr ref android.R.styleable#TextView_textColor
*/
+ @android.view.RemotableViewMethod
public void setTextColor(ColorStateList colors) {
if (colors == null) {
throw new NullPointerException();
diff --git a/core/java/android/widget/TimePickerClockDelegate.java b/core/java/android/widget/TimePickerClockDelegate.java
index c21f1dfe0ed13c386c1719e51c124351f5ca6c0c..aa0b93d76a15ad07abe25edbdc42558bbdced3d7 100644
--- a/core/java/android/widget/TimePickerClockDelegate.java
+++ b/core/java/android/widget/TimePickerClockDelegate.java
@@ -61,9 +61,6 @@ class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate {
private static final int HOUR_INDEX = RadialTimePickerView.HOURS;
private static final int MINUTE_INDEX = RadialTimePickerView.MINUTES;
- // NOT a real index for the purpose of what's showing.
- private static final int AMPM_INDEX = 2;
-
private static final int[] ATTRS_TEXT_COLOR = new int[] {R.attr.textColor};
private static final int[] ATTRS_DISABLED_ALPHA = new int[] {R.attr.disabledAlpha};
@@ -701,22 +698,21 @@ class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate {
/** Listener for RadialTimePickerView interaction. */
private final OnValueSelectedListener mOnValueSelectedListener = new OnValueSelectedListener() {
@Override
- public void onValueSelected(int pickerIndex, int newValue, boolean autoAdvance) {
- switch (pickerIndex) {
- case HOUR_INDEX:
+ public void onValueSelected(int pickerType, int newValue, boolean autoAdvance) {
+ switch (pickerType) {
+ case RadialTimePickerView.HOURS:
final boolean isTransition = mAllowAutoAdvance && autoAdvance;
setHourInternal(newValue, true, !isTransition);
if (isTransition) {
setCurrentItemShowing(MINUTE_INDEX, true, false);
- mDelegator.announceForAccessibility(newValue + ". " + mSelectMinutes);
+
+ final int localizedHour = getLocalizedHour(newValue);
+ mDelegator.announceForAccessibility(localizedHour + ". " + mSelectMinutes);
}
break;
- case MINUTE_INDEX:
+ case RadialTimePickerView.MINUTES:
setMinuteInternal(newValue, true);
break;
- case AMPM_INDEX:
- updateAmPmLabelStates(newValue);
- break;
}
if (mOnTimeChangedListener != null) {
diff --git a/core/java/android/widget/Toolbar.java b/core/java/android/widget/Toolbar.java
index 9cdb73ae51ce88c494862e4e9ef05310b09a0b9c..0988c928cb2633b624f15d0402b271a2833afaf3 100644
--- a/core/java/android/widget/Toolbar.java
+++ b/core/java/android/widget/Toolbar.java
@@ -161,7 +161,7 @@ public class Toolbar extends ViewGroup {
private int mTitleMarginTop;
private int mTitleMarginBottom;
- private final RtlSpacingHelper mContentInsets = new RtlSpacingHelper();
+ private RtlSpacingHelper mContentInsets;
private int mContentInsetStartWithNavigation;
private int mContentInsetEndWithActions;
@@ -270,6 +270,7 @@ public class Toolbar extends ViewGroup {
final int contentInsetRight =
a.getDimensionPixelSize(R.styleable.Toolbar_contentInsetRight, 0);
+ ensureContentInsets();
mContentInsets.setAbsolute(contentInsetLeft, contentInsetRight);
if (contentInsetStart != RtlSpacingHelper.UNDEFINED ||
@@ -463,13 +464,13 @@ public class Toolbar extends ViewGroup {
*/
public void setTitleMarginBottom(int margin) {
mTitleMarginBottom = margin;
-
requestLayout();
}
@Override
public void onRtlPropertiesChanged(@ResolvedLayoutDir int layoutDirection) {
super.onRtlPropertiesChanged(layoutDirection);
+ ensureContentInsets();
mContentInsets.setDirection(layoutDirection == LAYOUT_DIRECTION_RTL);
}
@@ -1092,6 +1093,7 @@ public class Toolbar extends ViewGroup {
* @attr ref android.R.styleable#Toolbar_contentInsetStart
*/
public void setContentInsetsRelative(int contentInsetStart, int contentInsetEnd) {
+ ensureContentInsets();
mContentInsets.setRelative(contentInsetStart, contentInsetEnd);
}
@@ -1112,7 +1114,7 @@ public class Toolbar extends ViewGroup {
* @attr ref android.R.styleable#Toolbar_contentInsetStart
*/
public int getContentInsetStart() {
- return mContentInsets.getStart();
+ return mContentInsets != null ? mContentInsets.getStart() : 0;
}
/**
@@ -1132,7 +1134,7 @@ public class Toolbar extends ViewGroup {
* @attr ref android.R.styleable#Toolbar_contentInsetEnd
*/
public int getContentInsetEnd() {
- return mContentInsets.getEnd();
+ return mContentInsets != null ? mContentInsets.getEnd() : 0;
}
/**
@@ -1154,6 +1156,7 @@ public class Toolbar extends ViewGroup {
* @attr ref android.R.styleable#Toolbar_contentInsetRight
*/
public void setContentInsetsAbsolute(int contentInsetLeft, int contentInsetRight) {
+ ensureContentInsets();
mContentInsets.setAbsolute(contentInsetLeft, contentInsetRight);
}
@@ -1174,7 +1177,7 @@ public class Toolbar extends ViewGroup {
* @attr ref android.R.styleable#Toolbar_contentInsetLeft
*/
public int getContentInsetLeft() {
- return mContentInsets.getLeft();
+ return mContentInsets != null ? mContentInsets.getLeft() : 0;
}
/**
@@ -1194,7 +1197,7 @@ public class Toolbar extends ViewGroup {
* @attr ref android.R.styleable#Toolbar_contentInsetRight
*/
public int getContentInsetRight() {
- return mContentInsets.getRight();
+ return mContentInsets != null ? mContentInsets.getRight() : 0;
}
/**
@@ -2128,6 +2131,12 @@ public class Toolbar extends ViewGroup {
}
}
+ private void ensureContentInsets() {
+ if (mContentInsets == null) {
+ mContentInsets = new RtlSpacingHelper();
+ }
+ }
+
/**
* Accessor to enable LayoutLib to get ActionMenuPresenter directly.
*/
diff --git a/core/java/com/android/internal/app/AlertActivity.java b/core/java/com/android/internal/app/AlertActivity.java
index ed48b0d1610c5e25f0fa428c69be12ce51bd2b28..35ffa71de56f87aa64144d56c2725468c810ec80 100644
--- a/core/java/com/android/internal/app/AlertActivity.java
+++ b/core/java/com/android/internal/app/AlertActivity.java
@@ -49,7 +49,7 @@ public abstract class AlertActivity extends Activity implements DialogInterface
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- mAlert = new AlertController(this, this, getWindow());
+ mAlert = AlertController.create(this, this, getWindow());
mAlertParams = new AlertController.AlertParams(this);
}
diff --git a/core/java/com/android/internal/app/AlertController.java b/core/java/com/android/internal/app/AlertController.java
index b7ac6008a1fdc04bf0d32eb2e793869afd28b8ad..5aeb7f92eeda3e2609db0dfd7d350864842e495e 100644
--- a/core/java/com/android/internal/app/AlertController.java
+++ b/core/java/com/android/internal/app/AlertController.java
@@ -24,6 +24,7 @@ import android.annotation.Nullable;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
+import android.content.res.Configuration;
import android.content.res.TypedArray;
import android.database.Cursor;
import android.graphics.drawable.Drawable;
@@ -61,14 +62,15 @@ import android.widget.TextView;
import java.lang.ref.WeakReference;
public class AlertController {
+ public static final int MICRO = 1;
private final Context mContext;
private final DialogInterface mDialogInterface;
- private final Window mWindow;
+ protected final Window mWindow;
private CharSequence mTitle;
- private CharSequence mMessage;
- private ListView mListView;
+ protected CharSequence mMessage;
+ protected ListView mListView;
private View mView;
private int mViewLayoutResId;
@@ -91,14 +93,14 @@ public class AlertController {
private CharSequence mButtonNeutralText;
private Message mButtonNeutralMessage;
- private ScrollView mScrollView;
+ protected ScrollView mScrollView;
private int mIconId = 0;
private Drawable mIcon;
private ImageView mIconView;
private TextView mTitleView;
- private TextView mMessageView;
+ protected TextView mMessageView;
private View mCustomTitleView;
private boolean mForceInverseBackground;
@@ -176,7 +178,21 @@ public class AlertController {
return outValue.data != 0;
}
- public AlertController(Context context, DialogInterface di, Window window) {
+ public static final AlertController create(Context context, DialogInterface di, Window window) {
+ final TypedArray a = context.obtainStyledAttributes(
+ null, R.styleable.AlertDialog, R.attr.alertDialogStyle, 0);
+ int controllerType = a.getInt(R.styleable.AlertDialog_controllerType, 0);
+ a.recycle();
+
+ switch (controllerType) {
+ case MICRO:
+ return new MicroAlertController(context, di, window);
+ default:
+ return new AlertController(context, di, window);
+ }
+ }
+
+ protected AlertController(Context context, DialogInterface di, Window window) {
mContext = context;
mDialogInterface = di;
mWindow = window;
@@ -597,7 +613,7 @@ public class AlertController {
}
}
- private void setupTitle(ViewGroup topPanel) {
+ protected void setupTitle(ViewGroup topPanel) {
if (mCustomTitleView != null && mShowTitle) {
// Add the custom title view directly to the topPanel layout
final LayoutParams lp = new LayoutParams(
@@ -643,7 +659,7 @@ public class AlertController {
}
}
- private void setupContent(ViewGroup contentPanel) {
+ protected void setupContent(ViewGroup contentPanel) {
mScrollView = (ScrollView) contentPanel.findViewById(R.id.scrollView);
mScrollView.setFocusable(false);
@@ -680,7 +696,7 @@ public class AlertController {
}
}
- private void setupButtons(ViewGroup buttonPanel) {
+ protected void setupButtons(ViewGroup buttonPanel) {
int BIT_BUTTON_POSITIVE = 1;
int BIT_BUTTON_NEGATIVE = 2;
int BIT_BUTTON_NEUTRAL = 4;
@@ -1072,7 +1088,8 @@ public class AlertController {
public void bindView(View view, Context context, Cursor cursor) {
CheckedTextView text = (CheckedTextView) view.findViewById(R.id.text1);
text.setText(cursor.getString(mLabelIndex));
- listView.setItemChecked(cursor.getPosition(),
+ listView.setItemChecked(
+ cursor.getPosition(),
cursor.getInt(mIsCheckedIndex) == 1);
}
diff --git a/core/java/com/android/internal/app/AssistUtils.java b/core/java/com/android/internal/app/AssistUtils.java
index d552e542e5274ad7dfcff9f74dbe0d26156d36b1..294007946c773c4134cb171dfc96f0e159aaa317 100644
--- a/core/java/com/android/internal/app/AssistUtils.java
+++ b/core/java/com/android/internal/app/AssistUtils.java
@@ -16,10 +16,13 @@
package com.android.internal.app;
+import com.android.internal.R;
+
import android.app.SearchManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.os.Bundle;
@@ -132,6 +135,16 @@ public class AssistUtils {
}
}
+ public void registerVoiceInteractionSessionListener(IVoiceInteractionSessionListener listener) {
+ try {
+ if (mVoiceInteractionManagerService != null) {
+ mVoiceInteractionManagerService.registerVoiceInteractionSessionListener(listener);
+ }
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed to register voice interaction listener", e);
+ }
+ }
+
public ComponentName getAssistComponentForUser(int userId) {
final String setting = Settings.Secure.getStringForUser(mContext.getContentResolver(),
Settings.Secure.ASSISTANT, userId);
@@ -156,4 +169,41 @@ public class AssistUtils {
return null;
}
+ public static boolean isPreinstalledAssistant(Context context, ComponentName assistant) {
+ if (assistant == null) {
+ return false;
+ }
+ ApplicationInfo applicationInfo;
+ try {
+ applicationInfo = context.getPackageManager().getApplicationInfo(
+ assistant.getPackageName(), 0);
+ } catch (PackageManager.NameNotFoundException e) {
+ return false;
+ }
+ return applicationInfo.isSystemApp() || applicationInfo.isUpdatedSystemApp();
+ }
+
+ private static boolean isDisclosureEnabled(Context context) {
+ return Settings.Secure.getInt(context.getContentResolver(),
+ Settings.Secure.ASSIST_DISCLOSURE_ENABLED, 0) != 0;
+ }
+
+ /**
+ * @return if the disclosure animation should trigger for the given assistant.
+ *
+ * Third-party assistants will always need to disclose, while the user can configure this for
+ * pre-installed assistants.
+ */
+ public static boolean shouldDisclose(Context context, ComponentName assistant) {
+ if (!allowDisablingAssistDisclosure(context)) {
+ return true;
+ }
+
+ return isDisclosureEnabled(context) || !isPreinstalledAssistant(context, assistant);
+ }
+
+ public static boolean allowDisablingAssistDisclosure(Context context) {
+ return context.getResources().getBoolean(
+ com.android.internal.R.bool.config_allowDisablingAssistDisclosure);
+ }
}
diff --git a/core/java/com/android/internal/app/IBatteryStats.aidl b/core/java/com/android/internal/app/IBatteryStats.aidl
index 216a4f1c9a4486f70a6e42aecd52d0c110a38465..5623a2cb430c15e0bf132a1ecc7ec903de6b2e22 100644
--- a/core/java/com/android/internal/app/IBatteryStats.aidl
+++ b/core/java/com/android/internal/app/IBatteryStats.aidl
@@ -79,6 +79,8 @@ interface IBatteryStats {
String newHistoryName, int newType, boolean newUnimportantForLogging);
void noteStopWakelockFromSource(in WorkSource ws, int pid, String name, String historyName,
int type);
+ void noteLongPartialWakelockStart(String name, String historyName, int uid);
+ void noteLongPartialWakelockFinish(String name, String historyName, int uid);
void noteVibratorOn(int uid, long durationMillis);
void noteVibratorOff(int uid);
@@ -118,7 +120,7 @@ interface IBatteryStats {
void noteWifiBatchedScanStoppedFromSource(in WorkSource ws);
void noteWifiMulticastEnabledFromSource(in WorkSource ws);
void noteWifiMulticastDisabledFromSource(in WorkSource ws);
- void noteWifiRadioPowerState(int powerState, long timestampNs);
+ void noteWifiRadioPowerState(int powerState, long timestampNs, int uid);
void noteNetworkInterfaceType(String iface, int type);
void noteNetworkStatsEnabled();
void noteDeviceIdleMode(int mode, String activeReason, int activeUid);
diff --git a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
index 1a963f30ca075e81ba70e93fa008387c800cde5d..033dd13046eab1a56c8b38008c1209c2ee0638a4 100644
--- a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
+++ b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
@@ -22,6 +22,7 @@ import android.os.Bundle;
import com.android.internal.app.IVoiceInteractionSessionShowCallback;
import com.android.internal.app.IVoiceInteractor;
+import com.android.internal.app.IVoiceInteractionSessionListener;
import android.hardware.soundtrigger.IRecognitionStatusCallback;
import android.hardware.soundtrigger.SoundTrigger;
import android.service.voice.IVoiceInteractionService;
@@ -136,4 +137,9 @@ interface IVoiceInteractionManagerService {
* Called when the lockscreen got shown.
*/
void onLockscreenShown();
+
+ /**
+ * Register a voice interaction listener.
+ */
+ void registerVoiceInteractionSessionListener(IVoiceInteractionSessionListener listener);
}
diff --git a/core/java/com/android/internal/app/IVoiceInteractionSessionListener.aidl b/core/java/com/android/internal/app/IVoiceInteractionSessionListener.aidl
new file mode 100644
index 0000000000000000000000000000000000000000..87749d26e4a0c09c2c275983388a4ca07486e104
--- /dev/null
+++ b/core/java/com/android/internal/app/IVoiceInteractionSessionListener.aidl
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+ package com.android.internal.app;
+
+ oneway interface IVoiceInteractionSessionListener {
+ /**
+ * Called when a voice session is shown.
+ */
+ void onVoiceSessionShown();
+
+ /**
+ * Called when a voice session is hidden.
+ */
+ void onVoiceSessionHidden();
+ }
\ No newline at end of file
diff --git a/core/java/com/android/internal/app/MicroAlertController.java b/core/java/com/android/internal/app/MicroAlertController.java
new file mode 100644
index 0000000000000000000000000000000000000000..4431f3c6a50f682c0817d39b3deb7238246c7a46
--- /dev/null
+++ b/core/java/com/android/internal/app/MicroAlertController.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.app;
+
+import android.content.Context;
+import android.content.DialogInterface;
+import android.text.TextUtils;
+import android.view.Gravity;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.Window;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+import android.widget.ScrollView;
+import android.widget.TextView;
+
+import com.android.internal.app.AlertController;
+import com.android.internal.R;
+
+public class MicroAlertController extends AlertController {
+ public MicroAlertController(Context context, DialogInterface di, Window window) {
+ super(context, di, window);
+ }
+
+ @Override
+ protected void setupContent(ViewGroup contentPanel) {
+ // Special case for small screen - the scroll view is higher in hierarchy
+ mScrollView = (ScrollView) mWindow.findViewById(R.id.scrollView);
+
+ // Special case for users that only want to display a String
+ mMessageView = (TextView) contentPanel.findViewById(R.id.message);
+ if (mMessageView == null) {
+ return;
+ }
+
+ if (mMessage != null) {
+ mMessageView.setText(mMessage);
+ } else {
+ // no message, remove associated views
+ mMessageView.setVisibility(View.GONE);
+ contentPanel.removeView(mMessageView);
+
+ if (mListView != null) {
+ // has ListView, swap scrollView with ListView
+
+ // move topPanel into top of scrollParent
+ View topPanel = mScrollView.findViewById(R.id.topPanel);
+ ((ViewGroup) topPanel.getParent()).removeView(topPanel);
+ FrameLayout.LayoutParams topParams =
+ new FrameLayout.LayoutParams(topPanel.getLayoutParams());
+ topParams.gravity = Gravity.TOP;
+ topPanel.setLayoutParams(topParams);
+
+ // move buttonPanel into bottom of scrollParent
+ View buttonPanel = mScrollView.findViewById(R.id.buttonPanel);
+ ((ViewGroup) buttonPanel.getParent()).removeView(buttonPanel);
+ FrameLayout.LayoutParams buttonParams =
+ new FrameLayout.LayoutParams(buttonPanel.getLayoutParams());
+ buttonParams.gravity = Gravity.BOTTOM;
+ buttonPanel.setLayoutParams(buttonParams);
+
+ // remove scrollview
+ final ViewGroup scrollParent = (ViewGroup) mScrollView.getParent();
+ final int childIndex = scrollParent.indexOfChild(mScrollView);
+ scrollParent.removeViewAt(childIndex);
+
+ // add list view
+ scrollParent.addView(mListView,
+ new ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.MATCH_PARENT));
+
+ // add top and button panel
+ scrollParent.addView(topPanel);
+ scrollParent.addView(buttonPanel);
+ } else {
+ // no content, just hide everything
+ contentPanel.setVisibility(View.GONE);
+ }
+ }
+ }
+
+ @Override
+ protected void setupTitle(ViewGroup topPanel) {
+ super.setupTitle(topPanel);
+ if (topPanel.getVisibility() == View.GONE) {
+ topPanel.setVisibility(View.INVISIBLE);
+ }
+ }
+
+ @Override
+ protected void setupButtons(ViewGroup buttonPanel) {
+ super.setupButtons(buttonPanel);
+ if (buttonPanel.getVisibility() == View.GONE) {
+ buttonPanel.setVisibility(View.INVISIBLE);
+ }
+ }
+}
diff --git a/core/java/com/android/internal/app/NightDisplayController.java b/core/java/com/android/internal/app/NightDisplayController.java
new file mode 100644
index 0000000000000000000000000000000000000000..03cd729db62ba0554d0db0cd46b7735b733575c0
--- /dev/null
+++ b/core/java/com/android/internal/app/NightDisplayController.java
@@ -0,0 +1,421 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.app;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.UserHandle;
+import android.provider.Settings.Secure;
+import android.util.Slog;
+
+import com.android.internal.R;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Calendar;
+import java.util.Locale;
+
+/**
+ * Controller for managing Night display settings.
+ *
+ * Night display tints your screen red at night. This makes it easier to look at your screen in
+ * dim light and may help you fall asleep more easily.
+ */
+public final class NightDisplayController {
+
+ private static final String TAG = "NightDisplayController";
+ private static final boolean DEBUG = false;
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({ AUTO_MODE_DISABLED, AUTO_MODE_CUSTOM, AUTO_MODE_TWILIGHT })
+ public @interface AutoMode {}
+
+ /**
+ * Auto mode value to prevent Night display from being automatically activated. It can still
+ * be activated manually via {@link #setActivated(boolean)}.
+ *
+ * @see #setAutoMode(int)
+ */
+ public static final int AUTO_MODE_DISABLED = 0;
+ /**
+ * Auto mode value to automatically activate Night display at a specific start and end time.
+ *
+ * @see #setAutoMode(int)
+ * @see #setCustomStartTime(LocalTime)
+ * @see #setCustomEndTime(LocalTime)
+ */
+ public static final int AUTO_MODE_CUSTOM = 1;
+ /**
+ * Auto mode value to automatically activate Night display from sunset to sunrise.
+ *
+ * @see #setAutoMode(int)
+ */
+ public static final int AUTO_MODE_TWILIGHT = 2;
+
+ private final Context mContext;
+ private final int mUserId;
+
+ private final ContentObserver mContentObserver;
+
+ private Callback mCallback;
+
+ public NightDisplayController(@NonNull Context context) {
+ this(context, UserHandle.myUserId());
+ }
+
+ public NightDisplayController(@NonNull Context context, int userId) {
+ mContext = context.getApplicationContext();
+ mUserId = userId;
+
+ mContentObserver = new ContentObserver(new Handler(Looper.getMainLooper())) {
+ @Override
+ public void onChange(boolean selfChange, Uri uri) {
+ super.onChange(selfChange, uri);
+
+ final String setting = uri == null ? null : uri.getLastPathSegment();
+ if (setting != null) {
+ onSettingChanged(setting);
+ }
+ }
+ };
+ }
+
+ /**
+ * Returns {@code true} when Night display is activated (the display is tinted red).
+ */
+ public boolean isActivated() {
+ return Secure.getIntForUser(mContext.getContentResolver(),
+ Secure.NIGHT_DISPLAY_ACTIVATED, 0, mUserId) == 1;
+ }
+
+ /**
+ * Sets whether Night display should be activated.
+ *
+ * @param activated {@code true} if Night display should be activated
+ * @return {@code true} if the activated value was set successfully
+ */
+ public boolean setActivated(boolean activated) {
+ return Secure.putIntForUser(mContext.getContentResolver(),
+ Secure.NIGHT_DISPLAY_ACTIVATED, activated ? 1 : 0, mUserId);
+ }
+
+ /**
+ * Returns the current auto mode value controlling when Night display will be automatically
+ * activated. One of {@link #AUTO_MODE_DISABLED}, {@link #AUTO_MODE_CUSTOM}, or
+ * {@link #AUTO_MODE_TWILIGHT}.
+ */
+ public @AutoMode int getAutoMode() {
+ int autoMode = Secure.getIntForUser(mContext.getContentResolver(),
+ Secure.NIGHT_DISPLAY_AUTO_MODE, -1, mUserId);
+ if (autoMode == -1) {
+ if (DEBUG) {
+ Slog.d(TAG, "Using default value for setting: " + Secure.NIGHT_DISPLAY_AUTO_MODE);
+ }
+ autoMode = mContext.getResources().getInteger(
+ R.integer.config_defaultNightDisplayAutoMode);
+ }
+
+ if (autoMode != AUTO_MODE_DISABLED
+ && autoMode != AUTO_MODE_CUSTOM
+ && autoMode != AUTO_MODE_TWILIGHT) {
+ Slog.e(TAG, "Invalid autoMode: " + autoMode);
+ autoMode = AUTO_MODE_DISABLED;
+ }
+
+ return autoMode;
+ }
+
+ /**
+ * Sets the current auto mode value controlling when Night display will be automatically
+ * activated. One of {@link #AUTO_MODE_DISABLED}, {@link #AUTO_MODE_CUSTOM}, or
+ * {@link #AUTO_MODE_TWILIGHT}.
+ *
+ * @param autoMode the new auto mode to use
+ * @return {@code true} if new auto mode was set successfully
+ */
+ public boolean setAutoMode(@AutoMode int autoMode) {
+ if (autoMode != AUTO_MODE_DISABLED
+ && autoMode != AUTO_MODE_CUSTOM
+ && autoMode != AUTO_MODE_TWILIGHT) {
+ throw new IllegalArgumentException("Invalid autoMode: " + autoMode);
+ }
+
+ return Secure.putIntForUser(mContext.getContentResolver(),
+ Secure.NIGHT_DISPLAY_AUTO_MODE, autoMode, mUserId);
+ }
+
+ /**
+ * Returns the local time when Night display will be automatically activated when using
+ * {@link #AUTO_MODE_CUSTOM}.
+ */
+ public @NonNull LocalTime getCustomStartTime() {
+ int startTimeValue = Secure.getIntForUser(mContext.getContentResolver(),
+ Secure.NIGHT_DISPLAY_CUSTOM_START_TIME, -1, mUserId);
+ if (startTimeValue == -1) {
+ if (DEBUG) {
+ Slog.d(TAG, "Using default value for setting: "
+ + Secure.NIGHT_DISPLAY_CUSTOM_START_TIME);
+ }
+ startTimeValue = mContext.getResources().getInteger(
+ R.integer.config_defaultNightDisplayCustomStartTime);
+ }
+
+ return LocalTime.valueOf(startTimeValue);
+ }
+
+ /**
+ * Sets the local time when Night display will be automatically activated when using
+ * {@link #AUTO_MODE_CUSTOM}.
+ *
+ * @param startTime the local time to automatically activate Night display
+ * @return {@code true} if the new custom start time was set successfully
+ */
+ public boolean setCustomStartTime(@NonNull LocalTime startTime) {
+ if (startTime == null) {
+ throw new IllegalArgumentException("startTime cannot be null");
+ }
+ return Secure.putIntForUser(mContext.getContentResolver(),
+ Secure.NIGHT_DISPLAY_CUSTOM_START_TIME, startTime.toMillis(), mUserId);
+ }
+
+ /**
+ * Returns the local time when Night display will be automatically deactivated when using
+ * {@link #AUTO_MODE_CUSTOM}.
+ */
+ public @NonNull LocalTime getCustomEndTime() {
+ int endTimeValue = Secure.getIntForUser(mContext.getContentResolver(),
+ Secure.NIGHT_DISPLAY_CUSTOM_END_TIME, -1, mUserId);
+ if (endTimeValue == -1) {
+ if (DEBUG) {
+ Slog.d(TAG, "Using default value for setting: "
+ + Secure.NIGHT_DISPLAY_CUSTOM_END_TIME);
+ }
+ endTimeValue = mContext.getResources().getInteger(
+ R.integer.config_defaultNightDisplayCustomEndTime);
+ }
+
+ return LocalTime.valueOf(endTimeValue);
+ }
+
+ /**
+ * Sets the local time when Night display will be automatically deactivated when using
+ * {@link #AUTO_MODE_CUSTOM}.
+ *
+ * @param endTime the local time to automatically deactivate Night display
+ * @return {@code true} if the new custom end time was set successfully
+ */
+ public boolean setCustomEndTime(@NonNull LocalTime endTime) {
+ if (endTime == null) {
+ throw new IllegalArgumentException("endTime cannot be null");
+ }
+ return Secure.putIntForUser(mContext.getContentResolver(),
+ Secure.NIGHT_DISPLAY_CUSTOM_END_TIME, endTime.toMillis(), mUserId);
+ }
+
+ private void onSettingChanged(@NonNull String setting) {
+ if (DEBUG) {
+ Slog.d(TAG, "onSettingChanged: " + setting);
+ }
+
+ if (mCallback != null) {
+ switch (setting) {
+ case Secure.NIGHT_DISPLAY_ACTIVATED:
+ mCallback.onActivated(isActivated());
+ break;
+ case Secure.NIGHT_DISPLAY_AUTO_MODE:
+ mCallback.onAutoModeChanged(getAutoMode());
+ break;
+ case Secure.NIGHT_DISPLAY_CUSTOM_START_TIME:
+ mCallback.onCustomStartTimeChanged(getCustomStartTime());
+ break;
+ case Secure.NIGHT_DISPLAY_CUSTOM_END_TIME:
+ mCallback.onCustomEndTimeChanged(getCustomEndTime());
+ break;
+ }
+ }
+ }
+
+ /**
+ * Register a callback to be invoked whenever the Night display settings are changed.
+ */
+ public void setListener(Callback callback) {
+ final Callback oldCallback = mCallback;
+ if (oldCallback != callback) {
+ mCallback = callback;
+
+ if (callback == null) {
+ // Stop listening for changes now that there IS NOT a listener.
+ mContext.getContentResolver().unregisterContentObserver(mContentObserver);
+ } else if (oldCallback == null) {
+ // Start listening for changes now that there IS a listener.
+ final ContentResolver cr = mContext.getContentResolver();
+ cr.registerContentObserver(Secure.getUriFor(Secure.NIGHT_DISPLAY_ACTIVATED),
+ false /* notifyForDescendants */, mContentObserver, mUserId);
+ cr.registerContentObserver(Secure.getUriFor(Secure.NIGHT_DISPLAY_AUTO_MODE),
+ false /* notifyForDescendants */, mContentObserver, mUserId);
+ cr.registerContentObserver(Secure.getUriFor(Secure.NIGHT_DISPLAY_CUSTOM_START_TIME),
+ false /* notifyForDescendants */, mContentObserver, mUserId);
+ cr.registerContentObserver(Secure.getUriFor(Secure.NIGHT_DISPLAY_CUSTOM_END_TIME),
+ false /* notifyForDescendants */, mContentObserver, mUserId);
+ }
+ }
+ }
+
+ /**
+ * Returns {@code true} if Night display is supported by the device.
+ */
+ public static boolean isAvailable(Context context) {
+ return context.getResources().getBoolean(R.bool.config_nightDisplayAvailable);
+ }
+
+ /**
+ * A time without a time-zone or date.
+ */
+ public static class LocalTime {
+
+ /**
+ * The hour of the day from 0 - 23.
+ */
+ public final int hourOfDay;
+ /**
+ * The minute within the hour from 0 - 59.
+ */
+ public final int minute;
+
+ public LocalTime(int hourOfDay, int minute) {
+ if (hourOfDay < 0 || hourOfDay > 23) {
+ throw new IllegalArgumentException("Invalid hourOfDay: " + hourOfDay);
+ } else if (minute < 0 || minute > 59) {
+ throw new IllegalArgumentException("Invalid minute: " + minute);
+ }
+
+ this.hourOfDay = hourOfDay;
+ this.minute = minute;
+ }
+
+ /**
+ * Returns the first date time corresponding to this local time that occurs before the
+ * provided date time.
+ *
+ * @param time the date time to compare against
+ * @return the prior date time corresponding to this local time
+ */
+ public Calendar getDateTimeBefore(Calendar time) {
+ final Calendar c = Calendar.getInstance();
+ c.set(Calendar.YEAR, time.get(Calendar.YEAR));
+ c.set(Calendar.DAY_OF_YEAR, time.get(Calendar.DAY_OF_YEAR));
+
+ c.set(Calendar.HOUR_OF_DAY, hourOfDay);
+ c.set(Calendar.MINUTE, minute);
+ c.set(Calendar.SECOND, 0);
+ c.set(Calendar.MILLISECOND, 0);
+
+ // Check if the local time has past, if so return the same time tomorrow.
+ if (c.after(time)) {
+ c.add(Calendar.DATE, -1);
+ }
+
+ return c;
+ }
+
+ /**
+ * Returns the first date time corresponding to this local time that occurs after the
+ * provided date time.
+ *
+ * @param time the date time to compare against
+ * @return the next date time corresponding to this local time
+ */
+ public Calendar getDateTimeAfter(Calendar time) {
+ final Calendar c = Calendar.getInstance();
+ c.set(Calendar.YEAR, time.get(Calendar.YEAR));
+ c.set(Calendar.DAY_OF_YEAR, time.get(Calendar.DAY_OF_YEAR));
+
+ c.set(Calendar.HOUR_OF_DAY, hourOfDay);
+ c.set(Calendar.MINUTE, minute);
+ c.set(Calendar.SECOND, 0);
+ c.set(Calendar.MILLISECOND, 0);
+
+ // Check if the local time has past, if so return the same time tomorrow.
+ if (c.before(time)) {
+ c.add(Calendar.DATE, 1);
+ }
+
+ return c;
+ }
+
+ /**
+ * Returns a local time corresponding the given number of milliseconds from midnight.
+ *
+ * @param millis the number of milliseconds from midnight
+ * @return the corresponding local time
+ */
+ private static LocalTime valueOf(int millis) {
+ final int hourOfDay = (millis / 3600000) % 24;
+ final int minutes = (millis / 60000) % 60;
+ return new LocalTime(hourOfDay, minutes);
+ }
+
+ /**
+ * Returns the local time represented as milliseconds from midnight.
+ */
+ private int toMillis() {
+ return hourOfDay * 3600000 + minute * 60000;
+ }
+
+ @Override
+ public String toString() {
+ return String.format(Locale.US, "%02d:%02d", hourOfDay, minute);
+ }
+ }
+
+ /**
+ * Callback invoked whenever the Night display settings are changed.
+ */
+ public interface Callback {
+ /**
+ * Callback invoked when the activated state changes.
+ *
+ * @param activated {@code true} if Night display is activated
+ */
+ default void onActivated(boolean activated) {}
+ /**
+ * Callback invoked when the auto mode changes.
+ *
+ * @param autoMode the auto mode to use
+ */
+ default void onAutoModeChanged(int autoMode) {}
+ /**
+ * Callback invoked when the time to automatically activate Night display changes.
+ *
+ * @param startTime the local time to automatically activate Night display
+ */
+ default void onCustomStartTimeChanged(LocalTime startTime) {}
+ /**
+ * Callback invoked when the time to automatically deactivate Night display changes.
+ *
+ * @param endTime the local time to automatically deactivate Night display
+ */
+ default void onCustomEndTimeChanged(LocalTime endTime) {}
+ }
+}
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index 085e159c8b21765c8bb322a9a7d6253f0ea50a8f..0a4ac0d44db4b83e94dd42aa9aa945612d5131c1 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -69,9 +69,13 @@ import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
+
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto;
import com.android.internal.widget.ResolverDrawerLayout;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
@@ -359,6 +363,12 @@ public class ResolverActivity extends Activity {
if (isVoiceInteraction()) {
onSetupVoiceInteraction();
}
+ final Set categories = intent.getCategories();
+ MetricsLogger.action(this, mAdapter.hasFilteredItem()
+ ? MetricsProto.MetricsEvent.ACTION_SHOW_APP_DISAMBIG_APP_FEATURED
+ : MetricsProto.MetricsEvent.ACTION_SHOW_APP_DISAMBIG_NONE_FEATURED,
+ intent.getAction() + ":" + intent.getType() + ":"
+ + (categories != null ? Arrays.toString(categories.toArray()) : ""));
}
public final void setFilteredComponents(ComponentName[] components) {
@@ -649,6 +659,19 @@ public class ResolverActivity extends Activity {
TargetInfo target = mAdapter.targetInfoForPosition(which, filtered);
if (onTargetSelected(target, always)) {
+ if (always && filtered) {
+ MetricsLogger.action(
+ this, MetricsProto.MetricsEvent.ACTION_APP_DISAMBIG_ALWAYS);
+ } else if (filtered) {
+ MetricsLogger.action(
+ this, MetricsProto.MetricsEvent.ACTION_APP_DISAMBIG_JUST_ONCE);
+ } else {
+ MetricsLogger.action(
+ this, MetricsProto.MetricsEvent.ACTION_APP_DISAMBIG_TAP);
+ }
+ MetricsLogger.action(this, mAdapter.hasFilteredItem()
+ ? MetricsProto.MetricsEvent.ACTION_HIDE_APP_DISAMBIG_APP_FEATURED
+ : MetricsProto.MetricsEvent.ACTION_HIDE_APP_DISAMBIG_NONE_FEATURED);
finish();
}
}
diff --git a/core/java/com/android/internal/app/UnlaunchableAppActivity.java b/core/java/com/android/internal/app/UnlaunchableAppActivity.java
index d24cefeecf077239d378426375c795c03433338d..0a539f19c48aa416158be63f64bfd59cdc3aaf14 100644
--- a/core/java/com/android/internal/app/UnlaunchableAppActivity.java
+++ b/core/java/com/android/internal/app/UnlaunchableAppActivity.java
@@ -37,6 +37,7 @@ import android.text.TextUtils;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
+import android.view.Window;
import android.widget.TextView;
import com.android.internal.R;
@@ -59,6 +60,9 @@ public class UnlaunchableAppActivity extends Activity
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ // As this activity has nothing to show, we should hide the title bar also
+ // TODO: Use AlertActivity so we don't need to hide title bar and create a dialog
+ requestWindowFeature(Window.FEATURE_NO_TITLE);
Intent intent = getIntent();
mReason = intent.getIntExtra(EXTRA_UNLAUNCHABLE_REASON, -1);
mUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
diff --git a/core/java/com/android/internal/appwidget/IAppWidgetService.aidl b/core/java/com/android/internal/appwidget/IAppWidgetService.aidl
index 4260e50a31f26120cf34b33409424d810e0af968..951a45a7b4376a42de8a624c916e1acac6f4cb94 100644
--- a/core/java/com/android/internal/appwidget/IAppWidgetService.aidl
+++ b/core/java/com/android/internal/appwidget/IAppWidgetService.aidl
@@ -34,7 +34,7 @@ interface IAppWidgetService {
// for AppWidgetHost
//
ParceledListSlice startListening(IAppWidgetHost host, String callingPackage, int hostId,
- in int[] appWidgetIds, out int[] updatedIds);
+ in int[] appWidgetIds);
void stopListening(String callingPackage, int hostId);
int allocateAppWidgetId(String callingPackage, int hostId);
void deleteAppWidgetId(String callingPackage, int appWidgetId);
diff --git a/core/java/com/android/internal/inputmethod/IInputContentUriToken.aidl b/core/java/com/android/internal/inputmethod/IInputContentUriToken.aidl
new file mode 100644
index 0000000000000000000000000000000000000000..8abc8074b5acc376deff9976b0fdcc15c8d032e4
--- /dev/null
+++ b/core/java/com/android/internal/inputmethod/IInputContentUriToken.aidl
@@ -0,0 +1,27 @@
+/*
+** Copyright 2016, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package com.android.internal.inputmethod;
+
+import android.os.IBinder;
+
+/**
+ * {@hide}
+ */
+interface IInputContentUriToken {
+ void take();
+ void release();
+}
diff --git a/core/java/com/android/internal/net/VpnProfile.java b/core/java/com/android/internal/net/VpnProfile.java
index 5c92f3c68c774b0c276fc81b7d11da850504df35..9a5543afcd78962850e48db93bb26cf11e10843e 100644
--- a/core/java/com/android/internal/net/VpnProfile.java
+++ b/core/java/com/android/internal/net/VpnProfile.java
@@ -176,6 +176,11 @@ public class VpnProfile implements Cloneable, Parcelable {
* connection.
*/
public boolean isValidLockdownProfile() {
+ // b/7064069: lockdown firewall blocks ports that would be used for PPTP
+ if (type == TYPE_PPTP) {
+ return false;
+ }
+
try {
InetAddress.parseNumericAddress(server);
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index a1df8c186982dbd2324d0a4889b44536355f842d..2538d60f1924836ed10604744075ed53350a27d8 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -108,7 +108,7 @@ public class BatteryStatsImpl extends BatteryStats {
private static final int MAGIC = 0xBA757475; // 'BATSTATS'
// Current on-disk Parcel version
- private static final int VERSION = 147 + (USE_OLD_HISTORY ? 1000 : 0);
+ private static final int VERSION = 150 + (USE_OLD_HISTORY ? 1000 : 0);
// Maximum number of items we will record in the history.
private static final int MAX_HISTORY_ITEMS = 2000;
@@ -1415,22 +1415,6 @@ public class BatteryStatsImpl extends BatteryStats {
mUnpluggedReportedCount = 0;
return true;
}
-
- @Override
- public void writeSummaryFromParcelLocked(Parcel out, long batteryRealtime) {
- super.writeSummaryFromParcelLocked(out, batteryRealtime);
- out.writeLong(mCurrentReportedTotalTime);
- out.writeInt(mCurrentReportedCount);
- out.writeInt(mTrackingReportedValues ? 1 : 0);
- }
-
- @Override
- public void readSummaryFromParcelLocked(Parcel in) {
- super.readSummaryFromParcelLocked(in);
- mUnpluggedReportedTotalTime = mCurrentReportedTotalTime = in.readLong();
- mUnpluggedReportedCount = mCurrentReportedCount = in.readInt();
- mTrackingReportedValues = in.readInt() == 1;
- }
}
/**
@@ -1566,6 +1550,186 @@ public class BatteryStatsImpl extends BatteryStats {
}
}
+
+ /**
+ * A StopwatchTimer that also tracks the total and max individual
+ * time spent active according to the given timebase. Whereas
+ * StopwatchTimer apportions the time amongst all in the pool,
+ * the total and max durations are not apportioned.
+ */
+ public static class DurationTimer extends StopwatchTimer {
+ /**
+ * The time (in ms) that the timer was last acquired or the time base
+ * last (re-)started. Increasing the nesting depth does not reset this time.
+ *
+ * -1 if the timer is currently not running or the time base is not running.
+ *
+ * If written to a parcel, the start time is reset, as is mNesting in the base class
+ * StopwatchTimer.
+ */
+ long mStartTimeMs = -1;
+
+ /**
+ * The longest time period (in ms) that the timer has been active.
+ */
+ long mMaxDurationMs;
+
+ /**
+ * The total time (in ms) that that the timer has been active since reset().
+ */
+ long mCurrentDurationMs;
+
+ public DurationTimer(Clocks clocks, Uid uid, int type, ArrayList timerPool,
+ TimeBase timeBase, Parcel in) {
+ super(clocks, uid, type, timerPool, timeBase, in);
+ mMaxDurationMs = in.readLong();
+ }
+
+ public DurationTimer(Clocks clocks, Uid uid, int type, ArrayList timerPool,
+ TimeBase timeBase) {
+ super(clocks, uid, type, timerPool, timeBase);
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, long elapsedRealtimeUs) {
+ super.writeToParcel(out, elapsedRealtimeUs);
+ out.writeLong(mMaxDurationMs);
+ }
+
+ /**
+ * Write the summary to the parcel.
+ *
+ * Since the time base is probably meaningless after we come back, reading
+ * from this will have the effect of stopping the timer. So here all we write
+ * is the max duration.
+ */
+ @Override
+ public void writeSummaryFromParcelLocked(Parcel out, long elapsedRealtimeUs) {
+ super.writeSummaryFromParcelLocked(out, elapsedRealtimeUs);
+ out.writeLong(mMaxDurationMs);
+ }
+
+ /**
+ * Read the summary parcel.
+ *
+ * Has the side effect of stopping the timer.
+ */
+ @Override
+ public void readSummaryFromParcelLocked(Parcel in) {
+ super.readSummaryFromParcelLocked(in);
+ mMaxDurationMs = in.readLong();
+ mStartTimeMs = -1;
+ mCurrentDurationMs = 0;
+ }
+
+ /**
+ * The TimeBase time started (again).
+ *
+ * If the timer is also running, store the start time.
+ */
+ public void onTimeStarted(long elapsedRealtimeUs, long baseUptime, long baseRealtime) {
+ super.onTimeStarted(elapsedRealtimeUs, baseUptime, baseRealtime);
+ if (mNesting > 0) {
+ mStartTimeMs = mTimeBase.getRealtime(mClocks.elapsedRealtime()*1000) / 1000;
+ }
+ }
+
+ /**
+ * The TimeBase stopped running.
+ *
+ * If the timer is running, add the duration into mCurrentDurationMs.
+ */
+ @Override
+ public void onTimeStopped(long elapsedRealtimeUs, long baseUptime, long baseRealtime) {
+ super.onTimeStopped(elapsedRealtimeUs, baseUptime, baseRealtime);
+ if (mNesting > 0) {
+ mCurrentDurationMs += (elapsedRealtimeUs / 1000) - mStartTimeMs;
+ }
+ mStartTimeMs = -1;
+ }
+
+ @Override
+ public void logState(Printer pw, String prefix) {
+ super.logState(pw, prefix);
+ }
+
+ @Override
+ public void startRunningLocked(long elapsedRealtimeMs) {
+ super.startRunningLocked(elapsedRealtimeMs);
+ if (mNesting == 1 && mTimeBase.isRunning()) {
+ // Just started
+ mStartTimeMs = mTimeBase.getRealtime(mClocks.elapsedRealtime()*1000) / 1000;
+ }
+ }
+
+ /**
+ * Decrements the mNesting ref-count on this timer.
+ *
+ * If it actually stopped (mNesting went to 0), then possibly update
+ * mMaxDuration if the current duration was the longest ever.
+ */
+ @Override
+ public void stopRunningLocked(long elapsedRealtimeMs) {
+ super.stopRunningLocked(elapsedRealtimeMs);
+ if (mNesting == 0) {
+ final long durationMs = getCurrentDurationMsLocked(elapsedRealtimeMs);
+ if (durationMs > mMaxDurationMs) {
+ mMaxDurationMs = durationMs;
+ }
+ mStartTimeMs = -1;
+ mCurrentDurationMs = 0;
+ }
+ }
+
+ @Override
+ public boolean reset(boolean detachIfReset) {
+ boolean result = super.reset(detachIfReset);
+ mMaxDurationMs = 0;
+ mCurrentDurationMs = 0;
+ if (mNesting > 0) {
+ mStartTimeMs = mTimeBase.getRealtime(mClocks.elapsedRealtime()*1000) / 1000;
+ } else {
+ mStartTimeMs = -1;
+ }
+ return result;
+ }
+
+ /**
+ * Returns the max duration that this timer has ever seen.
+ *
+ * Note that this time is NOT split between the timers in the timer group that
+ * this timer is attached to. It is the TOTAL time.
+ */
+ @Override
+ public long getMaxDurationMsLocked(long elapsedRealtimeMs) {
+ if (mNesting > 0) {
+ final long durationMs = getCurrentDurationMsLocked(elapsedRealtimeMs);
+ if (durationMs > mMaxDurationMs) {
+ return durationMs;
+ }
+ }
+ return mMaxDurationMs;
+ }
+
+ /**
+ * Returns the time since the timer was started.
+ *
+ * Note that this time is NOT split between the timers in the timer group that
+ * this timer is attached to. It is the TOTAL time.
+ */
+ @Override
+ public long getCurrentDurationMsLocked(long elapsedRealtimeMs) {
+ long durationMs = mCurrentDurationMs;
+ if (mNesting > 0) {
+ if (mTimeBase.isRunning()) {
+ durationMs += (mTimeBase.getRealtime(elapsedRealtimeMs*1000)/1000)
+ - mStartTimeMs;
+ }
+ }
+ return durationMs;
+ }
+ }
+
/**
* State for keeping track of timing information.
*/
@@ -1791,11 +1955,17 @@ public class BatteryStatsImpl extends BatteryStats {
public abstract class OverflowArrayMap {
private static final String OVERFLOW_NAME = "*overflow*";
+ final int mUid;
final ArrayMap mMap = new ArrayMap<>();
T mCurOverflow;
ArrayMap mActiveOverflow;
+ long mLastOverflowTime;
+ long mLastOverflowFinishTime;
+ long mLastClearTime;
+ long mLastCleanupTime;
- public OverflowArrayMap() {
+ public OverflowArrayMap(int uid) {
+ mUid = uid;
}
public ArrayMap getMap() {
@@ -1803,6 +1973,7 @@ public class BatteryStatsImpl extends BatteryStats {
}
public void clear() {
+ mLastClearTime = SystemClock.elapsedRealtime();
mMap.clear();
mCurOverflow = null;
mActiveOverflow = null;
@@ -1819,6 +1990,7 @@ public class BatteryStatsImpl extends BatteryStats {
}
public void cleanup() {
+ mLastCleanupTime = SystemClock.elapsedRealtime();
if (mActiveOverflow != null) {
if (mActiveOverflow.size() == 0) {
mActiveOverflow = null;
@@ -1885,6 +2057,7 @@ public class BatteryStatsImpl extends BatteryStats {
mActiveOverflow = new ArrayMap<>();
}
mActiveOverflow.put(name, new MutableInt(1));
+ mLastOverflowTime = SystemClock.elapsedRealtime();
return obj;
}
@@ -1914,6 +2087,7 @@ public class BatteryStatsImpl extends BatteryStats {
over.value--;
if (over.value <= 0) {
mActiveOverflow.remove(name);
+ mLastOverflowFinishTime = SystemClock.elapsedRealtime();
}
return obj;
}
@@ -1922,9 +2096,35 @@ public class BatteryStatsImpl extends BatteryStats {
// Huh, they are stopping an active operation but we can't find one!
// That's not good.
- Slog.wtf(TAG, "Unable to find object for " + name + " mapsize="
- + mMap.size() + " activeoverflow=" + mActiveOverflow
- + " curoverflow=" + mCurOverflow);
+ StringBuilder sb = new StringBuilder();
+ sb.append("Unable to find object for ");
+ sb.append(name);
+ sb.append(" in uid ");
+ sb.append(mUid);
+ sb.append(" mapsize=");
+ sb.append(mMap.size());
+ sb.append(" activeoverflow=");
+ sb.append(mActiveOverflow);
+ sb.append(" curoverflow=");
+ sb.append(mCurOverflow);
+ long now = SystemClock.elapsedRealtime();
+ if (mLastOverflowTime != 0) {
+ sb.append(" lastOverflowTime=");
+ TimeUtils.formatDuration(mLastOverflowTime-now, sb);
+ }
+ if (mLastOverflowFinishTime != 0) {
+ sb.append(" lastOverflowFinishTime=");
+ TimeUtils.formatDuration(mLastOverflowFinishTime-now, sb);
+ }
+ if (mLastClearTime != 0) {
+ sb.append(" lastClearTime=");
+ TimeUtils.formatDuration(mLastClearTime-now, sb);
+ }
+ if (mLastCleanupTime != 0) {
+ sb.append(" lastCleanupTime=");
+ TimeUtils.formatDuration(mLastCleanupTime-now, sb);
+ }
+ Slog.wtf(TAG, sb.toString());
return null;
}
@@ -3285,6 +3485,36 @@ public class BatteryStatsImpl extends BatteryStats {
}
}
+ public void noteLongPartialWakelockStart(String name, String historyName, int uid) {
+ uid = mapUid(uid);
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
+ if (historyName == null) {
+ historyName = name;
+ }
+ if (!mActiveEvents.updateState(HistoryItem.EVENT_LONG_WAKE_LOCK_START, historyName, uid,
+ 0)) {
+ return;
+ }
+ addHistoryEventLocked(elapsedRealtime, uptime, HistoryItem.EVENT_LONG_WAKE_LOCK_START,
+ historyName, uid);
+ }
+
+ public void noteLongPartialWakelockFinish(String name, String historyName, int uid) {
+ uid = mapUid(uid);
+ final long elapsedRealtime = mClocks.elapsedRealtime();
+ final long uptime = mClocks.uptimeMillis();
+ if (historyName == null) {
+ historyName = name;
+ }
+ if (!mActiveEvents.updateState(HistoryItem.EVENT_LONG_WAKE_LOCK_FINISH, historyName, uid,
+ 0)) {
+ return;
+ }
+ addHistoryEventLocked(elapsedRealtime, uptime, HistoryItem.EVENT_LONG_WAKE_LOCK_FINISH,
+ historyName, uid);
+ }
+
void aggregateLastWakeupUptimeLocked(long uptimeMs) {
if (mLastWakeupReason != null) {
long deltaUptime = uptimeMs - mLastWakeupUptimeMs;
@@ -3554,6 +3784,14 @@ public class BatteryStatsImpl extends BatteryStats {
mNumConnectivityChange++;
}
+ private void noteMobileRadioApWakeupLocked(final long elapsedRealtimeMillis,
+ final long uptimeMillis, int uid) {
+ uid = mapUid(uid);
+ addHistoryEventLocked(elapsedRealtimeMillis, uptimeMillis, HistoryItem.EVENT_WAKEUP_AP, "",
+ uid);
+ getUidStatsLocked(uid).noteMobileRadioApWakeupLocked();
+ }
+
public void noteMobileRadioPowerState(int powerState, long timestampNs, int uid) {
final long elapsedRealtime = mClocks.elapsedRealtime();
final long uptime = mClocks.uptimeMillis();
@@ -3563,6 +3801,10 @@ public class BatteryStatsImpl extends BatteryStats {
powerState == DataConnectionRealTimeInfo.DC_POWER_STATE_MEDIUM
|| powerState == DataConnectionRealTimeInfo.DC_POWER_STATE_HIGH;
if (active) {
+ if (uid > 0) {
+ noteMobileRadioApWakeupLocked(elapsedRealtime, uptime, uid);
+ }
+
mMobileRadioActiveStartTime = realElapsedRealtimeMs = timestampNs / (1000 * 1000);
mHistoryCur.states |= HistoryItem.STATE_MOBILE_RADIO_ACTIVE_FLAG;
} else {
@@ -4239,7 +4481,15 @@ public class BatteryStatsImpl extends BatteryStats {
}
}
- public void noteWifiRadioPowerState(int powerState, long timestampNs) {
+ private void noteWifiRadioApWakeupLocked(final long elapsedRealtimeMillis,
+ final long uptimeMillis, int uid) {
+ uid = mapUid(uid);
+ addHistoryEventLocked(elapsedRealtimeMillis, uptimeMillis, HistoryItem.EVENT_WAKEUP_AP, "",
+ uid);
+ getUidStatsLocked(uid).noteWifiRadioApWakeupLocked();
+ }
+
+ public void noteWifiRadioPowerState(int powerState, long timestampNs, int uid) {
final long elapsedRealtime = mClocks.elapsedRealtime();
final long uptime = mClocks.uptimeMillis();
if (mWifiRadioPowerState != powerState) {
@@ -4247,6 +4497,9 @@ public class BatteryStatsImpl extends BatteryStats {
powerState == DataConnectionRealTimeInfo.DC_POWER_STATE_MEDIUM
|| powerState == DataConnectionRealTimeInfo.DC_POWER_STATE_HIGH;
if (active) {
+ if (uid > 0) {
+ noteWifiRadioApWakeupLocked(elapsedRealtime, uptime, uid);
+ }
mHistoryCur.states |= HistoryItem.STATE_WIFI_RADIO_ACTIVE_FLAG;
} else {
mHistoryCur.states &= ~HistoryItem.STATE_WIFI_RADIO_ACTIVE_FLAG;
@@ -4874,6 +5127,33 @@ public class BatteryStatsImpl extends BatteryStats {
return mUidStats;
}
+ private static void detachTimerIfNotNull(BatteryStatsImpl.Timer timer) {
+ if (timer != null) {
+ timer.detach();
+ }
+ }
+
+ private static boolean resetTimerIfNotNull(BatteryStatsImpl.Timer timer,
+ boolean detachIfReset) {
+ if (timer != null) {
+ return timer.reset(detachIfReset);
+ }
+ return true;
+ }
+
+ private static void detachLongCounterIfNotNull(LongSamplingCounter counter) {
+ if (counter != null) {
+ counter.detach();
+ }
+ }
+
+ private static void resetLongCounterIfNotNull(LongSamplingCounter counter,
+ boolean detachIfReset) {
+ if (counter != null) {
+ counter.reset(detachIfReset);
+ }
+ }
+
/**
* The statistics associated with a particular uid.
*/
@@ -4920,6 +5200,16 @@ public class BatteryStatsImpl extends BatteryStats {
LongSamplingCounter mMobileRadioActiveTime;
LongSamplingCounter mMobileRadioActiveCount;
+ /**
+ * How many times this UID woke up the Application Processor due to a Mobile radio packet.
+ */
+ private LongSamplingCounter mMobileRadioApWakeupCount;
+
+ /**
+ * How many times this UID woke up the Application Processor due to a Wifi packet.
+ */
+ private LongSamplingCounter mWifiRadioApWakeupCount;
+
/**
* The amount of time this uid has kept the WiFi controller in idle, tx, and rx mode.
* Can be null if the UID has had no such activity.
@@ -4994,18 +5284,18 @@ public class BatteryStatsImpl extends BatteryStats {
mSystemCpuTime = new LongSamplingCounter(mBsi.mOnBatteryTimeBase);
mCpuPower = new LongSamplingCounter(mBsi.mOnBatteryTimeBase);
- mWakelockStats = mBsi.new OverflowArrayMap() {
+ mWakelockStats = mBsi.new OverflowArrayMap(uid) {
@Override public Wakelock instantiateObject() {
return new Wakelock(mBsi, Uid.this);
}
};
- mSyncStats = mBsi.new OverflowArrayMap() {
+ mSyncStats = mBsi.new OverflowArrayMap(uid) {
@Override public StopwatchTimer instantiateObject() {
return new StopwatchTimer(mBsi.mClocks, Uid.this, SYNC, null,
mBsi.mOnBatteryTimeBase);
}
};
- mJobStats = mBsi.new OverflowArrayMap() {
+ mJobStats = mBsi.new OverflowArrayMap(uid) {
@Override public StopwatchTimer instantiateObject() {
return new StopwatchTimer(mBsi.mClocks, Uid.this, JOB, null,
mBsi.mOnBatteryTimeBase);
@@ -5629,6 +5919,36 @@ public class BatteryStatsImpl extends BatteryStats {
return 0;
}
+ public void noteMobileRadioApWakeupLocked() {
+ if (mMobileRadioApWakeupCount == null) {
+ mMobileRadioApWakeupCount = new LongSamplingCounter(mBsi.mOnBatteryTimeBase);
+ }
+ mMobileRadioApWakeupCount.addCountLocked(1);
+ }
+
+ @Override
+ public long getMobileRadioApWakeupCount(int which) {
+ if (mMobileRadioApWakeupCount != null) {
+ return mMobileRadioApWakeupCount.getCountLocked(which);
+ }
+ return 0;
+ }
+
+ public void noteWifiRadioApWakeupLocked() {
+ if (mWifiRadioApWakeupCount == null) {
+ mWifiRadioApWakeupCount = new LongSamplingCounter(mBsi.mOnBatteryTimeBase);
+ }
+ mWifiRadioApWakeupCount.addCountLocked(1);
+ }
+
+ @Override
+ public long getWifiRadioApWakeupCount(int which) {
+ if (mWifiRadioApWakeupCount != null) {
+ return mWifiRadioApWakeupCount.getCountLocked(which);
+ }
+ return 0;
+ }
+
void initNetworkActivityLocked() {
mNetworkByteActivityCounters = new LongSamplingCounter[NUM_NETWORK_ACTIVITY_TYPES];
mNetworkPacketActivityCounters = new LongSamplingCounter[NUM_NETWORK_ACTIVITY_TYPES];
@@ -5671,24 +5991,14 @@ public class BatteryStatsImpl extends BatteryStats {
active |= !mWifiMulticastTimer.reset(false);
active |= mWifiMulticastEnabled;
}
- if (mAudioTurnedOnTimer != null) {
- active |= !mAudioTurnedOnTimer.reset(false);
- }
- if (mVideoTurnedOnTimer != null) {
- active |= !mVideoTurnedOnTimer.reset(false);
- }
- if (mFlashlightTurnedOnTimer != null) {
- active |= !mFlashlightTurnedOnTimer.reset(false);
- }
- if (mCameraTurnedOnTimer != null) {
- active |= !mCameraTurnedOnTimer.reset(false);
- }
- if (mForegroundActivityTimer != null) {
- active |= !mForegroundActivityTimer.reset(false);
- }
- if (mBluetoothScanTimer != null) {
- active |= !mBluetoothScanTimer.reset(false);
- }
+
+ active |= !resetTimerIfNotNull(mAudioTurnedOnTimer, false);
+ active |= !resetTimerIfNotNull(mVideoTurnedOnTimer, false);
+ active |= !resetTimerIfNotNull(mFlashlightTurnedOnTimer, false);
+ active |= !resetTimerIfNotNull(mCameraTurnedOnTimer, false);
+ active |= !resetTimerIfNotNull(mForegroundActivityTimer, false);
+ active |= !resetTimerIfNotNull(mBluetoothScanTimer, false);
+
if (mProcessStateTimer != null) {
for (int i = 0; i < NUM_PROCESS_STATE; i++) {
if (mProcessStateTimer[i] != null) {
@@ -5749,6 +6059,9 @@ public class BatteryStatsImpl extends BatteryStats {
}
}
+ resetLongCounterIfNotNull(mMobileRadioApWakeupCount, false);
+ resetLongCounterIfNotNull(mWifiRadioApWakeupCount, false);
+
final ArrayMap wakeStats = mWakelockStats.getMap();
for (int iw=wakeStats.size()-1; iw>=0; iw--) {
Wakelock wl = wakeStats.valueAt(iw);
@@ -5908,6 +6221,9 @@ public class BatteryStatsImpl extends BatteryStats {
}
}
}
+
+ detachLongCounterIfNotNull(mMobileRadioApWakeupCount);
+ detachLongCounterIfNotNull(mWifiRadioApWakeupCount);
}
return !active;
@@ -6114,6 +6430,20 @@ public class BatteryStatsImpl extends BatteryStats {
} else {
out.writeInt(0);
}
+
+ if (mMobileRadioApWakeupCount != null) {
+ out.writeInt(1);
+ mMobileRadioApWakeupCount.writeToParcel(out);
+ } else {
+ out.writeInt(0);
+ }
+
+ if (mWifiRadioApWakeupCount != null) {
+ out.writeInt(1);
+ mWifiRadioApWakeupCount.writeToParcel(out);
+ } else {
+ out.writeInt(0);
+ }
}
void readFromParcelLocked(TimeBase timeBase, TimeBase screenOffTimeBase, Parcel in) {
@@ -6338,6 +6668,18 @@ public class BatteryStatsImpl extends BatteryStats {
} else {
mCpuClusterSpeed = null;
}
+
+ if (in.readInt() != 0) {
+ mMobileRadioApWakeupCount = new LongSamplingCounter(mBsi.mOnBatteryTimeBase, in);
+ } else {
+ mMobileRadioApWakeupCount = null;
+ }
+
+ if (in.readInt() != 0) {
+ mWifiRadioApWakeupCount = new LongSamplingCounter(mBsi.mOnBatteryTimeBase, in);
+ } else {
+ mWifiRadioApWakeupCount = null;
+ }
}
/**
@@ -6357,7 +6699,7 @@ public class BatteryStatsImpl extends BatteryStats {
/**
* How long (in ms) this uid has been keeping the device partially awake.
*/
- StopwatchTimer mTimerPartial;
+ DurationTimer mTimerPartial;
/**
* How long (in ms) this uid has been keeping the device fully awake.
@@ -6386,8 +6728,8 @@ public class BatteryStatsImpl extends BatteryStats {
* @param in the Parcel to be read from.
* return a new Timer, or null.
*/
- private StopwatchTimer readTimerFromParcel(int type, ArrayList pool,
- TimeBase timeBase, Parcel in) {
+ private StopwatchTimer readStopwatchTimerFromParcel(int type,
+ ArrayList pool, TimeBase timeBase, Parcel in) {
if (in.readInt() == 0) {
return null;
}
@@ -6395,6 +6737,22 @@ public class BatteryStatsImpl extends BatteryStats {
return new StopwatchTimer(mBsi.mClocks, mUid, type, pool, timeBase, in);
}
+ /**
+ * Reads a possibly null Timer from a Parcel. The timer is associated with the
+ * proper timer pool from the given BatteryStatsImpl object.
+ *
+ * @param in the Parcel to be read from.
+ * return a new Timer, or null.
+ */
+ private DurationTimer readDurationTimerFromParcel(int type,
+ ArrayList pool, TimeBase timeBase, Parcel in) {
+ if (in.readInt() == 0) {
+ return null;
+ }
+
+ return new DurationTimer(mBsi.mClocks, mUid, type, pool, timeBase, in);
+ }
+
boolean reset() {
boolean wlactive = false;
if (mTimerFull != null) {
@@ -6431,11 +6789,14 @@ public class BatteryStatsImpl extends BatteryStats {
}
void readFromParcelLocked(TimeBase timeBase, TimeBase screenOffTimeBase, Parcel in) {
- mTimerPartial = readTimerFromParcel(WAKE_TYPE_PARTIAL,
+ mTimerPartial = readDurationTimerFromParcel(WAKE_TYPE_PARTIAL,
mBsi.mPartialTimers, screenOffTimeBase, in);
- mTimerFull = readTimerFromParcel(WAKE_TYPE_FULL, mBsi.mFullTimers, timeBase, in);
- mTimerWindow = readTimerFromParcel(WAKE_TYPE_WINDOW, mBsi.mWindowTimers, timeBase, in);
- mTimerDraw = readTimerFromParcel(WAKE_TYPE_DRAW, mBsi.mDrawTimers, timeBase, in);
+ mTimerFull = readStopwatchTimerFromParcel(WAKE_TYPE_FULL,
+ mBsi.mFullTimers, timeBase, in);
+ mTimerWindow = readStopwatchTimerFromParcel(WAKE_TYPE_WINDOW,
+ mBsi.mWindowTimers, timeBase, in);
+ mTimerDraw = readStopwatchTimerFromParcel(WAKE_TYPE_DRAW,
+ mBsi.mDrawTimers, timeBase, in);
}
void writeToParcelLocked(Parcel out, long elapsedRealtimeUs) {
@@ -6457,40 +6818,43 @@ public class BatteryStatsImpl extends BatteryStats {
}
public StopwatchTimer getStopwatchTimer(int type) {
- StopwatchTimer t;
switch (type) {
- case WAKE_TYPE_PARTIAL:
- t = mTimerPartial;
+ case WAKE_TYPE_PARTIAL: {
+ DurationTimer t = mTimerPartial;
if (t == null) {
- t = new StopwatchTimer(mBsi.mClocks, mUid, WAKE_TYPE_PARTIAL,
+ t = new DurationTimer(mBsi.mClocks, mUid, WAKE_TYPE_PARTIAL,
mBsi.mPartialTimers, mBsi.mOnBatteryScreenOffTimeBase);
mTimerPartial = t;
}
return t;
- case WAKE_TYPE_FULL:
- t = mTimerFull;
+ }
+ case WAKE_TYPE_FULL: {
+ StopwatchTimer t = mTimerFull;
if (t == null) {
t = new StopwatchTimer(mBsi.mClocks, mUid, WAKE_TYPE_FULL,
mBsi.mFullTimers, mBsi.mOnBatteryTimeBase);
mTimerFull = t;
}
return t;
- case WAKE_TYPE_WINDOW:
- t = mTimerWindow;
+ }
+ case WAKE_TYPE_WINDOW: {
+ StopwatchTimer t = mTimerWindow;
if (t == null) {
t = new StopwatchTimer(mBsi.mClocks, mUid, WAKE_TYPE_WINDOW,
mBsi.mWindowTimers, mBsi.mOnBatteryTimeBase);
mTimerWindow = t;
}
return t;
- case WAKE_TYPE_DRAW:
- t = mTimerDraw;
+ }
+ case WAKE_TYPE_DRAW: {
+ StopwatchTimer t = mTimerDraw;
if (t == null) {
t = new StopwatchTimer(mBsi.mClocks, mUid, WAKE_TYPE_DRAW,
mBsi.mDrawTimers, mBsi.mOnBatteryTimeBase);
mTimerDraw = t;
}
return t;
+ }
default:
throw new IllegalArgumentException("type=" + type);
}
@@ -10348,6 +10712,20 @@ public class BatteryStatsImpl extends BatteryStats {
u.mCpuClusterSpeed = null;
}
+ if (in.readInt() != 0) {
+ u.mMobileRadioApWakeupCount = new LongSamplingCounter(mOnBatteryTimeBase);
+ u.mMobileRadioApWakeupCount.readSummaryFromParcelLocked(in);
+ } else {
+ u.mMobileRadioApWakeupCount = null;
+ }
+
+ if (in.readInt() != 0) {
+ u.mWifiRadioApWakeupCount = new LongSamplingCounter(mOnBatteryTimeBase);
+ u.mWifiRadioApWakeupCount.readSummaryFromParcelLocked(in);
+ } else {
+ u.mWifiRadioApWakeupCount = null;
+ }
+
int NW = in.readInt();
if (NW > 100) {
throw new ParcelFormatException("File corrupt: too many wake locks " + NW);
@@ -10708,6 +11086,20 @@ public class BatteryStatsImpl extends BatteryStats {
out.writeInt(0);
}
+ if (u.mMobileRadioApWakeupCount != null) {
+ out.writeInt(1);
+ u.mMobileRadioApWakeupCount.writeSummaryFromParcelLocked(out);
+ } else {
+ out.writeInt(0);
+ }
+
+ if (u.mWifiRadioApWakeupCount != null) {
+ out.writeInt(1);
+ u.mWifiRadioApWakeupCount.writeSummaryFromParcelLocked(out);
+ } else {
+ out.writeInt(0);
+ }
+
final ArrayMap wakeStats = u.mWakelockStats.getMap();
int NW = wakeStats.size();
out.writeInt(NW);
diff --git a/core/java/com/android/internal/os/KernelUidCpuTimeReader.java b/core/java/com/android/internal/os/KernelUidCpuTimeReader.java
index c828d11fd3d20e7bbdc3d1817441b86a6cdc3924..e8919ede82b52bd5553972d75c290bf896755682 100644
--- a/core/java/com/android/internal/os/KernelUidCpuTimeReader.java
+++ b/core/java/com/android/internal/os/KernelUidCpuTimeReader.java
@@ -120,7 +120,7 @@ public class KernelUidCpuTimeReader {
sb.append(" s=");
TimeUtils.formatDuration(systemTimeDeltaUs / 1000, sb);
sb.append(" p=").append(powerDeltaMaUs / 1000).append("mAms");
- Slog.wtf(TAG, sb.toString());
+ Slog.e(TAG, sb.toString());
userTimeDeltaUs = 0;
systemTimeDeltaUs = 0;
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index 9c960c04d4914e016142e3ece5f86fb25ddb1361..68299615b5b9f9051b9e67a96cc53e6b873c9060 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -586,21 +586,42 @@ public class ZygoteInit {
// System server is fully AOTed and never profiled
// for profile guided compilation.
// TODO: Make this configurable between INTERPRET_ONLY, SPEED, SPACE and EVERYTHING?
- final int dexoptNeeded = DexFile.getDexOptNeeded(
+
+ int dexoptNeeded;
+ try {
+ dexoptNeeded = DexFile.getDexOptNeeded(
classPathElement, instructionSet, "speed",
false /* newProfile */);
+ } catch (FileNotFoundException ignored) {
+ // Do not add to the classpath.
+ Log.w(TAG, "Missing classpath element for system server: " + classPathElement);
+ continue;
+ } catch (IOException e) {
+ // Not fully clear what to do here as we don't know the cause of the
+ // IO exception. Add to the classpath to be conservative, but don't
+ // attempt to compile it.
+ Log.w(TAG, "Error checking classpath element for system server: "
+ + classPathElement, e);
+ dexoptNeeded = DexFile.NO_DEXOPT_NEEDED;
+ }
+
if (dexoptNeeded != DexFile.NO_DEXOPT_NEEDED) {
- installer.dexopt(classPathElement, Process.SYSTEM_UID, instructionSet,
- dexoptNeeded, 0 /*dexFlags*/, "speed", null /*volumeUuid*/,
- sharedLibraries);
+ try {
+ installer.dexopt(classPathElement, Process.SYSTEM_UID, instructionSet,
+ dexoptNeeded, 0 /*dexFlags*/, "speed", null /*volumeUuid*/,
+ sharedLibraries);
+ } catch (InstallerException e) {
+ // Ignore (but log), we need this on the classpath for fallback mode.
+ Log.w(TAG, "Failed compiling classpath element for system server: "
+ + classPathElement, e);
+ }
}
+
if (!sharedLibraries.isEmpty()) {
sharedLibraries += ":";
}
sharedLibraries += classPathElement;
}
- } catch (IOException | InstallerException e) {
- throw new RuntimeException("Error starting system_server", e);
} finally {
installer.disconnect();
}
@@ -753,7 +774,7 @@ public class ZygoteInit {
closeServerSocket();
} catch (MethodAndArgsCaller caller) {
caller.run();
- } catch (RuntimeException ex) {
+ } catch (Throwable ex) {
Log.e(TAG, "Zygote died with exception", ex);
closeServerSocket();
throw ex;
diff --git a/core/java/com/android/internal/policy/BackdropFrameRenderer.java b/core/java/com/android/internal/policy/BackdropFrameRenderer.java
index 488f769cdf3182188d95d33e444033a922eb8ec0..619303f34c32e732c2a4d3de284542cbdd8cd819 100644
--- a/core/java/com/android/internal/policy/BackdropFrameRenderer.java
+++ b/core/java/com/android/internal/policy/BackdropFrameRenderer.java
@@ -371,6 +371,8 @@ public class BackdropFrameRenderer extends Thread implements Choreographer.Frame
systemInsets.bottom);
final int rightInset = DecorView.getColorViewRightInset(stableInsets.right,
systemInsets.right);
+ final int leftInset = DecorView.getColorViewLeftInset(stableInsets.left,
+ systemInsets.left);
if (mStatusBarColor != null) {
mStatusBarColor.setBounds(0, 0, left + width, topInset);
mStatusBarColor.draw(canvas);
@@ -380,9 +382,11 @@ public class BackdropFrameRenderer extends Thread implements Choreographer.Frame
// don't want the navigation bar background be moving around when resizing in docked mode.
// However, we need it for the transitions into/out of docked mode.
if (mNavigationBarColor != null && fullscreen) {
- final int size = DecorView.getNavBarSize(bottomInset, rightInset);
+ final int size = DecorView.getNavBarSize(bottomInset, rightInset, leftInset);
if (DecorView.isNavBarToRightEdge(bottomInset, rightInset)) {
mNavigationBarColor.setBounds(width - size, 0, width, height);
+ } else if (DecorView.isNavBarToLeftEdge(bottomInset, leftInset)) {
+ mNavigationBarColor.setBounds(0, 0, size, height);
} else {
mNavigationBarColor.setBounds(0, height - size, width, height);
}
diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java
index 3cf7a4e6b9ecc75f52493fd0203e2531f9cfdea8..92ab3246e354b3e427369f5701ddd836fe4332e6 100644
--- a/core/java/com/android/internal/policy/DecorView.java
+++ b/core/java/com/android/internal/policy/DecorView.java
@@ -97,11 +97,11 @@ import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACK
import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN;
import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
-import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION;
import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
+import static android.view.WindowManager.LayoutParams.TYPE_DRAWN_APPLICATION;
import static com.android.internal.policy.PhoneWindow.FEATURE_OPTIONS_PANEL;
/** @hide */
@@ -162,13 +162,13 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
private final ColorViewState mStatusColorViewState = new ColorViewState(
SYSTEM_UI_FLAG_FULLSCREEN, FLAG_TRANSLUCENT_STATUS,
- Gravity.TOP, Gravity.LEFT,
+ Gravity.TOP, Gravity.LEFT, Gravity.RIGHT,
Window.STATUS_BAR_BACKGROUND_TRANSITION_NAME,
com.android.internal.R.id.statusBarBackground,
FLAG_FULLSCREEN);
private final ColorViewState mNavigationColorViewState = new ColorViewState(
SYSTEM_UI_FLAG_HIDE_NAVIGATION, FLAG_TRANSLUCENT_NAVIGATION,
- Gravity.BOTTOM, Gravity.RIGHT,
+ Gravity.BOTTOM, Gravity.RIGHT, Gravity.LEFT,
Window.NAVIGATION_BAR_BACKGROUND_TRANSITION_NAME,
com.android.internal.R.id.navigationBarBackground,
0 /* hideWindowFlag */);
@@ -184,9 +184,11 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
private int mLastTopInset = 0;
private int mLastBottomInset = 0;
private int mLastRightInset = 0;
+ private int mLastLeftInset = 0;
private boolean mLastHasTopStableInset = false;
private boolean mLastHasBottomStableInset = false;
private boolean mLastHasRightStableInset = false;
+ private boolean mLastHasLeftStableInset = false;
private int mLastWindowFlags = 0;
private boolean mLastShouldAlwaysConsumeNavBar = false;
@@ -991,12 +993,21 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
return Math.min(stableRight, systemRight);
}
+ static int getColorViewLeftInset(int stableLeft, int systemLeft) {
+ return Math.min(stableLeft, systemLeft);
+ }
+
static boolean isNavBarToRightEdge(int bottomInset, int rightInset) {
return bottomInset == 0 && rightInset > 0;
}
- static int getNavBarSize(int bottomInset, int rightInset) {
- return isNavBarToRightEdge(bottomInset, rightInset) ? rightInset : bottomInset;
+ static boolean isNavBarToLeftEdge(int bottomInset, int leftInset) {
+ return bottomInset == 0 && leftInset > 0;
+ }
+
+ static int getNavBarSize(int bottomInset, int rightInset, int leftInset) {
+ return isNavBarToRightEdge(bottomInset, rightInset) ? rightInset
+ : isNavBarToLeftEdge(bottomInset, leftInset) ? leftInset : bottomInset;
}
WindowInsets updateColorViews(WindowInsets insets, boolean animate) {
@@ -1016,6 +1027,8 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
insets.getSystemWindowInsetBottom());
mLastRightInset = getColorViewRightInset(insets.getStableInsetRight(),
insets.getSystemWindowInsetRight());
+ mLastLeftInset = getColorViewRightInset(insets.getStableInsetLeft(),
+ insets.getSystemWindowInsetLeft());
// Don't animate if the presence of stable insets has changed, because that
// indicates that the window was either just added and received them for the
@@ -1031,21 +1044,32 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
boolean hasRightStableInset = insets.getStableInsetRight() != 0;
disallowAnimate |= (hasRightStableInset != mLastHasRightStableInset);
mLastHasRightStableInset = hasRightStableInset;
+
+ boolean hasLeftStableInset = insets.getStableInsetLeft() != 0;
+ disallowAnimate |= (hasLeftStableInset != mLastHasLeftStableInset);
+ mLastHasLeftStableInset = hasLeftStableInset;
+
mLastShouldAlwaysConsumeNavBar = insets.shouldAlwaysConsumeNavBar();
}
boolean navBarToRightEdge = isNavBarToRightEdge(mLastBottomInset, mLastRightInset);
- int navBarSize = getNavBarSize(mLastBottomInset, mLastRightInset);
+ boolean navBarToLeftEdge = isNavBarToLeftEdge(mLastBottomInset, mLastLeftInset);
+ int navBarSize = getNavBarSize(mLastBottomInset, mLastRightInset, mLastLeftInset);
updateColorViewInt(mNavigationColorViewState, sysUiVisibility,
- mWindow.mNavigationBarColor, navBarSize, navBarToRightEdge,
- 0 /* rightInset */, animate && !disallowAnimate, false /* force */);
+ mWindow.mNavigationBarColor, navBarSize, navBarToRightEdge || navBarToLeftEdge,
+ navBarToLeftEdge,
+ 0 /* sideInset */, animate && !disallowAnimate, false /* force */);
boolean statusBarNeedsRightInset = navBarToRightEdge
&& mNavigationColorViewState.present;
- int statusBarRightInset = statusBarNeedsRightInset ? mLastRightInset : 0;
+ boolean statusBarNeedsLeftInset = navBarToLeftEdge
+ && mNavigationColorViewState.present;
+ int statusBarSideInset = statusBarNeedsRightInset ? mLastRightInset
+ : statusBarNeedsLeftInset ? mLastLeftInset : 0;
updateColorViewInt(mStatusColorViewState, sysUiVisibility,
calculateStatusBarColor(), mLastTopInset,
- false /* matchVertical */, statusBarRightInset, animate && !disallowAnimate,
+ false /* matchVertical */, statusBarNeedsLeftInset, statusBarSideInset,
+ animate && !disallowAnimate,
mForceWindowDrawsStatusBarBackground);
}
@@ -1070,15 +1094,17 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
int consumedTop = consumingStatusBar ? mLastTopInset : 0;
int consumedRight = consumingNavBar ? mLastRightInset : 0;
int consumedBottom = consumingNavBar ? mLastBottomInset : 0;
+ int consumedLeft = consumingNavBar ? mLastLeftInset : 0;
if (mContentRoot != null
&& mContentRoot.getLayoutParams() instanceof MarginLayoutParams) {
MarginLayoutParams lp = (MarginLayoutParams) mContentRoot.getLayoutParams();
if (lp.topMargin != consumedTop || lp.rightMargin != consumedRight
- || lp.bottomMargin != consumedBottom) {
+ || lp.bottomMargin != consumedBottom || lp.leftMargin != consumedLeft) {
lp.topMargin = consumedTop;
lp.rightMargin = consumedRight;
lp.bottomMargin = consumedBottom;
+ lp.leftMargin = consumedLeft;
mContentRoot.setLayoutParams(lp);
if (insets == null) {
@@ -1089,7 +1115,7 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
}
if (insets != null) {
insets = insets.replaceSystemWindowInsets(
- insets.getSystemWindowInsetLeft(),
+ insets.getSystemWindowInsetLeft() - consumedLeft,
insets.getSystemWindowInsetTop() - consumedTop,
insets.getSystemWindowInsetRight() - consumedRight,
insets.getSystemWindowInsetBottom() - consumedBottom);
@@ -1126,11 +1152,12 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
* @param size the current size in the non-parent-matching dimension.
* @param verticalBar if true the view is attached to a vertical edge, otherwise to a
* horizontal edge,
- * @param rightMargin rightMargin for the color view.
+ * @param sideMargin sideMargin for the color view.
* @param animate if true, the change will be animated.
*/
private void updateColorViewInt(final ColorViewState state, int sysUiVis, int color,
- int size, boolean verticalBar, int rightMargin, boolean animate, boolean force) {
+ int size, boolean verticalBar, boolean seascape, int sideMargin,
+ boolean animate, boolean force) {
state.present = (sysUiVis & state.systemUiHideFlag) == 0
&& (mWindow.getAttributes().flags & state.hideWindowFlag) == 0
&& ((mWindow.getAttributes().flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0
@@ -1145,7 +1172,9 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
int resolvedHeight = verticalBar ? LayoutParams.MATCH_PARENT : size;
int resolvedWidth = verticalBar ? size : LayoutParams.MATCH_PARENT;
- int resolvedGravity = verticalBar ? state.horizontalGravity : state.verticalGravity;
+ int resolvedGravity = verticalBar
+ ? (seascape ? state.seascapeGravity : state.horizontalGravity)
+ : state.verticalGravity;
if (view == null) {
if (showView) {
@@ -1159,7 +1188,11 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
LayoutParams lp = new LayoutParams(resolvedWidth, resolvedHeight,
resolvedGravity);
- lp.rightMargin = rightMargin;
+ if (seascape) {
+ lp.leftMargin = sideMargin;
+ } else {
+ lp.rightMargin = sideMargin;
+ }
addView(view, lp);
updateColorViewTranslations();
}
@@ -1168,12 +1201,16 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
visibilityChanged = state.targetVisibility != vis;
state.targetVisibility = vis;
LayoutParams lp = (LayoutParams) view.getLayoutParams();
+ int rightMargin = seascape ? 0 : sideMargin;
+ int leftMargin = seascape ? sideMargin : 0;
if (lp.height != resolvedHeight || lp.width != resolvedWidth
- || lp.gravity != resolvedGravity || lp.rightMargin != rightMargin) {
+ || lp.gravity != resolvedGravity || lp.rightMargin != rightMargin
+ || lp.leftMargin != leftMargin) {
lp.height = resolvedHeight;
lp.width = resolvedWidth;
lp.gravity = resolvedGravity;
lp.rightMargin = rightMargin;
+ lp.leftMargin = leftMargin;
view.setLayoutParams(lp);
}
if (showView) {
@@ -1824,7 +1861,7 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
}
final WindowManager.LayoutParams attrs = mWindow.getAttributes();
final boolean isApplication = attrs.type == TYPE_BASE_APPLICATION ||
- attrs.type == TYPE_APPLICATION;
+ attrs.type == TYPE_APPLICATION || attrs.type == TYPE_DRAWN_APPLICATION;
// Only a non floating application window on one of the allowed workspaces can get a caption
if (!mWindow.isFloating() && isApplication && StackId.hasWindowDecor(mStackId)) {
// Dependent on the brightness of the used title we either use the
@@ -2217,17 +2254,19 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
final int translucentFlag;
final int verticalGravity;
final int horizontalGravity;
+ final int seascapeGravity;
final String transitionName;
final int hideWindowFlag;
ColorViewState(int systemUiHideFlag,
int translucentFlag, int verticalGravity, int horizontalGravity,
- String transitionName, int id, int hideWindowFlag) {
+ int seascapeGravity, String transitionName, int id, int hideWindowFlag) {
this.id = id;
this.systemUiHideFlag = systemUiHideFlag;
this.translucentFlag = translucentFlag;
this.verticalGravity = verticalGravity;
this.horizontalGravity = horizontalGravity;
+ this.seascapeGravity = seascapeGravity;
this.transitionName = transitionName;
this.hideWindowFlag = hideWindowFlag;
}
diff --git a/core/java/com/android/internal/policy/IKeyguardService.aidl b/core/java/com/android/internal/policy/IKeyguardService.aidl
index 171a264eea8b2c4bc210b3e8ed4930c2290e04fd..83d75fba80f9ade4f40b9eab79f75800f585986e 100644
--- a/core/java/com/android/internal/policy/IKeyguardService.aidl
+++ b/core/java/com/android/internal/policy/IKeyguardService.aidl
@@ -34,7 +34,7 @@ oneway interface IKeyguardService {
void addStateMonitorCallback(IKeyguardStateCallback callback);
void verifyUnlock(IKeyguardExitCallback callback);
void keyguardDone(boolean authenticated, boolean wakeup);
- void dismiss();
+ void dismiss(boolean allowWhileOccluded);
void onDreamingStarted();
void onDreamingStopped();
diff --git a/core/java/com/android/internal/policy/IKeyguardStateCallback.aidl b/core/java/com/android/internal/policy/IKeyguardStateCallback.aidl
index db3b40b29903e62822a5179490e63e9a69207ce6..8e454db4cb040146664e9e58f5c0829680ead6eb 100644
--- a/core/java/com/android/internal/policy/IKeyguardStateCallback.aidl
+++ b/core/java/com/android/internal/policy/IKeyguardStateCallback.aidl
@@ -19,4 +19,6 @@ interface IKeyguardStateCallback {
void onShowingStateChanged(boolean showing);
void onSimSecureStateChanged(boolean simSecure);
void onInputRestrictedStateChanged(boolean inputRestricted);
+ void onTrustedChanged(boolean trusted);
+ void onHasLockscreenWallpaperChanged(boolean hasLockscreenWallpaper);
}
\ No newline at end of file
diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java
index 9ad750d3a59945c280f753872f4fa17ac6f64bb9..878f3a69a504bd3f329c01f53fcf2c98108c54ea 100644
--- a/core/java/com/android/internal/policy/PhoneWindow.java
+++ b/core/java/com/android/internal/policy/PhoneWindow.java
@@ -92,8 +92,6 @@ import android.util.EventLog;
import android.util.Log;
import android.util.SparseArray;
import android.util.TypedValue;
-import android.view.accessibility.AccessibilityNodeInfo;
-import android.view.accessibility.AccessibilityNodeProvider;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.FrameLayout;
@@ -2057,9 +2055,6 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
}
static private final String FOCUSED_ID_TAG = "android:focusedViewId";
- static private final String ACCESSIBILITY_FOCUSED_ID_TAG = "android:accessibilityFocusedViewId";
- static private final String ACCESSIBILITY_FOCUSED_VIRTUAL_ID_TAG =
- "android:accessibilityFocusedVirtualViewId";
static private final String VIEWS_TAG = "android:views";
static private final String PANELS_TAG = "android:Panels";
static private final String ACTION_BAR_TAG = "android:ActionBar";
@@ -2082,26 +2077,6 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
outState.putInt(FOCUSED_ID_TAG, focusedView.getId());
}
- // Save the accessibility focused view ID.
- if (mDecor != null) {
- final ViewRootImpl viewRootImpl = mDecor.getViewRootImpl();
- if (viewRootImpl != null) {
- final View accessFocusHost = viewRootImpl.getAccessibilityFocusedHost();
- if (accessFocusHost != null && accessFocusHost.getId() != View.NO_ID) {
- outState.putInt(ACCESSIBILITY_FOCUSED_ID_TAG, accessFocusHost.getId());
-
- // If we have a focused virtual node ID, save that too.
- final AccessibilityNodeInfo accessFocusedNode =
- viewRootImpl.getAccessibilityFocusedVirtualView();
- if (accessFocusedNode != null) {
- final int virtualNodeId = AccessibilityNodeInfo.getVirtualDescendantId(
- accessFocusedNode.getSourceNodeId());
- outState.putInt(ACCESSIBILITY_FOCUSED_VIRTUAL_ID_TAG, virtualNodeId);
- }
- }
- }
- }
-
// save the panels
SparseArray panelStates = new SparseArray();
savePanelState(panelStates);
@@ -2144,13 +2119,6 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
}
}
- // Restore the accessibility focused view.
- final int accessFocusHostViewId = savedInstanceState.getInt(
- ACCESSIBILITY_FOCUSED_ID_TAG, View.NO_ID);
- final int accessFocusVirtualViewId = savedInstanceState.getInt(
- ACCESSIBILITY_FOCUSED_VIRTUAL_ID_TAG, AccessibilityNodeInfo.UNDEFINED_ITEM_ID);
- tryRestoreAccessibilityFocus(accessFocusHostViewId, accessFocusVirtualViewId);
-
// Restore the panels.
SparseArray panelStates = savedInstanceState.getSparseParcelableArray(PANELS_TAG);
if (panelStates != null) {
@@ -2170,33 +2138,6 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
}
}
- private void tryRestoreAccessibilityFocus(int hostViewId, int virtualViewId) {
- if (hostViewId != View.NO_ID && mDecor != null) {
- final View needsAccessFocus = mDecor.findViewById(hostViewId);
- if (needsAccessFocus != null) {
- if (!tryFocusingVirtualView(needsAccessFocus, virtualViewId)
- && !needsAccessFocus.requestAccessibilityFocus()) {
- Log.w(TAG, "Failed to restore focus to previously accessibility"
- + " focused view with id " + hostViewId);
- }
- } else {
- Log.w(TAG, "Previously accessibility focused view reported id " + hostViewId
- + " during save, but can't be found during restore.");
- }
- }
- }
-
- private boolean tryFocusingVirtualView(View host, int virtualViewId) {
- if (virtualViewId != AccessibilityNodeInfo.UNDEFINED_ITEM_ID) {
- final AccessibilityNodeProvider nodeProvider = host.getAccessibilityNodeProvider();
- if (nodeProvider != null) {
- return nodeProvider.performAction(virtualViewId,
- AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS, null);
- }
- }
- return false;
- }
-
/**
* Invoked when the panels should freeze their state.
*
diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl
index 7706ff7f173ffe4e48d5727b7af48f35dc89dc2d..20f10b33343b197ec22a523507e4a39b6ee5f497 100644
--- a/core/java/com/android/internal/statusbar/IStatusBar.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl
@@ -112,4 +112,5 @@ oneway interface IStatusBar
void addQsTile(in ComponentName tile);
void remQsTile(in ComponentName tile);
void clickQsTile(in ComponentName tile);
+ void handleSystemNavigationKey(in int key);
}
diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
index 3d054225d2342b0ec4480683f949044cc0c1525b..698e387175fbc719a4cdff2378c52edb75d206f7 100644
--- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
@@ -66,4 +66,5 @@ interface IStatusBarService
void addTile(in ComponentName tile);
void remTile(in ComponentName tile);
void clickTile(in ComponentName tile);
+ void handleSystemNavigationKey(in int key);
}
diff --git a/core/java/com/android/internal/util/MimeIconUtils.java b/core/java/com/android/internal/util/MimeIconUtils.java
new file mode 100644
index 0000000000000000000000000000000000000000..841ec7ca994ceca849f47b29be8291a392cf4559
--- /dev/null
+++ b/core/java/com/android/internal/util/MimeIconUtils.java
@@ -0,0 +1,230 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.util;
+
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.provider.DocumentsContract;
+
+import com.android.internal.R;
+
+import java.util.HashMap;
+
+public class MimeIconUtils {
+
+ private static HashMap sMimeIcons = new HashMap<>();
+
+ private static void add(String mimeType, int resId) {
+ if (sMimeIcons.put(mimeType, resId) != null) {
+ throw new RuntimeException(mimeType + " already registered!");
+ }
+ }
+
+ static {
+ int icon;
+
+ // Package
+ icon = R.drawable.ic_doc_apk;
+ add("application/vnd.android.package-archive", icon);
+
+ // Audio
+ icon = R.drawable.ic_doc_audio;
+ add("application/ogg", icon);
+ add("application/x-flac", icon);
+
+ // Certificate
+ icon = R.drawable.ic_doc_certificate;
+ add("application/pgp-keys", icon);
+ add("application/pgp-signature", icon);
+ add("application/x-pkcs12", icon);
+ add("application/x-pkcs7-certreqresp", icon);
+ add("application/x-pkcs7-crl", icon);
+ add("application/x-x509-ca-cert", icon);
+ add("application/x-x509-user-cert", icon);
+ add("application/x-pkcs7-certificates", icon);
+ add("application/x-pkcs7-mime", icon);
+ add("application/x-pkcs7-signature", icon);
+
+ // Source code
+ icon = R.drawable.ic_doc_codes;
+ add("application/rdf+xml", icon);
+ add("application/rss+xml", icon);
+ add("application/x-object", icon);
+ add("application/xhtml+xml", icon);
+ add("text/css", icon);
+ add("text/html", icon);
+ add("text/xml", icon);
+ add("text/x-c++hdr", icon);
+ add("text/x-c++src", icon);
+ add("text/x-chdr", icon);
+ add("text/x-csrc", icon);
+ add("text/x-dsrc", icon);
+ add("text/x-csh", icon);
+ add("text/x-haskell", icon);
+ add("text/x-java", icon);
+ add("text/x-literate-haskell", icon);
+ add("text/x-pascal", icon);
+ add("text/x-tcl", icon);
+ add("text/x-tex", icon);
+ add("application/x-latex", icon);
+ add("application/x-texinfo", icon);
+ add("application/atom+xml", icon);
+ add("application/ecmascript", icon);
+ add("application/json", icon);
+ add("application/javascript", icon);
+ add("application/xml", icon);
+ add("text/javascript", icon);
+ add("application/x-javascript", icon);
+
+ // Compressed
+ icon = R.drawable.ic_doc_compressed;
+ add("application/mac-binhex40", icon);
+ add("application/rar", icon);
+ add("application/zip", icon);
+ add("application/x-apple-diskimage", icon);
+ add("application/x-debian-package", icon);
+ add("application/x-gtar", icon);
+ add("application/x-iso9660-image", icon);
+ add("application/x-lha", icon);
+ add("application/x-lzh", icon);
+ add("application/x-lzx", icon);
+ add("application/x-stuffit", icon);
+ add("application/x-tar", icon);
+ add("application/x-webarchive", icon);
+ add("application/x-webarchive-xml", icon);
+ add("application/gzip", icon);
+ add("application/x-7z-compressed", icon);
+ add("application/x-deb", icon);
+ add("application/x-rar-compressed", icon);
+
+ // Contact
+ icon = R.drawable.ic_doc_contact;
+ add("text/x-vcard", icon);
+ add("text/vcard", icon);
+
+ // Event
+ icon = R.drawable.ic_doc_event;
+ add("text/calendar", icon);
+ add("text/x-vcalendar", icon);
+
+ // Font
+ icon = R.drawable.ic_doc_font;
+ add("application/x-font", icon);
+ add("application/font-woff", icon);
+ add("application/x-font-woff", icon);
+ add("application/x-font-ttf", icon);
+
+ // Image
+ icon = R.drawable.ic_doc_image;
+ add("application/vnd.oasis.opendocument.graphics", icon);
+ add("application/vnd.oasis.opendocument.graphics-template", icon);
+ add("application/vnd.oasis.opendocument.image", icon);
+ add("application/vnd.stardivision.draw", icon);
+ add("application/vnd.sun.xml.draw", icon);
+ add("application/vnd.sun.xml.draw.template", icon);
+
+ // PDF
+ icon = R.drawable.ic_doc_pdf;
+ add("application/pdf", icon);
+
+ // Presentation
+ icon = R.drawable.ic_doc_presentation;
+ add("application/vnd.stardivision.impress", icon);
+ add("application/vnd.sun.xml.impress", icon);
+ add("application/vnd.sun.xml.impress.template", icon);
+ add("application/x-kpresenter", icon);
+ add("application/vnd.oasis.opendocument.presentation", icon);
+
+ // Spreadsheet
+ icon = R.drawable.ic_doc_spreadsheet;
+ add("application/vnd.oasis.opendocument.spreadsheet", icon);
+ add("application/vnd.oasis.opendocument.spreadsheet-template", icon);
+ add("application/vnd.stardivision.calc", icon);
+ add("application/vnd.sun.xml.calc", icon);
+ add("application/vnd.sun.xml.calc.template", icon);
+ add("application/x-kspread", icon);
+
+ // Document
+ icon = R.drawable.ic_doc_document;
+ add("application/vnd.oasis.opendocument.text", icon);
+ add("application/vnd.oasis.opendocument.text-master", icon);
+ add("application/vnd.oasis.opendocument.text-template", icon);
+ add("application/vnd.oasis.opendocument.text-web", icon);
+ add("application/vnd.stardivision.writer", icon);
+ add("application/vnd.stardivision.writer-global", icon);
+ add("application/vnd.sun.xml.writer", icon);
+ add("application/vnd.sun.xml.writer.global", icon);
+ add("application/vnd.sun.xml.writer.template", icon);
+ add("application/x-abiword", icon);
+ add("application/x-kword", icon);
+
+ // Video
+ icon = R.drawable.ic_doc_video;
+ add("application/x-quicktimeplayer", icon);
+ add("application/x-shockwave-flash", icon);
+
+ // Word
+ icon = R.drawable.ic_doc_word;
+ add("application/msword", icon);
+ add("application/vnd.openxmlformats-officedocument.wordprocessingml.document", icon);
+ add("application/vnd.openxmlformats-officedocument.wordprocessingml.template", icon);
+
+ // Excel
+ icon = R.drawable.ic_doc_excel;
+ add("application/vnd.ms-excel", icon);
+ add("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", icon);
+ add("application/vnd.openxmlformats-officedocument.spreadsheetml.template", icon);
+
+ // Powerpoint
+ icon = R.drawable.ic_doc_powerpoint;
+ add("application/vnd.ms-powerpoint", icon);
+ add("application/vnd.openxmlformats-officedocument.presentationml.presentation", icon);
+ add("application/vnd.openxmlformats-officedocument.presentationml.template", icon);
+ add("application/vnd.openxmlformats-officedocument.presentationml.slideshow", icon);
+ }
+
+ public static Drawable loadMimeIcon(Context context, String mimeType) {
+ if (DocumentsContract.Document.MIME_TYPE_DIR.equals(mimeType)) {
+ return context.getDrawable(R.drawable.ic_doc_folder);
+ }
+
+ // Look for exact match first
+ Integer resId = sMimeIcons.get(mimeType);
+ if (resId != null) {
+ return context.getDrawable(resId);
+ }
+
+ if (mimeType == null) {
+ // TODO: generic icon?
+ return null;
+ }
+
+ // Otherwise look for partial match
+ final String typeOnly = mimeType.split("/")[0];
+ if ("audio".equals(typeOnly)) {
+ return context.getDrawable(R.drawable.ic_doc_audio);
+ } else if ("image".equals(typeOnly)) {
+ return context.getDrawable(R.drawable.ic_doc_image);
+ } else if ("text".equals(typeOnly)) {
+ return context.getDrawable(R.drawable.ic_doc_text);
+ } else if ("video".equals(typeOnly)) {
+ return context.getDrawable(R.drawable.ic_doc_video);
+ } else {
+ return context.getDrawable(R.drawable.ic_doc_generic);
+ }
+ }
+}
diff --git a/core/java/com/android/internal/util/NotificationColorUtil.java b/core/java/com/android/internal/util/NotificationColorUtil.java
index 48bcc09301648ab2f9ef85b99a40050d1a3bf06e..4748e6fb19ff0f9d21d4c6de42ebebb429aaa386 100644
--- a/core/java/com/android/internal/util/NotificationColorUtil.java
+++ b/core/java/com/android/internal/util/NotificationColorUtil.java
@@ -271,7 +271,7 @@ public class NotificationColorUtil {
* Finds a text color with sufficient contrast over bg that has the same hue as the original
* color, assuming it is for large text.
*/
- private static int ensureLargeTextContrast(int color, int bg) {
+ public static int ensureLargeTextContrast(int color, int bg) {
return findContrastColor(color, bg, true, 3);
}
@@ -340,6 +340,20 @@ public class NotificationColorUtil {
return color;
}
+ /**
+ * Lighten a color by a specified value
+ * @param baseColor the base color to lighten
+ * @param amount the amount to lighten the color from 0 to 100. This corresponds to the L
+ * increase in the LAB color space.
+ * @return the lightened color
+ */
+ public static int lightenColor(int baseColor, int amount) {
+ final double[] result = ColorUtilsFromCompat.getTempDouble3Array();
+ ColorUtilsFromCompat.colorToLAB(baseColor, result);
+ result[0] = Math.min(100, result[0] + amount);
+ return ColorUtilsFromCompat.LABToColor(result[0], result[1], result[2]);
+ }
+
/**
* Framework copy of functions needed from android.support.v4.graphics.ColorUtils.
*/
@@ -434,7 +448,7 @@ public class NotificationColorUtil {
* Convert RGB components to its CIE Lab representative components.
*
*
- *
outLab[0] is L [0 ...1)
+ *
outLab[0] is L [0 ...100)
*
outLab[1] is a [-128...127)
*
outLab[2] is b [-128...127)
*
@@ -516,7 +530,7 @@ public class NotificationColorUtil {
* 2° Standard Observer (1931).
*
*
- *
outLab[0] is L [0 ...1)
+ *
outLab[0] is L [0 ...100)
*
outLab[1] is a [-128...127)
*
outLab[2] is b [-128...127)
*
@@ -634,7 +648,7 @@ public class NotificationColorUtil {
: (XYZ_KAPPA * component + 16) / 116;
}
- private static double[] getTempDouble3Array() {
+ public static double[] getTempDouble3Array() {
double[] result = TEMP_ARRAY.get();
if (result == null) {
result = new double[3];
diff --git a/core/java/com/android/internal/util/StateMachine.java b/core/java/com/android/internal/util/StateMachine.java
index e93d911af93a60c2e8de457243f3e12fcd3d2d0e..f804002df2d09dff5d1f06ce59915625b5b5cd26 100644
--- a/core/java/com/android/internal/util/StateMachine.java
+++ b/core/java/com/android/internal/util/StateMachine.java
@@ -29,8 +29,8 @@ import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
-import java.util.Iterator;
import java.util.HashMap;
+import java.util.Iterator;
import java.util.Vector;
/**
@@ -1642,7 +1642,7 @@ public class StateMachine {
*
* Message is ignored if state machine has quit.
*/
- public final void sendMessage(int what) {
+ public void sendMessage(int what) {
// mSmHandler can be null if the state machine has quit.
SmHandler smh = mSmHandler;
if (smh == null) return;
@@ -1655,7 +1655,7 @@ public class StateMachine {
*
* Message is ignored if state machine has quit.
*/
- public final void sendMessage(int what, Object obj) {
+ public void sendMessage(int what, Object obj) {
// mSmHandler can be null if the state machine has quit.
SmHandler smh = mSmHandler;
if (smh == null) return;
@@ -1668,7 +1668,7 @@ public class StateMachine {
*
* Message is ignored if state machine has quit.
*/
- public final void sendMessage(int what, int arg1) {
+ public void sendMessage(int what, int arg1) {
// mSmHandler can be null if the state machine has quit.
SmHandler smh = mSmHandler;
if (smh == null) return;
@@ -1681,7 +1681,7 @@ public class StateMachine {
*
* Message is ignored if state machine has quit.
*/
- public final void sendMessage(int what, int arg1, int arg2) {
+ public void sendMessage(int what, int arg1, int arg2) {
// mSmHandler can be null if the state machine has quit.
SmHandler smh = mSmHandler;
if (smh == null) return;
@@ -1694,7 +1694,7 @@ public class StateMachine {
*
* Message is ignored if state machine has quit.
*/
- public final void sendMessage(int what, int arg1, int arg2, Object obj) {
+ public void sendMessage(int what, int arg1, int arg2, Object obj) {
// mSmHandler can be null if the state machine has quit.
SmHandler smh = mSmHandler;
if (smh == null) return;
@@ -1707,7 +1707,7 @@ public class StateMachine {
*
* Message is ignored if state machine has quit.
*/
- public final void sendMessage(Message msg) {
+ public void sendMessage(Message msg) {
// mSmHandler can be null if the state machine has quit.
SmHandler smh = mSmHandler;
if (smh == null) return;
@@ -1720,7 +1720,7 @@ public class StateMachine {
*
* Message is ignored if state machine has quit.
*/
- public final void sendMessageDelayed(int what, long delayMillis) {
+ public void sendMessageDelayed(int what, long delayMillis) {
// mSmHandler can be null if the state machine has quit.
SmHandler smh = mSmHandler;
if (smh == null) return;
@@ -1733,7 +1733,7 @@ public class StateMachine {
*
* Message is ignored if state machine has quit.
*/
- public final void sendMessageDelayed(int what, Object obj, long delayMillis) {
+ public void sendMessageDelayed(int what, Object obj, long delayMillis) {
// mSmHandler can be null if the state machine has quit.
SmHandler smh = mSmHandler;
if (smh == null) return;
@@ -1746,7 +1746,7 @@ public class StateMachine {
*
* Message is ignored if state machine has quit.
*/
- public final void sendMessageDelayed(int what, int arg1, long delayMillis) {
+ public void sendMessageDelayed(int what, int arg1, long delayMillis) {
// mSmHandler can be null if the state machine has quit.
SmHandler smh = mSmHandler;
if (smh == null) return;
@@ -1759,7 +1759,7 @@ public class StateMachine {
*
* Message is ignored if state machine has quit.
*/
- public final void sendMessageDelayed(int what, int arg1, int arg2, long delayMillis) {
+ public void sendMessageDelayed(int what, int arg1, int arg2, long delayMillis) {
// mSmHandler can be null if the state machine has quit.
SmHandler smh = mSmHandler;
if (smh == null) return;
@@ -1772,7 +1772,7 @@ public class StateMachine {
*
* Message is ignored if state machine has quit.
*/
- public final void sendMessageDelayed(int what, int arg1, int arg2, Object obj,
+ public void sendMessageDelayed(int what, int arg1, int arg2, Object obj,
long delayMillis) {
// mSmHandler can be null if the state machine has quit.
SmHandler smh = mSmHandler;
@@ -1786,7 +1786,7 @@ public class StateMachine {
*
* Message is ignored if state machine has quit.
*/
- public final void sendMessageDelayed(Message msg, long delayMillis) {
+ public void sendMessageDelayed(Message msg, long delayMillis) {
// mSmHandler can be null if the state machine has quit.
SmHandler smh = mSmHandler;
if (smh == null) return;
diff --git a/core/java/com/android/internal/util/WakeupMessage.java b/core/java/com/android/internal/util/WakeupMessage.java
index 26537451992c609750aa2ab16e89f5f9acc796e4..7d222c74ac3beb246d1c3eb6a8b689ace04a8c30 100644
--- a/core/java/com/android/internal/util/WakeupMessage.java
+++ b/core/java/com/android/internal/util/WakeupMessage.java
@@ -45,24 +45,32 @@ public class WakeupMessage implements AlarmManager.OnAlarmListener {
protected final String mCmdName;
@VisibleForTesting
protected final int mCmd, mArg1, mArg2;
+ @VisibleForTesting
+ protected final Object mObj;
private boolean mScheduled;
public WakeupMessage(Context context, Handler handler,
- String cmdName, int cmd, int arg1, int arg2) {
+ String cmdName, int cmd, int arg1, int arg2, Object obj) {
mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
mHandler = handler;
mCmdName = cmdName;
mCmd = cmd;
mArg1 = arg1;
mArg2 = arg2;
+ mObj = obj;
}
public WakeupMessage(Context context, Handler handler, String cmdName, int cmd, int arg1) {
- this(context, handler, cmdName, cmd, arg1, 0);
+ this(context, handler, cmdName, cmd, arg1, 0, null);
+ }
+
+ public WakeupMessage(Context context, Handler handler,
+ String cmdName, int cmd, int arg1, int arg2) {
+ this(context, handler, cmdName, cmd, arg1, arg2, null);
}
public WakeupMessage(Context context, Handler handler, String cmdName, int cmd) {
- this(context, handler, cmdName, cmd, 0, 0);
+ this(context, handler, cmdName, cmd, 0, 0, null);
}
/**
@@ -99,7 +107,7 @@ public class WakeupMessage implements AlarmManager.OnAlarmListener {
mScheduled = false;
}
if (stillScheduled) {
- Message msg = mHandler.obtainMessage(mCmd, mArg1, mArg2);
+ Message msg = mHandler.obtainMessage(mCmd, mArg1, mArg2, mObj);
mHandler.handleMessage(msg);
msg.recycle();
}
diff --git a/core/java/com/android/internal/view/IInputConnectionWrapper.java b/core/java/com/android/internal/view/IInputConnectionWrapper.java
index 59b4b35fa24ef16a5f113ef65ff2d03e375893fb..644c7e90f8b024a0ddf41d36ca28db926b7ce988 100644
--- a/core/java/com/android/internal/view/IInputConnectionWrapper.java
+++ b/core/java/com/android/internal/view/IInputConnectionWrapper.java
@@ -33,6 +33,7 @@ import android.view.inputmethod.ExtractedTextRequest;
import android.view.inputmethod.InputConnection;
import android.view.inputmethod.InputConnectionInspector;
import android.view.inputmethod.InputConnectionInspector.MissingMethodFlags;
+import android.view.inputmethod.InputContentInfo;
public abstract class IInputConnectionWrapper extends IInputContext.Stub {
static final String TAG = "IInputConnectionWrapper";
@@ -61,6 +62,7 @@ public abstract class IInputConnectionWrapper extends IInputContext.Stub {
private static final int DO_CLEAR_META_KEY_STATES = 130;
private static final int DO_REQUEST_UPDATE_CURSOR_ANCHOR_INFO = 140;
private static final int DO_CLOSE_CONNECTION = 150;
+ private static final int DO_COMMIT_CONTENT = 160;
@GuardedBy("mLock")
@Nullable
@@ -241,6 +243,12 @@ public abstract class IInputConnectionWrapper extends IInputContext.Stub {
dispatchMessage(obtainMessage(DO_CLOSE_CONNECTION));
}
+ public void commitContent(InputContentInfo inputContentInfo, int flags, Bundle opts,
+ int seq, IInputContextCallback callback) {
+ dispatchMessage(obtainMessageIOOSC(DO_COMMIT_CONTENT, flags, inputContentInfo, opts, seq,
+ callback));
+ }
+
void dispatchMessage(Message msg) {
// If we are calling this from the main thread, then we can call
// right through. Otherwise, we need to send the message to the
@@ -552,6 +560,41 @@ public abstract class IInputConnectionWrapper extends IInputContext.Stub {
}
return;
}
+ case DO_COMMIT_CONTENT: {
+ final int flags = msg.arg1;
+ final boolean grantUriPermission =
+ (flags & InputConnection.INPUT_CONTENT_GRANT_READ_URI_PERMISSION) != 0;
+ SomeArgs args = (SomeArgs) msg.obj;
+ try {
+ InputConnection ic = getInputConnection();
+ if (ic == null || !isActive()) {
+ Log.w(TAG, "commitContent on inactive InputConnection");
+ args.callback.setCommitContentResult(false, args.seq);
+ return;
+ }
+ final InputContentInfo inputContentInfo = (InputContentInfo) args.arg1;
+ if (inputContentInfo == null || !inputContentInfo.validate()) {
+ Log.w(TAG, "commitContent with invalid inputContentInfo="
+ + inputContentInfo);
+ args.callback.setCommitContentResult(false, args.seq);
+ return;
+ }
+ if (grantUriPermission) {
+ inputContentInfo.requestPermission();
+ }
+ final boolean result =
+ ic.commitContent(inputContentInfo, flags, (Bundle) args.arg2);
+ // If this request is not handled, then there is no reason to keep the URI
+ // permission.
+ if (grantUriPermission && !result) {
+ inputContentInfo.releasePermission();
+ }
+ args.callback.setCommitContentResult(result, args.seq);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Got RemoteException calling commitContent", e);
+ }
+ return;
+ }
}
Log.w(TAG, "Unhandled message code: " + msg.what);
}
@@ -582,12 +625,14 @@ public abstract class IInputConnectionWrapper extends IInputContext.Stub {
return mH.obtainMessage(what, arg1, arg2, args);
}
- Message obtainMessageOSC(int what, Object arg1, int seq, IInputContextCallback callback) {
+ Message obtainMessageIOOSC(int what, int arg1, Object objArg1, Object objArg2, int seq,
+ IInputContextCallback callback) {
SomeArgs args = new SomeArgs();
- args.arg1 = arg1;
+ args.arg1 = objArg1;
+ args.arg2 = objArg2;
args.callback = callback;
args.seq = seq;
- return mH.obtainMessage(what, 0, 0, args);
+ return mH.obtainMessage(what, arg1, 0, args);
}
Message obtainMessageIOSC(int what, int arg1, Object arg2, int seq,
diff --git a/core/java/com/android/internal/view/IInputContext.aidl b/core/java/com/android/internal/view/IInputContext.aidl
index f7ec420ba6769041fc09e54cf92d2e5c9bef0282..728c55786c49c352ed4640d46f01113f1f8b9e3d 100644
--- a/core/java/com/android/internal/view/IInputContext.aidl
+++ b/core/java/com/android/internal/view/IInputContext.aidl
@@ -21,6 +21,7 @@ import android.view.KeyEvent;
import android.view.inputmethod.CompletionInfo;
import android.view.inputmethod.CorrectionInfo;
import android.view.inputmethod.ExtractedTextRequest;
+import android.view.inputmethod.InputContentInfo;
import com.android.internal.view.IInputContextCallback;
@@ -74,6 +75,9 @@ import com.android.internal.view.IInputContextCallback;
void getSelectedText(int flags, int seq, IInputContextCallback callback);
- void requestUpdateCursorAnchorInfo(in int cursorUpdateMode, int seq,
+ void requestUpdateCursorAnchorInfo(int cursorUpdateMode, int seq,
+ IInputContextCallback callback);
+
+ void commitContent(in InputContentInfo inputContentInfo, int flags, in Bundle opts, int sec,
IInputContextCallback callback);
}
diff --git a/core/java/com/android/internal/view/IInputContextCallback.aidl b/core/java/com/android/internal/view/IInputContextCallback.aidl
index 54ea3064bd7e68058c5b307485ac7939ec770524..0f40a83d7ee4b4968f138a86ebfb010d30f74ee5 100644
--- a/core/java/com/android/internal/view/IInputContextCallback.aidl
+++ b/core/java/com/android/internal/view/IInputContextCallback.aidl
@@ -28,4 +28,5 @@ oneway interface IInputContextCallback {
void setExtractedText(in ExtractedText extractedText, int seq);
void setSelectedText(CharSequence selectedText, int seq);
void setRequestUpdateCursorAnchorInfoResult(boolean result, int seq);
+ void setCommitContentResult(boolean result, int seq);
}
diff --git a/core/java/com/android/internal/view/IInputMethodManager.aidl b/core/java/com/android/internal/view/IInputMethodManager.aidl
index cb7c3bfecc89bacea0498fcb482346b2a9673312..9e4b43b6c007dcf8077f8f84a67b4c4ac499a5aa 100644
--- a/core/java/com/android/internal/view/IInputMethodManager.aidl
+++ b/core/java/com/android/internal/view/IInputMethodManager.aidl
@@ -16,11 +16,13 @@
package com.android.internal.view;
+import android.net.Uri;
import android.os.ResultReceiver;
import android.text.style.SuggestionSpan;
import android.view.inputmethod.InputMethodInfo;
import android.view.inputmethod.InputMethodSubtype;
import android.view.inputmethod.EditorInfo;
+import com.android.internal.inputmethod.IInputContentUriToken;
import com.android.internal.view.InputBindResult;
import com.android.internal.view.IInputContext;
import com.android.internal.view.IInputMethodClient;
@@ -81,5 +83,8 @@ interface IInputMethodManager {
int getInputMethodWindowVisibleHeight();
void clearLastInputMethodWindowForTransition(in IBinder token);
+ IInputContentUriToken createInputContentUriToken(in IBinder token, in Uri contentUri,
+ in String packageName);
+
oneway void notifyUserAction(int sequenceNumber);
}
diff --git a/core/java/com/android/internal/view/InputConnectionWrapper.java b/core/java/com/android/internal/view/InputConnectionWrapper.java
index f9884d85d52cb7337e7cf1633545ce3efa6e735b..9a09dcccd1a7b672f06a64cfea249097d8415ff2 100644
--- a/core/java/com/android/internal/view/InputConnectionWrapper.java
+++ b/core/java/com/android/internal/view/InputConnectionWrapper.java
@@ -16,6 +16,8 @@
package com.android.internal.view;
+import android.annotation.NonNull;
+import android.inputmethodservice.AbstractInputMethodService;
import android.os.Bundle;
import android.os.Handler;
import android.os.RemoteException;
@@ -29,10 +31,16 @@ import android.view.inputmethod.ExtractedTextRequest;
import android.view.inputmethod.InputConnection;
import android.view.inputmethod.InputConnectionInspector;
import android.view.inputmethod.InputConnectionInspector.MissingMethodFlags;
+import android.view.inputmethod.InputContentInfo;
+
+import java.lang.ref.WeakReference;
public class InputConnectionWrapper implements InputConnection {
private static final int MAX_WAIT_TIME_MILLIS = 2000;
private final IInputContext mIInputContext;
+ @NonNull
+ private final WeakReference mInputMethodService;
+
@MissingMethodFlags
private final int mMissingMethods;
@@ -46,7 +54,8 @@ public class InputConnectionWrapper implements InputConnection {
public ExtractedText mExtractedText;
public int mCursorCapsMode;
public boolean mRequestUpdateCursorAnchorInfoResult;
-
+ public boolean mCommitContentResult;
+
// A 'pool' of one InputContextCallback. Each ICW request will attempt to gain
// exclusive access to this object.
private static InputContextCallback sInstance = new InputContextCallback();
@@ -172,6 +181,19 @@ public class InputConnectionWrapper implements InputConnection {
}
}
+ public void setCommitContentResult(boolean result, int seq) {
+ synchronized (this) {
+ if (seq == mSeq) {
+ mCommitContentResult = result;
+ mHaveValue = true;
+ notifyAll();
+ } else {
+ Log.i(TAG, "Got out-of-sequence callback " + seq + " (expected " + mSeq
+ + ") in setCommitContentResult, ignoring.");
+ }
+ }
+ }
+
/**
* Waits for a result for up to {@link #MAX_WAIT_TIME_MILLIS} milliseconds.
*
@@ -195,8 +217,10 @@ public class InputConnectionWrapper implements InputConnection {
}
}
- public InputConnectionWrapper(IInputContext inputContext,
- @MissingMethodFlags final int missingMethods) {
+ public InputConnectionWrapper(
+ @NonNull WeakReference inputMethodService,
+ IInputContext inputContext, @MissingMethodFlags final int missingMethods) {
+ mInputMethodService = inputMethodService;
mIInputContext = inputContext;
mMissingMethods = missingMethods;
}
@@ -491,6 +515,37 @@ public class InputConnectionWrapper implements InputConnection {
// Nothing should happen when called from input method.
}
+ public boolean commitContent(InputContentInfo inputContentInfo, int flags, Bundle opts) {
+ boolean result = false;
+ if (isMethodMissing(MissingMethodFlags.COMMIT_CONTENT)) {
+ // This method is not implemented.
+ return false;
+ }
+ try {
+ if ((flags & InputConnection.INPUT_CONTENT_GRANT_READ_URI_PERMISSION) != 0) {
+ final AbstractInputMethodService inputMethodService = mInputMethodService.get();
+ if (inputMethodService == null) {
+ // This basically should not happen, because it's the the caller of this method.
+ return false;
+ }
+ inputMethodService.exposeContent(inputContentInfo, this);
+ }
+
+ InputContextCallback callback = InputContextCallback.getInstance();
+ mIInputContext.commitContent(inputContentInfo, flags, opts, callback.mSeq, callback);
+ synchronized (callback) {
+ callback.waitForResultLocked();
+ if (callback.mHaveValue) {
+ result = callback.mCommitContentResult;
+ }
+ }
+ callback.dispose();
+ } catch (RemoteException e) {
+ return false;
+ }
+ return result;
+ }
+
private boolean isMethodMissing(@MissingMethodFlags final int methodFlag) {
return (mMissingMethods & methodFlag) == methodFlag;
}
diff --git a/core/java/com/android/internal/view/animation/FallbackLUTInterpolator.java b/core/java/com/android/internal/view/animation/FallbackLUTInterpolator.java
index 9e2cbdba44d475f2c634049af50d953e8c912351..d28ab078d74a612c663f027961687c2ce2b7589e 100644
--- a/core/java/com/android/internal/view/animation/FallbackLUTInterpolator.java
+++ b/core/java/com/android/internal/view/animation/FallbackLUTInterpolator.java
@@ -30,6 +30,8 @@ import android.view.Choreographer;
@HasNativeInterpolator
public class FallbackLUTInterpolator implements NativeInterpolatorFactory, TimeInterpolator {
+ // If the duration of an animation is more than 300 frames, we cap the sample size to 300.
+ private static final int MAX_SAMPLE_POINTS = 300;
private TimeInterpolator mSourceInterpolator;
private final float mLut[];
@@ -47,6 +49,7 @@ public class FallbackLUTInterpolator implements NativeInterpolatorFactory, TimeI
int animIntervalMs = (int) (frameIntervalNanos / TimeUtils.NANOS_PER_MS);
// We need 2 frame values as the minimal.
int numAnimFrames = Math.max(2, (int) Math.ceil(((double) duration) / animIntervalMs));
+ numAnimFrames = Math.min(numAnimFrames, MAX_SAMPLE_POINTS);
float values[] = new float[numAnimFrames];
float lastFrame = numAnimFrames - 1;
for (int i = 0; i < numAnimFrames; i++) {
diff --git a/core/java/com/android/internal/view/menu/CascadingMenuPopup.java b/core/java/com/android/internal/view/menu/CascadingMenuPopup.java
index ddf3a764661297eb8320079bdaf05acd25e66e1d..69e974c672d063518a9d7d805fc5ed15e29b0638 100644
--- a/core/java/com/android/internal/view/menu/CascadingMenuPopup.java
+++ b/core/java/com/android/internal/view/menu/CascadingMenuPopup.java
@@ -366,7 +366,7 @@ final class CascadingMenuPopup extends MenuPopup implements MenuPresenter, OnKey
final int menuWidth = measureIndividualMenuWidth(adapter, null, mContext, mMenuMaxWidth);
final MenuPopupWindow popupWindow = createPopupWindow();
popupWindow.setAdapter(adapter);
- popupWindow.setWidth(menuWidth);
+ popupWindow.setContentWidth(menuWidth);
popupWindow.setDropDownGravity(mDropDownGravity);
final CascadingMenuInfo parentInfo;
diff --git a/core/java/com/android/internal/widget/CachingIconView.java b/core/java/com/android/internal/widget/CachingIconView.java
new file mode 100644
index 0000000000000000000000000000000000000000..293b77b91d3795d5b51a0d3ff0f9249f1490ce47
--- /dev/null
+++ b/core/java/com/android/internal/widget/CachingIconView.java
@@ -0,0 +1,178 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.internal.widget;
+
+import android.annotation.DrawableRes;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.content.res.Configuration;
+import android.graphics.Bitmap;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.Icon;
+import android.net.Uri;
+import android.text.TextUtils;
+import android.util.AttributeSet;
+import android.view.RemotableViewMethod;
+import android.widget.ImageView;
+import android.widget.RemoteViews;
+
+import libcore.util.Objects;
+
+/**
+ * An ImageView for displaying an Icon. Avoids reloading the Icon when possible.
+ */
+@RemoteViews.RemoteView
+public class CachingIconView extends ImageView {
+
+ private String mLastPackage;
+ private int mLastResId;
+ private boolean mInternalSetDrawable;
+
+ public CachingIconView(Context context, @Nullable AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ @RemotableViewMethod(asyncImpl="setImageIconAsync")
+ public void setImageIcon(@Nullable Icon icon) {
+ if (!testAndSetCache(icon)) {
+ mInternalSetDrawable = true;
+ // This calls back to setImageDrawable, make sure we don't clear the cache there.
+ super.setImageIcon(icon);
+ mInternalSetDrawable = false;
+ }
+ }
+
+ @Override
+ public Runnable setImageIconAsync(@Nullable Icon icon) {
+ resetCache();
+ return super.setImageIconAsync(icon);
+ }
+
+ @Override
+ @RemotableViewMethod(asyncImpl="setImageResourceAsync")
+ public void setImageResource(@DrawableRes int resId) {
+ if (!testAndSetCache(resId)) {
+ mInternalSetDrawable = true;
+ // This calls back to setImageDrawable, make sure we don't clear the cache there.
+ super.setImageResource(resId);
+ mInternalSetDrawable = false;
+ }
+ }
+
+ @Override
+ public Runnable setImageResourceAsync(@DrawableRes int resId) {
+ resetCache();
+ return super.setImageResourceAsync(resId);
+ }
+
+ @Override
+ @RemotableViewMethod(asyncImpl="setImageURIAsync")
+ public void setImageURI(@Nullable Uri uri) {
+ resetCache();
+ super.setImageURI(uri);
+ }
+
+ @Override
+ public Runnable setImageURIAsync(@Nullable Uri uri) {
+ resetCache();
+ return super.setImageURIAsync(uri);
+ }
+
+ @Override
+ public void setImageDrawable(@Nullable Drawable drawable) {
+ if (!mInternalSetDrawable) {
+ // Only clear the cache if we were externally called.
+ resetCache();
+ }
+ super.setImageDrawable(drawable);
+ }
+
+ @Override
+ @RemotableViewMethod
+ public void setImageBitmap(Bitmap bm) {
+ resetCache();
+ super.setImageBitmap(bm);
+ }
+
+ @Override
+ protected void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+ resetCache();
+ }
+
+ /**
+ * @return true if the currently set image is the same as {@param icon}
+ */
+ private synchronized boolean testAndSetCache(Icon icon) {
+ if (icon != null && icon.getType() == Icon.TYPE_RESOURCE) {
+ String iconPackage = normalizeIconPackage(icon);
+
+ boolean isCached = mLastResId != 0
+ && icon.getResId() == mLastResId
+ && Objects.equal(iconPackage, mLastPackage);
+
+ mLastPackage = iconPackage;
+ mLastResId = icon.getResId();
+
+ return isCached;
+ } else {
+ resetCache();
+ return false;
+ }
+ }
+
+ /**
+ * @return true if the currently set image is the same as {@param resId}
+ */
+ private synchronized boolean testAndSetCache(int resId) {
+ boolean isCached;
+ if (resId == 0 || mLastResId == 0) {
+ isCached = false;
+ } else {
+ isCached = resId == mLastResId && null == mLastPackage;
+ }
+ mLastPackage = null;
+ mLastResId = resId;
+ return isCached;
+ }
+
+ /**
+ * Returns the normalized package name of {@param icon}.
+ * @return null if icon is null or if the icons package is null, empty or matches the current
+ * context. Otherwise returns the icon's package context.
+ */
+ private String normalizeIconPackage(Icon icon) {
+ if (icon == null) {
+ return null;
+ }
+
+ String pkg = icon.getResPackage();
+ if (TextUtils.isEmpty(pkg)) {
+ return null;
+ }
+ if (pkg.equals(mContext.getPackageName())) {
+ return null;
+ }
+ return pkg;
+ }
+
+ private synchronized void resetCache() {
+ mLastResId = 0;
+ mLastPackage = null;
+ }
+}
diff --git a/core/java/com/android/internal/widget/DecorCaptionView.java b/core/java/com/android/internal/widget/DecorCaptionView.java
index e59d7ba57ea1d9e7c52eb14494990e8aec7d385f..fc68b849ed2080f06a1c6e410faaa4711ea55f2a 100644
--- a/core/java/com/android/internal/widget/DecorCaptionView.java
+++ b/core/java/com/android/internal/widget/DecorCaptionView.java
@@ -244,6 +244,11 @@ public class DecorCaptionView extends ViewGroup implements View.OnTouchListener,
return mTouchDispatchList;
}
+ @Override
+ public boolean shouldDelayChildPressedState() {
+ return false;
+ }
+
private boolean passedSlop(int x, int y) {
return Math.abs(x - mTouchDownX) > mDragSlop || Math.abs(y - mTouchDownY) > mDragSlop;
}
diff --git a/core/java/com/android/internal/widget/FloatingToolbar.java b/core/java/com/android/internal/widget/FloatingToolbar.java
index 594581af8837f1922fda9d23c9f09de775cd3ff8..66042086e9257d16943e5c49ba2e21bb6008282b 100644
--- a/core/java/com/android/internal/widget/FloatingToolbar.java
+++ b/core/java/com/android/internal/widget/FloatingToolbar.java
@@ -737,7 +737,7 @@ public final class FloatingToolbar {
protected void applyTransformation(float interpolatedTime, Transformation t) {
int deltaWidth = (int) (interpolatedTime * (targetWidth - startWidth));
setWidth(mContentContainer, startWidth + deltaWidth);
- if (isRTL()) {
+ if (isInRTLMode()) {
mContentContainer.setX(left);
// Lock the panels in place.
@@ -766,7 +766,7 @@ public final class FloatingToolbar {
}
};
final float overflowButtonStartX = mOverflowButton.getX();
- final float overflowButtonTargetX = isRTL() ?
+ final float overflowButtonTargetX = isInRTLMode() ?
overflowButtonStartX + targetWidth - mOverflowButton.getWidth() :
overflowButtonStartX - targetWidth + mOverflowButton.getWidth();
Animation overflowButtonAnimation = new Animation() {
@@ -774,7 +774,7 @@ public final class FloatingToolbar {
protected void applyTransformation(float interpolatedTime, Transformation t) {
float overflowButtonX = overflowButtonStartX
+ interpolatedTime * (overflowButtonTargetX - overflowButtonStartX);
- float deltaContainerWidth = isRTL() ?
+ float deltaContainerWidth = isInRTLMode() ?
0 :
mContentContainer.getWidth() - startWidth;
float actualOverflowButtonX = overflowButtonX + deltaContainerWidth;
@@ -812,7 +812,7 @@ public final class FloatingToolbar {
protected void applyTransformation(float interpolatedTime, Transformation t) {
int deltaWidth = (int) (interpolatedTime * (targetWidth - startWidth));
setWidth(mContentContainer, startWidth + deltaWidth);
- if (isRTL()) {
+ if (isInRTLMode()) {
mContentContainer.setX(left);
// Lock the panels in place.
@@ -843,7 +843,7 @@ public final class FloatingToolbar {
}
};
final float overflowButtonStartX = mOverflowButton.getX();
- final float overflowButtonTargetX = isRTL() ?
+ final float overflowButtonTargetX = isInRTLMode() ?
overflowButtonStartX - startWidth + mOverflowButton.getWidth() :
overflowButtonStartX + startWidth - mOverflowButton.getWidth();
Animation overflowButtonAnimation = new Animation() {
@@ -851,7 +851,7 @@ public final class FloatingToolbar {
protected void applyTransformation(float interpolatedTime, Transformation t) {
float overflowButtonX = overflowButtonStartX
+ interpolatedTime * (overflowButtonTargetX - overflowButtonStartX);
- float deltaContainerWidth = isRTL() ?
+ float deltaContainerWidth = isInRTLMode() ?
0 :
mContentContainer.getWidth() - startWidth;
float actualOverflowButtonX = overflowButtonX + deltaContainerWidth;
@@ -903,7 +903,7 @@ public final class FloatingToolbar {
R.string.floating_toolbar_close_overflow_description));
// Update x-coordinates depending on RTL state.
- if (isRTL()) {
+ if (isInRTLMode()) {
mContentContainer.setX(mMarginHorizontal); // align left
mMainPanel.setX(0); // align left
mOverflowButton.setX( // align right
@@ -947,7 +947,7 @@ public final class FloatingToolbar {
if (hasOverflow()) {
// Update x-coordinates depending on RTL state.
- if (isRTL()) {
+ if (isInRTLMode()) {
mContentContainer.setX(mMarginHorizontal); // align left
mMainPanel.setX(0); // align left
mOverflowButton.setX(0); // align left
@@ -1087,9 +1087,10 @@ public final class FloatingToolbar {
viewTreeObserver.addOnComputeInternalInsetsListener(mInsetsComputer);
}
- private boolean isRTL() {
- return mContext.getResources().getConfiguration().getLayoutDirection()
- == View.LAYOUT_DIRECTION_RTL;
+ private boolean isInRTLMode() {
+ return mContext.getApplicationInfo().hasRtlSupport()
+ && mContext.getResources().getConfiguration().getLayoutDirection()
+ == View.LAYOUT_DIRECTION_RTL;
}
private boolean hasOverflow() {
@@ -1203,7 +1204,7 @@ public final class FloatingToolbar {
// The positioning of contents in RTL is wrong when the view is first rendered.
// Hide the view and post a runnable to recalculate positions and render the view.
// TODO: Investigate why this happens and fix.
- if (isRTL()) {
+ if (isInRTLMode()) {
mContentContainer.setAlpha(0);
mContentContainer.post(mPreparePopupContentRTLHelper);
}
diff --git a/core/java/com/android/internal/widget/ICheckCredentialProgressCallback.aidl b/core/java/com/android/internal/widget/ICheckCredentialProgressCallback.aidl
new file mode 100644
index 0000000000000000000000000000000000000000..79717cf2b0c9f254daa4ba2119df25491142d842
--- /dev/null
+++ b/core/java/com/android/internal/widget/ICheckCredentialProgressCallback.aidl
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.widget;
+
+/** {@hide} */
+oneway interface ICheckCredentialProgressCallback {
+ void onCredentialVerified();
+}
diff --git a/core/java/com/android/internal/widget/ILockSettings.aidl b/core/java/com/android/internal/widget/ILockSettings.aidl
index b352894a9f2f1ebc79d2d8231fe4cf8d2b99e000..3d27cf7c3d8292c44ce9080ffcf56d9c60c44efa 100644
--- a/core/java/com/android/internal/widget/ILockSettings.aidl
+++ b/core/java/com/android/internal/widget/ILockSettings.aidl
@@ -17,6 +17,7 @@
package com.android.internal.widget;
import android.app.trust.IStrongAuthTracker;
+import com.android.internal.widget.ICheckCredentialProgressCallback;
import com.android.internal.widget.VerifyCredentialResponse;
/** {@hide} */
@@ -29,10 +30,12 @@ interface ILockSettings {
String getString(in String key, in String defaultValue, in int userId);
void setLockPattern(in String pattern, in String savedPattern, int userId);
void resetKeyStore(int userId);
- VerifyCredentialResponse checkPattern(in String pattern, int userId);
+ VerifyCredentialResponse checkPattern(in String pattern, int userId,
+ in ICheckCredentialProgressCallback progressCallback);
VerifyCredentialResponse verifyPattern(in String pattern, long challenge, int userId);
void setLockPassword(in String password, in String savedPassword, int userId);
- VerifyCredentialResponse checkPassword(in String password, int userId);
+ VerifyCredentialResponse checkPassword(in String password, int userId,
+ in ICheckCredentialProgressCallback progressCallback);
VerifyCredentialResponse verifyPassword(in String password, long challenge, int userId);
VerifyCredentialResponse verifyTiedProfileChallenge(String password, boolean isPattern, long challenge, int userId);
byte getLockPatternSize(int userId);
diff --git a/core/java/com/android/internal/widget/LockPatternChecker.java b/core/java/com/android/internal/widget/LockPatternChecker.java
index 713f56f46266c3a35c00122ce4b513102bc25da2..df9b0ddc180473c114e5be41120ed27da783e9f1 100644
--- a/core/java/com/android/internal/widget/LockPatternChecker.java
+++ b/core/java/com/android/internal/widget/LockPatternChecker.java
@@ -14,6 +14,13 @@ public final class LockPatternChecker {
* Interface for a callback to be invoked after security check.
*/
public interface OnCheckCallback {
+
+ /**
+ * Invoked as soon as possible we know that the credentials match. This will be called
+ * earlier than {@link #onChecked} but only if the credentials match.
+ */
+ default void onEarlyMatched() {}
+
/**
* Invoked when a security check is finished.
*
@@ -92,7 +99,7 @@ public final class LockPatternChecker {
@Override
protected Boolean doInBackground(Void... args) {
try {
- return utils.checkPattern(pattern, userId);
+ return utils.checkPattern(pattern, userId, callback::onEarlyMatched);
} catch (RequestThrottledException ex) {
mThrottleTimeout = ex.getTimeoutMs();
return false;
@@ -199,7 +206,7 @@ public final class LockPatternChecker {
@Override
protected Boolean doInBackground(Void... args) {
try {
- return utils.checkPassword(password, userId);
+ return utils.checkPassword(password, userId, callback::onEarlyMatched);
} catch (RequestThrottledException ex) {
mThrottleTimeout = ex.getTimeoutMs();
return false;
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index 94b4679a5970e7049da051e90ea4005f62f2684e..916365bbb047f5ca9a0cbd570e69c7d2fb30bd9c 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -17,6 +17,7 @@
package com.android.internal.widget;
import android.annotation.IntDef;
+import android.annotation.Nullable;
import android.app.admin.DevicePolicyManager;
import android.app.trust.IStrongAuthTracker;
import android.app.trust.TrustManager;
@@ -32,7 +33,6 @@ import android.os.Message;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
-import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
import android.os.storage.IMountService;
@@ -154,6 +154,7 @@ public class LockPatternUtils {
private DevicePolicyManager mDevicePolicyManager;
private ILockSettings mLockSettingsService;
private UserManager mUserManager;
+ private final Handler mHandler;
/**
* Use {@link TrustManager#isTrustUsuallyManaged(int)}.
@@ -235,6 +236,9 @@ public class LockPatternUtils {
public LockPatternUtils(Context context) {
mContext = context;
mContentResolver = context.getContentResolver();
+
+ Looper looper = Looper.myLooper();
+ mHandler = looper != null ? new Handler(looper) : null;
}
private ILockSettings getLockSettings() {
@@ -289,7 +293,6 @@ public class LockPatternUtils {
public void reportFailedPasswordAttempt(int userId) {
getDevicePolicyManager().reportFailedPasswordAttempt(userId);
getTrustManager().reportUnlockAttempt(false /* authenticated */, userId);
- requireStrongAuth(StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_WRONG_CREDENTIAL, userId);
}
public void reportSuccessfulPasswordAttempt(int userId) {
@@ -346,10 +349,23 @@ public class LockPatternUtils {
*/
public boolean checkPattern(List pattern, int userId)
throws RequestThrottledException {
+ return checkPattern(pattern, userId, null /* progressCallback */);
+ }
+
+ /**
+ * Check to see if a pattern matches the saved pattern. If no pattern exists,
+ * always returns true.
+ * @param pattern The pattern to check.
+ * @return Whether the pattern matches the stored one.
+ */
+ public boolean checkPattern(List pattern, int userId,
+ @Nullable CheckCredentialProgressCallback progressCallback)
+ throws RequestThrottledException {
throwIfCalledOnMainThread();
try {
VerifyCredentialResponse response =
- getLockSettings().checkPattern(patternToString(pattern, userId), userId);
+ getLockSettings().checkPattern(patternToString(pattern), userId,
+ wrapCallback(progressCallback));
if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
return true;
@@ -428,10 +444,22 @@ public class LockPatternUtils {
* @return Whether the password matches the stored one.
*/
public boolean checkPassword(String password, int userId) throws RequestThrottledException {
+ return checkPassword(password, userId, null /* progressCallback */);
+ }
+
+ /**
+ * Check to see if a password matches the saved password. If no password exists,
+ * always returns true.
+ * @param password The password to check.
+ * @return Whether the password matches the stored one.
+ */
+ public boolean checkPassword(String password, int userId,
+ @Nullable CheckCredentialProgressCallback progressCallback)
+ throws RequestThrottledException {
throwIfCalledOnMainThread();
try {
VerifyCredentialResponse response =
- getLockSettings().checkPassword(password, userId);
+ getLockSettings().checkPassword(password, userId, wrapCallback(progressCallback));
if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
return true;
} else if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_RETRY) {
@@ -1535,6 +1563,37 @@ public class LockPatternUtils {
return (getStrongAuthForUser(userId) & ~StrongAuthTracker.ALLOWING_FINGERPRINT) == 0;
}
+ private ICheckCredentialProgressCallback wrapCallback(
+ final CheckCredentialProgressCallback callback) {
+ if (callback == null) {
+ return null;
+ } else {
+ if (mHandler == null) {
+ throw new IllegalStateException("Must construct LockPatternUtils on a looper thread"
+ + " to use progress callbacks.");
+ }
+ return new ICheckCredentialProgressCallback.Stub() {
+
+ @Override
+ public void onCredentialVerified() throws RemoteException {
+ mHandler.post(callback::onEarlyMatched);
+ }
+ };
+ }
+ }
+
+ /**
+ * Callback to be notified about progress when checking credentials.
+ */
+ public interface CheckCredentialProgressCallback {
+
+ /**
+ * Called as soon as possible when we know that the credentials match but the user hasn't
+ * been fully unlocked.
+ */
+ void onEarlyMatched();
+ }
+
/**
* Tracks the global strong authentication state.
*/
@@ -1544,7 +1603,8 @@ public class LockPatternUtils {
value = { STRONG_AUTH_NOT_REQUIRED,
STRONG_AUTH_REQUIRED_AFTER_BOOT,
STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW,
- SOME_AUTH_REQUIRED_AFTER_USER_REQUEST})
+ SOME_AUTH_REQUIRED_AFTER_USER_REQUEST,
+ STRONG_AUTH_REQUIRED_AFTER_LOCKOUT})
@Retention(RetentionPolicy.SOURCE)
public @interface StrongAuthFlags {}
@@ -1575,13 +1635,12 @@ public class LockPatternUtils {
public static final int STRONG_AUTH_REQUIRED_AFTER_LOCKOUT = 0x8;
/**
- * Some authentication is required because the user has entered a wrong credential.
+ * Strong auth flags that do not prevent fingerprint from being accepted as auth.
+ *
+ * If any other flags are set, fingerprint is disabled.
*/
- public static final int SOME_AUTH_REQUIRED_AFTER_WRONG_CREDENTIAL = 0x10;
-
private static final int ALLOWING_FINGERPRINT = STRONG_AUTH_NOT_REQUIRED
- | SOME_AUTH_REQUIRED_AFTER_USER_REQUEST
- | SOME_AUTH_REQUIRED_AFTER_WRONG_CREDENTIAL;
+ | SOME_AUTH_REQUIRED_AFTER_USER_REQUEST;
private final SparseIntArray mStrongAuthRequiredForUser = new SparseIntArray();
private final H mHandler;
diff --git a/core/java/com/android/internal/widget/NotificationActionListLayout.java b/core/java/com/android/internal/widget/NotificationActionListLayout.java
index 9dd118c5a942164e06ab9c8943de8d944a3deb74..073aac542e31535da94e2f03c33e94a860a45e6a 100644
--- a/core/java/com/android/internal/widget/NotificationActionListLayout.java
+++ b/core/java/com/android/internal/widget/NotificationActionListLayout.java
@@ -17,11 +17,13 @@
package com.android.internal.widget;
import android.content.Context;
+import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.Pair;
import android.view.Gravity;
+import android.view.RemotableViewMethod;
import android.view.View;
-import android.view.ViewGroup;
+import android.widget.LinearLayout;
import android.widget.RemoteViews;
import android.widget.TextView;
@@ -33,11 +35,14 @@ import java.util.Comparator;
* the remaining available width, and the last action consumes the remaining space.
*/
@RemoteViews.RemoteView
-public class NotificationActionListLayout extends ViewGroup {
+public class NotificationActionListLayout extends LinearLayout {
private int mTotalWidth = 0;
private ArrayList> mMeasureOrderTextViews = new ArrayList<>();
private ArrayList mMeasureOrderOther = new ArrayList<>();
+ private boolean mMeasureLinearly;
+ private int mDefaultPaddingEnd;
+ private Drawable mDefaultBackground;
public NotificationActionListLayout(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -45,6 +50,10 @@ public class NotificationActionListLayout extends ViewGroup {
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ if (mMeasureLinearly) {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ return;
+ }
final int N = getChildCount();
int textViews = 0;
int otherViews = 0;
@@ -186,6 +195,10 @@ public class NotificationActionListLayout extends ViewGroup {
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ if (mMeasureLinearly) {
+ super.onLayout(changed, left, top, right, bottom);
+ return;
+ }
final boolean isLayoutRtl = isLayoutRtl();
final int paddingTop = mPaddingTop;
@@ -241,26 +254,24 @@ public class NotificationActionListLayout extends ViewGroup {
}
@Override
- public LayoutParams generateLayoutParams(AttributeSet attrs) {
- return new MarginLayoutParams(getContext(), attrs);
- }
-
- @Override
- protected LayoutParams generateDefaultLayoutParams() {
- return new MarginLayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ mDefaultPaddingEnd = getPaddingEnd();
+ mDefaultBackground = getBackground();
}
- @Override
- protected LayoutParams generateLayoutParams(LayoutParams p) {
- if (p instanceof MarginLayoutParams) {
- return new MarginLayoutParams((MarginLayoutParams)p);
- }
- return new MarginLayoutParams(p);
- }
-
- @Override
- protected boolean checkLayoutParams(LayoutParams p) {
- return p instanceof MarginLayoutParams;
+ /**
+ * Set whether the list is in a mode where some actions are emphasized. This will trigger an
+ * equal measuring where all actions are full height and change a few parameters like
+ * the padding.
+ */
+ @RemotableViewMethod
+ public void setEmphasizedMode(boolean emphasizedMode) {
+ mMeasureLinearly = emphasizedMode;
+ setPaddingRelative(getPaddingStart(), getPaddingTop(),
+ emphasizedMode ? 0 : mDefaultPaddingEnd, getPaddingBottom());
+ setBackground(emphasizedMode ? null : mDefaultBackground);
+ requestLayout();
}
public static final Comparator> MEASURE_ORDER_COMPARATOR
diff --git a/core/java/com/android/internal/widget/ViewPager.java b/core/java/com/android/internal/widget/ViewPager.java
index 277fafd4adf726e983ec3e030ecdbe0af163a922..d5b6def97426d48bccacea77b197c8783a14f741 100644
--- a/core/java/com/android/internal/widget/ViewPager.java
+++ b/core/java/com/android/internal/widget/ViewPager.java
@@ -55,34 +55,7 @@ import java.util.Collections;
import java.util.Comparator;
/**
- * Layout manager that allows the user to flip left and right
- * through pages of data. You supply an implementation of a
- * {@link android.support.v4.view.PagerAdapter} to generate the pages that the view shows.
- *
- *
Note this class is currently under early design and
- * development. The API will likely change in later updates of
- * the compatibility library, requiring changes to the source code
- * of apps when they are compiled against the newer version.
- *
- *
ViewPager is most often used in conjunction with {@link android.app.Fragment},
- * which is a convenient way to supply and manage the lifecycle of each page.
- * There are standard adapters implemented for using fragments with the ViewPager,
- * which cover the most common use cases. These are
- * {@link android.support.v4.app.FragmentPagerAdapter} and
- * {@link android.support.v4.app.FragmentStatePagerAdapter}; each of these
- * classes have simple code showing how to build a full user interface
- * with them.
- *
- *
Cuando el sistema detecta una red adecuada, se conecta a la red e invoca la devolución de llamada {@link android.net.ConnectivityManager.NetworkCallback#onAvailable(android.net.Network) onAvailable()}. Puedes usar el objeto {@link android.net.Network} de la devolución de llamada para obtener información adicional acerca de la red o para indicar que el tráfico use la red seleccionada.
Bluetooth de baja energía
-
Android 4.3 introdujo compatibilidad de plataforma para Bluetooth de baja energía (Bluetooth LE) en el rol central. En Android 5.0, un dispositivo Android ahora puede actuar como un dispositivo periférico Bluetooth LE. Las aplicaciones pueden utilizar esta capacidad para que otros dispositivos cercanos detecten su presencia. Por ejemplo, puedes crear aplicaciones que permiten que un dispositivo funcione como un podómetro o un monitor de estado, y comunique sus datos a otro dispositivo Bluetooth LE.
+
Android 4.3 introdujo compatibilidad de plataforma para Bluetooth de baja energía (Bluetooth LE) en el rol central. En Android 5.0, un dispositivo Android ahora puede actuar como un dispositivo periférico Bluetooth LE. Las aplicaciones pueden utilizar esta capacidad para que otros dispositivos cercanos detecten su presencia. Por ejemplo, puedes crear aplicaciones que permiten que un dispositivo funcione como un podómetro o un monitor de estado, y comunique sus datos a otro dispositivo Bluetooth LE.
Las nuevas API {@link android.bluetooth.le} permiten a sus aplicaciones transmitir anuncios, buscar respuestas y establecer conexiones con dispositivos Bluetooth LE cercanos. Para utilizar las nuevas funciones de anuncio y búsqueda, agrega el permiso {@link android.Manifest.permission#BLUETOOTH_ADMIN BLUETOOTH_ADMIN} en el manifiesto. Cuando los usuarios actualizan o descargan tu aplicación desde Play Store, se les pide que concedan el siguiente permiso a tu aplicación: "Información de conexión Bluetooth: Permite que la aplicación controle Bluetooth, incluida la transmisión de información a dispositivos Bluetooth cercanos o la obtención de información sobre ellos".
Para comenzar el anuncio de Bluetooth LE a fin de que otros dispositivos puedan detectar tu aplicación, llama a {@link android.bluetooth.le.BluetoothLeAdvertiser#startAdvertising(android.bluetooth.le.AdvertiseSettings, android.bluetooth.le.AdvertiseData, android.bluetooth.le.AdvertiseCallback) startAdvertising()} y envía una implementación de la clase {@link android.bluetooth.le.AdvertiseCallback}. El objeto de devolución de llamada recibe un informe del éxito o fracaso de la operación de anuncio.
diff --git a/docs/html-intl/intl/es/preview/guide.jd b/docs/html-intl/intl/es/about/versions/marshmallow/android-6.0-testing.jd
similarity index 99%
rename from docs/html-intl/intl/es/preview/guide.jd
rename to docs/html-intl/intl/es/about/versions/marshmallow/android-6.0-testing.jd
index 9fe555ccc289ab66460947022679233d7c224d56..20d2d6e686ddd50434385bf3ec19ae5f4354d4aa 100644
--- a/docs/html-intl/intl/es/preview/guide.jd
+++ b/docs/html-intl/intl/es/about/versions/marshmallow/android-6.0-testing.jd
@@ -5,8 +5,8 @@ page.tags="preview", "developer preview"
@jd:body
-
Android N te brinda la oportunidad de garantizar que tus aplicaciones funcionen con la próxima versión de la plataforma.
- Esta versión preliminar incluye diversas API y cambios en los comportamientos que pueden
+ Esta versión preliminar incluye diversas API y cambios en los comportamientos que pueden
tener impactos en tu aplicación, como se describe en las secciones Información general de la API y Cambios en los comportamientos.
Al probar tu aplicación con la versión preliminar, te debes centrar en algunos cambios específicos del sistema para garantizar que los usuarios disfruten de una buena experiencia.
diff --git a/docs/html-intl/intl/es/preview/behavior-changes.jd b/docs/html-intl/intl/es/about/versions/nougat/android-7.0-changes.jd
similarity index 97%
rename from docs/html-intl/intl/es/preview/behavior-changes.jd
rename to docs/html-intl/intl/es/about/versions/nougat/android-7.0-changes.jd
index 5eb4966b8c3472a996a7877b9f87eda74d267cca..d4438f202630fc2fcfa849186f1434245de8a267 100644
--- a/docs/html-intl/intl/es/preview/behavior-changes.jd
+++ b/docs/html-intl/intl/es/about/versions/nougat/android-7.0-changes.jd
@@ -6,8 +6,8 @@ page.image=images/cards/card-n-changes_2x.png
@jd:body
-