diff --git a/Android.mk b/Android.mk
index 7230cbff33d915b9f67b7f69922bd858ae058519..c0bb7240c796b2dff88d480e91c90199824247ee 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 \
@@ -201,6 +202,7 @@ LOCAL_SRC_FILES += \
core/java/android/net/ICaptivePortal.aidl \
core/java/android/net/IConnectivityManager.aidl \
core/java/android/net/IConnectivityMetricsLogger.aidl \
+ core/java/android/net/IIpConnectivityMetrics.aidl \
core/java/android/net/IEthernetManager.aidl \
core/java/android/net/IEthernetServiceListener.aidl \
core/java/android/net/INetworkManagementEventObserver.aidl \
@@ -309,9 +311,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 \
@@ -322,6 +324,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 \
@@ -345,6 +348,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 \
@@ -471,6 +475,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
@@ -504,6 +511,10 @@ LOCAL_JACK_FLAGS := --multi-dex native
LOCAL_RMTYPEDEFS := true
+ifeq ($(EMMA_INSTRUMENT_FRAMEWORK),true)
+LOCAL_EMMA_INSTRUMENT := true
+endif
+
include $(BUILD_JAVA_LIBRARY)
framework_module := $(LOCAL_INSTALLED_MODULE)
@@ -695,6 +706,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)
@@ -886,16 +898,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)
@@ -915,6 +927,7 @@ LOCAL_DROIDDOC_STUB_OUT_DIR := $(TARGET_OUT_COMMON_INTERMEDIATES)/JAVA_LIBRARIES
LOCAL_DROIDDOC_OPTIONS:=\
$(framework_docs_LOCAL_DROIDDOC_OPTIONS) \
+ -referenceonly \
-api $(INTERNAL_PLATFORM_API_FILE) \
-removedApi $(INTERNAL_PLATFORM_REMOVED_API_FILE) \
-nodocs
@@ -948,6 +961,7 @@ LOCAL_DROIDDOC_STUB_OUT_DIR := $(TARGET_OUT_COMMON_INTERMEDIATES)/JAVA_LIBRARIES
LOCAL_DROIDDOC_OPTIONS:=\
$(framework_docs_LOCAL_DROIDDOC_OPTIONS) \
+ -referenceonly \
-showAnnotation android.annotation.SystemApi \
-api $(INTERNAL_PLATFORM_SYSTEM_API_FILE) \
-removedApi $(INTERNAL_PLATFORM_SYSTEM_REMOVED_API_FILE) \
@@ -982,6 +996,7 @@ LOCAL_DROIDDOC_STUB_OUT_DIR := $(TARGET_OUT_COMMON_INTERMEDIATES)/JAVA_LIBRARIES
LOCAL_DROIDDOC_OPTIONS:=\
$(framework_docs_LOCAL_DROIDDOC_OPTIONS) \
+ -referenceonly \
-stubs $(TARGET_OUT_COMMON_INTERMEDIATES)/JAVA_LIBRARIES/android_test_stubs_current_intermediates/src \
-showAnnotation android.annotation.TestApi \
-api $(INTERNAL_PLATFORM_TEST_API_FILE) \
@@ -1015,6 +1030,7 @@ LOCAL_MODULE := doc-comment-check
LOCAL_DROIDDOC_OPTIONS:=\
$(framework_docs_LOCAL_DROIDDOC_OPTIONS) \
+ -referenceonly \
-parsecomments
LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=build/tools/droiddoc/templates-sdk
@@ -1045,6 +1061,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
+
+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 \
@@ -1059,10 +1111,17 @@ LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=build/tools/droiddoc/templates-sdk
include $(BUILD_DROIDDOC)
static_doc_index_redirect := $(out_dir)/index.html
-$(static_doc_index_redirect): $(LOCAL_PATH)/docs/docs-preview-index.html
+$(static_doc_index_redirect): $(LOCAL_PATH)/docs/docs-documentation-redirect.html
$(copy-file-to-target)
+static_doc_properties := $(out_dir)/source.properties
+$(static_doc_properties): \
+ $(LOCAL_PATH)/docs/source.properties | $(ACP)
+ $(hide) mkdir -p $(dir $@)
+ $(hide) $(ACP) $< $@
+
$(full_target): $(static_doc_index_redirect)
+$(full_target): $(static_doc_properties)
$(full_target): $(framework_built)
@@ -1114,6 +1173,7 @@ LOCAL_MODULE := online-system-api-sdk
LOCAL_DROIDDOC_OPTIONS:= \
$(framework_docs_LOCAL_DROIDDOC_OPTIONS) \
+ -referenceonly \
-showAnnotation android.annotation.SystemApi \
-title "Android SDK - Including system APIs." \
-toroot / \
@@ -1150,17 +1210,67 @@ 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
+LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=build/tools/droiddoc/templates-sdk
+
+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
+
+include $(BUILD_DROIDDOC)
+
+# ==== generates full navtree for resolving @links in ds postprocessing ====
+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_ADDITIONAL_JAVA_DIR:=$(framework_docs_LOCAL_ADDITIONAL_JAVA_DIR)
+LOCAL_ADDITIONAL_DEPENDENCIES:=$(framework_docs_LOCAL_ADDITIONAL_DEPENDENCIES)
+
+LOCAL_MODULE := ds-ref-navtree
+
+LOCAL_DROIDDOC_OPTIONS:= \
+ $(framework_docs_LOCAL_DROIDDOC_OPTIONS) \
+ -hdf android.whichdoc online \
+ -toroot / \
+ -atLinksNavtree \
+ -navtreeonly
+
+LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=build/tools/droiddoc/templates-sdk
include $(BUILD_DROIDDOC)
@@ -1185,11 +1295,10 @@ LOCAL_DROIDDOC_OPTIONS:= \
-toroot / \
-hdf android.whichdoc online \
$(sample_groups) \
- -useUpdatedTemplates \
-hdf android.hasSamples true \
-samplesdir $(samples_dir)
-LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=build/tools/droiddoc/templates-sdk-dev
+LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=build/tools/droiddoc/templates-sdk
include $(BUILD_DROIDDOC)
@@ -1208,6 +1317,7 @@ LOCAL_ADDITIONAL_DEPENDENCIES:=$(framework_docs_LOCAL_ADDITIONAL_DEPENDENCIES)
LOCAL_MODULE := hidden
LOCAL_DROIDDOC_OPTIONS:=\
$(framework_docs_LOCAL_DROIDDOC_OPTIONS) \
+ -referenceonly \
-title "Android SDK - Including hidden APIs."
# -hidden
diff --git a/api/current.txt b/api/current.txt
index c1314ad050914f624d40030f14f9705b52e5b35a..2788f3648eb661137f9a07cb6232ee79858872b7 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 {
@@ -29261,6 +29362,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();
@@ -29501,6 +29603,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 {
@@ -30643,6 +30746,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";
@@ -30665,6 +30769,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
@@ -32370,6 +32475,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";
@@ -32379,7 +32485,7 @@ package android.provider {
field public static final java.lang.String RADIO_CELL = "cell";
field public static final java.lang.String RADIO_NFC = "nfc";
field public static final java.lang.String RADIO_WIFI = "wifi";
- field public static final java.lang.String SHOW_PROCESSES = "show_processes";
+ field public static final deprecated java.lang.String SHOW_PROCESSES = "show_processes";
field public static final java.lang.String STAY_ON_WHILE_PLUGGED_IN = "stay_on_while_plugged_in";
field public static final java.lang.String TRANSITION_ANIMATION_SCALE = "transition_animation_scale";
field public static final java.lang.String USB_MASS_STORAGE_ENABLED = "usb_mass_storage_enabled";
@@ -32955,6 +33061,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";
}
@@ -32963,6 +33070,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;
@@ -32987,6 +33097,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";
}
@@ -35946,9 +36057,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();
@@ -35962,6 +36078,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
}
@@ -35972,6 +36089,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);
@@ -36002,6 +36120,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
@@ -36021,7 +36140,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
}
@@ -36072,6 +36193,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();
@@ -36084,6 +36206,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();
@@ -36092,10 +36215,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);
@@ -36125,6 +36252,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();
@@ -36135,16 +36263,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);
@@ -36152,6 +36288,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);
@@ -36160,6 +36297,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);
@@ -36168,6 +36306,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
@@ -36185,15 +36324,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
}
@@ -36271,7 +36416,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;
@@ -36307,6 +36454,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);
@@ -36430,6 +36578,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);
@@ -36448,6 +36597,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();
@@ -36459,6 +36609,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();
@@ -36475,6 +36626,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);
@@ -36571,6 +36724,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
@@ -36625,9 +36779,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";
@@ -36659,6 +36815,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";
@@ -36717,6 +36874,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";
@@ -37315,12 +37473,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
@@ -40121,7 +40282,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
@@ -41451,6 +41615,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
@@ -42333,6 +42501,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();
@@ -42620,6 +42789,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);
@@ -43769,6 +43939,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
@@ -44541,6 +44712,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);
@@ -44650,6 +44822,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;
@@ -44709,6 +44882,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);
@@ -44734,6 +44908,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 {
@@ -44742,6 +44917,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);
@@ -44766,6 +44942,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 cfc05dd7d850d1f043a4f43ddedb9ddb023dd4c4..74b1af306657f09d87e715ad7a4292c6c93bdc5d 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
@@ -25947,6 +26056,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);
@@ -25964,6 +26100,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;
}
@@ -26055,6 +26192,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);
@@ -30740,6 +30889,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 {
@@ -31575,6 +31725,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;
@@ -31817,6 +31968,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);
@@ -32066,6 +32218,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 {
@@ -33247,6 +33400,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";
@@ -33269,6 +33423,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
@@ -35107,6 +35262,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";
@@ -35118,7 +35274,7 @@ package android.provider {
field public static final java.lang.String RADIO_CELL = "cell";
field public static final java.lang.String RADIO_NFC = "nfc";
field public static final java.lang.String RADIO_WIFI = "wifi";
- field public static final java.lang.String SHOW_PROCESSES = "show_processes";
+ field public static final deprecated java.lang.String SHOW_PROCESSES = "show_processes";
field public static final java.lang.String STAY_ON_WHILE_PLUGGED_IN = "stay_on_while_plugged_in";
field public static final java.lang.String THEATER_MODE_ON = "theater_mode_on";
field public static final java.lang.String TRANSITION_ANIMATION_SCALE = "transition_animation_scale";
@@ -35697,6 +35853,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";
}
@@ -35705,6 +35862,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;
@@ -35729,6 +35889,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";
}
@@ -38816,10 +38977,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();
@@ -38834,6 +39000,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
}
@@ -38844,6 +39011,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);
@@ -38874,6 +39042,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
@@ -38893,7 +39062,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
}
@@ -38950,6 +39121,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();
@@ -38964,6 +39136,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();
@@ -38972,11 +39145,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);
@@ -39007,6 +39184,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();
@@ -39018,16 +39196,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);
@@ -39035,6 +39221,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);
@@ -39043,6 +39230,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);
@@ -39051,6 +39239,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
@@ -39068,15 +39257,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
}
@@ -39154,7 +39349,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;
@@ -39191,6 +39388,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();
@@ -39228,14 +39426,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();
@@ -39256,6 +39456,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();
@@ -39369,6 +39636,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);
@@ -39387,6 +39655,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();
@@ -39398,6 +39667,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();
@@ -39415,6 +39685,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);
@@ -39468,6 +39740,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);
@@ -39477,7 +39784,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);
@@ -39538,6 +39845,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
@@ -39594,9 +39902,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";
@@ -39628,6 +39938,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";
@@ -39686,6 +39997,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";
@@ -40186,6 +40498,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);
@@ -40237,6 +40569,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();
@@ -40260,6 +40593,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();
@@ -40273,6 +40607,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);
@@ -40325,12 +40660,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
@@ -43148,7 +43486,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
@@ -44478,6 +44819,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
@@ -45360,6 +45705,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();
@@ -45647,6 +45993,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);
@@ -46799,6 +47146,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
@@ -47571,6 +47919,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);
@@ -47680,6 +48029,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;
@@ -47739,6 +48089,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);
@@ -47764,6 +48115,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 {
@@ -47772,6 +48124,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);
@@ -47796,6 +48149,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 2d7b29fe2d591c0f7442ff6948238dc771446a11..8e3d4ef6cbadcc52c0d2e62098eb1de3fad438f5 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
@@ -3246,6 +3255,7 @@ package android.animation {
method public java.lang.Object getAnimatedValue(java.lang.String);
method public long getCurrentPlayTime();
method public long getDuration();
+ method public static float getDurationScale();
method public static long getFrameDelay();
method public int getRepeatCount();
method public int getRepeatMode();
@@ -3263,6 +3273,7 @@ package android.animation {
method public void setCurrentFraction(float);
method public void setCurrentPlayTime(long);
method public android.animation.ValueAnimator setDuration(long);
+ method public static void setDurationScale(float);
method public void setEvaluator(android.animation.TypeEvaluator);
method public void setFloatValues(float...);
method public static void setFrameDelay(long);
@@ -3696,6 +3707,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 +5050,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);
}
@@ -5617,6 +5631,7 @@ package android.app {
public class TimePickerDialog extends android.app.AlertDialog implements android.content.DialogInterface.OnClickListener android.widget.TimePicker.OnTimeChangedListener {
ctor public TimePickerDialog(android.content.Context, android.app.TimePickerDialog.OnTimeSetListener, int, int, boolean);
ctor public TimePickerDialog(android.content.Context, int, android.app.TimePickerDialog.OnTimeSetListener, int, int, boolean);
+ method public android.widget.TimePicker getTimePicker();
method public void onClick(android.content.DialogInterface, int);
method public void onTimeChanged(android.widget.TimePicker, int, int);
method public void updateTime(int, int);
@@ -5762,7 +5777,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 +6508,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 +8219,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 +9533,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 +9559,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 +10074,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 +10341,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 +10392,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 +19728,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 +28441,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 +29231,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);
@@ -29331,6 +29437,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();
@@ -29571,6 +29678,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 {
@@ -30716,6 +30824,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";
@@ -30738,6 +30847,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
@@ -32443,6 +32553,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";
@@ -32452,7 +32563,7 @@ package android.provider {
field public static final java.lang.String RADIO_CELL = "cell";
field public static final java.lang.String RADIO_NFC = "nfc";
field public static final java.lang.String RADIO_WIFI = "wifi";
- field public static final java.lang.String SHOW_PROCESSES = "show_processes";
+ field public static final deprecated java.lang.String SHOW_PROCESSES = "show_processes";
field public static final java.lang.String STAY_ON_WHILE_PLUGGED_IN = "stay_on_while_plugged_in";
field public static final java.lang.String TRANSITION_ANIMATION_SCALE = "transition_animation_scale";
field public static final java.lang.String USB_MASS_STORAGE_ENABLED = "usb_mass_storage_enabled";
@@ -33031,6 +33142,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";
}
@@ -33039,6 +33151,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;
@@ -33063,6 +33178,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";
}
@@ -36023,9 +36139,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();
@@ -36039,6 +36160,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
}
@@ -36049,6 +36171,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);
@@ -36079,6 +36202,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
@@ -36098,7 +36222,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
}
@@ -36149,6 +36275,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();
@@ -36161,6 +36288,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();
@@ -36169,10 +36297,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);
@@ -36202,6 +36334,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();
@@ -36212,16 +36345,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);
@@ -36229,6 +36370,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);
@@ -36237,6 +36379,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);
@@ -36245,6 +36388,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
@@ -36262,15 +36406,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
}
@@ -36348,7 +36498,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;
@@ -36384,6 +36536,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);
@@ -36507,6 +36660,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);
@@ -36525,6 +36679,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();
@@ -36536,6 +36691,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();
@@ -36552,6 +36708,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);
@@ -36648,6 +36806,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
@@ -36702,9 +36861,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";
@@ -36736,6 +36897,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";
@@ -36794,6 +36956,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";
@@ -37392,12 +37555,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
@@ -40200,7 +40366,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
@@ -41530,6 +41699,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
@@ -42412,6 +42585,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();
@@ -42699,6 +42873,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);
@@ -43848,6 +44023,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
@@ -44620,6 +44796,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);
@@ -44729,6 +44906,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;
@@ -44788,6 +44966,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);
@@ -44813,6 +44992,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 {
@@ -44821,6 +45001,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);
@@ -44845,6 +45026,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);
@@ -46438,6 +46632,7 @@ package android.widget {
method public int getFirstDayOfWeek();
method public long getMaxDate();
method public long getMinDate();
+ method public int getMode();
method public int getMonth();
method public deprecated boolean getSpinnersShown();
method public int getYear();
@@ -46448,6 +46643,8 @@ package android.widget {
method public void setMinDate(long);
method public deprecated void setSpinnersShown(boolean);
method public void updateDate(int, int, int);
+ field public static final int MODE_CALENDAR = 2; // 0x2
+ field public static final int MODE_SPINNER = 1; // 0x1
}
public static abstract interface DatePicker.OnDateChangedListener {
@@ -48212,6 +48409,7 @@ package android.widget {
method public deprecated java.lang.Integer getCurrentMinute();
method public int getHour();
method public int getMinute();
+ method public int getMode();
method public boolean is24HourView();
method public deprecated void setCurrentHour(java.lang.Integer);
method public deprecated void setCurrentMinute(java.lang.Integer);
@@ -48219,6 +48417,8 @@ package android.widget {
method public void setIs24HourView(java.lang.Boolean);
method public void setMinute(int);
method public void setOnTimeChangedListener(android.widget.TimePicker.OnTimeChangedListener);
+ field public static final int MODE_CLOCK = 2; // 0x2
+ field public static final int MODE_SPINNER = 1; // 0x1
}
public static abstract interface TimePicker.OnTimeChangedListener {
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 7c8842ca02316ba9b6e3aefd2cd9e3f157745c0c..3a92b9e74144c7b4fcd583826ac796747447f483 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
LOCAL_MODULE:= bootanimation
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 25b264ecff103853c84ab7e096c57735a3538318..c9211939ec6c150dfe2e105dddc7dd24bd5c31dd 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
@@ -55,26 +58,56 @@
#include
#include "BootAnimation.h"
-#include "AudioPlayer.h"
-
-#define OEM_BOOTANIMATION_FILE "/oem/media/bootanimation.zip"
-#define SYSTEM_BOOTANIMATION_FILE "/system/media/bootanimation.zip"
-#define SYSTEM_ENCRYPTED_BOOTANIMATION_FILE "/system/media/bootanimation-encrypted.zip"
-#define EXIT_PROP_NAME "service.bootanim.exit"
+#include "audioplay.h"
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 CLOCK_FONT_ASSET[] = "images/clock_font.png";
+static const char CLOCK_FONT_ZIP_NAME[] = "clock_font.png";
+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 constexpr char FONT_BEGIN_CHAR = ' ';
+static constexpr char FONT_END_CHAR = '~' + 1;
+static constexpr size_t FONT_NUM_CHARS = FONT_END_CHAR - FONT_BEGIN_CHAR + 1;
+static constexpr size_t FONT_NUM_COLS = 16;
+static constexpr size_t FONT_NUM_ROWS = FONT_NUM_CHARS / FONT_NUM_COLS;
+static const int TEXT_CENTER_VALUE = INT_MAX;
+static const int TEXT_MISSING_VALUE = INT_MIN;
+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 constexpr size_t TEXT_POS_LEN_MAX = 16;
+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",
+};
// ---------------------------------------------------------------------------
-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));
@@ -97,9 +130,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,
@@ -154,15 +185,14 @@ status_t BootAnimation::initTexture(Texture* texture, AssetManager& assets,
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+
return NO_ERROR;
}
-status_t BootAnimation::initTexture(const Animation::Frame& frame)
+status_t BootAnimation::initTexture(FileMap* map, int* width, int* height)
{
- //StopWatch watch("blah");
-
SkBitmap bitmap;
- SkMemoryStream stream(frame.map->getDataPtr(), frame.map->getDataLength());
+ SkMemoryStream stream(map->getDataPtr(), map->getDataLength());
SkImageDecoder* codec = SkImageDecoder::Factory(&stream);
if (codec != NULL) {
codec->setDitherImage(false);
@@ -175,7 +205,7 @@ status_t BootAnimation::initTexture(const Animation::Frame& frame)
// FileMap memory is never released until application exit.
// Release it now as the texture is already loaded and the memory used for
// the packed resource can be released.
- delete frame.map;
+ delete map;
// ensure we can call getPixels(). No need to call unlock, since the
// bitmap will go out of scope when we return from this method.
@@ -193,25 +223,25 @@ status_t BootAnimation::initTexture(const Animation::Frame& frame)
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;
@@ -221,6 +251,9 @@ status_t BootAnimation::initTexture(const Animation::Frame& frame)
glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop);
+ *width = w;
+ *height = h;
+
return NO_ERROR;
}
@@ -384,7 +417,6 @@ bool BootAnimation::android()
return false;
}
-
void BootAnimation::checkExit() {
// Allow surface flinger to gracefully request shutdown
char value[PROPERTY_VALUE_MAX];
@@ -392,10 +424,48 @@ void BootAnimation::checkExit() {
int exitnow = atoi(value);
if (exitnow) {
requestExit();
- if (mAudioPlayer != NULL) {
- mAudioPlayer->requestExit();
+ }
+}
+
+bool BootAnimation::validClock(const Animation::Part& part) {
+ return part.clockPosX != TEXT_MISSING_VALUE && part.clockPosY != TEXT_MISSING_VALUE;
+}
+
+bool parseTextCoord(const char* str, int* dest) {
+ if (strcmp("c", str) == 0) {
+ *dest = TEXT_CENTER_VALUE;
+ return true;
+ }
+
+ char* end;
+ int val = (int) strtol(str, &end, 0);
+ if (end == str || *end != '\0' || val == INT_MAX || val == INT_MIN) {
+ return false;
+ }
+ *dest = val;
+ return true;
+}
+
+// Parse two position coordinates. If only string is non-empty, treat it as the y value.
+void parsePosition(const char* str1, const char* str2, int* x, int* y) {
+ bool success = false;
+ if (strlen(str1) == 0) { // No values were specified
+ // success = false
+ } else if (strlen(str2) == 0) { // we have only one value
+ if (parseTextCoord(str1, y)) {
+ *x = TEXT_CENTER_VALUE;
+ success = true;
+ }
+ } else {
+ if (parseTextCoord(str1, x) && parseTextCoord(str2, y)) {
+ success = true;
}
}
+
+ if (!success) {
+ *x = TEXT_MISSING_VALUE;
+ *y = TEXT_MISSING_VALUE;
+ }
}
// Parse a color represented as an HTML-style 'RRGGBB' string: each pair of
@@ -444,69 +514,105 @@ static bool readFile(ZipFileRO* zip, const char* name, String8& outString)
return true;
}
-// The time glyphs are stored in a single image of height 64 pixels. Each digit is 40 pixels wide,
-// and the colon character is half that at 20 pixels. The glyph order is '0123456789:'.
-// We render 24 hour time.
-void BootAnimation::drawTime(const Texture& clockTex, const int yPos) {
- static constexpr char TIME_FORMAT[] = "%H:%M";
- static constexpr int TIME_LENGTH = sizeof(TIME_FORMAT);
+// The font image should be a 96x2 array of character images. The
+// columns are the printable ASCII characters 0x20 - 0x7f. The
+// top row is regular text; the bottom row is bold.
+status_t BootAnimation::initFont(Font* font, const char* fallback) {
+ status_t status = NO_ERROR;
- static constexpr int DIGIT_HEIGHT = 64;
- static constexpr int DIGIT_WIDTH = 40;
- static constexpr int COLON_WIDTH = DIGIT_WIDTH / 2;
- static constexpr int TIME_WIDTH = (DIGIT_WIDTH * 4) + COLON_WIDTH;
+ if (font->map != nullptr) {
+ glGenTextures(1, &font->texture.name);
+ glBindTexture(GL_TEXTURE_2D, font->texture.name);
- if (clockTex.h < DIGIT_HEIGHT || clockTex.w < (10 * DIGIT_WIDTH + COLON_WIDTH)) {
- ALOGE("Clock texture is too small; abandoning boot animation clock");
- mClockEnabled = false;
- return;
+ status = initTexture(font->map, &font->texture.w, &font->texture.h);
+
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+ } else if (fallback != nullptr) {
+ status = initTexture(&font->texture, mAssets, fallback);
+ } else {
+ return NO_INIT;
}
- time_t rawtime;
- time(&rawtime);
- struct tm* timeInfo = localtime(&rawtime);
+ if (status == NO_ERROR) {
+ font->char_width = font->texture.w / FONT_NUM_COLS;
+ font->char_height = font->texture.h / FONT_NUM_ROWS / 2; // There are bold and regular rows
+ }
- char timeBuff[TIME_LENGTH];
- size_t length = strftime(timeBuff, TIME_LENGTH, TIME_FORMAT, timeInfo);
+ return status;
+}
- if (length != TIME_LENGTH - 1) {
- ALOGE("Couldn't format time; abandoning boot animation clock");
- mClockEnabled = false;
- return;
+void BootAnimation::drawText(const char* str, const Font& font, bool bold, int* x, int* y) {
+ glEnable(GL_BLEND); // Allow us to draw on top of the animation
+ glBindTexture(GL_TEXTURE_2D, font.texture.name);
+
+ const int len = strlen(str);
+ const int strWidth = font.char_width * len;
+
+ if (*x == TEXT_CENTER_VALUE) {
+ *x = (mWidth - strWidth) / 2;
+ } else if (*x < 0) {
+ *x = mWidth + *x - strWidth;
+ }
+ if (*y == TEXT_CENTER_VALUE) {
+ *y = (mHeight - font.char_height) / 2;
+ } else if (*y < 0) {
+ *y = mHeight + *y - font.char_height;
}
- glEnable(GL_BLEND); // Allow us to draw on top of the animation
- glBindTexture(GL_TEXTURE_2D, clockTex.name);
+ int cropRect[4] = { 0, 0, font.char_width, -font.char_height };
- int xPos = (mWidth - TIME_WIDTH) / 2;
- int cropRect[4] = { 0, DIGIT_HEIGHT, DIGIT_WIDTH, -DIGIT_HEIGHT };
+ for (int i = 0; i < len; i++) {
+ char c = str[i];
- for (int i = 0; i < TIME_LENGTH - 1; i++) {
- char c = timeBuff[i];
- int width = DIGIT_WIDTH;
- int pos = c - '0'; // Position in the character list
- if (pos < 0 || pos > 10) {
- continue;
- }
- if (c == ':') {
- width = COLON_WIDTH;
+ if (c < FONT_BEGIN_CHAR || c > FONT_END_CHAR) {
+ c = '?';
}
// Crop the texture to only the pixels in the current glyph
- int left = pos * DIGIT_WIDTH;
- cropRect[0] = left;
- cropRect[2] = width;
+ const int charPos = (c - FONT_BEGIN_CHAR); // Position in the list of valid characters
+ const int row = charPos / FONT_NUM_COLS;
+ const int col = charPos % FONT_NUM_COLS;
+ cropRect[0] = col * font.char_width; // Left of column
+ cropRect[1] = row * font.char_height * 2; // Top of row
+ // Move down to bottom of regular (one char_heigh) or bold (two char_heigh) line
+ cropRect[1] += bold ? 2 * font.char_height : font.char_height;
glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, cropRect);
- glDrawTexiOES(xPos, yPos, 0, width, DIGIT_HEIGHT);
+ glDrawTexiOES(*x, *y, 0, font.char_width, font.char_height);
- xPos += width;
+ *x += font.char_width;
}
glDisable(GL_BLEND); // Return to the animation's default behaviour
glBindTexture(GL_TEXTURE_2D, 0);
}
+// We render 24 hour time.
+void BootAnimation::drawClock(const Font& font, const int xPos, const int yPos) {
+ static constexpr char TIME_FORMAT[] = "%H:%M";
+ static constexpr int TIME_LENGTH = 6;
+
+ time_t rawtime;
+ time(&rawtime);
+ struct tm* timeInfo = localtime(&rawtime);
+
+ char timeBuff[TIME_LENGTH];
+ size_t length = strftime(timeBuff, TIME_LENGTH, TIME_FORMAT, timeInfo);
+
+ if (length != TIME_LENGTH - 1) {
+ ALOGE("Couldn't format time; abandoning boot animation clock");
+ mClockEnabled = false;
+ return;
+ }
+
+ int x = xPos;
+ int y = yPos;
+ drawText(timeBuff, font, false, &x, &y);
+}
+
bool BootAnimation::parseAnimationDesc(Animation& animation)
{
String8 desString;
@@ -516,16 +622,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");
@@ -537,9 +633,10 @@ bool BootAnimation::parseAnimationDesc(Animation& animation)
int height = 0;
int count = 0;
int pause = 0;
- int clockPosY = -1;
char path[ANIM_ENTRY_NAME_MAX];
char color[7] = "000000"; // default to black if unspecified
+ char clockPos1[TEXT_POS_LEN_MAX + 1] = "";
+ char clockPos2[TEXT_POS_LEN_MAX + 1] = "";
char pathType;
if (sscanf(l, "%d %d %d", &width, &height, &fps) == 3) {
@@ -547,16 +644,16 @@ bool BootAnimation::parseAnimationDesc(Animation& animation)
animation.width = width;
animation.height = height;
animation.fps = fps;
- } else if (sscanf(l, " %c %d %d %s #%6s %d",
- &pathType, &count, &pause, path, color, &clockPosY) >= 4) {
- // ALOGD("> type=%c, count=%d, pause=%d, path=%s, color=%s, clockPosY=%d", pathType, count, pause, path, color, clockPosY);
+ } else if (sscanf(l, " %c %d %d %s #%6s %16s %16s",
+ &pathType, &count, &pause, path, color, clockPos1, clockPos2) >= 4) {
+ //ALOGD("> type=%c, count=%d, pause=%d, path=%s, color=%s, clockPos1=%s, clockPos2=%s",
+ // pathType, count, pause, path, color, clockPos1, clockPos2);
Animation::Part part;
part.playUntilComplete = pathType == 'c';
part.count = count;
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);
@@ -564,6 +661,7 @@ bool BootAnimation::parseAnimationDesc(Animation& animation)
part.backgroundColor[1] = 0.0f;
part.backgroundColor[2] = 0.0f;
}
+ parsePosition(clockPos1, clockPos2, &part.clockPosX, &part.clockPosY);
animation.parts.add(part);
}
else if (strcmp(l, "$SYSTEM") == 0) {
@@ -572,7 +670,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);
@@ -588,15 +686,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;
@@ -606,25 +705,44 @@ bool BootAnimation::preloadZip(Animation& animation)
const String8 path(entryName.getPathDir());
const String8 leaf(entryName.getPathLeaf());
if (leaf.size() > 0) {
- for (size_t j=0 ; jcreateEntryFileMap(entry);
+ if (map) {
+ animation.clockFont.map = map;
+ }
+ continue;
+ }
+
+ for (size_t j = 0; j < pcount; j++) {
if (path == animation.parts[j].path) {
uint16_t method;
// supports only stored png files
- if (mZip->getEntryInfo(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");
}
}
}
@@ -632,18 +750,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(validClock(animation->parts[i])) {
+ 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);
@@ -659,17 +835,29 @@ bool BootAnimation::movie()
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- bool clockTextureInitialized = false;
+ bool clockFontInitialized = false;
if (mClockEnabled) {
- clockTextureInitialized = (initTexture(&mClock, mAssets, "images/clock64.png") == NO_ERROR);
- mClockEnabled = clockTextureInitialized;
+ clockFontInitialized =
+ (initFont(&animation->clockFont, CLOCK_FONT_ASSET) == NO_ERROR);
+ mClockEnabled = clockFontInitialized;
+ }
+
+ 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) {
- glDeleteTextures(1, &mClock.name);
+ if (clockFontInitialized) {
+ glDeleteTextures(1, &animation->clockFont.texture.name);
}
return false;
@@ -678,12 +866,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(
@@ -727,27 +913,31 @@ bool BootAnimation::playAnimation(const Animation& animation)
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
}
- initTexture(frame);
+ int w, h;
+ initTexture(frame.map, &w, &h);
}
+ 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) {
- drawTime(mClock, part.clockPosY);
+ // 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 && validClock(part)) {
+ drawClock(animation.clockFont, part.clockPosX, part.clockPosY);
}
eglSwapBuffers(mDisplay, mSurface);
@@ -777,14 +967,23 @@ bool BootAnimation::playAnimation(const Animation& animation)
break;
}
- // free the textures for this part
+ }
+
+ // Free textures created for looping parts now that the animation is done.
+ for (const Animation::Part& part : animation.parts) {
if (part.count != 1) {
- for (size_t j=0 ; jfileName = fn;
animation->zip = zip;
+ animation->clockFont.map = nullptr;
mLoadedFiles.add(animation->fileName);
parseAnimationDesc(*animation);
- preloadZip(*animation);
+ if (!preloadZip(*animation)) {
+ return NULL;
+ }
+
mLoadedFiles.remove(fn);
return animation;
}
+
+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 d49e1ec837b95299e6207b72aca22e54250f8404..42759f1acf0dc5fac12078d22e461e1558503220 100644
--- a/cmds/bootanimation/BootAnimation.h
+++ b/cmds/bootanimation/BootAnimation.h
@@ -30,7 +30,6 @@ class SkBitmap;
namespace android {
-class AudioPlayer;
class Surface;
class SurfaceComposerClient;
class SurfaceControl;
@@ -51,16 +50,45 @@ 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;
GLuint name;
};
+ struct Font {
+ FileMap* map;
+ Texture texture;
+ int char_width;
+ int char_height;
+ };
+
struct Animation {
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;
@@ -69,13 +97,19 @@ private:
struct Part {
int count; // The number of times this part should repeat, 0 for infinite
int pause; // The number of frames to pause for at the end of this part
- 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
+ int clockPosX; // The x position of the clock, in pixels. Positive values offset from
+ // the left of the screen, negative values offset from the right.
+ int clockPosY; // The y position of the clock, in pixels. Positive values offset from
+ // the bottom of the screen, negative values offset from the top.
+ // If either of the above are INT_MIN the clock is disabled, if INT_MAX
+ // the clock is centred on that axis.
String8 path;
+ String8 trimData;
SortedVector frames;
bool playUntilComplete;
float backgroundColor[3];
- FileMap* audioFile;
+ uint8_t* audioData;
+ int audioLength;
Animation* animation;
};
int fps;
@@ -85,36 +119,43 @@ private:
String8 audioConf;
String8 fileName;
ZipFileRO* zip;
+ Font clockFont;
};
status_t initTexture(Texture* texture, AssetManager& asset, const char* name);
- status_t initTexture(const Animation::Frame& frame);
+ status_t initTexture(FileMap* map, int* width, int* height);
+ status_t initFont(Font* font, const char* fallback);
bool android();
bool movie();
- void drawTime(const Texture& clockTex, const int yPos);
+ void drawText(const char* str, const Font& font, bool bold, int* x, int* y);
+ void drawClock(const Font& font, const int xPos, const int yPos);
+ bool validClock(const Animation::Part& part);
Animation* loadAnimation(const String8&);
bool playAnimation(const Animation&);
void releaseAnimation(Animation*) const;
bool parseAnimationDesc(Animation&);
bool preloadZip(Animation &animation);
+ bool playSoundsAllowed() const;
void checkExit();
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;
};
// ---------------------------------------------------------------------------
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..c546072e733a17618ecaed19e6e5bca563ae65bc
--- /dev/null
+++ b/cmds/bootanimation/audioplay.cpp
@@ -0,0 +1,400 @@
+/*
+ * 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};
+
+ // Determine channelMask from num_channels
+ SLuint32 channelMask;
+ switch (chunkFormat->num_channels) {
+ case 1:
+ channelMask = SL_SPEAKER_FRONT_CENTER;
+ break;
+ case 2:
+ channelMask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT;
+ break;
+ default:
+ // Default of 0 will derive mask from num_channels and log a warning.
+ channelMask = 0;
+ }
+
+ SLDataFormat_PCM format_pcm = {
+ SL_DATAFORMAT_PCM,
+ chunkFormat->num_channels,
+ chunkFormat->sample_rate * 1000, // convert to milliHz
+ chunkFormat->bits_per_sample,
+ 16,
+ channelMask,
+ 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..5f83d191a731571fcbd1c5d43b16de09d4fb3322 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -41,6 +41,10 @@ import android.content.pm.PackageInstaller;
import android.content.pm.PackageInstaller.SessionInfo;
import android.content.pm.PackageInstaller.SessionParams;
import android.content.pm.PackageManager;
+import android.content.pm.PackageParser;
+import android.content.pm.PackageParser.ApkLite;
+import android.content.pm.PackageParser.PackageLite;
+import android.content.pm.PackageParser.PackageParserException;
import android.content.pm.UserInfo;
import android.net.Uri;
import android.os.Binder;
@@ -362,11 +366,27 @@ public final class Pm {
*/
private int runInstall() throws RemoteException {
final InstallParams params = makeInstallParams();
+ final String inPath = nextArg();
+ if (params.sessionParams.sizeBytes < 0 && inPath != null) {
+ File file = new File(inPath);
+ if (file.isFile()) {
+ try {
+ ApkLite baseApk = PackageParser.parseApkLite(file, 0);
+ PackageLite pkgLite = new PackageLite(null, baseApk, null, null, null);
+ params.sessionParams.setSize(
+ PackageHelper.calculateInstalledSize(pkgLite, false,
+ params.sessionParams.abiOverride));
+ } catch (PackageParserException | IOException e) {
+ System.err.println("Error: Failed to parse APK file : " + e);
+ return 1;
+ }
+ }
+ }
+
final int sessionId = doCreateSession(params.sessionParams,
params.installerPackageName, params.userId);
try {
- final String inPath = nextArg();
if (inPath == null && params.sessionParams.sizeBytes == 0) {
System.err.println("Error: must either specify a package size or an APK file");
return 1;
@@ -922,6 +942,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/cmds/wm/src/com/android/commands/wm/Wm.java b/cmds/wm/src/com/android/commands/wm/Wm.java
index f7f7c887aeb06d1d89aa401390667f9d8af5f1e8..383cd01ddcd6cca8e2007fb5463cb96166ddf8bb 100644
--- a/cmds/wm/src/com/android/commands/wm/Wm.java
+++ b/cmds/wm/src/com/android/commands/wm/Wm.java
@@ -23,6 +23,7 @@ import android.graphics.Point;
import android.graphics.Rect;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.UserHandle;
import android.util.AndroidException;
import android.util.DisplayMetrics;
import android.view.Display;
@@ -201,9 +202,11 @@ public class Wm extends BaseCommand {
try {
if (density > 0) {
// TODO(multidisplay): For now Configuration only applies to main screen.
- mWm.setForcedDisplayDensity(Display.DEFAULT_DISPLAY, density);
+ mWm.setForcedDisplayDensityForUser(Display.DEFAULT_DISPLAY, density,
+ UserHandle.USER_CURRENT);
} else {
- mWm.clearForcedDisplayDensity(Display.DEFAULT_DISPLAY);
+ mWm.clearForcedDisplayDensityForUser(Display.DEFAULT_DISPLAY,
+ UserHandle.USER_CURRENT);
}
} catch (RemoteException e) {
}
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index ae78e21807e84c66cc2c85f210e68a1e8a8e1638..163e7d2661b91bca0185eef7ea81d75acc228158 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -53,7 +53,7 @@ import java.lang.annotation.RetentionPolicy;
import java.util.List;
/**
- * Accessibility services are intended to assist users with disabilities in using
+ * Accessibility services should only be used to assist users with disabilities in using
* Android devices and apps. They run in the background and receive callbacks by the system
* when {@link AccessibilityEvent}s are fired. Such events denote some state transition
* in the user interface, for example, the focus has changed, a button has been clicked,
@@ -628,8 +628,8 @@ public abstract class AccessibilityService extends Service {
if (connection == null) {
return false;
}
- List events = MotionEventGenerator.getMotionEventsFromGestureDescription(
- gesture, 100);
+ List steps =
+ MotionEventGenerator.getGestureStepsFromGestureDescription(gesture, 100);
try {
synchronized (mLock) {
mGestureStatusCallbackSequence++;
@@ -641,8 +641,8 @@ public abstract class AccessibilityService extends Service {
callback, handler);
mGestureStatusCallbackInfos.put(mGestureStatusCallbackSequence, callbackInfo);
}
- connection.sendMotionEvents(mGestureStatusCallbackSequence,
- new ParceledListSlice<>(events));
+ connection.sendGesture(mGestureStatusCallbackSequence,
+ new ParceledListSlice<>(steps));
}
} catch (RemoteException re) {
throw new RuntimeException(re);
diff --git a/core/java/android/accessibilityservice/GestureDescription.java b/core/java/android/accessibilityservice/GestureDescription.java
index fc9581e7367c589be5536c04617ffbd6541b18db..d9b03faa42faab73716fb32f6b48aff699633258 100644
--- a/core/java/android/accessibilityservice/GestureDescription.java
+++ b/core/java/android/accessibilityservice/GestureDescription.java
@@ -21,6 +21,8 @@ import android.annotation.NonNull;
import android.graphics.Path;
import android.graphics.PathMeasure;
import android.graphics.RectF;
+import android.os.Parcel;
+import android.os.Parcelable;
import android.view.InputDevice;
import android.view.MotionEvent;
import android.view.MotionEvent.PointerCoords;
@@ -303,13 +305,37 @@ public final class GestureDescription {
}
}
- private static class TouchPoint {
+ /**
+ * The location of a finger for gesture dispatch
+ *
+ * @hide
+ */
+ public static class TouchPoint implements Parcelable {
+ private static final int FLAG_IS_START_OF_PATH = 0x01;
+ private static final int FLAG_IS_END_OF_PATH = 0x02;
+
int mPathIndex;
boolean mIsStartOfPath;
boolean mIsEndOfPath;
float mX;
float mY;
+ public TouchPoint() {
+ }
+
+ public TouchPoint(TouchPoint pointToCopy) {
+ copyFrom(pointToCopy);
+ }
+
+ public TouchPoint(Parcel parcel) {
+ mPathIndex = parcel.readInt();
+ int startEnd = parcel.readInt();
+ mIsStartOfPath = (startEnd & FLAG_IS_START_OF_PATH) != 0;
+ mIsEndOfPath = (startEnd & FLAG_IS_END_OF_PATH) != 0;
+ mX = parcel.readFloat();
+ mY = parcel.readFloat();
+ }
+
void copyFrom(TouchPoint other) {
mPathIndex = other.mPathIndex;
mIsStartOfPath = other.mIsStartOfPath;
@@ -317,12 +343,94 @@ public final class GestureDescription {
mX = other.mX;
mY = other.mY;
}
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(mPathIndex);
+ int startEnd = mIsStartOfPath ? FLAG_IS_START_OF_PATH : 0;
+ startEnd |= mIsEndOfPath ? FLAG_IS_END_OF_PATH : 0;
+ dest.writeInt(startEnd);
+ dest.writeFloat(mX);
+ dest.writeFloat(mY);
+ }
+
+ public static final Parcelable.Creator CREATOR
+ = new Parcelable.Creator() {
+ public TouchPoint createFromParcel(Parcel in) {
+ return new TouchPoint(in);
+ }
+
+ public TouchPoint[] newArray(int size) {
+ return new TouchPoint[size];
+ }
+ };
+ }
+
+ /**
+ * A step along a gesture. Contains all of the touch points at a particular time
+ *
+ * @hide
+ */
+ public static class GestureStep implements Parcelable {
+ public long timeSinceGestureStart;
+ public int numTouchPoints;
+ public TouchPoint[] touchPoints;
+
+ public GestureStep(long timeSinceGestureStart, int numTouchPoints,
+ TouchPoint[] touchPointsToCopy) {
+ this.timeSinceGestureStart = timeSinceGestureStart;
+ this.numTouchPoints = numTouchPoints;
+ this.touchPoints = new TouchPoint[numTouchPoints];
+ for (int i = 0; i < numTouchPoints; i++) {
+ this.touchPoints[i] = new TouchPoint(touchPointsToCopy[i]);
+ }
+ }
+
+ public GestureStep(Parcel parcel) {
+ timeSinceGestureStart = parcel.readLong();
+ Parcelable[] parcelables =
+ parcel.readParcelableArray(TouchPoint.class.getClassLoader());
+ numTouchPoints = (parcelables == null) ? 0 : parcelables.length;
+ touchPoints = new TouchPoint[numTouchPoints];
+ for (int i = 0; i < numTouchPoints; i++) {
+ touchPoints[i] = (TouchPoint) parcelables[i];
+ }
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeLong(timeSinceGestureStart);
+ dest.writeParcelableArray(touchPoints, flags);
+ }
+
+ public static final Parcelable.Creator CREATOR
+ = new Parcelable.Creator() {
+ public GestureStep createFromParcel(Parcel in) {
+ return new GestureStep(in);
+ }
+
+ public GestureStep[] newArray(int size) {
+ return new GestureStep[size];
+ }
+ };
}
/**
* Class to convert a GestureDescription to a series of MotionEvents.
+ *
+ * @hide
*/
- static class MotionEventGenerator {
+ public static class MotionEventGenerator {
/**
* Constants used to initialize all MotionEvents
*/
@@ -341,38 +449,52 @@ public final class GestureDescription {
private static PointerCoords[] sPointerCoords;
private static PointerProperties[] sPointerProps;
- static List getMotionEventsFromGestureDescription(
+ static List getGestureStepsFromGestureDescription(
GestureDescription description, int sampleTimeMs) {
- final List motionEvents = new ArrayList<>();
+ final List gestureSteps = new ArrayList<>();
// Point data at each time we generate an event for
final TouchPoint[] currentTouchPoints =
getCurrentTouchPoints(description.getStrokeCount());
- // Point data sent in last touch event
- int lastTouchPointSize = 0;
- final TouchPoint[] lastTouchPoints =
- getLastTouchPoints(description.getStrokeCount());
-
+ int currentTouchPointSize = 0;
/* Loop through each time slice where there are touch points */
long timeSinceGestureStart = 0;
long nextKeyPointTime = description.getNextKeyPointAtLeast(timeSinceGestureStart);
while (nextKeyPointTime >= 0) {
- timeSinceGestureStart = (lastTouchPointSize == 0) ? nextKeyPointTime
+ timeSinceGestureStart = (currentTouchPointSize == 0) ? nextKeyPointTime
: Math.min(nextKeyPointTime, timeSinceGestureStart + sampleTimeMs);
- int currentTouchPointSize = description.getPointsForTime(timeSinceGestureStart,
+ currentTouchPointSize = description.getPointsForTime(timeSinceGestureStart,
currentTouchPoints);
+ gestureSteps.add(new GestureStep(timeSinceGestureStart, currentTouchPointSize,
+ currentTouchPoints));
+
+ /* Move to next time slice */
+ nextKeyPointTime = description.getNextKeyPointAtLeast(timeSinceGestureStart + 1);
+ }
+ return gestureSteps;
+ }
+
+ public static List getMotionEventsFromGestureSteps(List steps) {
+ final List motionEvents = new ArrayList<>();
+
+ // Number of points in last touch event
+ int lastTouchPointSize = 0;
+ TouchPoint[] lastTouchPoints;
+
+ for (int i = 0; i < steps.size(); i++) {
+ GestureStep step = steps.get(i);
+ int currentTouchPointSize = step.numTouchPoints;
+ lastTouchPoints = getLastTouchPoints(
+ Math.max(lastTouchPointSize, currentTouchPointSize));
appendMoveEventIfNeeded(motionEvents, lastTouchPoints, lastTouchPointSize,
- currentTouchPoints, currentTouchPointSize, timeSinceGestureStart);
+ step.touchPoints, currentTouchPointSize, step.timeSinceGestureStart);
lastTouchPointSize = appendUpEvents(motionEvents, lastTouchPoints,
- lastTouchPointSize, currentTouchPoints, currentTouchPointSize,
- timeSinceGestureStart);
+ lastTouchPointSize, step.touchPoints, currentTouchPointSize,
+ step.timeSinceGestureStart);
lastTouchPointSize = appendDownEvents(motionEvents, lastTouchPoints,
- lastTouchPointSize, currentTouchPoints, currentTouchPointSize,
- timeSinceGestureStart);
-
- /* Move to next time slice */
- nextKeyPointTime = description.getNextKeyPointAtLeast(timeSinceGestureStart + 1);
+ lastTouchPointSize, step.touchPoints, currentTouchPointSize,
+ step.timeSinceGestureStart);
}
return motionEvents;
}
diff --git a/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl b/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
index 7a55079d3ecf2eb50b9db5d947c040074e27ef06..81cddbac3f53b2f69280584f9357344882db1ded 100644
--- a/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
+++ b/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
@@ -88,5 +88,5 @@ interface IAccessibilityServiceConnection {
void setSoftKeyboardCallbackEnabled(boolean enabled);
- void sendMotionEvents(int sequence, in ParceledListSlice events);
+ void sendGesture(int sequence, in ParceledListSlice gestureSteps);
}
diff --git a/core/java/android/accounts/Account.java b/core/java/android/accounts/Account.java
index 7b83a3076db336d53bb8d3eef65eb799ed96ff39..b6e85f18a69525e6d35ee20d70d0ae6ae11c9015 100644
--- a/core/java/android/accounts/Account.java
+++ b/core/java/android/accounts/Account.java
@@ -16,9 +16,19 @@
package android.accounts;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
import android.os.Parcelable;
import android.os.Parcel;
+import android.os.RemoteException;
+import android.os.ServiceManager;
import android.text.TextUtils;
+import android.util.ArraySet;
+import android.util.Log;
+import com.android.internal.annotations.GuardedBy;
+
+import java.util.Set;
/**
* Value type that represents an Account in the {@link AccountManager}. This object is
@@ -26,8 +36,14 @@ import android.text.TextUtils;
* suitable for use as the key of a {@link java.util.Map}
*/
public class Account implements Parcelable {
+ private static final String TAG = "Account";
+
+ @GuardedBy("sAccessedAccounts")
+ private static final Set sAccessedAccounts = new ArraySet<>();
+
public final String name;
public final String type;
+ private final @Nullable String accessId;
public boolean equals(Object o) {
if (o == this) return true;
@@ -44,6 +60,20 @@ public class Account implements Parcelable {
}
public Account(String name, String type) {
+ this(name, type, null);
+ }
+
+ /**
+ * @hide
+ */
+ public Account(@NonNull Account other, @NonNull String accessId) {
+ this(other.name, other.type, accessId);
+ }
+
+ /**
+ * @hide
+ */
+ public Account(String name, String type, String accessId) {
if (TextUtils.isEmpty(name)) {
throw new IllegalArgumentException("the name must not be empty: " + name);
}
@@ -52,11 +82,31 @@ public class Account implements Parcelable {
}
this.name = name;
this.type = type;
+ this.accessId = accessId;
}
public Account(Parcel in) {
this.name = in.readString();
this.type = in.readString();
+ this.accessId = in.readString();
+ if (accessId != null) {
+ synchronized (sAccessedAccounts) {
+ if (sAccessedAccounts.add(this)) {
+ try {
+ IAccountManager accountManager = IAccountManager.Stub.asInterface(
+ ServiceManager.getService(Context.ACCOUNT_SERVICE));
+ accountManager.onAccountAccessed(accessId);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error noting account access", e);
+ }
+ }
+ }
+ }
+ }
+
+ /** @hide */
+ public String getAccessId() {
+ return accessId;
}
public int describeContents() {
@@ -66,6 +116,7 @@ public class Account implements Parcelable {
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(name);
dest.writeString(type);
+ dest.writeString(accessId);
}
public static final Creator CREATOR = new Creator() {
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java
index 5cf59bc4760db8987131657ec8aa6f9987521477..cabaf85b37c35750e1120df52a349cb81ff7db14 100644
--- a/core/java/android/accounts/AccountManager.java
+++ b/core/java/android/accounts/AccountManager.java
@@ -28,6 +28,7 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.IntentSender;
import android.content.res.Resources;
import android.database.SQLException;
import android.os.Build;
@@ -177,6 +178,14 @@ public class AccountManager {
*/
public static final String KEY_ACCOUNT_TYPE = "accountType";
+ /**
+ * Bundle key used for the account access id used for noting the
+ * account was accessed when unmarshalled from a parcel.
+ *
+ * @hide
+ */
+ public static final String KEY_ACCOUNT_ACCESS_ID = "accountAccessId";
+
/**
* Bundle key used for the auth token value in results
* from {@link #getAuthToken} and friends.
@@ -265,6 +274,15 @@ public class AccountManager {
"android.accounts.AccountAuthenticator";
public static final String AUTHENTICATOR_ATTRIBUTES_NAME = "account-authenticator";
+ /**
+ * Token type for the special case where a UID has access only to an account
+ * but no authenticator specific auth token types.
+ *
+ * @hide
+ */
+ public static final String ACCOUNT_ACCESS_TOKEN_TYPE =
+ "com.android.AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE";
+
private final Context mContext;
private final IAccountManager mService;
private final Handler mMainHandler;
@@ -803,7 +821,8 @@ public class AccountManager {
public Account bundleToResult(Bundle bundle) throws AuthenticatorException {
String name = bundle.getString(KEY_ACCOUNT_NAME);
String type = bundle.getString(KEY_ACCOUNT_TYPE);
- return new Account(name, type);
+ String accessId = bundle.getString(KEY_ACCOUNT_ACCESS_ID);
+ return new Account(name, type, accessId);
}
}.start();
}
@@ -2263,6 +2282,7 @@ public class AccountManager {
result.putString(KEY_ACCOUNT_NAME, null);
result.putString(KEY_ACCOUNT_TYPE, null);
result.putString(KEY_AUTHTOKEN, null);
+ result.putBinder(KEY_ACCOUNT_ACCESS_ID, null);
try {
mResponse.onResult(result);
} catch (RemoteException e) {
@@ -2288,9 +2308,11 @@ public class AccountManager {
public void onResult(Bundle value) throws RemoteException {
Account account = new Account(
value.getString(KEY_ACCOUNT_NAME),
- value.getString(KEY_ACCOUNT_TYPE));
- mFuture = getAuthToken(account, mAuthTokenType, mLoginOptions,
- mActivity, mMyCallback, mHandler);
+ value.getString(KEY_ACCOUNT_TYPE),
+ value.getString(KEY_ACCOUNT_ACCESS_ID));
+ mFuture = getAuthToken(account, mAuthTokenType,
+ mLoginOptions, mActivity, mMyCallback,
+ mHandler);
}
@Override
@@ -2337,7 +2359,8 @@ public class AccountManager {
setException(new AuthenticatorException("account not in result"));
return;
}
- final Account account = new Account(accountName, accountType);
+ final String accessId = result.getString(KEY_ACCOUNT_ACCESS_ID);
+ final Account account = new Account(accountName, accountType, accessId);
mNumAccounts = 1;
getAuthToken(account, mAuthTokenType, null /* options */, mActivity,
mMyCallback, mHandler);
@@ -2680,8 +2703,6 @@ public class AccountManager {
*
*
{@link #KEY_ACCOUNT_SESSION_BUNDLE} - encrypted Bundle for
* adding the the to the device later.
- *
{@link #KEY_PASSWORD} - optional, the password or password
- * hash of the account.
*
{@link #KEY_ACCOUNT_STATUS_TOKEN} - optional, token to check
* status of the account
*
@@ -2769,8 +2790,6 @@ public class AccountManager {
*
*
{@link #KEY_ACCOUNT_SESSION_BUNDLE} - encrypted Bundle for
* updating the local credentials on device later.
- *
{@link #KEY_PASSWORD} - optional, the password or password
- * hash of the account
*
{@link #KEY_ACCOUNT_STATUS_TOKEN} - optional, token to check
* status of the account
*
@@ -2964,4 +2983,49 @@ public class AccountManager {
}
}.start();
}
+
+ /**
+ * Gets whether a given package under a user has access to an account.
+ * Can be called only from the system UID.
+ *
+ * @param account The account for which to check.
+ * @param packageName The package for which to check.
+ * @param userHandle The user for which to check.
+ * @return True if the package can access the account.
+ *
+ * @hide
+ */
+ public boolean hasAccountAccess(@NonNull Account account, @NonNull String packageName,
+ @NonNull UserHandle userHandle) {
+ try {
+ return mService.hasAccountAccess(account, packageName, userHandle);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Creates an intent to request access to a given account for a UID.
+ * The returned intent should be stated for a result where {@link
+ * Activity#RESULT_OK} result means access was granted whereas {@link
+ * Activity#RESULT_CANCELED} result means access wasn't granted. Can
+ * be called only from the system UID.
+ *
+ * @param account The account for which to request.
+ * @param packageName The package name which to request.
+ * @param userHandle The user for which to request.
+ * @return The intent to request account access or null if the package
+ * doesn't exist.
+ *
+ * @hide
+ */
+ public IntentSender createRequestAccountAccessIntentSenderAsUser(@NonNull Account account,
+ @NonNull String packageName, @NonNull UserHandle userHandle) {
+ try {
+ return mService.createRequestAccountAccessIntentSenderAsUser(account, packageName,
+ userHandle);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
}
diff --git a/core/java/android/accounts/AccountManagerInternal.java b/core/java/android/accounts/AccountManagerInternal.java
new file mode 100644
index 0000000000000000000000000000000000000000..68c17c32fdc3e9c9e9db64976236218d17a35a79
--- /dev/null
+++ b/core/java/android/accounts/AccountManagerInternal.java
@@ -0,0 +1,90 @@
+/*
+ * 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.accounts;
+
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.os.RemoteCallback;
+
+/**
+ * Account manager local system service interface.
+ *
+ * @hide Only for use within the system server.
+ */
+public abstract class AccountManagerInternal {
+
+ /**
+ * Listener for explicit UID account access grant changes.
+ */
+ public interface OnAppPermissionChangeListener {
+
+ /**
+ * Called when the explicit grant state for a given UID to
+ * access an account changes.
+ *
+ * @param account The account
+ * @param uid The UID for which the grant changed
+ */
+ public void onAppPermissionChanged(Account account, int uid);
+ }
+
+ /**
+ * Requests that a given package is given access to an account.
+ * The provided callback will be invoked with a {@link android.os.Bundle}
+ * containing the result which will be a boolean value mapped to the
+ * {@link AccountManager#KEY_BOOLEAN_RESULT} key.
+ *
+ * @param account The account for which to request.
+ * @param packageName The package name for which to request.
+ * @param userId Concrete user id for which to request.
+ * @param callback A callback for receiving the result.
+ */
+ public abstract void requestAccountAccess(@NonNull Account account,
+ @NonNull String packageName, @IntRange(from = 0) int userId,
+ @NonNull RemoteCallback callback);
+
+ /**
+ * Check whether the given UID has access to the account.
+ *
+ * @param account The account
+ * @param uid The UID
+ * @return Whether the UID can access the account
+ */
+ public abstract boolean hasAccountAccess(@NonNull Account account, @IntRange(from = 0) int uid);
+
+ /**
+ * Adds a listener for explicit UID account access grant changes.
+ *
+ * @param listener The listener
+ */
+ public abstract void addOnAppPermissionChangeListener(
+ @NonNull OnAppPermissionChangeListener listener);
+
+ /**
+ * Backups the account access permissions.
+ * @param userId The user for which to backup.
+ * @return The backup data.
+ */
+ public abstract byte[] backupAccountAccessPermissions(int userId);
+
+ /**
+ * Restores the account access permissions.
+ * @param data The restore data.
+ * @param userId The user for which to restore.
+ */
+ public abstract void restoreAccountAccessPermissions(byte[] data, int userId);
+}
diff --git a/core/java/android/accounts/ChooseTypeAndAccountActivity.java b/core/java/android/accounts/ChooseTypeAndAccountActivity.java
index 133df2bfa16aadafaf5d9baa69cf0151d6edb4e7..aed7a36937177c6c01f57536625c7455372b9901 100644
--- a/core/java/android/accounts/ChooseTypeAndAccountActivity.java
+++ b/core/java/android/accounts/ChooseTypeAndAccountActivity.java
@@ -399,7 +399,7 @@ public class ChooseTypeAndAccountActivity extends Activity
* useless.
*/
private void setNonLabelThemeAndCallSuperCreate(Bundle savedInstanceState) {
- setTheme(R.style.Theme_Material_Light_Dialog_NoActionBar);
+ setTheme(R.style.Theme_DeviceDefault_Light_Dialog_NoActionBar);
super.onCreate(savedInstanceState);
}
diff --git a/core/java/android/accounts/GrantCredentialsPermissionActivity.java b/core/java/android/accounts/GrantCredentialsPermissionActivity.java
index 12b2b9ccf1480c8d8e6c93c6ebda1ad5bb259aec..38eab290502259c1085b130c93998baa8699b648 100644
--- a/core/java/android/accounts/GrantCredentialsPermissionActivity.java
+++ b/core/java/android/accounts/GrantCredentialsPermissionActivity.java
@@ -35,12 +35,10 @@ import java.io.IOException;
*/
public class GrantCredentialsPermissionActivity extends Activity implements View.OnClickListener {
public static final String EXTRAS_ACCOUNT = "account";
- public static final String EXTRAS_AUTH_TOKEN_LABEL = "authTokenLabel";
public static final String EXTRAS_AUTH_TOKEN_TYPE = "authTokenType";
public static final String EXTRAS_RESPONSE = "response";
- public static final String EXTRAS_ACCOUNT_TYPE_LABEL = "accountTypeLabel";
- public static final String EXTRAS_PACKAGES = "application";
public static final String EXTRAS_REQUESTING_UID = "uid";
+
private Account mAccount;
private String mAuthTokenType;
private int mUid;
@@ -109,7 +107,11 @@ public class GrantCredentialsPermissionActivity extends Activity implements View
}
}
};
- AccountManager.get(this).getAuthTokenLabel(mAccount.type, mAuthTokenType, callback, null);
+
+ if (!AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE.equals(mAuthTokenType)) {
+ AccountManager.get(this).getAuthTokenLabel(mAccount.type,
+ mAuthTokenType, callback, null);
+ }
findViewById(R.id.allow_button).setOnClickListener(this);
findViewById(R.id.deny_button).setOnClickListener(this);
diff --git a/core/java/android/accounts/IAccountManager.aidl b/core/java/android/accounts/IAccountManager.aidl
index 7199288426f2a2fbc638da1d7f846ea38bec267c..c271e7ebc52c8cd051404d8ed67b6304e0c47536 100644
--- a/core/java/android/accounts/IAccountManager.aidl
+++ b/core/java/android/accounts/IAccountManager.aidl
@@ -19,8 +19,10 @@ package android.accounts;
import android.accounts.IAccountManagerResponse;
import android.accounts.Account;
import android.accounts.AuthenticatorDescription;
+import android.content.IntentSender;
import android.os.Bundle;
-
+import android.os.RemoteCallback;
+import android.os.UserHandle;
/**
* Central application service that provides account management.
@@ -102,4 +104,12 @@ interface IAccountManager {
/* Check if credentials update is suggested */
void isCredentialsUpdateSuggested(in IAccountManagerResponse response, in Account account,
String statusToken);
+
+ /* Check if the package in a user can access an account */
+ boolean hasAccountAccess(in Account account, String packageName, in UserHandle userHandle);
+ /* Crate an intent to request account access for package and a given user id */
+ IntentSender createRequestAccountAccessIntentSenderAsUser(in Account account,
+ String packageName, in UserHandle userHandle);
+
+ void onAccountAccessed(String token);
}
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/LayoutTransition.java b/core/java/android/animation/LayoutTransition.java
index cdd72be76805a2c57845a1e771a409ae3e53dd8b..5a23fddf1d5128bb2497663f5fa73d40826cca26 100644
--- a/core/java/android/animation/LayoutTransition.java
+++ b/core/java/android/animation/LayoutTransition.java
@@ -62,7 +62,11 @@ import java.util.Map;
* layout will run (closing the gap created in the layout when the item was removed). If this
* default choreography behavior is not desired, the {@link #setDuration(int, long)} and
* {@link #setStartDelay(int, long)} of any or all of the animations can be changed as
- * appropriate.
+ * appropriate. Keep in mind, however, that if you start an APPEARING animation before a
+ * DISAPPEARING animation is completed, the DISAPPEARING animation stops, and any effects from
+ * the DISAPPEARING animation are reverted. If you instead start a DISAPPEARING animation
+ * before an APPEARING animation is completed, a similar set of effects occurs for the
+ * APPEARING animation.
*
*
The animations specified for the transition, both the defaults and any custom animations
* set on the transition object, are templates only. That is, these animations exist to hold the
diff --git a/core/java/android/animation/ObjectAnimator.java b/core/java/android/animation/ObjectAnimator.java
index 5c4b979ccb3cb1159634758feb2b1778fe3a82c5..0c21c4ff55e7a7c0907af540d4c968db4febf645 100644
--- a/core/java/android/animation/ObjectAnimator.java
+++ b/core/java/android/animation/ObjectAnimator.java
@@ -978,7 +978,8 @@ public final class ObjectAnimator extends ValueAnimator {
void animateValue(float fraction) {
final Object target = getTarget();
if (mTarget != null && target == null) {
- // We lost the target reference, cancel and clean up.
+ // We lost the target reference, cancel and clean up. Note: we allow null target if the
+ /// target has never been set.
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..7e16e3ece5495583d979b18ba2fbd5c2f9b44bd2 100644
--- a/core/java/android/animation/ValueAnimator.java
+++ b/core/java/android/animation/ValueAnimator.java
@@ -18,6 +18,7 @@ package android.animation;
import android.annotation.CallSuper;
import android.annotation.IntDef;
+import android.annotation.TestApi;
import android.os.Looper;
import android.os.Trace;
import android.util.AndroidRuntimeException;
@@ -261,6 +262,7 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio
/**
* @hide
*/
+ @TestApi
public static void setDurationScale(float durationScale) {
sDurationScale = durationScale;
}
@@ -268,6 +270,7 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio
/**
* @hide
*/
+ @TestApi
public static float getDurationScale() {
return sDurationScale;
}
@@ -982,6 +985,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.
*
- *
*
*
@@ -1483,9 +1483,10 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
* at this point. If you want to do work once the activity itself is
* created, see {@link #onActivityCreated(Bundle)}.
*
- *
If your app's targetSdkVersion is 23 or lower, child fragments
- * being restored from the savedInstanceState are restored after onCreate
- * returns. When targeting N or above and running on an N or newer platform version
+ *
If your app's targetSdkVersion is {@link android.os.Build.VERSION_CODES#M}
+ * or lower, child fragments being restored from the savedInstanceState are restored after
+ * onCreate returns. When targeting {@link android.os.Build.VERSION_CODES#N} or
+ * above and running on an N or newer platform version
* they are restored by Fragment.onCreate.
*
* @param savedInstanceState If the fragment is being re-created from
diff --git a/core/java/android/app/FragmentHostCallback.java b/core/java/android/app/FragmentHostCallback.java
index e1d713626e2e1911c8d99da56dd90b137d6ae418..d869168e2b6a55a266093c22a6ab1f44d37483fd 100644
--- a/core/java/android/app/FragmentHostCallback.java
+++ b/core/java/android/app/FragmentHostCallback.java
@@ -340,6 +340,11 @@ public abstract class FragmentHostCallback extends FragmentContainer {
}
void restoreLoaderNonConfig(ArrayMap loaderManagers) {
+ if (loaderManagers != null) {
+ for (int i = 0, N = loaderManagers.size(); i < N; i++) {
+ ((LoaderManagerImpl) loaderManagers.valueAt(i)).updateHostController(this);
+ }
+ }
mAllLoaderManagers = loaderManagers;
}
diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java
index cd7665cf1163eaff434a0667dd92d2e42c45ec82..bfaf3328f6116bff6c426d8a802f2efe2190f9d4 100644
--- a/core/java/android/app/FragmentManager.java
+++ b/core/java/android/app/FragmentManager.java
@@ -59,7 +59,7 @@ import java.util.List;
*
*
Developer Guides
*
For more information about using fragments, read the
- * Fragments developer guide.
*
* While the FragmentManager API was introduced in
diff --git a/core/java/android/app/FragmentTransaction.java b/core/java/android/app/FragmentTransaction.java
index e435580d55fef9626ff9195af921550cbb834d3c..633e85b781184bd78fd39c29f6db090b2b62381a 100644
--- a/core/java/android/app/FragmentTransaction.java
+++ b/core/java/android/app/FragmentTransaction.java
@@ -17,7 +17,8 @@ import java.lang.annotation.RetentionPolicy;
*
*
Developer Guides
*
For more information about using fragments, read the
- * Fragments developer guide.
*/
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 5037e3eb9dc54772a136f35f2a535b0c7da5dfe2..5a4470b2ecdb5ba25aef19af2f73c22b9fa6764f 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -136,7 +136,7 @@ public interface IActivityManager extends IInterface {
ActivityManager.TaskDescription description, Bitmap thumbnail) throws RemoteException;
public Point getAppTaskThumbnailSize() throws RemoteException;
public List getTasks(int maxNum, int flags) throws RemoteException;
- public List getRecentTasks(int maxNum,
+ public ParceledListSlice getRecentTasks(int maxNum,
int flags, int userId) throws RemoteException;
public ActivityManager.TaskThumbnail getTaskThumbnail(int taskId) throws RemoteException;
public List getServices(int maxNum, int flags) throws RemoteException;
@@ -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,31 @@ 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;
+
+ /**
+ * Returns if the target of the PendingIntent can be fired directly, without triggering
+ * a work profile challenge. This can happen if the PendingIntent is to start direct-boot
+ * aware activities, and the target user is in RUNNING_LOCKED state, i.e. we should allow
+ * direct-boot aware activity to bypass work challenge when the user hasn't unlocked yet.
+ * @param intent the {@link PendingIntent} to be tested.
+ * @return {@code true} if the intent should not trigger a work challenge, {@code false}
+ * otherwise.
+ * @throws RemoteException
+ */
+ public boolean canBypassWorkChallenge(PendingIntent intent) throws RemoteException;
+
/*
* Private non-Binder interfaces
*/
@@ -1043,4 +1069,10 @@ 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;
+ int CAN_BYPASS_WORK_CHALLENGE = IBinder.FIRST_CALL_TRANSACTION + 380;
}
diff --git a/core/java/android/app/IApplicationThread.java b/core/java/android/app/IApplicationThread.java
index 5b13164ddb4a236f6e1cd8c0f0013d13df08380f..3fa88ae674a44fc9a0e5a12f063d1fb8b31ffa6e 100644
--- a/core/java/android/app/IApplicationThread.java
+++ b/core/java/android/app/IApplicationThread.java
@@ -67,7 +67,8 @@ public interface IApplicationThread extends IInterface {
List pendingNewIntents, int configChanges, boolean notResumed,
Configuration config, Configuration overrideConfig, boolean preserveWindow)
throws RemoteException;
- void scheduleNewIntent(List intent, IBinder token) throws RemoteException;
+ void scheduleNewIntent(
+ List intent, IBinder token, boolean andPause) throws RemoteException;
void scheduleDestroyActivity(IBinder token, boolean finished,
int configChanges) throws RemoteException;
void scheduleReceiver(Intent intent, ActivityInfo info, CompatibilityInfo compatInfo,
@@ -122,7 +123,6 @@ public interface IApplicationThread extends IInterface {
throws RemoteException;
void dumpHeap(boolean managed, String path, ParcelFileDescriptor fd)
throws RemoteException;
- void attachAgent(String path) throws RemoteException;
void setSchedulingGroup(int group) throws RemoteException;
// the package has been removed, clean up internal references
static final int PACKAGE_REMOVED = 0;
@@ -225,5 +225,4 @@ public interface IApplicationThread extends IInterface {
int SCHEDULE_MULTI_WINDOW_CHANGED_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+58;
int SCHEDULE_PICTURE_IN_PICTURE_CHANGED_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+59;
int SCHEDULE_LOCAL_VOICE_INTERACTION_STARTED_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+60;
- int ATTACH_AGENT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+61;
}
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/ITransientNotification.aidl b/core/java/android/app/ITransientNotification.aidl
index 35b53a48e6e18385fd0b42b19c8232cc8f8cc6d5..d5b3ed0a44d80274de5003e873a414398a57c516 100644
--- a/core/java/android/app/ITransientNotification.aidl
+++ b/core/java/android/app/ITransientNotification.aidl
@@ -19,7 +19,7 @@ package android.app;
/** @hide */
oneway interface ITransientNotification {
- void show();
+ void show(IBinder windowToken);
void hide();
}
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/IntentService.java b/core/java/android/app/IntentService.java
index f33af396070e9dde19302ef366a73e4a7f815a94..e4a22c42d9bcbeadeb63d1ea6a57adca35cdf024 100644
--- a/core/java/android/app/IntentService.java
+++ b/core/java/android/app/IntentService.java
@@ -46,7 +46,8 @@ import android.os.Message;
*
*
Developer Guides
*
For a detailed discussion about how to create services, read the
- * Services developer guide.
*
* @see android.os.AsyncTask
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index 8824c981dc45e12b97a6b8aeb62e334f90bb1474..9ea16a719ceb7ddadb66a9b3ac469df88cc041c1 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -1400,18 +1400,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 {
@@ -1460,7 +1448,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);
}
@@ -1471,6 +1459,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/LoaderManager.java b/core/java/android/app/LoaderManager.java
index c14dec93c348ee1b05112f88fb3a0358566a5970..bedf31a22f26410806c220c20e36ec46ba99a031 100644
--- a/core/java/android/app/LoaderManager.java
+++ b/core/java/android/app/LoaderManager.java
@@ -195,6 +195,9 @@ public abstract class LoaderManager {
public static void enableDebugLogging(boolean enabled) {
LoaderManagerImpl.DEBUG = enabled;
}
+
+ /** @hide for internal testing only */
+ public FragmentHostCallback getFragmentHostCallback() { return null; }
}
class LoaderManagerImpl extends LoaderManager {
@@ -542,6 +545,10 @@ class LoaderManagerImpl extends LoaderManager {
void updateHostController(FragmentHostCallback host) {
mHost = host;
}
+
+ public FragmentHostCallback getFragmentHostCallback() {
+ return mHost;
+ }
private LoaderInfo createLoader(int id, Bundle args,
LoaderManager.LoaderCallbacks
*
- *
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/TimePickerDialog.java b/core/java/android/app/TimePickerDialog.java
index aca07636e26ea4f52136a68f0af3cc459e904483..3f467a01bee2a6cca3462575d973b4e159c42994 100644
--- a/core/java/android/app/TimePickerDialog.java
+++ b/core/java/android/app/TimePickerDialog.java
@@ -16,6 +16,7 @@
package android.app;
+import android.annotation.TestApi;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
@@ -91,6 +92,12 @@ public class TimePickerDialog extends AlertDialog implements OnClickListener,
/**
* Creates a new time picker dialog with the specified theme.
+ *
+ * The theme is overlaid on top of the theme of the parent {@code context}.
+ * If {@code themeResId} is 0, the dialog will be inflated using the theme
+ * specified by the
+ * {@link android.R.attr#timePickerDialogTheme android:timePickerDialogTheme}
+ * attribute on the parent {@code context}'s theme.
*
* @param context the parent context
* @param themeResId the resource ID of the theme to apply to this dialog
@@ -109,11 +116,6 @@ public class TimePickerDialog extends AlertDialog implements OnClickListener,
mIs24HourView = is24HourView;
final Context themeContext = getContext();
-
-
- final TypedValue outValue = new TypedValue();
- context.getTheme().resolveAttribute(R.attr.timePickerDialogTheme, outValue, true);
-
final LayoutInflater inflater = LayoutInflater.from(themeContext);
final View view = inflater.inflate(R.layout.time_picker_dialog, null);
setView(view);
@@ -128,6 +130,15 @@ public class TimePickerDialog extends AlertDialog implements OnClickListener,
mTimePicker.setOnTimeChangedListener(this);
}
+ /**
+ * @return the time picker displayed in the dialog
+ * @hide For testing only.
+ */
+ @TestApi
+ public TimePicker getTimePicker() {
+ return mTimePicker;
+ }
+
@Override
public void onTimeChanged(TimePicker view, int hourOfDay, int minute) {
/* do nothing */
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 84457b44103048e4a586cd5a51cbb9963cbea79b..aa0eaaebf9758d3cb0c555eaa50659c430a5448a 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 {
@@ -1367,7 +1393,8 @@ public class WallpaperManager {
*/
@SystemApi
public void clearWallpaper() {
- clearWallpaper(FLAG_SYSTEM | FLAG_LOCK, mContext.getUserId());
+ clearWallpaper(FLAG_LOCK, mContext.getUserId());
+ clearWallpaper(FLAG_SYSTEM, mContext.getUserId());
}
/**
@@ -1399,12 +1426,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 +1696,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 325a15f1cb30f9d042bc1d56d667806455349724..a2f9bdd2370dcf883d6c8f450a1e26f3dc2a772c 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -416,6 +416,14 @@ public class DevicePolicyManager {
*/
public static final int NOTIFICATION_BUGREPORT_FINISHED_NOT_ACCEPTED = 3;
+ /**
+ * Default and maximum timeout in milliseconds after which unlocking with weak auth times out,
+ * i.e. the user has to use a strong authentication method like password, PIN or pattern.
+ *
+ * @hide
+ */
+ public static final long DEFAULT_STRONG_AUTH_TIMEOUT_MS = 72 * 60 * 60 * 1000; // 72h
+
/**
* A {@link android.os.Parcelable} extra of type {@link android.os.PersistableBundle} that
* allows a mobile device management application or NFC programmer application which starts
@@ -1275,6 +1283,33 @@ public class DevicePolicyManager {
*/
public static final int PASSWORD_QUALITY_MANAGED = 0x80000;
+ /**
+ * @hide
+ *
+ * adb shell dpm set-{device,profile}-owner will normally not allow installing an owner to
+ * a user with accounts. {@link #ACCOUNT_FEATURE_DEVICE_OR_PROFILE_OWNER_ALLOWED}
+ * and {@link #ACCOUNT_FEATURE_DEVICE_OR_PROFILE_OWNER_DISALLOWED} are the account features
+ * used by authenticator to exempt their accounts from this:
+ *
+ *
+ *
Non-test-only DO/PO still can't be installed when there are accounts.
+ *
In order to make an apk test-only, add android:testOnly="true" to the
+ * <application> tag in the manifest.
+ *
+ *
Test-only DO/PO can be installed even when there are accounts, as long as all the
+ * accounts have the {@link #ACCOUNT_FEATURE_DEVICE_OR_PROFILE_OWNER_ALLOWED} feature.
+ * Some authenticators claim to have any features, so to detect it, we also check
+ * {@link #ACCOUNT_FEATURE_DEVICE_OR_PROFILE_OWNER_DISALLOWED} and disallow installing
+ * if any of the accounts have it.
+ *
+ */
+ public static final String ACCOUNT_FEATURE_DEVICE_OR_PROFILE_OWNER_ALLOWED =
+ "android.account.DEVICE_OR_PROFILE_OWNER_ALLOWED";
+
+ /** @hide See {@link #ACCOUNT_FEATURE_DEVICE_OR_PROFILE_OWNER_ALLOWED} */
+ public static final String ACCOUNT_FEATURE_DEVICE_OR_PROFILE_OWNER_DISALLOWED =
+ "android.account.DEVICE_OR_PROFILE_OWNER_DISALLOWED";
+
/**
* Called by an application that is administering the device to set the password restrictions it
* is imposing. After setting this, the user will not be able to enter a new password that is
@@ -1315,7 +1350,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 +1414,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 +1477,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 +1546,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 +1615,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 +1683,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 +1751,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 +1818,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 +1950,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 +1974,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 +2156,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.
*
@@ -2219,6 +2254,7 @@ public class DevicePolicyManager {
* @throws SecurityException if the calling application does not own an active administrator
* that uses {@link DeviceAdminInfo#USES_POLICY_RESET_PASSWORD}
* @throws IllegalStateException if the calling user is locked or has a managed profile.
+ * @throws IllegalArgumentException if the password does not meet system requirements.
*/
public boolean resetPassword(String password, int flags) {
throwIfParentInstance("resetPassword");
@@ -2262,7 +2298,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
@@ -2307,6 +2343,83 @@ public class DevicePolicyManager {
return 0;
}
+ /**
+ * Called by a device/profile owner to set the timeout after which unlocking with secondary, non
+ * strong auth (e.g. fingerprint, trust agents) times out, i.e. the user has to use a strong
+ * authentication method like password, pin or pattern.
+ *
+ *
This timeout is used internally to reset the timer to require strong auth again after
+ * specified timeout each time it has been successfully used.
+ *
+ *
Fingerprint can also be disabled altogether using {@link #KEYGUARD_DISABLE_FINGERPRINT}.
+ *
+ *
Trust agents can also be disabled altogether using {@link #KEYGUARD_DISABLE_TRUST_AGENTS}.
+ *
+ *
The calling device admin must be a device or profile owner. If it is not,
+ * a {@link SecurityException} will be thrown.
+ *
+ *
The calling device admin can verify the value it has set by calling
+ * {@link #getRequiredStrongAuthTimeout(ComponentName)} and passing in its instance.
+ *
+ *
This method can be called on the {@link DevicePolicyManager} instance returned by
+ * {@link #getParentProfileInstance(ComponentName)} in order to set restrictions on the parent
+ * profile.
+ *
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+ * @param timeoutMs The new timeout, after which the user will have to unlock with strong
+ * authentication method. A value of 0 means the admin is not participating in
+ * controlling the timeout.
+ * The minimum and maximum timeouts are platform-defined and are typically 1 hour and
+ * 72 hours, respectively. Though discouraged, the admin may choose to require strong
+ * auth at all times using {@link #KEYGUARD_DISABLE_FINGERPRINT} and/or
+ * {@link #KEYGUARD_DISABLE_TRUST_AGENTS}.
+ *
+ * @throws SecurityException if {@code admin} is not a device or profile owner.
+ *
+ * @hide
+ */
+ public void setRequiredStrongAuthTimeout(@NonNull ComponentName admin,
+ long timeoutMs) {
+ if (mService != null) {
+ try {
+ mService.setRequiredStrongAuthTimeout(admin, timeoutMs, mParentInstance);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ }
+
+ /**
+ * Determine for how long the user will be able to use secondary, non strong auth for
+ * authentication, since last strong method authentication (password, pin or pattern) was used.
+ * After the returned timeout the user is required to use strong authentication method.
+ *
+ *
This method can be called on the {@link DevicePolicyManager} instance
+ * returned by {@link #getParentProfileInstance(ComponentName)} in order to retrieve
+ * restrictions on the parent profile.
+ *
+ * @param admin The name of the admin component to check, or {@code null} to aggregate
+ * accross all participating admins.
+ * @return The timeout or 0 if not configured for the provided admin.
+ *
+ * @hide
+ */
+ public long getRequiredStrongAuthTimeout(@Nullable ComponentName admin) {
+ return getRequiredStrongAuthTimeout(admin, myUserId());
+ }
+
+ /** @hide per-user version */
+ public long getRequiredStrongAuthTimeout(@Nullable ComponentName admin, @UserIdInt int userId) {
+ if (mService != null) {
+ try {
+ return mService.getRequiredStrongAuthTimeout(admin, userId, mParentInstance);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ return DEFAULT_STRONG_AUTH_TIMEOUT_MS;
+ }
+
/**
* Make the device lock immediately, as if the lock screen timeout has expired at the point of
* this call.
@@ -2510,6 +2623,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 +2637,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 +2768,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 +2776,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 +3461,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,9 +6536,77 @@ 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");
}
}
+
+ /**
+ * @hide
+ * Enable backup service.
+ *
This includes all backup and restore mechanisms.
+ * Setting this to {@code false} will make backup service no-op or return empty results.
+ *
+ *
There must be only one user on the device, managed by the device owner.
+ * Otherwise a {@link SecurityException} will be thrown.
+ *
+ *
Backup service is off by default when device owner is present.
+ */
+ public void setBackupServiceEnabled(@NonNull ComponentName admin, boolean enabled) {
+ try {
+ mService.setBackupServiceEnabled(admin, enabled);
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * @hide
+ * @return {@code true} if backup service is enabled, {@code false} otherwise.
+ */
+ public boolean isBackupServiceEnabled(@NonNull ComponentName admin) {
+ try {
+ return mService.isBackupServiceEnabled(admin);
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
}
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index ddec412e53c14dd935395f4b3f8d5a9a432279ab..f39cb5ae9fbd95e9198d1d626213857134b4309e 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -82,6 +82,9 @@ interface IDevicePolicyManager {
long getMaximumTimeToLock(in ComponentName who, int userHandle, boolean parent);
long getMaximumTimeToLockForUserAndProfiles(int userHandle);
+ void setRequiredStrongAuthTimeout(in ComponentName who, long timeMs, boolean parent);
+ long getRequiredStrongAuthTimeout(in ComponentName who, int userId, boolean parent);
+
void lockNow(boolean parent);
void wipeData(int flags);
@@ -301,4 +304,11 @@ interface IDevicePolicyManager {
boolean isUninstallInQueue(String packageName);
void uninstallPackageWithActiveAdmins(String packageName);
+
+ boolean isDeviceProvisioned();
+ boolean isDeviceProvisioningConfigApplied();
+ void setDeviceProvisioningConfigApplied();
+
+ void setBackupServiceEnabled(in ComponentName admin, boolean enabled);
+ boolean isBackupServiceEnabled(in ComponentName admin);
}
diff --git a/core/java/android/app/backup/BackupAgent.java b/core/java/android/app/backup/BackupAgent.java
index bc8280681e4a1ccd1db2d3cbb75dbd1991dec5ba..bad632555c4212ac7cbbe1735ef08458c33ed4da 100644
--- a/core/java/android/app/backup/BackupAgent.java
+++ b/core/java/android/app/backup/BackupAgent.java
@@ -35,6 +35,8 @@ import android.system.StructStat;
import android.util.ArraySet;
import android.util.Log;
+import libcore.io.IoUtils;
+
import org.xmlpull.v1.XmlPullParserException;
import java.io.File;
@@ -647,10 +649,11 @@ public abstract class BackupAgent extends ContextWrapper {
File file = scanQueue.remove(0);
String filePath;
try {
- // Ignore symlinks outright
+ // Ignore things that aren't "real" files or dirs
StructStat stat = Os.lstat(file.getPath());
- if (OsConstants.S_ISLNK(stat.st_mode)) {
- if (DEBUG) Log.i(TAG, "Symlink (skipping)!: " + file);
+ if (!OsConstants.S_ISREG(stat.st_mode)
+ && !OsConstants.S_ISDIR(stat.st_mode)) {
+ if (DEBUG) Log.i(TAG, "Not a file/dir (skipping)!: " + file);
continue;
}
@@ -921,6 +924,13 @@ public abstract class BackupAgent extends ContextWrapper {
} catch (RemoteException e) {
// we'll time out anyway, so we're safe
}
+
+ // Don't close the fd out from under the system service if this was local
+ if (Binder.getCallingPid() != Process.myPid()) {
+ IoUtils.closeQuietly(oldState);
+ IoUtils.closeQuietly(data);
+ IoUtils.closeQuietly(newState);
+ }
}
}
@@ -951,6 +961,11 @@ public abstract class BackupAgent extends ContextWrapper {
} catch (RemoteException e) {
// we'll time out anyway, so we're safe
}
+
+ if (Binder.getCallingPid() != Process.myPid()) {
+ IoUtils.closeQuietly(data);
+ IoUtils.closeQuietly(newState);
+ }
}
}
@@ -994,6 +1009,10 @@ public abstract class BackupAgent extends ContextWrapper {
} catch (RemoteException e) {
// we'll time out anyway, so we're safe
}
+
+ if (Binder.getCallingPid() != Process.myPid()) {
+ IoUtils.closeQuietly(data);
+ }
}
}
@@ -1041,6 +1060,10 @@ public abstract class BackupAgent extends ContextWrapper {
} catch (RemoteException e) {
// we'll time out anyway, so we're safe
}
+
+ if (Binder.getCallingPid() != Process.myPid()) {
+ IoUtils.closeQuietly(data);
+ }
}
}
diff --git a/core/java/android/app/backup/BackupManager.java b/core/java/android/app/backup/BackupManager.java
index 7fcca0969f75966d7c69bc1b180f51cd5989e876..80bc1364fa58755331d0f9681bb445b3d2d345eb 100644
--- a/core/java/android/app/backup/BackupManager.java
+++ b/core/java/android/app/backup/BackupManager.java
@@ -128,6 +128,14 @@ public class BackupManager {
@SystemApi
public static final int ERROR_AGENT_FAILURE = BackupTransport.AGENT_ERROR;
+ /**
+ * Intent extra when any subsidiary backup-related UI is launched from Settings: does
+ * device policy or configuration permit backup operations to run at all?
+ *
+ * @hide
+ */
+ public static final String EXTRA_BACKUP_SERVICES_AVAILABLE = "backup_services_available";
+
private Context mContext;
private static IBackupManager sService;
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/package.html b/core/java/android/app/package.html
index f37f1dcc8401df0acba9c925f3d7c54520e68f1c..b259cadc2bceb689e9317f14dd3057a2a902ebc4 100644
--- a/core/java/android/app/package.html
+++ b/core/java/android/app/package.html
@@ -34,7 +34,7 @@ action bar.
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 4271e3f99dff2d327e873da36d465fc280a0b785..d419d0384f5cd489d7c3069f974457a8711315ed 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -23,7 +23,6 @@ import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.annotation.SystemApi;
-import android.app.ActivityThread;
import android.bluetooth.le.BluetoothLeAdvertiser;
import android.bluetooth.le.BluetoothLeScanner;
import android.bluetooth.le.ScanCallback;
@@ -90,8 +89,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.
+ *
*
*
* {@see BluetoothDevice}
@@ -252,29 +254,6 @@ public final class BluetoothAdapter {
public static final String ACTION_REQUEST_ENABLE =
"android.bluetooth.adapter.action.REQUEST_ENABLE";
- /**
- * Activity Action: Show a system activity that allows the user to turn off
- * Bluetooth. This is used only if permission review is enabled which is for
- * apps targeting API less than 23 require a permission review before any of
- * the app's components can run.
- *
This system activity will return once Bluetooth has completed turning
- * off, or the user has decided not to turn Bluetooth off.
- *
Notification of the result of this activity is posted using the
- * {@link android.app.Activity#onActivityResult} callback. The
- * resultCode
- * will be {@link android.app.Activity#RESULT_OK} if Bluetooth has been
- * turned off or {@link android.app.Activity#RESULT_CANCELED} if the user
- * has rejected the request or an error has occurred.
- *
Applications can also listen for {@link #ACTION_STATE_CHANGED}
- * for global notification whenever Bluetooth is turned on or off.
- *
Requires {@link android.Manifest.permission#BLUETOOTH}
- *
- * @hide
- */
- @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
- public static final String ACTION_REQUEST_DISABLE =
- "android.bluetooth.adapter.action.REQUEST_DISABLE";
-
/**
* Activity Action: Show a system activity that allows user to enable BLE scans even when
* Bluetooth is turned off.
@@ -789,7 +768,7 @@ public final class BluetoothAdapter {
return true;
}
if (DBG) Log.d(TAG, "enableBLE(): Calling enable");
- return mManagerService.enable(ActivityThread.currentPackageName());
+ return mManagerService.enable();
} catch (RemoteException e) {
Log.e(TAG, "", e);
}
@@ -916,7 +895,7 @@ public final class BluetoothAdapter {
return true;
}
try {
- return mManagerService.enable(ActivityThread.currentPackageName());
+ return mManagerService.enable();
} catch (RemoteException e) {Log.e(TAG, "", e);}
return false;
}
@@ -948,7 +927,7 @@ public final class BluetoothAdapter {
@RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
public boolean disable() {
try {
- return mManagerService.disable(ActivityThread.currentPackageName(), true);
+ return mManagerService.disable(true);
} catch (RemoteException e) {Log.e(TAG, "", e);}
return false;
}
@@ -966,7 +945,7 @@ public final class BluetoothAdapter {
public boolean disable(boolean persist) {
try {
- return mManagerService.disable(ActivityThread.currentPackageName(), persist);
+ return mManagerService.disable(persist);
} catch (RemoteException e) {Log.e(TAG, "", e);}
return false;
}
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index ce54637d883364ed85815562ddb32af5995b2c2a..5c9e2ee4fc423cfded846e10d39646e5de7bbfca 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -59,8 +59,11 @@ import java.util.UUID;
*
*
*
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 BluetoothAdapter}
@@ -1172,12 +1175,12 @@ public final class BluetoothDevice implements Parcelable {
/**
* Confirm passkey for {@link #PAIRING_VARIANT_PASSKEY_CONFIRMATION} pairing.
- *
Requires {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED}.
*
* @return true confirmation has been sent out
* false for error
*/
- @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
+ @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
public boolean setPairingConfirmation(boolean confirm) {
if (sService == null) {
Log.e(TAG, "BT not enabled. Cannot set pairing confirmation");
@@ -1601,7 +1604,7 @@ public final class BluetoothDevice implements Parcelable {
// BLE is not supported
return null;
}
- BluetoothGatt gatt = new BluetoothGatt(context, iGatt, this, transport);
+ BluetoothGatt gatt = new BluetoothGatt(iGatt, this, transport);
gatt.connect(autoConnect, callback);
return gatt;
} catch (RemoteException e) {Log.e(TAG, "", e);}
diff --git a/core/java/android/bluetooth/BluetoothGatt.java b/core/java/android/bluetooth/BluetoothGatt.java
index f76d62d3c41945da0b337af87ca1717b60ba096b..97a32974d2ab4756b30b480bcb6ef8c89e47f8fe 100644
--- a/core/java/android/bluetooth/BluetoothGatt.java
+++ b/core/java/android/bluetooth/BluetoothGatt.java
@@ -41,7 +41,6 @@ public final class BluetoothGatt implements BluetoothProfile {
private static final boolean DBG = true;
private static final boolean VDBG = false;
- private final Context mContext;
private IBluetoothGatt mService;
private BluetoothGattCallback mCallback;
private int mClientIf;
@@ -503,9 +502,8 @@ public final class BluetoothGatt implements BluetoothProfile {
}
};
- /*package*/ BluetoothGatt(Context context, IBluetoothGatt iGatt, BluetoothDevice device,
+ /*package*/ BluetoothGatt(IBluetoothGatt iGatt, BluetoothDevice device,
int transport) {
- mContext = context;
mService = iGatt;
mDevice = device;
mTransport = transport;
diff --git a/core/java/android/bluetooth/BluetoothGattServer.java b/core/java/android/bluetooth/BluetoothGattServer.java
index c2bcbb2df6366a71a1468f12b87859407fe0fc7a..5ffceba5e11d7d746be35af42c609bd6e47a049b 100644
--- a/core/java/android/bluetooth/BluetoothGattServer.java
+++ b/core/java/android/bluetooth/BluetoothGattServer.java
@@ -44,7 +44,6 @@ public final class BluetoothGattServer implements BluetoothProfile {
private static final boolean DBG = true;
private static final boolean VDBG = false;
- private final Context mContext;
private BluetoothAdapter mAdapter;
private IBluetoothGatt mService;
private BluetoothGattServerCallback mCallback;
@@ -298,8 +297,7 @@ public final class BluetoothGattServer implements BluetoothProfile {
/**
* Create a BluetoothGattServer proxy object.
*/
- /*package*/ BluetoothGattServer(Context context, IBluetoothGatt iGatt, int transport) {
- mContext = context;
+ /*package*/ BluetoothGattServer(IBluetoothGatt iGatt, int transport) {
mService = iGatt;
mAdapter = BluetoothAdapter.getDefaultAdapter();
mCallback = null;
diff --git a/core/java/android/bluetooth/BluetoothHealthAppConfiguration.java b/core/java/android/bluetooth/BluetoothHealthAppConfiguration.java
index 15a9101452edd7bfc9f818b416a9552927da6573..1717a1e36e1f69dff73ebeb130a76cafee3ea107 100644
--- a/core/java/android/bluetooth/BluetoothHealthAppConfiguration.java
+++ b/core/java/android/bluetooth/BluetoothHealthAppConfiguration.java
@@ -68,7 +68,9 @@ public final class BluetoothHealthAppConfiguration implements Parcelable {
public boolean equals(Object o) {
if (o instanceof BluetoothHealthAppConfiguration) {
BluetoothHealthAppConfiguration config = (BluetoothHealthAppConfiguration) o;
- // config.getName() can never be NULL
+
+ if (mName == null) return false;
+
return mName.equals(config.getName()) &&
mDataType == config.getDataType() &&
mRole == config.getRole() &&
diff --git a/core/java/android/bluetooth/BluetoothManager.java b/core/java/android/bluetooth/BluetoothManager.java
index 35437a1fd7078a99ed39f6eb65fb1e123ec86939..29283e793ce931c15ccde9567a257d915e9f2341 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
@@ -233,7 +236,7 @@ public final class BluetoothManager {
Log.e(TAG, "Fail to get GATT Server connection");
return null;
}
- BluetoothGattServer mGattServer = new BluetoothGattServer(context, iGatt,transport);
+ BluetoothGattServer mGattServer = new BluetoothGattServer(iGatt,transport);
Boolean regStatus = mGattServer.registerCallback(callback);
return regStatus? mGattServer : null;
} catch (RemoteException e) {
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 1e99eceeecec22f9aae9ff0983176d8f62faa449..b68693880acfa6dc5c6423de981e6a3ac025276e 100644
--- a/core/java/android/bluetooth/BluetoothSocket.java
+++ b/core/java/android/bluetooth/BluetoothSocket.java
@@ -532,22 +532,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/IBluetoothManager.aidl b/core/java/android/bluetooth/IBluetoothManager.aidl
index f39ca8e0e9c865c581f99cb317cc3d82d50c4fa1..2b853a373b522ab47f0cffe750b369a5b1b39707 100644
--- a/core/java/android/bluetooth/IBluetoothManager.aidl
+++ b/core/java/android/bluetooth/IBluetoothManager.aidl
@@ -34,9 +34,10 @@ interface IBluetoothManager
void registerStateChangeCallback(in IBluetoothStateChangeCallback callback);
void unregisterStateChangeCallback(in IBluetoothStateChangeCallback callback);
boolean isEnabled();
- boolean enable(String packageName);
+ boolean enable();
boolean enableNoAutoConnect();
- boolean disable(String packageName, boolean persist);
+ boolean disable(boolean persist);
+ int getState();
IBluetoothGatt getBluetoothGatt();
boolean bindBluetoothProfileService(int profile, IBluetoothProfileServiceConnection proxy);
@@ -49,4 +50,3 @@ interface IBluetoothManager
int updateBleAppCount(IBinder b, boolean enable);
boolean isBleAppPresent();
}
-
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 c8d89204d8d4889b873b943597b9eb89e1e0cc3f..daa1b93889cccc0c7d2b7d6c8b070a2218e1177b 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;
@@ -1875,6 +1877,7 @@ public abstract class ContentResolver {
if (extras != null) {
String accountName = extras.getString(SYNC_EXTRAS_ACCOUNT);
if (!TextUtils.isEmpty(accountName)) {
+ // TODO: No references to Google in AOSP
account = new Account(accountName, "com.google");
}
extras.remove(SYNC_EXTRAS_ACCOUNT);
@@ -2693,4 +2696,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 b79c72e03141af2e74b2be94c4535a3b52486ad2..fd11031d5d7b5d1c17f6857f62f5472868e72a0d 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -1130,7 +1130,9 @@ public abstract class Context {
* Note: you should not rely on the system deleting these
* files for you; you should always have a reasonable maximum, such as 1 MB,
* for the amount of space you consume with cache files, and prune those
- * files when exceeding that space.
+ * files when exceeding that space. If your app requires a larger
+ * cache (larger than 1 MB), you should use {@link #getExternalCacheDir()}
+ * instead.
*
* The returned path may change over time if the calling app is moved to an
* adopted storage device, so only relative paths should be persisted.
@@ -1142,6 +1144,7 @@ public abstract class Context {
* @see #openFileOutput
* @see #getFileStreamPath
* @see #getDir
+ * @see #getExternalCacheDir
*/
public abstract File getCacheDir();
@@ -1190,7 +1193,7 @@ public abstract class Context {
*
*
* If a shared storage device is emulated (as determined by
- * {@link Environment#isExternalStorageEmulated(File)}), it's contents are
+ * {@link Environment#isExternalStorageEmulated(File)}), its contents are
* backed by a private user data partition, which means there is little
* benefit to storing data here instead of the private directory returned by
* {@link #getCacheDir()}.
@@ -2761,8 +2764,10 @@ public abstract class Context {
*
A {@link android.net.ConnectivityManager ConnectivityManager} for
* handling management of network connections.
*
{@link #WIFI_SERVICE} ("wifi")
- *
A {@link android.net.wifi.WifiManager WifiManager} for management of
- * Wi-Fi connectivity.
+ *
A {@link android.net.wifi.WifiManager WifiManager} for management of Wi-Fi
+ * connectivity. On releases before NYC, it should only be obtained from an application
+ * context, and not from any other derived context to avoid memory leaks within the calling
+ * process.
*
{@link #WIFI_P2P_SERVICE} ("wifip2p")
*
A {@link android.net.wifi.p2p.WifiP2pManager WifiP2pManager} for management of
* Wi-Fi Direct connectivity.
@@ -3615,12 +3620,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 ace54ba9ef43037c0b8e6c51ac0ee50fa31eb41d..c6aaa48ddad09b0fe0f1ff3759445bc94b9462a4 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -128,7 +128,7 @@ import static android.content.ContentProvider.maybeAddUserId;
* a list of people, which the user can browse through. This example is a
* typical top-level entry into the Contacts application, showing you the
* list of people. Selecting a particular person to view would result in a
- * new intent { {@link #ACTION_VIEW} content://contacts/N }
+ * new intent { {@link #ACTION_VIEW} content://contacts/people/N }
* being used to start an activity to display that person.
*
*
@@ -2218,6 +2218,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.
@@ -3173,6 +3189,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,
@@ -4289,6 +4313,14 @@ public class Intent implements Parcelable, Cloneable {
*/
public static final int FLAG_DEBUG_TRIAGED_MISSING = 0x00000100;
+ /**
+ * Internal flag used to indicate ephemeral applications should not be
+ * considered when resolving the intent.
+ *
+ * @hide
+ */
+ public static final int FLAG_IGNORE_EPHEMERAL = 0x00000200;
+
/**
* If set, the new activity is not kept in the history stack. As soon as
* the user navigates away from it, the activity is finished. This may also
@@ -6541,7 +6573,7 @@ public class Intent implements Parcelable, Cloneable {
*/
public void removeUnsafeExtras() {
if (mExtras != null) {
- mExtras.filterValues();
+ mExtras = mExtras.filterValues();
}
}
diff --git a/core/java/android/content/IntentFilter.java b/core/java/android/content/IntentFilter.java
index 22ab43bbb42921315f63d713e8ca92ead790a886..f5a79c8c13eb33dc3d1ee4e8efbbf69fa37463a4 100644
--- a/core/java/android/content/IntentFilter.java
+++ b/core/java/android/content/IntentFilter.java
@@ -124,7 +124,7 @@ import java.util.Set;
* Note that authority matching here is case sensitive, unlike
* formal RFC host names! You should thus always use lower case letters
* for your authority.
- *
+ *
*
Data Path matches if any of the given values match the
* Intent's data path and both a scheme and authority in the filter
* has matched against the Intent, or no paths were supplied in the
@@ -265,6 +265,7 @@ public class IntentFilter implements Parcelable {
public static final String SCHEME_HTTPS = "https";
private int mPriority;
+ private int mOrder;
private final ArrayList mActions;
private ArrayList mCategories = null;
private ArrayList mDataSchemes = null;
@@ -358,8 +359,8 @@ public class IntentFilter implements Parcelable {
* the {@link MalformedMimeTypeException} exception that the constructor
* can call and turns it into a runtime exception.
*
- * @param action The action to match, i.e. Intent.ACTION_VIEW.
- * @param dataType The type to match, i.e. "vnd.android.cursor.dir/person".
+ * @param action The action to match, such as Intent.ACTION_VIEW.
+ * @param dataType The type to match, such as "vnd.android.cursor.dir/person".
*
* @return A new IntentFilter for the given action and type.
*
@@ -386,7 +387,7 @@ public class IntentFilter implements Parcelable {
* no data characteristics are subsequently specified, then the
* filter will only match intents that contain no data.
*
- * @param action The action to match, i.e. Intent.ACTION_MAIN.
+ * @param action The action to match, such as Intent.ACTION_MAIN.
*/
public IntentFilter(String action) {
mPriority = 0;
@@ -406,8 +407,8 @@ public class IntentFilter implements Parcelable {
*
Throws {@link MalformedMimeTypeException} if the given MIME type is
* not syntactically correct.
*
- * @param action The action to match, i.e. Intent.ACTION_VIEW.
- * @param dataType The type to match, i.e. "vnd.android.cursor.dir/person".
+ * @param action The action to match, such as Intent.ACTION_VIEW.
+ * @param dataType The type to match, such as "vnd.android.cursor.dir/person".
*
*/
public IntentFilter(String action, String dataType)
@@ -425,6 +426,7 @@ public class IntentFilter implements Parcelable {
*/
public IntentFilter(IntentFilter o) {
mPriority = o.mPriority;
+ mOrder = o.mOrder;
mActions = new ArrayList(o.mActions);
if (o.mCategories != null) {
mCategories = new ArrayList(o.mCategories);
@@ -477,6 +479,16 @@ public class IntentFilter implements Parcelable {
return mPriority;
}
+ /** @hide */
+ public final void setOrder(int order) {
+ mOrder = order;
+ }
+
+ /** @hide */
+ public final int getOrder() {
+ return mOrder;
+ }
+
/**
* Set whether this filter will needs to be automatically verified against its data URIs or not.
* The default is false.
@@ -640,7 +652,7 @@ public class IntentFilter implements Parcelable {
* in the filter, then an Intent's action must be one of those values for
* it to match. If no actions are included, the Intent action is ignored.
*
- * @param action Name of the action to match, i.e. Intent.ACTION_VIEW.
+ * @param action Name of the action to match, such as Intent.ACTION_VIEW.
*/
public final void addAction(String action) {
if (!mActions.contains(action)) {
@@ -709,7 +721,7 @@ public class IntentFilter implements Parcelable {
*
Throws {@link MalformedMimeTypeException} if the given MIME type is
* not syntactically correct.
*
- * @param type Name of the data type to match, i.e. "vnd.android.cursor.dir/person".
+ * @param type Name of the data type to match, such as "vnd.android.cursor.dir/person".
*
* @see #matchData
*/
@@ -786,7 +798,7 @@ public class IntentFilter implements Parcelable {
* and any schemes you receive from outside of Android should be
* converted to lower case before supplying them here.
*
- * @param scheme Name of the scheme to match, i.e. "http".
+ * @param scheme Name of the scheme to match, such as "http".
*
* @see #matchData
*/
@@ -897,7 +909,7 @@ public class IntentFilter implements Parcelable {
* Determine whether this AuthorityEntry matches the given data Uri.
* Note that this comparison is case-sensitive, unlike formal
* RFC host names. You thus should always normalize to lower-case.
- *
+ *
* @param data The Uri to match.
* @return Returns either {@link IntentFilter#NO_MATCH_DATA},
* {@link IntentFilter#MATCH_CATEGORY_PORT}, or
@@ -1352,7 +1364,7 @@ public class IntentFilter implements Parcelable {
* filter has no impact on matching unless that category is specified in
* the intent.
*
- * @param category Name of category to match, i.e. Intent.CATEGORY_EMBED.
+ * @param category Name of category to match, such as Intent.CATEGORY_EMBED.
*/
public final void addCategory(String category) {
if (mCategories == null) mCategories = new ArrayList();
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/SyncAdapterType.java b/core/java/android/content/SyncAdapterType.java
index 8a16ac94522ebdd3b2bc0a58a1af58f48ed6a670..6ef7fd214069bf7d9858bb2203593839549a20b7 100644
--- a/core/java/android/content/SyncAdapterType.java
+++ b/core/java/android/content/SyncAdapterType.java
@@ -16,6 +16,7 @@
package android.content;
+import android.annotation.Nullable;
import android.text.TextUtils;
import android.os.Parcelable;
import android.os.Parcel;
@@ -33,6 +34,7 @@ public class SyncAdapterType implements Parcelable {
private final boolean isAlwaysSyncable;
private final boolean allowParallelSyncs;
private final String settingsActivity;
+ private final String packageName;
public SyncAdapterType(String authority, String accountType, boolean userVisible,
boolean supportsUploading) {
@@ -50,6 +52,7 @@ public class SyncAdapterType implements Parcelable {
this.allowParallelSyncs = false;
this.settingsActivity = null;
this.isKey = false;
+ this.packageName = null;
}
/** @hide */
@@ -57,7 +60,8 @@ public class SyncAdapterType implements Parcelable {
boolean supportsUploading,
boolean isAlwaysSyncable,
boolean allowParallelSyncs,
- String settingsActivity) {
+ String settingsActivity,
+ String packageName) {
if (TextUtils.isEmpty(authority)) {
throw new IllegalArgumentException("the authority must not be empty: " + authority);
}
@@ -72,6 +76,7 @@ public class SyncAdapterType implements Parcelable {
this.allowParallelSyncs = allowParallelSyncs;
this.settingsActivity = settingsActivity;
this.isKey = false;
+ this.packageName = packageName;
}
private SyncAdapterType(String authority, String accountType) {
@@ -89,6 +94,7 @@ public class SyncAdapterType implements Parcelable {
this.allowParallelSyncs = false;
this.settingsActivity = null;
this.isKey = true;
+ this.packageName = null;
}
public boolean supportsUploading() {
@@ -148,6 +154,16 @@ public class SyncAdapterType implements Parcelable {
return settingsActivity;
}
+ /**
+ * The package hosting the sync adapter.
+ * @return The package name.
+ *
+ * @hide
+ */
+ public @Nullable String getPackageName() {
+ return packageName;
+ }
+
public static SyncAdapterType newKey(String authority, String accountType) {
return new SyncAdapterType(authority, accountType);
}
@@ -181,6 +197,7 @@ public class SyncAdapterType implements Parcelable {
+ ", isAlwaysSyncable=" + isAlwaysSyncable
+ ", allowParallelSyncs=" + allowParallelSyncs
+ ", settingsActivity=" + settingsActivity
+ + ", packageName=" + packageName
+ "}";
}
}
@@ -201,6 +218,7 @@ public class SyncAdapterType implements Parcelable {
dest.writeInt(isAlwaysSyncable ? 1 : 0);
dest.writeInt(allowParallelSyncs ? 1 : 0);
dest.writeString(settingsActivity);
+ dest.writeString(packageName);
}
public SyncAdapterType(Parcel source) {
@@ -211,6 +229,7 @@ public class SyncAdapterType implements Parcelable {
source.readInt() != 0,
source.readInt() != 0,
source.readInt() != 0,
+ source.readString(),
source.readString());
}
diff --git a/core/java/android/content/SyncAdaptersCache.java b/core/java/android/content/SyncAdaptersCache.java
index 6704b75dff7f306634d0e8a2c515a7cc6bb6c1d5..ddbdb8a7a559b965dd63894065bd2dd51156a6c7 100644
--- a/core/java/android/content/SyncAdaptersCache.java
+++ b/core/java/android/content/SyncAdaptersCache.java
@@ -81,7 +81,7 @@ public class SyncAdaptersCache extends RegisteredServicesCache
sa.getString(com.android.internal.R.styleable
.SyncAdapter_settingsActivity);
return new SyncAdapterType(authority, accountType, userVisible, supportsUploading,
- isAlwaysSyncable, allowParallelSyncs, settingsActivity);
+ isAlwaysSyncable, allowParallelSyncs, settingsActivity, packageName);
} finally {
sa.recycle();
}
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/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 81229402e895be21a1514ed6aa2b174e9b4ce3c2..b0efd892558699dc5f19e5ee2f34af314d48381e 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 {}
@@ -2868,6 +2880,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
*/
@@ -3496,6 +3509,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
*/
@@ -5416,7 +5430,7 @@ public abstract class PackageManager {
* {@link #COMPONENT_ENABLED_STATE_DISABLED}, or
* {@link #COMPONENT_ENABLED_STATE_DEFAULT}. The last one means the
* application's enabled state is based on the original information in
- * the manifest as found in {@link ComponentInfo}.
+ * the manifest as found in {@link ApplicationInfo}.
* @throws IllegalArgumentException if the named package does not exist.
*/
public abstract int getApplicationEnabledSetting(String packageName);
diff --git a/core/java/android/content/pm/PackageManagerInternal.java b/core/java/android/content/pm/PackageManagerInternal.java
index 14f7727e61a02daaeb5ac9bbfd08789b35098812..f5bcf64417a666a9d7e2ec949ab486dbdd0c73d7 100644
--- a/core/java/android/content/pm/PackageManagerInternal.java
+++ b/core/java/android/content/pm/PackageManagerInternal.java
@@ -157,7 +157,15 @@ 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);
+
+ /**
+ * Gets whether the package was ever launched.
+ * @param packageName The package name.
+ * @param userId The user for which to check.
+ * @return Whether was launched.
+ */
+ public abstract boolean wasPackageEverLaunched(String packageName, int userId);
}
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index adf9fe62c37e529c78c342387e6b240d94133e05..2093124d5b8a644a98e91771c61db01517b4eb2b 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -270,6 +270,7 @@ public class PackageParser {
final int nameRes;
final int labelRes;
final int iconRes;
+ final int roundIconRes;
final int logoRes;
final int bannerRes;
@@ -277,7 +278,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;
@@ -285,6 +287,7 @@ public class PackageParser {
iconRes = _iconRes;
logoRes = _logoRes;
bannerRes = _bannerRes;
+ roundIconRes = _roundIconRes;
}
}
@@ -296,10 +299,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;
@@ -1871,7 +1876,7 @@ public class PackageParser {
sa = res.obtainAttributes(parser,
com.android.internal.R.styleable.AndroidManifestUsesSdk);
- int minVers = 0;
+ int minVers = 1;
String minCode = null;
int targetVers = 0;
String targetCode = null;
@@ -1898,9 +1903,6 @@ public class PackageParser {
} else {
// If it's not a string, it's an integer.
targetVers = val.data;
- if (minVers == 0) {
- minVers = targetVers;
- }
}
}
@@ -2288,11 +2290,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,
@@ -2506,12 +2504,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();
@@ -2552,10 +2550,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();
@@ -2621,10 +2620,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();
@@ -2671,6 +2671,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 = "";
@@ -2736,15 +2737,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(
@@ -2810,18 +2817,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(
@@ -3335,25 +3330,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);
@@ -3387,6 +3392,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,
@@ -3761,6 +3767,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,
@@ -3915,6 +3922,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,
@@ -4234,6 +4242,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,
@@ -4550,8 +4559,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);
@@ -5180,45 +5197,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 693228f4cd13193322d99ea96f69398f78dfcb03..aea843adbd4814cf8618b97972685402152bf087 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);
@@ -381,10 +424,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/ResolveInfo.java b/core/java/android/content/pm/ResolveInfo.java
index c9be6edab424c0e381cc6f7a4735f0da20abbfca..b5df4d75a2384a39aec1aefcda047fc6ebd654fa 100644
--- a/core/java/android/content/pm/ResolveInfo.java
+++ b/core/java/android/content/pm/ResolveInfo.java
@@ -67,12 +67,6 @@ public class ResolveInfo implements Parcelable {
*/
public EphemeralResolveInfo ephemeralResolveInfo;
- /**
- * A ResolveInfo that points at the ephemeral installer.
- * @hide
- */
- public ResolveInfo ephemeralInstaller;
-
/**
* The IntentFilter that was matched for this ResolveInfo.
*/
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..96ad67c6f3abae859d26ee549307474fb87edacb 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 the 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= fullLen) {
return attrs;
@@ -66,7 +70,7 @@ public class TypedArray {
private final Resources mResources;
private final DisplayMetrics mMetrics;
- private final AssetManager mAssets;
+ private AssetManager mAssets;
private boolean mRecycled;
@@ -1086,6 +1090,7 @@ public class TypedArray {
// These may have been set by the client.
mXml = null;
mTheme = null;
+ mAssets = null;
mResources.mTypedArrayPool.release(this);
}
diff --git a/core/java/android/database/CursorJoiner.java b/core/java/android/database/CursorJoiner.java
index e3c298893e806975fb253b90946515e0cf737cc5..a95263b67b433dde64d9eca98c4d09ec83c7b8ad 100644
--- a/core/java/android/database/CursorJoiner.java
+++ b/core/java/android/database/CursorJoiner.java
@@ -27,7 +27,7 @@ import java.util.Iterator;
*
*
* CursorJoiner joiner = new CursorJoiner(cursorA, keyColumnsofA, cursorB, keyColumnsofB);
- * for (CursorJointer.Result joinerResult : joiner) {
+ * for (CursorJoiner.Result joinerResult : joiner) {
* switch (joinerResult) {
* case LEFT:
* // handle case where a row in cursorA is unique
diff --git a/core/java/android/database/sqlite/SQLiteDatabase.java b/core/java/android/database/sqlite/SQLiteDatabase.java
index 0f64b921a07993779b6e278938204e56d51218eb..8e178320d66d5126f4a6f60126be417aeb6675d0 100644
--- a/core/java/android/database/sqlite/SQLiteDatabase.java
+++ b/core/java/android/database/sqlite/SQLiteDatabase.java
@@ -1371,6 +1371,7 @@ public final class SQLiteDatabase extends SQLiteClosable {
/**
* Convenience method for replacing a row in the database.
+ * Inserts a new row if a row does not already exist.
*
* @param table the table in which to replace the row
* @param nullColumnHack optional; may be null.
@@ -1381,7 +1382,7 @@ public final class SQLiteDatabase extends SQLiteClosable {
* provides the name of nullable column name to explicitly insert a NULL into
* in the case where your initialValues is empty.
* @param initialValues this map contains the initial column values for
- * the row.
+ * the row. The keys should be the column names and the values the column values.
* @return the row ID of the newly inserted row, or -1 if an error occurred
*/
public long replace(String table, String nullColumnHack, ContentValues initialValues) {
@@ -1396,6 +1397,7 @@ public final class SQLiteDatabase extends SQLiteClosable {
/**
* Convenience method for replacing a row in the database.
+ * Inserts a new row if a row does not already exist.
*
* @param table the table in which to replace the row
* @param nullColumnHack optional; may be null.
@@ -1406,7 +1408,7 @@ public final class SQLiteDatabase extends SQLiteClosable {
* provides the name of nullable column name to explicitly insert a NULL into
* in the case where your initialValues is empty.
* @param initialValues this map contains the initial column values for
- * the row. The key
+ * the row. The keys should be the column names and the values the column values.
* @throws SQLException
* @return the row ID of the newly inserted row, or -1 if an error occurred
*/
@@ -1740,7 +1742,7 @@ public final class SQLiteDatabase extends SQLiteClosable {
* Returns true if the new version code is greater than the current database version.
*
* @param newVersion The new version code.
- * @return True if the new version code is greater than the current database version.
+ * @return True if the new version code is greater than the current database version.
*/
public boolean needUpgrade(int newVersion) {
return newVersion > getVersion();
diff --git a/core/java/android/database/sqlite/package.html b/core/java/android/database/sqlite/package.html
index ceed171ce48c269f5bcf9fd284be0a2e49df4461..864a9bb32702ea2e438f05d3727fa53bcffc49ac 100644
--- a/core/java/android/database/sqlite/package.html
+++ b/core/java/android/database/sqlite/package.html
@@ -6,15 +6,44 @@ classes that an application would use to manage its own private database.
Applications use these classes to manage private databases. If creating a
content provider, you will probably have to use these classes to create and
manage your own database to store content. See Content Providers to learn
-the conventions for implementing a content provider. See the
-NotePadProvider class in the NotePad sample application in the SDK for an
-example of a content provider. Android ships with SQLite version 3.4.0
-
If you are working with data sent to you by a provider, you will not use
-these SQLite classes, but instead use the generic {@link android.database}
-classes.
-
Android ships with the sqlite3 database tool in the tools/
-folder. You can use this tool to browse or run SQL commands on the device. Run by
-typing sqlite3 in a shell window.
+href="{@docRoot}guide/topics/providers/content-providers.html">Content Providers
+to learn the conventions for implementing a content provider. If you are working
+with data sent to you by a provider, you do not use these SQLite classes, but
+instead use the generic {@link android.database} classes.
+
+
The Android SDK and Android emulators both include the
+sqlite3 command-line
+database tool. On your development machine, run the tool from the
+platform-tools/ folder of your SDK. On the emulator, run the tool
+with adb shell, for example, adb -e shell sqlite3.
+
+
The version of SQLite depends on the version of Android. See the following table:
+
+
Android API
SQLite Version
+
API 24
3.9
+
API 21
3.8
+
API 11
3.7
+
API 8
3.6
+
API 3
3.5
+
API 1
3.4
+
+
+
Some device manufacturers include different versions of SQLite on their devices.
+ There are two ways to programmatically determine the version number.
+
+
+
If available, use the sqlite3 tool, for example:
+ adb -e shell sqlite3 --version.
+
Create and query an in-memory database as shown in the following code sample:
+