summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--api/current.txt23
-rw-r--r--api/system-current.txt22
-rw-r--r--cmds/app_process/Android.mk8
-rw-r--r--cmds/uiautomator/library/core-src/com/android/uiautomator/core/AccessibilityNodeInfoHelper.java7
-rw-r--r--cmds/uiautomator/library/core-src/com/android/uiautomator/core/UiObject.java8
-rw-r--r--core/java/android/app/ActivityManagerNative.java10
-rw-r--r--core/java/android/app/ActivityThread.java16
-rw-r--r--core/java/android/app/AssistContent.java44
-rw-r--r--core/java/android/app/AssistStructure.java10
-rw-r--r--core/java/android/app/IActivityManager.java3
-rw-r--r--core/java/android/content/Intent.java5
-rw-r--r--core/java/android/hardware/SensorEvent.java4
-rw-r--r--core/java/android/hardware/SensorManager.java59
-rw-r--r--core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java1
-rw-r--r--core/java/android/inputmethodservice/InputMethodService.java35
-rw-r--r--core/java/android/os/BatteryStats.java42
-rw-r--r--core/java/android/os/Build.java12
-rw-r--r--core/java/android/os/RecoverySystem.java14
-rw-r--r--core/java/android/service/notification/ZenModeConfig.java143
-rw-r--r--core/java/android/service/voice/IVoiceInteractionSession.aidl4
-rw-r--r--core/java/android/service/voice/VoiceInteractionSession.java38
-rw-r--r--core/java/android/text/Layout.java1
-rw-r--r--core/java/android/text/TextLine.java10
-rw-r--r--core/java/android/view/inputmethod/InputMethodManager.java16
-rw-r--r--core/java/android/widget/Editor.java11
-rw-r--r--core/java/android/widget/ScrollView.java44
-rw-r--r--core/java/android/widget/TextView.java4
-rw-r--r--core/jni/Android.mk3
-rwxr-xr-xcore/jni/android/graphics/Bitmap.cpp31
-rw-r--r--core/jni/android/graphics/Bitmap.h1
-rw-r--r--core/jni/android_media_AudioRecord.cpp1
-rw-r--r--core/jni/android_media_AudioTrack.cpp1
-rw-r--r--core/res/AndroidManifest.xml13
-rw-r--r--core/res/res/values/strings.xml9
-rwxr-xr-xcore/res/res/values/symbols.xml2
-rw-r--r--core/res/res/values/themes_material.xml22
-rw-r--r--core/res/res/values/themes_micro.xml17
-rw-r--r--docs/html-ndk/ndk/guides/abis.jd2
-rw-r--r--docs/html-ndk/ndk/guides/android_mk.jd9
-rw-r--r--docs/html-ndk/ndk/guides/index.jd10
-rw-r--r--docs/html-ndk/ndk/guides/ndk-build.jd6
-rw-r--r--docs/html-ndk/ndk/guides/prebuilts.jd2
-rw-r--r--docs/html-ndk/ndk/guides/standalone_toolchain.jd2
-rw-r--r--docs/html/distribute/googleplay/work/about.jd2
-rw-r--r--docs/html/distribute/index.jd4
-rw-r--r--docs/html/distribute/users/app-invites.jd2
-rw-r--r--docs/html/distribute/users/house-ads.jd2
-rw-r--r--docs/html/distribute/users/index.jd6
-rw-r--r--docs/html/images/cards/card-app-invites_16-9_2x.pngbin0 -> 11769 bytes
-rw-r--r--docs/html/images/cards/card-app-linking_2x.pngbin0 -> 82867 bytes
-rw-r--r--docs/html/images/cards/card-auto-backup_2x.pngbin0 -> 86310 bytes
-rw-r--r--docs/html/images/cards/card-test-performance_2x.pngbin0 -> 99188 bytes
-rw-r--r--docs/html/images/permissions_check.pngbin63920 -> 31042 bytes
-rw-r--r--docs/html/jd_collections.js18
-rw-r--r--docs/html/preview/api-changes.jd338
-rw-r--r--docs/html/preview/api-overview.jd4
-rw-r--r--docs/html/preview/backup/index.jd2
-rw-r--r--docs/html/preview/behavior-changes.jd4
-rw-r--r--docs/html/preview/data-binding/guide.jd908
-rw-r--r--docs/html/preview/download.jd15
-rw-r--r--docs/html/preview/features/app-linking.jd4
-rw-r--r--docs/html/preview/index.jd33
-rw-r--r--docs/html/preview/overview.jd25
-rw-r--r--docs/html/preview/preview_toc.cs2
-rw-r--r--docs/html/preview/samples.jd1
-rw-r--r--docs/html/preview/setup-sdk.jd8
-rw-r--r--docs/html/preview/testing/guide.jd14
-rw-r--r--docs/html/preview/testing/performance.jd16
-rw-r--r--docs/html/tools/data-binding/guide.jd42
-rw-r--r--docs/html/tools/data-binding/index.jd18
-rw-r--r--docs/html/training/training_toc.cs18
-rw-r--r--docs/html/training/tv/index.jd3
-rw-r--r--graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java273
-rw-r--r--graphics/java/android/graphics/drawable/ClipDrawable.java17
-rw-r--r--graphics/java/android/graphics/drawable/DrawableWrapper.java13
-rw-r--r--libs/hwui/CanvasState.cpp3
-rw-r--r--libs/hwui/CanvasState.h1
-rw-r--r--libs/hwui/DeferredDisplayList.cpp1
-rw-r--r--libs/hwui/DeferredDisplayList.h1
-rw-r--r--libs/hwui/Matrix.h6
-rw-r--r--libs/hwui/OpenGLRenderer.cpp46
-rwxr-xr-xlibs/hwui/OpenGLRenderer.h1
-rw-r--r--libs/hwui/PathTessellator.cpp62
-rw-r--r--libs/hwui/PathTessellator.h2
-rw-r--r--libs/hwui/RenderNode.cpp34
-rw-r--r--libs/hwui/ShadowTessellator.cpp65
-rw-r--r--libs/hwui/ShadowTessellator.h17
-rw-r--r--libs/hwui/Snapshot.cpp42
-rw-r--r--libs/hwui/Snapshot.h27
-rw-r--r--libs/hwui/TessellationCache.cpp17
-rw-r--r--libs/hwui/utils/MathUtils.h15
-rw-r--r--location/java/android/location/CountryDetector.java2
-rw-r--r--media/java/android/media/AudioTrack.java17
-rw-r--r--media/jni/Android.mk2
-rw-r--r--media/jni/soundpool/Android.mk2
-rw-r--r--media/jni/soundpool/SoundPool.cpp1
-rw-r--r--media/tests/audiotests/Android.mk2
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java29
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java63
-rw-r--r--services/core/java/com/android/server/location/LocationBasedCountryDetector.java40
-rw-r--r--services/core/java/com/android/server/notification/ConditionProviders.java8
-rw-r--r--services/core/java/com/android/server/notification/NotificationManagerService.java189
-rw-r--r--services/core/java/com/android/server/notification/RankingHelper.java84
-rw-r--r--services/core/java/com/android/server/notification/ZenLog.java7
-rw-r--r--services/core/java/com/android/server/notification/ZenModeConditions.java13
-rw-r--r--services/core/java/com/android/server/notification/ZenModeHelper.java58
-rw-r--r--services/core/java/com/android/server/power/PowerManagerService.java13
-rw-r--r--services/core/java/com/android/server/power/ShutdownThread.java157
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java12
-rw-r--r--services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java45
-rw-r--r--telecomm/java/android/telecom/Call.java23
-rw-r--r--telecomm/java/android/telecom/Conference.java25
-rw-r--r--telecomm/java/android/telecom/Connection.java26
-rw-r--r--telecomm/java/android/telecom/ConnectionService.java24
-rw-r--r--telecomm/java/android/telecom/ConnectionServiceAdapter.java17
-rw-r--r--telecomm/java/android/telecom/ConnectionServiceAdapterServant.java18
-rw-r--r--telecomm/java/android/telecom/ParcelableCall.java21
-rw-r--r--telecomm/java/android/telecom/ParcelableConference.java14
-rw-r--r--telecomm/java/android/telecom/ParcelableConnection.java21
-rw-r--r--telecomm/java/android/telecom/RemoteConference.java28
-rw-r--r--telecomm/java/android/telecom/RemoteConnection.java37
-rw-r--r--telecomm/java/android/telecom/RemoteConnectionService.java12
-rw-r--r--telecomm/java/android/telecom/TelecomManager.java2
-rw-r--r--telecomm/java/com/android/internal/telecom/IConnectionServiceAdapter.aidl3
-rw-r--r--telephony/java/android/telephony/CarrierConfigManager.java3
-rw-r--r--telephony/java/android/telephony/PhoneNumberUtils.java8
-rw-r--r--telephony/java/android/telephony/TelephonyManager.java18
-rw-r--r--telephony/java/com/android/internal/telephony/ITelephony.aidl8
-rw-r--r--tests/Compatibility/src/com/android/compatibilitytest/AppCompatibility.java3
-rw-r--r--tests/HwAccelerationTest/AndroidManifest.xml18
-rw-r--r--tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java38
-rw-r--r--tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java122
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java3
136 files changed, 2080 insertions, 2020 deletions
diff --git a/api/current.txt b/api/current.txt
index 348ebf9..39444bc 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -106,7 +106,7 @@ package android {
field public static final deprecated java.lang.String READ_INPUT_STATE = "android.permission.READ_INPUT_STATE";
field public static final java.lang.String READ_LOGS = "android.permission.READ_LOGS";
field public static final java.lang.String READ_PHONE_STATE = "android.permission.READ_PHONE_STATE";
- field public static final java.lang.String READ_PROFILE = "android.permission.READ_PROFILE";
+ field public static final deprecated java.lang.String READ_PROFILE = "android.permission.READ_PROFILE";
field public static final java.lang.String READ_SMS = "android.permission.READ_SMS";
field public static final deprecated java.lang.String READ_SOCIAL_STREAM = "android.permission.READ_SOCIAL_STREAM";
field public static final java.lang.String READ_SYNC_SETTINGS = "android.permission.READ_SYNC_SETTINGS";
@@ -120,6 +120,7 @@ package android {
field public static final java.lang.String RECEIVE_WAP_PUSH = "android.permission.RECEIVE_WAP_PUSH";
field public static final java.lang.String RECORD_AUDIO = "android.permission.RECORD_AUDIO";
field public static final java.lang.String REORDER_TASKS = "android.permission.REORDER_TASKS";
+ field public static final java.lang.String REQUEST_INSTALL_PACKAGES = "android.permission.REQUEST_INSTALL_PACKAGES";
field public static final deprecated java.lang.String RESTART_PACKAGES = "android.permission.RESTART_PACKAGES";
field public static final java.lang.String SEND_RESPOND_VIA_MESSAGE = "android.permission.SEND_RESPOND_VIA_MESSAGE";
field public static final java.lang.String SEND_SMS = "android.permission.SEND_SMS";
@@ -154,7 +155,7 @@ package android {
field public static final java.lang.String WRITE_EXTERNAL_STORAGE = "android.permission.WRITE_EXTERNAL_STORAGE";
field public static final java.lang.String WRITE_GSERVICES = "android.permission.WRITE_GSERVICES";
field public static final java.lang.String WRITE_HISTORY_BOOKMARKS = "com.android.browser.permission.WRITE_HISTORY_BOOKMARKS";
- field public static final java.lang.String WRITE_PROFILE = "android.permission.WRITE_PROFILE";
+ field public static final deprecated java.lang.String WRITE_PROFILE = "android.permission.WRITE_PROFILE";
field public static final java.lang.String WRITE_SECURE_SETTINGS = "android.permission.WRITE_SECURE_SETTINGS";
field public static final java.lang.String WRITE_SETTINGS = "android.permission.WRITE_SETTINGS";
field public static final deprecated java.lang.String WRITE_SOCIAL_STREAM = "android.permission.WRITE_SOCIAL_STREAM";
@@ -3996,24 +3997,22 @@ package android.app {
public class AssistContent implements android.os.Parcelable {
ctor public AssistContent();
method public int describeContents();
- method public static android.app.AssistContent getAssistContent(android.os.Bundle);
method public android.content.ClipData getClipData();
method public android.content.Intent getIntent();
+ method public android.net.Uri getWebUri();
method public void setClipData(android.content.ClipData);
method public void setIntent(android.content.Intent);
+ method public void setWebUri(android.net.Uri);
method public void writeToParcel(android.os.Parcel, int);
- field public static final java.lang.String ASSIST_KEY = "android:assist_content";
field public static final android.os.Parcelable.Creator<android.app.AssistContent> CREATOR;
}
public final class AssistStructure implements android.os.Parcelable {
method public int describeContents();
method public android.content.ComponentName getActivityComponent();
- method public static android.app.AssistStructure getAssistStructure(android.os.Bundle);
method public android.app.AssistStructure.WindowNode getWindowNodeAt(int);
method public int getWindowNodeCount();
method public void writeToParcel(android.os.Parcel, int);
- field public static final java.lang.String ASSIST_KEY = "android:assist_structure";
field public static final android.os.Parcelable.Creator<android.app.AssistStructure> CREATOR;
}
@@ -28915,7 +28914,7 @@ package android.service.voice {
method public android.view.View onCreateContentView();
method public void onDestroy();
method public boolean[] onGetSupportedCommands(android.service.voice.VoiceInteractionSession.Caller, java.lang.String[]);
- method public void onHandleAssist(android.os.Bundle);
+ method public void onHandleAssist(android.os.Bundle, android.app.AssistStructure, android.app.AssistContent);
method public void onHide();
method public boolean onKeyDown(int, android.view.KeyEvent);
method public boolean onKeyLongPress(int, android.view.KeyEvent);
@@ -30003,6 +30002,7 @@ package android.telecom {
method public android.telecom.GatewayInfo getGatewayInfo();
method public android.net.Uri getHandle();
method public int getHandlePresentation();
+ method public android.os.Bundle getIntentExtras();
method public android.telecom.StatusHints getStatusHints();
method public int getVideoState();
method public static boolean hasProperty(int, int);
@@ -30057,6 +30057,7 @@ package android.telecom {
method public final long getConnectionTime();
method public final java.util.List<android.telecom.Connection> getConnections();
method public final android.telecom.DisconnectCause getDisconnectCause();
+ method public final android.os.Bundle getExtras();
method public final android.telecom.PhoneAccountHandle getPhoneAccountHandle();
method public final int getState();
method public final android.telecom.StatusHints getStatusHints();
@@ -30079,6 +30080,7 @@ package android.telecom {
method public final void setConnectionCapabilities(int);
method public final void setConnectionTime(long);
method public final void setDisconnected(android.telecom.DisconnectCause);
+ method public final void setExtras(android.os.Bundle);
method public final void setOnHold();
method public final void setStatusHints(android.telecom.StatusHints);
method public final void setVideoProvider(android.telecom.Connection, android.telecom.Connection.VideoProvider);
@@ -30105,6 +30107,7 @@ package android.telecom {
method public final java.util.List<android.telecom.Conferenceable> getConferenceables();
method public final int getConnectionCapabilities();
method public final android.telecom.DisconnectCause getDisconnectCause();
+ method public final android.os.Bundle getExtras();
method public final int getState();
method public final android.telecom.StatusHints getStatusHints();
method public final android.telecom.Connection.VideoProvider getVideoProvider();
@@ -30132,6 +30135,7 @@ package android.telecom {
method public final void setConnectionService(android.telecom.ConnectionService);
method public final void setDialing();
method public final void setDisconnected(android.telecom.DisconnectCause);
+ method public final void setExtras(android.os.Bundle);
method public final void setInitialized();
method public final void setInitializing();
method public final void setNextPostDialChar(char);
@@ -30372,6 +30376,7 @@ package android.telecom {
method public final int getConnectionCapabilities();
method public final java.util.List<android.telecom.RemoteConnection> getConnections();
method public android.telecom.DisconnectCause getDisconnectCause();
+ method public final android.os.Bundle getExtras();
method public final int getState();
method public void hold();
method public void merge();
@@ -30394,6 +30399,7 @@ package android.telecom {
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);
+ method public void onExtrasChanged(android.telecom.RemoteConference, android.os.Bundle);
method public void onStateChanged(android.telecom.RemoteConference, int, int);
}
@@ -30409,6 +30415,7 @@ package android.telecom {
method public java.util.List<android.telecom.RemoteConnection> getConferenceableConnections();
method public int getConnectionCapabilities();
method public android.telecom.DisconnectCause getDisconnectCause();
+ method public final android.os.Bundle getExtras();
method public int getState();
method public android.telecom.StatusHints getStatusHints();
method public void hold();
@@ -30434,6 +30441,7 @@ package android.telecom {
method public void onConnectionCapabilitiesChanged(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);
method public void onPostDialChar(android.telecom.RemoteConnection, char);
method public void onPostDialWait(android.telecom.RemoteConnection, java.lang.String);
method public void onRingbackRequested(android.telecom.RemoteConnection, boolean);
@@ -30474,6 +30482,7 @@ package android.telecom {
method public void unregisterPhoneAccount(android.telecom.PhoneAccountHandle);
field public static final java.lang.String ACTION_CHANGE_DEFAULT_DIALER = "android.telecom.action.CHANGE_DEFAULT_DIALER";
field public static final java.lang.String ACTION_CHANGE_PHONE_ACCOUNTS = "android.telecom.action.CHANGE_PHONE_ACCOUNTS";
+ field public static final java.lang.String ACTION_CONNECTION_SERVICE_CONFIGURE = "android.telecom.action.CONNECTION_SERVICE_CONFIGURE";
field public static final java.lang.String ACTION_INCOMING_CALL = "android.telecom.action.INCOMING_CALL";
field public static final java.lang.String ACTION_SHOW_CALL_ACCESSIBILITY_SETTINGS = "android.telecom.action.SHOW_CALL_ACCESSIBILITY_SETTINGS";
field public static final java.lang.String ACTION_SHOW_CALL_SETTINGS = "android.telecom.action.SHOW_CALL_SETTINGS";
diff --git a/api/system-current.txt b/api/system-current.txt
index 4c44ce0..d75a9a0 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -155,7 +155,7 @@ package android {
field public static final java.lang.String READ_NETWORK_USAGE_HISTORY = "android.permission.READ_NETWORK_USAGE_HISTORY";
field public static final java.lang.String READ_PHONE_STATE = "android.permission.READ_PHONE_STATE";
field public static final java.lang.String READ_PRIVILEGED_PHONE_STATE = "android.permission.READ_PRIVILEGED_PHONE_STATE";
- field public static final java.lang.String READ_PROFILE = "android.permission.READ_PROFILE";
+ field public static final deprecated java.lang.String READ_PROFILE = "android.permission.READ_PROFILE";
field public static final java.lang.String READ_SEARCH_INDEXABLES = "android.permission.READ_SEARCH_INDEXABLES";
field public static final java.lang.String READ_SMS = "android.permission.READ_SMS";
field public static final deprecated java.lang.String READ_SOCIAL_STREAM = "android.permission.READ_SOCIAL_STREAM";
@@ -180,6 +180,7 @@ package android {
field public static final java.lang.String REGISTER_SIM_SUBSCRIPTION = "android.permission.REGISTER_SIM_SUBSCRIPTION";
field public static final java.lang.String REMOVE_DRM_CERTIFICATES = "android.permission.REMOVE_DRM_CERTIFICATES";
field public static final java.lang.String REORDER_TASKS = "android.permission.REORDER_TASKS";
+ field public static final java.lang.String REQUEST_INSTALL_PACKAGES = "android.permission.REQUEST_INSTALL_PACKAGES";
field public static final deprecated java.lang.String RESTART_PACKAGES = "android.permission.RESTART_PACKAGES";
field public static final java.lang.String RETRIEVE_WINDOW_CONTENT = "android.permission.RETRIEVE_WINDOW_CONTENT";
field public static final java.lang.String SCORE_NETWORKS = "android.permission.SCORE_NETWORKS";
@@ -227,7 +228,7 @@ package android {
field public static final java.lang.String WRITE_GSERVICES = "android.permission.WRITE_GSERVICES";
field public static final java.lang.String WRITE_HISTORY_BOOKMARKS = "com.android.browser.permission.WRITE_HISTORY_BOOKMARKS";
field public static final java.lang.String WRITE_MEDIA_STORAGE = "android.permission.WRITE_MEDIA_STORAGE";
- field public static final java.lang.String WRITE_PROFILE = "android.permission.WRITE_PROFILE";
+ field public static final deprecated java.lang.String WRITE_PROFILE = "android.permission.WRITE_PROFILE";
field public static final java.lang.String WRITE_SECURE_SETTINGS = "android.permission.WRITE_SECURE_SETTINGS";
field public static final java.lang.String WRITE_SETTINGS = "android.permission.WRITE_SETTINGS";
field public static final deprecated java.lang.String WRITE_SOCIAL_STREAM = "android.permission.WRITE_SOCIAL_STREAM";
@@ -4091,24 +4092,22 @@ package android.app {
public class AssistContent implements android.os.Parcelable {
ctor public AssistContent();
method public int describeContents();
- method public static android.app.AssistContent getAssistContent(android.os.Bundle);
method public android.content.ClipData getClipData();
method public android.content.Intent getIntent();
+ method public android.net.Uri getWebUri();
method public void setClipData(android.content.ClipData);
method public void setIntent(android.content.Intent);
+ method public void setWebUri(android.net.Uri);
method public void writeToParcel(android.os.Parcel, int);
- field public static final java.lang.String ASSIST_KEY = "android:assist_content";
field public static final android.os.Parcelable.Creator<android.app.AssistContent> CREATOR;
}
public final class AssistStructure implements android.os.Parcelable {
method public int describeContents();
method public android.content.ComponentName getActivityComponent();
- method public static android.app.AssistStructure getAssistStructure(android.os.Bundle);
method public android.app.AssistStructure.WindowNode getWindowNodeAt(int);
method public int getWindowNodeCount();
method public void writeToParcel(android.os.Parcel, int);
- field public static final java.lang.String ASSIST_KEY = "android:assist_structure";
field public static final android.os.Parcelable.Creator<android.app.AssistStructure> CREATOR;
}
@@ -31041,7 +31040,7 @@ package android.service.voice {
method public android.view.View onCreateContentView();
method public void onDestroy();
method public boolean[] onGetSupportedCommands(android.service.voice.VoiceInteractionSession.Caller, java.lang.String[]);
- method public void onHandleAssist(android.os.Bundle);
+ method public void onHandleAssist(android.os.Bundle, android.app.AssistStructure, android.app.AssistContent);
method public void onHide();
method public boolean onKeyDown(int, android.view.KeyEvent);
method public boolean onKeyLongPress(int, android.view.KeyEvent);
@@ -32150,6 +32149,7 @@ package android.telecom {
method public android.telecom.GatewayInfo getGatewayInfo();
method public android.net.Uri getHandle();
method public int getHandlePresentation();
+ method public android.os.Bundle getIntentExtras();
method public android.telecom.StatusHints getStatusHints();
method public int getVideoState();
method public static boolean hasProperty(int, int);
@@ -32210,6 +32210,7 @@ package android.telecom {
method public final long getConnectionTime();
method public final java.util.List<android.telecom.Connection> getConnections();
method public final android.telecom.DisconnectCause getDisconnectCause();
+ method public final android.os.Bundle getExtras();
method public final android.telecom.PhoneAccountHandle getPhoneAccountHandle();
method public android.telecom.Connection getPrimaryConnection();
method public final int getState();
@@ -32235,6 +32236,7 @@ package android.telecom {
method public final void setConnectionCapabilities(int);
method public final void setConnectionTime(long);
method public final void setDisconnected(android.telecom.DisconnectCause);
+ method public final void setExtras(android.os.Bundle);
method public final void setOnHold();
method public final void setStatusHints(android.telecom.StatusHints);
method public final void setVideoProvider(android.telecom.Connection, android.telecom.Connection.VideoProvider);
@@ -32262,6 +32264,7 @@ package android.telecom {
method public final java.util.List<android.telecom.Conferenceable> getConferenceables();
method public final int getConnectionCapabilities();
method public final android.telecom.DisconnectCause getDisconnectCause();
+ method public final android.os.Bundle getExtras();
method public final int getState();
method public final android.telecom.StatusHints getStatusHints();
method public final android.telecom.Connection.VideoProvider getVideoProvider();
@@ -32290,6 +32293,7 @@ package android.telecom {
method public final void setConnectionService(android.telecom.ConnectionService);
method public final void setDialing();
method public final void setDisconnected(android.telecom.DisconnectCause);
+ method public final void setExtras(android.os.Bundle);
method public final void setInitialized();
method public final void setInitializing();
method public final void setNextPostDialChar(char);
@@ -32555,6 +32559,7 @@ package android.telecom {
method public final int getConnectionCapabilities();
method public final java.util.List<android.telecom.RemoteConnection> getConnections();
method public android.telecom.DisconnectCause getDisconnectCause();
+ method public final android.os.Bundle getExtras();
method public final int getState();
method public void hold();
method public void merge();
@@ -32578,6 +32583,7 @@ package android.telecom {
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);
+ method public void onExtrasChanged(android.telecom.RemoteConference, android.os.Bundle);
method public void onStateChanged(android.telecom.RemoteConference, int, int);
}
@@ -32593,6 +32599,7 @@ package android.telecom {
method public java.util.List<android.telecom.RemoteConnection> getConferenceableConnections();
method public int getConnectionCapabilities();
method public android.telecom.DisconnectCause getDisconnectCause();
+ method public final android.os.Bundle getExtras();
method public int getState();
method public android.telecom.StatusHints getStatusHints();
method public void hold();
@@ -32619,6 +32626,7 @@ package android.telecom {
method public void onConnectionCapabilitiesChanged(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);
method public void onPostDialChar(android.telecom.RemoteConnection, char);
method public void onPostDialWait(android.telecom.RemoteConnection, java.lang.String);
method public void onRingbackRequested(android.telecom.RemoteConnection, boolean);
diff --git a/cmds/app_process/Android.mk b/cmds/app_process/Android.mk
index ce6d7b5..3599695 100644
--- a/cmds/app_process/Android.mk
+++ b/cmds/app_process/Android.mk
@@ -52,11 +52,13 @@ LOCAL_LDFLAGS := -ldl -Wl,--version-script,art/sigchainlib/version-script.txt -W
LOCAL_CPPFLAGS := -std=c++11
LOCAL_MODULE := app_process__asan
-LOCAL_MODULE_TAGS := eng
-LOCAL_MODULE_PATH := $(TARGET_OUT_EXECUTABLES)/asan
-LOCAL_MODULE_STEM := app_process
+LOCAL_MULTILIB := both
+LOCAL_MODULE_STEM_32 := app_process32
+LOCAL_MODULE_STEM_64 := app_process64
+
LOCAL_ADDRESS_SANITIZER := true
LOCAL_CLANG := true
+LOCAL_MODULE_PATH := $(TARGET_OUT_EXECUTABLES)/asan
LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code
diff --git a/cmds/uiautomator/library/core-src/com/android/uiautomator/core/AccessibilityNodeInfoHelper.java b/cmds/uiautomator/library/core-src/com/android/uiautomator/core/AccessibilityNodeInfoHelper.java
index 54835e3..de2fec0 100644
--- a/cmds/uiautomator/library/core-src/com/android/uiautomator/core/AccessibilityNodeInfoHelper.java
+++ b/cmds/uiautomator/library/core-src/com/android/uiautomator/core/AccessibilityNodeInfoHelper.java
@@ -46,7 +46,10 @@ class AccessibilityNodeInfoHelper {
displayRect.right = width;
displayRect.bottom = height;
- nodeRect.intersect(displayRect);
- return nodeRect;
+ if (nodeRect.intersect(displayRect)) {
+ return nodeRect;
+ } else {
+ return new Rect();
+ }
}
}
diff --git a/cmds/uiautomator/library/core-src/com/android/uiautomator/core/UiObject.java b/cmds/uiautomator/library/core-src/com/android/uiautomator/core/UiObject.java
index 4bb99cd..2118da8 100644
--- a/cmds/uiautomator/library/core-src/com/android/uiautomator/core/UiObject.java
+++ b/cmds/uiautomator/library/core-src/com/android/uiautomator/core/UiObject.java
@@ -353,8 +353,12 @@ public class UiObject {
Rect parentRect = AccessibilityNodeInfoHelper
.getVisibleBoundsInScreen(scrollableParentNode, w, h);
// adjust for partial clipping of targeted by parent node if required
- nodeRect.intersect(parentRect);
- return nodeRect;
+ if (nodeRect.intersect(parentRect)) {
+ return nodeRect;
+ } else {
+ // Node rect has no intersection with parent Rect
+ return new Rect();
+ }
}
/**
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 02e0d5b..e4def1e 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -2193,7 +2193,9 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
data.enforceInterface(IActivityManager.descriptor);
IBinder token = data.readStrongBinder();
Bundle extras = data.readBundle();
- reportAssistContextExtras(token, extras);
+ AssistStructure structure = AssistStructure.CREATOR.createFromParcel(data);
+ AssistContent content = AssistContent.CREATOR.createFromParcel(data);
+ reportAssistContextExtras(token, extras, structure, content);
reply.writeNoException();
return true;
}
@@ -5359,13 +5361,15 @@ class ActivityManagerProxy implements IActivityManager
reply.recycle();
}
- public void reportAssistContextExtras(IBinder token, Bundle extras)
- throws RemoteException {
+ public void reportAssistContextExtras(IBinder token, Bundle extras, AssistStructure structure,
+ AssistContent content) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeStrongBinder(token);
data.writeBundle(extras);
+ structure.writeToParcel(data, 0);
+ content.writeToParcel(data, 0);
mRemote.transact(REPORT_ASSIST_CONTEXT_EXTRAS_TRANSACTION, data, reply, 0);
reply.readException();
data.recycle();
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index cb436b5..2a98b6c 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -2562,15 +2562,18 @@ public final class ActivityThread {
public void handleRequestAssistContextExtras(RequestAssistContextExtras cmd) {
Bundle data = new Bundle();
+ AssistStructure structure = null;
+ AssistContent content = new AssistContent();
ActivityClientRecord r = mActivities.get(cmd.activityToken);
if (r != null) {
r.activity.getApplication().dispatchOnProvideAssistData(r.activity, data);
r.activity.onProvideAssistData(data);
if (cmd.requestType == ActivityManager.ASSIST_CONTEXT_FULL) {
- data.putParcelable(AssistStructure.ASSIST_KEY, new AssistStructure(r.activity));
- AssistContent content = new AssistContent();
+ structure = new AssistStructure(r.activity);
Intent activityIntent = r.activity.getIntent();
- if (activityIntent != null) {
+ if (activityIntent != null && (r.window == null ||
+ (r.window.getAttributes().flags
+ & WindowManager.LayoutParams.FLAG_SECURE) == 0)) {
Intent intent = new Intent(activityIntent);
intent.setFlags(intent.getFlags() & ~(Intent.FLAG_GRANT_WRITE_URI_PERMISSION
| Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION));
@@ -2580,15 +2583,14 @@ public final class ActivityThread {
content.setIntent(new Intent());
}
r.activity.onProvideAssistContent(content);
- data.putParcelable(AssistContent.ASSIST_KEY, content);
}
}
- if (data.isEmpty()) {
- data = null;
+ if (structure == null) {
+ structure = new AssistStructure();
}
IActivityManager mgr = ActivityManagerNative.getDefault();
try {
- mgr.reportAssistContextExtras(cmd.requestToken, data);
+ mgr.reportAssistContextExtras(cmd.requestToken, data, structure, content);
} catch (RemoteException e) {
}
}
diff --git a/core/java/android/app/AssistContent.java b/core/java/android/app/AssistContent.java
index cb1a3f5..f271af1 100644
--- a/core/java/android/app/AssistContent.java
+++ b/core/java/android/app/AssistContent.java
@@ -18,6 +18,7 @@ package android.app;
import android.content.ClipData;
import android.content.Intent;
+import android.net.Uri;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
@@ -30,14 +31,17 @@ import android.os.Parcelable;
public class AssistContent implements Parcelable {
private Intent mIntent;
private ClipData mClipData;
+ private Uri mUri;
/**
+ * @hide
* Key name this data structure is stored in the Bundle generated by
* {@link Activity#onProvideAssistData}.
*/
public static final String ASSIST_KEY = "android:assist_content";
/**
+ * @hide
* Retrieve the framework-generated AssistContent that is stored within
* the Bundle filled in by {@link Activity#onProvideAssistContent}.
*/
@@ -56,6 +60,13 @@ public class AssistContent implements Parcelable {
*/
public void setIntent(Intent intent) {
mIntent = intent;
+ setWebUri(null);
+ if (intent != null && Intent.ACTION_VIEW.equals(intent.getAction())) {
+ Uri uri = intent.getData();
+ if ("http".equals(uri.getScheme()) || "https".equals(uri.getScheme())) {
+ setWebUri(uri);
+ }
+ }
}
/**
@@ -81,6 +92,30 @@ public class AssistContent implements Parcelable {
return mClipData;
}
+ /**
+ * Set a web URI associated with the current data being shown to the user.
+ * This URI could be opened in a web browser, or in the app as an
+ * {@link Intent#ACTION_VIEW} Intent, to show the same data that is currently
+ * being displayed by it. The URI here should be something that is transportable
+ * off the device into other environments to acesss the same data as is currently
+ * being shown in the app; if the app does not have such a representation, it should
+ * leave the null and only report the local intent and clip data.
+ *
+ * <p>This will be automatically populated for you from {@link #setIntent} if that Intent
+ * is an {@link Intent#ACTION_VIEW} of a web (http or https scheme) URI.</p>
+ */
+ public void setWebUri(Uri uri) {
+ mUri = uri;
+ }
+
+ /**
+ * Return the content's web URI as per {@link #setWebUri(android.net.Uri)}, or null if
+ * there is none.
+ */
+ public Uri getWebUri() {
+ return mUri;
+ }
+
AssistContent(Parcel in) {
if (in.readInt() != 0) {
mIntent = Intent.CREATOR.createFromParcel(in);
@@ -88,6 +123,9 @@ public class AssistContent implements Parcelable {
if (in.readInt() != 0) {
mClipData = ClipData.CREATOR.createFromParcel(in);
}
+ if (in.readInt() != 0) {
+ mUri = Uri.CREATOR.createFromParcel(in);
+ }
}
@Override
@@ -109,6 +147,12 @@ public class AssistContent implements Parcelable {
} else {
dest.writeInt(0);
}
+ if (mUri != null) {
+ dest.writeInt(1);
+ mUri.writeToParcel(dest, flags);
+ } else {
+ dest.writeInt(0);
+ }
}
public static final Parcelable.Creator<AssistContent> CREATOR
diff --git a/core/java/android/app/AssistStructure.java b/core/java/android/app/AssistStructure.java
index b703b0e..bb9cb3b 100644
--- a/core/java/android/app/AssistStructure.java
+++ b/core/java/android/app/AssistStructure.java
@@ -42,13 +42,13 @@ import java.util.ArrayList;
/**
* Assist data automatically created by the platform's implementation
- * of {@link Activity#onProvideAssistData}. Retrieve it from the assist
- * data with {@link #getAssistStructure(android.os.Bundle)}.
+ * of {@link Activity#onProvideAssistData}.
*/
final public class AssistStructure implements Parcelable {
static final String TAG = "AssistStructure";
/**
+ * @hide
* Key name this data structure is stored in the Bundle generated by
* {@link Activity#onProvideAssistData}.
*/
@@ -741,6 +741,11 @@ final public class AssistStructure implements Parcelable {
}
}
+ AssistStructure() {
+ mHaveData = true;
+ mActivityComponent = null;
+ }
+
AssistStructure(Parcel in) {
mReceiveChannel = in.readStrongBinder();
}
@@ -811,6 +816,7 @@ final public class AssistStructure implements Parcelable {
}
/**
+ * @hide
* Retrieve the framework-generated AssistStructure that is stored within
* the Bundle filled in by {@link Activity#onProvideAssistData}.
*/
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index c42719b..0a425ae 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -433,7 +433,8 @@ public interface IActivityManager extends IInterface {
public void requestAssistContextExtras(int requestType, IResultReceiver receiver)
throws RemoteException;
- public void reportAssistContextExtras(IBinder token, Bundle extras) throws RemoteException;
+ public void reportAssistContextExtras(IBinder token, Bundle extras,
+ AssistStructure structure, AssistContent content) throws RemoteException;
public boolean launchAssistIntent(Intent intent, int requestType, String hint, int userHandle)
throws RemoteException;
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 62a1617..c01ce4f 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1387,6 +1387,11 @@ public class Intent implements Parcelable, Cloneable {
* <p>
* Output: If {@link #EXTRA_RETURN_RESULT}, returns whether the install
* succeeded.
+ * <p>
+ * <strong>Note:</strong>If your app is targeting API level higher than 22 you
+ * need to hold {@link android.Manifest.permission#REQUEST_INSTALL_PACKAGES}
+ * in order to launch the application installer.
+ * </p>
*
* @see #EXTRA_INSTALLER_PACKAGE_NAME
* @see #EXTRA_NOT_UNKNOWN_SOURCE
diff --git a/core/java/android/hardware/SensorEvent.java b/core/java/android/hardware/SensorEvent.java
index 2bc0f9b..906c2a1 100644
--- a/core/java/android/hardware/SensorEvent.java
+++ b/core/java/android/hardware/SensorEvent.java
@@ -312,7 +312,7 @@ public class SensorEvent {
* </p>
*
* <p>
- * values[2]: Roll, rotation around the x-axis (-90 to 90)
+ * values[2]: Roll, rotation around the y-axis (-90 to 90)
* increasing as the device moves clockwise.
* </p>
* </ul>
@@ -325,6 +325,8 @@ public class SensorEvent {
*
* <p>
* <b>Note:</b> This sensor type exists for legacy reasons, please use
+ * {@link android.hardware.Sensor#TYPE_ROTATION_VECTOR
+ * rotation vector sensor type} and
* {@link android.hardware.SensorManager#getRotationMatrix
* getRotationMatrix()} in conjunction with
* {@link android.hardware.SensorManager#remapCoordinateSystem
diff --git a/core/java/android/hardware/SensorManager.java b/core/java/android/hardware/SensorManager.java
index 861969e..fda889f 100644
--- a/core/java/android/hardware/SensorManager.java
+++ b/core/java/android/hardware/SensorManager.java
@@ -967,8 +967,9 @@ public abstract class SensorManager {
* TYPE_MAGNETIC_FIELD}.
*
* @return <code>true</code> on success, <code>false</code> on failure (for
- * instance, if the device is in free fall). On failure the output
- * matrices are not modified.
+ * instance, if the device is in free fall). Free fall is defined as
+ * condition when the magnitude of the gravity is less than 1/10 of
+ * the nominal value. On failure the output matrices are not modified.
*
* @see #getInclination(float[])
* @see #getOrientation(float[], float[])
@@ -981,6 +982,15 @@ public abstract class SensorManager {
float Ax = gravity[0];
float Ay = gravity[1];
float Az = gravity[2];
+
+ final float normsqA = (Ax*Ax + Ay*Ay + Az*Az);
+ final float g = 9.81f;
+ final float freeFallGravitySquared = 0.01f * g * g;
+ if (normsqA < freeFallGravitySquared) {
+ // gravity less than 10% of normal value
+ return false;
+ }
+
final float Ex = geomagnetic[0];
final float Ey = geomagnetic[1];
final float Ez = geomagnetic[2];
@@ -988,6 +998,7 @@ public abstract class SensorManager {
float Hy = Ez*Ax - Ex*Az;
float Hz = Ex*Ay - Ey*Ax;
final float normH = (float)Math.sqrt(Hx*Hx + Hy*Hy + Hz*Hz);
+
if (normH < 0.1f) {
// device is close to free fall (or in space?), or close to
// magnetic north pole. Typical values are > 100.
@@ -1117,12 +1128,12 @@ public abstract class SensorManager {
* returned by {@link #getRotationMatrix}.
*
* @param X
- * defines on which world axis and direction the X axis of the device
- * is mapped.
+ * defines the axis of the new cooridinate system that coincide with the X axis of the
+ * original coordinate system.
*
* @param Y
- * defines on which world axis and direction the Y axis of the device
- * is mapped.
+ * defines the axis of the new cooridinate system that coincide with the Y axis of the
+ * original coordinate system.
*
* @param outR
* the transformed rotation matrix. inR and outR should not be the same
@@ -1219,27 +1230,18 @@ public abstract class SensorManager {
* <p>
* When it returns, the array values is filled with the result:
* <ul>
- * <li>values[0]: <i>azimuth</i>, rotation around the Z axis.</li>
- * <li>values[1]: <i>pitch</i>, rotation around the X axis.</li>
+ * <li>values[0]: <i>azimuth</i>, rotation around the -Z axis,
+ * i.e. the opposite direction of Z axis.</li>
+ * <li>values[1]: <i>pitch</i>, rotation around the -X axis,
+ * i.e the opposite direction of X axis.</li>
* <li>values[2]: <i>roll</i>, rotation around the Y axis.</li>
* </ul>
- * <p>The reference coordinate-system used is different from the world
- * coordinate-system defined for the rotation matrix:</p>
- * <ul>
- * <li>X is defined as the vector product <b>Y.Z</b> (It is tangential to
- * the ground at the device's current location and roughly points West).</li>
- * <li>Y is tangential to the ground at the device's current location and
- * points towards the magnetic North Pole.</li>
- * <li>Z points towards the center of the Earth and is perpendicular to the ground.</li>
- * </ul>
- *
- * <p>
- * <center><img src="../../../images/axis_globe_inverted.png"
- * alt="Inverted world coordinate-system diagram." border="0" /></center>
- * </p>
* <p>
+ * Applying these three intrinsic rotations in azimuth, pitch and roll order transforms
+ * identity matrix to the rotation matrix given in input R.
* All three angles above are in <b>radians</b> and <b>positive</b> in the
- * <b>counter-clockwise</b> direction.
+ * <b>counter-clockwise</b> direction. Range of output is: azimuth from -&pi; to &pi;,
+ * pitch from -&pi;/2 to &pi;/2 and roll from -&pi; to &pi;.
*
* @param R
* rotation matrix see {@link #getRotationMatrix}.
@@ -1275,6 +1277,7 @@ public abstract class SensorManager {
values[1] = (float)Math.asin(-R[9]);
values[2] = (float)Math.atan2(-R[8], R[10]);
}
+
return values;
}
@@ -1314,9 +1317,9 @@ public abstract class SensorManager {
/** Helper function to compute the angle change between two rotation matrices.
* Given a current rotation matrix (R) and a previous rotation matrix
- * (prevR) computes the rotation around the z,x, and y axes which
+ * (prevR) computes the intrinsic rotation around the z, x, and y axes which
* transforms prevR to R.
- * outputs a 3 element vector containing the z,x, and y angle
+ * outputs a 3 element vector containing the z, x, and y angle
* change at indexes 0, 1, and 2 respectively.
* <p> Each input matrix is either as a 3x3 or 4x4 row-major matrix
* depending on the length of the passed array:
@@ -1333,9 +1336,13 @@ public abstract class SensorManager {
* | R[ 8] R[ 9] R[10] R[11] |
* \ R[12] R[13] R[14] R[15] /
*</pre>
+ *
+ * See {@link #getOrientation} for more detailed definition of the output.
+ *
* @param R current rotation matrix
* @param prevR previous rotation matrix
- * @param angleChange an an array of floats (z, x, and y) in which the angle change is stored
+ * @param angleChange an an array of floats (z, x, and y) in which the angle change
+ * (in radians) is stored
*/
public static void getAngleChange( float[] angleChange, float[] R, float[] prevR) {
diff --git a/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java b/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java
index 8776418..2de846c 100644
--- a/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java
+++ b/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java
@@ -754,6 +754,7 @@ public class LegacyMetadataMapper {
CameraCharacteristics.CONTROL_AE_COMPENSATION_STEP ,
CameraCharacteristics.CONTROL_AF_AVAILABLE_MODES ,
CameraCharacteristics.CONTROL_AVAILABLE_EFFECTS ,
+ CameraCharacteristics.CONTROL_AVAILABLE_MODES ,
CameraCharacteristics.CONTROL_AVAILABLE_SCENE_MODES ,
CameraCharacteristics.CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES ,
CameraCharacteristics.CONTROL_AWB_AVAILABLE_MODES ,
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 1b57055..81a65f8 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -306,6 +306,14 @@ public class InputMethodService extends AbstractInputMethodService {
int mStatusIcon;
int mBackDisposition;
+ /**
+ * {@code true} when the previous IME had non-empty inset at the bottom of the screen and we
+ * have not shown our own window yet. In this situation, the previous inset continues to be
+ * shown as an empty region until it is explicitly updated. Basically we can trigger the update
+ * by calling 1) {@code mWindow.show()} or 2) {@link #clearInsetOfPreviousIme()}.
+ */
+ boolean mShouldClearInsetOfPreviousIme;
+
final Insets mTmpInsets = new Insets();
final int[] mTmpLocation = new int[2];
@@ -408,6 +416,7 @@ public class InputMethodService extends AbstractInputMethodService {
mShowInputRequested = false;
mShowInputForced = false;
doHideWindow();
+ clearInsetOfPreviousIme();
if (resultReceiver != null) {
resultReceiver.send(wasVis != isInputViewShown()
? InputMethodManager.RESULT_HIDDEN
@@ -432,6 +441,7 @@ public class InputMethodService extends AbstractInputMethodService {
mWindowAdded = false;
}
}
+ clearInsetOfPreviousIme();
// If user uses hard keyboard, IME button should always be shown.
boolean showing = isInputViewShown();
mImm.setImeWindowStatus(mToken, IME_ACTIVE | (showing ? IME_VISIBLE : 0),
@@ -669,6 +679,9 @@ public class InputMethodService extends AbstractInputMethodService {
super.setTheme(mTheme);
super.onCreate();
mImm = (InputMethodManager)getSystemService(INPUT_METHOD_SERVICE);
+ // If the previous IME has occupied non-empty inset in the screen, we need to decide whether
+ // we continue to use the same size of the inset or update it
+ mShouldClearInsetOfPreviousIme = (mImm.getInputMethodWindowVisibleHeight() > 0);
mInflater = (LayoutInflater)getSystemService(
Context.LAYOUT_INFLATER_SERVICE);
mWindow = new SoftInputWindow(this, "InputMethod", mTheme, null, null, mDispatcherState,
@@ -1494,6 +1507,9 @@ public class InputMethodService extends AbstractInputMethodService {
if (DEBUG) Log.v(TAG, "showWindow: showing!");
onWindowShown();
mWindow.show();
+ // Put here rather than in onWindowShown() in case people forget to call
+ // super.onWindowShown().
+ mShouldClearInsetOfPreviousIme = false;
}
}
@@ -1540,7 +1556,23 @@ public class InputMethodService extends AbstractInputMethodService {
public void onWindowHidden() {
// Intentionally empty
}
-
+
+ /**
+ * Reset the inset occupied the previous IME when and only when
+ * {@link #mShouldClearInsetOfPreviousIme} is {@code true}.
+ */
+ private void clearInsetOfPreviousIme() {
+ if (DEBUG) Log.v(TAG, "clearInsetOfPreviousIme() "
+ + " mShouldClearInsetOfPreviousIme=" + mShouldClearInsetOfPreviousIme);
+ if (!mShouldClearInsetOfPreviousIme || mWindow == null) return;
+ // We do not call onWindowShown() and onWindowHidden() so as not to make the IME author
+ // confused.
+ // TODO: Find out a better way which has less side-effect.
+ mWindow.show();
+ mWindow.hide();
+ mShouldClearInsetOfPreviousIme = false;
+ }
+
/**
* Called when a new client has bound to the input method. This
* may be followed by a series of {@link #onStartInput(EditorInfo, boolean)}
@@ -2428,5 +2460,6 @@ public class InputMethodService extends AbstractInputMethodService {
+ " visibleTopInsets=" + mTmpInsets.visibleTopInsets
+ " touchableInsets=" + mTmpInsets.touchableInsets
+ " touchableRegion=" + mTmpInsets.touchableRegion);
+ p.println(" mShouldClearInsetOfPreviousIme=" + mShouldClearInsetOfPreviousIme);
}
}
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 5f515eb..56e919a 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -3282,12 +3282,13 @@ public abstract class BatteryStats implements Parcelable {
final long wifiIdleTimeMs = getWifiControllerActivity(CONTROLLER_IDLE_TIME, which);
final long wifiRxTimeMs = getWifiControllerActivity(CONTROLLER_RX_TIME, which);
final long wifiTxTimeMs = getWifiControllerActivity(CONTROLLER_TX_TIME, which);
+ final long wifiPowerDrainMaMs = getWifiControllerActivity(CONTROLLER_POWER_DRAIN, which);
final long wifiTotalTimeMs = wifiIdleTimeMs + wifiRxTimeMs + wifiTxTimeMs;
sb.setLength(0);
sb.append(prefix);
sb.append(" WiFi Idle time: "); formatTimeMs(sb, wifiIdleTimeMs);
- sb.append(" (");
+ sb.append("(");
sb.append(formatRatioLocked(wifiIdleTimeMs, wifiTotalTimeMs));
sb.append(")");
pw.println(sb.toString());
@@ -3295,7 +3296,7 @@ public abstract class BatteryStats implements Parcelable {
sb.setLength(0);
sb.append(prefix);
sb.append(" WiFi Rx time: "); formatTimeMs(sb, wifiRxTimeMs);
- sb.append(" (");
+ sb.append("(");
sb.append(formatRatioLocked(wifiRxTimeMs, wifiTotalTimeMs));
sb.append(")");
pw.println(sb.toString());
@@ -3303,16 +3304,16 @@ public abstract class BatteryStats implements Parcelable {
sb.setLength(0);
sb.append(prefix);
sb.append(" WiFi Tx time: "); formatTimeMs(sb, wifiTxTimeMs);
- sb.append(" (");
+ sb.append("(");
sb.append(formatRatioLocked(wifiTxTimeMs, wifiTotalTimeMs));
sb.append(")");
pw.println(sb.toString());
sb.setLength(0);
sb.append(prefix);
- sb.append(" WiFi Power drain: ").append(BatteryStatsHelper.makemAh(
- getWifiControllerActivity(CONTROLLER_POWER_DRAIN, which) / (double)(1000*60*60)));
- sb.append(" mAh");
+ sb.append(" WiFi Power drain: ").append(
+ BatteryStatsHelper.makemAh(wifiPowerDrainMaMs / (double) (1000*60*60)));
+ sb.append("mAh");
pw.println(sb.toString());
final long bluetoothIdleTimeMs =
@@ -3325,7 +3326,7 @@ public abstract class BatteryStats implements Parcelable {
sb.setLength(0);
sb.append(prefix);
sb.append(" Bluetooth Idle time: "); formatTimeMs(sb, bluetoothIdleTimeMs);
- sb.append(" (");
+ sb.append("(");
sb.append(formatRatioLocked(bluetoothIdleTimeMs, bluetoothTotalTimeMs));
sb.append(")");
pw.println(sb.toString());
@@ -3333,7 +3334,7 @@ public abstract class BatteryStats implements Parcelable {
sb.setLength(0);
sb.append(prefix);
sb.append(" Bluetooth Rx time: "); formatTimeMs(sb, bluetoothRxTimeMs);
- sb.append(" (");
+ sb.append("(");
sb.append(formatRatioLocked(bluetoothRxTimeMs, bluetoothTotalTimeMs));
sb.append(")");
pw.println(sb.toString());
@@ -3341,7 +3342,7 @@ public abstract class BatteryStats implements Parcelable {
sb.setLength(0);
sb.append(prefix);
sb.append(" Bluetooth Tx time: "); formatTimeMs(sb, bluetoothTxTimeMs);
- sb.append(" (");
+ sb.append("(");
sb.append(formatRatioLocked(bluetoothTxTimeMs, bluetoothTotalTimeMs));
sb.append(")");
pw.println(sb.toString());
@@ -3351,7 +3352,7 @@ public abstract class BatteryStats implements Parcelable {
sb.append(" Bluetooth Power drain: ").append(BatteryStatsHelper.makemAh(
getBluetoothControllerActivity(CONTROLLER_POWER_DRAIN, which) /
(double)(1000*60*60)));
- sb.append(" mAh");
+ sb.append("mAh");
pw.println(sb.toString());
pw.println();
@@ -3656,6 +3657,27 @@ public abstract class BatteryStats implements Parcelable {
pw.println(sb.toString());
}
+ final long uidWifiIdleTimeMs = u.getWifiControllerActivity(CONTROLLER_IDLE_TIME, which);
+ final long uidWifiRxTimeMs = u.getWifiControllerActivity(CONTROLLER_RX_TIME, which);
+ final long uidWifiTxTimeMs = u.getWifiControllerActivity(CONTROLLER_TX_TIME, which);
+ final long uidWifiTotalTimeMs = uidWifiIdleTimeMs + uidWifiRxTimeMs + uidWifiTxTimeMs;
+ if (uidWifiTotalTimeMs > 0) {
+ sb.setLength(0);
+ sb.append(prefix).append(" WiFi Idle time: ");
+ formatTimeMs(sb, uidWifiIdleTimeMs);
+ sb.append("(").append(formatRatioLocked(uidWifiIdleTimeMs, uidWifiTotalTimeMs))
+ .append(")\n");
+
+ sb.append(prefix).append(" WiFi Rx time: "); formatTimeMs(sb, uidWifiRxTimeMs);
+ sb.append("(").append(formatRatioLocked(uidWifiRxTimeMs, uidWifiTotalTimeMs))
+ .append(")\n");
+
+ sb.append(prefix).append(" WiFi Tx time: "); formatTimeMs(sb, uidWifiTxTimeMs);
+ sb.append("(").append(formatRatioLocked(uidWifiTxTimeMs, uidWifiTotalTimeMs))
+ .append(")");
+ pw.println(sb.toString());
+ }
+
if (u.hasUserActivity()) {
boolean hasData = false;
for (int i=0; i<Uid.NUM_USER_ACTIVITY_TYPES; i++) {
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index 50eed3e..dfd523a 100644
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -685,6 +685,8 @@ public class Build {
final String bootimage = SystemProperties.get("ro.bootimage.build.fingerprint");
final String requiredBootloader = SystemProperties.get("ro.build.expect.bootloader");
final String currentBootloader = SystemProperties.get("ro.bootloader");
+ final String requiredRecovery = SystemProperties.get("ro.expect.recovery_id");
+ final String currentRecovery = SystemProperties.get("ro.recovery_id");
final String requiredRadio = SystemProperties.get("ro.build.expect.baseband");
final String currentRadio = SystemProperties.get("gsm.version.baseband");
@@ -701,7 +703,6 @@ public class Build {
}
}
- /* TODO: Figure out issue with checks failing
if (!TextUtils.isEmpty(bootimage)) {
if (!Objects.equals(system, bootimage)) {
Slog.e(TAG, "Mismatched fingerprints; system reported " + system
@@ -718,6 +719,15 @@ public class Build {
}
}
+ if (!TextUtils.isEmpty(requiredRecovery)) {
+ if (!Objects.equals(currentRecovery, requiredRecovery)) {
+ Slog.e(TAG, "Mismatched recovery version: build requires " + requiredRecovery
+ + " but runtime reports " + currentRecovery);
+ return false;
+ }
+ }
+
+ /* TODO: uncomment when new bootloader lands b/20860620
if (!TextUtils.isEmpty(requiredRadio)) {
if (!Objects.equals(currentRadio, requiredRadio)) {
Slog.e(TAG, "Mismatched radio version: build requires " + requiredRadio
diff --git a/core/java/android/os/RecoverySystem.java b/core/java/android/os/RecoverySystem.java
index 4aeab49..0c79094 100644
--- a/core/java/android/os/RecoverySystem.java
+++ b/core/java/android/os/RecoverySystem.java
@@ -71,6 +71,7 @@ public class RecoverySystem {
/** Used to communicate with recovery. See bootable/recovery/recovery.c. */
private static File RECOVERY_DIR = new File("/cache/recovery");
private static File COMMAND_FILE = new File(RECOVERY_DIR, "command");
+ private static File UNCRYPT_FILE = new File(RECOVERY_DIR, "uncrypt_file");
private static File LOG_FILE = new File(RECOVERY_DIR, "log");
private static String LAST_PREFIX = "last_";
@@ -333,8 +334,21 @@ public class RecoverySystem {
public static void installPackage(Context context, File packageFile)
throws IOException {
String filename = packageFile.getCanonicalPath();
+
+ FileWriter uncryptFile = new FileWriter(UNCRYPT_FILE);
+ try {
+ uncryptFile.write(filename + "\n");
+ } finally {
+ uncryptFile.close();
+ }
Log.w(TAG, "!!! REBOOTING TO INSTALL " + filename + " !!!");
+ // If the package is on the /data partition, write the block map file
+ // into COMMAND_FILE instead.
+ if (filename.startsWith("/data/")) {
+ filename = "@/cache/recovery/block.map";
+ }
+
final String filenameArg = "--update_package=" + filename;
final String localeArg = "--locale=" + Locale.getDefault().toString();
bootCommand(context, filenameArg, localeArg);
diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java
index dd3cedc..1da46d0 100644
--- a/core/java/android/service/notification/ZenModeConfig.java
+++ b/core/java/android/service/notification/ZenModeConfig.java
@@ -79,6 +79,7 @@ public class ZenModeConfig implements Parcelable {
private static final int XML_VERSION = 2;
private static final String ZEN_TAG = "zen";
private static final String ZEN_ATT_VERSION = "version";
+ private static final String ZEN_ATT_USER = "user";
private static final String ALLOW_TAG = "allow";
private static final String ALLOW_ATT_CALLS = "calls";
private static final String ALLOW_ATT_REPEAT_CALLERS = "repeatCallers";
@@ -117,6 +118,7 @@ public class ZenModeConfig implements Parcelable {
public boolean allowEvents = DEFAULT_ALLOW_EVENTS;
public int allowCallsFrom = DEFAULT_SOURCE;
public int allowMessagesFrom = DEFAULT_SOURCE;
+ public int user = UserHandle.USER_OWNER;
public ZenRule manualRule;
public ArrayMap<String, ZenRule> automaticRules = new ArrayMap<>();
@@ -131,6 +133,7 @@ public class ZenModeConfig implements Parcelable {
allowEvents = source.readInt() == 1;
allowCallsFrom = source.readInt();
allowMessagesFrom = source.readInt();
+ user = source.readInt();
manualRule = source.readParcelable(null);
final int len = source.readInt();
if (len > 0) {
@@ -153,6 +156,7 @@ public class ZenModeConfig implements Parcelable {
dest.writeInt(allowEvents ? 1 : 0);
dest.writeInt(allowCallsFrom);
dest.writeInt(allowMessagesFrom);
+ dest.writeInt(user);
dest.writeParcelable(manualRule, 0);
if (!automaticRules.isEmpty()) {
final int len = automaticRules.size();
@@ -173,7 +177,8 @@ public class ZenModeConfig implements Parcelable {
@Override
public String toString() {
return new StringBuilder(ZenModeConfig.class.getSimpleName()).append('[')
- .append("allowCalls=").append(allowCalls)
+ .append("user=").append(user)
+ .append(",allowCalls=").append(allowCalls)
.append(",allowRepeatCallers=").append(allowRepeatCallers)
.append(",allowMessages=").append(allowMessages)
.append(",allowCallsFrom=").append(sourceToString(allowCallsFrom))
@@ -185,6 +190,68 @@ public class ZenModeConfig implements Parcelable {
.append(']').toString();
}
+ private Diff diff(ZenModeConfig to) {
+ final Diff d = new Diff();
+ if (to == null) {
+ return d.addLine("config", "delete");
+ }
+ if (user != to.user) {
+ d.addLine("user", user, to.user);
+ }
+ if (allowCalls != to.allowCalls) {
+ d.addLine("allowCalls", allowCalls, to.allowCalls);
+ }
+ if (allowRepeatCallers != to.allowRepeatCallers) {
+ d.addLine("allowRepeatCallers", allowRepeatCallers, to.allowRepeatCallers);
+ }
+ if (allowMessages != to.allowMessages) {
+ d.addLine("allowMessages", allowMessages, to.allowMessages);
+ }
+ if (allowCallsFrom != to.allowCallsFrom) {
+ d.addLine("allowCallsFrom", allowCallsFrom, to.allowCallsFrom);
+ }
+ if (allowMessagesFrom != to.allowMessagesFrom) {
+ d.addLine("allowMessagesFrom", allowMessagesFrom, to.allowMessagesFrom);
+ }
+ if (allowReminders != to.allowReminders) {
+ d.addLine("allowReminders", allowReminders, to.allowReminders);
+ }
+ if (allowEvents != to.allowEvents) {
+ d.addLine("allowEvents", allowEvents, to.allowEvents);
+ }
+ final ArraySet<String> allRules = new ArraySet<>();
+ addKeys(allRules, automaticRules);
+ addKeys(allRules, to.automaticRules);
+ final int N = allRules.size();
+ for (int i = 0; i < N; i++) {
+ final String rule = allRules.valueAt(i);
+ final ZenRule fromRule = automaticRules != null ? automaticRules.get(rule) : null;
+ final ZenRule toRule = to.automaticRules != null ? to.automaticRules.get(rule) : null;
+ ZenRule.appendDiff(d, "automaticRule[" + rule + "]", fromRule, toRule);
+ }
+ ZenRule.appendDiff(d, "manualRule", manualRule, to.manualRule);
+ return d;
+ }
+
+ public static Diff diff(ZenModeConfig from, ZenModeConfig to) {
+ if (from == null) {
+ final Diff d = new Diff();
+ if (to != null) {
+ d.addLine("config", "insert");
+ }
+ return d;
+ }
+ return from.diff(to);
+ }
+
+ private static <T> void addKeys(ArraySet<T> set, ArrayMap<T, ?> map) {
+ if (map != null) {
+ for (int i = 0; i < map.size(); i++) {
+ set.add(map.keyAt(i));
+ }
+ }
+ }
+
public boolean isValid() {
if (!isValidManualRule(manualRule)) return false;
final int N = automaticRules.size();
@@ -249,6 +316,7 @@ public class ZenModeConfig implements Parcelable {
&& other.allowMessagesFrom == allowMessagesFrom
&& other.allowReminders == allowReminders
&& other.allowEvents == allowEvents
+ && other.user == user
&& Objects.equals(other.automaticRules, automaticRules)
&& Objects.equals(other.manualRule, manualRule);
}
@@ -256,7 +324,7 @@ public class ZenModeConfig implements Parcelable {
@Override
public int hashCode() {
return Objects.hash(allowCalls, allowRepeatCallers, allowMessages, allowCallsFrom,
- allowMessagesFrom, allowReminders, allowEvents, automaticRules, manualRule);
+ allowMessagesFrom, allowReminders, allowEvents, user, automaticRules, manualRule);
}
private static String toDayList(int[] days) {
@@ -312,6 +380,7 @@ public class ZenModeConfig implements Parcelable {
final XmlV1 v1 = XmlV1.readXml(parser);
return migration.migrate(v1);
}
+ rt.user = safeInt(parser, ZEN_ATT_USER, rt.user);
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
tag = parser.getName();
if (type == XmlPullParser.END_TAG && ZEN_TAG.equals(tag)) {
@@ -357,6 +426,7 @@ public class ZenModeConfig implements Parcelable {
public void writeXml(XmlSerializer out) throws IOException {
out.startTag(null, ZEN_TAG);
out.attribute(null, ZEN_ATT_VERSION, Integer.toString(XML_VERSION));
+ out.attribute(null, ZEN_ATT_USER, Integer.toString(user));
out.startTag(null, ALLOW_TAG);
out.attribute(null, ALLOW_ATT_CALLS, Boolean.toString(allowCalls));
@@ -915,6 +985,45 @@ public class ZenModeConfig implements Parcelable {
.append(']').toString();
}
+ private static void appendDiff(Diff d, String item, ZenRule from, ZenRule to) {
+ if (d == null) return;
+ if (from == null) {
+ if (to != null) {
+ d.addLine(item, "insert");
+ }
+ return;
+ }
+ from.appendDiff(d, item, to);
+ }
+
+ private void appendDiff(Diff d, String item, ZenRule to) {
+ if (to == null) {
+ d.addLine(item, "delete");
+ return;
+ }
+ if (enabled != to.enabled) {
+ d.addLine(item, "enabled", enabled, to.enabled);
+ }
+ if (snoozing != to.snoozing) {
+ d.addLine(item, "snoozing", snoozing, to.snoozing);
+ }
+ if (!Objects.equals(name, to.name)) {
+ d.addLine(item, "name", name, to.name);
+ }
+ if (zenMode != to.zenMode) {
+ d.addLine(item, "zenMode", zenMode, to.zenMode);
+ }
+ if (!Objects.equals(conditionId, to.conditionId)) {
+ d.addLine(item, "conditionId", conditionId, to.conditionId);
+ }
+ if (!Objects.equals(condition, to.condition)) {
+ d.addLine(item, "condition", condition, to.condition);
+ }
+ if (!Objects.equals(component, to.component)) {
+ d.addLine(item, "component", component, to.component);
+ }
+ }
+
@Override
public boolean equals(Object o) {
if (!(o instanceof ZenRule)) return false;
@@ -1073,4 +1182,34 @@ public class ZenModeConfig implements Parcelable {
ZenModeConfig migrate(XmlV1 v1);
}
+ public static class Diff {
+ private final ArrayList<String> lines = new ArrayList<>();
+
+ @Override
+ public String toString() {
+ final StringBuilder sb = new StringBuilder("Diff[");
+ final int N = lines.size();
+ for (int i = 0; i < N; i++) {
+ if (i > 0) {
+ sb.append(',');
+ }
+ sb.append(lines.get(i));
+ }
+ return sb.append(']').toString();
+ }
+
+ private Diff addLine(String item, String action) {
+ lines.add(item + ":" + action);
+ return this;
+ }
+
+ public Diff addLine(String item, String subitem, Object from, Object to) {
+ return addLine(item + "." + subitem, from, to);
+ }
+
+ public Diff addLine(String item, Object from, Object to) {
+ return addLine(item, from + "->" + to);
+ }
+ }
+
}
diff --git a/core/java/android/service/voice/IVoiceInteractionSession.aidl b/core/java/android/service/voice/IVoiceInteractionSession.aidl
index 7c90261..894edac 100644
--- a/core/java/android/service/voice/IVoiceInteractionSession.aidl
+++ b/core/java/android/service/voice/IVoiceInteractionSession.aidl
@@ -16,6 +16,8 @@
package android.service.voice;
+import android.app.AssistContent;
+import android.app.AssistStructure;
import android.content.Intent;
import android.graphics.Bitmap;
import android.os.Bundle;
@@ -28,7 +30,7 @@ import com.android.internal.app.IVoiceInteractionSessionShowCallback;
oneway interface IVoiceInteractionSession {
void show(in Bundle sessionArgs, int flags, IVoiceInteractionSessionShowCallback showCallback);
void hide();
- void handleAssist(in Bundle assistData);
+ void handleAssist(in Bundle assistData, in AssistStructure structure, in AssistContent content);
void handleScreenshot(in Bitmap screenshot);
void taskStarted(in Intent intent, int taskId);
void taskFinished(in Intent intent, int taskId);
diff --git a/core/java/android/service/voice/VoiceInteractionSession.java b/core/java/android/service/voice/VoiceInteractionSession.java
index f122d10..f09b6a2 100644
--- a/core/java/android/service/voice/VoiceInteractionSession.java
+++ b/core/java/android/service/voice/VoiceInteractionSession.java
@@ -16,6 +16,7 @@
package android.service.voice;
+import android.app.AssistContent;
import android.app.AssistStructure;
import android.app.Dialog;
import android.app.Instrumentation;
@@ -180,21 +181,16 @@ public abstract class VoiceInteractionSession implements KeyEvent.Callback,
}
@Override
- public void handleAssist(Bundle assistBundle) {
+ public void handleAssist(Bundle data, AssistStructure structure,
+ AssistContent content) {
// We want to pre-warm the AssistStructure before handing it off to the main
// thread. There is a strong argument to be made that it should be handed
// through as a separate param rather than part of the assistBundle.
- if (assistBundle != null) {
- Bundle assistContext = assistBundle.getBundle(Intent.EXTRA_ASSIST_CONTEXT);
- if (assistContext != null) {
- AssistStructure as = AssistStructure.getAssistStructure(assistContext);
- if (as != null) {
- as.ensureData();
- }
- }
+ if (structure != null) {
+ structure.ensureData();
}
- mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageO(MSG_HANDLE_ASSIST,
- assistBundle));
+ mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageOOO(MSG_HANDLE_ASSIST,
+ data, structure, content));
}
@Override
@@ -422,8 +418,11 @@ public abstract class VoiceInteractionSession implements KeyEvent.Callback,
doDestroy();
break;
case MSG_HANDLE_ASSIST:
- if (DEBUG) Log.d(TAG, "onHandleAssist: " + msg.obj);
- onHandleAssist((Bundle) msg.obj);
+ args = (SomeArgs)msg.obj;
+ if (DEBUG) Log.d(TAG, "onHandleAssist: data=" + args.arg1
+ + " structure=" + args.arg2 + " content=" + args.arg3);
+ onHandleAssist((Bundle) args.arg1, (AssistStructure) args.arg2,
+ (AssistContent) args.arg3);
break;
case MSG_HANDLE_SCREENSHOT:
if (DEBUG) Log.d(TAG, "onHandleScreenshot: " + msg.obj);
@@ -817,9 +816,22 @@ public abstract class VoiceInteractionSession implements KeyEvent.Callback,
}
+ /** @hide */
public void onHandleAssist(Bundle assistBundle) {
}
+ public void onHandleAssist(Bundle data, AssistStructure structure, AssistContent content) {
+ if (data != null) {
+ Bundle assistContext = data.getBundle(Intent.EXTRA_ASSIST_CONTEXT);
+ if (assistContext != null) {
+ assistContext.putParcelable(AssistStructure.ASSIST_KEY, structure);
+ assistContext.putParcelable(AssistContent.ASSIST_KEY, content);
+ data.putBundle(Intent.EXTRA_ASSIST_CONTEXT, assistContext);
+ }
+ }
+ onHandleAssist(data);
+ }
+
/** @hide */
public void onHandleScreenshot(Bitmap screenshot) {
}
diff --git a/core/java/android/text/Layout.java b/core/java/android/text/Layout.java
index f176240..f7027f9 100644
--- a/core/java/android/text/Layout.java
+++ b/core/java/android/text/Layout.java
@@ -1121,6 +1121,7 @@ public abstract class Layout {
* closest to the specified horizontal position.
*/
public int getOffsetForHorizontal(int line, float horiz) {
+ // TODO: use Paint.getOffsetForAdvance to avoid binary search
int max = getLineEnd(line) - 1;
int min = getLineStart(line);
Directions dirs = getLineDirections(line);
diff --git a/core/java/android/text/TextLine.java b/core/java/android/text/TextLine.java
index 479242c..605b91d 100644
--- a/core/java/android/text/TextLine.java
+++ b/core/java/android/text/TextLine.java
@@ -739,16 +739,14 @@ class TextLine {
float ret = 0;
- int contextLen = contextEnd - contextStart;
if (needWidth || (c != null && (wp.bgColor != 0 || wp.underlineColor != 0 || runIsRtl))) {
if (mCharsValid) {
- ret = wp.getTextRunAdvances(mChars, start, runLen,
- contextStart, contextLen, runIsRtl, null, 0);
+ ret = wp.getRunAdvance(mChars, start, contextEnd, contextStart, contextEnd,
+ runIsRtl, end);
} else {
int delta = mStart;
- ret = wp.getTextRunAdvances(mText, delta + start,
- delta + end, delta + contextStart, delta + contextEnd,
- runIsRtl, null, 0);
+ ret = wp.getRunAdvance(mText, delta + start, delta + contextEnd,
+ delta + contextStart, delta + contextEnd, runIsRtl, delta + end);
}
}
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index f61e372..3f7bad6 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -1306,16 +1306,12 @@ public final class InputMethodManager {
if (DEBUG) Log.v(TAG, "focusOut: " + view
+ " mServedView=" + mServedView
+ " winFocus=" + view.hasWindowFocus());
- if (mServedView != view) {
- // The following code would auto-hide the IME if we end up
- // with no more views with focus. This can happen, however,
- // whenever we go into touch mode, so it ends up hiding
- // at times when we don't really want it to. For now it
- // seems better to just turn it all off.
- if (false && view.hasWindowFocus()) {
- mNextServedView = null;
- scheduleCheckFocusLocked(view);
- }
+ // CAVEAT: We have ignored focusOut event in Android L MR-1 and prior. Need special
+ // care when changing the logic here because there are so many cases to be taken into
+ // consideration, e.g., WindowManager.LayoutParams.SOFT_INPUT_* flags.
+ if (mServedView == view && view.hasWindowFocus()) {
+ mNextServedView = null;
+ scheduleCheckFocusLocked(view);
}
}
}
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index fc84cf9..6cd35f9 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -1890,6 +1890,11 @@ public class Editor {
if (!extractedTextModeWillBeStarted()) {
if (isCursorInsideEasyCorrectionSpan()) {
+ // Cancel the single tap delayed runnable.
+ if (mSelectionModeWithoutSelectionRunnable != null) {
+ mTextView.removeCallbacks(mSelectionModeWithoutSelectionRunnable);
+ }
+
mShowSuggestionRunnable = new Runnable() {
public void run() {
showSuggestions();
@@ -3819,13 +3824,15 @@ public class Editor {
SystemClock.uptimeMillis() - TextView.sLastCutCopyOrTextChangedTime;
// Cancel the single tap delayed runnable.
- if (mDoubleTap && mSelectionModeWithoutSelectionRunnable != null) {
+ if (mSelectionModeWithoutSelectionRunnable != null
+ && (mDoubleTap || isCursorInsideEasyCorrectionSpan())) {
mTextView.removeCallbacks(mSelectionModeWithoutSelectionRunnable);
}
// Prepare and schedule the single tap runnable to run exactly after the double tap
// timeout has passed.
- if (!mDoubleTap && (durationSinceCutOrCopy < RECENT_CUT_COPY_DURATION)) {
+ if (!mDoubleTap && !isCursorInsideEasyCorrectionSpan()
+ && (durationSinceCutOrCopy < RECENT_CUT_COPY_DURATION)) {
if (mSelectionModeWithoutSelectionRunnable == null) {
mSelectionModeWithoutSelectionRunnable = new Runnable() {
public void run() {
diff --git a/core/java/android/widget/ScrollView.java b/core/java/android/widget/ScrollView.java
index 2709f25..ca57d1a 100644
--- a/core/java/android/widget/ScrollView.java
+++ b/core/java/android/widget/ScrollView.java
@@ -1704,12 +1704,26 @@ public class ScrollView extends FrameLayout {
super.draw(canvas);
if (mEdgeGlowTop != null) {
final int scrollY = mScrollY;
+ final boolean clipToPadding = getClipToPadding();
if (!mEdgeGlowTop.isFinished()) {
final int restoreCount = canvas.save();
- final int width = getWidth() - mPaddingLeft - mPaddingRight;
-
- canvas.translate(mPaddingLeft, Math.min(0, scrollY));
- mEdgeGlowTop.setSize(width, getHeight());
+ final int width;
+ final int height;
+ final float translateX;
+ final float translateY;
+ if (clipToPadding) {
+ width = getWidth() - mPaddingLeft - mPaddingRight;
+ height = getHeight() - mPaddingTop - mPaddingBottom;
+ translateX = mPaddingLeft;
+ translateY = mPaddingTop;
+ } else {
+ width = getWidth();
+ height = getHeight();
+ translateX = 0;
+ translateY = 0;
+ }
+ canvas.translate(translateX, Math.min(0, scrollY) + translateY);
+ mEdgeGlowTop.setSize(width, height);
if (mEdgeGlowTop.draw(canvas)) {
postInvalidateOnAnimation();
}
@@ -1717,11 +1731,23 @@ public class ScrollView extends FrameLayout {
}
if (!mEdgeGlowBottom.isFinished()) {
final int restoreCount = canvas.save();
- final int width = getWidth() - mPaddingLeft - mPaddingRight;
- final int height = getHeight();
-
- canvas.translate(-width + mPaddingLeft,
- Math.max(getScrollRange(), scrollY) + height);
+ final int width;
+ final int height;
+ final float translateX;
+ final float translateY;
+ if (clipToPadding) {
+ width = getWidth() - mPaddingLeft - mPaddingRight;
+ height = getHeight() - mPaddingTop - mPaddingBottom;
+ translateX = mPaddingLeft;
+ translateY = mPaddingTop;
+ } else {
+ width = getWidth();
+ height = getHeight();
+ translateX = 0;
+ translateY = 0;
+ }
+ canvas.translate(-width + translateX,
+ Math.max(getScrollRange(), scrollY) + height + translateY);
canvas.rotate(180, width, 0);
mEdgeGlowBottom.setSize(width, height);
if (mEdgeGlowBottom.draw(canvas)) {
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index a93e7ef..9de7778 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -8015,8 +8015,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
* through a thunk.
*/
void sendAfterTextChanged(Editable text) {
- sLastCutCopyOrTextChangedTime = 0;
-
if (mListeners != null) {
final ArrayList<TextWatcher> list = mListeners;
final int count = list.size();
@@ -8049,6 +8047,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
* through a thunk.
*/
void handleTextChanged(CharSequence buffer, int start, int before, int after) {
+ sLastCutCopyOrTextChangedTime = 0;
+
final Editor.InputMethodState ims = mEditor == null ? null : mEditor.mInputMethodState;
if (ims == null || ims.mBatchEditNesting == 0) {
updateAfterEdit();
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index 5448214..40fee2c 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -257,7 +257,8 @@ LOCAL_MODULE:= libandroid_runtime
# -Wno-unknown-pragmas: necessary for Clang as the GL bindings need to turn
# off a GCC warning that Clang doesn't know.
-LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code -Wno-unknown-pragmas
+LOCAL_CFLAGS += -Wall -Werror -Wno-error=deprecated-declarations -Wunused -Wunreachable-code \
+ -Wno-unknown-pragmas
# -Wno-c++11-extensions: Clang warns about Skia using the C++11 override keyword, but this project
# is not being compiled with that level. Remove once this has changed.
diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp
index 04b9a95..832f92f 100755
--- a/core/jni/android/graphics/Bitmap.cpp
+++ b/core/jni/android/graphics/Bitmap.cpp
@@ -46,8 +46,8 @@ public:
SkSafeUnref(mColorTable);
}
- void reconfigure(const SkImageInfo& info, size_t rowBytes, SkColorTable* ctable) {
- if (kIndex_8_SkColorType != info.colorType()) {
+ void reconfigure(const SkImageInfo& newInfo, size_t rowBytes, SkColorTable* ctable) {
+ if (kIndex_8_SkColorType != newInfo.colorType()) {
ctable = nullptr;
}
mRowBytes = rowBytes;
@@ -56,13 +56,22 @@ public:
mColorTable = ctable;
SkSafeRef(mColorTable);
}
+
+ // Need to validate the alpha type to filter against the color type
+ // to prevent things like a non-opaque RGB565 bitmap
+ SkAlphaType alphaType;
+ LOG_ALWAYS_FATAL_IF(!SkColorTypeValidateAlphaType(
+ newInfo.colorType(), newInfo.alphaType(), &alphaType),
+ "Failed to validate alpha type!");
+
// Dirty hack is dirty
// TODO: Figure something out here, Skia's current design makes this
// really hard to work with. Skia really, really wants immutable objects,
// but with the nested-ref-count hackery going on that's just not
// feasible without going insane trying to figure it out
SkImageInfo* myInfo = const_cast<SkImageInfo*>(&this->info());
- *myInfo = info;
+ *myInfo = newInfo;
+ changeAlphaType(alphaType);
// Docs say to only call this in the ctor, but we're going to call
// it anyway even if this isn't always the ctor.
@@ -254,6 +263,14 @@ void Bitmap::reconfigure(const SkImageInfo& info) {
reconfigure(info, info.minRowBytes(), nullptr);
}
+void Bitmap::setAlphaType(SkAlphaType alphaType) {
+ if (!SkColorTypeValidateAlphaType(info().colorType(), alphaType, &alphaType)) {
+ return;
+ }
+
+ mPixelRef->changeAlphaType(alphaType);
+}
+
void Bitmap::detachFromJava() {
bool disposeSelf;
{
@@ -861,10 +878,10 @@ static void Bitmap_setHasAlpha(JNIEnv* env, jobject, jlong bitmapHandle,
jboolean hasAlpha, jboolean requestPremul) {
LocalScopedBitmap bitmap(bitmapHandle);
if (hasAlpha) {
- bitmap->peekAtPixelRef()->changeAlphaType(
+ bitmap->setAlphaType(
requestPremul ? kPremul_SkAlphaType : kUnpremul_SkAlphaType);
} else {
- bitmap->peekAtPixelRef()->changeAlphaType(kOpaque_SkAlphaType);
+ bitmap->setAlphaType(kOpaque_SkAlphaType);
}
}
@@ -873,9 +890,9 @@ static void Bitmap_setPremultiplied(JNIEnv* env, jobject, jlong bitmapHandle,
LocalScopedBitmap bitmap(bitmapHandle);
if (!bitmap->info().isOpaque()) {
if (isPremul) {
- bitmap->peekAtPixelRef()->changeAlphaType(kPremul_SkAlphaType);
+ bitmap->setAlphaType(kPremul_SkAlphaType);
} else {
- bitmap->peekAtPixelRef()->changeAlphaType(kUnpremul_SkAlphaType);
+ bitmap->setAlphaType(kUnpremul_SkAlphaType);
}
}
}
diff --git a/core/jni/android/graphics/Bitmap.h b/core/jni/android/graphics/Bitmap.h
index 95b5fae..eadba5c 100644
--- a/core/jni/android/graphics/Bitmap.h
+++ b/core/jni/android/graphics/Bitmap.h
@@ -71,6 +71,7 @@ public:
void reconfigure(const SkImageInfo& info, size_t rowBytes, SkColorTable* ctable);
void reconfigure(const SkImageInfo& info);
+ void setAlphaType(SkAlphaType alphaType);
void getSkBitmap(SkBitmap* outBitmap);
void detachFromJava();
diff --git a/core/jni/android_media_AudioRecord.cpp b/core/jni/android_media_AudioRecord.cpp
index 5928c69..6c2bbd4 100644
--- a/core/jni/android_media_AudioRecord.cpp
+++ b/core/jni/android_media_AudioRecord.cpp
@@ -321,6 +321,7 @@ native_init_failure:
delete lpCallbackData;
env->SetLongField(thiz, javaAudioRecordFields.nativeCallbackCookie, 0);
+ // lpRecorder goes out of scope, so reference count drops to zero
return (jint) AUDIORECORD_ERROR_SETUP_NATIVEINITFAILED;
}
diff --git a/core/jni/android_media_AudioTrack.cpp b/core/jni/android_media_AudioTrack.cpp
index 5b52a49..5faa150 100644
--- a/core/jni/android_media_AudioTrack.cpp
+++ b/core/jni/android_media_AudioTrack.cpp
@@ -405,6 +405,7 @@ native_init_failure:
delete lpJniStorage;
env->SetLongField(thiz, javaAudioTrackFields.jniData, 0);
+ // lpTrack goes out of scope, so reference count drops to zero
return (jint) AUDIOTRACK_ERROR_SETUP_NATIVEINITFAILED;
}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 57a2ede..1b77bfb 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -349,14 +349,14 @@
android:description="@string/permdesc_writeContacts"
android:protectionLevel="dangerous" />
- <!-- Allows an application to read the user's personal profile data. -->
+ <!-- @deprecated No longer enforced. This was last enforced in API version 22. -->
<permission android:name="android.permission.READ_PROFILE"
android:permissionGroup="android.permission-group.CONTACTS"
android:label="@string/permlab_readProfile"
android:description="@string/permdesc_readProfile"
android:protectionLevel="dangerous" />
- <!-- Allows an application to write the user's personal profile data. -->
+ <!-- @deprecated No longer enforced. This was last enforced in API version 22. -->
<permission android:name="android.permission.WRITE_PROFILE"
android:permissionGroup="android.permission-group.CONTACTS"
android:label="@string/permlab_writeProfile"
@@ -1475,7 +1475,6 @@
android:label="@string/permlab_readSyncStats"
android:protectionLevel="normal" />
-
<!-- ============================================ -->
<!-- Permissions for low-level system interaction -->
<!-- ============================================ -->
@@ -1933,6 +1932,14 @@
<permission android:name="android.permission.SET_KEYBOARD_LAYOUT"
android:protectionLevel="signature" />
+ <!-- Allows an application to request installing packages. Apps
+ targeting APIs greater than 22 must hold this permission in
+ order to use {@link android.content.Intent#ACTION_INSTALL_PACKAGE}.-->
+ <permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"
+ android:label="@string/permlab_requestInstallPackages"
+ android:description="@string/permdesc_requestInstallPackages"
+ android:protectionLevel="normal" />
+
<!-- @SystemApi Allows an application to install packages.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.INSTALL_PACKAGES"
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 74d448c..d9801ef 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -413,6 +413,10 @@
<!-- Spoken description for ringer normal option. [CHAR LIMIT=NONE] -->
<string name="silent_mode_ring">Ringer on</string>
+ <!-- Reboot to Recovery Progress Dialog. This is shown before it reboots to recovery. -->
+ <string name="reboot_to_recovery_title">Prepare for update</string>
+ <string name="reboot_to_recovery_progress">Processing the update package\u2026</string>
+
<!-- Shutdown Progress Dialog. This is shown if the user chooses to power off the phone. -->
<string name="shutdown_progress">Shutting down\u2026</string>
@@ -3044,6 +3048,11 @@
<!-- Description of an application permission that lets it read install sessions. -->
<string name="permdesc_readInstallSessions">Allows an application to read install sessions. This allows it to see details about active package installations.</string>
+ <!-- Title of an application permission that lets it read install sessions. -->
+ <string name="permlab_requestInstallPackages">Request install packages</string>
+ <!-- Description of an application permission that lets it read install sessions. -->
+ <string name="permdesc_requestInstallPackages">Allows an application to request installation of packages.</string>
+
<!-- Shown in the tutorial for tap twice for zoom control. -->
<string name="tutorial_double_tap_to_zoom_message_short">Touch twice for zoom control</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index e3033e7..ff3801f 100755
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -815,6 +815,8 @@
<java-symbol type="string" name="mobile_provisioning_url" />
<java-symbol type="string" name="mobile_redirected_provisioning_url" />
<java-symbol type="string" name="quick_contacts_not_available" />
+ <java-symbol type="string" name="reboot_to_recovery_progress" />
+ <java-symbol type="string" name="reboot_to_recovery_title" />
<java-symbol type="string" name="reboot_safemode_confirm" />
<java-symbol type="string" name="reboot_safemode_title" />
<java-symbol type="string" name="relationTypeAssistant" />
diff --git a/core/res/res/values/themes_material.xml b/core/res/res/values/themes_material.xml
index f01e3f8..9f3668d 100644
--- a/core/res/res/values/themes_material.xml
+++ b/core/res/res/values/themes_material.xml
@@ -141,6 +141,7 @@ please see themes_device_defaults.xml.
<item name="expandableListPreferredItemIndicatorRight">0dip</item>
<item name="expandableListPreferredChildIndicatorLeft">?attr/expandableListPreferredItemIndicatorLeft</item>
<item name="expandableListPreferredChildIndicatorRight">?attr/expandableListPreferredItemIndicatorRight</item>
+
<item name="findOnPageNextDrawable">@drawable/ic_find_next_material</item>
<item name="findOnPagePreviousDrawable">@drawable/ic_find_previous_material</item>
@@ -160,8 +161,6 @@ please see themes_device_defaults.xml.
<item name="windowTitleStyle">@style/WindowTitle.Material</item>
<item name="windowTitleSize">@dimen/action_bar_default_height_material</item>
<item name="windowTitleBackgroundStyle">@style/WindowTitleBackground.Material</item>
- <item name="windowContentTransitions">false</item>
- <item name="windowActivityTransitions">true</item>
<item name="windowAnimationStyle">@style/Animation.Material.Activity</item>
<item name="windowSoftInputMode">stateUnspecified|adjustUnspecified</item>
<item name="windowActionBar">true</item>
@@ -173,6 +172,8 @@ please see themes_device_defaults.xml.
<item name="windowEnterTransition">@transition/fade</item>
<item name="windowSharedElementEnterTransition">@transition/move</item>
<item name="windowSharedElementExitTransition">@transition/move</item>
+ <item name="windowContentTransitions">false</item>
+ <item name="windowActivityTransitions">true</item>
<!-- Dialog attributes -->
<item name="dialogTheme">@style/ThemeOverlay.Material.Dialog</item>
@@ -305,6 +306,9 @@ please see themes_device_defaults.xml.
<item name="detailsElementBackground">?attr/colorBackground</item>
<item name="fingerprintDrawable">@drawable/ic_fingerprint_dark</item>
+ <!-- PreferenceFrameLayout attributes -->
+ <item name="preferenceFrameLayoutStyle">@style/Widget.Material.PreferenceFrameLayout</item>
+
<!-- Search widget styles -->
<item name="searchWidgetCorpusItemBackground">@color/search_widget_corpus_item_background</item>
@@ -351,9 +355,6 @@ please see themes_device_defaults.xml.
<item name="searchViewStyle">@style/Widget.Material.SearchView</item>
<item name="searchDialogTheme">@style/Theme.Material.SearchBar</item>
- <!-- PreferenceFrameLayout attributes -->
- <item name="preferenceFrameLayoutStyle">@style/Widget.Material.PreferenceFrameLayout</item>
-
<!-- NumberPicker style-->
<item name="numberPickerStyle">@style/Widget.Material.NumberPicker</item>
@@ -453,8 +454,8 @@ please see themes_device_defaults.xml.
<item name="buttonStyleSmall">@style/Widget.Material.Light.Button.Small</item>
<item name="buttonStyleInset">@style/Widget.Material.Light.Button.Inset</item>
-
<item name="buttonStyleToggle">@style/Widget.Material.Light.Button.Toggle</item>
+
<item name="switchStyle">@style/Widget.Material.Light.CompoundButton.Switch</item>
<item name="mediaRouteButtonStyle">@style/Widget.Material.Light.MediaRouteButton</item>
@@ -487,6 +488,8 @@ please see themes_device_defaults.xml.
<item name="listChoiceBackgroundIndicator">@drawable/list_choice_background_material</item>
<item name="activatedBackgroundIndicator">@drawable/activated_background_material</item>
+ <item name="listDividerAlertDialog">@null</item>
+
<item name="expandableListPreferredItemPaddingLeft">40dip</item>
<item name="expandableListPreferredChildPaddingLeft">?attr/expandableListPreferredItemPaddingLeft</item>
@@ -495,7 +498,6 @@ please see themes_device_defaults.xml.
<item name="expandableListPreferredChildIndicatorLeft">?attr/expandableListPreferredItemIndicatorLeft</item>
<item name="expandableListPreferredChildIndicatorRight">?attr/expandableListPreferredItemIndicatorRight</item>
- <item name="listDividerAlertDialog">@null</item>
<item name="findOnPageNextDrawable">@drawable/ic_find_next_material</item>
<item name="findOnPagePreviousDrawable">@drawable/ic_find_previous_material</item>
@@ -632,6 +634,7 @@ please see themes_device_defaults.xml.
<item name="quickContactBadgeStyleSmallWindowLarge">@style/Widget.Material.QuickContactBadgeSmall.WindowLarge</item>
<item name="listPopupWindowStyle">@style/Widget.Material.Light.ListPopupWindow</item>
<item name="popupMenuStyle">@style/Widget.Material.Light.PopupMenu</item>
+ <item name="popupTheme">@null</item>
<item name="stackViewStyle">@style/Widget.Material.Light.StackView</item>
<item name="activityChooserViewStyle">@style/Widget.Material.Light.ActivityChooserView</item>
<item name="fragmentBreadCrumbsStyle">@style/Widget.Material.FragmentBreadCrumbs</item>
@@ -681,7 +684,10 @@ please see themes_device_defaults.xml.
<item name="actionBarStyle">@style/Widget.Material.Light.ActionBar.Solid</item>
<item name="actionBarSize">@dimen/action_bar_default_height_material</item>
<item name="actionModePopupWindowStyle">@style/Widget.Material.Light.PopupWindow.ActionMode</item>
+ <item name="actionMenuTextAppearance">@style/TextAppearance.Material.Widget.ActionBar.Menu</item>
+ <item name="actionMenuTextColor">?attr/textColorPrimary</item>
<item name="actionBarWidgetTheme">@null</item>
+ <item name="actionBarPopupTheme">?attr/popupTheme</item>
<item name="actionBarTheme">@style/ThemeOverlay.Material.ActionBar</item>
<item name="actionBarItemBackground">@drawable/action_bar_item_background_material</item>
@@ -723,6 +729,7 @@ please see themes_device_defaults.xml.
<!-- DatePicker dialog theme -->
<item name="datePickerDialogTheme">?attr/dialogTheme</item>
+ <!-- TODO: This belongs in a FastScroll style -->
<item name="fastScrollThumbDrawable">@drawable/fastscroll_thumb_material</item>
<item name="fastScrollPreviewBackgroundLeft">@drawable/fastscroll_label_left_material</item>
<item name="fastScrollPreviewBackgroundRight">@drawable/fastscroll_label_right_material</item>
@@ -733,6 +740,7 @@ please see themes_device_defaults.xml.
<item name="colorPrimaryDark">@color/primary_dark_material_light</item>
<item name="colorPrimary">@color/primary_material_light</item>
<item name="colorAccent">@color/accent_material_light</item>
+ <item name="colorEdgeEffect">?attr/colorPrimary</item>
<item name="colorControlNormal">?attr/textColorSecondary</item>
<item name="colorControlActivated">?attr/colorAccent</item>
diff --git a/core/res/res/values/themes_micro.xml b/core/res/res/values/themes_micro.xml
index 112afa6..8bf635e 100644
--- a/core/res/res/values/themes_micro.xml
+++ b/core/res/res/values/themes_micro.xml
@@ -14,7 +14,7 @@
limitations under the License.
-->
<resources>
- <style name="Theme.Micro" parent="Theme.Material.NoActionBar">
+ <style name="Theme.MicroBase" parent="Theme.Material.NoActionBar">
<item name="alertDialogTheme">@style/Theme.Micro.Dialog.Alert</item>
<item name="alertDialogStyle">@style/AlertDialog.Micro</item>
<item name="dialogTheme">@style/Theme.Micro.Dialog</item>
@@ -29,7 +29,10 @@
<item name="windowOverscan">true</item>
</style>
- <style name="Theme.Micro.Light" parent="Theme.Material.Light.NoActionBar">
+ <style name="Theme.Micro" parent="Theme.MicroBase">
+ </style>
+
+ <style name="Theme.Micro.LightBase" parent="Theme.Material.Light.NoActionBar">
<item name="alertDialogTheme">@style/Theme.Micro.Dialog.Alert</item>
<item name="alertDialogStyle">@style/AlertDialog.Micro</item>
<item name="dialogTheme">@style/Theme.Micro.Dialog</item>
@@ -44,7 +47,11 @@
<item name="windowOverscan">true</item>
</style>
- <style name="Theme.Micro.Dialog" parent="Theme.Material.Light.Dialog">
+ <!-- Indirection needed for overlays to make sure there is a common base parent -->
+ <style name="Theme.Micro.Light" parent="Theme.Micro.LightBase">
+ </style>
+
+ <style name="Theme.Micro.DialogBase" parent="Theme.Material.Light.Dialog">
<item name="windowTitleStyle">@android:style/DialogWindowTitle.Micro</item>
<item name="windowIsFloating">false</item>
<item name="windowFullscreen">true</item>
@@ -54,6 +61,10 @@
<item name="windowOverscan">true</item>
</style>
+ <!-- Indirection needed for overlays to make sure there is a common base parent -->
+ <style name="Theme.Micro.Dialog" parent="Theme.Micro.DialogBase">
+ </style>
+
<style name="Theme.Micro.Dialog.Alert">
<item name="windowTitleStyle">@style/DialogWindowTitle.Micro</item>
<item name="alertDialogStyle">@style/AlertDialog.Micro</item>
diff --git a/docs/html-ndk/ndk/guides/abis.jd b/docs/html-ndk/ndk/guides/abis.jd
index ee55898..f4819b2 100644
--- a/docs/html-ndk/ndk/guides/abis.jd
+++ b/docs/html-ndk/ndk/guides/abis.jd
@@ -373,7 +373,7 @@ further information
<h3 id="mips64">mips64</h3>
<p>This ABI is for MIPS64 R6. For more information, see
-<a href="http://www.imgtec.com/mips/architectures/mips64.asp">MIPS Architecture</a>.</p>
+<a href="http://www.imgtec.com/mips/architectures/mips64.asp">MIPS64 Architecture</a>.</p>
<h2 id="gc">Generating Code for a Specific ABI</h2>
<p>By default, the NDK generates machine code for the armeabi ABI. You can
diff --git a/docs/html-ndk/ndk/guides/android_mk.jd b/docs/html-ndk/ndk/guides/android_mk.jd
index 8d0a8b1..47fefc3 100644
--- a/docs/html-ndk/ndk/guides/android_mk.jd
+++ b/docs/html-ndk/ndk/guides/android_mk.jd
@@ -114,7 +114,7 @@ script determines what to build, and how to do it.</p>
<p>There are more complex examples in the samples directories, with commented
{@code Android.mk} files that you can look at. In addition,
-<a href="{@docRoot}ndk/guides/sample_na.html">Sample: native-activity</a> provides
+<a href="{@docRoot}ndk/samples/sample_na.html">Sample: native-activity</a> provides
a detailed explanation of that sample's {@code Android.mk} file. Finally, <a href="#var">
Variables and Macros</a> provides further information on the variables from this section.
@@ -217,7 +217,7 @@ The following example shows the syntax for using this variable:</p>
TARGET_PLATFORM := android-22
</pre>
-<h4>TARGET_ARCH_ABI</h4>
+<h4 id="taa">TARGET_ARCH_ABI</h4>
<p>This variable stores the name of the CPU and architecture to target when the build system
parses this {@code Android.mk} file. You can specify one or more of the following values, using
a space as a delimiter between multiple targets. Table 1 shows the ABI setting to use for each
@@ -872,7 +872,4 @@ $(call import-module,&lt;name&gt;)
<p>In this example, the build system looks for the module tagged {@code &lt;name&gt;} in the list of
directories referenced that your {@code NDK_MODULE_PATH} environment variable references, and
-includes its {@code Android.mk} file automatically for you.</p>
-
-<p>For more information, see <a href="import.html">Android Module Paths (Sharing Code)</a>.
-</p>
+includes its {@code Android.mk} file automatically for you.</p> \ No newline at end of file
diff --git a/docs/html-ndk/ndk/guides/index.jd b/docs/html-ndk/ndk/guides/index.jd
index febeaab..465ce13 100644
--- a/docs/html-ndk/ndk/guides/index.jd
+++ b/docs/html-ndk/ndk/guides/index.jd
@@ -17,9 +17,9 @@ development process. However, it can be useful in cases in which you need to:</p
<p>This guide gives you the information you need to get up and running with the NDK. It starts by
explaining the <a href="{@docRoot}ndk/guides/concepts.html">concepts</a> underpinning the NDK, and
-how to <a href="{@docRoot}ndk/guides/setup.html">set it up</a>. Next, it explains how to use
-the NDK to <a href="{@docRoot}ndk/guides/build.html">build</a> and
-<a href="{@docRoot}ndk/guides/debug.html">debug</a> your app. Then, it continues with information
+how to <a href="{@docRoot}ndk/guides/setup.html">set it up</a>. Next, it continues with information
about targeting <a href="{@docRoot}ndk/guides/arch.html">different hardware platforms</a> in your
-builds. Finally, it discusses how to use your own and other prebuilt
-<a href="{@docRoot}ndk/guides/libs.html">libraries</a>.</p>
+builds. Then, it explains how to use
+the NDK to <a href="{@docRoot}ndk/guides/build.html">build</a> and
+<a href="{@docRoot}ndk/guides/debug.html">debug</a> your app. Finally, it discusses how to use your
+own and other prebuilt <a href="{@docRoot}ndk/guides/libs.html">libraries</a>.</p>
diff --git a/docs/html-ndk/ndk/guides/ndk-build.jd b/docs/html-ndk/ndk/guides/ndk-build.jd
index 9e3edda..18ca2d8 100644
--- a/docs/html-ndk/ndk/guides/ndk-build.jd
+++ b/docs/html-ndk/ndk/guides/ndk-build.jd
@@ -46,10 +46,8 @@ $ &lt;ndk&gt;/ndk-build
<p>In this example, <code>&lt;project&gt;</code> points to your
project’s root directory, and <code>&lt;ndk&gt;</code> is the directory where
-you installed the NDK. As noted in <a
-href="{@docRoot}ndk/guides/setup.html#install">Setup</a>, you can add {@code $NDK} to your
-{@code PATH} to avoid having to type the whole filepath every time you use ndk-build.
-Alternatively, you can create an alias.</p>
+you installed the NDK.</p>
+
<p><a class="anchor" id="options"></a> </p>
<h3>Options</h3>
<p>All parameters to ndk-build are passed directly to the underlying GNU {@code make}
diff --git a/docs/html-ndk/ndk/guides/prebuilts.jd b/docs/html-ndk/ndk/guides/prebuilts.jd
index f13e70e..52eb437 100644
--- a/docs/html-ndk/ndk/guides/prebuilts.jd
+++ b/docs/html-ndk/ndk/guides/prebuilts.jd
@@ -39,7 +39,7 @@ use cases for this functionality:</p>
library appropriate to your target ABI. For more information on ensuring library support for
ABIs, see <a href="#sa">Selecting ABIs for Prebuilt Libraries.</a></p></li>
<li>Include {@code PREBUILT_SHARED_LIBRARY} or {@code PREBUILT_STATIC_LIBRARY}, depending on
- whether you are using a shared ({@code .so}) or static {@code .a}) library.</li>
+ whether you are using a shared ({@code .so}) or static ({@code .a}) library.</li>
</ol>
<p>Here is a trivial example that assumes the prebuilt library {@code libfoo.so} resides in
diff --git a/docs/html-ndk/ndk/guides/standalone_toolchain.jd b/docs/html-ndk/ndk/guides/standalone_toolchain.jd
index 895f0fc..3b6f7f1 100644
--- a/docs/html-ndk/ndk/guides/standalone_toolchain.jd
+++ b/docs/html-ndk/ndk/guides/standalone_toolchain.jd
@@ -485,7 +485,7 @@ NEON functions.</p>
<p>You don't have to use any specific compiler flag when targeting the MIPS ABI.</p>
-<p>To learn more about ABI support, see <a href="{@docRoot}ndk/guides/x86.html">x86</a>.</p>
+<p>To learn more about ABI support, see <a href="{@docRoot}ndk/guides/x86.html">x86 Support</a>.</p>
<h2 id="war">Warnings and Limitations</h2>
<h3>Windows support</h3>
diff --git a/docs/html/distribute/googleplay/work/about.jd b/docs/html/distribute/googleplay/work/about.jd
index bd0f72b..20fec7a 100644
--- a/docs/html/distribute/googleplay/work/about.jd
+++ b/docs/html/distribute/googleplay/work/about.jd
@@ -55,7 +55,7 @@ page.image=images/distribute/gpfw.jpg
<li>Follow best practices for security and manage user data properly. Businesses
are more conscious of data security and employee productivity, especially when it
comes to features that share information with other services.</li>
- <li>Support the <a href="{@docRoot}training/enterprise/app-restrictions.html">App Configuration framework to let an administrator remotely configure app settings such as:
+ <li>Support the <a href="{@docRoot}training/enterprise/app-restrictions.html">App Configuration framework</a> to let an administrator remotely configure app settings such as:
<ul>
<li>Server address and protocol settings</li>
<li>The ability to switch features on and off</li>
diff --git a/docs/html/distribute/index.jd b/docs/html/distribute/index.jd
index c8928df..a6ece63 100644
--- a/docs/html/distribute/index.jd
+++ b/docs/html/distribute/index.jd
@@ -43,11 +43,11 @@ page.metaDescription=The most visited store in the world for Android apps. Cloud
<span class="dac-sprite dac-auto-chevron"></span>
Get started
</a></li>
- <li class="dac-section-link"><a href="/distribute/essentials/index.html#quality-guidelines">
+ <li class="dac-section-link"><a href="/distribute/essentials/index.html#guidelines">
<span class="dac-sprite dac-auto-chevron"></span>
Quality guidelines
</a></li>
- <li class="dac-section-link"><a href="/distribute/essentials/index.html#tools-and-resources">
+ <li class="dac-section-link"><a href="/distribute/essentials/index.html#tools">
<span class="dac-sprite dac-auto-chevron"></span>
Resources &amp; tools
</a></li>
diff --git a/docs/html/distribute/users/app-invites.jd b/docs/html/distribute/users/app-invites.jd
index ec9579d..e19e6eb 100644
--- a/docs/html/distribute/users/app-invites.jd
+++ b/docs/html/distribute/users/app-invites.jd
@@ -1,7 +1,7 @@
page.title=Smarter App Invites
page.metaDescription=Tap into your existing user base to increase downloads and increase conversions.
page.tags="google", "identity", "signin"
-page.image=distribute/images/advertising.jpg
+page.image=images/cards/card-app-invites_16-9_2x.png
@jd:body
diff --git a/docs/html/distribute/users/house-ads.jd b/docs/html/distribute/users/house-ads.jd
index d662fb2..ec73393 100644
--- a/docs/html/distribute/users/house-ads.jd
+++ b/docs/html/distribute/users/house-ads.jd
@@ -1,4 +1,4 @@
-page.title=Cross-Sell to Users with House Ads
+page.title=Cross-Sell with House Ads
page.metaDescription=Tap into your existing user base to increase downloads and increase conversions.
page.tags="google", "identity", "signin"
page.image=distribute/images/advertising.jpg
diff --git a/docs/html/distribute/users/index.jd b/docs/html/distribute/users/index.jd
index 4da4077..23f08c4 100644
--- a/docs/html/distribute/users/index.jd
+++ b/docs/html/distribute/users/index.jd
@@ -13,13 +13,13 @@ nonavpage=true
<div class="resource-widget resource-flow-layout landing col-16"
data-query="collection:distribute/users"
data-cardSizes="6x6"
- data-maxResults="9">
+ data-maxResults="15">
</div>
-<div class="resource-widget resource-flow-layout landing col-16"
+<!--<div class="resource-widget resource-flow-layout landing col-16"
data-query="collection:distribute/users"
data-cardSizes="9x3"
data-maxResults="16">
-</div>
+</div>-->
<!-- <h2>Related resources</h2>
diff --git a/docs/html/images/cards/card-app-invites_16-9_2x.png b/docs/html/images/cards/card-app-invites_16-9_2x.png
new file mode 100644
index 0000000..e0da07e
--- /dev/null
+++ b/docs/html/images/cards/card-app-invites_16-9_2x.png
Binary files differ
diff --git a/docs/html/images/cards/card-app-linking_2x.png b/docs/html/images/cards/card-app-linking_2x.png
new file mode 100644
index 0000000..abff805
--- /dev/null
+++ b/docs/html/images/cards/card-app-linking_2x.png
Binary files differ
diff --git a/docs/html/images/cards/card-auto-backup_2x.png b/docs/html/images/cards/card-auto-backup_2x.png
new file mode 100644
index 0000000..3c79ba9
--- /dev/null
+++ b/docs/html/images/cards/card-auto-backup_2x.png
Binary files differ
diff --git a/docs/html/images/cards/card-test-performance_2x.png b/docs/html/images/cards/card-test-performance_2x.png
new file mode 100644
index 0000000..fd949c8
--- /dev/null
+++ b/docs/html/images/cards/card-test-performance_2x.png
Binary files differ
diff --git a/docs/html/images/permissions_check.png b/docs/html/images/permissions_check.png
index bbbba4f..376d0fa 100644
--- a/docs/html/images/permissions_check.png
+++ b/docs/html/images/permissions_check.png
Binary files differ
diff --git a/docs/html/jd_collections.js b/docs/html/jd_collections.js
index d39bb0f..073feb8 100644
--- a/docs/html/jd_collections.js
+++ b/docs/html/jd_collections.js
@@ -125,7 +125,7 @@ var RESOURCE_COLLECTIONS = {
"https://developers.google.com/maps/documentation/android/",
"https://developers.google.com/identity/sign-in/android/",
"https://developers.google.com/mobile-ads-sdk/download",
- "https://devsite.googleplex.com/cloud-messaging/gcm",
+ "https://developers.google.com/cloud-messaging/gcm",
"https://developers.google.com/app-indexing/"
]
},
@@ -160,12 +160,15 @@ var RESOURCE_COLLECTIONS = {
"https://www.udacity.com/course/gradle-for-android-and-java--ud867"
]
},
- "preview/landing/herolinks": {
+ "preview/landing/more": {
"title": "",
"resources": [
- "https://www.udacity.com/course/ux-design-for-mobile-developers--ud849",
- "https://www.udacity.com/course/developing-android-apps--ud853",
- "https://www.udacity.com/course/android-performance--ud825"
+ "preview/features/runtime-permissions.html",
+ "preview/behavior-changes.html",
+ "preview/backup/index.html",
+ "preview/features/app-linking.html",
+ "preview/testing/guide.html",
+ "preview/testing/performance.html",
]
},
"distribute/landing/carousel": {
@@ -974,9 +977,8 @@ var RESOURCE_COLLECTIONS = {
"distribute/engage/gcm": {
"title": "",
"resources": [
- "https://devsite.googleplex.com/cloud-messaging/gcm",
- "http://developer.chrome.com/apps/cloudMessagingV2",
- "http://www.youtube.com/watch?v=y76rjidm8cU"
+ "https://developers.google.com/cloud-messaging/gcm",
+ "https://developers.google.com/cloud-messaging/android/client",
]
},
"distribute/engage/googleplaygames": {
diff --git a/docs/html/preview/api-changes.jd b/docs/html/preview/api-changes.jd
deleted file mode 100644
index 8ea91dd..0000000
--- a/docs/html/preview/api-changes.jd
+++ /dev/null
@@ -1,338 +0,0 @@
-page.title=Behavior Changes
-page.keywords=preview,sdk,compatibility
-page.tags=previewresources, androidm
-@jd:body
-
-<div id="qv-wrapper">
-<div id="qv">
-
-<h2>In this document</h2>
-
-<ol id="toc44" class="hide-nested">
- <li><a href="#behavior-runtime-permissions">Runtime Permissions</a></li>
- <li><a href="#behavior-notifications">Notifications</a></li>
- <li><a href="#behavior-openssl">OpenSSL</a></li>
- <li><a href="#behavior-project-volta">Project Volta</a>
- <ol>
- <li><a href="#behavior-doze">Doze Mode</a></li>
- <li><a href="#behavior-app-standby">App Standby Mode</a></li>
- </ol>
- </li>
- <li><a href="#behavior-adoptable-storage">Adoptable Storage Devices</a></li>
- <li><a href="#behavior-apache-http-client">Apache HTTP Client Removal</a></li>
- <li><a href="#behavior-audiomanager-Changes">AudioManager Changes</a></li>
- <li><a href="#behavior-test-selection">Text Selection</a></li>
- <li><a href="#behavior-keystore">Android Keystore Changes</a></li>
- <li><a href="#behavior-themeable-colorstatelists">Themeable ColorStateLists</a></li>
- <li><a href="#night-mode">Night Mode</a></li>
- <li><a href="#behavior-art-runtime">ART Runtime</a></li>
- <li><a href="#behavior-afw">Android for Work Changes</a></li>
-</ol>
-
-<h2>API Differences</h2>
-<ol>
-<li><a href="">API level 22 to M &raquo;</a> </li>
-</ol>
-
-
-<h2>See Also</h2>
-<ol>
-<li><a href="{@docRoot}preview/api-overview.html">M Developer Preview API Overview</a> </li>
-</ol>
-
-</div>
-</div>
-
-<p>API Level: M</p>
-<p>Along with new features and capabilities, M includes a variety of
-system changes and API behavior changes. This document highlights
-some of the key changes that you should be understand and account for in your apps.</p>
-
-<p>If you have previously published an app for Android, be aware that your app
- might be affected by these changes in M.</p>
-
-<h2 id="behavior-runtime-permissions">Runtime Permissions</h1>
-<p>This release introduces a new runtime permissions model, where users can now directly manage
-their app permissions at runtime. This model gives users improved visibility and control over
-permissions, while streamlining the installation and auto-update processes for app developers.
-Users can set permissions on or off for all apps running on Android M. However, apps that don’t
-target M cannot request permissions at runtime.</p>
-
-<p>On your apps that target M, make sure to check and request for permissions at
-runtime. To determine if your app has been granted a permission, call the
-new {@code Context.checkSelfPermission()} method. To request for a permission, call the new
-{@code Activity.requestPermission()} method.</p>
-
-<p>For more information on supporting the new permissions model in your app, see the
-<a href="{@docRoot}preview/features/runtime-permissions.html">
-Android M Runtime Permissions guide</a>.</p>
-
-<h2 id="behavior-openssl">OpenSSL</h2>
-<p>Android is moving away from OpenSSL to the
-<a href="https://boringssl.googlesource.com/boringssl/" class="external-link">BoringSSL</a>
-library. If you’re using the Android NDK in your app, don't link against cryptographic libraries
-that are not a part of the NDK API, such as {@code libcrypto.so} and {@code libssl.so}. These
-libraries are not public APIs, and may change or break without notice across releases and devices.
-In addition, you may expose yourself to security vulnerabilities. Instead, modify your
-native code to call the Java cryptography APIs via JNI or to statically link against a
-cryptography library of your choice.</p>
-
-<h2 id="behavior-project-volta">Project Volta</h2>
-<p>This release introduces new power-saving optimizations for idle devices and apps.</p>
-
-<h3 id="behavior-doze">Doze mode</h3>
-<p>If a device is unplugged and not used for up to an hour, it goes into <em>doze</em> mode where
-it attempts to keep the system in a sleep state. In this mode, devices may briefly resume normal
-operations for up to 5 minutes every few hours so that app syncing can occur and the system can
-perform any pending operations.</p>
-
-<p>The following restrictions apply to your apps while in device doze mode:</p>
-<ul>
-<li>Network access is disabled</li>
-<li>Alarms scheduled with the {@link android.app.AlarmManager} class are disabled, except for
-alarms that you've set with the
-{@link android.app.AlarmManager#setAlarmClock(android.app.AlarmManager.AlarmClockInfo,android.app.PendingIntent) setAlarmClock()}
-method</li>
-<li>WiFi scans are not performed</li>
-<li>Syncs and jobs for your sync adapters and {@link android.app.job.JobScheduler} are not
-permitted to run</li>
-</ul>
-</p>
-<p>When the system comes out of doze mode, it executes jobs and syncs that are pending.</p>
-
-<h3 id="behavior-app-standby">App standby mode</h3>
-<p>In M, the system may determine that apps are idle when they are not in active use by the user.
-Your app goes into <em>app standby</em> mode after two days unless the system detects any of these
-signals:</p>
-
-<ul>
-<li>The app has a process currently in the foreground (either as an activity or foreground service,
-or in use by another activity or foreground service)</li>
-<li>The app generates a notification that the user can see</li>
-<li>The user explicitly asks for the app to remain running</li>
-</ul>
-
-<p>If the system is running on battery power, apps that are in standby mode will have their
-network access disabled and their syncs and jobs suspended. When the system is plugged into a power
-supply, it brings an app out of standby mode and executes any jobs and syncs that are pending.</p>
-
-<p>Apps that use <a href="{@docRoot}google/gcm/index.html">Google Cloud Messaging</a> will
-continue to receive messages even if they are idle. When the system is plugged into a power
-supply, apps resume normal operations and can run any pending syncs and jobs.</p>
-
-<p>You can test this feature by connecting a device running M to your development machine and
-calling the following commands:
-</p>
-<pre>
-$ adb shell am broadcast -a android.os.action.DISCHARGING
-$ adb shell am set-idle &lt;packageName&gt; true
-$ adb shell am set-idle &lt;packageName&gt; false
-$ adb shell am get-idle &lt;packageName&gt;
-</pre>
-
-<h2 id="behavior-adoptable-storage">Adoptable Storage Devices</h2>
-<p>
-In M, users can adopt external storage devices such as SD cards. Adopting an external storage
-device encrypts and formats the device to behave like internal storage. This feature allows users
-to move both apps and private data of those apps between storage devices. When moving apps, the
-system respects the <a href="{@docRoot}guide/topics/manifest/manifest-element.html#install">
-{@code android:installLocation}</a> preference in the manifest.</p>
-
-<p>If your app accesses the following APIs or fields, be aware that the file paths they return
-will dynamically change when the app is moved between internal and external storage devices.
-When building file paths, it is strongly recommended that you always call these APIs dynamically.
-Don’t use hardcoded file paths or persist fully-qualified file paths that were built previously.</p>
-
-<ul>
-<li>{@link android.content.Context} methods:
- <ul>
- <li>{@link android.content.Context#getFilesDir() getFilesDir()}</li>
- <li>{@link android.content.Context#getCacheDir() getCacheDir()}</li>
- <li>{@link android.content.Context#getCodeCacheDir() getCodeCacheDir()}</li>
- <li>{@link android.content.Context#getDatabasePath(java.lang.String) getDatabasePath()}</li>
- <li>{@link android.content.Context#getDir(java.lang.String,int) getDir()}</li>
- <li>{@link android.content.Context#getNoBackupFilesDir() getNoBackupFilesDir()}</li>
- <li>{@link android.content.Context#getFileStreamPath(java.lang.String) getFileStreamPath()}</li>
- <li>{@link android.content.Context#getPackageCodePath() getPackageCodePath()}</li>
- <li>{@link android.content.Context#getPackageResourcePath() getPackageResourcePath()}</li>
- </ul>
-</li>
-<li>{@link android.content.pm.ApplicationInfo} fields:
- <ul>
- <li>{@link android.content.pm.ApplicationInfo#dataDir dataDir}</li>
- <li>{@link android.content.pm.ApplicationInfo#sourceDir sourceDir}</li>
- <li>{@link android.content.pm.ApplicationInfo#nativeLibraryDir nativeLibraryDir}</li>
- <li>{@link android.content.pm.ApplicationInfo#publicSourceDir publicSourceDir}</li>
- <li>{@link android.content.pm.ApplicationInfo#splitSourceDirs splitSourceDirs}</li>
- <li>{@link android.content.pm.ApplicationInfo#splitPublicSourceDirs splitPublicSourceDirs}</li>
- </ul>
-</li>
-</ul>
-
-<p>To debug this feature in the developer preview, you can enable adoption of a USB drive that is
-connected to an Android device through a USB On-The-Go (OTG) cable, by running these
-commands:</p>
-
-<pre>
-$ adb root
-$ sleep 2
-$ adb shell setprop persist.fw.force_adoptable 1
-$ adb reboot
-</pre>
-
-<h2 id="behavior-apache-http-client">Apache HTTP Client Removal</h2>
-<p>This release removes support for the Apache HTTP client. If your app is using this client and
-targets Android 2.3 (API level 9) or higher, use the {@link java.net.HttpURLConnection} class
-instead. This API is more efficient because it reduces network use through transparent compression
-and response caching, and minimizes power consumption. To continue using the Apache HTTP APIs, you
-must first declare the following compile-time dependency in your {@code build.gradle} file:
-</p>
-<pre>
-android {
- compileSdkVersion M
- useLibrary 'org.apache.http.legacy'
-}
-</pre>
-
-<h2 id="behavior-audiomanager-Changes">AudioManager Changes</h2>
-<p>Setting the volume directly or muting specific streams via the {@link android.media.AudioManager}
-class is no longer supported. The {@link android.media.AudioManager#setStreamSolo(int,boolean)
-setStreamSolo()} method is deprecated, and you should call the
-{@code AudioManager.requestAudioFocus()} method instead. Similarly, the
-{@link android.media.AudioManager#setStreamMute(int,boolean) setStreamMute()} method is
-deprecated; instead, call the {@code AudioManager.adjustStreamVolume()} method
-and pass in the direction value {@code ADJUST_MUTE} or {@code ADJUST_UNMUTE}.</p>
-
-<h2 id="behavior-test-selection">Text Selection</h2>
-
-<img src="{@docRoot}preview/images/text-selection.gif"
-style="float:right; margin:0 0 20px 30px" width="270" height="480" />
-
-<p>When users selects text in your app, you can now display text selection actions such as
-<em>Cut</em>, <em>Copy</em>, and <em>Paste</em> in a
-<a href="http://www.google.com/design/spec/patterns/selection.html#selection-text-selection"
-class="external-link">floating toolbar</a>. The user interaction implementation is similar to that
-for the contextual action bar, as described in
-<a href="{@docRoot}guide/topics/ui/menus.html#CABforViews">
-Enabling the contextual action mode for individual views</a>.</p>
-
-<p>To implement a floating toolbar for text selection, make the following changes in your existing
-apps:</p>
-<ol>
-<li>In your {@link android.view.View} or {@link android.app.Activity} object, change your
-{@link android.view.ActionMode} calls from
-{@code startActionMode(Callback)} to {@code startActionMode(Callback, ActionMode.TYPE_FLOATING)}.</li>
-<li>Take your existing implementation of ActionMode.Callback and make it extend
-{@code ActionMode.Callback2} instead.</li>
-<li>Override the {@code Callback2.onGetContentRect()} method to provide the coordinates of the
-content {@link android.graphics.Rect} object (such as a text selection rectangle) in the view.</li>
-<li>If the rectangle positioning is no longer valid, and this is the only element to be invalidated,
-call the {@code ActionMode.invalidateContentRect()} method.</li>
-</ol>
-
-<p>If you are using <a href="{@docRoot}tools/support-library/index.html">
-Android Support Library</a> revision 22.2, be aware that floating toolbars are not
-backward-compatible and appcompat takes control over {@link android.view.ActionMode} objects by
-default. This prevents floating toolbars from being displayed in M. To enable
-{@link android.view.ActionMode} support in an
-{@link android.support.v7.app.AppCompatActivity}, call
-{@code android.support.v7.app.AppCompatActivity.getDelegate()}, then call
-{@code android.support.v7.app.AppCompatDelegate.setHandleNativeActionModesEnabled()} on the returned
-{@link android.support.v7.app.AppCompatDelegate} object and set the input
-parameter to {@code false}. This call returns control of {@link android.view.ActionMode} objects to
-the framework. In devices running M, that allows the framework to support
-{@link android.support.v7.app.ActionBar} or floating toolbar modes, while on pre-M devices, only the
-{@link android.support.v7.app.ActionBar} modes are supported.</p>
-
-<h2 id="behavior-keystore">Android Keystore Changes</h2>
-<p>Starting this release, the
-<a href="{@docRoot}training/articles/keystore.html">Android Keystore provider</a> no longer supports
-DSA. ECDSA is still supported.</p>
-
-<p>Keys which do not require encryption at rest will no longer be deleted when secure lock screen
-is disabled or reset (for example, by the user or a Device Administrator). Keys which require
-encryption at rest will be deleted during these events.</p>
-
-<h2 id="behavior-themeable-colorstatelists">Themeable ColorStateLists</h2>
-<p>Theme attributes are now supported in
-{@link android.content.res.ColorStateList} for devices running M. The
-{@link android.content.res.Resources#getColorStateList(int) getColorStateList()} and
-{@link android.content.res.Resources#getColor(int) getColor()} methods have been deprecated. If
-you are calling these APIs, call the new {@code Context.getColorStateList()} or
-{@code Context.getColor()} methods instead. These methods are also available in the
-v4 appcompat library via {@link android.support.v4.content.ContextCompat}.</p>
-
-<h2 id="night-mode">Night Mode (User-configurable Dark Theme)</h2>
-<p>
-Support for the {@code -night} resource qualifier has been updated in M. Previously, night mode was
-only available when a device was docked and in car mode. Starting in M, night mode is available on
-all devices and is user-configurable via <em>Settings > Display > Theme</em>. You can adjust this
-setting globally using {@link android.app.UiModeManager#setNightMode(int) setNightMode()}. The
-Dark theme corresponds to {@link android.app.UiModeManager#MODE_NIGHT_YES}. When the device is in
-night mode, the resource framework will prefer resources that have the -night qualifier. To
-take advantage of user-configurable Dark mode in your app, extend from the
-{@code Theme.Material.DayNight} set of themes rather than {@code Theme.Material} or
-{@code Theme.Material.Light}.
-</p>
-
-<h2 id="behavior-art-runtime">ART Runtime</h2>
-<p>The ART runtime now properly implements access rules for the
-{@link java.lang.reflect.Constructor#newInstance(java.lang.Object...) newInstance()} method. This
-change fixes a problem where Dalvik was checking access rules incorrectly in previous versions.
-If your app uses the
-{@link java.lang.reflect.Constructor#newInstance(java.lang.Object...) newInstance()} method and you
-want to override access checks, call the
-{@link java.lang.reflect.Constructor#setAccessible(boolean) setAccessible()} method with the input
-parameter set to {@code true}. If your app uses the
-<a href="{@docRoot}tools/support-library/features.html#v7">v7 appcompat library</a> or the
-<a href="{@docRoot}tools/support-library/features.html#v7-recyclerview">v7 recyclerview library</a>,
-you must update your app to use to the latest versions of these libraries. Otherwise, make sure that
-any custom classes referenced from XML are updated so that their class constructors are accessible.</p>
-
-<p>The M release updates the behavior of the dynamic linker. The dynamic linker now understands the
-difference between a library’s {@code soname} and its path
-(<a href="https://code.google.com/p/android/issues/detail?id=6670" class="external-link">
-public bug 6670</a>), and search by {@code soname} is now
-implemented. Apps which previously worked that have bad {@code DT_NEEDED} entries
-(usually absolute paths on the build machine’s file system) may fail when loaded on M.</p>
-
-<p>The {@code dlopen(3) RTLD_LOCAL} flag is now correctly implemented in M. Note that
-{@code RTLD_LOCAL} is the default, so calls to {@code dlopen(3)} that didn’t explicitly use
-{@code RTLD_LOCAL} will be affected (unless your app explicitly used {@code RTLD_GLOBAL}). With
-{@code RTLD_LOCAL}, symbols will not be made available to libraries loaded by later calls to
-{@code dlopen(3)} (as opposed to being referenced by {@code DT_NEEDED} entries).</p>
-</p>
-
-<h2 id="behavior-afw">Android for Work Changes</h2>
-<p>This release includes the following behavior changes for Android for Work:</p>
-<ul>
-<li><strong>Work contacts in personal contexts.</strong> Google Messenger and the Google Dialer
-Call Log now display work contacts when the user views past messages or calls. Furthermore, both
-work and personal contacts are now available to devices over Bluetooth, but you can hide work
-profile contacts through a device policy by calling the new
-{@code DevicePolicyManager.setBluetoothContactSharingDisabled()} method. Initiating a call or
-creating a new message will only show personal contacts, as consistent with the experience in
-Android 5.0.
-</li>
-<li><strong>WiFi configuration removal:</strong> WiFi configurations added by a Profile Owner
-(for example, through calls to the
-{@link android.net.wifi.WifiManager#addNetwork(android.net.wifi.WifiConfiguration)
-addNetwork()} method) are now removed if that work profile is deleted.</li>
-<li><strong>WiFi configuration lockdown:</strong> Any WiFi configuration created by an active Device
-Owner can no longer be modified or deleted by the user. The user can still create and
-modify their own WiFi configurations, so long as the {@link android.os.UserManager} constant
-{@link android.os.UserManager#DISALLOW_CONFIG_WIFI} has not been set for that user.</li>
-<li><strong>VPN in Settings:</strong> VPN apps are now visible in <em>Settings > More > VPN</em>.
-Additionally, the notifications that accompany VPN usage are now specific to whether that VPN is
-configured for a managed profile or the entire device.</li>
-<li><strong>Work status notification:</strong> A status bar briefcase icon now appears whenever
-an app from the managed profile has an activity in the foreground. Furthermore, if the device is
-unlocked directly to the activity of an app in the managed profile, a toast is displayed notifying
-the user that they are within the work profile.
-</li>
-<li><strong>Download Work Policy Controller via Google account addition:</strong> When a Google
-account that requires management via a Work Policy Controller (WPC) app is added to a device
-outside of a managed context, the add account flow now prompts the user to install the
-appropriate WPC. This behavior also applies to accounts added via
-<em>Settings > Accounts</em> in the initial device setup wizard.</li>
-</ul>
diff --git a/docs/html/preview/api-overview.jd b/docs/html/preview/api-overview.jd
index 5fd6bb8..b8a6033 100644
--- a/docs/html/preview/api-overview.jd
+++ b/docs/html/preview/api-overview.jd
@@ -165,11 +165,11 @@ method to re-authenticate the user within your app.
<p>To see an app implementation of this feature, refer to the
<a href="https://github.com/googlesamples/android-ConfirmCredentials" class="external-link">
- Confirm Device Credentials sample</a>.</p>
+ Confirm Credentials sample</a>.</p>
<h2 id="direct-share">Direct Share</h2>
-<img src="{@docRoot}preview/images/direct-share-screen_2x.png"
+<img src="{@docRoot}preview/images/direct-share-screen.png"
srcset="{@docRoot}preview/images/direct-share-screen.png 1x, preview/images/direct-share-screen_2x.png 2x"
style="float:right; margin:0 0 20px 30px" width="312" height="335" />
diff --git a/docs/html/preview/backup/index.jd b/docs/html/preview/backup/index.jd
index c7d85ae..6735379 100644
--- a/docs/html/preview/backup/index.jd
+++ b/docs/html/preview/backup/index.jd
@@ -1,7 +1,7 @@
page.title=Auto Backup for Apps
page.tags=backup, previewresources, androidm
page.keywords=backup, autobackup, preview
-
+page.image=images/cards/card-auto-backup_2x.png
@jd:body
<div id="qv-wrapper">
diff --git a/docs/html/preview/behavior-changes.jd b/docs/html/preview/behavior-changes.jd
index 568d46e..9b3dbab 100644
--- a/docs/html/preview/behavior-changes.jd
+++ b/docs/html/preview/behavior-changes.jd
@@ -1,6 +1,6 @@
page.title=Behavior Changes
page.keywords=preview,sdk,compatibility
-sdk.platform.apiLevel=22-mnc
+sdk.platform.apiLevel=MNC
@jd:body
<div id="qv-wrapper">
@@ -44,7 +44,7 @@ sdk.platform.apiLevel=22-mnc
<p>Along with new features and capabilities, the M Developer Preview includes a variety of
system changes and API behavior changes. This document highlights
-some of the key changes that you should be understand and account for in your apps.</p>
+some of the key changes that you should understand and account for in your apps.</p>
<p>If you have previously published an app for Android, be aware that your app
might be affected by these changes in the platform.</p>
diff --git a/docs/html/preview/data-binding/guide.jd b/docs/html/preview/data-binding/guide.jd
deleted file mode 100644
index 49b690f..0000000
--- a/docs/html/preview/data-binding/guide.jd
+++ /dev/null
@@ -1,908 +0,0 @@
-page.title=Data Binding Guide
-
-@jd:body
-<p>Data Binding allows you write declarative layouts and minimize the glue code
-that is necessary to bind your application logic and layouts.</p>
-
-
-<h2 id=build_environment>Build Environment</h2>
-
-
-<p><strong>Setting Up Work Environment:</strong></p>
-
-<p>Data Binding EAP only supports gradle.</p>
-
-<p>To set up your application, unzip the provided bundle to a location. It has 3
-sections</p>
-
-<ul>
- <li> <em>maven-repo:</em> which keeps the data-binding libraries
- <li> <em>samples:</em> Sample applications
- <li> <em>databinding.properties:</em> Properties file that can be used to integrate with your app
-</ul>
-
-<p>Add the following section to the project’s build.gradle file (not the module&apos;s
-build.gradle) and replace <code><BUNDLE_FOLDER> </code>with the absolute path of the bundle that you’ve unzipped in the previous step.</p>
-
-<pre class=prettyprint>
-buildscript {
- <strong>def </strong>eapFolder = &apos;&lt;BUNDLE_FOLDER>&apos;
-<strong> def </strong>Properties props = <strong>new </strong>Properties()
- props.load(<strong>new </strong>FileInputStream(<strong>"</strong>${eapFolder}<strong>/databinding.properties"</strong>))
- props.mavenRepoDir = <strong>"</strong>${eapFolder}<strong>/</strong>${props.mavenRepoName}<strong>"
- </strong>ext.config = props
- repositories {
- jcenter()
- maven {
- url config.mavenRepoDir
- }
- }
- dependencies {
- classpath <strong>"com.android.tools.build:gradle:1.1.3"
- </strong>classpath <strong>"com.android.databinding:dataBinder:</strong>${config.snapshotVersion}<strong>"
-<em></strong> </em>}
-}
-allprojects {
- repositories {
- jcenter()
- maven {
- url config.mavenRepoDir
- }
- }
-}
-</pre>
-
-<p>Next, add the following lines to the <em>build.gradle</em>
-file of each module that will use data-binding. The application module must
-have this, even if only its libraries use data binding.</p>
-
-<pre class=prettyprint>
-apply plugin: <strong>&apos;com.android.databinding&apos;
-</strong>dependencies {
- compile <strong>"com.android.databinding:library:</strong>${config.snapshotVersion}<strong>"
-</strong> compile <strong>"com.android.databinding:baseLibrary:</strong>${config.snapshotVersion}<strong>"
-</strong> compile <strong>"com.android.databinding:adapters:</strong>${config.snapshotVersion}<strong>"
-</strong> provided <strong>"com.android.databinding:annotationprocessor:</strong>${config.snapshotVersion}<strong>"
-</strong>}
-</pre>
-
-
-<h2 id="data_binding_layout_files">Data Binding Layout Files</h2>
-
-
-<h3 id="writing_expressions">Writing your first data binding expressions:</h3>
-
-<p>Data-binding layout files are slightly different and start with a root tag of
-<strong>layout</strong> followed by a <strong>data</strong> element and a
-<strong>view</strong> root element. This view element is what your root would
-be in a non-binding layout file.A sample file looks like this:</p>
-
-<pre class=prettyprint>
-<em>&lt;?<strong></em>xml version="1.0" encoding="utf-8"<em></strong>?>
-</em>&lt;<strong>layout xmlns:android="http://schemas.android.com/apk/res/android"</strong>>
- &lt;<strong>data</strong>>
- &lt;<strong>variable name="user" type="com.example.User"</strong>/>
- &lt;/<strong>data</strong>>
- &lt;<strong>LinearLayout
- android:orientation="vertical"
- android:layout_width="match_parent"
- android:layout_height="match_parent"</strong>>
- &lt;<strong>TextView android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="&commat;{user.firstName}"</strong>/>
- &lt;<strong>TextView android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="&commat;{user.lastName}"</strong>/>
- &lt;/<strong>LinearLayout</strong>>
-&lt;/<strong>layout</strong>>
-</pre>
-
-<p>The user <strong>variable</strong> within <strong>data</strong> describes a property that may be used within this layout.</p>
-
-<pre class=prettyprint>
-&lt;<strong>variable name="user" type="com.example.User"</strong>/>
-</pre>
-
-<p>Expressions within the layout are written in the attribute properties using the
-“<code>&commat;{}</code>” syntax. Here, the TextView’s text is set to the firstName property of user:</p>
-<pre class=prettyprint>
-&lt;<strong>TextView android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="&commat;{user.firstName}"</strong>/>
-</pre>
-
-
-<h3 id="data_object">Data Object</h3>
-
-<p>Let’s assume for now that you have a plain-old Java object (POJO) for User:</p>
-<pre class=prettyprint>
-<strong>public class </strong>User {
- <strong>public final </strong>String <strong>firstName</strong>;
- <strong>public final </strong>String <strong>lastName</strong>;
- <strong>public </strong>User(String firstName, String lastName) {
- <strong>this</strong>.<strong>firstName </strong>= firstName;
- <strong>this</strong>.<strong>lastName </strong>= lastName;
- }
-}
-</pre>
-
-<p>This type of object has data that never changes. It is common in applications
-to have data that is read once and never changes thereafter. It is also
-possible to use a JavaBeans objects:</p>
-<pre class=prettyprint>
-<strong>public class </strong>User {
- <strong>private final </strong>String <strong>firstName</strong>;
- <strong>private final </strong>String <strong>lastName</strong>;
- <strong>public </strong>User(String firstName, String lastName) {
- <strong>this</strong>.<strong>firstName </strong>= firstName;
- <strong>this</strong>.<strong>lastName </strong>= lastName;
- }
- <strong>public </strong>String getFirstName() {
- <strong>return this</strong>.<strong>firstName</strong>;
- }
- <strong>public </strong>String getLastName() {
- <strong>return this</strong>.<strong>lastName</strong>;
- }
-}
-</pre>
-
-<p>From the perspective of data binding, these two classes are equivalent. The
-expression <strong><code>&commat;{user.lastName}</code></strong> used for the TextView’s <strong><code>android:text</code></strong> attribute will access the <strong><code>firstName</code></strong> field in the former class and the <code>getFirstName()</code> method in the latter class.
-</p><h3 id=binding_data>Binding Data</h3>
-
-<p>By default, a Binding class will be generated based on the name of the layout
-file, converting it to Pascal case and suffixing “Binding” to it. The above
-layout file was <code>activity_main.xml</code> so the generate class was <code>ActivityMainBinding</code>. This class holds all the bindings from the layout properties (e.g. the <code>user</code> variable) to the layout’s Views and knows how to assign values for the binding
-expressions.The easiest means for creating the bindings is to do it while inflating:
-</p>
-
-<pre class=prettyprint>
-&commat;Override
-<strong>protected void </strong>onCreate(Bundle savedInstanceState) {
- <strong>super</strong>.onCreate(savedInstanceState);
- ActivityMainBinding binding = DataBindingUtil.<em>setContentView</em>(<strong>this</strong>, R.layout.<em><strong>main_activity</strong></em>);
- User user = <strong>new </strong>User(<strong>"Test"</strong>, <strong>"User"</strong>);
- binding.setUser(user);
-}
-</pre>
-
-<p>You’re done! Run the application and you’ll see Test User in the UI.Alternatively, you can get the view via:
-</p><pre class=prettyprint>
-MainActivityBinding binding = MainActivityBinding.<em>inflate</em>(getLayoutInflater());
-</pre>
-
-<p>If you are using data binding items inside a ListView or RecyclerView adapter,
-you may prefer to use:
-</p><pre class=prettyprint>
-ListItemBinding binding = ListItemBinding.inflate(layoutInflater, viewGroup,
-false);
-//or
-ListItemBinding binding = DataBindingUtil.<em>inflate</em>(layoutInflater, R.layout.<em><strong>list_item</strong></em>, viewGroup, <strong>false</strong>);
-</pre>
-
-
-<h2 id=layout_details>Layout Details</h2>
-
-
-<h3 id=imports>Imports</h3>
-
-<p>Zero or more <strong><code>import</code></strong> elements may be used inside the <strong><code>data</code></strong> element. These allow easy reference to classes inside your layout file, just
-like in Java.
-</p><pre class=prettyprint>
-&lt;<strong>data</strong>>
- &lt;<strong>import type="android.view.View"</strong>/>
-&lt;/<strong>data</strong>>
-</pre>
-
-<p>Now, View may be used within your binding expression:
-</p><pre class=prettyprint>
-&lt;<strong>TextView
- android:text="&commat;{user.lastName}"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:visibility="&commat;{user.isAdult ? View.VISIBLE : View.GONE}"</strong>/>
-</pre>
-
-<p>When there are class name conflicts, one of the classes may be renamed to an
-“alias:”</p>
-<pre class=prettyprint>
-&lt;<strong>import type="android.view.View"</strong>/>
-&lt;<strong>import type="com.example.real.estate.View"
- alias="Vista"</strong>/>
-</pre>
-
-<p>Now, <strong><code>Vista</code></strong> may be used to reference the <code>com.example.real.estate.View</code> and <strong><code>View</code></strong> may be used to reference <code>android.view.View </code>within the layout file.Imported types may be used as type references in variables and expressions:</p>
-<pre class=prettyprint>
-&lt;<strong>data</strong>>
- &lt;<strong>import type="com.example.User"</strong>/>
- &lt;<strong>import type="java.util.List"</strong>/>
- &lt;<strong>variable name="user" type="User"</strong>/>
- &lt;<strong>variable name="userList" type="List&lt;User&gt;"</strong>/>
-&lt;/<strong>data</strong>>
-…
-&lt;<strong>TextView
- android:text="&commat;{((User)(user.connection)).lastName}"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"</strong>/>
-</pre>
-
-<p>Imported types may also be used when referencing static fields and methods in
-expressions:</p>
-<pre class=prettyprint>
-&lt;<strong>data</strong>>
- &lt;<strong>import type="com.example.MyStringUtils"</strong>/>
- &lt;<strong>variable name="user" type="com.example.User"</strong>/>
-&lt;/<strong>data</strong>>
-…
-&lt;<strong>TextView
- android:text="&commat;{MyStringUtils.capitalize(user.lastName)}"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"</strong>/>
-</pre>
-
-<p>Just as in Java, <code>java.lang.*</code> is imported automatically.</p>
-<h3 id=variables>Variables</h3>
-
-<p>Any number of <strong><code>variable</code></strong> elements may be used inside the <strong><code>data</code></strong> element. Each <strong><code>variable</code></strong> element describes a property that may be set on the layout to be used in
-binding expressions within the layout file.</p>
-<pre class=prettyprint>
-&lt;<strong>data</strong>>
- &lt;<strong>import type="android.graphics.drawable.Drawable"</strong>/>
- &lt;<strong>variable name="user" type="com.example.User"</strong>/>
- &lt;<strong>variable name="image" type="Drawable"</strong>/>
- &lt;<strong>variable name="note" type="String"</strong>/>
-&lt;/<strong>data</strong>>
-</pre>
-
-<p>The variable types are inspected at compile time, so if a variable implements <a href="#observable_objects">Observable</a>, <a href="#observable_collections">observable collection</a>, that should be reflected in the type. If the variable is a base class or
- interface that does not implement the Observable* interface, the variables will <strong>not be</strong> observed!</p>
-
-<p>When there are different layout files for various configurations (e.g.
-landscape or portrait), the variables will be combined. There must not be
-conflicting variable definitions between these layout files.</p>
-
-<p>The generated binding class will have a setter and getter for each of the
-described variables. The variables will take the default Java values until the
-setter is called &mdash; <code>null</code> for reference types, <code>0</code> for <code>int</code>, <code>false</code> for <code>boolean</code>, etc.</p>
-
-<h3 id=custom_binding_class_names>Custom Binding Class Names</h3>
-
-<p>By default, a Binding class is generated based on the name of the layout file,
-starting it with upper-case, removing underscores ( _ ) and capitalizing the
-following letter and then suffixing “Binding”. This class will be placed in a
-databinding package under the module package. For example, the layout file <code>contact_item.xml</code> will generate <code>ContactItemBinding</code>. If the module package is <code>com.example.my.app</code>, then it will be placed in <code>com.example.my.app.databinding</code>.</p>
-
-<p>Binding classes may be renamed or placed in different packages by adjusting the <strong><code>class</code></strong> attribute of the <strong><code>data</code></strong> element. For example:</p>
-<pre class=prettyprint>
-&lt;<strong>data class="ContactItem"</strong>>
- ...
-&lt;/<strong>data</strong>>
-</pre>
-
-<p>This generates the binding class as <code>ContactItem</code> in the databinding package in the module package. If the class should be
-generated in a different package within the module package, it may be prefixed
-with “.”:</p>
-<pre class=prettyprint>
-&lt;<strong>data class=".ContactItem"</strong>>
- ...
-&lt;/<strong>data</strong>>
-</pre>
-
-In this case, <code>ContactItem</code> is generated in the module package directly.Any package may be used if the full package is provided:
-<pre class=prettyprint>
-&lt;<strong>data class="com.example.ContactItem"</strong>>
- ...
-&lt;/<strong>data</strong>>
-</pre>
-
-
-<h3 id=includes>Includes</h3>
-
-<p>Variables may be passed into an included layout&apos;s binding from the containing
-layout by using the application namespace and the variable name in an
-attribute:</p>
-<pre class=prettyprint>
-<em>&lt;?<strong></em>xml version="1.0" encoding="utf-8"<em></strong>?>
-</em>&lt;<strong>layout xmlns:android="http://schemas.android.com/apk/res/android"
-</strong> <strong> xmlns:bind="http://schemas.android.com/apk/res-auto"</strong>>
- &lt;<strong>data</strong>>
- &lt;<strong>variable name="user" type="com.example.User"</strong>/>
- &lt;/<strong>data</strong>>
- &lt;<strong>LinearLayout
- android:orientation="vertical"
- android:layout_width="match_parent"
- android:layout_height="match_parent"</strong>>
- &lt;<strong>include layout="&commat;layout/name"
- bind:user="&commat;{user}"</strong>/>
- &lt;<strong>include layout="&commat;layout/contact"
- bind:user="&commat;{user}"</strong>/>
- &lt;/<strong>LinearLayout</strong>>
-&lt;/<strong>layout</strong>>
-</pre>
-
-<p>Here, there must be a <code>user</code> variable in both the <code>name.xml </code>and <code>contact.xml </code>layout files.</p>
-<h3 id=expression_language>Expression Language</h3>
-
-
-<h4 id=common_features>Common Features</h4>
-
-<p>The expression language looks a lot like a Java expression. These are the same:</p>
-<ul>
- <li> Mathematical <strong><code>+ - / * %</code></strong>
- <li> String concatenation <strong><code>+</code></strong>
- <li> <code>L</code>ogical <strong><code>&& ||</code></strong>
- <li> Binary <strong><code>&</code> <code>|</code> <code>^</code></strong>
- <li> Unary <strong><code>+ - ! ~</code></strong>
- <li> Shift <strong><code>>> >>> <<</code></strong>
- <li> Comparison <strong><code>== > < >= <=</code></strong>
- <li> <strong><code>instanceof</code></strong>
- <li> Grouping <strong><code>()</code></strong>
- <li> Literals - character, String, numeric, <strong><code>null</code></strong>
- <li> Cast
- <li> Method calls
- <li> Field access
- <li> Array access <strong><code>[]</code></strong>
- <li> Ternary operator <strong><code>?:</code></strong>
-</ul>
-<p>Examples:</p>
-<pre class=prettyprint>
-<strong>android:text="&commat;{String.valueOf(index + 1)}"
-android:visibility="&commat;{age &lt; 13 ? View.GONE : View.VISIBLE}"
-android:transitionName=&apos;&commat;{"image_" + id}&apos;</strong>
-</pre>
-
-
-<h4 id=missing_operations>Missing Operations</h4>
-
-<p>A few operations are missing from the expression syntax that you can use in
-Java.</p>
-<ul>
- <li> <strong><code>this</code></strong>
- <li> <strong><code>super</code></strong>
- <li> <strong><code>new</code></strong>
- <li> Explicit generic invocation
-</ul>
-
-<h4 id=null_coalescing_operator>Null Coalescing Operator</h4>
-
-<p>The null coalescing operator (<strong><code>??</code></strong>) chooses the left operand if it is not null or the right if it is null.</p>
-<pre class=prettyprint>
-<strong>android:text="&commat;{user.displayName ?? user.lastName}"</strong>
-</pre>
-
-<p>This is functionally equivalent to:</p>
-<pre class=prettyprint>
-<strong>android:text="&commat;{user.displayName != null ? user.displayName : user.lastName}"</strong>
-</pre>
-
-
-<h4 id=property_reference>Property Reference</h4>
-
-<p>The first was already discussed in the <a href="#writing_your_first_data_binding_expressions">Writing your first data binding expressions</a> above: short form JavaBean references. When an expression references a
-property on a class, it uses the same format for fields, getters, and
-ObservableFields.</p>
-<pre class=prettyprint>
-<strong>android:text="&commat;{user.lastName}"</strong>
-</pre>
-
-
-<h4 id=collections>Collections</h4>
-
-<p>Common collections: arrays, lists, sparse lists, and maps, may be accessed
-using the <code>[]</code> operator for convenience.</p>
-<pre class=prettyprint>
-&lt;<strong>data</strong>>
- &lt;<strong>import type="android.util.SparseArray"</strong>/>
- &lt;<strong>import type="java.util.Map"</strong>/>
- &lt;<strong>import type="java.util.List"</strong>/>
- &lt;<strong>variable name="list" type="List&lt;String&gt;"</strong>/>
- &lt;<strong>variable name="sparse" type="SparseArray&lt;String&gt;"</strong>/>
- &lt;<strong>variable name="map" type="Map&lt;String, String&gt;"</strong>/>
- &lt;<strong>variable name="index" type="int"</strong>/>
- &lt;<strong>variable name="key" type="String"</strong>/>
-&lt;/<strong>data</strong>>
-…
-<strong>android:text="&commat;{list[index]}"
-</strong>…
-<strong>android:text="&commat;{sparse[index]}"
-</strong>…
-<strong>android:text="&commat;{map[key]}"
-</strong>
-</pre>
-
-
-<h4 id=string_literals>String Literals</h4>
-
-<p>When using single quotes around the attribute value, it is easy to use double
-quotes in the expression:</p>
-<pre class=prettyprint>
-<strong>android:text=&apos;&commat;{map["firstName"]}&apos;</strong>
-</pre>
-
-<p>It is also possible to use double quotes to surround the attribute value. When
-doing so, String literals should either use the &quot; or back quote (`).</p>
-<pre class=prettyprint>
-<strong>android:text="&commat;{map[`firstName`}"
-android:text="&commat;{map[&quot;firstName&quot;]}"</strong>
-</pre>
-
-
-<h4 id=resources>Resources</h4>
-
-<p>It is possible to access resources as part of expressions using the normal
-syntax:</p>
-<pre class=prettyprint>
-<strong>android:padding="&commat;{large? &commat;dimen/largePadding : &commat;dimen/smallPadding}"</strong>
-</pre>
-
-<p>Format strings and plurals may be evaluated by providing parameters:</p>
-<pre class=prettyprint>
-<strong>android:text="&commat;{&commat;string/nameFormat(firstName, lastName)}"
-android:text="&commat;{&commat;plurals/banana(bananaCount)}"</strong>
-</pre>
-
-<p>Some resources require explicit type evaluation.</p>
-
-<table>
- <tr>
- <th>Type</th>
- <th>Normal Reference</th>
- <th>Expression Reference</th>
- </tr>
- <tr>
- <td>
-<pre class=prettyprint>
-String[]</td>
- <td>
-&commat;array</td>
- <td>
-&commat;stringArray</td>
- </tr>
- <tr>
- <td>
-int[]</td>
- <td>
-&commat;array</td>
- <td>
-&commat;intArray</td>
- </tr>
- <tr>
- <td>
-TypedArray</td>
- <td>
-&commat;array</td>
- <td>
-&commat;typedArray</td>
- </tr>
- <tr>
- <td>
-Animator</td>
- <td>
-&commat;animator</td>
- <td>
-&commat;animator</td>
- </tr>
- <tr>
- <td>
-StateListAnimator</td>
- <td>
-&commat;animator</td>
- <td>
-&commat;stateListAnimator</td>
- </tr>
- <tr>
- <td>
-</pre>
-
-color <code>int</code></td>
- <td>
-<pre class=prettyprint>
-&commat;color</td>
- <td>
-&commat;color</td>
- </tr>
- <tr>
- <td>
-ColorStateList</td>
- <td>
-&commat;color</td>
- <td>
-&commat;colorStateList</td>
- </tr>
-</table>
-
-</pre>
-
-
-<h2 id="data_objects">Data Objects</h2>
-
-
-<p>Any plain old Java object (POJO) may be used for data binding, but modifying a
-POJO will not cause the UI to update. The real power of data binding can be
-used by giving your data objects the ability to notify when data changes. There
-are three different data change notification mechanisms, <code>Observable </code>objects, <code>ObservableField</code>s, and <code>observable collections</code>.</p>
-
-<p>When one of these observable data object is bound to the UI and a property of
-the data object changes, the UI will be updated automatically.</p>
-
-<h3 id=observable_objects>Observable Objects</h3>
-
-
-<p>A class implementing <code>android.databinding.Observable</code> interface will allow the binding to attach a single listener to a bound object
-to listen for changes of all properties on that object.</p>
-
-<p>The <code>Observable</code> interface has a mechanism to add and remove listeners, but notifying is up to
-the developer. To make development easier, a base class, <code>BaseObservable,</code> was created to implement the listener registration mechanism. The data class
-implementer is still responsible for notifying when the properties change. This
-is done by assigning an <code>Bindable </code>annotation to the getter and notifying in the setter.</p>
-
-<pre class=prettyprint>
-<strong>private static class </strong>User <strong>extends </strong>BaseObservable {
- <strong>private </strong>String <strong>firstName</strong>;
- <strong>private </strong>String <strong>lastName</strong>;
- &commat;Bindable
- <strong>public </strong>String getFirstName() {
- <strong>return this</strong>.<strong>firstName</strong>;
- }
- &commat;Bindable
- <strong>public </strong>String getFirstName() {
- <strong>return this</strong>.<strong>lastName</strong>;
- }
- <strong>public void </strong>setFirstName(String firstName) {
- <strong>this</strong>.<strong>firstName </strong>= firstName;
- notifyPropertyChanged(BR.firstName);
- }
- <strong>public void </strong>setLastName(String lastName) {
- <strong>this</strong>.<strong>lastName </strong>= lastName;
- notifyPropertyChanged(BR.lastName);
- }
-}
-</pre>
-
-<p>The <code>Bindable </code>annotation generates an entry in the BR class file during compilation. The BR
-class file will be generated in the module package.If the base class for data classes cannot be changed, the <code>Observable</code> interface may be implemented using the convenient <code>PropertyChangeRegistry</code> to store and notify listeners efficiently.</p>
-
-<h3 id=observablefields>ObservableFields</h3>
-
-<p>A little work is involved in creating Observable classes, so developers who
-want to save time or have few properties may use ObservableFields.
-ObservableFields are self-contained observable objects that have a single
-field. There are versions for all primitive types and one for reference types.
-To use, create a public final field in the data class:</p>
-<pre class=prettyprint>
-<strong>private static class </strong>User <strong>extends </strong>BaseObservable {
- <strong>public final </strong>ObservableField&lt;String> <strong>firstName </strong>=
- <strong>new </strong>ObservableField&lt;>();
- <strong>public final </strong>ObservableField&lt;String> <strong>lastName </strong>=
- <strong>new </strong>ObservableField&lt;>();
- <strong>public final </strong>ObservableInt <strong>age </strong>= <strong>new </strong>ObservableInt();
-}
-</pre>
-
-<p>That&apos;s it! To access the value, use the set and get accessor methods:</p>
-<pre class=prettyprint>
-user.<strong>firstName</strong>.set(<strong>"Google"</strong>);
-<strong>int </strong>age = user.<strong>age</strong>.get();
-</pre>
-
-
-<h3 id=observable_collections>Observable Collections</h3>
-
-<p>Some applications use more dynamic structures to hold data. Observable
- collections allow keyed access to these data objects.ObservableArrayMap is useful when the key is a reference type, such as String.</p>
-
-<pre class=prettyprint>
-ObservableArrayMap&lt;String, Object> user = <strong>new </strong>ObservableArrayMap&lt;>();
-user.put(<strong>"firstName"</strong>, <strong>"Google"</strong>);
-user.put(<strong>"lastName"</strong>, <strong>"Inc."</strong>);
-user.put(<strong>"age"</strong>, 17);
-</pre>
-
-In the layout, the map may be accessed through the String keys:
-<pre class=prettyprint>
-&lt;<strong>data</strong>>
- &lt;<strong>import type="android.databinding.ObservableMap"</strong>/>
- &lt;<strong>variable name="user" type="ObservableMap&lt;String, Object>"</strong>/>
-&lt;/<strong>data</strong>>
-…
-&lt;<strong>TextView
- android:text=&apos;&commat;{user["lastName"]}&apos;
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"</strong>/>
-&lt;<strong>TextView
- android:text=&apos;&commat;{String.valueOf(1 + (Integer)user["age"])}&apos;
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"</strong>/>
-</pre>
-
-<p>ObservableArrayList is useful when the key is an integer:</p>
-<pre class=prettyprint>
-ObservableArrayList&lt;Object> user = <strong>new </strong>ObservableArrayList&lt;>();
-user.add(<strong>"Google"</strong>);
-user.add(<strong>"Inc."</strong>);
-user.add(17);
-</pre>
-
-<p>In the layout, the list may be accessed through the indices:</p>
-<pre class=prettyprint>
-&lt;<strong>data</strong>>
- &lt;<strong>import type="android.databinding.ObservableList"</strong>/>
- &lt;<strong>import type="com.example.my.app.Fields"</strong>/>
- &lt;<strong>variable name="user" type="ObservableList&lt;Object>"</strong>/>
-&lt;/<strong>data</strong>>
-…
-&lt;<strong>TextView
- android:text=&apos;&commat;{user[Fields.LAST_NAME]}&apos;
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"</strong>/>
-&lt;<strong>TextView
- android:text=&apos;&commat;{String.valueOf(1 + (Integer)user[Fields.AGE])}&apos;
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"</strong>/>
-</pre>
-
-
-<h2 id=generated_binding>Generated Binding</h2>
-
-<p>The generated binding class links the layout variables with the Views within
-the layout. As discussed earlier, the name and package of the Binding may be <a href="#custom_binding_class_names">customized</a>. The Generated binding classes all extend <code>android.databinding.ViewDataBinding</code>.</p>
-<h3 id=creating>Creating</h3>
-
-<p>The binding should be created soon after inflation to ensure that the View
-hierarchy is not disturbed prior to binding to the Views with expressions
-within the layout. There are a few ways to bind to a layout. The most common is
-to use the static methods on the Binding class.The inflate method inflates the View hierarchy and binds to it all it one step.
-There are versions that attach the View to its parent and that inflate without
-attaching.</p>
-<pre class=prettyprint>
-MyLayoutBinding binding = MyLayoutBinding.<em>inflate</em>(<strong>this</strong>);
-MyLayoutBinding binding = MyLayoutBinding.<em>inflate</em>(viewGroup);
-</pre>
-
-<p>If the layout was inflated using a different mechanism, it may be bound
-separately:</p>
-<pre class=prettyprint>
-MyLayoutBinding binding = MyLayoutBinding.<em>bind</em>(viewRoot);
-</pre>
-
-<p>Sometimes the binding cannot be known in advance. In such cases, the binding
-can be created using the DataBindingUtil class:</p>
-<pre class=prettyprint>
-ViewDataBinding binding = DataBindingUtil.<em>inflate</em>(context, layoutId,
- parent, attachToParent);
-ViewDataBinding binding = DataBindingUtil.<em>bindTo</em>(viewRoot, layoutId);
-</pre>
-
-
-<h3 id=views_with_ids>Views With IDs</h3>
-
-<p>A public final field will be generated for each View with an ID in the layout.
-The binding does a single pass on the View hierarchy, extracting the Views with
-IDs. This mechanism can be faster than calling findViewById for several Views. For example:</p>
-<pre class=prettyprint>
-&lt;<strong>layout xmlns:android="http://schemas.android.com/apk/res/android"</strong>>
- &lt;<strong>data</strong>>
- &lt;<strong>variable name="user" type="com.example.User"</strong>/>
- &lt;/<strong>data</strong>>
- &lt;<strong>LinearLayout
- android:orientation="vertical"
- android:layout_width="match_parent"
- android:layout_height="match_parent"</strong>>
- &lt;<strong>TextView android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="&commat;{user.firstName}"
-</strong> <strong>android:id="&commat;+id/firstName"</strong>/>
- &lt;<strong>TextView android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="&commat;{user.lastName}"</strong> <strong>android:id="&commat;+id/lastName"</strong>/>
- &lt;/<strong>LinearLayout</strong>>
-&lt;/<strong>layout</strong>>
-</pre>
-
-Will generate a binding class with:
-<pre class=prettyprint>
-<strong>public final </strong>TextView <strong>firstName</strong>;
-<strong>public final </strong>TextView <strong>lastName</strong>;
-</pre>
-
-<p>IDs are not nearly as necessary as without data binding, but there are still
-some instances where access to Views are still necessary from code.</p>
-<h3 id=variables>Variables</h3>
-
-<p>Each variable will be given a accessor methods.</p>
-<pre class=prettyprint>
-&lt;<strong>data</strong>>
- &lt;<strong>import type="android.graphics.drawable.Drawable"</strong>/>
- &lt;<strong>variable name="user" type="com.example.User"</strong>/>
- &lt;<strong>variable name="image" type="Drawable"</strong>/>
- &lt;<strong>variable name="note" type="String"</strong>/>
-&lt;/<strong>data</strong>>
-</pre>
-
-<p>will generate setters and getters in the binding:</p>
-<pre class=prettyprint>
-<strong>public abstract </strong>com.example.User getUser();
-<strong>public abstract void </strong>setUser(com.example.User user);
-<strong>public abstract </strong>Drawable getImage();
-<strong>public abstract void </strong>setImage(Drawable image);
-<strong>public abstract </strong>String getNote();
-<strong>public abstract void </strong>setNote(String note);
-</pre>
-
-
-<h3 id=viewstubs>ViewStubs</h3>
-
-<p>ViewStubs are a little different from normal Views. They start off invisible
-and when they either are made visible or are explicitly told to inflate, they
-replace themselves in the layout by inflating another layout.</p>
-
-<p>Because the ViewStub essentially disappears from the View hierarchy, the View
-in the binding object must also disappear to allow collection. Because the
-Views are final, a ViewStubProxy object takes the place of the ViewStub, giving
-the developer access to the ViewStub when it exists and also access to the
-inflated View hierarchy when the ViewStub has been inflated.</p>
-
-<p>When inflating another layout, a binding must be established for the new
-layout. Therefore, the ViewStubProxy must listen to the ViewStub&apos;s
-OnInflateListener and establish the binding at that time. Since only one can
-exist, the ViewStubProxy allows the developer to set an OnInflateListener on it
-that it will call after establishing the binding.</p>
-
-<h3 id=advanced_binding>Advanced Binding</h3>
-
-
-<h4 id=dynamic_variables>Dynamic Variables</h4>
-
-<p>At times, the specific binding class won&apos;t be known. For example, a
-RecyclerView Adapter operating against arbitrary layouts won&apos;t know the
-specific binding class. It still must assign the binding value during the
-onBindViewHolder.</p>
-
-<p>In this example, all layouts that the RecyclerView binds to have an "item"
-variable. The BindingHolder has a getBinding method returning the <code>ViewDataBinding</code> base.</p>
-<pre class=prettyprint>
-<strong>public void </strong>onBindViewHolder(BindingHolder holder, <strong>int </strong>position) {
- <strong>final </strong>T item = <strong>mItems</strong>.get(position);
- holder.getBinding().setVariable(BR.item, item);
- holder.getBinding().executePendingBindings();
-}
-</pre>
-
-
-<h4 id=immediate_binding>Immediate Binding</h4>
-
-<p>When a variable or observable changes, the binding will be scheduled to change
-before the next frame. There are times, however, when binding must be executed
-immediately. To force execution, use the executePendingBindings() method.</p>
-<h2 id=attribute_setters>Attribute Setters</h2>
-
-<p>Whenever a bound value changes, the generated binding class must call a setter
-method on the View with the binding expression. The data binding framework has
-ways to customize which method to call to set the value.</p>
-<h3 id=automatic_setters>Automatic Setters</h3>
-
-For an attribute, data binding tries to find the method setAttribute. The
-namespace for the attribute does not matter, only the attribute name itself.
-
-<p>For example, an expression associated with TextView&apos;s attribute <strong><code>android:text</code></strong> will look for a setText(String). If the expression returns an int, data
-binding will search for a setText(int) method. Be careful to have the
-expression return the correct type, casting if necessary.Note that data binding will work even if no attribute exists with the given
-name. You can then easily "create" attributes for any setter by using data
-binding. For example, support DrawerLayout doesn&apos;t have any attributes, but
-plenty of setters. You can use the automatic setters to use one of these.</p>
-<pre class=prettyprint>
-&lt;android.support.v4.widget.<strong>DrawerLayout
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- app:scrimColor="&commat;{&commat;color/scrim}"
- app:drawerListener="&commat;{fragment.drawerListener}"/></strong>
-</pre>
-
-
-<h3 id=renamed_setters>Renamed Setters</h3>
-
-<p>Some attributes have setters that don&apos;t match by name. For these methods, an
-attribute may be associated with the setter through BindingMethods annotation.
-This must be associated with a class and contains BindingMethod annotations,
-one for each renamed method. For example, the <strong><code>android:tint</code></strong> attribute is really associated with setImageTintList, not setTint.</p>
-<pre class=prettyprint>
-&commat;BindingMethods({
- &commat;BindingMethod(type = <strong>"android.widget.ImageView"</strong>,
- attribute = <strong>"android:tint"</strong>,
- method = <strong>"setImageTintList"</strong>),
-})
-</pre>
-
-<p>It is unlikely that developers will need to rename setters; the android
-framework attributes have already been implemented.</p>
-<h3 id=custom_setters>Custom Setters</h3>
-
-<p>Some attributes need custom binding logic. For example, there is no associated
-setter for the <strong><code>android:paddingLeft</code></strong> attribute. Instead, setPadding(left, top, right, bottom) exists. A static
-binding adapter method with the BindingAdapter annotation allows the developer
-to customize how a setter for an attribute is called.</p>
-
-<p>The android attributes have already had BindingAdapters created. For example,
-here is the one for paddingLeft:</p>
-<pre class=prettyprint></p>
-&commat;BindingAdapter(<strong>"android:paddingLeft"</strong>)
-<strong>public static void </strong>setPaddingLeft(View view, <strong>int </strong>padding) {
- view.setPadding(padding,
- view.getPaddingTop(),
- view.getPaddingRight(),
- view.getPaddingBottom());
-}
-</pre>
-
-<p>Binding adapters are useful for other types of customization. For example, a
- custom loader can be called off-thread to load an image.</p>
-
-<p>Developer-created binding adapters will override the data binding default
-adapters when there is a conflict.</p>
-
-<p>You can also have adapters that receive multiple parameters. </p>
-<pre class=prettyprint>
-&commat;BindingAdapter(attributes = {<strong>"bind:imageUrl"</strong>, <strong>"bind:error"</strong>})
-<strong>public static void </strong>loadImage(ImageView view, String url, Drawable error) {
- Picasso.<em>with</em>(view.getContext()).load(url).error(error).into(view);
-}
-</pre>
-
-<p>This adapter will be called if both <strong>imageUrl </strong>and <strong>error </strong>are used for an ImageView and <em>imageUrl </em>is a string and <em>error</em> is a drawable.</p>
-<ul>
- <li> Custom namespaces are ignore during matching.
- <li> You can also write adapters for android namespace.
-</ul>
-
-<pre class=prettyprint>
-&lt;ImageView app:imageUrl=“&commat;{venue.imageUrl}”
-app:error=“&commat;{&commat;drawable/venueError}”/>
-</pre>
-
-
-<h2 id=converters>Converters</h2>
-
-
-<h3 id=object_conversions>Object Conversions</h3>
-
-<p>When an Object is returned from a binding expression, a setter will be chosen
-from the automatic, renamed, and custom setters. The Object will be cast to a
-parameter type of the chosen setter.</p><p>This is a convenience for those using ObservableMaps to hold data. for example:</p>
-<pre class=prettyprint>
-&lt;<strong>TextView
- android:text=&apos;&commat;{userMap["lastName"]}&apos;
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"</strong>/>
-</pre>
-
-<p>The userMap returns an Object and that Object will be automatically cast to
-parameter type found in the setter <code>setText(CharSequence)</code>. When there may be confusion about the parameter type, the developer will need
-to cast in the expression.</p>
-<h3 id=custom_conversions>Custom Conversions</h3>
-
-<p>Sometimes conversions should be automatic between specific types. For example,
-when setting the background:</p>
-<pre class=prettyprint>
-&lt;<strong>View
- android:background="&commat;{isError ? &commat;color/red : &commat;color/white}"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"</strong>/>
-</pre>
-
-<p>Here, the background takes a <code>Drawable</code>, but the color is an integer. Whenever a <code>Drawable</code> is expected and an integer is returned, the <code>int</code> should be converted to a <code>ColorDrawable</code>. This conversion is done using a static method with a BindingConversion
-annotation:</p>
-<pre class=prettyprint>
-&commat;BindingConversion
-<strong>public static </strong>ColorDrawable convertColorToDrawable(<strong>int </strong>color) {
- <strong>return new </strong>ColorDrawable(color);
-}
-</pre>
-
-<p>Note that conversions only happen at the setter level, so it is <strong>not allowed </strong>to mix types like this:</p>
-<pre class=prettyprint>
-&lt;<strong>View
- android:background="&commat;{isError ? &commat;drawable/error : &commat;color/white}"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"</strong>/>
-</pre>
-
diff --git a/docs/html/preview/download.jd b/docs/html/preview/download.jd
index 9dd0f85..448a23d 100644
--- a/docs/html/preview/download.jd
+++ b/docs/html/preview/download.jd
@@ -189,7 +189,7 @@ This is the Android SDK Preview License Agreement (the “License Agreement”).
</p>
-<h2 id="#docs">Developer Documentation</h2>
+<h2 id="docs">Developer Documentation</h2>
<p>
The developer documentation download package provides detailed API reference information and an API difference report for the preview.
@@ -214,7 +214,7 @@ This is the Android SDK Preview License Agreement (the “License Agreement”).
<h2 id="images">Hardware System Images</h2>
<p>
- These system images allow you install a preview version of the platform on a physical device for
+ These system images allow you to install a preview version of the platform on a physical device for
testing. By configuring a device with one of these images, you can install and test your app to
see how it performs on the next version of the platform. The process of installing a system image
on a device <em>removes all data from the device</em>, so you should backup your data before
@@ -292,7 +292,7 @@ This is the Android SDK Preview License Agreement (the “License Agreement”).
<h3 id="revertDevice">Revert a Device to Factory Specifications</h3>
<p>
- If you want to uninstall the Preview and revert the device to factory specifications, go to
+ If you want to uninstall the preview and revert the device to factory specifications, go to
<a href="http://developers.google.com/android/nexus/images">developers.google.com/android</a> and
download the image you want to flash to for your device. Follow the instructions on that page to
flash the image to your device.
@@ -330,15 +330,18 @@ This is the Android SDK Preview License Agreement (the “License Agreement”).
function onDownloadForRealz(link) {
if ($("input#agree").is(':checked')) {
+ /*
$("#tos").fadeOut('fast');
$("#landing").fadeIn('fast');
+ */
+
ga('send', 'event', 'M Preview', 'System Image', $("#downloadForRealz").html());
+
+ /*
location.hash = "";
+ */
return true;
} else {
- $("label#agreeLabel").parent().stop().animate({color: "#258AAF"}, 200,
- function() {$("label#agreeLabel").parent().stop().animate({color: "#222"}, 200)}
- );
return false;
}
}
diff --git a/docs/html/preview/features/app-linking.jd b/docs/html/preview/features/app-linking.jd
index ffca1a9..5592323 100644
--- a/docs/html/preview/features/app-linking.jd
+++ b/docs/html/preview/features/app-linking.jd
@@ -1,8 +1,8 @@
page.title=App Links
-
+page.image=images/cards/card-app-linking_2x.png
+page.keywords=applinking, deeplinks, intents
@jd:body
-
<div id="qv-wrapper">
<div id="qv">
<h2>In this document</h2>
diff --git a/docs/html/preview/index.jd b/docs/html/preview/index.jd
index 4ea5b4a..eb18aa6 100644
--- a/docs/html/preview/index.jd
+++ b/docs/html/preview/index.jd
@@ -1,6 +1,6 @@
page.title=Android M Developer Preview
page.tags="preview",
-meta.tags="preview, M preview"
+meta.tags="preview, M preview", androidm
fullpage=true
section.landing=true
header.hide=1
@@ -44,24 +44,25 @@ footer.hide=1
<div class="dac-section-subtitle">
Essential information to help you get your apps ready for Android M.
</div>
+
<div class="resource-widget resource-flow-layout col-16"
- data-query="tag:previewresources"
+ data-query="collection:preview/landing/more"
data-cardSizes="6x6"
- data-initial-results="6"
data-maxResults="16"></div>
- <ul class="dac-section-links">
- <li class="dac-section-link"><a href="http://g.co/dev/AndroidMDevPreview">
- <span class="dac-sprite dac-auto-chevron"></span>
- Join G+ Community
- </a></li>
-
- <li class="dac-section-link">
- <a href="https://code.google.com/p/android-developer-preview/">
+ <ul class="dac-section-links">
+ <li class="dac-section-link">
+ <a href="https://code.google.com/p/android-developer-preview/">
+ <span class="dac-sprite dac-auto-chevron"></span>
+ Report Issues
+ </a>
+ </li>
+ <li class="dac-section-link"><a href="http://g.co/dev/AndroidMDevPreview">
<span class="dac-sprite dac-auto-chevron"></span>
- Report Issues
- </a>
- </li>
- </ul>
-</div></section>
+ Join G+ Community
+ </a>
+ </li>
+ </ul>
+ </div>
+</section>
diff --git a/docs/html/preview/overview.jd b/docs/html/preview/overview.jd
index 1b8643e..d6bafb1 100644
--- a/docs/html/preview/overview.jd
+++ b/docs/html/preview/overview.jd
@@ -118,7 +118,7 @@ page.tags="preview", "developer", "android"
<p>
The M Developer Preview runs from May 27 until the final Android M SDK, which
we’ll release shortly before the public release during Q3
- 2015.
+ 2015.
</p>
<p>
@@ -204,7 +204,7 @@ page.tags="preview", "developer", "android"
<p>
You can download these hardware system images for Nexus devices from the
- <a href="downloads.html">Downloads page</a>:
+ <a href="download.html">Downloads page</a>:
</p>
<ul>
@@ -240,24 +240,25 @@ page.tags="preview", "developer", "android"
</li>
<li>
- <a href="testing.html">Testing Guide</a> and <a href=
- "api-changes.html">Behavior Changes</a> point you to key areas to test.
+ <a href="{@docRoot}preview/testing/guide.html">Testing Guide</a> and <a href=
+ "behavior-changes.html">Behavior Changes</a> point you to key areas to test.
</li>
<li>Documentation of new APIs, including an <a href="api-overview.html">API Overview</a>,
- downloadable <a href="">API Reference</a>, and detailed developer guides on
- key features such as <a href="">permissions</a>, <a href="">app backup</a>,
- and others.
+ downloadable <a href="{@docRoot}preview/download.html#docs">API Reference</a>, and detailed developer guides on
+ key features such as
+ <a href="{@docRoot}preview/features/runtime-permissions.html">permissions</a>,
+ <a href="{@docRoot}preview/backup/index.html">app backup</a>, and others.
</li>
<li>
- <a href="">Sample code</a> that demonstrates how to support
+ <a href="{@docRoot}preview/samples.html">Sample code</a> that demonstrates how to support
permissions and other new features.
</li>
<li>
- <a href="">Release notes</a> for the current version of the M Developer
- Preview, including change notes and diff reports.
+ <a href="{@docRoot}preview/support.html#release-notes">Release notes</a> for the current version
+ of the M Developer Preview, including change notes and diff reports.
</li>
</ul>
@@ -334,7 +335,7 @@ page.tags="preview", "developer", "android"
<ol>
<li>Review the <a href="{@docRoot}preview/api-overview.html">API Overview</a>
- and <a href="{@docRoot}preview/behavior.html">Behavior Changes</a> to get an
+ and <a href="{@docRoot}preview/behavior-changes.html">Behavior Changes</a> to get an
idea of what's new and how it affects your apps.
</li>
@@ -349,7 +350,7 @@ page.tags="preview", "developer", "android"
Preview updates will be delivered through over-the-air (OTA) updates.</a>
</li>
- <li>Download the <a href="{@docRoot}preview/reference.html">M Preview API
+ <li>Download the <a href="{@docRoot}preview/download.html#docs">M Preview API
Reference</a> and <a href="{@docRoot}preview/samples.html">M Preview
samples</a> to gain more insight into new API features and how to use them in
your app.
diff --git a/docs/html/preview/preview_toc.cs b/docs/html/preview/preview_toc.cs
index 07afcdd..d0aa55f 100644
--- a/docs/html/preview/preview_toc.cs
+++ b/docs/html/preview/preview_toc.cs
@@ -33,7 +33,7 @@
<li><a href="<?cs var:toroot ?>preview/features/app-linking.html">
App Links</a></li>
<li><a href="<?cs var:toroot ?>preview/backup/index.html">
- Automatic Backups</a></li>
+ Auto Backup for Apps</a></li>
</ul>
</li>
diff --git a/docs/html/preview/samples.jd b/docs/html/preview/samples.jd
index 3974ee3..7d47e0e 100644
--- a/docs/html/preview/samples.jd
+++ b/docs/html/preview/samples.jd
@@ -7,7 +7,6 @@ page.image=images/cards/samples-new_2x.png
the samples in Android Studio, select the <b>File > Import Samples</b> menu option.
</p>
-<img src="{@docRoot}images/cards/card-google-cloud-messaging_16-9_2x" class="figure">
<p class="note">
<strong>Note:</strong> These downloadable projects are designed
for use with Gradle and Android Studio.
diff --git a/docs/html/preview/setup-sdk.jd b/docs/html/preview/setup-sdk.jd
index 016967d..1616053 100644
--- a/docs/html/preview/setup-sdk.jd
+++ b/docs/html/preview/setup-sdk.jd
@@ -116,7 +116,7 @@ of Android Studio to use for testing.</p>
<h3 id="create">Create a new project</h3>
<p>
- We recommend using Android Studio for create a project with the preview. Follow the steps
+ We recommend using Android Studio to create a project with the preview. Follow the steps
described in <a href="{@docRoot}sdk/installing/create-project.html">Creating a Project</a>
until you arrive at the <em>Form Factors</em> screen in the project wizard. Then perform
the following steps to create a project configured for the preview.
@@ -132,7 +132,7 @@ of Android Studio to use for testing.</p>
<p>
For existing projects, you must modify the project configuration to enable the preview APIs. In
- your the development environment, open the <code>build.gradle</code> file for your module and
+ your development environment, open the <code>build.gradle</code> file for your module and
set these values as follows:
</p>
@@ -146,7 +146,7 @@ of Android Studio to use for testing.</p>
<h2 id="setup-test">Set Up for Testing</h2>
<p>
- Testing app with the preview requires that you have a device or virtual device configured with
+ Testing an app with the preview requires that you have a device or virtual device configured with
the preview version of the platform. If you have a compatible device, you can install the preview
platform for testing. Otherwise, you can configure a virtual device for testing.
</p>
@@ -156,7 +156,7 @@ of Android Studio to use for testing.</p>
<p>
If you have a Nexus 5, Nexus 6, Nexus 9, or Android TV, you can install a preview
system image on these devices for testing your app.
- You can set up virtual device with the preview version of the platform from within Android Studio
+ You can set up a virtual device with the preview version of the platform from within Android Studio
using the Android Virtual Device Manager tool.
</p>
diff --git a/docs/html/preview/testing/guide.jd b/docs/html/preview/testing/guide.jd
index 317dc44..07a25a2 100644
--- a/docs/html/preview/testing/guide.jd
+++ b/docs/html/preview/testing/guide.jd
@@ -1,5 +1,6 @@
page.title=Testing Guide
-page.image=images/cards/card-set-up_16-9_2x.png
+page.image=images/cards/card-build_16x9_2x.png
+page.keywords=previewresources,androidm,testing,permissions
@jd:body
@@ -18,7 +19,7 @@ page.image=images/cards/card-set-up_16-9_2x.png
The Android M Developer Preview gives you an opportunity to ensure your apps work with the next
version of the platform. This preview includes a number of APIs and behavior changes that can
impact your app, as described in the <a href="{@docRoot}preview/api-overview.html">API
- Overview</a> and <a href="{@docRoot}preview/api-changes.html">Behavior Changes</a>. In testing
+ Overview</a> and <a href="{@docRoot}preview/behavior-changes.html">Behavior Changes</a>. In testing
your app with the preview, there are some specific system changes that you should focus on to
ensure that users have a good experience.
</p>
@@ -32,7 +33,7 @@ page.image=images/cards/card-set-up_16-9_2x.png
<ul>
<li><a href="#runtime-permissions">Permissions</a>
</li>
- <li><a href="#doze-mode">Doze and App Standby</a>
+ <li><a href="#doze-standby">Doze and App Standby</a>
</li>
<li><a href="#ids">Auto Backup and Device Identifiers</a></li>
</ul>
@@ -57,7 +58,7 @@ page.image=images/cards/card-set-up_16-9_2x.png
</p>
<p>
- This change that affects all apps running on the new platform, even those not targeting the new
+ This change affects all apps running on the new platform, even those not targeting the new
platform version. The platform provides a limited compatibility behavior for legacy apps, but you
should begin planning your app’s migration to the new permissions model now, with a goal of
publishing an updated version of your app at the official platform launch.
@@ -123,7 +124,7 @@ page.image=images/cards/card-set-up_16-9_2x.png
<h2 id="doze-standby">Testing Doze and App Standby</h2>
<p>
- The power saving features of Doze and App Standby limits the amount of background processing that
+ The power saving features of Doze and App Standby limit the amount of background processing that
your app can perform when a device is in an idle state or while your app is not in focus. The
restrictions the system may impose on apps include limited or no network access,
suspended background tasks, suspended Notifications, ignored wake requests, and alarms. To ensure
@@ -182,4 +183,5 @@ $ adb shell am set-idle &lt;packageName&gt; true
<p>If your app is persisting any device-specific identifiers, such as Google
Cloud Messaging registration ID, in internal storage,
make sure to follow best practices to exclude the storage
-location from auto-backup, as described in <a href="">Auto Backup for Apps</a>. </p>
+location from auto-backup, as described in <a href="{@docRoot}preview/backup/index.html">Auto
+Backup for Apps</a>. </p>
diff --git a/docs/html/preview/testing/performance.jd b/docs/html/preview/testing/performance.jd
index a61091f..003b619 100644
--- a/docs/html/preview/testing/performance.jd
+++ b/docs/html/preview/testing/performance.jd
@@ -1,4 +1,6 @@
page.title=Testing Display Performance
+page.image=images/cards/card-test-performance_2x.png
+page.keywords=performance, fps, tools
@jd:body
@@ -552,10 +554,10 @@ Number Slow draw: 23342
</h4>
<p>
- Tool suites like <a href=
- "https://developer.android.com/tools/testing-support-library/index.html">UIAutomator</a>,
- and <a href="https://code.google.com/p/android-test-kit/">Espresso</a> are built to help
- automate the action of a user moving through your application. These are simple
+ Tool suites, like <a href=
+ "{@docRoot}training/testing/ui-testing/uiautomator-testing.html">UI Automator</a> and
+ <a href="{@docRoot}training/testing/ui-testing/espresso-testing.html">Espresso</a>, are
+ built to help automate the action of a user moving through your application. These are simple
frameworks which mimic user interaction with your device. To use these frameworks, you
effectively create unique scripts, which run through a set of user-actions, and play them
out on the device itself.
@@ -583,7 +585,7 @@ Number Slow draw: 23342
<p>
It’s worth noting that UI testing frameworks (like <a href=
- "https://developer.android.com/tools/testing-support-library/index.html">UIAutomator</a>)
+ "{@docRoot}training/testing/ui-testing/uiautomator-testing.html">UI Automator</a>)
run on the target device/emulator directly. While performance gathering information done
by <em>dumpsys gfxinfo</em> is driven by a host machine, sending commands over ADB. To
help bridge the automation of these separate entities, <a href=
@@ -593,7 +595,7 @@ Number Slow draw: 23342
</p>
<p>
- Building a set of scripts for proper Automation of UI Performance testing, at a minimum,
+ Building a set of scripts for proper automation of UI Performance testing, at a minimum,
should be able to utilize monkeyRunner to accomplish the following tasks:
</p>
@@ -601,7 +603,7 @@ Number Slow draw: 23342
<li>Load &amp; Launch a desired APK to a target device, devices, or emulator.
</li>
- <li>Launch a UIAutomator UI test, and allow it to be executed
+ <li>Launch a UI Automator UI test, and allow it to be executed
</li>
<li>Collect performance information through <em>dumpsys gfxinfo</em><em>.</em>
diff --git a/docs/html/tools/data-binding/guide.jd b/docs/html/tools/data-binding/guide.jd
index 6a933d8..71409e4 100644
--- a/docs/html/tools/data-binding/guide.jd
+++ b/docs/html/tools/data-binding/guide.jd
@@ -26,16 +26,16 @@ tracker</a>. Stay tuned for more information about Data Binding and examples of
<a href="#data_binding_layout_files">Data Binding Layout Files</a>
<ol>
<li>
- <a href="writing_expressions">Writing your first data binding
+ <a href="#writing_expressions">Writing your first data binding
expressions</a>
</li>
<li>
- <a href="data_object">Data Object</a>
+ <a href="#data_object">Data Object</a>
</li>
<li>
- <a href="binding_data">Binding Data</a>
+ <a href="#binding_data">Binding Data</a>
</li>
</ol>
</li>
@@ -44,23 +44,23 @@ tracker</a>. Stay tuned for more information about Data Binding and examples of
<a href="#layout_details">Layout Details</a>
<ol>
<li>
- <a href="imports">Imports</a>
+ <a href="#imports">Imports</a>
</li>
<li>
- <a href="variables">Variables</a>
+ <a href="#variables">Variables</a>
</li>
<li>
- <a href="custom_binding_class_names">Custom Binding Class Names</a>
+ <a href="#custom_binding_class_names">Custom Binding Class Names</a>
</li>
<li>
- <a href="includes">Includes</a>
+ <a href="#includes">Includes</a>
</li>
<li>
- <a href="expression_language">Expression Language</a>
+ <a href="#expression_language">Expression Language</a>
</li>
</ol>
</li>
@@ -69,15 +69,15 @@ tracker</a>. Stay tuned for more information about Data Binding and examples of
<a href="#data_objects">Data Objects</a>
<ol>
<li>
- <a href="observable_objects">Observable Objects</a>
+ <a href="#observable_objects">Observable Objects</a>
</li>
<li>
- <a href="observablefields">ObservableFields</a>
+ <a href="#observablefields">ObservableFields</a>
</li>
<li>
- <a href="observable_collections">Observable Collections</a>
+ <a href="#observable_collections">Observable Collections</a>
</li>
</ol>
</li>
@@ -86,23 +86,23 @@ tracker</a>. Stay tuned for more information about Data Binding and examples of
<a href="#generated_binding">Generated Binding</a>
<ol>
<li>
- <a href="creating">Creating</a>
+ <a href="#creating">Creating</a>
</li>
<li>
- <a href="views_with_ids">Views With IDs</a>
+ <a href="#views_with_ids">Views With IDs</a>
</li>
<li>
- <a href="variables">Variables</a>
+ <a href="#variables">Variables</a>
</li>
<li>
- <a href="viewstubs">ViewStubs</a>
+ <a href="#viewstubs">ViewStubs</a>
</li>
<li>
- <a href="advanced_binding">Advanced Binding</a>
+ <a href="#advanced_binding">Advanced Binding</a>
</li>
</ol>
</li>
@@ -111,15 +111,15 @@ tracker</a>. Stay tuned for more information about Data Binding and examples of
<a href="#attribute_setters">Attribute Setters</a>
<ol>
<li>
- <a href="automatic_setters">Automatic Setters</a>
+ <a href="#automatic_setters">Automatic Setters</a>
</li>
<li>
- <a href="renamed_setters">Renamed Setters</a>
+ <a href="#renamed_setters">Renamed Setters</a>
</li>
<li>
- <a href="custom_setters">Custom Setters</a>
+ <a href="#custom_setters">Custom Setters</a>
</li>
</ol>
</li>
@@ -128,11 +128,11 @@ tracker</a>. Stay tuned for more information about Data Binding and examples of
<a href="#converters">Converters</a>
<ol>
<li>
- <a href="object_conversions">Object Conversions</a>
+ <a href="#object_conversions">Object Conversions</a>
</li>
<li>
- <a href="custom_conversions">Custom Conversions</a>
+ <a href="#custom_conversions">Custom Conversions</a>
</li>
</ol>
</li>
diff --git a/docs/html/tools/data-binding/index.jd b/docs/html/tools/data-binding/index.jd
deleted file mode 100644
index 4ad11b6..0000000
--- a/docs/html/tools/data-binding/index.jd
+++ /dev/null
@@ -1,18 +0,0 @@
-page.title=Android Data Binding Library
-page.metaDescription=
-
-@jd:body
-
-<p>
- Some text here.
-</p>
-
-
-
-<!-- <h2>Related Resources</h2>
- <div class="resource-widget resource-flow-layout col-16"
- data-query="tag:engagement"
- data-sortOrder="random"
- data-cardSizes="6x2"
- data-maxResults="3">
- </div> -->
diff --git a/docs/html/training/training_toc.cs b/docs/html/training/training_toc.cs
index 535a87e..0baef14 100644
--- a/docs/html/training/training_toc.cs
+++ b/docs/html/training/training_toc.cs
@@ -1654,6 +1654,14 @@ results."
</ul>
</li> <!-- end of Background Jobs -->
+ <li class="nav-section">
+ <div class="nav-section-header">
+ <a href="<?cs var:toroot ?>training/best-performance.html">
+ <span class="small">Best Practices for</span><br/>
+ Performance
+ </a>
+ </div>
+ <ul>
<li>
<a href="<?cs var:toroot ?>training/articles/memory.html"
description=
@@ -1661,7 +1669,6 @@ results."
on a variety of mobile devices."
>Managing Your App's Memory</a>
</li>
-
<li>
<a href="<?cs var:toroot ?>training/articles/perf-tips.html"
description=
@@ -1669,7 +1676,6 @@ results."
responsiveness and battery efficiency."
>Performance Tips</a>
</li>
-
<li class="nav-section">
<div class="nav-section-header">
<a href="<?cs var:toroot ?>training/improving-layouts/index.html"
@@ -1697,7 +1703,6 @@ results."
</li>
</ul>
</li>
-
<li class="nav-section">
<div class="nav-section-header">
<a href="<?cs var:toroot ?>training/monitoring-device-state/index.html"
@@ -1707,7 +1712,8 @@ results."
description=
"How to minimize the amount of power your app requires by adapting to current
power conditions and performing power-hungry tasks at proper intervals."
- >Optimizing Battery Life</a>
+ >Optimizing Battery Life
+ </a>
</div>
<ul>
<li><a href="<?cs var:toroot ?>training/monitoring-device-state/battery-monitoring.html"
@@ -1763,7 +1769,6 @@ results."
</li>
</ul>
</li>
-
<li>
<a href="<?cs var:toroot ?>training/articles/perf-anr.html"
description=
@@ -1771,7 +1776,6 @@ results."
display an &quot;Application Not Responding&quot; dialog."
>Keeping Your App Responsive</a>
</li>
-
<li>
<a href="<?cs var:toroot ?>training/articles/perf-jni.html"
description=
@@ -1787,8 +1791,6 @@ results."
</ul>
</li> <!-- end of Performance -->
-
-
<li class="nav-section">
<div class="nav-section-header">
<a href="<?cs var:toroot ?>training/best-security.html">
diff --git a/docs/html/training/tv/index.jd b/docs/html/training/tv/index.jd
index d52e1e8..ff9f111 100644
--- a/docs/html/training/tv/index.jd
+++ b/docs/html/training/tv/index.jd
@@ -8,4 +8,5 @@ page.image=design/tv/images/focus.png
<p>These classes teach you how to build apps for TV devices.</p>
-<p class="note"><strong>Note:</strong> For details on how to publish your TV apps in Google Play, see <a href="{docRoot}distribute/googleplay/tv.html">Distributing to Android TV</a>.</p> \ No newline at end of file
+<p class="note"><strong>Note:</strong> For details on how to publish your TV apps in Google Play,
+see <a href="{@docRoot}distribute/googleplay/tv.html">Distribute to Android TV</a>.</p> \ No newline at end of file
diff --git a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
index b8f64a4..073acd4 100644
--- a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
@@ -19,6 +19,7 @@ import android.animation.AnimatorInflater;
import android.animation.AnimatorSet;
import android.animation.Animator.AnimatorListener;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.content.res.Resources.Theme;
@@ -128,15 +129,27 @@ import java.util.List;
* @attr ref android.R.styleable#AnimatedVectorDrawableTarget_animation
*/
public class AnimatedVectorDrawable extends Drawable implements Animatable {
- private static final String LOGTAG = AnimatedVectorDrawable.class.getSimpleName();
+ private static final String LOGTAG = "AnimatedVectorDrawable";
private static final String ANIMATED_VECTOR = "animated-vector";
private static final String TARGET = "target";
private static final boolean DBG_ANIMATION_VECTOR_DRAWABLE = false;
+ /** Local, mutable animator set. */
+ private final AnimatorSet mAnimatorSet = new AnimatorSet();
+
+ /**
+ * The resources against which this drawable was created. Used to attempt
+ * to inflate animators if applyTheme() doesn't get called.
+ */
+ private Resources mRes;
+
private AnimatedVectorDrawableState mAnimatedVectorState;
+ /** Whether the animator set has been prepared. */
+ private boolean mHasAnimatorSet;
+
private boolean mMutated;
public AnimatedVectorDrawable() {
@@ -145,6 +158,7 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable {
private AnimatedVectorDrawable(AnimatedVectorDrawableState state, Resources res) {
mAnimatedVectorState = new AnimatedVectorDrawableState(state, mCallback, res);
+ mRes = res;
}
@Override
@@ -162,7 +176,9 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable {
*/
public void clearMutated() {
super.clearMutated();
- mAnimatedVectorState.mVectorDrawable.clearMutated();
+ if (mAnimatedVectorState.mVectorDrawable != null) {
+ mAnimatedVectorState.mVectorDrawable.clearMutated();
+ }
mMutated = false;
}
@@ -274,6 +290,7 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable {
@Override
public void inflate(Resources res, XmlPullParser parser, AttributeSet attrs, Theme theme)
throws XmlPullParserException, IOException {
+ final AnimatedVectorDrawableState state = mAnimatedVectorState;
int eventType = parser.getEventType();
float pathErrorScale = 1;
@@ -291,10 +308,10 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable {
vectorDrawable.setAllowCaching(false);
vectorDrawable.setCallback(mCallback);
pathErrorScale = vectorDrawable.getPixelSize();
- if (mAnimatedVectorState.mVectorDrawable != null) {
- mAnimatedVectorState.mVectorDrawable.setCallback(null);
+ if (state.mVectorDrawable != null) {
+ state.mVectorDrawable.setCallback(null);
}
- mAnimatedVectorState.mVectorDrawable = vectorDrawable;
+ state.mVectorDrawable = vectorDrawable;
}
a.recycle();
} else if (TARGET.equals(tagName)) {
@@ -302,13 +319,21 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable {
R.styleable.AnimatedVectorDrawableTarget);
final String target = a.getString(
R.styleable.AnimatedVectorDrawableTarget_name);
-
- int id = a.getResourceId(
+ final int animResId = a.getResourceId(
R.styleable.AnimatedVectorDrawableTarget_animation, 0);
- if (id != 0) {
- Animator objectAnimator = AnimatorInflater.loadAnimator(res, theme, id,
- pathErrorScale);
- setupAnimatorsForTarget(target, objectAnimator);
+ if (animResId != 0) {
+ if (theme != null) {
+ final Animator objectAnimator = AnimatorInflater.loadAnimator(
+ res, theme, animResId, pathErrorScale);
+ state.addTargetAnimator(target, objectAnimator);
+ } else {
+ // The animation may be theme-dependent. As a
+ // workaround until Animator has full support for
+ // applyTheme(), postpone loading the animator
+ // until we have a theme in applyTheme().
+ state.addPendingAnimator(animResId, pathErrorScale, target);
+
+ }
}
a.recycle();
}
@@ -316,15 +341,10 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable {
eventType = parser.next();
}
- setupAnimatorSet();
- }
- private void setupAnimatorSet() {
- if (mAnimatedVectorState.mTempAnimators != null) {
- mAnimatedVectorState.mAnimatorSet.playTogether(mAnimatedVectorState.mTempAnimators);
- mAnimatedVectorState.mTempAnimators.clear();
- mAnimatedVectorState.mTempAnimators = null;
- }
+ // If we don't have any pending animations, we don't need to hold a
+ // reference to the resources.
+ mRes = state.mPendingAnims == null ? null : res;
}
@Override
@@ -341,6 +361,16 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable {
if (vectorDrawable != null && vectorDrawable.canApplyTheme()) {
vectorDrawable.applyTheme(t);
}
+
+ if (t != null) {
+ mAnimatedVectorState.inflatePendingAnimators(t.getResources(), t);
+ }
+
+ // If we don't have any pending animations, we don't need to hold a
+ // reference to the resources.
+ if (mAnimatedVectorState.mPendingAnims == null) {
+ mRes = null;
+ }
}
/**
@@ -350,7 +380,7 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable {
* @param listener the listener to be added to the current set of listeners for this animation.
*/
public void addListener(AnimatorListener listener) {
- mAnimatedVectorState.mAnimatorSet.addListener(listener);
+ mAnimatorSet.addListener(listener);
}
/**
@@ -360,7 +390,7 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable {
* animation.
*/
public void removeListener(AnimatorListener listener) {
- mAnimatedVectorState.mAnimatorSet.removeListener(listener);
+ mAnimatorSet.removeListener(listener);
}
/**
@@ -370,23 +400,27 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable {
* @return List<AnimatorListener> The set of listeners.
*/
public List<AnimatorListener> getListeners() {
- return mAnimatedVectorState.mAnimatorSet.getListeners();
+ return mAnimatorSet.getListeners();
}
private static class AnimatedVectorDrawableState extends ConstantState {
int mChangingConfigurations;
VectorDrawable mVectorDrawable;
- // Always have a valid animatorSet to handle all the listeners call.
- AnimatorSet mAnimatorSet = new AnimatorSet();
- // When parsing the XML, we build individual animator and store in this array. At the end,
- // we add this array into the mAnimatorSet.
- private ArrayList<Animator> mTempAnimators;
+
+ /** Animators that require a theme before inflation. */
+ ArrayList<PendingAnimator> mPendingAnims;
+
+ /** Fully inflated animators awaiting cloning into an AnimatorSet. */
+ ArrayList<Animator> mAnimators;
+
+ /** Map of animators to their target object names */
ArrayMap<Animator, String> mTargetNameMap;
public AnimatedVectorDrawableState(AnimatedVectorDrawableState copy,
Callback owner, Resources res) {
if (copy != null) {
mChangingConfigurations = copy.mChangingConfigurations;
+
if (copy.mVectorDrawable != null) {
final ConstantState cs = copy.mVectorDrawable.getConstantState();
if (res != null) {
@@ -400,24 +434,17 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable {
mVectorDrawable.setBounds(copy.mVectorDrawable.getBounds());
mVectorDrawable.setAllowCaching(false);
}
- if (copy.mAnimatorSet != null) {
- final int numAnimators = copy.mTargetNameMap.size();
- // Deep copy a animator set, and then setup the target map again.
- mAnimatorSet = copy.mAnimatorSet.clone();
- mTargetNameMap = new ArrayMap<Animator, String>(numAnimators);
- // Since the new AnimatorSet is cloned from the old one, the order must be the
- // same inside the array.
- ArrayList<Animator> oldAnim = copy.mAnimatorSet.getChildAnimations();
- ArrayList<Animator> newAnim = mAnimatorSet.getChildAnimations();
-
- for (int i = 0; i < numAnimators; ++i) {
- // Target name must be the same for new and old
- String targetName = copy.mTargetNameMap.get(oldAnim.get(i));
-
- Object newTargetObject = mVectorDrawable.getTargetByName(targetName);
- newAnim.get(i).setTarget(newTargetObject);
- mTargetNameMap.put(newAnim.get(i), targetName);
- }
+
+ if (copy.mAnimators != null) {
+ mAnimators = new ArrayList<>(copy.mAnimators);
+ }
+
+ if (copy.mTargetNameMap != null) {
+ mTargetNameMap = new ArrayMap<>(copy.mTargetNameMap);
+ }
+
+ if (copy.mPendingAnims != null) {
+ mPendingAnims = new ArrayList<>(copy.mPendingAnims);
}
} else {
mVectorDrawable = new VectorDrawable();
@@ -427,7 +454,7 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable {
@Override
public boolean canApplyTheme() {
return (mVectorDrawable != null && mVectorDrawable.canApplyTheme())
- || super.canApplyTheme();
+ || mPendingAnims != null || super.canApplyTheme();
}
@Override
@@ -444,44 +471,157 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable {
public int getChangingConfigurations() {
return mChangingConfigurations;
}
- }
- private void setupAnimatorsForTarget(String name, Animator animator) {
- Object target = mAnimatedVectorState.mVectorDrawable.getTargetByName(name);
- animator.setTarget(target);
- if (mAnimatedVectorState.mTempAnimators == null) {
- mAnimatedVectorState.mTempAnimators = new ArrayList<Animator>();
- mAnimatedVectorState.mTargetNameMap = new ArrayMap<Animator, String>();
+ public void addPendingAnimator(int resId, float pathErrorScale, String target) {
+ if (mPendingAnims == null) {
+ mPendingAnims = new ArrayList<>(1);
+ }
+ mPendingAnims.add(new PendingAnimator(resId, pathErrorScale, target));
+ }
+
+ public void addTargetAnimator(String targetName, Animator animator) {
+ if (mAnimators == null) {
+ mAnimators = new ArrayList<>(1);
+ mTargetNameMap = new ArrayMap<>(1);
+ }
+ mAnimators.add(animator);
+ mTargetNameMap.put(animator, targetName);
+
+ if (DBG_ANIMATION_VECTOR_DRAWABLE) {
+ Log.v(LOGTAG, "add animator for target " + targetName + " " + animator);
+ }
}
- mAnimatedVectorState.mTempAnimators.add(animator);
- mAnimatedVectorState.mTargetNameMap.put(animator, name);
- if (DBG_ANIMATION_VECTOR_DRAWABLE) {
- Log.v(LOGTAG, "add animator for target " + name + " " + animator);
+
+ /**
+ * Prepares a local set of mutable animators based on the constant
+ * state.
+ * <p>
+ * If there are any pending uninflated animators, attempts to inflate
+ * them immediately against the provided resources object.
+ *
+ * @param animatorSet the animator set to which the animators should
+ * be added
+ * @param res the resources against which to inflate any pending
+ * animators, or {@code null} if not available
+ */
+ public void prepareLocalAnimators(@NonNull AnimatorSet animatorSet,
+ @Nullable Resources res) {
+ // Check for uninflated animators. We can remove this after we add
+ // support for Animator.applyTheme(). See comments in inflate().
+ if (mPendingAnims != null) {
+ // Attempt to load animators without applying a theme.
+ if (res != null) {
+ inflatePendingAnimators(res, null);
+ } else {
+ Log.e(LOGTAG, "Failed to load animators. Either the AnimatedVectorDrawable"
+ + " must be created using a Resources object or applyTheme() must be"
+ + " called with a non-null Theme object.");
+ }
+
+ mPendingAnims = null;
+ }
+
+ // Perform a deep copy of the constant state's animators.
+ final int count = mAnimators == null ? 0 : mAnimators.size();
+ if (count > 0) {
+ final Animator firstAnim = prepareLocalAnimator(0);
+ final AnimatorSet.Builder builder = animatorSet.play(firstAnim);
+ for (int i = 1; i < count; ++i) {
+ final Animator nextAnim = prepareLocalAnimator(i);
+ builder.with(nextAnim);
+ }
+ }
+ }
+
+ /**
+ * Prepares a local animator for the given index within the constant
+ * state's list of animators.
+ *
+ * @param index the index of the animator within the constant state
+ */
+ private Animator prepareLocalAnimator(int index) {
+ final Animator animator = mAnimators.get(index);
+ final Animator localAnimator = animator.clone();
+ final String targetName = mTargetNameMap.get(animator);
+ final Object target = mVectorDrawable.getTargetByName(targetName);
+ localAnimator.setTarget(target);
+ return localAnimator;
+ }
+
+ /**
+ * Inflates pending animators, if any, against a theme. Clears the list of
+ * pending animators.
+ *
+ * @param t the theme against which to inflate the animators
+ */
+ public void inflatePendingAnimators(@NonNull Resources res, @Nullable Theme t) {
+ final ArrayList<PendingAnimator> pendingAnims = mPendingAnims;
+ if (pendingAnims != null) {
+ mPendingAnims = null;
+
+ for (int i = 0, count = pendingAnims.size(); i < count; i++) {
+ final PendingAnimator pendingAnimator = pendingAnims.get(i);
+ final Animator objectAnimator = pendingAnimator.newInstance(res, t);
+ addTargetAnimator(pendingAnimator.target, objectAnimator);
+ }
+ }
+ }
+
+ /**
+ * Basically a constant state for Animators until we actually implement
+ * constant states for Animators.
+ */
+ private static class PendingAnimator {
+ public final int animResId;
+ public final float pathErrorScale;
+ public final String target;
+
+ public PendingAnimator(int animResId, float pathErrorScale, String target) {
+ this.animResId = animResId;
+ this.pathErrorScale = pathErrorScale;
+ this.target = target;
+ }
+
+ public Animator newInstance(Resources res, Theme theme) {
+ return AnimatorInflater.loadAnimator(res, theme, animResId, pathErrorScale);
+ }
}
}
@Override
public boolean isRunning() {
- return mAnimatedVectorState.mAnimatorSet.isRunning();
+ return mAnimatorSet.isRunning();
}
private boolean isStarted() {
- return mAnimatedVectorState.mAnimatorSet.isStarted();
+ return mAnimatorSet.isStarted();
}
@Override
public void start() {
+ ensureAnimatorSet();
+
// If any one of the animator has not ended, do nothing.
if (isStarted()) {
return;
}
- mAnimatedVectorState.mAnimatorSet.start();
+
+ mAnimatorSet.start();
invalidateSelf();
}
+ @NonNull
+ private void ensureAnimatorSet() {
+ if (!mHasAnimatorSet) {
+ mAnimatedVectorState.prepareLocalAnimators(mAnimatorSet, mRes);
+ mHasAnimatorSet = true;
+ mRes = null;
+ }
+ }
+
@Override
public void stop() {
- mAnimatedVectorState.mAnimatorSet.end();
+ mAnimatorSet.end();
}
/**
@@ -492,20 +632,23 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable {
* @hide
*/
public void reverse() {
- // Only reverse when all the animators can be reverse. Otherwise, partially
- // reverse is confusing.
+ ensureAnimatorSet();
+
+ // Only reverse when all the animators can be reversed.
if (!canReverse()) {
Log.w(LOGTAG, "AnimatedVectorDrawable can't reverse()");
return;
}
- mAnimatedVectorState.mAnimatorSet.reverse();
+
+ mAnimatorSet.reverse();
+ invalidateSelf();
}
/**
* @hide
*/
public boolean canReverse() {
- return mAnimatedVectorState.mAnimatorSet.canReverse();
+ return mAnimatorSet.canReverse();
}
private final Callback mCallback = new Callback() {
diff --git a/graphics/java/android/graphics/drawable/ClipDrawable.java b/graphics/java/android/graphics/drawable/ClipDrawable.java
index 2acf602..31fccd0 100644
--- a/graphics/java/android/graphics/drawable/ClipDrawable.java
+++ b/graphics/java/android/graphics/drawable/ClipDrawable.java
@@ -150,6 +150,23 @@ public class ClipDrawable extends DrawableWrapper {
}
@Override
+ public int getOpacity() {
+ final Drawable dr = getDrawable();
+ final int opacity = dr.getOpacity();
+ if (opacity == PixelFormat.TRANSPARENT || dr.getLevel() == 0) {
+ return PixelFormat.TRANSPARENT;
+ }
+
+ final int level = getLevel();
+ if (level >= MAX_LEVEL) {
+ return dr.getOpacity();
+ }
+
+ // Some portion of non-transparent drawable is showing.
+ return PixelFormat.TRANSLUCENT;
+ }
+
+ @Override
public void draw(Canvas canvas) {
final Drawable dr = getDrawable();
if (dr.getLevel() == 0) {
diff --git a/graphics/java/android/graphics/drawable/DrawableWrapper.java b/graphics/java/android/graphics/drawable/DrawableWrapper.java
index 58d43f9..9185e1a 100644
--- a/graphics/java/android/graphics/drawable/DrawableWrapper.java
+++ b/graphics/java/android/graphics/drawable/DrawableWrapper.java
@@ -180,7 +180,8 @@ public abstract class DrawableWrapper extends Drawable implements Drawable.Callb
@Override
public int getChangingConfigurations() {
return super.getChangingConfigurations()
- | (mState != null ? mState.getChangingConfigurations() : 0);
+ | (mState != null ? mState.getChangingConfigurations() : 0)
+ | mDrawable.getChangingConfigurations();
}
@Override
@@ -366,15 +367,12 @@ public abstract class DrawableWrapper extends Drawable implements Drawable.Callb
}
/**
- * Called during inflation to inflate the child element.
+ * Called during inflation to inflate the child element. The last valid
+ * child element will take precedence over any other child elements or
+ * explicit drawable attribute.
*/
void inflateChildDrawable(Resources r, XmlPullParser parser, AttributeSet attrs,
Resources.Theme theme) throws XmlPullParserException, IOException {
- // Drawable specified on the root element takes precedence.
- if (getDrawable() != null) {
- return;
- }
-
// Seek to the first child element.
Drawable dr = null;
int type;
@@ -383,7 +381,6 @@ public abstract class DrawableWrapper extends Drawable implements Drawable.Callb
&& (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
if (type == XmlPullParser.START_TAG) {
dr = Drawable.createFromXmlInner(r, parser, attrs, theme);
- break;
}
}
diff --git a/libs/hwui/CanvasState.cpp b/libs/hwui/CanvasState.cpp
index e88e9f6..e22b0d3 100644
--- a/libs/hwui/CanvasState.cpp
+++ b/libs/hwui/CanvasState.cpp
@@ -189,6 +189,9 @@ void CanvasState::setClippingRoundRect(LinearAllocator& allocator,
mSnapshot->setClippingRoundRect(allocator, rect, radius, highPriority);
}
+void CanvasState::setProjectionPathMask(LinearAllocator& allocator, const SkPath* path) {
+ mSnapshot->setProjectionPathMask(allocator, path);
+}
///////////////////////////////////////////////////////////////////////////////
// Quick Rejection
diff --git a/libs/hwui/CanvasState.h b/libs/hwui/CanvasState.h
index 8e4a4d3..9354e94 100644
--- a/libs/hwui/CanvasState.h
+++ b/libs/hwui/CanvasState.h
@@ -130,6 +130,7 @@ public:
void setClippingOutline(LinearAllocator& allocator, const Outline* outline);
void setClippingRoundRect(LinearAllocator& allocator,
const Rect& rect, float radius, bool highPriority = true);
+ void setProjectionPathMask(LinearAllocator& allocator, const SkPath* path);
/**
* Returns true if drawing in the rectangle (left, top, right, bottom)
diff --git a/libs/hwui/DeferredDisplayList.cpp b/libs/hwui/DeferredDisplayList.cpp
index 6fcf958..b077a85 100644
--- a/libs/hwui/DeferredDisplayList.cpp
+++ b/libs/hwui/DeferredDisplayList.cpp
@@ -195,6 +195,7 @@ public:
// Identical round rect clip state means both ops will clip in the same way, or not at all.
// As the state objects are const, we can compare their pointers to determine mergeability
if (lhs->mRoundRectClipState != rhs->mRoundRectClipState) return false;
+ if (lhs->mProjectionPathMask != rhs->mProjectionPathMask) return false;
/* Clipping compatibility check
*
diff --git a/libs/hwui/DeferredDisplayList.h b/libs/hwui/DeferredDisplayList.h
index 3d0ca6d..160c1ad 100644
--- a/libs/hwui/DeferredDisplayList.h
+++ b/libs/hwui/DeferredDisplayList.h
@@ -63,6 +63,7 @@ public:
mat4 mMatrix;
float mAlpha;
const RoundRectClipState* mRoundRectClipState;
+ const ProjectionPathMask* mProjectionPathMask;
};
class OpStatePair {
diff --git a/libs/hwui/Matrix.h b/libs/hwui/Matrix.h
index a760135..c152789 100644
--- a/libs/hwui/Matrix.h
+++ b/libs/hwui/Matrix.h
@@ -134,6 +134,12 @@ public:
uint8_t getType() const;
+ void multiplyInverse(const Matrix4& v) {
+ Matrix4 inv;
+ inv.loadInverse(v);
+ multiply(inv);
+ }
+
void multiply(const Matrix4& v) {
Matrix4 u;
u.loadMultiply(*this, v);
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index b3fb7ef..8f91620 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -40,6 +40,7 @@
#include <SkCanvas.h>
#include <SkColor.h>
+#include <SkPathOps.h>
#include <SkShader.h>
#include <SkTypeface.h>
@@ -1193,8 +1194,9 @@ bool OpenGLRenderer::storeDisplayState(DeferredDisplayState& state, int stateDef
state.mMatrix.load(*currentMatrix);
state.mAlpha = currentSnapshot()->alpha;
- // always store/restore, since it's just a pointer
+ // always store/restore, since these are just pointers
state.mRoundRectClipState = currentSnapshot()->roundRectClipState;
+ state.mProjectionPathMask = currentSnapshot()->projectionPathMask;
return false;
}
@@ -1202,6 +1204,7 @@ void OpenGLRenderer::restoreDisplayState(const DeferredDisplayState& state, bool
setMatrix(state.mMatrix);
writableSnapshot()->alpha = state.mAlpha;
writableSnapshot()->roundRectClipState = state.mRoundRectClipState;
+ writableSnapshot()->projectionPathMask = state.mProjectionPathMask;
if (state.mClipValid && !skipClipRestore) {
writableSnapshot()->setClip(state.mClip.left, state.mClip.top,
@@ -1758,6 +1761,7 @@ void OpenGLRenderer::drawVertexBuffer(float translateX, float translateY,
void OpenGLRenderer::drawConvexPath(const SkPath& path, const SkPaint* paint) {
VertexBuffer vertexBuffer;
// TODO: try clipping large paths to viewport
+
PathTessellator::tessellatePath(path, paint, *currentTransform(), vertexBuffer);
drawVertexBuffer(vertexBuffer, paint);
}
@@ -1864,19 +1868,41 @@ void OpenGLRenderer::drawCircle(float x, float y, float radius, const SkPaint* p
|| PaintUtils::paintWillNotDraw(*p)) {
return;
}
+
if (p->getPathEffect() != nullptr) {
mCaches.textureState().activateTexture(0);
PathTexture* texture = mCaches.pathCache.getCircle(radius, p);
drawShape(x - radius, y - radius, texture, p);
+ return;
+ }
+
+ SkPath path;
+ if (p->getStyle() == SkPaint::kStrokeAndFill_Style) {
+ path.addCircle(x, y, radius + p->getStrokeWidth() / 2);
} else {
- SkPath path;
- if (p->getStyle() == SkPaint::kStrokeAndFill_Style) {
- path.addCircle(x, y, radius + p->getStrokeWidth() / 2);
- } else {
- path.addCircle(x, y, radius);
- }
- drawConvexPath(path, p);
+ path.addCircle(x, y, radius);
+ }
+
+ if (CC_UNLIKELY(currentSnapshot()->projectionPathMask != nullptr)) {
+ // mask ripples with projection mask
+ SkPath maskPath = *(currentSnapshot()->projectionPathMask->projectionMask);
+
+ Matrix4 screenSpaceTransform;
+ currentSnapshot()->buildScreenSpaceTransform(&screenSpaceTransform);
+
+ Matrix4 totalTransform;
+ totalTransform.loadInverse(screenSpaceTransform);
+ totalTransform.multiply(currentSnapshot()->projectionPathMask->projectionMaskTransform);
+
+ SkMatrix skTotalTransform;
+ totalTransform.copyTo(skTotalTransform);
+ maskPath.transform(skTotalTransform);
+
+ // Mask the ripple path by the projection mask, now that it's
+ // in local space. Note that this can create CCW paths.
+ Op(path, maskPath, kIntersect_PathOp, &path);
}
+ drawConvexPath(path, p);
}
void OpenGLRenderer::drawOval(float left, float top, float right, float bottom,
@@ -2149,6 +2175,10 @@ void OpenGLRenderer::setClippingRoundRect(LinearAllocator& allocator,
mState.setClippingRoundRect(allocator, rect, radius, highPriority);
}
+void OpenGLRenderer::setProjectionPathMask(LinearAllocator& allocator, const SkPath* path) {
+ mState.setProjectionPathMask(allocator, path);
+}
+
void OpenGLRenderer::drawText(const char* text, int bytesCount, int count, float x, float y,
const float* positions, const SkPaint* paint, float totalAdvance, const Rect& bounds,
DrawOpMode drawOpMode) {
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index 218818d..8dae82c 100755
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -399,6 +399,7 @@ public:
void setClippingOutline(LinearAllocator& allocator, const Outline* outline);
void setClippingRoundRect(LinearAllocator& allocator,
const Rect& rect, float radius, bool highPriority = true);
+ void setProjectionPathMask(LinearAllocator& allocator, const SkPath* path);
inline bool hasRectToRectTransform() const { return mState.hasRectToRectTransform(); }
inline const mat4* currentTransform() const { return mState.currentTransform(); }
diff --git a/libs/hwui/PathTessellator.cpp b/libs/hwui/PathTessellator.cpp
index c1f61d6..547c877 100644
--- a/libs/hwui/PathTessellator.cpp
+++ b/libs/hwui/PathTessellator.cpp
@@ -37,6 +37,7 @@
#include <SkPath.h>
#include <SkPaint.h>
+#include <SkPoint.h>
#include <SkGeometry.h> // WARNING: Internal Skia Header
#include <stdlib.h>
@@ -151,13 +152,11 @@ public:
*/
inline int capExtraDivisions() const {
if (cap == SkPaint::kRound_Cap) {
+ // always use 2 points for hairline
if (halfStrokeWidth == 0.0f) return 2;
- // ROUND_CAP_THRESH is the maximum error for polygonal approximation of the round cap
- const float errConst = (-ROUND_CAP_THRESH / halfStrokeWidth + 1);
- const float targetCosVal = 2 * errConst * errConst - 1;
- int neededDivisions = (int)(ceilf(PI / acos(targetCosVal)/2)) * 2;
- return neededDivisions;
+ float threshold = MathUtils::min(inverseScaleX, inverseScaleY) * ROUND_CAP_THRESH;
+ return MathUtils::divisionsNeededToApproximateArc(halfStrokeWidth, PI, threshold);
}
return 0;
}
@@ -912,6 +911,40 @@ void pushToVector(Vector<Vertex>& vertices, float x, float y) {
Vertex::set(newVertex, x, y);
}
+class ClockwiseEnforcer {
+public:
+ void addPoint(const SkPoint& point) {
+ double x = point.x();
+ double y = point.y();
+
+ if (initialized) {
+ sum += (x + lastX) * (y - lastY);
+ } else {
+ initialized = true;
+ }
+
+ lastX = x;
+ lastY = y;
+ }
+ void reverseVectorIfNotClockwise(Vector<Vertex>& vertices) {
+ if (sum < 0) {
+ // negative sum implies CounterClockwise
+ const int size = vertices.size();
+ for (int i = 0; i < size / 2; i++) {
+ Vertex tmp = vertices[i];
+ int k = size - 1 - i;
+ vertices.replaceAt(vertices[k], i);
+ vertices.replaceAt(tmp, k);
+ }
+ }
+ }
+private:
+ bool initialized = false;
+ double lastX = 0;
+ double lastY = 0;
+ double sum = 0;
+};
+
bool PathTessellator::approximatePathOutlineVertices(const SkPath& path, bool forceClose,
float sqrInvScaleX, float sqrInvScaleY, float thresholdSquared,
Vector<Vertex>& outputVertices) {
@@ -922,18 +955,22 @@ bool PathTessellator::approximatePathOutlineVertices(const SkPath& path, bool fo
SkPath::Iter iter(path, forceClose);
SkPoint pts[4];
SkPath::Verb v;
+ ClockwiseEnforcer clockwiseEnforcer;
while (SkPath::kDone_Verb != (v = iter.next(pts))) {
switch (v) {
case SkPath::kMove_Verb:
pushToVector(outputVertices, pts[0].x(), pts[0].y());
ALOGV("Move to pos %f %f", pts[0].x(), pts[0].y());
+ clockwiseEnforcer.addPoint(pts[0]);
break;
case SkPath::kClose_Verb:
ALOGV("Close at pos %f %f", pts[0].x(), pts[0].y());
+ clockwiseEnforcer.addPoint(pts[0]);
break;
case SkPath::kLine_Verb:
ALOGV("kLine_Verb %f %f -> %f %f", pts[0].x(), pts[0].y(), pts[1].x(), pts[1].y());
pushToVector(outputVertices, pts[1].x(), pts[1].y());
+ clockwiseEnforcer.addPoint(pts[1]);
break;
case SkPath::kQuad_Verb:
ALOGV("kQuad_Verb");
@@ -942,6 +979,8 @@ bool PathTessellator::approximatePathOutlineVertices(const SkPath& path, bool fo
pts[2].x(), pts[2].y(),
pts[1].x(), pts[1].y(),
sqrInvScaleX, sqrInvScaleY, thresholdSquared, outputVertices);
+ clockwiseEnforcer.addPoint(pts[1]);
+ clockwiseEnforcer.addPoint(pts[2]);
break;
case SkPath::kCubic_Verb:
ALOGV("kCubic_Verb");
@@ -951,6 +990,9 @@ bool PathTessellator::approximatePathOutlineVertices(const SkPath& path, bool fo
pts[3].x(), pts[3].y(),
pts[2].x(), pts[2].y(),
sqrInvScaleX, sqrInvScaleY, thresholdSquared, outputVertices);
+ clockwiseEnforcer.addPoint(pts[1]);
+ clockwiseEnforcer.addPoint(pts[2]);
+ clockwiseEnforcer.addPoint(pts[3]);
break;
case SkPath::kConic_Verb: {
ALOGV("kConic_Verb");
@@ -965,6 +1007,8 @@ bool PathTessellator::approximatePathOutlineVertices(const SkPath& path, bool fo
quads[offset+1].x(), quads[offset+1].y(),
sqrInvScaleX, sqrInvScaleY, thresholdSquared, outputVertices);
}
+ clockwiseEnforcer.addPoint(pts[1]);
+ clockwiseEnforcer.addPoint(pts[2]);
break;
}
default:
@@ -972,13 +1016,17 @@ bool PathTessellator::approximatePathOutlineVertices(const SkPath& path, bool fo
}
}
+ bool wasClosed = false;
int size = outputVertices.size();
if (size >= 2 && outputVertices[0].x == outputVertices[size - 1].x &&
outputVertices[0].y == outputVertices[size - 1].y) {
outputVertices.pop();
- return true;
+ wasClosed = true;
}
- return false;
+
+ // ensure output vector is clockwise
+ clockwiseEnforcer.reverseVectorIfNotClockwise(outputVertices);
+ return wasClosed;
}
///////////////////////////////////////////////////////////////////////////////
diff --git a/libs/hwui/PathTessellator.h b/libs/hwui/PathTessellator.h
index 8ac9a3b..ccae65b 100644
--- a/libs/hwui/PathTessellator.h
+++ b/libs/hwui/PathTessellator.h
@@ -82,7 +82,7 @@ public:
const mat4& transform, VertexBuffer& vertexBuffer);
/**
- * Approximates a convex, CW outline into a Vector of 2d vertices.
+ * Approximates a convex outline into a clockwise Vector of 2d vertices.
*
* @param path The outline to be approximated
* @param thresholdSquared The threshold of acceptable error (in pixels) when approximating
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index 9e5ec28..7d3b41e 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -769,31 +769,9 @@ void RenderNode::issueOperationsOfProjectedChildren(OpenGLRenderer& renderer, T&
const RenderProperties& backgroundProps = backgroundOp->mRenderNode->properties();
renderer.translate(backgroundProps.getTranslationX(), backgroundProps.getTranslationY());
- // If the projection reciever has an outline, we mask each of the projected rendernodes to it
- // Either with clipRect, or special saveLayer masking
- if (projectionReceiverOutline != nullptr) {
- const SkRect& outlineBounds = projectionReceiverOutline->getBounds();
- if (projectionReceiverOutline->isRect(nullptr)) {
- // mask to the rect outline simply with clipRect
- ClipRectOp* clipOp = new (alloc) ClipRectOp(
- outlineBounds.left(), outlineBounds.top(),
- outlineBounds.right(), outlineBounds.bottom(), SkRegion::kIntersect_Op);
- handler(clipOp, PROPERTY_SAVECOUNT, properties().getClipToBounds());
- } else {
- // wrap the projected RenderNodes with a SaveLayer that will mask to the outline
- SaveLayerOp* op = new (alloc) SaveLayerOp(
- outlineBounds.left(), outlineBounds.top(),
- outlineBounds.right(), outlineBounds.bottom(),
- 255, SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag | SkCanvas::kARGB_ClipLayer_SaveFlag);
- op->setMask(projectionReceiverOutline);
- handler(op, PROPERTY_SAVECOUNT, properties().getClipToBounds());
-
- /* TODO: add optimizations here to take advantage of placement/size of projected
- * children (which may shrink saveLayer area significantly). This is dependent on
- * passing actual drawing/dirtying bounds of projected content down to native.
- */
- }
- }
+ // If the projection reciever has an outline, we mask projected content to it
+ // (which we know, apriori, are all tessellated paths)
+ renderer.setProjectionPathMask(alloc, projectionReceiverOutline);
// draw projected nodes
for (size_t i = 0; i < mProjectedNodes.size(); i++) {
@@ -808,10 +786,8 @@ void RenderNode::issueOperationsOfProjectedChildren(OpenGLRenderer& renderer, T&
renderer.restoreToCount(restoreTo);
}
- if (projectionReceiverOutline != nullptr) {
- handler(new (alloc) RestoreToCountOp(restoreTo),
- PROPERTY_SAVECOUNT, properties().getClipToBounds());
- }
+ handler(new (alloc) RestoreToCountOp(restoreTo),
+ PROPERTY_SAVECOUNT, properties().getClipToBounds());
}
/**
diff --git a/libs/hwui/ShadowTessellator.cpp b/libs/hwui/ShadowTessellator.cpp
index fb28531..024ff10 100644
--- a/libs/hwui/ShadowTessellator.cpp
+++ b/libs/hwui/ShadowTessellator.cpp
@@ -158,71 +158,6 @@ Vector2 ShadowTessellator::calculateNormal(const Vector2& p1, const Vector2& p2)
}
return result;
}
-/**
- * Test whether the polygon is order in clockwise.
- *
- * @param polygon the polygon as a Vector2 array
- * @param len the number of points of the polygon
- */
-bool ShadowTessellator::isClockwise(const Vector2* polygon, int len) {
- if (len < 2 || polygon == nullptr) {
- return true;
- }
- double sum = 0;
- double p1x = polygon[len - 1].x;
- double p1y = polygon[len - 1].y;
- for (int i = 0; i < len; i++) {
-
- double p2x = polygon[i].x;
- double p2y = polygon[i].y;
- sum += p1x * p2y - p2x * p1y;
- p1x = p2x;
- p1y = p2y;
- }
- return sum < 0;
-}
-
-bool ShadowTessellator::isClockwisePath(const SkPath& path) {
- SkPath::Iter iter(path, false);
- SkPoint pts[4];
- SkPath::Verb v;
-
- Vector<Vector2> arrayForDirection;
- while (SkPath::kDone_Verb != (v = iter.next(pts))) {
- switch (v) {
- case SkPath::kMove_Verb:
- arrayForDirection.add((Vector2){pts[0].x(), pts[0].y()});
- break;
- case SkPath::kLine_Verb:
- arrayForDirection.add((Vector2){pts[1].x(), pts[1].y()});
- break;
- case SkPath::kConic_Verb:
- case SkPath::kQuad_Verb:
- arrayForDirection.add((Vector2){pts[1].x(), pts[1].y()});
- arrayForDirection.add((Vector2){pts[2].x(), pts[2].y()});
- break;
- case SkPath::kCubic_Verb:
- arrayForDirection.add((Vector2){pts[1].x(), pts[1].y()});
- arrayForDirection.add((Vector2){pts[2].x(), pts[2].y()});
- arrayForDirection.add((Vector2){pts[3].x(), pts[3].y()});
- break;
- default:
- break;
- }
- }
-
- return isClockwise(arrayForDirection.array(), arrayForDirection.size());
-}
-
-void ShadowTessellator::reverseVertexArray(Vertex* polygon, int len) {
- int n = len / 2;
- for (int i = 0; i < n; i++) {
- Vertex tmp = polygon[i];
- int k = len - 1 - i;
- polygon[i] = polygon[k];
- polygon[k] = tmp;
- }
-}
int ShadowTessellator::getExtraVertexNumber(const Vector2& vector1,
const Vector2& vector2, float divisor) {
diff --git a/libs/hwui/ShadowTessellator.h b/libs/hwui/ShadowTessellator.h
index c04d8ef..5f4c9c5 100644
--- a/libs/hwui/ShadowTessellator.h
+++ b/libs/hwui/ShadowTessellator.h
@@ -83,23 +83,6 @@ public:
static bool isClockwise(const Vector2* polygon, int len);
static Vector2 calculateNormal(const Vector2& p1, const Vector2& p2);
- /**
- * Determine whether the path is clockwise, using the control points.
- *
- * TODO: Given the skia is using inverted Y coordinate, shadow system needs
- * to convert to the same coordinate to avoid the extra reverse.
- *
- * @param path The path to be examined.
- */
- static bool isClockwisePath(const SkPath &path);
-
- /**
- * Reverse the vertex array.
- *
- * @param polygon The vertex array to be reversed.
- * @param len The length of the vertex array.
- */
- static void reverseVertexArray(Vertex* polygon, int len);
static int getExtraVertexNumber(const Vector2& vector1, const Vector2& vector2,
float divisor);
diff --git a/libs/hwui/Snapshot.cpp b/libs/hwui/Snapshot.cpp
index 9e7faee..beb2e1d 100644
--- a/libs/hwui/Snapshot.cpp
+++ b/libs/hwui/Snapshot.cpp
@@ -36,6 +36,7 @@ Snapshot::Snapshot()
, empty(false)
, alpha(1.0f)
, roundRectClipState(nullptr)
+ , projectionPathMask(nullptr)
, mClipArea(&mClipAreaRoot) {
transform = &mTransformRoot;
region = nullptr;
@@ -54,6 +55,7 @@ Snapshot::Snapshot(const sp<Snapshot>& s, int saveFlags)
, empty(false)
, alpha(s->alpha)
, roundRectClipState(s->roundRectClipState)
+ , projectionPathMask(s->projectionPathMask)
, mClipArea(nullptr)
, mViewportData(s->mViewportData)
, mRelativeLightCenter(s->mRelativeLightCenter) {
@@ -141,6 +143,34 @@ void Snapshot::resetTransform(float x, float y, float z) {
transform->loadTranslate(x, y, z);
}
+void Snapshot::buildScreenSpaceTransform(Matrix4* outTransform) const {
+ // build (reverse ordered) list of the stack of snapshots, terminated with a NULL
+ Vector<const Snapshot*> snapshotList;
+ snapshotList.push(nullptr);
+ const Snapshot* current = this;
+ do {
+ snapshotList.push(current);
+ current = current->previous.get();
+ } while (current);
+
+ // traverse the list, adding in each transform that contributes to the total transform
+ outTransform->loadIdentity();
+ for (size_t i = snapshotList.size() - 1; i > 0; i--) {
+ // iterate down the stack
+ const Snapshot* current = snapshotList[i];
+ const Snapshot* next = snapshotList[i - 1];
+ if (current->flags & kFlagIsFboLayer) {
+ // if we've hit a layer, translate by the layer's draw offset
+ outTransform->translate(current->layer->layer.left, current->layer->layer.top);
+ }
+ if (!next || (next->flags & kFlagIsFboLayer)) {
+ // if this snapshot is last, or if this snapshot is last before an
+ // FBO layer (which reset the transform), apply it
+ outTransform->multiply(*(current->transform));
+ }
+ }
+}
+
///////////////////////////////////////////////////////////////////////////////
// Clipping round rect
///////////////////////////////////////////////////////////////////////////////
@@ -191,6 +221,18 @@ void Snapshot::setClippingRoundRect(LinearAllocator& allocator, const Rect& boun
roundRectClipState = state;
}
+void Snapshot::setProjectionPathMask(LinearAllocator& allocator, const SkPath* path) {
+ if (path) {
+ ProjectionPathMask* mask = new (allocator) ProjectionPathMask;
+ mask->projectionMask = path;
+ buildScreenSpaceTransform(&(mask->projectionMaskTransform));
+
+ projectionPathMask = mask;
+ } else {
+ projectionPathMask = nullptr;
+ }
+}
+
///////////////////////////////////////////////////////////////////////////////
// Queries
///////////////////////////////////////////////////////////////////////////////
diff --git a/libs/hwui/Snapshot.h b/libs/hwui/Snapshot.h
index 4d704ab..af6ad72 100644
--- a/libs/hwui/Snapshot.h
+++ b/libs/hwui/Snapshot.h
@@ -63,6 +63,17 @@ public:
float radius;
};
+class ProjectionPathMask {
+public:
+ /** static void* operator new(size_t size); PURPOSELY OMITTED, allocator only **/
+ static void* operator new(size_t size, LinearAllocator& allocator) {
+ return allocator.alloc(size);
+ }
+
+ const SkPath* projectionMask;
+ Matrix4 projectionMaskTransform;
+};
+
/**
* A snapshot holds information about the current state of the rendering
* surface. A snapshot is usually created whenever the user calls save()
@@ -190,6 +201,11 @@ public:
float radius, bool highPriority);
/**
+ * Sets (and replaces) the current projection mask
+ */
+ void setProjectionPathMask(LinearAllocator& allocator, const SkPath* path);
+
+ /**
* Indicates whether this snapshot should be ignored. A snapshot
* is typically ignored if its layer is invisible or empty.
*/
@@ -201,6 +217,12 @@ public:
bool hasPerspectiveTransform() const;
/**
+ * Fills outTransform with the current, total transform to screen space,
+ * across layer boundaries.
+ */
+ void buildScreenSpaceTransform(Matrix4* outTransform) const;
+
+ /**
* Dirty flags.
*/
int flags;
@@ -272,6 +294,11 @@ public:
*/
const RoundRectClipState* roundRectClipState;
+ /**
+ * Current projection masking path - used exclusively to mask tessellated circles.
+ */
+ const ProjectionPathMask* projectionPathMask;
+
void dump() const;
private:
diff --git a/libs/hwui/TessellationCache.cpp b/libs/hwui/TessellationCache.cpp
index fc173f7..704a691 100644
--- a/libs/hwui/TessellationCache.cpp
+++ b/libs/hwui/TessellationCache.cpp
@@ -207,6 +207,16 @@ static void mapPointFakeZ(Vector3& point, const mat4* transformXY, const mat4* t
transformXY->mapPoint(point.x, point.y);
}
+static void reverseVertexArray(Vertex* polygon, int len) {
+ int n = len / 2;
+ for (int i = 0; i < n; i++) {
+ Vertex tmp = polygon[i];
+ int k = len - 1 - i;
+ polygon[i] = polygon[k];
+ polygon[k] = tmp;
+ }
+}
+
static void tessellateShadows(
const Matrix4* drawTransform, const Rect* localClip,
bool isCasterOpaque, const SkPath* casterPerimeter,
@@ -219,10 +229,9 @@ static void tessellateShadows(
const float casterRefinementThresholdSquared = 4.0f;
PathTessellator::approximatePathOutlineVertices(*casterPerimeter,
casterRefinementThresholdSquared, casterVertices2d);
- if (!ShadowTessellator::isClockwisePath(*casterPerimeter)) {
- ShadowTessellator::reverseVertexArray(casterVertices2d.editArray(),
- casterVertices2d.size());
- }
+
+ // Shadow requires CCW for now. TODO: remove potential double-reverse
+ reverseVertexArray(casterVertices2d.editArray(), casterVertices2d.size());
if (casterVertices2d.size() == 0) return;
diff --git a/libs/hwui/utils/MathUtils.h b/libs/hwui/utils/MathUtils.h
index d89859b..9c3787c 100644
--- a/libs/hwui/utils/MathUtils.h
+++ b/libs/hwui/utils/MathUtils.h
@@ -16,6 +16,8 @@
#ifndef MATHUTILS_H
#define MATHUTILS_H
+#include <math.h>
+
namespace android {
namespace uirenderer {
@@ -62,6 +64,19 @@ public:
return scale;
}
+ /**
+ * Returns the number of points (beyond two, the start and end) needed to form a polygonal
+ * approximation of an arc, with a given threshold value.
+ */
+ inline static int divisionsNeededToApproximateArc(float radius,
+ float angleInRads, float threshold) {
+ const float errConst = (-threshold / radius + 1);
+ const float targetCosVal = 2 * errConst * errConst - 1;
+
+ // needed divisions are rounded up from approximation
+ return (int)(ceilf(angleInRads / acos(targetCosVal)/2)) * 2;
+ }
+
inline static bool areEqual(float valueA, float valueB) {
return isZero(valueA - valueB);
}
diff --git a/location/java/android/location/CountryDetector.java b/location/java/android/location/CountryDetector.java
index 0b780ce..ce3c56f 100644
--- a/location/java/android/location/CountryDetector.java
+++ b/location/java/android/location/CountryDetector.java
@@ -44,8 +44,6 @@ import android.util.Log;
* You do not instantiate this class directly; instead, retrieve it through
* {@link android.content.Context#getSystemService
* Context.getSystemService(Context.COUNTRY_DETECTOR)}.
- * <p>
- * Both ACCESS_FINE_LOCATION and ACCESS_COARSE_LOCATION permissions are needed.
*
* @hide
*/
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index f76189c..7293c6c 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -1990,9 +1990,24 @@ public class AudioTrack
* The dead object error code is not returned if some data was successfully transferred.
* In this case, the error is returned at the next write().
*/
- public int write(ByteBuffer audioData, int sizeInBytes,
+ public int write(@NonNull ByteBuffer audioData, int sizeInBytes,
@WriteMode int writeMode, long timestamp) {
+ if (mState == STATE_UNINITIALIZED) {
+ Log.e(TAG, "AudioTrack.write() called in invalid state STATE_UNINITIALIZED");
+ return ERROR_INVALID_OPERATION;
+ }
+
+ if ((writeMode != WRITE_BLOCKING) && (writeMode != WRITE_NON_BLOCKING)) {
+ Log.e(TAG, "AudioTrack.write() called with invalid blocking mode");
+ return ERROR_BAD_VALUE;
+ }
+
+ if (mDataLoadMode != MODE_STREAM) {
+ Log.e(TAG, "AudioTrack.write() with timestamp called for non-streaming mode track");
+ return ERROR_INVALID_OPERATION;
+ }
+
if ((mAttributes.getFlags() & AudioAttributes.FLAG_HW_AV_SYNC) == 0) {
Log.d(TAG, "AudioTrack.write() called on a regular AudioTrack. Ignoring pts...");
return write(audioData, sizeInBytes, writeMode);
diff --git a/media/jni/Android.mk b/media/jni/Android.mk
index 51d0140..79557bc 100644
--- a/media/jni/Android.mk
+++ b/media/jni/Android.mk
@@ -69,7 +69,7 @@ LOCAL_C_INCLUDES += \
$(PV_INCLUDES) \
$(JNI_H_INCLUDE)
-LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code
+LOCAL_CFLAGS += -Wall -Werror -Wno-error=deprecated-declarations -Wunused -Wunreachable-code
LOCAL_MODULE:= libmedia_jni
diff --git a/media/jni/soundpool/Android.mk b/media/jni/soundpool/Android.mk
index 2476056..2bc41b5 100644
--- a/media/jni/soundpool/Android.mk
+++ b/media/jni/soundpool/Android.mk
@@ -18,6 +18,6 @@ LOCAL_SHARED_LIBRARIES := \
LOCAL_MODULE:= libsoundpool
-LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code
+LOCAL_CFLAGS += -Wall -Werror -Wno-error=deprecated-declarations -Wunused -Wunreachable-code
include $(BUILD_SHARED_LIBRARY)
diff --git a/media/jni/soundpool/SoundPool.cpp b/media/jni/soundpool/SoundPool.cpp
index 8038cdf..a705bcc 100644
--- a/media/jni/soundpool/SoundPool.cpp
+++ b/media/jni/soundpool/SoundPool.cpp
@@ -753,6 +753,7 @@ void SoundChannel::play(const sp<Sample>& sample, int nextChannelID, float leftV
status = newTrack->initCheck();
if (status != NO_ERROR) {
ALOGE("Error creating AudioTrack");
+ // newTrack goes out of scope, so reference count drops to zero
goto exit;
}
// From now on, AudioTrack callbacks received with previous toggle value will be ignored.
diff --git a/media/tests/audiotests/Android.mk b/media/tests/audiotests/Android.mk
index 794e7f22..3507434 100644
--- a/media/tests/audiotests/Android.mk
+++ b/media/tests/audiotests/Android.mk
@@ -18,6 +18,6 @@ LOCAL_SHARED_LIBRARIES := \
LOCAL_MODULE_TAGS := tests
-LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code
+LOCAL_CFLAGS += -Wall -Werror -Wno-error=deprecated-declarations -Wunused -Wunreachable-code
include $(BUILD_EXECUTABLE)
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
index 7049d6a..3130875 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
@@ -755,7 +755,7 @@ public class AccessPoint implements Comparable<AccessPoint> {
int index = state.ordinal();
if (index >= formats.length || formats[index].length() == 0) {
- return null;
+ return "";
}
return String.format(formats[index], ssid);
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
index ed954bb..abce31f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
@@ -149,9 +149,10 @@ public class BluetoothTile extends QSTile<QSTile.BooleanState> {
private final BluetoothController.Callback mCallback = new BluetoothController.Callback() {
@Override
- public void onBluetoothStateChange(boolean enabled, boolean connecting) {
+ public void onBluetoothStateChange(boolean enabled) {
refreshState();
}
+
@Override
public void onBluetoothDevicesChanged() {
mUiHandler.post(new Runnable() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java
index cbe4c4d..8fa9c7e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java
@@ -35,7 +35,7 @@ public interface BluetoothController {
void disconnect(CachedBluetoothDevice device);
public interface Callback {
- void onBluetoothStateChange(boolean enabled, boolean connecting);
+ void onBluetoothStateChange(boolean enabled);
void onBluetoothDevicesChanged();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java
index ed98a15..3cc9297 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java
@@ -41,7 +41,7 @@ public class BluetoothControllerImpl implements BluetoothController, BluetoothCa
private final LocalBluetoothManager mLocalBluetoothManager;
private boolean mEnabled;
- private boolean mConnecting;
+ private int mConnectionState = BluetoothAdapter.STATE_DISCONNECTED;
private CachedBluetoothDevice mLastDevice;
private final H mHandler = new H();
@@ -63,7 +63,7 @@ public class BluetoothControllerImpl implements BluetoothController, BluetoothCa
return;
}
pw.print(" mEnabled="); pw.println(mEnabled);
- pw.print(" mConnecting="); pw.println(mConnecting);
+ pw.print(" mConnectionState="); pw.println(stateToString(mConnectionState));
pw.print(" mLastDevice="); pw.println(mLastDevice);
pw.print(" mCallbacks.size="); pw.println(mCallbacks.size());
pw.println(" Bluetooth Devices:");
@@ -73,10 +73,25 @@ public class BluetoothControllerImpl implements BluetoothController, BluetoothCa
}
}
+ private static String stateToString(int state) {
+ switch (state) {
+ case BluetoothAdapter.STATE_CONNECTED:
+ return "CONNECTED";
+ case BluetoothAdapter.STATE_CONNECTING:
+ return "CONNECTING";
+ case BluetoothAdapter.STATE_DISCONNECTED:
+ return "DISCONNECTED";
+ case BluetoothAdapter.STATE_DISCONNECTING:
+ return "DISCONNECTING";
+ }
+ return "UNKNOWN(" + state + ")";
+ }
+
private String getDeviceString(CachedBluetoothDevice device) {
return device.getName() + " " + device.getBondState() + " " + device.isConnected();
}
+ @Override
public void addStateChangedCallback(Callback cb) {
mCallbacks.add(cb);
mHandler.sendEmptyMessage(H.MSG_STATE_CHANGED);
@@ -94,14 +109,12 @@ public class BluetoothControllerImpl implements BluetoothController, BluetoothCa
@Override
public boolean isBluetoothConnected() {
- return mLocalBluetoothManager != null
- && mLocalBluetoothManager.getBluetoothAdapter().getConnectionState()
- == BluetoothAdapter.STATE_CONNECTED;
+ return mConnectionState == BluetoothAdapter.STATE_CONNECTED;
}
@Override
public boolean isBluetoothConnecting() {
- return mConnecting;
+ return mConnectionState == BluetoothAdapter.STATE_CONNECTING;
}
@Override
@@ -190,7 +203,7 @@ public class BluetoothControllerImpl implements BluetoothController, BluetoothCa
@Override
public void onConnectionStateChanged(CachedBluetoothDevice cachedDevice, int state) {
- mConnecting = state == BluetoothAdapter.STATE_CONNECTING;
+ mConnectionState = state;
mLastDevice = cachedDevice;
updateConnected();
mHandler.sendEmptyMessage(H.MSG_STATE_CHANGED);
@@ -225,7 +238,7 @@ public class BluetoothControllerImpl implements BluetoothController, BluetoothCa
}
private void fireStateChange(BluetoothController.Callback cb) {
- cb.onBluetoothStateChange(mEnabled, mConnecting);
+ cb.onBluetoothStateChange(mEnabled);
}
}
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 2b6f8e1..706e965 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -39,6 +39,8 @@ import static org.xmlpull.v1.XmlPullParser.START_TAG;
import android.Manifest;
import android.app.AppOpsManager;
import android.app.ApplicationThreadNative;
+import android.app.AssistContent;
+import android.app.AssistStructure;
import android.app.IActivityContainer;
import android.app.IActivityContainerCallback;
import android.app.IAppTask;
@@ -55,6 +57,7 @@ import android.graphics.Rect;
import android.os.BatteryStats;
import android.os.PersistableBundle;
import android.os.PowerManager;
+import android.os.Trace;
import android.os.TransactionTooLargeException;
import android.os.WorkSource;
import android.os.storage.IMountService;
@@ -359,6 +362,10 @@ public final class ActivityManagerService extends ActivityManagerNative
// to respond with the result.
static final int PENDING_ASSIST_EXTRAS_TIMEOUT = 500;
+ // How long top wait when going through the modern assist (which doesn't need to block
+ // on getting this result before starting to launch its UI).
+ static final int PENDING_ASSIST_EXTRAS_LONG_TIMEOUT = 2000;
+
// Maximum number of persisted Uri grants a package is allowed
static final int MAX_PERSISTED_URI_GRANTS = 128;
@@ -476,6 +483,8 @@ public final class ActivityManagerService extends ActivityManagerNative
public final int userHandle;
public boolean haveResult = false;
public Bundle result = null;
+ public AssistStructure structure = null;
+ public AssistContent content = null;
public PendingAssistExtras(ActivityRecord _activity, Bundle _extras, Intent _intent,
String _hint, IResultReceiver _receiver, int _userHandle) {
activity = _activity;
@@ -3284,12 +3293,15 @@ public final class ActivityManagerService extends ActivityManagerNative
// the PID of the new process, or else throw a RuntimeException.
boolean isActivityProcess = (entryPoint == null);
if (entryPoint == null) entryPoint = "android.app.ActivityThread";
+ Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Start proc: " +
+ app.processName);
checkTime(startTime, "startProcess: asking zygote to start proc");
Process.ProcessStartResult startResult = Process.start(entryPoint,
app.processName, uid, uid, gids, debugFlags, mountExternal,
app.info.targetSdkVersion, app.info.seinfo, requiredAbi, instructionSet,
app.info.dataDir, entryPointArgs);
checkTime(startTime, "startProcess: returned from zygote!");
+ Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
if (app.isolated) {
mBatteryStatsService.addIsolatedUid(app.uid, app.info.uid);
@@ -8525,13 +8537,16 @@ public final class ActivityManagerService extends ActivityManagerNative
return;
}
+ // Find any running services associated with this app and stop if needed.
+ mServices.cleanUpRemovedTaskLocked(tr, component, new Intent(tr.getBaseIntent()));
+
if (!killProcess) {
return;
}
// Determine if the process(es) for this task should be killed.
final String pkg = component.getPackageName();
- ArrayList<ProcessRecord> procsToKill = new ArrayList<ProcessRecord>();
+ ArrayList<ProcessRecord> procsToKill = new ArrayList<>();
ArrayMap<String, SparseArray<ProcessRecord>> pmap = mProcessNames.getMap();
for (int i = 0; i < pmap.size(); i++) {
@@ -8560,20 +8575,24 @@ public final class ActivityManagerService extends ActivityManagerNative
}
}
+ if (proc.foregroundServices) {
+ // Don't kill process(es) with foreground service.
+ return;
+ }
+
// Add process to kill list.
procsToKill.add(proc);
}
}
- // Find any running services associated with this app and stop if needed.
- mServices.cleanUpRemovedTaskLocked(tr, component, new Intent(tr.getBaseIntent()));
-
// Kill the running processes.
for (int i = 0; i < procsToKill.size(); i++) {
ProcessRecord pr = procsToKill.get(i);
- if (pr.setSchedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE) {
+ if (pr.setSchedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE
+ && pr.curReceiver == null) {
pr.kill("remove task", true);
} else {
+ // We delay killing processes that are not in the background or running a receiver.
pr.waitingToKill = "remove task";
}
}
@@ -10613,7 +10632,7 @@ public final class ActivityManagerService extends ActivityManagerNative
@Override
public Bundle getAssistContextExtras(int requestType) {
PendingAssistExtras pae = enqueueAssistContext(requestType, null, null, null,
- UserHandle.getCallingUserId());
+ UserHandle.getCallingUserId(), PENDING_ASSIST_EXTRAS_TIMEOUT);
if (pae == null) {
return null;
}
@@ -10635,11 +10654,12 @@ public final class ActivityManagerService extends ActivityManagerNative
@Override
public void requestAssistContextExtras(int requestType, IResultReceiver receiver) {
- enqueueAssistContext(requestType, null, null, receiver, UserHandle.getCallingUserId());
+ enqueueAssistContext(requestType, null, null, receiver, UserHandle.getCallingUserId(),
+ PENDING_ASSIST_EXTRAS_LONG_TIMEOUT);
}
private PendingAssistExtras enqueueAssistContext(int requestType, Intent intent, String hint,
- IResultReceiver receiver, int userHandle) {
+ IResultReceiver receiver, int userHandle, long timeout) {
enforceCallingPermission(android.Manifest.permission.GET_TOP_ACTIVITY_INFO,
"enqueueAssistContext()");
synchronized (this) {
@@ -10665,7 +10685,7 @@ public final class ActivityManagerService extends ActivityManagerNative
activity.app.thread.requestAssistContextExtras(activity.appToken, pae,
requestType);
mPendingAssistExtras.add(pae);
- mHandler.postDelayed(pae, PENDING_ASSIST_EXTRAS_TIMEOUT);
+ mHandler.postDelayed(pae, timeout);
} catch (RemoteException e) {
Slog.w(TAG, "getAssistContextExtras failed: crash calling " + activity);
return null;
@@ -10694,10 +10714,13 @@ public final class ActivityManagerService extends ActivityManagerNative
}
}
- public void reportAssistContextExtras(IBinder token, Bundle extras) {
+ public void reportAssistContextExtras(IBinder token, Bundle extras, AssistStructure structure,
+ AssistContent content) {
PendingAssistExtras pae = (PendingAssistExtras)token;
synchronized (pae) {
pae.result = extras;
+ pae.structure = structure;
+ pae.content = content;
pae.haveResult = true;
pae.notifyAll();
if (pae.intent == null && pae.receiver == null) {
@@ -10717,8 +10740,12 @@ public final class ActivityManagerService extends ActivityManagerNative
}
if (pae.receiver != null) {
// Caller wants result sent back to them.
+ Bundle topBundle = new Bundle();
+ topBundle.putBundle("data", pae.extras);
+ topBundle.putParcelable("structure", pae.structure);
+ topBundle.putParcelable("content", pae.content);
try {
- pae.receiver.send(0, pae.extras);
+ pae.receiver.send(0, topBundle);
} catch (RemoteException e) {
}
return;
@@ -10737,7 +10764,8 @@ public final class ActivityManagerService extends ActivityManagerNative
}
public boolean launchAssistIntent(Intent intent, int requestType, String hint, int userHandle) {
- return enqueueAssistContext(requestType, intent, hint, null, userHandle) != null;
+ return enqueueAssistContext(requestType, intent, hint, null, userHandle,
+ PENDING_ASSIST_EXTRAS_TIMEOUT) != null;
}
public void registerProcessObserver(IProcessObserver observer) {
@@ -18323,8 +18351,7 @@ public final class ActivityManagerService extends ActivityManagerNative
}
}
- private final boolean applyOomAdjLocked(ProcessRecord app,
- ProcessRecord TOP_APP, boolean doingAll, long now) {
+ private final boolean applyOomAdjLocked(ProcessRecord app, boolean doingAll, long now) {
boolean success = true;
if (app.curRawAdj != app.setRawAdj) {
@@ -18346,8 +18373,8 @@ public final class ActivityManagerService extends ActivityManagerNative
if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(TAG_OOM_ADJ,
"Setting process group of " + app.processName
+ " to " + app.curSchedGroup);
- if (app.waitingToKill != null &&
- app.setSchedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE) {
+ if (app.waitingToKill != null && app.curReceiver == null
+ && app.setSchedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE) {
app.kill(app.waitingToKill, true);
success = false;
} else {
@@ -18577,7 +18604,7 @@ public final class ActivityManagerService extends ActivityManagerNative
computeOomAdjLocked(app, cachedAdj, TOP_APP, doingAll, now);
- return applyOomAdjLocked(app, TOP_APP, doingAll, now);
+ return applyOomAdjLocked(app, doingAll, now);
}
final void updateProcessForegroundLocked(ProcessRecord proc, boolean isForeground,
@@ -18795,7 +18822,7 @@ public final class ActivityManagerService extends ActivityManagerNative
}
}
- applyOomAdjLocked(app, TOP_APP, true, now);
+ applyOomAdjLocked(app, true, now);
// Count the number of process types.
switch (app.curProcState) {
diff --git a/services/core/java/com/android/server/location/LocationBasedCountryDetector.java b/services/core/java/com/android/server/location/LocationBasedCountryDetector.java
index 03db621..6527899 100644
--- a/services/core/java/com/android/server/location/LocationBasedCountryDetector.java
+++ b/services/core/java/com/android/server/location/LocationBasedCountryDetector.java
@@ -23,6 +23,7 @@ import android.location.Geocoder;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
+import android.os.Binder;
import android.os.Bundle;
import android.util.Slog;
@@ -95,33 +96,48 @@ public class LocationBasedCountryDetector extends CountryDetectorBase {
* Register a listener with a provider name
*/
protected void registerListener(String provider, LocationListener listener) {
- mLocationManager.requestLocationUpdates(provider, 0, 0, listener);
+ final long bid = Binder.clearCallingIdentity();
+ try {
+ mLocationManager.requestLocationUpdates(provider, 0, 0, listener);
+ } finally {
+ Binder.restoreCallingIdentity(bid);
+ }
}
/**
* Unregister an already registered listener
*/
protected void unregisterListener(LocationListener listener) {
- mLocationManager.removeUpdates(listener);
+ final long bid = Binder.clearCallingIdentity();
+ try {
+ mLocationManager.removeUpdates(listener);
+ } finally {
+ Binder.restoreCallingIdentity(bid);
+ }
}
/**
* @return the last known location from all providers
*/
protected Location getLastKnownLocation() {
- List<String> providers = mLocationManager.getAllProviders();
- Location bestLocation = null;
- for (String provider : providers) {
- Location lastKnownLocation = mLocationManager.getLastKnownLocation(provider);
- if (lastKnownLocation != null) {
- if (bestLocation == null ||
- bestLocation.getElapsedRealtimeNanos() <
- lastKnownLocation.getElapsedRealtimeNanos()) {
- bestLocation = lastKnownLocation;
+ final long bid = Binder.clearCallingIdentity();
+ try {
+ List<String> providers = mLocationManager.getAllProviders();
+ Location bestLocation = null;
+ for (String provider : providers) {
+ Location lastKnownLocation = mLocationManager.getLastKnownLocation(provider);
+ if (lastKnownLocation != null) {
+ if (bestLocation == null ||
+ bestLocation.getElapsedRealtimeNanos() <
+ lastKnownLocation.getElapsedRealtimeNanos()) {
+ bestLocation = lastKnownLocation;
+ }
}
}
+ return bestLocation;
+ } finally {
+ Binder.restoreCallingIdentity(bid);
}
- return bestLocation;
}
/**
diff --git a/services/core/java/com/android/server/notification/ConditionProviders.java b/services/core/java/com/android/server/notification/ConditionProviders.java
index 33c666a..40956c1 100644
--- a/services/core/java/com/android/server/notification/ConditionProviders.java
+++ b/services/core/java/com/android/server/notification/ConditionProviders.java
@@ -262,6 +262,14 @@ public class ConditionProviders extends ManagedServices {
return null;
}
+ public Condition findCondition(ComponentName component, Uri conditionId) {
+ if (component == null || conditionId == null) return null;
+ synchronized (mMutex) {
+ final ConditionRecord r = getRecordLocked(conditionId, component, false /*create*/);
+ return r != null ? r.condition : null;
+ }
+ }
+
public void ensureRecordExists(ComponentName component, Uri conditionId,
IConditionProvider provider) {
// constructed by convention, make sure the record exists...
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index c8ab10a..2d15d13 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -36,6 +36,7 @@ import android.app.NotificationManager;
import android.app.NotificationManager.Policy;
import android.app.PendingIntent;
import android.app.StatusBarManager;
+import android.app.backup.BackupManager;
import android.app.usage.UsageEvents;
import android.app.usage.UsageStatsManagerInternal;
import android.content.BroadcastReceiver;
@@ -113,12 +114,16 @@ import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
import java.util.ArrayDeque;
@@ -126,7 +131,6 @@ import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map.Entry;
-import java.util.NoSuchElementException;
import java.util.Objects;
/** {@hide} */
@@ -244,15 +248,18 @@ public class NotificationManagerService extends SystemService {
private Archive mArchive;
- // Notification control database. For now just contains disabled packages.
+ // Persistent storage for notification policy
private AtomicFile mPolicyFile;
+
+ // Temporary holder for <blocked-packages> config coming from old policy files.
private HashSet<String> mBlockedPackages = new HashSet<String>();
private static final int DB_VERSION = 1;
- private static final String TAG_BODY = "notification-policy";
+ private static final String TAG_NOTIFICATION_POLICY = "notification-policy";
private static final String ATTR_VERSION = "version";
+ // Obsolete: converted if present, but not resaved to disk.
private static final String TAG_BLOCKED_PKGS = "blocked-packages";
private static final String TAG_PACKAGE = "package";
private static final String ATTR_NAME = "name";
@@ -310,53 +317,9 @@ public class NotificationManagerService extends SystemService {
mBuffer.addLast(nr.cloneLight());
}
- public void clear() {
- mBuffer.clear();
- }
-
public Iterator<StatusBarNotification> descendingIterator() {
return mBuffer.descendingIterator();
}
- public Iterator<StatusBarNotification> ascendingIterator() {
- return mBuffer.iterator();
- }
- public Iterator<StatusBarNotification> filter(
- final Iterator<StatusBarNotification> iter, final String pkg, final int userId) {
- return new Iterator<StatusBarNotification>() {
- StatusBarNotification mNext = findNext();
-
- private StatusBarNotification findNext() {
- while (iter.hasNext()) {
- StatusBarNotification nr = iter.next();
- if ((pkg == null || nr.getPackageName() == pkg)
- && (userId == UserHandle.USER_ALL || nr.getUserId() == userId)) {
- return nr;
- }
- }
- return null;
- }
-
- @Override
- public boolean hasNext() {
- return mNext == null;
- }
-
- @Override
- public StatusBarNotification next() {
- StatusBarNotification next = mNext;
- if (next == null) {
- throw new NoSuchElementException();
- }
- mNext = findNext();
- return next;
- }
-
- @Override
- public void remove() {
- iter.remove();
- }
- };
- }
public StatusBarNotification[] getArray(int count) {
if (count == 0) count = mBufferSize;
@@ -370,54 +333,48 @@ public class NotificationManagerService extends SystemService {
return a;
}
- public StatusBarNotification[] getArray(int count, String pkg, int userId) {
- if (count == 0) count = mBufferSize;
- final StatusBarNotification[] a
- = new StatusBarNotification[Math.min(count, mBuffer.size())];
- Iterator<StatusBarNotification> iter = filter(descendingIterator(), pkg, userId);
- int i=0;
- while (iter.hasNext() && i < count) {
- a[i++] = iter.next();
+ }
+
+ private void readPolicyXml(InputStream stream, boolean forRestore)
+ throws XmlPullParserException, NumberFormatException, IOException {
+ final XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(stream, StandardCharsets.UTF_8.name());
+
+ int type;
+ String tag;
+ int version = DB_VERSION;
+ while ((type = parser.next()) != END_DOCUMENT) {
+ tag = parser.getName();
+ if (type == START_TAG) {
+ if (TAG_NOTIFICATION_POLICY.equals(tag)) {
+ version = Integer.parseInt(
+ parser.getAttributeValue(null, ATTR_VERSION));
+ } else if (TAG_BLOCKED_PKGS.equals(tag)) {
+ while ((type = parser.next()) != END_DOCUMENT) {
+ tag = parser.getName();
+ if (TAG_PACKAGE.equals(tag)) {
+ mBlockedPackages.add(
+ parser.getAttributeValue(null, ATTR_NAME));
+ } else if (TAG_BLOCKED_PKGS.equals(tag) && type == END_TAG) {
+ break;
+ }
+ }
+ }
}
- return a;
+ mZenModeHelper.readXml(parser, forRestore);
+ mRankingHelper.readXml(parser, forRestore);
}
-
}
private void loadPolicyFile() {
+ if (DBG) Slog.d(TAG, "loadPolicyFile");
synchronized(mPolicyFile) {
mBlockedPackages.clear();
FileInputStream infile = null;
try {
infile = mPolicyFile.openRead();
- final XmlPullParser parser = Xml.newPullParser();
- parser.setInput(infile, StandardCharsets.UTF_8.name());
-
- int type;
- String tag;
- int version = DB_VERSION;
- while ((type = parser.next()) != END_DOCUMENT) {
- tag = parser.getName();
- if (type == START_TAG) {
- if (TAG_BODY.equals(tag)) {
- version = Integer.parseInt(
- parser.getAttributeValue(null, ATTR_VERSION));
- } else if (TAG_BLOCKED_PKGS.equals(tag)) {
- while ((type = parser.next()) != END_DOCUMENT) {
- tag = parser.getName();
- if (TAG_PACKAGE.equals(tag)) {
- mBlockedPackages.add(
- parser.getAttributeValue(null, ATTR_NAME));
- } else if (TAG_BLOCKED_PKGS.equals(tag) && type == END_TAG) {
- break;
- }
- }
- }
- }
- mZenModeHelper.readXml(parser);
- mRankingHelper.readXml(parser);
- }
+ readPolicyXml(infile, false /*forRestore*/);
} catch (FileNotFoundException e) {
// No data yet
} catch (IOException e) {
@@ -438,7 +395,7 @@ public class NotificationManagerService extends SystemService {
}
private void handleSavePolicyFile() {
- Slog.d(TAG, "handleSavePolicyFile");
+ if (DBG) Slog.d(TAG, "handleSavePolicyFile");
synchronized (mPolicyFile) {
final FileOutputStream stream;
try {
@@ -449,21 +406,26 @@ public class NotificationManagerService extends SystemService {
}
try {
- final XmlSerializer out = new FastXmlSerializer();
- out.setOutput(stream, StandardCharsets.UTF_8.name());
- out.startDocument(null, true);
- out.startTag(null, TAG_BODY);
- out.attribute(null, ATTR_VERSION, Integer.toString(DB_VERSION));
- mZenModeHelper.writeXml(out);
- mRankingHelper.writeXml(out);
- out.endTag(null, TAG_BODY);
- out.endDocument();
+ writePolicyXml(stream, false /*forBackup*/);
mPolicyFile.finishWrite(stream);
} catch (IOException e) {
Slog.w(TAG, "Failed to save policy file, restoring backup", e);
mPolicyFile.failWrite(stream);
}
}
+ BackupManager.dataChanged(getContext().getPackageName());
+ }
+
+ private void writePolicyXml(OutputStream stream, boolean forBackup) throws IOException {
+ final XmlSerializer out = new FastXmlSerializer();
+ out.setOutput(stream, StandardCharsets.UTF_8.name());
+ out.startDocument(null, true);
+ out.startTag(null, TAG_NOTIFICATION_POLICY);
+ out.attribute(null, ATTR_VERSION, Integer.toString(DB_VERSION));
+ mZenModeHelper.writeXml(out, forBackup);
+ mRankingHelper.writeXml(out, forBackup);
+ out.endTag(null, TAG_NOTIFICATION_POLICY);
+ out.endDocument();
}
/** Use this when you actually want to post a notification or toast.
@@ -775,6 +737,7 @@ public class NotificationManagerService extends SystemService {
}
mListeners.onPackagesChanged(queryReplace, pkgList);
mConditionProviders.onPackagesChanged(queryReplace, pkgList);
+ mRankingHelper.onPackagesChanged(queryReplace, pkgList);
}
}
};
@@ -814,8 +777,12 @@ public class NotificationManagerService extends SystemService {
// Refresh managed services
mConditionProviders.onUserSwitched(user);
mListeners.onUserSwitched(user);
+ mZenModeHelper.onUserSwitched(user);
} else if (action.equals(Intent.ACTION_USER_ADDED)) {
mUserProfiles.updateCache(context);
+ } else if (action.equals(Intent.ACTION_USER_REMOVED)) {
+ final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
+ mZenModeHelper.onUserRemoved(user);
}
}
};
@@ -976,6 +943,7 @@ public class NotificationManagerService extends SystemService {
filter.addAction(Intent.ACTION_USER_STOPPED);
filter.addAction(Intent.ACTION_USER_SWITCHED);
filter.addAction(Intent.ACTION_USER_ADDED);
+ filter.addAction(Intent.ACTION_USER_REMOVED);
getContext().registerReceiver(mIntentReceiver, filter);
IntentFilter pkgFilter = new IntentFilter();
@@ -1426,8 +1394,6 @@ public class NotificationManagerService extends SystemService {
@Override
public void setNotificationsShownFromListener(INotificationListener token, String[] keys) {
- final int callingUid = Binder.getCallingUid();
- final int callingPid = Binder.getCallingPid();
long identity = Binder.clearCallingIdentity();
try {
synchronized (mNotificationList) {
@@ -1721,13 +1687,40 @@ public class NotificationManagerService extends SystemService {
// Backup/restore interface
@Override
public byte[] getBackupPayload(int user) {
- // TODO: build a payload of whatever is appropriate
+ if (DBG) Slog.d(TAG, "getBackupPayload u=" + user);
+ if (user != UserHandle.USER_OWNER) {
+ Slog.w(TAG, "getBackupPayload: cannot backup policy for user " + user);
+ return null;
+ }
+ final ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ try {
+ writePolicyXml(baos, true /*forBackup*/);
+ return baos.toByteArray();
+ } catch (IOException e) {
+ Slog.w(TAG, "getBackupPayload: error writing payload for user " + user, e);
+ }
return null;
}
@Override
public void applyRestore(byte[] payload, int user) {
- // TODO: apply the restored payload as new current state
+ if (DBG) Slog.d(TAG, "applyRestore u=" + user + " payload="
+ + (payload != null ? new String(payload, StandardCharsets.UTF_8) : null));
+ if (payload == null) {
+ Slog.w(TAG, "applyRestore: no payload to restore for user " + user);
+ return;
+ }
+ if (user != UserHandle.USER_OWNER) {
+ Slog.w(TAG, "applyRestore: cannot restore policy for user " + user);
+ return;
+ }
+ final ByteArrayInputStream bais = new ByteArrayInputStream(payload);
+ try {
+ readPolicyXml(bais, true /*forRestore*/);
+ savePolicyFile();
+ } catch (NumberFormatException | XmlPullParserException | IOException e) {
+ Slog.w(TAG, "applyRestore: error reading payload", e);
+ }
}
@Override
diff --git a/services/core/java/com/android/server/notification/RankingHelper.java b/services/core/java/com/android/server/notification/RankingHelper.java
index 88055ba..e503ac8 100644
--- a/services/core/java/com/android/server/notification/RankingHelper.java
+++ b/services/core/java/com/android/server/notification/RankingHelper.java
@@ -17,6 +17,8 @@ package com.android.server.notification;
import android.app.Notification;
import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Handler;
import android.os.Message;
import android.os.UserHandle;
@@ -61,6 +63,7 @@ public class RankingHelper implements RankingConfig {
private final ArrayMap<String, Record> mRecords = new ArrayMap<>(); // pkg|uid => Record
private final ArrayMap<String, NotificationRecord> mProxyByGroupTmp = new ArrayMap<>();
+ private final ArrayMap<String, Record> mRestoredWithoutUids = new ArrayMap<>(); // pkg => Record
private final Context mContext;
private final Handler mRankingHandler;
@@ -119,12 +122,15 @@ public class RankingHelper implements RankingConfig {
}
}
- public void readXml(XmlPullParser parser) throws XmlPullParserException, IOException {
+ public void readXml(XmlPullParser parser, boolean forRestore)
+ throws XmlPullParserException, IOException {
+ final PackageManager pm = mContext.getPackageManager();
int type = parser.getEventType();
if (type != XmlPullParser.START_TAG) return;
String tag = parser.getName();
if (!TAG_RANKING.equals(tag)) return;
mRecords.clear();
+ mRestoredWithoutUids.clear();
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
tag = parser.getName();
if (type == XmlPullParser.END_TAG && TAG_RANKING.equals(tag)) {
@@ -132,21 +138,38 @@ public class RankingHelper implements RankingConfig {
}
if (type == XmlPullParser.START_TAG) {
if (TAG_PACKAGE.equals(tag)) {
- int uid = safeInt(parser, ATT_UID, UserHandle.USER_ALL);
+ int uid = safeInt(parser, ATT_UID, Record.UNKNOWN_UID);
int priority = safeInt(parser, ATT_PRIORITY, DEFAULT_PRIORITY);
boolean peekable = safeBool(parser, ATT_PEEKABLE, DEFAULT_PEEKABLE);
int vis = safeInt(parser, ATT_VISIBILITY, DEFAULT_VISIBILITY);
String name = parser.getAttributeValue(null, ATT_NAME);
if (!TextUtils.isEmpty(name)) {
+ if (forRestore) {
+ try {
+ uid = pm.getPackageUid(name, UserHandle.USER_OWNER);
+ } catch (NameNotFoundException e) {
+ // noop
+ }
+ }
+ Record r = null;
+ if (uid == Record.UNKNOWN_UID) {
+ r = mRestoredWithoutUids.get(name);
+ if (r == null) {
+ r = new Record();
+ mRestoredWithoutUids.put(name, r);
+ }
+ } else {
+ r = getOrCreateRecord(name, uid);
+ }
if (priority != DEFAULT_PRIORITY) {
- getOrCreateRecord(name, uid).priority = priority;
+ r.priority = priority;
}
if (peekable != DEFAULT_PEEKABLE) {
- getOrCreateRecord(name, uid).peekable = peekable;
+ r.peekable = peekable;
}
if (vis != DEFAULT_VISIBILITY) {
- getOrCreateRecord(name, uid).visibility = vis;
+ r.visibility = vis;
}
}
}
@@ -182,13 +205,16 @@ public class RankingHelper implements RankingConfig {
}
}
- public void writeXml(XmlSerializer out) throws IOException {
+ public void writeXml(XmlSerializer out, boolean forBackup) throws IOException {
out.startTag(null, TAG_RANKING);
out.attribute(null, ATT_VERSION, Integer.toString(XML_VERSION));
final int N = mRecords.size();
for (int i = 0; i < N; i++) {
final Record r = mRecords.valueAt(i);
+ if (forBackup && UserHandle.getUserId(r.uid) != UserHandle.USER_OWNER) {
+ continue;
+ }
out.startTag(null, TAG_PACKAGE);
out.attribute(null, ATT_NAME, r.pkg);
if (r.priority != DEFAULT_PRIORITY) {
@@ -200,7 +226,9 @@ public class RankingHelper implements RankingConfig {
if (r.visibility != DEFAULT_VISIBILITY) {
out.attribute(null, ATT_VISIBILITY, Integer.toString(r.visibility));
}
- out.attribute(null, ATT_UID, Integer.toString(r.uid));
+ if (!forBackup) {
+ out.attribute(null, ATT_UID, Integer.toString(r.uid));
+ }
out.endTag(null, TAG_PACKAGE);
}
out.endTag(null, TAG_RANKING);
@@ -364,15 +392,21 @@ public class RankingHelper implements RankingConfig {
pw.print(prefix);
pw.println("per-package config:");
}
- final int N = mRecords.size();
+ dumpRecords(pw, prefix, filter, mRecords);
+ dumpRecords(pw, prefix, filter, mRestoredWithoutUids);
+ }
+
+ private static void dumpRecords(PrintWriter pw, String prefix,
+ NotificationManagerService.DumpFilter filter, ArrayMap<String, Record> records) {
+ final int N = records.size();
for (int i = 0; i < N; i++) {
- final Record r = mRecords.valueAt(i);
+ final Record r = records.valueAt(i);
if (filter == null || filter.matches(r.pkg)) {
pw.print(prefix);
pw.print(" ");
pw.print(r.pkg);
pw.print(" (");
- pw.print(r.uid);
+ pw.print(r.uid == Record.UNKNOWN_UID ? "UNKNOWN_UID" : Integer.toString(r.uid));
pw.print(')');
if (r.priority != DEFAULT_PRIORITY) {
pw.print(" priority=");
@@ -391,11 +425,39 @@ public class RankingHelper implements RankingConfig {
}
}
+ public void onPackagesChanged(boolean queryReplace, String[] pkgList) {
+ if (queryReplace || pkgList == null || pkgList.length == 0
+ || mRestoredWithoutUids.isEmpty()) {
+ return; // nothing to do
+ }
+ final PackageManager pm = mContext.getPackageManager();
+ boolean updated = false;
+ for (String pkg : pkgList) {
+ final Record r = mRestoredWithoutUids.get(pkg);
+ if (r != null) {
+ try {
+ r.uid = pm.getPackageUid(r.pkg, UserHandle.USER_OWNER);
+ mRestoredWithoutUids.remove(pkg);
+ mRecords.put(recordKey(r.pkg, r.uid), r);
+ updated = true;
+ } catch (NameNotFoundException e) {
+ // noop
+ }
+ }
+ }
+ if (updated) {
+ updateConfig();
+ }
+ }
+
private static class Record {
+ static int UNKNOWN_UID = UserHandle.USER_NULL;
+
String pkg;
- int uid;
+ int uid = UNKNOWN_UID;
int priority = DEFAULT_PRIORITY;
boolean peekable = DEFAULT_PEEKABLE;
int visibility = DEFAULT_VISIBILITY;
}
+
}
diff --git a/services/core/java/com/android/server/notification/ZenLog.java b/services/core/java/com/android/server/notification/ZenLog.java
index 44fbd2d..c45071b 100644
--- a/services/core/java/com/android/server/notification/ZenLog.java
+++ b/services/core/java/com/android/server/notification/ZenLog.java
@@ -115,8 +115,11 @@ public class ZenLog {
append(TYPE_UNSUBSCRIBE, uri + "," + subscribeResult(provider, e));
}
- public static void traceConfig(String reason, ZenModeConfig newConfig) {
- append(TYPE_CONFIG, reason + "," + (newConfig != null ? newConfig.toString() : null));
+ public static void traceConfig(String reason, ZenModeConfig oldConfig,
+ ZenModeConfig newConfig) {
+ append(TYPE_CONFIG, reason
+ + "," + (newConfig != null ? newConfig.toString() : null)
+ + "," + ZenModeConfig.diff(oldConfig, newConfig));
}
public static void traceDisableEffects(NotificationRecord record, String reason) {
diff --git a/services/core/java/com/android/server/notification/ZenModeConditions.java b/services/core/java/com/android/server/notification/ZenModeConditions.java
index d6b7f2f..b89a654 100644
--- a/services/core/java/com/android/server/notification/ZenModeConditions.java
+++ b/services/core/java/com/android/server/notification/ZenModeConditions.java
@@ -63,7 +63,7 @@ public class ZenModeConditions implements ConditionProviders.Callback {
mConditionProviders.requestConditions(callback, relevance);
}
- public void evaluateConfig(ZenModeConfig config, boolean processSubscriptione) {
+ public void evaluateConfig(ZenModeConfig config, boolean processSubscriptions) {
if (config == null) return;
if (config.manualRule != null && config.manualRule.condition != null
&& !config.manualRule.isTrueOrUnknown()) {
@@ -71,16 +71,16 @@ public class ZenModeConditions implements ConditionProviders.Callback {
config.manualRule = null;
}
final ArraySet<Uri> current = new ArraySet<>();
- evaluateRule(config.manualRule, current, processSubscriptione);
+ evaluateRule(config.manualRule, current, processSubscriptions);
for (ZenRule automaticRule : config.automaticRules.values()) {
- evaluateRule(automaticRule, current, processSubscriptione);
+ evaluateRule(automaticRule, current, processSubscriptions);
updateSnoozing(automaticRule);
}
final int N = mSubscriptions.size();
for (int i = N - 1; i >= 0; i--) {
final Uri id = mSubscriptions.keyAt(i);
final ComponentName component = mSubscriptions.valueAt(i);
- if (processSubscriptione) {
+ if (processSubscriptions) {
if (!current.contains(id)) {
mConditionProviders.unsubscribeIfNecessary(component, id);
mSubscriptions.removeAt(i);
@@ -157,6 +157,11 @@ public class ZenModeConditions implements ConditionProviders.Callback {
if (DEBUG) Log.d(TAG, "zmc failed to subscribe");
}
}
+ if (rule.condition == null) {
+ rule.condition = mConditionProviders.findCondition(rule.component, rule.conditionId);
+ if (rule.condition != null && DEBUG) Log.d(TAG, "Found existing condition for: "
+ + rule.conditionId);
+ }
}
private boolean isAutomaticActive(ComponentName component) {
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index 1860673..755b2ea 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -46,6 +46,7 @@ import android.service.notification.ZenModeConfig.ScheduleInfo;
import android.service.notification.ZenModeConfig.ZenRule;
import android.util.ArraySet;
import android.util.Log;
+import android.util.SparseArray;
import com.android.internal.R;
import com.android.server.LocalServices;
@@ -77,8 +78,10 @@ public class ZenModeHelper {
private final ZenModeFiltering mFiltering;
private final RingerModeDelegate mRingerModeDelegate = new RingerModeDelegate();
private final ZenModeConditions mConditions;
+ private final SparseArray<ZenModeConfig> mConfigs = new SparseArray<>();
private int mZenMode;
+ private int mUser = UserHandle.USER_OWNER;
private ZenModeConfig mConfig;
private AudioManagerInternal mAudioManager;
private int mPreviousRingerMode = -1;
@@ -92,6 +95,7 @@ public class ZenModeHelper {
appendDefaultScheduleRules(mDefaultConfig);
appendDefaultEventRules(mDefaultConfig);
mConfig = mDefaultConfig;
+ mConfigs.put(UserHandle.USER_OWNER, mConfig);
mSettingsObserver = new SettingsObserver(mHandler);
mSettingsObserver.observe();
mFiltering = new ZenModeFiltering(mContext);
@@ -142,6 +146,25 @@ public class ZenModeHelper {
}
}
+ public void onUserSwitched(int user) {
+ if (mUser == user || user < UserHandle.USER_OWNER) return;
+ mUser = user;
+ if (DEBUG) Log.d(TAG, "onUserSwitched u=" + user);
+ ZenModeConfig config = mConfigs.get(user);
+ if (config == null) {
+ if (DEBUG) Log.d(TAG, "onUserSwitched: generating default config for user " + user);
+ config = mDefaultConfig.copy();
+ config.user = user;
+ }
+ setConfig(config, "onUserSwitched");
+ }
+
+ public void onUserRemoved(int user) {
+ if (user < UserHandle.USER_OWNER) return;
+ if (DEBUG) Log.d(TAG, "onUserRemoved u=" + user);
+ mConfigs.remove(user);
+ }
+
public void requestZenModeConditions(IConditionListener callback, int relevance) {
mConditions.requestConditions(callback, relevance);
}
@@ -200,8 +223,13 @@ public class ZenModeHelper {
public void dump(PrintWriter pw, String prefix) {
pw.print(prefix); pw.print("mZenMode=");
pw.println(Global.zenModeToString(mZenMode));
- dump(pw, prefix, "mConfig", mConfig);
dump(pw, prefix, "mDefaultConfig", mDefaultConfig);
+ final int N = mConfigs.size();
+ for (int i = 0; i < N; i++) {
+ dump(pw, prefix, "mConfigs[u=" + mConfigs.keyAt(i) + "]", mConfigs.valueAt(i));
+ }
+ pw.print(prefix); pw.print("mUser="); pw.println(mUser);
+ dump(pw, prefix, "mConfig", mConfig);
pw.print(prefix); pw.print("mPreviousRingerMode="); pw.println(mPreviousRingerMode);
pw.print(prefix); pw.print("mEffectsSuppressed="); pw.println(mEffectsSuppressed);
mFiltering.dump(pw, prefix);
@@ -228,16 +256,29 @@ public class ZenModeHelper {
}
}
- public void readXml(XmlPullParser parser) throws XmlPullParserException, IOException {
+ public void readXml(XmlPullParser parser, boolean forRestore)
+ throws XmlPullParserException, IOException {
final ZenModeConfig config = ZenModeConfig.readXml(parser, mConfigMigration);
if (config != null) {
+ if (forRestore) {
+ if (config.user != UserHandle.USER_OWNER) {
+ return;
+ }
+ config.manualRule = null; // don't restore the manual rule
+ }
if (DEBUG) Log.d(TAG, "readXml");
setConfig(config, "readXml");
}
}
- public void writeXml(XmlSerializer out) throws IOException {
- mConfig.writeXml(out);
+ public void writeXml(XmlSerializer out, boolean forBackup) throws IOException {
+ final int N = mConfigs.size();
+ for (int i = 0; i < N; i++) {
+ if (forBackup && mConfigs.keyAt(i) != UserHandle.USER_OWNER) {
+ continue;
+ }
+ mConfigs.valueAt(i).writeXml(out);
+ }
}
public Policy getNotificationPolicy() {
@@ -268,10 +309,17 @@ public class ZenModeHelper {
Log.w(TAG, "Invalid config in setConfig; " + config);
return false;
}
+ if (config.user != mUser) {
+ // simply store away for background users
+ mConfigs.put(config.user, config);
+ if (DEBUG) Log.d(TAG, "setConfig: store config for user " + config.user);
+ return true;
+ }
mConditions.evaluateConfig(config, false /*processSubscriptions*/); // may modify config
+ mConfigs.put(config.user, config);
if (config.equals(mConfig)) return true;
if (DEBUG) Log.d(TAG, "setConfig reason=" + reason, new Throwable());
- ZenLog.traceConfig(reason, config);
+ ZenLog.traceConfig(reason, mConfig, config);
final boolean policyChanged = !Objects.equals(getNotificationPolicy(mConfig),
getNotificationPolicy(config));
mConfig = config;
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 5aea746..1b5391e 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -2518,8 +2518,7 @@ public final class PowerManagerService extends SystemService
/**
* Low-level function to reboot the device. On success, this
* function doesn't return. If more than 20 seconds passes from
- * the time a reboot is requested (120 seconds for reboot to
- * recovery), this method returns.
+ * the time a reboot is requested, this method returns.
*
* @param reason code to pass to the kernel (e.g. "recovery"), or null.
*/
@@ -2527,27 +2526,21 @@ public final class PowerManagerService extends SystemService
if (reason == null) {
reason = "";
}
- long duration;
if (reason.equals(PowerManager.REBOOT_RECOVERY)) {
// If we are rebooting to go into recovery, instead of
// setting sys.powerctl directly we'll start the
// pre-recovery service which will do some preparation for
// recovery and then reboot for us.
- //
- // This preparation can take more than 20 seconds if
- // there's a very large update package, so lengthen the
- // timeout. We have seen 750MB packages take 3-4 minutes
SystemProperties.set("ctl.start", "pre-recovery");
- duration = 300 * 1000L;
} else {
SystemProperties.set("sys.powerctl", "reboot," + reason);
- duration = 20 * 1000L;
}
try {
- Thread.sleep(duration);
+ Thread.sleep(20 * 1000L);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
+ Slog.wtf(TAG, "Unexpected return from lowLevelReboot!");
}
@Override // Watchdog.Monitor implementation
diff --git a/services/core/java/com/android/server/power/ShutdownThread.java b/services/core/java/com/android/server/power/ShutdownThread.java
index 84eab42..85dd9d4 100644
--- a/services/core/java/com/android/server/power/ShutdownThread.java
+++ b/services/core/java/com/android/server/power/ShutdownThread.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-
+
package com.android.server.power;
import android.app.ActivityManagerNative;
@@ -44,6 +44,8 @@ import android.os.Vibrator;
import android.os.SystemVibrator;
import android.os.storage.IMountService;
import android.os.storage.IMountShutdownObserver;
+import android.system.ErrnoException;
+import android.system.Os;
import com.android.internal.telephony.ITelephony;
import com.android.server.pm.PackageManagerService;
@@ -51,6 +53,11 @@ import com.android.server.pm.PackageManagerService;
import android.util.Log;
import android.view.WindowManager;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+
public final class ShutdownThread extends Thread {
// constants
private static final String TAG = "ShutdownThread";
@@ -59,14 +66,18 @@ public final class ShutdownThread extends Thread {
private static final int MAX_BROADCAST_TIME = 10*1000;
private static final int MAX_SHUTDOWN_WAIT_TIME = 20*1000;
private static final int MAX_RADIO_WAIT_TIME = 12*1000;
+ private static final int MAX_UNCRYPT_WAIT_TIME = 15*60*1000;
// length of vibration before shutting down
private static final int SHUTDOWN_VIBRATE_MS = 500;
-
+
// state tracking
private static Object sIsStartedGuard = new Object();
private static boolean sIsStarted = false;
-
+
+ // uncrypt status file
+ private static final String UNCRYPT_STATUS_FILE = "/cache/recovery/uncrypt_status";
+
private static boolean mReboot;
private static boolean mRebootSafeMode;
private static String mRebootReason;
@@ -94,10 +105,11 @@ public final class ShutdownThread extends Thread {
private Handler mHandler;
private static AlertDialog sConfirmDialog;
-
+ private ProgressDialog mProgressDialog;
+
private ShutdownThread() {
}
-
+
/**
* Request a clean shutdown, waiting for subsystems to clean up their
* state etc. Must be called from a Looper thread in which its UI
@@ -226,7 +238,11 @@ public final class ShutdownThread extends Thread {
// throw up an indeterminate system dialog to indicate radio is
// shutting down.
ProgressDialog pd = new ProgressDialog(context);
- pd.setTitle(context.getText(com.android.internal.R.string.power_off));
+ if (mRebootReason.equals(PowerManager.REBOOT_RECOVERY)) {
+ pd.setTitle(context.getText(com.android.internal.R.string.reboot_to_recovery_title));
+ } else {
+ pd.setTitle(context.getText(com.android.internal.R.string.power_off));
+ }
pd.setMessage(context.getText(com.android.internal.R.string.shutdown_progress));
pd.setIndeterminate(true);
pd.setCancelable(false);
@@ -234,6 +250,7 @@ public final class ShutdownThread extends Thread {
pd.show();
+ sInstance.mProgressDialog = pd;
sInstance.mContext = context;
sInstance.mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
@@ -307,14 +324,14 @@ public final class ShutdownThread extends Thread {
}
Log.i(TAG, "Sending shutdown broadcast...");
-
+
// First send the high-level shut down broadcast.
mActionDone = false;
Intent intent = new Intent(Intent.ACTION_SHUTDOWN);
intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
mContext.sendOrderedBroadcastAsUser(intent,
UserHandle.ALL, null, br, mHandler, 0, null, null);
-
+
final long endTime = SystemClock.elapsedRealtime() + MAX_BROADCAST_TIME;
synchronized (mActionDoneSync) {
while (!mActionDone) {
@@ -329,9 +346,9 @@ public final class ShutdownThread extends Thread {
}
}
}
-
+
Log.i(TAG, "Shutting down activity manager...");
-
+
final IActivityManager am =
ActivityManagerNative.asInterface(ServiceManager.checkService("activity"));
if (am != null) {
@@ -390,9 +407,55 @@ public final class ShutdownThread extends Thread {
}
}
+ // If it's to reboot into recovery, invoke uncrypt via init service.
+ if (mRebootReason.equals(PowerManager.REBOOT_RECOVERY)) {
+ uncrypt();
+ }
+
rebootOrShutdown(mContext, mReboot, mRebootReason);
}
+ private void prepareUncryptProgress() {
+ // Reset the dialog message to show the decrypt process.
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ if (mProgressDialog != null) {
+ mProgressDialog.dismiss();
+ }
+ // It doesn't work to change the style of the existing
+ // one. Have to create a new one.
+ ProgressDialog pd = new ProgressDialog(mContext);
+
+ pd.setTitle(mContext.getText(
+ com.android.internal.R.string.reboot_to_recovery_title));
+ pd.setMessage(mContext.getText(
+ com.android.internal.R.string.reboot_to_recovery_progress));
+ pd.setIndeterminate(false);
+ pd.setMax(100);
+ pd.setCancelable(false);
+ pd.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
+ pd.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
+ pd.setProgressNumberFormat(null);
+ pd.setProgress(0);
+
+ mProgressDialog = pd;
+ mProgressDialog.show();
+ }
+ });
+ }
+
+ private void setUncryptProgress(final int progress) {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ if (mProgressDialog != null) {
+ mProgressDialog.setProgress(progress);
+ }
+ }
+ });
+ }
+
private void shutdownRadios(int timeout) {
// If a radio is wedged, disabling it may hang so we do this work in another thread,
// just in case.
@@ -537,4 +600,78 @@ public final class ShutdownThread extends Thread {
Log.i(TAG, "Performing low-level shutdown...");
PowerManagerService.lowLevelShutdown();
}
+
+ private void uncrypt() {
+ Log.i(TAG, "Calling uncrypt and monitoring the progress...");
+
+ // Update the ProcessDialog message and style.
+ sInstance.prepareUncryptProgress();
+
+ final boolean[] done = new boolean[1];
+ done[0] = false;
+ Thread t = new Thread() {
+ @Override
+ public void run() {
+ // Create the status pipe file to communicate with /system/bin/uncrypt.
+ new File(UNCRYPT_STATUS_FILE).delete();
+ try {
+ Os.mkfifo(UNCRYPT_STATUS_FILE, 0600);
+ } catch (ErrnoException e) {
+ Log.w(TAG, "ErrnoException when creating named pipe \"" + UNCRYPT_STATUS_FILE +
+ "\": " + e.getMessage());
+ }
+
+ SystemProperties.set("ctl.start", "uncrypt");
+
+ // Read the status from the pipe.
+ try (BufferedReader reader = new BufferedReader(
+ new FileReader(UNCRYPT_STATUS_FILE))) {
+
+ int last_status = Integer.MIN_VALUE;
+ while (true) {
+ String str = reader.readLine();
+ try {
+ int status = Integer.parseInt(str);
+
+ // Avoid flooding the log with the same message.
+ if (status == last_status && last_status != Integer.MIN_VALUE) {
+ continue;
+ }
+ last_status = status;
+
+ if (status >= 0 && status < 100) {
+ // Update status
+ Log.d(TAG, "uncrypt read status: " + status);
+ sInstance.setUncryptProgress(status);
+ } else if (status == 100) {
+ Log.d(TAG, "uncrypt successfully finished.");
+ sInstance.setUncryptProgress(status);
+ break;
+ } else {
+ // Error in /system/bin/uncrypt. Or it's rebooting to recovery
+ // to perform other operations (e.g. factory reset).
+ Log.d(TAG, "uncrypt failed with status: " + status);
+ break;
+ }
+ } catch (NumberFormatException unused) {
+ Log.d(TAG, "uncrypt invalid status received: " + str);
+ break;
+ }
+ }
+ } catch (IOException unused) {
+ Log.w(TAG, "IOException when reading \"" + UNCRYPT_STATUS_FILE + "\".");
+ }
+ done[0] = true;
+ }
+ };
+ t.start();
+
+ try {
+ t.join(MAX_UNCRYPT_WAIT_TIME);
+ } catch (InterruptedException unused) {
+ }
+ if (!done[0]) {
+ Log.w(TAG, "Timed out waiting for uncrypt.");
+ }
+ }
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 5d8979f..6042c27 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -466,6 +466,8 @@ public class WindowManagerService extends IWindowManager.Stub
boolean mShowingBootMessages = false;
boolean mBootAnimationStopped = false;
+ /** Dump of the windows and app tokens at the time of the last ANR. Cleared after
+ * LAST_ANR_LIFETIME_DURATION_MSECS */
String mLastANRState;
/** All DisplayContents in the world, kept here */
@@ -1025,7 +1027,7 @@ public class WindowManagerService extends IWindowManager.Stub
private void placeWindowAfter(WindowState pos, WindowState window) {
final WindowList windows = pos.getWindowList();
final int i = windows.indexOf(pos);
- if (true || DEBUG_FOCUS || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(
+ if (DEBUG_FOCUS || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(
TAG, "Adding window " + window + " at "
+ (i+1) + " of " + windows.size() + " (after " + pos + ")");
windows.add(i+1, window);
@@ -1035,7 +1037,7 @@ public class WindowManagerService extends IWindowManager.Stub
private void placeWindowBefore(WindowState pos, WindowState window) {
final WindowList windows = pos.getWindowList();
int i = windows.indexOf(pos);
- if (true || DEBUG_FOCUS || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(
+ if (DEBUG_FOCUS || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(
TAG, "Adding window " + window + " at "
+ i + " of " + windows.size() + " (before " + pos + ")");
if (i < 0) {
@@ -1133,7 +1135,7 @@ public class WindowManagerService extends IWindowManager.Stub
//apptoken note that the window could be a floating window
//that was created later or a window at the top of the list of
//windows associated with this token.
- if (true || DEBUG_FOCUS_LIGHT || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG,
+ if (DEBUG_FOCUS_LIGHT || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG,
"not Base app: Adding window " + win + " at " + (newIdx + 1) + " of " +
N);
windows.add(newIdx + 1, win);
@@ -1255,7 +1257,7 @@ public class WindowManagerService extends IWindowManager.Stub
break;
}
}
- if (true || DEBUG_FOCUS_LIGHT || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG,
+ if (DEBUG_FOCUS_LIGHT || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG,
"Based on layer: Adding window " + win + " at " + (i + 1) + " of " + N);
windows.add(i + 1, win);
mWindowsChanged = true;
@@ -3720,7 +3722,7 @@ public class WindowManagerService extends IWindowManager.Stub
atoken.layoutConfigChanges = (configChanges &
(ActivityInfo.CONFIG_SCREEN_SIZE | ActivityInfo.CONFIG_ORIENTATION)) != 0;
atoken.mLaunchTaskBehind = launchTaskBehind;
- if (true || DEBUG_TOKEN_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG, "addAppToken: " + atoken
+ if (DEBUG_TOKEN_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG, "addAppToken: " + atoken
+ " to stack=" + stackId + " task=" + taskId + " at " + addPos);
Task task = mTaskIdToTask.get(taskId);
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
index 03abfba..1117373 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
@@ -20,6 +20,7 @@ import android.app.ActivityManager;
import android.app.ActivityManagerNative;
import android.app.AppOpsManager;
import android.app.AssistContent;
+import android.app.AssistStructure;
import android.app.IActivityManager;
import android.content.ClipData;
import android.content.ComponentName;
@@ -291,33 +292,37 @@ final class VoiceInteractionSessionConnection implements ServiceConnection {
return;
}
if (mHaveAssistData) {
+ Bundle assistData;
+ AssistStructure structure;
+ AssistContent content;
if (mAssistData != null) {
+ assistData = mAssistData.getBundle("data");
+ structure = mAssistData.getParcelable("structure");
+ content = mAssistData.getParcelable("content");
int uid = mAssistData.getInt(Intent.EXTRA_ASSIST_UID, -1);
- if (uid >= 0) {
- Bundle assistContext = mAssistData.getBundle(Intent.EXTRA_ASSIST_CONTEXT);
- if (assistContext != null) {
- AssistContent content = AssistContent.getAssistContent(assistContext);
- if (content != null) {
- Intent intent = content.getIntent();
- if (intent != null) {
- ClipData data = intent.getClipData();
- if (data != null && Intent.isAccessUriMode(intent.getFlags())) {
- grantClipDataPermissions(data, intent.getFlags(), uid,
- mCallingUid, mSessionComponentName.getPackageName());
- }
- }
- ClipData data = content.getClipData();
- if (data != null) {
- grantClipDataPermissions(data,
- Intent.FLAG_GRANT_READ_URI_PERMISSION,
- uid, mCallingUid, mSessionComponentName.getPackageName());
- }
+ if (uid >= 0 && content != null) {
+ Intent intent = content.getIntent();
+ if (intent != null) {
+ ClipData data = intent.getClipData();
+ if (data != null && Intent.isAccessUriMode(intent.getFlags())) {
+ grantClipDataPermissions(data, intent.getFlags(), uid,
+ mCallingUid, mSessionComponentName.getPackageName());
}
}
+ ClipData data = content.getClipData();
+ if (data != null) {
+ grantClipDataPermissions(data,
+ Intent.FLAG_GRANT_READ_URI_PERMISSION,
+ uid, mCallingUid, mSessionComponentName.getPackageName());
+ }
}
+ } else {
+ assistData = null;
+ structure = null;
+ content = null;
}
try {
- mSession.handleAssist(mAssistData);
+ mSession.handleAssist(assistData, structure, content);
} catch (RemoteException e) {
}
mAssistData = null;
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index d74c61c..a2e0706 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -253,6 +253,7 @@ public final class Call {
private final int mVideoState;
private final StatusHints mStatusHints;
private final Bundle mExtras;
+ private final Bundle mIntentExtras;
/**
* Whether the supplied capabilities supports the specified capability.
@@ -480,12 +481,19 @@ public final class Call {
}
/**
- * @return A bundle extras to pass with the call
+ * @return The extras associated with this call.
*/
public Bundle getExtras() {
return mExtras;
}
+ /**
+ * @return The extras used with the original intent to place this call.
+ */
+ public Bundle getIntentExtras() {
+ return mIntentExtras;
+ }
+
@Override
public boolean equals(Object o) {
if (o instanceof Details) {
@@ -504,7 +512,8 @@ public final class Call {
Objects.equals(mGatewayInfo, d.mGatewayInfo) &&
Objects.equals(mVideoState, d.mVideoState) &&
Objects.equals(mStatusHints, d.mStatusHints) &&
- Objects.equals(mExtras, d.mExtras);
+ Objects.equals(mExtras, d.mExtras) &&
+ Objects.equals(mIntentExtras, d.mIntentExtras);
}
return false;
}
@@ -524,7 +533,8 @@ public final class Call {
Objects.hashCode(mGatewayInfo) +
Objects.hashCode(mVideoState) +
Objects.hashCode(mStatusHints) +
- Objects.hashCode(mExtras);
+ Objects.hashCode(mExtras) +
+ Objects.hashCode(mIntentExtras);
}
/** {@hide} */
@@ -541,7 +551,8 @@ public final class Call {
GatewayInfo gatewayInfo,
int videoState,
StatusHints statusHints,
- Bundle extras) {
+ Bundle extras,
+ Bundle intentExtras) {
mHandle = handle;
mHandlePresentation = handlePresentation;
mCallerDisplayName = callerDisplayName;
@@ -555,6 +566,7 @@ public final class Call {
mVideoState = videoState;
mStatusHints = statusHints;
mExtras = extras;
+ mIntentExtras = intentExtras;
}
}
@@ -986,7 +998,8 @@ public final class Call {
parcelableCall.getGatewayInfo(),
parcelableCall.getVideoState(),
parcelableCall.getStatusHints(),
- parcelableCall.getExtras());
+ parcelableCall.getExtras(),
+ parcelableCall.getIntentExtras());
boolean detailsChanged = !Objects.equals(mDetails, details);
if (detailsChanged) {
mDetails = details;
diff --git a/telecomm/java/android/telecom/Conference.java b/telecomm/java/android/telecom/Conference.java
index dfbb67a..9db0b92 100644
--- a/telecomm/java/android/telecom/Conference.java
+++ b/telecomm/java/android/telecom/Conference.java
@@ -16,7 +16,9 @@
package android.telecom;
+import android.annotation.Nullable;
import android.annotation.SystemApi;
+import android.os.Bundle;
import android.telecom.Connection.VideoProvider;
import java.util.ArrayList;
@@ -52,6 +54,7 @@ public abstract class Conference extends Conferenceable {
public void onVideoStateChanged(Conference c, int videoState) { }
public void onVideoProviderChanged(Conference c, Connection.VideoProvider videoProvider) {}
public void onStatusHintsChanged(Conference conference, StatusHints statusHints) {}
+ public void onExtrasChanged(Conference conference, Bundle extras) {}
}
private final Set<Listener> mListeners = new CopyOnWriteArraySet<>();
@@ -70,6 +73,7 @@ public abstract class Conference extends Conferenceable {
private String mDisconnectMessage;
private long mConnectTimeMillis = CONNECT_TIME_NOT_SPECIFIED;
private StatusHints mStatusHints;
+ private Bundle mExtras;
private final Connection.Listener mConnectionDeathListener = new Connection.Listener() {
@Override
@@ -600,4 +604,25 @@ public abstract class Conference extends Conferenceable {
public final StatusHints getStatusHints() {
return mStatusHints;
}
+
+ /**
+ * Set some extras that can be associated with this {@code Conference}. No assumptions should
+ * be made as to how an In-Call UI or service will handle these extras.
+ * Keys should be fully qualified (e.g., com.example.MY_EXTRA) to avoid conflicts.
+ *
+ * @param extras The extras associated with this {@code Connection}.
+ */
+ public final void setExtras(@Nullable Bundle extras) {
+ mExtras = extras;
+ for (Listener l : mListeners) {
+ l.onExtrasChanged(this, extras);
+ }
+ }
+
+ /**
+ * @return The extras associated with this conference.
+ */
+ public final Bundle getExtras() {
+ return mExtras;
+ }
}
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index fba4e6a..f9e48b6 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -20,8 +20,10 @@ import com.android.internal.os.SomeArgs;
import com.android.internal.telecom.IVideoCallback;
import com.android.internal.telecom.IVideoProvider;
+import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.net.Uri;
+import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
@@ -334,6 +336,7 @@ public abstract class Connection extends Conferenceable {
List<ConferenceParticipant> participants) {}
public void onConferenceStarted() {}
public void onConferenceMergeFailed(Connection c) {}
+ public void onExtrasChanged(Connection c, Bundle extras) {}
}
public static abstract class VideoProvider {
@@ -832,6 +835,7 @@ public abstract class Connection extends Conferenceable {
private DisconnectCause mDisconnectCause;
private Conference mConference;
private ConnectionService mConnectionService;
+ private Bundle mExtras;
/**
* Create a new Connection.
@@ -942,6 +946,13 @@ public abstract class Connection extends Conferenceable {
}
/**
+ * @return The extras associated with this connection.
+ */
+ public final Bundle getExtras() {
+ return mExtras;
+ }
+
+ /**
* Assign a listener to be notified of state changes.
*
* @param l A listener.
@@ -1371,6 +1382,21 @@ public abstract class Connection extends Conferenceable {
}
/**
+ * Set some extras that can be associated with this {@code Connection}. No assumptions should
+ * be made as to how an In-Call UI or service will handle these extras.
+ * Keys should be fully qualified (e.g., com.example.MY_EXTRA) to avoid conflicts.
+ *
+ * @param extras The extras associated with this {@code Connection}.
+ */
+ public final void setExtras(@Nullable Bundle extras) {
+ checkImmutable();
+ mExtras = extras;
+ for (Listener l : mListeners) {
+ l.onExtrasChanged(this, extras);
+ }
+ }
+
+ /**
* Notifies this Connection that the {@link #getAudioState()} property has a new value.
*
* @param state The new connection audio state.
diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java
index 199100b..1e8ae88 100644
--- a/telecomm/java/android/telecom/ConnectionService.java
+++ b/telecomm/java/android/telecom/ConnectionService.java
@@ -21,6 +21,7 @@ import android.app.Service;
import android.content.ComponentName;
import android.content.Intent;
import android.net.Uri;
+import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
@@ -432,6 +433,12 @@ public abstract class ConnectionService extends Service {
String id = mIdByConference.get(conference);
mAdapter.setStatusHints(id, statusHints);
}
+
+ @Override
+ public void onExtrasChanged(Conference conference, Bundle extras) {
+ String id = mIdByConference.get(conference);
+ mAdapter.setExtras(id, extras);
+ }
};
private final Connection.Listener mConnectionListener = new Connection.Listener() {
@@ -569,6 +576,14 @@ public abstract class ConnectionService extends Service {
mAdapter.onConferenceMergeFailed(id);
}
}
+
+ @Override
+ public void onExtrasChanged(Connection connection, Bundle extras) {
+ String id = mIdByConnection.get(connection);
+ if (id != null) {
+ mAdapter.setExtras(id, extras);
+ }
+ }
};
/** {@inheritDoc} */
@@ -638,7 +653,8 @@ public abstract class ConnectionService extends Service {
connection.getAudioModeIsVoip(),
connection.getStatusHints(),
connection.getDisconnectCause(),
- createIdList(connection.getConferenceables())));
+ createIdList(connection.getConferenceables()),
+ connection.getExtras()));
}
private void abort(String callId) {
@@ -919,7 +935,8 @@ public abstract class ConnectionService extends Service {
null : conference.getVideoProvider().getInterface(),
conference.getVideoState(),
conference.getConnectTimeMillis(),
- conference.getStatusHints());
+ conference.getStatusHints(),
+ conference.getExtras());
mAdapter.addConferenceCall(id, parcelableConference);
mAdapter.setVideoProvider(id, conference.getVideoProvider());
@@ -964,7 +981,8 @@ public abstract class ConnectionService extends Service {
connection.getAudioModeIsVoip(),
connection.getStatusHints(),
connection.getDisconnectCause(),
- emptyList);
+ emptyList,
+ connection.getExtras());
mAdapter.addExistingConnection(id, parcelableConnection);
}
}
diff --git a/telecomm/java/android/telecom/ConnectionServiceAdapter.java b/telecomm/java/android/telecom/ConnectionServiceAdapter.java
index a87dbe7..1cb042c 100644
--- a/telecomm/java/android/telecom/ConnectionServiceAdapter.java
+++ b/telecomm/java/android/telecom/ConnectionServiceAdapter.java
@@ -17,6 +17,7 @@
package android.telecom;
import android.net.Uri;
+import android.os.Bundle;
import android.os.IBinder.DeathRecipient;
import android.os.RemoteException;
@@ -384,4 +385,20 @@ final class ConnectionServiceAdapter implements DeathRecipient {
}
}
}
+
+ /**
+ * Sets extras associated with a connection.
+ *
+ * @param callId The unique ID of the call.
+ * @param extras The extras to associate with this call.
+ */
+ void setExtras(String callId, Bundle extras) {
+ Log.v(this, "setExtras: %s", extras);
+ for (IConnectionServiceAdapter adapter : mAdapters) {
+ try {
+ adapter.setExtras(callId, extras);
+ } catch (RemoteException ignored) {
+ }
+ }
+ }
}
diff --git a/telecomm/java/android/telecom/ConnectionServiceAdapterServant.java b/telecomm/java/android/telecom/ConnectionServiceAdapterServant.java
index db815ba..293dc11 100644
--- a/telecomm/java/android/telecom/ConnectionServiceAdapterServant.java
+++ b/telecomm/java/android/telecom/ConnectionServiceAdapterServant.java
@@ -17,6 +17,7 @@
package android.telecom;
import android.net.Uri;
+import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.RemoteException;
@@ -60,6 +61,7 @@ final class ConnectionServiceAdapterServant {
private static final int MSG_ADD_EXISTING_CONNECTION = 21;
private static final int MSG_ON_POST_DIAL_CHAR = 22;
private static final int MSG_SET_CONFERENCE_MERGE_FAILED = 23;
+ private static final int MSG_SET_EXTRAS = 24;
private final IConnectionServiceAdapter mDelegate;
@@ -230,6 +232,14 @@ final class ConnectionServiceAdapterServant {
}
break;
}
+ case MSG_SET_EXTRAS: {
+ SomeArgs args = (SomeArgs) msg.obj;
+ try {
+ mDelegate.setExtras((String) args.arg1, (Bundle) args.arg2);
+ } finally {
+ args.recycle();
+ }
+ }
}
}
};
@@ -401,6 +411,14 @@ final class ConnectionServiceAdapterServant {
args.arg2 = connection;
mHandler.obtainMessage(MSG_ADD_EXISTING_CONNECTION, args).sendToTarget();
}
+
+ @Override
+ public final void setExtras(String connectionId, Bundle extras) {
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = connectionId;
+ args.arg2 = extras;
+ mHandler.obtainMessage(MSG_SET_EXTRAS, args).sendToTarget();
+ }
};
public ConnectionServiceAdapterServant(IConnectionServiceAdapter delegate) {
diff --git a/telecomm/java/android/telecom/ParcelableCall.java b/telecomm/java/android/telecom/ParcelableCall.java
index bb65ce9..8cf4aeb 100644
--- a/telecomm/java/android/telecom/ParcelableCall.java
+++ b/telecomm/java/android/telecom/ParcelableCall.java
@@ -54,6 +54,7 @@ public final class ParcelableCall implements Parcelable {
private final StatusHints mStatusHints;
private final int mVideoState;
private final List<String> mConferenceableCallIds;
+ private final Bundle mIntentExtras;
private final Bundle mExtras;
public ParcelableCall(
@@ -77,6 +78,7 @@ public final class ParcelableCall implements Parcelable {
StatusHints statusHints,
int videoState,
List<String> conferenceableCallIds,
+ Bundle intentExtras,
Bundle extras) {
mId = id;
mState = state;
@@ -98,6 +100,7 @@ public final class ParcelableCall implements Parcelable {
mStatusHints = statusHints;
mVideoState = videoState;
mConferenceableCallIds = Collections.unmodifiableList(conferenceableCallIds);
+ mIntentExtras = intentExtras;
mExtras = extras;
}
@@ -227,7 +230,7 @@ public final class ParcelableCall implements Parcelable {
}
/**
- * Any extras to pass with the call
+ * Any extras associated with this call.
*
* @return a bundle of extras
*/
@@ -236,6 +239,15 @@ public final class ParcelableCall implements Parcelable {
}
/**
+ * Extras passed in as part of the original call intent.
+ *
+ * @return The intent extras.
+ */
+ public Bundle getIntentExtras() {
+ return mIntentExtras;
+ }
+
+ /**
* Indicates to the receiver of the {@link ParcelableCall} whether a change has occurred in the
* {@link android.telecom.InCallService.VideoCall} associated with this call. Since
* {@link #getVideoCall()} creates a new {@link VideoCallImpl}, it is useful to know whether
@@ -277,7 +289,8 @@ public final class ParcelableCall implements Parcelable {
int videoState = source.readInt();
List<String> conferenceableCallIds = new ArrayList<>();
source.readList(conferenceableCallIds, classLoader);
- Bundle extras = source.readParcelable(classLoader);
+ Bundle intentExtras = source.readBundle(classLoader);
+ Bundle extras = source.readBundle(classLoader);
return new ParcelableCall(
id,
state,
@@ -299,6 +312,7 @@ public final class ParcelableCall implements Parcelable {
statusHints,
videoState,
conferenceableCallIds,
+ intentExtras,
extras);
}
@@ -338,7 +352,8 @@ public final class ParcelableCall implements Parcelable {
destination.writeParcelable(mStatusHints, 0);
destination.writeInt(mVideoState);
destination.writeList(mConferenceableCallIds);
- destination.writeParcelable(mExtras, 0);
+ destination.writeBundle(mIntentExtras);
+ destination.writeBundle(mExtras);
}
@Override
diff --git a/telecomm/java/android/telecom/ParcelableConference.java b/telecomm/java/android/telecom/ParcelableConference.java
index 3d0c558..870f5ee 100644
--- a/telecomm/java/android/telecom/ParcelableConference.java
+++ b/telecomm/java/android/telecom/ParcelableConference.java
@@ -16,6 +16,7 @@
package android.telecom;
+import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
@@ -38,6 +39,7 @@ public final class ParcelableConference implements Parcelable {
private final IVideoProvider mVideoProvider;
private final int mVideoState;
private StatusHints mStatusHints;
+ private Bundle mExtras;
public ParcelableConference(
PhoneAccountHandle phoneAccount,
@@ -47,7 +49,8 @@ public final class ParcelableConference implements Parcelable {
IVideoProvider videoProvider,
int videoState,
long connectTimeMillis,
- StatusHints statusHints) {
+ StatusHints statusHints,
+ Bundle extras) {
mPhoneAccount = phoneAccount;
mState = state;
mConnectionCapabilities = connectionCapabilities;
@@ -57,6 +60,7 @@ public final class ParcelableConference implements Parcelable {
mVideoState = videoState;
mConnectTimeMillis = connectTimeMillis;
mStatusHints = statusHints;
+ mExtras = extras;
}
@Override
@@ -110,6 +114,10 @@ public final class ParcelableConference implements Parcelable {
return mStatusHints;
}
+ public Bundle getExtras() {
+ return mExtras;
+ }
+
public static final Parcelable.Creator<ParcelableConference> CREATOR =
new Parcelable.Creator<ParcelableConference> () {
@Override
@@ -125,9 +133,10 @@ public final class ParcelableConference implements Parcelable {
IVideoProvider.Stub.asInterface(source.readStrongBinder());
int videoState = source.readInt();
StatusHints statusHints = source.readParcelable(classLoader);
+ Bundle extras = source.readBundle(classLoader);
return new ParcelableConference(phoneAccount, state, capabilities, connectionIds,
- videoCallProvider, videoState, connectTimeMillis, statusHints);
+ videoCallProvider, videoState, connectTimeMillis, statusHints, extras);
}
@Override
@@ -154,5 +163,6 @@ public final class ParcelableConference implements Parcelable {
mVideoProvider != null ? mVideoProvider.asBinder() : null);
destination.writeInt(mVideoState);
destination.writeParcelable(mStatusHints, 0);
+ destination.writeBundle(mExtras);
}
}
diff --git a/telecomm/java/android/telecom/ParcelableConnection.java b/telecomm/java/android/telecom/ParcelableConnection.java
index 552e250..683ab6a 100644
--- a/telecomm/java/android/telecom/ParcelableConnection.java
+++ b/telecomm/java/android/telecom/ParcelableConnection.java
@@ -17,6 +17,7 @@
package android.telecom;
import android.net.Uri;
+import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
@@ -46,6 +47,7 @@ public final class ParcelableConnection implements Parcelable {
private final StatusHints mStatusHints;
private final DisconnectCause mDisconnectCause;
private final List<String> mConferenceableConnectionIds;
+ private final Bundle mExtras;
/** @hide */
public ParcelableConnection(
@@ -62,7 +64,8 @@ public final class ParcelableConnection implements Parcelable {
boolean isVoipAudioMode,
StatusHints statusHints,
DisconnectCause disconnectCause,
- List<String> conferenceableConnectionIds) {
+ List<String> conferenceableConnectionIds,
+ Bundle extras) {
mPhoneAccount = phoneAccount;
mState = state;
mConnectionCapabilities = capabilities;
@@ -76,7 +79,8 @@ public final class ParcelableConnection implements Parcelable {
mIsVoipAudioMode = isVoipAudioMode;
mStatusHints = statusHints;
mDisconnectCause = disconnectCause;
- this.mConferenceableConnectionIds = conferenceableConnectionIds;
+ mConferenceableConnectionIds = conferenceableConnectionIds;
+ mExtras = extras;
}
public PhoneAccountHandle getPhoneAccount() {
@@ -136,15 +140,21 @@ public final class ParcelableConnection implements Parcelable {
return mConferenceableConnectionIds;
}
+ public final Bundle getExtras() {
+ return mExtras;
+ }
+
@Override
public String toString() {
return new StringBuilder()
.append("ParcelableConnection [act:")
.append(mPhoneAccount)
- .append(", state:")
+ .append("], state:")
.append(mState)
.append(", capabilities:")
.append(Connection.capabilitiesToString(mConnectionCapabilities))
+ .append(", extras:")
+ .append(mExtras)
.toString();
}
@@ -170,6 +180,7 @@ public final class ParcelableConnection implements Parcelable {
DisconnectCause disconnectCause = source.readParcelable(classLoader);
List<String> conferenceableConnectionIds = new ArrayList<>();
source.readStringList(conferenceableConnectionIds);
+ Bundle extras = source.readBundle(classLoader);
return new ParcelableConnection(
phoneAccount,
@@ -185,7 +196,8 @@ public final class ParcelableConnection implements Parcelable {
audioModeIsVoip,
statusHints,
disconnectCause,
- conferenceableConnectionIds);
+ conferenceableConnectionIds,
+ extras);
}
@Override
@@ -218,5 +230,6 @@ public final class ParcelableConnection implements Parcelable {
destination.writeParcelable(mStatusHints, 0);
destination.writeParcelable(mDisconnectCause, 0);
destination.writeStringList(mConferenceableConnectionIds);
+ destination.writeBundle(mExtras);
}
}
diff --git a/telecomm/java/android/telecom/RemoteConference.java b/telecomm/java/android/telecom/RemoteConference.java
index 095a88f..c2261c3 100644
--- a/telecomm/java/android/telecom/RemoteConference.java
+++ b/telecomm/java/android/telecom/RemoteConference.java
@@ -18,7 +18,9 @@ package android.telecom;
import com.android.internal.telecom.IConnectionService;
+import android.annotation.Nullable;
import android.annotation.SystemApi;
+import android.os.Bundle;
import android.os.Handler;
import android.os.RemoteException;
@@ -49,6 +51,7 @@ public final class RemoteConference {
RemoteConference conference,
List<RemoteConnection> conferenceableConnections) {}
public void onDestroyed(RemoteConference conference) {}
+ public void onExtrasChanged(RemoteConference conference, @Nullable Bundle extras) {}
}
private final String mId;
@@ -65,6 +68,7 @@ public final class RemoteConference {
private int mState = Connection.STATE_NEW;
private DisconnectCause mDisconnectCause;
private int mConnectionCapabilities;
+ private Bundle mExtras;
/** @hide */
RemoteConference(String id, IConnectionService connectionService) {
@@ -209,6 +213,21 @@ public final class RemoteConference {
}
}
+ /** @hide */
+ void setExtras(final Bundle extras) {
+ mExtras = extras;
+ for (CallbackRecord<Callback> record : mCallbackRecords) {
+ final RemoteConference conference = this;
+ final Callback callback = record.getCallback();
+ record.getHandler().post(new Runnable() {
+ @Override
+ public void run() {
+ callback.onExtrasChanged(conference, extras);
+ }
+ });
+ }
+ }
+
/**
* Returns the list of {@link RemoteConnection}s contained in this conference.
*
@@ -238,6 +257,15 @@ public final class RemoteConference {
}
/**
+ * Obtain the extras associated with this {@code RemoteConnection}.
+ *
+ * @return The extras for this connection.
+ */
+ public final Bundle getExtras() {
+ return mExtras;
+ }
+
+ /**
* Disconnects the conference call as well as the child {@link RemoteConnection}s.
*/
public void disconnect() {
diff --git a/telecomm/java/android/telecom/RemoteConnection.java b/telecomm/java/android/telecom/RemoteConnection.java
index 1d6e15c..9003ed1 100644
--- a/telecomm/java/android/telecom/RemoteConnection.java
+++ b/telecomm/java/android/telecom/RemoteConnection.java
@@ -20,8 +20,10 @@ import com.android.internal.telecom.IConnectionService;
import com.android.internal.telecom.IVideoCallback;
import com.android.internal.telecom.IVideoProvider;
+import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.net.Uri;
+import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
@@ -197,9 +199,17 @@ public final class RemoteConnection {
public void onConferenceChanged(
RemoteConnection connection,
RemoteConference conference) {}
+
+ /**
+ * Handles changes to the {@code RemoteConference} extras.
+ *
+ * @param connection The {@code RemoteConnection} invoking this method.
+ * @param extras The extras containing other information associated with the connection.
+ */
+ public void onExtrasChanged(RemoteConnection connection, @Nullable Bundle extras) {}
}
- /** {@hide} */
+ /** @hide */
public static class VideoProvider {
public abstract static class Listener {
@@ -415,6 +425,7 @@ public final class RemoteConnection {
private String mCallerDisplayName;
private int mCallerDisplayNamePresentation;
private RemoteConference mConference;
+ private Bundle mExtras;
/**
* @hide
@@ -614,6 +625,15 @@ public final class RemoteConnection {
}
/**
+ * Obtain the extras associated with this {@code RemoteConnection}.
+ *
+ * @return The extras for this connection.
+ */
+ public final Bundle getExtras() {
+ return mExtras;
+ }
+
+ /**
* Determines whether this {@code RemoteConnection} is requesting ringback.
*
* @return Whether the {@code RemoteConnection} is requesting that the framework play a
@@ -1097,6 +1117,21 @@ public final class RemoteConnection {
}
}
+ /** @hide */
+ void setExtras(final Bundle extras) {
+ mExtras = extras;
+ for (CallbackRecord record : mCallbackRecords) {
+ final RemoteConnection connection = this;
+ final Callback callback = record.getCallback();
+ record.getHandler().post(new Runnable() {
+ @Override
+ public void run() {
+ callback.onExtrasChanged(connection, extras);
+ }
+ });
+ }
+ }
+
/**
* Create a RemoteConnection represents a failure, and which will be in
* {@link Connection#STATE_DISCONNECTED}. Attempting to use it for anything will almost
diff --git a/telecomm/java/android/telecom/RemoteConnectionService.java b/telecomm/java/android/telecom/RemoteConnectionService.java
index 0208744..dc0de0c 100644
--- a/telecomm/java/android/telecom/RemoteConnectionService.java
+++ b/telecomm/java/android/telecom/RemoteConnectionService.java
@@ -17,6 +17,7 @@
package android.telecom;
import android.net.Uri;
+import android.os.Bundle;
import android.os.IBinder;
import android.os.IBinder.DeathRecipient;
import android.os.RemoteException;
@@ -318,6 +319,17 @@ final class RemoteConnectionService {
mOurConnectionServiceImpl.addRemoteExistingConnection(remoteConnction);
}
+
+ @Override
+ public void setExtras(String callId, Bundle extras) {
+ if (mConnectionById.containsKey(callId)) {
+ findConnectionForAction(callId, "setExtras")
+ .setExtras(extras);
+ } else {
+ findConferenceForAction(callId, "setExtras")
+ .setExtras(extras);
+ }
+ }
};
private final ConnectionServiceAdapterServant mServant =
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index 145c993..4cf741d 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -69,9 +69,7 @@ public class TelecomManager {
/**
* The {@link android.content.Intent} action used to configure a
* {@link android.telecom.ConnectionService}.
- * @hide
*/
- @SystemApi
public static final String ACTION_CONNECTION_SERVICE_CONFIGURE =
"android.telecom.action.CONNECTION_SERVICE_CONFIGURE";
diff --git a/telecomm/java/com/android/internal/telecom/IConnectionServiceAdapter.aidl b/telecomm/java/com/android/internal/telecom/IConnectionServiceAdapter.aidl
index 67e2edb..7647444 100644
--- a/telecomm/java/com/android/internal/telecom/IConnectionServiceAdapter.aidl
+++ b/telecomm/java/com/android/internal/telecom/IConnectionServiceAdapter.aidl
@@ -18,6 +18,7 @@ package com.android.internal.telecom;
import android.app.PendingIntent;
import android.net.Uri;
+import android.os.Bundle;
import android.telecom.ConnectionRequest;
import android.telecom.DisconnectCause;
import android.telecom.ParcelableConnection;
@@ -83,4 +84,6 @@ oneway interface IConnectionServiceAdapter {
void setConferenceableConnections(String callId, in List<String> conferenceableCallIds);
void addExistingConnection(String callId, in ParcelableConnection connection);
+
+ void setExtras(String callId, in Bundle extras);
}
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 9232040..76da13f 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -216,7 +216,8 @@ public class CarrierConfigManager {
public static final String INT_VVM_PORT_NUMBER = "int_vvm_port_number";
/**
- * The type of visual voicemail protocol the carrier adheres to (see below).
+ * The type of visual voicemail protocol the carrier adheres to. See {@link TelephonyManager}
+ * for possible values. For example {@link TelephonyManager#VVM_TYPE_OMTP}.
*
* @hide
*/
diff --git a/telephony/java/android/telephony/PhoneNumberUtils.java b/telephony/java/android/telephony/PhoneNumberUtils.java
index aae3ff6..a41875f 100644
--- a/telephony/java/android/telephony/PhoneNumberUtils.java
+++ b/telephony/java/android/telephony/PhoneNumberUtils.java
@@ -2351,12 +2351,12 @@ public class PhoneNumberUtils
*
* @param s A {@code Spannable} to annotate.
* @param start The starting character position of the phone number in {@code s}.
- * @param end The ending character position of the phone number in {@code s}.
+ * @param endExclusive The position after the ending character in the phone number {@code s}.
*/
- public static void addPhoneTtsSpan(Spannable s, int start, int end) {
- s.setSpan(getPhoneTtsSpan(s.subSequence(start, end).toString()),
+ public static void addPhoneTtsSpan(Spannable s, int start, int endExclusive) {
+ s.setSpan(getPhoneTtsSpan(s.subSequence(start, endExclusive).toString()),
start,
- end,
+ endExclusive,
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index fbc70de..f29a6ed 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -1644,7 +1644,6 @@ public class TelephonyManager {
return SIM_STATE_UNKNOWN;
}
int simState = SubscriptionManager.getSimStateForSubscriber(subId[0]);
- Rlog.d(TAG, "getSimState: simState=" + simState + " slotIdx=" + slotIdx);
return simState;
}
@@ -1695,7 +1694,6 @@ public class TelephonyManager {
}
}
}
- Rlog.d(TAG, "getSimOperatorNumeric(): default subId=" + subId);
return getSimOperatorNumericForSubscription(subId);
}
@@ -3237,8 +3235,6 @@ public class TelephonyManager {
propVal = values[phoneId];
}
}
- Rlog.d(TAG, "getTelephonyProperty: return propVal='" + propVal + "' phoneId=" + phoneId
- + " property='" + property + "' defaultVal='" + defaultVal + "' prop=" + prop);
return propVal == null ? defaultVal : propVal;
}
@@ -4580,4 +4576,18 @@ public class TelephonyManager {
} catch (RemoteException e) {
}
}
+
+
+ /** @hide */
+ public String getLocaleFromDefaultSim() {
+ try {
+ final ITelephony telephony = getITelephony();
+ if (telephony != null) {
+ return telephony.getLocaleFromDefaultSim();
+ }
+ } catch (RemoteException ex) {
+ }
+
+ return null;
+ }
}
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 25fe97c..11d0ea6 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -945,4 +945,12 @@ interface ITelephony {
int getSubIdForPhoneAccount(in PhoneAccount phoneAccount);
void factoryReset(int subId);
+
+ /**
+ * An estimate of the users's current locale based on the default SIM.
+ *
+ * The returned string will be a well formed BCP-47 language tag, or {@code null}
+ * if no locale could be derived.
+ */
+ String getLocaleFromDefaultSim();
}
diff --git a/tests/Compatibility/src/com/android/compatibilitytest/AppCompatibility.java b/tests/Compatibility/src/com/android/compatibilitytest/AppCompatibility.java
index eaff6c7..f81b001 100644
--- a/tests/Compatibility/src/com/android/compatibilitytest/AppCompatibility.java
+++ b/tests/Compatibility/src/com/android/compatibilitytest/AppCompatibility.java
@@ -17,6 +17,7 @@
package com.android.compatibilitytest;
import android.app.ActivityManager;
+import android.app.UiAutomation;
import android.app.UiModeManager;
import android.app.ActivityManager.ProcessErrorStateInfo;
import android.app.ActivityManager.RunningTaskInfo;
@@ -82,10 +83,12 @@ public class AppCompatibility extends InstrumentationTestCase {
if (workspaceLaunchTimeoutMsecs != null) {
mWorkspaceLaunchTimeout = Integer.parseInt(workspaceLaunchTimeoutMsecs);
}
+ getInstrumentation().getUiAutomation().setRotation(UiAutomation.ROTATION_FREEZE_0);
}
@Override
protected void tearDown() throws Exception {
+ getInstrumentation().getUiAutomation().setRotation(UiAutomation.ROTATION_UNFREEZE);
super.tearDown();
}
diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml
index 8531944..10cf5c1 100644
--- a/tests/HwAccelerationTest/AndroidManifest.xml
+++ b/tests/HwAccelerationTest/AndroidManifest.xml
@@ -24,11 +24,11 @@
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />
- <uses-sdk android:minSdkVersion="11" />
-
+ <uses-sdk android:minSdkVersion="21" />
+
<application
android:label="HwUi"
- android:hardwareAccelerated="true">
+ android:theme="@android:style/Theme.Material.Light">
<activity
android:name="HwTests"
@@ -42,8 +42,7 @@
<activity
android:name="PathOpsActivity"
- android:label="Path/Ops"
- android:theme="@android:style/Theme.Holo.Light">
+ android:label="Path/Ops">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="com.android.test.hwui.TEST" />
@@ -52,8 +51,7 @@
<activity
android:name="AssetsAtlasActivity"
- android:label="Atlas/Framework"
- android:theme="@android:style/Theme.Holo.Light">
+ android:label="Atlas/Framework">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="com.android.test.hwui.TEST" />
@@ -62,8 +60,7 @@
<activity
android:name="ScaledTextActivity"
- android:label="Text/Scaled"
- android:theme="@android:style/Theme.Holo.Light">
+ android:label="Text/Scaled">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="com.android.test.hwui.TEST" />
@@ -72,8 +69,7 @@
<activity
android:name="Rotate3dTextActivity"
- android:label="Text/3D Rotation"
- android:theme="@android:style/Theme.Holo.Light">
+ android:label="Text/3D Rotation">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="com.android.test.hwui.TEST" />
diff --git a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java
index 3c5c201..70a6336 100644
--- a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java
+++ b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java
@@ -119,11 +119,16 @@ public class MainInteractionSession extends VoiceInteractionSession
}
@Override
- public void onHandleAssist(Bundle assistBundle) {
- if (assistBundle != null) {
- parseAssistData(assistBundle);
- } else {
- Log.i(TAG, "onHandleAssist: NO ASSIST BUNDLE");
+ public void onHandleAssist(Bundle data, AssistStructure structure, AssistContent content) {
+ mAssistStructure = structure;
+ if (mAssistStructure != null) {
+ if (mAssistVisualizer != null) {
+ mAssistVisualizer.setAssistStructure(mAssistStructure);
+ }
+ }
+ if (content != null) {
+ Log.i(TAG, "Assist intent: " + content.getIntent());
+ Log.i(TAG, "Assist clipdata: " + content.getClipData());
}
}
@@ -139,29 +144,6 @@ public class MainInteractionSession extends VoiceInteractionSession
}
}
- void parseAssistData(Bundle assistBundle) {
- if (assistBundle != null) {
- Bundle assistContext = assistBundle.getBundle(Intent.EXTRA_ASSIST_CONTEXT);
- if (assistContext != null) {
- mAssistStructure = AssistStructure.getAssistStructure(assistContext);
- if (mAssistStructure != null) {
- if (mAssistVisualizer != null) {
- mAssistVisualizer.setAssistStructure(mAssistStructure);
- }
- }
- AssistContent content = AssistContent.getAssistContent(assistContext);
- if (content != null) {
- Log.i(TAG, "Assist intent: " + content.getIntent());
- Log.i(TAG, "Assist clipdata: " + content.getClipData());
- }
- return;
- }
- }
- if (mAssistVisualizer != null) {
- mAssistVisualizer.clearAssistData();
- }
- }
-
void updateState() {
if (mState == STATE_IDLE) {
mTopContent.setVisibility(View.VISIBLE);
diff --git a/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java b/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java
index 76019bf..2e515fb 100644
--- a/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java
+++ b/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java
@@ -45,7 +45,24 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Map;
-import static com.android.ide.common.rendering.api.RenderResources.*;
+import static android.util.TypedValue.TYPE_ATTRIBUTE;
+import static android.util.TypedValue.TYPE_DIMENSION;
+import static android.util.TypedValue.TYPE_FLOAT;
+import static android.util.TypedValue.TYPE_INT_BOOLEAN;
+import static android.util.TypedValue.TYPE_INT_COLOR_ARGB4;
+import static android.util.TypedValue.TYPE_INT_COLOR_ARGB8;
+import static android.util.TypedValue.TYPE_INT_COLOR_RGB4;
+import static android.util.TypedValue.TYPE_INT_COLOR_RGB8;
+import static android.util.TypedValue.TYPE_INT_DEC;
+import static android.util.TypedValue.TYPE_INT_HEX;
+import static android.util.TypedValue.TYPE_NULL;
+import static android.util.TypedValue.TYPE_REFERENCE;
+import static android.util.TypedValue.TYPE_STRING;
+import static com.android.SdkConstants.PREFIX_RESOURCE_REF;
+import static com.android.SdkConstants.PREFIX_THEME_REF;
+import static com.android.ide.common.rendering.api.RenderResources.REFERENCE_EMPTY;
+import static com.android.ide.common.rendering.api.RenderResources.REFERENCE_NULL;
+import static com.android.ide.common.rendering.api.RenderResources.REFERENCE_UNDEFINED;
/**
* Custom implementation of TypedArray to handle non compiled resources.
@@ -223,7 +240,7 @@ public final class BridgeTypedArray extends TypedArray {
String s = getString(index);
try {
if (s != null) {
- return XmlUtils.convertValueToInt(s, defValue);
+ return convertValueToInt(s, defValue);
}
} catch (NumberFormatException e) {
Bridge.getLog().warning(LayoutLog.TAG_RESOURCES_FORMAT,
@@ -764,14 +781,57 @@ public final class BridgeTypedArray extends TypedArray {
}
@Override
+ @SuppressWarnings("ResultOfMethodCallIgnored")
public int getType(int index) {
- if (!hasValue(index)) {
- return TypedValue.TYPE_NULL;
+ String value = getString(index);
+ if (value == null) {
+ return TYPE_NULL;
}
- ResourceValue value = mResourceData[index];
- ResourceType resourceType = value.getResourceType();
- return 0;
- // TODO: fixme.
+ if (value.startsWith(PREFIX_RESOURCE_REF)) {
+ return TYPE_REFERENCE;
+ }
+ if (value.startsWith(PREFIX_THEME_REF)) {
+ return TYPE_ATTRIBUTE;
+ }
+ try {
+ // Don't care about the value. Only called to check if an exception is thrown.
+ convertValueToInt(value, 0);
+ if (value.startsWith("0x") || value.startsWith("0X")) {
+ return TYPE_INT_HEX;
+ }
+ // is it a color?
+ if (value.startsWith("#")) {
+ int length = value.length() - 1;
+ if (length == 3) { // rgb
+ return TYPE_INT_COLOR_RGB4;
+ }
+ if (length == 4) { // argb
+ return TYPE_INT_COLOR_ARGB4;
+ }
+ if (length == 6) { // rrggbb
+ return TYPE_INT_COLOR_RGB8;
+ }
+ if (length == 8) { // aarrggbb
+ return TYPE_INT_COLOR_ARGB8;
+ }
+ }
+ if (value.equalsIgnoreCase("true") || value.equalsIgnoreCase("false")) {
+ return TYPE_INT_BOOLEAN;
+ }
+ return TYPE_INT_DEC;
+ } catch (NumberFormatException ignored) {
+ try {
+ Float.parseFloat(value);
+ return TYPE_FLOAT;
+ } catch (NumberFormatException ignore) {
+ }
+ // Might be a dimension.
+ if (ResourceHelper.parseFloatAttribute(null, value, new TypedValue(), false)) {
+ return TYPE_DIMENSION;
+ }
+ }
+ // TODO: handle fractions.
+ return TYPE_STRING;
}
/**
@@ -883,6 +943,52 @@ public final class BridgeTypedArray extends TypedArray {
return null;
}
+ /**
+ * Copied from {@link XmlUtils#convertValueToInt(CharSequence, int)}, but adapted to account
+ * for aapt, and the fact that host Java VM's Integer.parseInt("XXXXXXXX", 16) cannot handle
+ * "XXXXXXXX" > 80000000.
+ */
+ private static int convertValueToInt(@Nullable String charSeq, int defValue) {
+ if (null == charSeq)
+ return defValue;
+
+ int sign = 1;
+ int index = 0;
+ int len = charSeq.length();
+ int base = 10;
+
+ if ('-' == charSeq.charAt(0)) {
+ sign = -1;
+ index++;
+ }
+
+ if ('0' == charSeq.charAt(index)) {
+ // Quick check for a zero by itself
+ if (index == (len - 1))
+ return 0;
+
+ char c = charSeq.charAt(index + 1);
+
+ if ('x' == c || 'X' == c) {
+ index += 2;
+ base = 16;
+ } else {
+ index++;
+ // Leave the base as 10. aapt removes the preceding zero, and thus when framework
+ // sees the value, it only gets the decimal value.
+ }
+ } else if ('#' == charSeq.charAt(index)) {
+ return ResourceHelper.getColor(charSeq) * sign;
+ } else if ("true".equals(charSeq) || "TRUE".equals(charSeq)) {
+ return -1;
+ } else if ("false".equals(charSeq) || "FALSE".equals(charSeq)) {
+ return 0;
+ }
+
+ // Use Long, since we want to handle hex ints > 80000000.
+ return ((int)Long.parseLong(charSeq.substring(index), base)) * sign;
+ }
+
static TypedArray obtain(Resources res, int len) {
return res instanceof BridgeResources ?
new BridgeTypedArray(((BridgeResources) res), null, len, true) : null;
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
index 9d2b884..f03ec58 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
@@ -130,6 +130,7 @@ public final class BridgeContext extends Context {
new IdentityHashMap<Object, Map<String,String>>();
// maps for dynamically generated id representing style objects (StyleResourceValue)
+ @Nullable
private Map<Integer, StyleResourceValue> mDynamicIdToStyleMap;
private Map<StyleResourceValue, Integer> mStyleToDynamicIdMap;
private int mDynamicIdGenerator = 0x02030000; // Base id for R.style in custom namespace
@@ -727,7 +728,7 @@ public final class BridgeContext extends Context {
}
}
} else if (defStyleRes != 0) {
- StyleResourceValue item = mDynamicIdToStyleMap.get(defStyleRes);
+ StyleResourceValue item = getStyleByDynamicId(defStyleRes);
if (item != null) {
defStyleValues = item;
} else {