diff options
303 files changed, 7123 insertions, 6021 deletions
diff --git a/Android.mk b/Android.mk index 2cfc9a220be1..76e9b337a3a4 100644 --- a/Android.mk +++ b/Android.mk @@ -215,6 +215,7 @@ LOCAL_SRC_FILES += \ core/java/android/nfc/INfcCardEmulation.aidl \ core/java/android/nfc/INfcFCardEmulation.aidl \ core/java/android/nfc/INfcUnlockHandler.aidl \ + core/java/android/nfc/ITagRemovedCallback.aidl \ core/java/android/os/IBatteryPropertiesListener.aidl \ core/java/android/os/IBatteryPropertiesRegistrar.aidl \ core/java/android/os/ICancellationSignal.aidl \ @@ -1155,6 +1156,7 @@ LOCAL_DROIDDOC_OPTIONS:= \ $(sample_groups) \ -useUpdatedTemplates \ -hdf android.hasSamples true \ + -yaml _book.yaml \ -samplesdir $(samples_dir) LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=build/tools/droiddoc/templates-sdk-dev diff --git a/api/current.txt b/api/current.txt index 6fdd1bcb9866..233fbd7e060b 100644 --- a/api/current.txt +++ b/api/current.txt @@ -4924,7 +4924,6 @@ package android.app { field public static final int DEFAULT_LIGHTS = 4; // 0x4 field public static final int DEFAULT_SOUND = 1; // 0x1 field public static final int DEFAULT_VIBRATE = 2; // 0x2 - field public static final java.lang.String EXTRA_ALLOW_GENERATED_REPLIES = "android.allowGeneratedReplies"; field public static final java.lang.String EXTRA_BACKGROUND_IMAGE_URI = "android.backgroundImageUri"; field public static final java.lang.String EXTRA_BIG_TEXT = "android.bigText"; field public static final java.lang.String EXTRA_CHRONOMETER_COUNTS_DOWN = "android.chronometerCountsDown"; @@ -5007,6 +5006,7 @@ package android.app { ctor public deprecated Notification.Action(int, java.lang.CharSequence, android.app.PendingIntent); method public android.app.Notification.Action clone(); method public int describeContents(); + method public boolean getAllowGeneratedReplies(); method public android.os.Bundle getExtras(); method public android.graphics.drawable.Icon getIcon(); method public android.app.RemoteInput[] getRemoteInputs(); @@ -5026,6 +5026,7 @@ package android.app { method public android.app.Notification.Action build(); method public android.app.Notification.Action.Builder extend(android.app.Notification.Action.Extender); method public android.os.Bundle getExtras(); + method public android.app.Notification.Action.Builder setAllowGeneratedReplies(boolean); } public static abstract interface Notification.Action.Extender { @@ -5193,11 +5194,9 @@ package android.app { ctor public Notification.MessagingStyle(java.lang.CharSequence); method public android.app.Notification.MessagingStyle addMessage(java.lang.CharSequence, long, java.lang.CharSequence); method public android.app.Notification.MessagingStyle addMessage(android.app.Notification.MessagingStyle.Message); - method public boolean getAllowGeneratedReplies(); method public java.lang.CharSequence getConversationTitle(); method public java.util.List<android.app.Notification.MessagingStyle.Message> getMessages(); method public java.lang.CharSequence getUserDisplayName(); - method public android.app.Notification.MessagingStyle setAllowGeneratedReplies(boolean); method public android.app.Notification.MessagingStyle setConversationTitle(java.lang.CharSequence); field public static final int MAXIMUM_RETAINED_MESSAGES = 25; // 0x19 } @@ -5242,6 +5241,7 @@ package android.app { method public boolean getContentIntentAvailableOffline(); method public int getCustomContentHeight(); method public int getCustomSizePreset(); + method public java.lang.String getDismissalId(); method public android.app.PendingIntent getDisplayIntent(); method public int getGravity(); method public boolean getHintAmbientBigPicture(); @@ -5259,6 +5259,7 @@ package android.app { method public android.app.Notification.WearableExtender setContentIntentAvailableOffline(boolean); method public android.app.Notification.WearableExtender setCustomContentHeight(int); method public android.app.Notification.WearableExtender setCustomSizePreset(int); + method public android.app.Notification.WearableExtender setDismissalId(java.lang.String); method public android.app.Notification.WearableExtender setDisplayIntent(android.app.PendingIntent); method public android.app.Notification.WearableExtender setGravity(int); method public android.app.Notification.WearableExtender setHintAmbientBigPicture(boolean); @@ -20641,6 +20642,7 @@ package android.media { field public static final int DolbyVisionProfileDvavPer = 1; // 0x1 field public static final int DolbyVisionProfileDvheDen = 8; // 0x8 field public static final int DolbyVisionProfileDvheDer = 4; // 0x4 + field public static final int DolbyVisionProfileDvheDtb = 128; // 0x80 field public static final int DolbyVisionProfileDvheDth = 64; // 0x40 field public static final int DolbyVisionProfileDvheDtr = 16; // 0x10 field public static final int DolbyVisionProfileDvheStn = 32; // 0x20 @@ -20729,20 +20731,20 @@ package android.media { field public static final int VP8Level_Version2 = 4; // 0x4 field public static final int VP8Level_Version3 = 8; // 0x8 field public static final int VP8ProfileMain = 1; // 0x1 - field public static final int VP9Level1 = 0; // 0x0 - field public static final int VP9Level11 = 1; // 0x1 - field public static final int VP9Level2 = 2; // 0x2 - field public static final int VP9Level21 = 4; // 0x4 - field public static final int VP9Level3 = 8; // 0x8 - field public static final int VP9Level31 = 16; // 0x10 - field public static final int VP9Level4 = 32; // 0x20 - field public static final int VP9Level41 = 64; // 0x40 - field public static final int VP9Level5 = 128; // 0x80 - field public static final int VP9Level51 = 256; // 0x100 - field public static final int VP9Level52 = 512; // 0x200 - field public static final int VP9Level6 = 1024; // 0x400 - field public static final int VP9Level61 = 2048; // 0x800 - field public static final int VP9Level62 = 4096; // 0x1000 + field public static final int VP9Level1 = 1; // 0x1 + field public static final int VP9Level11 = 2; // 0x2 + field public static final int VP9Level2 = 4; // 0x4 + field public static final int VP9Level21 = 8; // 0x8 + field public static final int VP9Level3 = 16; // 0x10 + field public static final int VP9Level31 = 32; // 0x20 + field public static final int VP9Level4 = 64; // 0x40 + field public static final int VP9Level41 = 128; // 0x80 + field public static final int VP9Level5 = 256; // 0x100 + field public static final int VP9Level51 = 512; // 0x200 + field public static final int VP9Level52 = 1024; // 0x400 + field public static final int VP9Level6 = 2048; // 0x800 + field public static final int VP9Level61 = 4096; // 0x1000 + field public static final int VP9Level62 = 8192; // 0x2000 field public static final int VP9Profile0 = 1; // 0x1 field public static final int VP9Profile1 = 2; // 0x2 field public static final int VP9Profile2 = 4; // 0x4 @@ -25011,6 +25013,7 @@ package android.nfc { method public deprecated void enableForegroundNdefPush(android.app.Activity, android.nfc.NdefMessage); method public void enableReaderMode(android.app.Activity, android.nfc.NfcAdapter.ReaderCallback, int, android.os.Bundle); method public static android.nfc.NfcAdapter getDefaultAdapter(android.content.Context); + method public boolean ignore(android.nfc.Tag, int, android.nfc.NfcAdapter.OnTagRemovedListener, android.os.Handler); method public boolean invokeBeam(android.app.Activity); method public boolean isEnabled(); method public boolean isNdefPushEnabled(); @@ -25053,6 +25056,10 @@ package android.nfc { method public abstract void onNdefPushComplete(android.nfc.NfcEvent); } + public static abstract interface NfcAdapter.OnTagRemovedListener { + method public abstract void onTagRemoved(); + } + public static abstract interface NfcAdapter.ReaderCallback { method public abstract void onTagDiscovered(android.nfc.Tag); } @@ -25069,7 +25076,6 @@ package android.nfc { public final class Tag implements android.os.Parcelable { method public int describeContents(); - method public boolean done(int); method public byte[] getId(); method public java.lang.String[] getTechList(); method public void writeToParcel(android.os.Parcel, int); diff --git a/api/system-current.txt b/api/system-current.txt index 41b73ebf344b..10d71591fbcf 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -5067,7 +5067,6 @@ package android.app { field public static final int DEFAULT_LIGHTS = 4; // 0x4 field public static final int DEFAULT_SOUND = 1; // 0x1 field public static final int DEFAULT_VIBRATE = 2; // 0x2 - field public static final java.lang.String EXTRA_ALLOW_GENERATED_REPLIES = "android.allowGeneratedReplies"; field public static final java.lang.String EXTRA_BACKGROUND_IMAGE_URI = "android.backgroundImageUri"; field public static final java.lang.String EXTRA_BIG_TEXT = "android.bigText"; field public static final java.lang.String EXTRA_CHRONOMETER_COUNTS_DOWN = "android.chronometerCountsDown"; @@ -5152,6 +5151,7 @@ package android.app { ctor public deprecated Notification.Action(int, java.lang.CharSequence, android.app.PendingIntent); method public android.app.Notification.Action clone(); method public int describeContents(); + method public boolean getAllowGeneratedReplies(); method public android.os.Bundle getExtras(); method public android.graphics.drawable.Icon getIcon(); method public android.app.RemoteInput[] getRemoteInputs(); @@ -5171,6 +5171,7 @@ package android.app { method public android.app.Notification.Action build(); method public android.app.Notification.Action.Builder extend(android.app.Notification.Action.Extender); method public android.os.Bundle getExtras(); + method public android.app.Notification.Action.Builder setAllowGeneratedReplies(boolean); } public static abstract interface Notification.Action.Extender { @@ -5338,11 +5339,9 @@ package android.app { ctor public Notification.MessagingStyle(java.lang.CharSequence); method public android.app.Notification.MessagingStyle addMessage(java.lang.CharSequence, long, java.lang.CharSequence); method public android.app.Notification.MessagingStyle addMessage(android.app.Notification.MessagingStyle.Message); - method public boolean getAllowGeneratedReplies(); method public java.lang.CharSequence getConversationTitle(); method public java.util.List<android.app.Notification.MessagingStyle.Message> getMessages(); method public java.lang.CharSequence getUserDisplayName(); - method public android.app.Notification.MessagingStyle setAllowGeneratedReplies(boolean); method public android.app.Notification.MessagingStyle setConversationTitle(java.lang.CharSequence); field public static final int MAXIMUM_RETAINED_MESSAGES = 25; // 0x19 } @@ -5387,6 +5386,7 @@ package android.app { method public boolean getContentIntentAvailableOffline(); method public int getCustomContentHeight(); method public int getCustomSizePreset(); + method public java.lang.String getDismissalId(); method public android.app.PendingIntent getDisplayIntent(); method public int getGravity(); method public boolean getHintAmbientBigPicture(); @@ -5404,6 +5404,7 @@ package android.app { method public android.app.Notification.WearableExtender setContentIntentAvailableOffline(boolean); method public android.app.Notification.WearableExtender setCustomContentHeight(int); method public android.app.Notification.WearableExtender setCustomSizePreset(int); + method public android.app.Notification.WearableExtender setDismissalId(java.lang.String); method public android.app.Notification.WearableExtender setDisplayIntent(android.app.PendingIntent); method public android.app.Notification.WearableExtender setGravity(int); method public android.app.Notification.WearableExtender setHintAmbientBigPicture(boolean); @@ -22161,6 +22162,7 @@ package android.media { field public static final int DolbyVisionProfileDvavPer = 1; // 0x1 field public static final int DolbyVisionProfileDvheDen = 8; // 0x8 field public static final int DolbyVisionProfileDvheDer = 4; // 0x4 + field public static final int DolbyVisionProfileDvheDtb = 128; // 0x80 field public static final int DolbyVisionProfileDvheDth = 64; // 0x40 field public static final int DolbyVisionProfileDvheDtr = 16; // 0x10 field public static final int DolbyVisionProfileDvheStn = 32; // 0x20 @@ -22249,20 +22251,20 @@ package android.media { field public static final int VP8Level_Version2 = 4; // 0x4 field public static final int VP8Level_Version3 = 8; // 0x8 field public static final int VP8ProfileMain = 1; // 0x1 - field public static final int VP9Level1 = 0; // 0x0 - field public static final int VP9Level11 = 1; // 0x1 - field public static final int VP9Level2 = 2; // 0x2 - field public static final int VP9Level21 = 4; // 0x4 - field public static final int VP9Level3 = 8; // 0x8 - field public static final int VP9Level31 = 16; // 0x10 - field public static final int VP9Level4 = 32; // 0x20 - field public static final int VP9Level41 = 64; // 0x40 - field public static final int VP9Level5 = 128; // 0x80 - field public static final int VP9Level51 = 256; // 0x100 - field public static final int VP9Level52 = 512; // 0x200 - field public static final int VP9Level6 = 1024; // 0x400 - field public static final int VP9Level61 = 2048; // 0x800 - field public static final int VP9Level62 = 4096; // 0x1000 + field public static final int VP9Level1 = 1; // 0x1 + field public static final int VP9Level11 = 2; // 0x2 + field public static final int VP9Level2 = 4; // 0x4 + field public static final int VP9Level21 = 8; // 0x8 + field public static final int VP9Level3 = 16; // 0x10 + field public static final int VP9Level31 = 32; // 0x20 + field public static final int VP9Level4 = 64; // 0x40 + field public static final int VP9Level41 = 128; // 0x80 + field public static final int VP9Level5 = 256; // 0x100 + field public static final int VP9Level51 = 512; // 0x200 + field public static final int VP9Level52 = 1024; // 0x400 + field public static final int VP9Level6 = 2048; // 0x800 + field public static final int VP9Level61 = 4096; // 0x1000 + field public static final int VP9Level62 = 8192; // 0x2000 field public static final int VP9Profile0 = 1; // 0x1 field public static final int VP9Profile1 = 2; // 0x2 field public static final int VP9Profile2 = 4; // 0x4 @@ -26170,8 +26172,12 @@ package android.net.metrics { method public static void logEvent(int, long, int, int); method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator<android.net.metrics.ValidationProbeEvent> CREATOR; - field public static final int PROBE_HTTP = 0; // 0x0 - field public static final int PROBE_HTTPS = 1; // 0x1 + field public static final int DNS_FAILURE = 0; // 0x0 + field public static final int DNS_SUCCESS = 1; // 0x1 + field public static final int PROBE_DNS = 0; // 0x0 + field public static final int PROBE_HTTP = 1; // 0x1 + field public static final int PROBE_HTTPS = 2; // 0x2 + field public static final int PROBE_PAC = 3; // 0x3 field public final long durationMs; field public final int netId; field public final int probeType; @@ -27443,6 +27449,7 @@ package android.nfc { method public boolean enableNdefPush(); method public void enableReaderMode(android.app.Activity, android.nfc.NfcAdapter.ReaderCallback, int, android.os.Bundle); method public static android.nfc.NfcAdapter getDefaultAdapter(android.content.Context); + method public boolean ignore(android.nfc.Tag, int, android.nfc.NfcAdapter.OnTagRemovedListener, android.os.Handler); method public boolean invokeBeam(android.app.Activity); method public boolean isEnabled(); method public boolean isNdefPushEnabled(); @@ -27492,6 +27499,10 @@ package android.nfc { method public abstract void onNdefPushComplete(android.nfc.NfcEvent); } + public static abstract interface NfcAdapter.OnTagRemovedListener { + method public abstract void onTagRemoved(); + } + public static abstract interface NfcAdapter.ReaderCallback { method public abstract void onTagDiscovered(android.nfc.Tag); } @@ -27508,7 +27519,6 @@ package android.nfc { public final class Tag implements android.os.Parcelable { method public int describeContents(); - method public boolean done(int); method public byte[] getId(); method public java.lang.String[] getTechList(); method public void writeToParcel(android.os.Parcel, int); diff --git a/api/test-current.txt b/api/test-current.txt index d40d0b8d4e3d..d66b5c73e24a 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -4924,7 +4924,6 @@ package android.app { field public static final int DEFAULT_LIGHTS = 4; // 0x4 field public static final int DEFAULT_SOUND = 1; // 0x1 field public static final int DEFAULT_VIBRATE = 2; // 0x2 - field public static final java.lang.String EXTRA_ALLOW_GENERATED_REPLIES = "android.allowGeneratedReplies"; field public static final java.lang.String EXTRA_BACKGROUND_IMAGE_URI = "android.backgroundImageUri"; field public static final java.lang.String EXTRA_BIG_TEXT = "android.bigText"; field public static final java.lang.String EXTRA_CHRONOMETER_COUNTS_DOWN = "android.chronometerCountsDown"; @@ -5007,6 +5006,7 @@ package android.app { ctor public deprecated Notification.Action(int, java.lang.CharSequence, android.app.PendingIntent); method public android.app.Notification.Action clone(); method public int describeContents(); + method public boolean getAllowGeneratedReplies(); method public android.os.Bundle getExtras(); method public android.graphics.drawable.Icon getIcon(); method public android.app.RemoteInput[] getRemoteInputs(); @@ -5026,6 +5026,7 @@ package android.app { method public android.app.Notification.Action build(); method public android.app.Notification.Action.Builder extend(android.app.Notification.Action.Extender); method public android.os.Bundle getExtras(); + method public android.app.Notification.Action.Builder setAllowGeneratedReplies(boolean); } public static abstract interface Notification.Action.Extender { @@ -5193,11 +5194,9 @@ package android.app { ctor public Notification.MessagingStyle(java.lang.CharSequence); method public android.app.Notification.MessagingStyle addMessage(java.lang.CharSequence, long, java.lang.CharSequence); method public android.app.Notification.MessagingStyle addMessage(android.app.Notification.MessagingStyle.Message); - method public boolean getAllowGeneratedReplies(); method public java.lang.CharSequence getConversationTitle(); method public java.util.List<android.app.Notification.MessagingStyle.Message> getMessages(); method public java.lang.CharSequence getUserDisplayName(); - method public android.app.Notification.MessagingStyle setAllowGeneratedReplies(boolean); method public android.app.Notification.MessagingStyle setConversationTitle(java.lang.CharSequence); field public static final int MAXIMUM_RETAINED_MESSAGES = 25; // 0x19 } @@ -5242,6 +5241,7 @@ package android.app { method public boolean getContentIntentAvailableOffline(); method public int getCustomContentHeight(); method public int getCustomSizePreset(); + method public java.lang.String getDismissalId(); method public android.app.PendingIntent getDisplayIntent(); method public int getGravity(); method public boolean getHintAmbientBigPicture(); @@ -5259,6 +5259,7 @@ package android.app { method public android.app.Notification.WearableExtender setContentIntentAvailableOffline(boolean); method public android.app.Notification.WearableExtender setCustomContentHeight(int); method public android.app.Notification.WearableExtender setCustomSizePreset(int); + method public android.app.Notification.WearableExtender setDismissalId(java.lang.String); method public android.app.Notification.WearableExtender setDisplayIntent(android.app.PendingIntent); method public android.app.Notification.WearableExtender setGravity(int); method public android.app.Notification.WearableExtender setHintAmbientBigPicture(boolean); @@ -20709,6 +20710,7 @@ package android.media { field public static final int DolbyVisionProfileDvavPer = 1; // 0x1 field public static final int DolbyVisionProfileDvheDen = 8; // 0x8 field public static final int DolbyVisionProfileDvheDer = 4; // 0x4 + field public static final int DolbyVisionProfileDvheDtb = 128; // 0x80 field public static final int DolbyVisionProfileDvheDth = 64; // 0x40 field public static final int DolbyVisionProfileDvheDtr = 16; // 0x10 field public static final int DolbyVisionProfileDvheStn = 32; // 0x20 @@ -20797,20 +20799,20 @@ package android.media { field public static final int VP8Level_Version2 = 4; // 0x4 field public static final int VP8Level_Version3 = 8; // 0x8 field public static final int VP8ProfileMain = 1; // 0x1 - field public static final int VP9Level1 = 0; // 0x0 - field public static final int VP9Level11 = 1; // 0x1 - field public static final int VP9Level2 = 2; // 0x2 - field public static final int VP9Level21 = 4; // 0x4 - field public static final int VP9Level3 = 8; // 0x8 - field public static final int VP9Level31 = 16; // 0x10 - field public static final int VP9Level4 = 32; // 0x20 - field public static final int VP9Level41 = 64; // 0x40 - field public static final int VP9Level5 = 128; // 0x80 - field public static final int VP9Level51 = 256; // 0x100 - field public static final int VP9Level52 = 512; // 0x200 - field public static final int VP9Level6 = 1024; // 0x400 - field public static final int VP9Level61 = 2048; // 0x800 - field public static final int VP9Level62 = 4096; // 0x1000 + field public static final int VP9Level1 = 1; // 0x1 + field public static final int VP9Level11 = 2; // 0x2 + field public static final int VP9Level2 = 4; // 0x4 + field public static final int VP9Level21 = 8; // 0x8 + field public static final int VP9Level3 = 16; // 0x10 + field public static final int VP9Level31 = 32; // 0x20 + field public static final int VP9Level4 = 64; // 0x40 + field public static final int VP9Level41 = 128; // 0x80 + field public static final int VP9Level5 = 256; // 0x100 + field public static final int VP9Level51 = 512; // 0x200 + field public static final int VP9Level52 = 1024; // 0x400 + field public static final int VP9Level6 = 2048; // 0x800 + field public static final int VP9Level61 = 4096; // 0x1000 + field public static final int VP9Level62 = 8192; // 0x2000 field public static final int VP9Profile0 = 1; // 0x1 field public static final int VP9Profile1 = 2; // 0x2 field public static final int VP9Profile2 = 4; // 0x4 @@ -25079,6 +25081,7 @@ package android.nfc { method public deprecated void enableForegroundNdefPush(android.app.Activity, android.nfc.NdefMessage); method public void enableReaderMode(android.app.Activity, android.nfc.NfcAdapter.ReaderCallback, int, android.os.Bundle); method public static android.nfc.NfcAdapter getDefaultAdapter(android.content.Context); + method public boolean ignore(android.nfc.Tag, int, android.nfc.NfcAdapter.OnTagRemovedListener, android.os.Handler); method public boolean invokeBeam(android.app.Activity); method public boolean isEnabled(); method public boolean isNdefPushEnabled(); @@ -25121,6 +25124,10 @@ package android.nfc { method public abstract void onNdefPushComplete(android.nfc.NfcEvent); } + public static abstract interface NfcAdapter.OnTagRemovedListener { + method public abstract void onTagRemoved(); + } + public static abstract interface NfcAdapter.ReaderCallback { method public abstract void onTagDiscovered(android.nfc.Tag); } @@ -25137,7 +25144,6 @@ package android.nfc { public final class Tag implements android.os.Parcelable { method public int describeContents(); - method public boolean done(int); method public byte[] getId(); method public java.lang.String[] getTechList(); method public void writeToParcel(android.os.Parcel, int); diff --git a/cmds/app_process/Android.mk b/cmds/app_process/Android.mk index 3ae9e1204632..fae0400a1212 100644 --- a/cmds/app_process/Android.mk +++ b/cmds/app_process/Android.mk @@ -53,7 +53,6 @@ LOCAL_SHARED_LIBRARIES := \ libutils \ liblog \ libbinder \ - libnativeloader \ libandroid_runtime \ $(app_process_common_shared_libs) \ diff --git a/cmds/app_process/app_main.cpp b/cmds/app_process/app_main.cpp index 7590325982f5..2e023825a219 100644 --- a/cmds/app_process/app_main.cpp +++ b/cmds/app_process/app_main.cpp @@ -21,7 +21,6 @@ #include <cutils/properties.h> #include <cutils/trace.h> #include <android_runtime/AndroidRuntime.h> -#include <nativeloader/native_loader.h> #include <private/android_filesystem_config.h> // for AID_SYSTEM namespace android { @@ -305,7 +304,6 @@ int main(int argc, char* const argv[]) } if (zygote) { - InitializeNativeLoader(); runtime.start("com.android.internal.os.ZygoteInit", args, zygote); } else if (className) { runtime.start("com.android.internal.os.RuntimeInit", args, zygote); diff --git a/core/java/android/animation/ObjectAnimator.java b/core/java/android/animation/ObjectAnimator.java index 542ecf41756e..1d1086049fdd 100644 --- a/core/java/android/animation/ObjectAnimator.java +++ b/core/java/android/animation/ObjectAnimator.java @@ -585,6 +585,11 @@ public final class ObjectAnimator extends ValueAnimator { * along the way, and an ending value (these values will be distributed evenly across * the duration of the animation). * + * <p><strong>Note:</strong> The values are stored as references to the original + * objects, which means that changes to those objects after this method is called will + * affect the values on the animator. If the objects will be mutated externally after + * this method is called, callers should pass a copy of those objects instead. + * * @param target The object whose property is to be animated. This object should * have a public method on it called <code>setName()</code>, where <code>name</code> is * the value of the <code>propertyName</code> parameter. @@ -635,6 +640,11 @@ public final class ObjectAnimator extends ValueAnimator { * along the way, and an ending value (these values will be distributed evenly across * the duration of the animation). * + * <p><strong>Note:</strong> The values are stored as references to the original + * objects, which means that changes to those objects after this method is called will + * affect the values on the animator. If the objects will be mutated externally after + * this method is called, callers should pass a copy of those objects instead. + * * @param target The object whose property is to be animated. * @param property The property being animated. * @param evaluator A TypeEvaluator that will be called on each animation frame to @@ -663,6 +673,11 @@ public final class ObjectAnimator extends ValueAnimator { * supplied, the <code>TypeConverter</code> must be a * {@link android.animation.BidirectionalTypeConverter} to retrieve the current value. * + * <p><strong>Note:</strong> The values are stored as references to the original + * objects, which means that changes to those objects after this method is called will + * affect the values on the animator. If the objects will be mutated externally after + * this method is called, callers should pass a copy of those objects instead. + * * @param target The object whose property is to be animated. * @param property The property being animated. * @param converter Converts the animated object to the Property type. diff --git a/core/java/android/animation/PropertyValuesHolder.java b/core/java/android/animation/PropertyValuesHolder.java index ffea6f5e0003..224823ee2ff1 100644 --- a/core/java/android/animation/PropertyValuesHolder.java +++ b/core/java/android/animation/PropertyValuesHolder.java @@ -388,6 +388,11 @@ public class PropertyValuesHolder implements Cloneable { * set of Object values. This variant also takes a TypeEvaluator because the system * cannot automatically interpolate between objects of unknown type. * + * <p><strong>Note:</strong> The Object values are stored as references to the original + * objects, which means that changes to those objects after this method is called will + * affect the values on the PropertyValuesHolder. If the objects will be mutated externally + * after this method is called, callers should pass a copy of those objects instead. + * * @param propertyName The name of the property being animated. * @param evaluator A TypeEvaluator that will be called on each animation frame to * provide the necessary interpolation between the Object values to derive the animated @@ -433,6 +438,11 @@ public class PropertyValuesHolder implements Cloneable { * set of Object values. This variant also takes a TypeEvaluator because the system * cannot automatically interpolate between objects of unknown type. * + * <p><strong>Note:</strong> The Object values are stored as references to the original + * objects, which means that changes to those objects after this method is called will + * affect the values on the PropertyValuesHolder. If the objects will be mutated externally + * after this method is called, callers should pass a copy of those objects instead. + * * @param property The property being animated. Should not be null. * @param evaluator A TypeEvaluator that will be called on each animation frame to * provide the necessary interpolation between the Object values to derive the animated @@ -458,6 +468,11 @@ public class PropertyValuesHolder implements Cloneable { * must be a {@link android.animation.BidirectionalTypeConverter} to retrieve the current * value. * + * <p><strong>Note:</strong> The Object values are stored as references to the original + * objects, which means that changes to those objects after this method is called will + * affect the values on the PropertyValuesHolder. If the objects will be mutated externally + * after this method is called, callers should pass a copy of those objects instead. + * * @param property The property being animated. Should not be null. * @param converter Converts the animated object to the Property type. * @param evaluator A TypeEvaluator that will be called on each animation frame to @@ -636,7 +651,12 @@ public class PropertyValuesHolder implements Cloneable { * {@link ObjectAnimator}, and with a getter function * derived automatically from <code>propertyName</code>, since otherwise PropertyValuesHolder has * no way of determining what the value should be. - * + * + * <p><strong>Note:</strong> The Object values are stored as references to the original + * objects, which means that changes to those objects after this method is called will + * affect the values on the PropertyValuesHolder. If the objects will be mutated externally + * after this method is called, callers should pass a copy of those objects instead. + * * @param values One or more values that the animation will animate between. */ public void setObjectValues(Object... values) { diff --git a/core/java/android/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java index 31035a746d5f..0a9b5ded8924 100644 --- a/core/java/android/animation/ValueAnimator.java +++ b/core/java/android/animation/ValueAnimator.java @@ -353,6 +353,11 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio * from the target object and property being animated). Therefore, there should typically * be two or more values. * + * <p><strong>Note:</strong> The Object values are stored as references to the original + * objects, which means that changes to those objects after this method is called will + * affect the values on the animator. If the objects will be mutated externally after + * this method is called, callers should pass a copy of those objects instead. + * * <p>Since ValueAnimator does not know how to animate between arbitrary Objects, this * factory method also takes a TypeEvaluator object that the ValueAnimator will use * to perform that interpolation. @@ -434,6 +439,11 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio * from the target object and property being animated). Therefore, there should typically * be two or more values. * + * <p><strong>Note:</strong> The Object values are stored as references to the original + * objects, which means that changes to those objects after this method is called will + * affect the values on the animator. If the objects will be mutated externally after + * this method is called, callers should pass a copy of those objects instead. + * * <p>If there are already multiple sets of values defined for this ValueAnimator via more * than one PropertyValuesHolder object, this method will set the values for the first * of those objects.</p> diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index d4400171ea89..ff8cf66770eb 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -3430,6 +3430,8 @@ public class ActivityManager { public static final int FLAG_AND_LOCKED = 1 << 1; /** {@hide} */ public static final int FLAG_AND_UNLOCKED = 1 << 2; + /** {@hide} */ + public static final int FLAG_AND_UNLOCKING_OR_UNLOCKED = 1 << 3; /** * Return whether the given user is actively running. This means that @@ -3449,26 +3451,6 @@ public class ActivityManager { } /** {@hide} */ - public boolean isUserRunningAndLocked(int userId) { - try { - return ActivityManagerNative.getDefault().isUserRunning(userId, - ActivityManager.FLAG_AND_LOCKED); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** {@hide} */ - public boolean isUserRunningAndUnlocked(int userId) { - try { - return ActivityManagerNative.getDefault().isUserRunning(userId, - ActivityManager.FLAG_AND_UNLOCKED); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** {@hide} */ public boolean isVrModePackageEnabled(ComponentName component) { try { return ActivityManagerNative.getDefault().isVrModePackageEnabled(component); diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java index a3f3b2b3ca4f..1a7c7467633f 100644 --- a/core/java/android/app/ActivityManagerNative.java +++ b/core/java/android/app/ActivityManagerNative.java @@ -794,7 +794,9 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM if (hasBounds) { bounds = Rect.CREATOR.createFromParcel(data); } - boolean res = moveTaskToDockedStack(taskId, createMode, toTop, animate, bounds); + final boolean moveHomeStackFront = data.readInt() != 0; + final boolean res = moveTaskToDockedStack( + taskId, createMode, toTop, animate, bounds, moveHomeStackFront); reply.writeNoException(); reply.writeInt(res ? 1 : 0); return true; @@ -3865,7 +3867,7 @@ class ActivityManagerProxy implements IActivityManager } @Override public boolean moveTaskToDockedStack(int taskId, int createMode, boolean toTop, boolean animate, - Rect initialBounds) throws RemoteException + Rect initialBounds, boolean moveHomeStackFront) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); @@ -3880,6 +3882,7 @@ class ActivityManagerProxy implements IActivityManager } else { data.writeInt(0); } + data.writeInt(moveHomeStackFront ? 1 : 0); mRemote.transact(MOVE_TASK_TO_DOCKED_STACK_TRANSACTION, data, reply, 0); reply.readException(); boolean res = reply.readInt() > 0; diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java index 284679838213..051295e450fa 100644 --- a/core/java/android/app/ActivityOptions.java +++ b/core/java/android/app/ActivityOptions.java @@ -160,6 +160,12 @@ public class ActivityOptions { private static final String KEY_LAUNCH_TASK_ID = "android.activity.launchTaskId"; /** + * See {@link #setAvoidMoveToFront}. + * @hide + */ + private static final String KEY_DONT_MOVE_TO_FRONT = "android.activity.dontMoveToFront"; + + /** * Where the docked stack should be positioned. * @hide */ @@ -232,6 +238,7 @@ public class ActivityOptions { private int mLaunchStackId = INVALID_STACK_ID; private int mLaunchTaskId = -1; private int mDockCreateMode = DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT; + private boolean mAvoidMoveToFront; private AppTransitionAnimationSpec mAnimSpecs[]; /** @@ -774,6 +781,7 @@ public class ActivityOptions { } mLaunchStackId = opts.getInt(KEY_LAUNCH_STACK_ID, INVALID_STACK_ID); mLaunchTaskId = opts.getInt(KEY_LAUNCH_TASK_ID, -1); + mAvoidMoveToFront = opts.getBoolean(KEY_DONT_MOVE_TO_FRONT, false); mDockCreateMode = opts.getInt(KEY_DOCK_CREATE_MODE, DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT); if (opts.containsKey(KEY_ANIM_SPECS)) { Parcelable[] specs = opts.getParcelableArray(KEY_ANIM_SPECS); @@ -950,6 +958,23 @@ public class ActivityOptions { return mLaunchTaskId; } + /** + * Set's whether the task should be moved to the front. This is different from + * {@link #getLaunchTaskBehind()} as we don't want to have an animation at all when launching + * an activity that shouldn't be moved to the front. + * @hide + */ + public void setAvoidMoveToFront(boolean avoidMoveToFront) { + mAvoidMoveToFront = avoidMoveToFront; + } + + /** + * @hide + */ + public boolean getAvoidMoveToFront() { + return mAvoidMoveToFront; + } + /** @hide */ public int getDockCreateMode() { return mDockCreateMode; @@ -1103,6 +1128,7 @@ public class ActivityOptions { } b.putInt(KEY_LAUNCH_STACK_ID, mLaunchStackId); b.putInt(KEY_LAUNCH_TASK_ID, mLaunchTaskId); + b.putBoolean(KEY_DONT_MOVE_TO_FRONT, mAvoidMoveToFront); b.putInt(KEY_DOCK_CREATE_MODE, mDockCreateMode); if (mAnimSpecs != null) { b.putParcelableArray(KEY_ANIM_SPECS, mAnimSpecs); diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index f7c0b4c32bc9..6d805eda2b38 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -4617,16 +4617,7 @@ public final class ActivityThread { // onConfigurationChanged int diff = activity.mCurrentConfig.diff(newConfig); if (diff != 0) { - // If this activity doesn't handle any of the config changes then don't bother - // calling onConfigurationChanged as we're going to destroy it. - // Except in the case where the configuration changed on the activity manager side, - // but wasn't big enough to cause a resource change so the activity wasn't destroyed. - // In this case we still want to change the configuration of the activity but not - // report it to the app. - if ((~activity.mActivityInfo.getRealConfigChanged() & diff) == 0 - || !reportToActivity) { - shouldChangeConfig = true; - } + shouldChangeConfig = true; } } diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java index 66b4fcfa0800..55ce6c2a9804 100644 --- a/core/java/android/app/IActivityManager.java +++ b/core/java/android/app/IActivityManager.java @@ -147,7 +147,7 @@ public interface IActivityManager extends IInterface { public void moveTaskBackwards(int task) throws RemoteException; public void moveTaskToStack(int taskId, int stackId, boolean toTop) throws RemoteException; public boolean moveTaskToDockedStack(int taskId, int createMode, boolean toTop, boolean animate, - Rect initialBounds) throws RemoteException; + Rect initialBounds, boolean moveHomeStackFront) throws RemoteException; public boolean moveTopActivityToPinnedStack(int stackId, Rect bounds) throws RemoteException; /** diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index db775d87c7da..0c2e3c189aae 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -939,14 +939,6 @@ public class Notification implements Parcelable public static final String EXTRA_SELF_DISPLAY_NAME = "android.selfDisplayName"; /** - * {@link #extras} key: a boolean describing whether the platform should automatically - * generate possible replies to - * {@link android.app.Notification.MessagingStyle.Message} objects provided by a - * {@link android.app.Notification.MessagingStyle} notification. - */ - public static final String EXTRA_ALLOW_GENERATED_REPLIES = "android.allowGeneratedReplies"; - - /** * {@link #extras} key: a {@link String} to be displayed as the title to a conversation * represented by a {@link android.app.Notification.MessagingStyle} */ @@ -996,6 +988,7 @@ public class Notification implements Parcelable private final Bundle mExtras; private Icon mIcon; private final RemoteInput[] mRemoteInputs; + private boolean mAllowGeneratedReplies = false; /** * Small icon representing the action. @@ -1029,6 +1022,7 @@ public class Notification implements Parcelable } mExtras = Bundle.setDefusable(in.readBundle(), true); mRemoteInputs = in.createTypedArray(RemoteInput.CREATOR); + mAllowGeneratedReplies = in.readInt() == 1; } /** @@ -1036,11 +1030,11 @@ public class Notification implements Parcelable */ @Deprecated public Action(int icon, CharSequence title, PendingIntent intent) { - this(Icon.createWithResource("", icon), title, intent, new Bundle(), null); + this(Icon.createWithResource("", icon), title, intent, new Bundle(), null, false); } private Action(Icon icon, CharSequence title, PendingIntent intent, Bundle extras, - RemoteInput[] remoteInputs) { + RemoteInput[] remoteInputs, boolean allowGeneratedReplies) { this.mIcon = icon; if (icon != null && icon.getType() == Icon.TYPE_RESOURCE) { this.icon = icon.getResId(); @@ -1049,6 +1043,7 @@ public class Notification implements Parcelable this.actionIntent = intent; this.mExtras = extras != null ? extras : new Bundle(); this.mRemoteInputs = remoteInputs; + this.mAllowGeneratedReplies = allowGeneratedReplies; } /** @@ -1070,6 +1065,14 @@ public class Notification implements Parcelable } /** + * Return whether the platform should automatically generate possible replies for this + * {@link Action} + */ + public boolean getAllowGeneratedReplies() { + return mAllowGeneratedReplies; + } + + /** * Get the list of inputs to be collected from the user when this action is sent. * May return null if no remote inputs were added. */ @@ -1084,6 +1087,7 @@ public class Notification implements Parcelable private final Icon mIcon; private final CharSequence mTitle; private final PendingIntent mIntent; + private boolean mAllowGeneratedReplies; private final Bundle mExtras; private ArrayList<RemoteInput> mRemoteInputs; @@ -1169,6 +1173,20 @@ public class Notification implements Parcelable } /** + * Set whether the platform should automatically generate possible replies to add to + * {@link RemoteInput#getChoices()}. If the {@link Action} doesn't have a + * {@link RemoteInput}, this has no effect. + * @param allowGeneratedReplies {@code true} to allow generated replies, {@code false} + * otherwise + * @return this object for method chaining + * The default value is {@code false} + */ + public Builder setAllowGeneratedReplies(boolean allowGeneratedReplies) { + mAllowGeneratedReplies = allowGeneratedReplies; + return this; + } + + /** * Apply an extender to this action builder. Extenders may be used to add * metadata or change options on this builder. */ @@ -1185,7 +1203,8 @@ public class Notification implements Parcelable public Action build() { RemoteInput[] remoteInputs = mRemoteInputs != null ? mRemoteInputs.toArray(new RemoteInput[mRemoteInputs.size()]) : null; - return new Action(mIcon, mTitle, mIntent, mExtras, remoteInputs); + return new Action(mIcon, mTitle, mIntent, mExtras, remoteInputs, + mAllowGeneratedReplies); } } @@ -1196,7 +1215,8 @@ public class Notification implements Parcelable title, actionIntent, // safe to alias new Bundle(mExtras), - getRemoteInputs()); + getRemoteInputs(), + getAllowGeneratedReplies()); } @Override public int describeContents() { @@ -1220,6 +1240,7 @@ public class Notification implements Parcelable } out.writeBundle(mExtras); out.writeTypedArray(mRemoteInputs, flags); + out.writeInt(mAllowGeneratedReplies ? 1 : 0); } public static final Parcelable.Creator<Action> CREATOR = new Parcelable.Creator<Action>() { @@ -4333,7 +4354,6 @@ public class Notification implements Parcelable CharSequence mUserDisplayName; CharSequence mConversationTitle; - boolean mAllowGeneratedReplies = true; List<Message> mMessages = new ArrayList<>(); MessagingStyle() { @@ -4357,25 +4377,6 @@ public class Notification implements Parcelable } /** - * Set whether the platform should automatically generate possible replies from messages. - * @param allowGeneratedReplies {@code true} to allow generated replies, {@code false} - * otherwise - * @return this object for method chaining - * The default value is {@code true} - */ - public MessagingStyle setAllowGeneratedReplies(boolean allowGeneratedReplies) { - mAllowGeneratedReplies = allowGeneratedReplies; - return this; - } - - /** - * Return whether the platform should automatically generate possible replies from messages. - */ - public boolean getAllowGeneratedReplies() { - return mAllowGeneratedReplies; - } - - /** * Sets the title to be displayed on this conversation. This should only be used for * group messaging and left unset for one-on-one conversations. * @param conversationTitle @@ -4449,7 +4450,6 @@ public class Notification implements Parcelable if (mConversationTitle != null) { extras.putCharSequence(EXTRA_CONVERSATION_TITLE, mConversationTitle); } - extras.putBoolean(EXTRA_ALLOW_GENERATED_REPLIES, mAllowGeneratedReplies); if (!mMessages.isEmpty()) { extras.putParcelableArray(EXTRA_MESSAGES, Message.getBundleArrayForMessages(mMessages)); } @@ -4465,11 +4465,9 @@ public class Notification implements Parcelable mMessages.clear(); mUserDisplayName = extras.getString(EXTRA_SELF_DISPLAY_NAME); mConversationTitle = extras.getString(EXTRA_CONVERSATION_TITLE); - mAllowGeneratedReplies = extras.getBoolean(EXTRA_ALLOW_GENERATED_REPLIES, - mAllowGeneratedReplies); Parcelable[] parcelables = extras.getParcelableArray(EXTRA_MESSAGES); - if (parcelables != null && parcelables instanceof Bundle[]) { - mMessages = Message.getMessagesFromBundleArray((Bundle[]) parcelables); + if (parcelables != null && parcelables instanceof Parcelable[]) { + mMessages = Message.getMessagesFromBundleArray(parcelables); } } @@ -4565,6 +4563,25 @@ public class Notification implements Parcelable return sb; } + /** + * @hide + */ + @Override + public RemoteViews makeHeadsUpContentView() { + Message m = findLatestIncomingMessage(); + CharSequence title = mConversationTitle != null + ? mConversationTitle + : (m == null) ? null : m.mSender; + CharSequence text = (m == null) + ? null + : mConversationTitle != null ? makeMessageLine(m) : m.mText; + + return mBuilder.applyStandardTemplateWithActions(mBuilder.getBigBaseLayoutResource(), + false /* hasProgress */, + title, + text); + } + private static TextAppearanceSpan makeFontColorSpan(int color) { return new TextAppearanceSpan(null, 0, 0, ColorStateList.valueOf(color), null); @@ -4698,12 +4715,14 @@ public class Notification implements Parcelable return bundles; } - static List<Message> getMessagesFromBundleArray(Bundle[] bundles) { + static List<Message> getMessagesFromBundleArray(Parcelable[] bundles) { List<Message> messages = new ArrayList<>(bundles.length); for (int i = 0; i < bundles.length; i++) { - Message message = getMessageFromBundle(bundles[i]); - if (message != null) { - messages.add(message); + if (bundles[i] instanceof Bundle) { + Message message = getMessageFromBundle((Bundle)bundles[i]); + if (message != null) { + messages.add(message); + } } } return messages; @@ -5467,6 +5486,7 @@ public class Notification implements Parcelable private static final String KEY_CUSTOM_CONTENT_HEIGHT = "customContentHeight"; private static final String KEY_GRAVITY = "gravity"; private static final String KEY_HINT_SCREEN_TIMEOUT = "hintScreenTimeout"; + private static final String KEY_DISMISSAL_ID = "dismissalId"; // Flags bitwise-ored to mFlags private static final int FLAG_CONTENT_INTENT_AVAILABLE_OFFLINE = 0x1; @@ -5495,6 +5515,7 @@ public class Notification implements Parcelable private int mCustomContentHeight; private int mGravity = DEFAULT_GRAVITY; private int mHintScreenTimeout; + private String mDismissalId; /** * Create a {@link android.app.Notification.WearableExtender} with default @@ -5531,6 +5552,7 @@ public class Notification implements Parcelable mCustomContentHeight = wearableBundle.getInt(KEY_CUSTOM_CONTENT_HEIGHT); mGravity = wearableBundle.getInt(KEY_GRAVITY, DEFAULT_GRAVITY); mHintScreenTimeout = wearableBundle.getInt(KEY_HINT_SCREEN_TIMEOUT); + mDismissalId = wearableBundle.getString(KEY_DISMISSAL_ID); } } @@ -5581,6 +5603,9 @@ public class Notification implements Parcelable if (mHintScreenTimeout != 0) { wearableBundle.putInt(KEY_HINT_SCREEN_TIMEOUT, mHintScreenTimeout); } + if (mDismissalId != null) { + wearableBundle.putString(KEY_DISMISSAL_ID, mDismissalId); + } builder.getExtras().putBundle(EXTRA_WEARABLE_EXTENSIONS, wearableBundle); return builder; @@ -5601,6 +5626,7 @@ public class Notification implements Parcelable that.mCustomContentHeight = this.mCustomContentHeight; that.mGravity = this.mGravity; that.mHintScreenTimeout = this.mHintScreenTimeout; + that.mDismissalId = this.mDismissalId; return that; } @@ -6088,6 +6114,29 @@ public class Notification implements Parcelable return (mFlags & FLAG_HINT_CONTENT_INTENT_LAUNCHES_ACTIVITY) != 0; } + /** + * When you post a notification, if you set the dismissal id field, then when that + * notification is canceled, notifications on other wearables and the paired Android phone + * having that same dismissal id will also be canceled. Note that this only works if you + * have notification bridge mode set to NO_BRIDGING in your Wear app manifest. See + * <a href="{@docRoot}wear/notifications/index.html">Adding Wearable Features to + * Notifications</a> for more information on how to use the bridge mode feature. + * @param dismissalId the dismissal id of the notification. + * @return this object for method chaining + */ + public WearableExtender setDismissalId(String dismissalId) { + mDismissalId = dismissalId; + return this; + } + + /** + * Returns the dismissal id of the notification. + * @return the dismissal id of the notification or null if it has not been set. + */ + public String getDismissalId() { + return mDismissalId; + } + private void setFlag(int mask, boolean value) { if (value) { mFlags |= mask; diff --git a/core/java/android/app/job/JobInfo.java b/core/java/android/app/job/JobInfo.java index ecfc527cb7f3..c47557501b64 100644 --- a/core/java/android/app/job/JobInfo.java +++ b/core/java/android/app/job/JobInfo.java @@ -16,6 +16,8 @@ package android.app.job; +import static android.util.TimeUtils.formatDuration; + import android.annotation.NonNull; import android.annotation.Nullable; import android.content.ComponentName; @@ -24,7 +26,6 @@ import android.os.Parcel; import android.os.Parcelable; import android.os.PersistableBundle; import android.util.Log; -import static android.util.TimeUtils.formatDuration; import java.util.ArrayList; @@ -154,6 +155,20 @@ public class JobInfo implements Parcelable { */ public static final int PRIORITY_ADJ_ALWAYS_RUNNING = -80; + /** + * Indicates that the implementation of this job will be using + * {@link JobService#startForeground(int, android.app.Notification)} to run + * in the foreground. + * <p> + * When set, the internal scheduling of this job will ignore any background + * network restrictions for the requesting app. Note that this flag alone + * doesn't actually place your {@link JobService} in the foreground; you + * still need to post the notification yourself. + * + * @hide + */ + public static final int FLAG_WILL_BE_FOREGROUND = 1 << 0; + private final int jobId; private final PersistableBundle extras; private final ComponentName service; @@ -174,6 +189,7 @@ public class JobInfo implements Parcelable { private final long initialBackoffMillis; private final int backoffPolicy; private final int priority; + private final int flags; /** * Unique job id associated with this class. This is assigned to your job by the scheduler. @@ -201,6 +217,11 @@ public class JobInfo implements Parcelable { return priority; } + /** @hide */ + public int getFlags() { + return flags; + } + /** * Whether this job needs the device to be plugged in. */ @@ -356,6 +377,7 @@ public class JobInfo implements Parcelable { hasEarlyConstraint = in.readInt() == 1; hasLateConstraint = in.readInt() == 1; priority = in.readInt(); + flags = in.readInt(); } private JobInfo(JobInfo.Builder b) { @@ -381,6 +403,7 @@ public class JobInfo implements Parcelable { hasEarlyConstraint = b.mHasEarlyConstraint; hasLateConstraint = b.mHasLateConstraint; priority = b.mPriority; + flags = b.mFlags; } @Override @@ -410,6 +433,7 @@ public class JobInfo implements Parcelable { out.writeInt(hasEarlyConstraint ? 1 : 0); out.writeInt(hasLateConstraint ? 1 : 0); out.writeInt(priority); + out.writeInt(this.flags); } public static final Creator<JobInfo> CREATOR = new Creator<JobInfo>() { @@ -504,6 +528,7 @@ public class JobInfo implements Parcelable { private PersistableBundle mExtras = PersistableBundle.EMPTY; private ComponentName mJobService; private int mPriority = PRIORITY_DEFAULT; + private int mFlags; // Requirements. private boolean mRequiresCharging; private boolean mRequiresDeviceIdle; @@ -539,14 +564,18 @@ public class JobInfo implements Parcelable { mJobId = jobId; } - /** - * @hide - */ + /** @hide */ public Builder setPriority(int priority) { mPriority = priority; return this; } + /** @hide */ + public Builder setFlags(int flags) { + mFlags = flags; + return this; + } + /** * Set optional extras. This is persisted, so we only allow primitive types. * @param extras Bundle containing extras you want the scheduler to hold on to for you. diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java index 4db45670dd85..aeda7a24066d 100644 --- a/core/java/android/content/ContentResolver.java +++ b/core/java/android/content/ContentResolver.java @@ -1748,7 +1748,7 @@ public abstract class ContentResolver { * * @hide */ - public void notifyChange(Uri uri, ContentObserver observer, boolean syncToNetwork, + public void notifyChange(@NonNull Uri uri, ContentObserver observer, boolean syncToNetwork, @UserIdInt int userHandle) { try { getContentService().notifyChange( @@ -1765,7 +1765,7 @@ public abstract class ContentResolver { * * @hide */ - public void notifyChange(Uri uri, ContentObserver observer, @NotifyFlags int flags, + public void notifyChange(@NonNull Uri uri, ContentObserver observer, @NotifyFlags int flags, @UserIdInt int userHandle) { try { getContentService().notifyChange( diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java index 167befc089dd..bdea1e009eb0 100644 --- a/core/java/android/content/pm/ActivityInfo.java +++ b/core/java/android/content/pm/ActivityInfo.java @@ -188,7 +188,7 @@ public class ActivityInfo extends ComponentInfo * See {@link android.R.attr#resizeableActivity}. * @hide */ - public int resizeMode; + public int resizeMode = RESIZE_MODE_RESIZEABLE; /** * Name of the VrListenerService component to run for this activity. diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl index 0c793120d0a8..03f83d622cde 100644 --- a/core/java/android/content/pm/IPackageManager.aidl +++ b/core/java/android/content/pm/IPackageManager.aidl @@ -222,7 +222,7 @@ interface IPackageManager { in String installerPackageName, int userId); - void finishPackageInstall(int token); + void finishPackageInstall(int token, boolean didLaunch); void setInstallerPackageName(in String targetPackage, in String installerPackageName); diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index 66c500063861..6534f5b32456 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -159,6 +159,7 @@ public class PackageParser { private static final String TAG_SUPPORTS_INPUT = "supports-input"; private static final String TAG_EAT_COMMENT = "eat-comment"; private static final String TAG_PACKAGE = "package"; + private static final String TAG_RESTRICT_UPDATE = "restrict-update"; // These are the tags supported by child packages private static final Set<String> CHILD_PACKAGE_TAGS = new ArraySet<>(); @@ -1639,9 +1640,9 @@ public class PackageParser { /** * This is the common parsing routing for handling parent and child * packages in a base APK. The difference between parent and child - * parsing is that some targs are not supported by child packages as + * parsing is that some tags are not supported by child packages as * well as some manifest attributes are ignored. The implementation - * assumes the calling code already handled the manifest tag if needed + * assumes the calling code has already handled the manifest tag if needed * (this applies to the parent only). * * @param pkg The package which to populate @@ -2089,6 +2090,29 @@ public class PackageParser { // If parsing a child failed the error is already set return null; } + + } else if (tagName.equals(TAG_RESTRICT_UPDATE)) { + if ((flags & PARSE_IS_SYSTEM_DIR) != 0) { + sa = res.obtainAttributes(parser, + com.android.internal.R.styleable.AndroidManifestRestrictUpdate); + final String hash = sa.getNonConfigurationString( + com.android.internal.R.styleable.AndroidManifestRestrictUpdate_hash, 0); + sa.recycle(); + + pkg.restrictUpdateHash = null; + if (hash != null) { + final int hashLength = hash.length(); + final byte[] hashBytes = new byte[hashLength / 2]; + for (int i = 0; i < hashLength; i += 2){ + hashBytes[i/2] = (byte) ((Character.digit(hash.charAt(i), 16) << 4) + + Character.digit(hash.charAt(i + 1), 16)); + } + pkg.restrictUpdateHash = hashBytes; + } + } + + XmlUtils.skipCurrentTag(parser); + } else if (RIGID_PARSER) { outError[0] = "Bad element under <manifest>: " + parser.getName(); @@ -4822,6 +4846,8 @@ public class PackageParser { */ public boolean use32bitAbi; + public byte[] restrictUpdateHash; + public Package(String packageName) { this.packageName = packageName; applicationInfo.packageName = packageName; diff --git a/core/java/android/hardware/location/ContextHubInfo.java b/core/java/android/hardware/location/ContextHubInfo.java index 194b9ee58780..aaf6c57b9abe 100644 --- a/core/java/android/hardware/location/ContextHubInfo.java +++ b/core/java/android/hardware/location/ContextHubInfo.java @@ -357,6 +357,7 @@ public class ContextHubInfo { retVal += "\n\tPeakMips : " + mPeakMips; retVal += ", StoppedPowerDraw : " + mStoppedPowerDrawMw + " mW"; retVal += ", PeakPowerDraw : " + mPeakPowerDrawMw + " mW"; + retVal += ", MaxPacketLength : " + mMaxPacketLengthBytes + " Bytes"; retVal += "\n\tSupported sensors : " + Arrays.toString(mSupportedSensors); retVal += "\n\tMemory Regions : " + Arrays.toString(mMemoryRegions); @@ -375,6 +376,7 @@ public class ContextHubInfo { mStoppedPowerDrawMw = in.readFloat(); mSleepPowerDrawMw = in.readFloat(); mPeakPowerDrawMw = in.readFloat(); + mMaxPacketLengthBytes = in.readInt(); int numSupportedSensors = in.readInt(); mSupportedSensors = new int[numSupportedSensors]; @@ -398,6 +400,7 @@ public class ContextHubInfo { out.writeFloat(mStoppedPowerDrawMw); out.writeFloat(mSleepPowerDrawMw); out.writeFloat(mPeakPowerDrawMw); + out.writeInt(mMaxPacketLengthBytes); out.writeInt(mSupportedSensors.length); out.writeIntArray(mSupportedSensors); @@ -414,4 +417,4 @@ public class ContextHubInfo { return new ContextHubInfo[size]; } }; -}
\ No newline at end of file +} diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index faf5c64e5a00..933dddf4a948 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -774,8 +774,13 @@ public class ConnectivityManager { * @hide */ public Network getActiveNetworkForUid(int uid) { + return getActiveNetworkForUid(uid, false); + } + + /** {@hide} */ + public Network getActiveNetworkForUid(int uid, boolean ignoreBlocked) { try { - return mService.getActiveNetworkForUid(uid); + return mService.getActiveNetworkForUid(uid, ignoreBlocked); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -836,8 +841,13 @@ public class ConnectivityManager { * {@hide} */ public NetworkInfo getActiveNetworkInfoForUid(int uid) { + return getActiveNetworkInfoForUid(uid, false); + } + + /** {@hide} */ + public NetworkInfo getActiveNetworkInfoForUid(int uid, boolean ignoreBlocked) { try { - return mService.getActiveNetworkInfoForUid(uid); + return mService.getActiveNetworkInfoForUid(uid, ignoreBlocked); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -880,8 +890,13 @@ public class ConnectivityManager { * is not valid. */ public NetworkInfo getNetworkInfo(Network network) { + return getNetworkInfoForUid(network, Process.myUid(), false); + } + + /** {@hide} */ + public NetworkInfo getNetworkInfoForUid(Network network, int uid, boolean ignoreBlocked) { try { - return mService.getNetworkInfoForNetwork(network); + return mService.getNetworkInfoForUid(network, uid, ignoreBlocked); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index c897c4506c1f..aec6b3ec23fe 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -44,11 +44,11 @@ import com.android.internal.net.VpnProfile; interface IConnectivityManager { Network getActiveNetwork(); - Network getActiveNetworkForUid(int uid); + Network getActiveNetworkForUid(int uid, boolean ignoreBlocked); NetworkInfo getActiveNetworkInfo(); - NetworkInfo getActiveNetworkInfoForUid(int uid); + NetworkInfo getActiveNetworkInfoForUid(int uid, boolean ignoreBlocked); NetworkInfo getNetworkInfo(int networkType); - NetworkInfo getNetworkInfoForNetwork(in Network network); + NetworkInfo getNetworkInfoForUid(in Network network, int uid, boolean ignoreBlocked); NetworkInfo[] getAllNetworkInfo(); Network getNetworkForType(int networkType); Network[] getAllNetworks(); diff --git a/core/java/android/net/INetworkPolicyManager.aidl b/core/java/android/net/INetworkPolicyManager.aidl index 2b8b28d91bd0..224ff5b395c7 100644 --- a/core/java/android/net/INetworkPolicyManager.aidl +++ b/core/java/android/net/INetworkPolicyManager.aidl @@ -38,6 +38,9 @@ interface INetworkPolicyManager { boolean isUidForeground(int uid); + /** Higher priority listener before general event dispatch */ + void setConnectivityListener(INetworkPolicyListener listener); + void registerListener(INetworkPolicyListener listener); void unregisterListener(INetworkPolicyListener listener); diff --git a/core/java/android/net/metrics/ValidationProbeEvent.java b/core/java/android/net/metrics/ValidationProbeEvent.java index 5c8ea65a7c7a..751c35f8a144 100644 --- a/core/java/android/net/metrics/ValidationProbeEvent.java +++ b/core/java/android/net/metrics/ValidationProbeEvent.java @@ -29,8 +29,13 @@ import com.android.internal.util.MessageUtils; @SystemApi public final class ValidationProbeEvent extends IpConnectivityEvent implements Parcelable { - public static final int PROBE_HTTP = 0; - public static final int PROBE_HTTPS = 1; + public static final int PROBE_DNS = 0; + public static final int PROBE_HTTP = 1; + public static final int PROBE_HTTPS = 2; + public static final int PROBE_PAC = 3; + + public static final int DNS_FAILURE = 0; + public static final int DNS_SUCCESS = 1; public final int netId; public final long durationMs; @@ -73,6 +78,11 @@ public final class ValidationProbeEvent extends IpConnectivityEvent implements P } }; + /** @hide */ + public static String getProbeName(int probeType) { + return Decoder.constants.get(probeType, "PROBE_???"); + } + public static void logEvent(int netId, long durationMs, int probeType, int returnCode) { logEvent(new ValidationProbeEvent(netId, durationMs, probeType, returnCode)); } @@ -80,7 +90,7 @@ public final class ValidationProbeEvent extends IpConnectivityEvent implements P @Override public String toString() { return String.format("ValidationProbeEvent(%d, %s:%d, %dms)", - netId, Decoder.constants.get(probeType), returnCode, durationMs); + netId, getProbeName(probeType), returnCode, durationMs); } final static class Decoder { diff --git a/core/java/android/nfc/INfcAdapter.aidl b/core/java/android/nfc/INfcAdapter.aidl index 940565f09c03..f991efed07eb 100644 --- a/core/java/android/nfc/INfcAdapter.aidl +++ b/core/java/android/nfc/INfcAdapter.aidl @@ -28,6 +28,7 @@ import android.nfc.INfcTag; import android.nfc.INfcCardEmulation; import android.nfc.INfcFCardEmulation; import android.nfc.INfcUnlockHandler; +import android.nfc.ITagRemovedCallback; import android.os.Bundle; /** @@ -55,6 +56,8 @@ interface INfcAdapter oneway void invokeBeam(); oneway void invokeBeamInternal(in BeamShareData shareData); + boolean ignore(int nativeHandle, int debounceMs, ITagRemovedCallback callback); + void dispatch(in Tag tag); void setReaderMode (IBinder b, IAppCallback callback, int flags, in Bundle extras); diff --git a/core/java/android/nfc/INfcTag.aidl b/core/java/android/nfc/INfcTag.aidl index 26d2bec761f8..539fd4adb0a0 100644 --- a/core/java/android/nfc/INfcTag.aidl +++ b/core/java/android/nfc/INfcTag.aidl @@ -31,7 +31,6 @@ interface INfcTag boolean isNdef(int nativeHandle); boolean isPresent(int nativeHandle); TransceiveResult transceive(int nativeHandle, in byte[] data, boolean raw); - boolean done(int nativeHandle, int debounceMs); NdefMessage ndefRead(int nativeHandle); int ndefWrite(int nativeHandle, in NdefMessage msg); diff --git a/core/java/android/nfc/ITagRemovedCallback.aidl b/core/java/android/nfc/ITagRemovedCallback.aidl new file mode 100644 index 000000000000..2a06ff314b22 --- /dev/null +++ b/core/java/android/nfc/ITagRemovedCallback.aidl @@ -0,0 +1,8 @@ +package android.nfc; + +/** + * @hide + */ +oneway interface ITagRemovedCallback { + void onTagRemoved(); +} diff --git a/core/java/android/nfc/NfcAdapter.java b/core/java/android/nfc/NfcAdapter.java index 6f911ceb4bed..8406bcfa8184 100644 --- a/core/java/android/nfc/NfcAdapter.java +++ b/core/java/android/nfc/NfcAdapter.java @@ -35,11 +35,14 @@ import android.nfc.tech.Ndef; import android.nfc.tech.NfcA; import android.nfc.tech.NfcF; import android.os.Bundle; +import android.os.Handler; import android.os.IBinder; import android.os.RemoteException; import android.os.ServiceManager; import android.util.Log; +import java.io.IOException; + /** * Represents the local NFC adapter. * <p> @@ -315,6 +318,8 @@ public final class NfcAdapter { final HashMap<NfcUnlockHandler, INfcUnlockHandler> mNfcUnlockHandlers; final Object mLock; + ITagRemovedCallback mTagRemovedListener; // protected by mLock + /** * A callback to be invoked when the system finds a tag while the foreground activity is * operating in reader mode. @@ -386,6 +391,13 @@ public final class NfcAdapter { } /** + * A callback that is invoked when a tag is removed from the field. + */ + public interface OnTagRemovedListener { + void onTagRemoved(); + } + + /** * A callback to be invoked when an application has registered as a * handler to unlock the device given an NFC tag at the lockscreen. * @hide @@ -541,6 +553,7 @@ public final class NfcAdapter { mContext = context; mNfcActivityManager = new NfcActivityManager(this); mNfcUnlockHandlers = new HashMap<NfcUnlockHandler, INfcUnlockHandler>(); + mTagRemovedListener = null; mLock = new Object(); } @@ -1494,6 +1507,75 @@ public final class NfcAdapter { } /** + * Signals that you are no longer interested in communicating with an NFC tag + * for as long as it remains in range. + * + * All future attempted communication to this tag will fail with {@link IOException}. + * The NFC controller will be put in a low-power polling mode, allowing the device + * to save power in cases where it's "attached" to a tag all the time (e.g. a tag in + * car dock). + * + * Additionally the debounceMs parameter allows you to specify for how long the tag needs + * to have gone out of range, before it will be dispatched again. + * + * Note: the NFC controller typically polls at a pretty slow interval (100 - 500 ms). + * This means that if the tag repeatedly goes in and out of range (for example, in + * case of a flaky connection), and the controller happens to poll every time the + * tag is out of range, it *will* re-dispatch the tag after debounceMs, despite the tag + * having been "in range" during the interval. + * + * Note 2: if a tag with another UID is detected after this API is called, its effect + * will be cancelled; if this tag shows up before the amount of time specified in + * debounceMs, it will be dispatched again. + * + * Note 3: some tags have a random UID, in which case this API won't work reliably. + * + * @param tag the {@link android.nfc.Tag Tag} to ignore. + * @param debounceMs minimum amount of time the tag needs to be out of range before being + * dispatched again. + * @param tagRemovedListener listener to be called when the tag is removed from the field. + * Note that this will only be called if the tag has been out of range + * for at least debounceMs, or if another tag came into range before + * debounceMs. May be null in case you don't want a callback. + * @param handler the {@link android.os.Handler Handler} that will be used for delivering + * the callback. if the handler is null, then the thread used for delivering + * the callback is unspecified. + * @return false if the tag couldn't be found (or has already gone out of range), true otherwise + */ + public boolean ignore(final Tag tag, int debounceMs, + final OnTagRemovedListener tagRemovedListener, final Handler handler) { + ITagRemovedCallback.Stub iListener = null; + if (tagRemovedListener != null) { + iListener = new ITagRemovedCallback.Stub() { + @Override + public void onTagRemoved() throws RemoteException { + if (handler != null) { + handler.post(new Runnable() { + @Override + public void run() { + tagRemovedListener.onTagRemoved(); + } + }); + } else { + tagRemovedListener.onTagRemoved(); + } + synchronized (mLock) { + mTagRemovedListener = null; + } + } + }; + } + synchronized (mLock) { + mTagRemovedListener = iListener; + } + try { + return sService.ignore(tag.getServiceHandle(), debounceMs, iListener); + } catch (RemoteException e) { + return false; + } + } + + /** * Inject a mock NFC tag.<p> * Used for testing purposes. * <p class="note">Requires the diff --git a/core/java/android/nfc/Tag.java b/core/java/android/nfc/Tag.java index 40d5a8db83b4..154d5a11db9e 100644 --- a/core/java/android/nfc/Tag.java +++ b/core/java/android/nfc/Tag.java @@ -214,42 +214,6 @@ public final class Tag implements Parcelable { return techIntList; } - /** - * Signals that you are no longer interested in communicating with this tag - * for as long as it remains in range. - * - * All future attempted communication to this tag will fail with {@link IOException}. - * The NFC controller will be put in a low-power polling mode, allowing the device - * to save power in cases where it's "attached" to a tag all the time (eg a tag in - * car dock). - * - * Additionally the debounceMs parameter allows you to specify for how long the tag needs - * to have gone out of range, before it will be dispatched again. - * - * Note: the NFC controller typically polls at a pretty slow interval (100 - 500 ms). - * This means that if the tag repeatedly goes in and out of range (for example, in - * case of a flaky connection), and the controller happens to poll every time the - * tag is out of range, it *will* re-dispatch the tag after debounceMs, despite the tag - * having been "in range" during the interval. - * - * Note 2: if a tag with another UID is detected after this API is called, its effect - * will be cancelled; if this tag shows up before the amount of time specified in - * debounceMs, it will be dispatched again. - * - * Note 3: some tags have a random UID, in which case this API won't work. - * - * @param debounceMs minimum amount of time the tag needs to be out of range before being - * dispatched again. - * @return false if the Tag couldn't be found (or has gone out of range), true otherwise - */ - public boolean done(int debounceMs) { - try { - return mTagService.done(getServiceHandle(), debounceMs); - } catch (RemoteException e) { - return false; - } - } - private static HashMap<String, Integer> getTechStringToCodeMap() { HashMap<String, Integer> techStringToCodeMap = new HashMap<String, Integer>(); diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java index b9a3cff1aabb..959b30946c8a 100644 --- a/core/java/android/os/BatteryStats.java +++ b/core/java/android/os/BatteryStats.java @@ -1070,6 +1070,9 @@ public abstract class BatteryStats implements Parcelable { public int statSoftIrqTime; public int statIdlTime; + // Platform-level low power state stats + public String statPlatformIdleState; + public HistoryStepDetails() { clear(); } @@ -1099,6 +1102,7 @@ public abstract class BatteryStats implements Parcelable { out.writeInt(statIrqTime); out.writeInt(statSoftIrqTime); out.writeInt(statIdlTime); + out.writeString(statPlatformIdleState); } public void readFromParcel(Parcel in) { @@ -1119,6 +1123,7 @@ public abstract class BatteryStats implements Parcelable { statIrqTime = in.readInt(); statSoftIrqTime = in.readInt(); statIdlTime = in.readInt(); + statPlatformIdleState = in.readString(); } } @@ -1152,6 +1157,8 @@ public abstract class BatteryStats implements Parcelable { public short batteryTemperature; public char batteryVoltage; + + public int batteryChargeCoulombs; // Constants from SCREEN_BRIGHTNESS_* public static final int STATE_BRIGHTNESS_SHIFT = 0; @@ -1176,6 +1183,8 @@ public abstract class BatteryStats implements Parcelable { public static final int STATE_WIFI_SCAN_FLAG = 1<<27; public static final int STATE_WIFI_RADIO_ACTIVE_FLAG = 1<<26; public static final int STATE_MOBILE_RADIO_ACTIVE_FLAG = 1<<25; + // Do not use, this is used for coulomb delta count. + private static final int STATE_RESERVED_0 = 1<<24; // These are on the lower bits used for the command; if they change // we need to write another int of data. public static final int STATE_SENSOR_ON_FLAG = 1<<23; @@ -1347,6 +1356,7 @@ public abstract class BatteryStats implements Parcelable { bat = (((int)batteryTemperature)&0xffff) | ((((int)batteryVoltage)<<16)&0xffff0000); dest.writeInt(bat); + dest.writeInt(batteryChargeCoulombs); dest.writeInt(states); dest.writeInt(states2); if (wakelockTag != null) { @@ -1375,6 +1385,7 @@ public abstract class BatteryStats implements Parcelable { int bat2 = src.readInt(); batteryTemperature = (short)(bat2&0xffff); batteryVoltage = (char)((bat2>>16)&0xffff); + batteryChargeCoulombs = src.readInt(); states = src.readInt(); states2 = src.readInt(); if ((bat&0x10000000) != 0) { @@ -1414,6 +1425,7 @@ public abstract class BatteryStats implements Parcelable { batteryPlugType = 0; batteryTemperature = 0; batteryVoltage = 0; + batteryChargeCoulombs = 0; states = 0; states2 = 0; wakelockTag = null; @@ -1441,6 +1453,7 @@ public abstract class BatteryStats implements Parcelable { batteryPlugType = o.batteryPlugType; batteryTemperature = o.batteryTemperature; batteryVoltage = o.batteryVoltage; + batteryChargeCoulombs = o.batteryChargeCoulombs; states = o.states; states2 = o.states2; if (o.wakelockTag != null) { @@ -1472,6 +1485,7 @@ public abstract class BatteryStats implements Parcelable { && batteryPlugType == o.batteryPlugType && batteryTemperature == o.batteryTemperature && batteryVoltage == o.batteryVoltage + && batteryChargeCoulombs == o.batteryChargeCoulombs && states == o.states && states2 == o.states2 && currentTime == o.currentTime; @@ -4522,6 +4536,7 @@ public abstract class BatteryStats implements Parcelable { int oldPlug = -1; int oldTemp = -1; int oldVolt = -1; + int oldCharge = -1; long lastTime = -1; void reset() { @@ -4532,6 +4547,7 @@ public abstract class BatteryStats implements Parcelable { oldPlug = -1; oldTemp = -1; oldVolt = -1; + oldCharge = -1; } public void printNextItem(PrintWriter pw, HistoryItem rec, long baseTime, boolean checkin, @@ -4693,6 +4709,11 @@ public abstract class BatteryStats implements Parcelable { pw.print(checkin ? ",Bv=" : " volt="); pw.print(oldVolt); } + if (oldCharge != rec.batteryChargeCoulombs) { + oldCharge = rec.batteryChargeCoulombs; + pw.print(checkin ? ",Bcc=" : " charge="); + pw.print(oldCharge); + } printBitDescriptions(pw, oldState, rec.states, rec.wakelockTag, HISTORY_STATE_DESCRIPTIONS, !checkin); printBitDescriptions(pw, oldState2, rec.states2, null, @@ -4788,6 +4809,8 @@ public abstract class BatteryStats implements Parcelable { pw.print(sb); pw.print(")"); } + pw.print(", PlatformIdleStat "); + pw.print(rec.stepDetails.statPlatformIdleState); pw.println(); } else { pw.print(BATTERY_STATS_CHECKIN_VERSION); pw.print(','); @@ -4821,6 +4844,8 @@ public abstract class BatteryStats implements Parcelable { pw.print(rec.stepDetails.statSoftIrqTime); pw.print(','); pw.print(rec.stepDetails.statIdlTime); + pw.print(','); + pw.print(rec.stepDetails.statPlatformIdleState); pw.println(); } } diff --git a/core/java/android/os/FileUtils.java b/core/java/android/os/FileUtils.java index 7d74a1234c26..fa32848e6362 100644 --- a/core/java/android/os/FileUtils.java +++ b/core/java/android/os/FileUtils.java @@ -72,8 +72,13 @@ public class FileUtils { public static final int S_IWOTH = 00002; public static final int S_IXOTH = 00001; - /** Regular expression for safe filenames: no spaces or metacharacters */ - private static final Pattern SAFE_FILENAME_PATTERN = Pattern.compile("[\\w%+,./=_-]+"); + /** Regular expression for safe filenames: no spaces or metacharacters. + * + * Use a preload holder so that FileUtils can be compile-time initialized. + */ + private static class NoImagePreloadHolder { + public static final Pattern SAFE_FILENAME_PATTERN = Pattern.compile("[\\w%+,./=_-]+"); + } private static final File[] EMPTY = new File[0]; @@ -243,7 +248,7 @@ public class FileUtils { // Note, we check whether it matches what's known to be safe, // rather than what's known to be unsafe. Non-ASCII, control // characters, etc. are all unsafe by default. - return SAFE_FILENAME_PATTERN.matcher(file.getPath()).matches(); + return NoImagePreloadHolder.SAFE_FILENAME_PATTERN.matcher(file.getPath()).matches(); } /** diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl index 68b0a9fb2969..b546da021e18 100644 --- a/core/java/android/os/INetworkManagementService.aidl +++ b/core/java/android/os/INetworkManagementService.aidl @@ -324,6 +324,11 @@ interface INetworkManagementService void removeIdleTimer(String iface); /** + * Configure name servers, search paths, and resolver parameters for the given network. + */ + void setDnsConfigurationForNetwork(int netId, in String[] servers, String domains); + + /** * Bind name servers to a network in the DNS resolver. */ void setDnsServersForNetwork(int netId, in String[] servers, String domains); diff --git a/core/java/android/os/RecoverySystem.java b/core/java/android/os/RecoverySystem.java index b25b33d00aa8..403e06ca8553 100644 --- a/core/java/android/os/RecoverySystem.java +++ b/core/java/android/os/RecoverySystem.java @@ -434,6 +434,9 @@ public class RecoverySystem { String filename = packageFile.getCanonicalPath(); Log.w(TAG, "!!! REBOOTING TO INSTALL " + filename + " !!!"); + // If the package name ends with "_s.zip", it's a security update. + boolean securityUpdate = filename.endsWith("_s.zip"); + // If the package is on the /data partition, the package needs to // be processed (i.e. uncrypt'd). The caller specifies if that has // been done in 'processed' parameter. @@ -468,7 +471,12 @@ public class RecoverySystem { final String filenameArg = "--update_package=" + filename + "\n"; final String localeArg = "--locale=" + Locale.getDefault().toString() + "\n"; - final String command = filenameArg + localeArg; + final String securityArg = "--security\n"; + + String command = filenameArg + localeArg; + if (securityUpdate) { + command += securityArg; + } RecoverySystem rs = (RecoverySystem) context.getSystemService( Context.RECOVERY_SERVICE); @@ -501,6 +509,7 @@ public class RecoverySystem { public static void scheduleUpdateOnBoot(Context context, File packageFile) throws IOException { String filename = packageFile.getCanonicalPath(); + boolean securityUpdate = filename.endsWith("_s.zip"); // If the package is on the /data partition, use the block map file as // the package name instead. @@ -510,7 +519,12 @@ public class RecoverySystem { final String filenameArg = "--update_package=" + filename + "\n"; final String localeArg = "--locale=" + Locale.getDefault().toString() + "\n"; - final String command = filenameArg + localeArg; + final String securityArg = "--security\n"; + + String command = filenameArg + localeArg; + if (securityUpdate) { + command += securityArg; + } RecoverySystem rs = (RecoverySystem) context.getSystemService(Context.RECOVERY_SERVICE); if (!rs.setupBcb(command)) { diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java index dd53cbb41c3e..d55201f709e9 100644 --- a/core/java/android/os/UserManager.java +++ b/core/java/android/os/UserManager.java @@ -36,7 +36,6 @@ import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Rect; import android.graphics.drawable.Drawable; -import android.os.storage.StorageManager; import android.provider.Settings; import android.telephony.TelephonyManager; import android.view.WindowManager.LayoutParams; @@ -984,10 +983,27 @@ public class UserManager { /** {@hide} */ public boolean isUserUnlocked(@UserIdInt int userId) { - // TODO: eventually pivot this back to look at ActivityManager state, - // but there is race where we can start a non-encryption-aware launcher - // before that lifecycle has entered the running unlocked state. - return mContext.getSystemService(StorageManager.class).isUserKeyUnlocked(userId); + try { + return ActivityManagerNative.getDefault().isUserRunning(userId, + ActivityManager.FLAG_AND_UNLOCKED); + } catch (RemoteException re) { + throw re.rethrowFromSystemServer(); + } + } + + /** {@hide} */ + public boolean isUserUnlockingOrUnlocked(UserHandle user) { + return isUserUnlockingOrUnlocked(user.getIdentifier()); + } + + /** {@hide} */ + public boolean isUserUnlockingOrUnlocked(@UserIdInt int userId) { + try { + return ActivityManagerNative.getDefault().isUserRunning(userId, + ActivityManager.FLAG_AND_UNLOCKING_OR_UNLOCKED); + } catch (RemoteException re) { + throw re.rethrowFromSystemServer(); + } } /** diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java index f68e227a32a3..fbf7b266330b 100644 --- a/core/java/android/os/storage/StorageManager.java +++ b/core/java/android/os/storage/StorageManager.java @@ -25,6 +25,7 @@ import android.content.ContentResolver; import android.content.Context; import android.content.pm.IPackageMoveObserver; import android.content.pm.PackageManager; +import android.os.Binder; import android.os.Environment; import android.os.FileUtils; import android.os.Handler; @@ -1062,11 +1063,20 @@ public class StorageManager { } /** {@hide} */ - public boolean isUserKeyUnlocked(int userId) { + public static boolean isUserKeyUnlocked(int userId) { + final IMountService mount = IMountService.Stub + .asInterface(ServiceManager.getService("mount")); + if (mount == null) { + Slog.w(TAG, "Early during boot, assuming locked"); + return false; + } + final long token = Binder.clearCallingIdentity(); try { - return mMountService.isUserKeyUnlocked(userId); + return mount.isUserKeyUnlocked(userId); } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); + throw e.rethrowAsRuntimeException(); + } finally { + Binder.restoreCallingIdentity(token); } } diff --git a/core/java/android/provider/CallLog.java b/core/java/android/provider/CallLog.java index 8a0759fbdb46..893eb3701df4 100644 --- a/core/java/android/provider/CallLog.java +++ b/core/java/android/provider/CallLog.java @@ -824,6 +824,8 @@ public class CallLog { UserHandle user, ContentValues values) { final ContentResolver resolver = context.getContentResolver(); + // Since we're doing this operation on behalf of an app, we only + // want to use the actual "unlocked" state. final Uri uri = ContentProvider.maybeAddUserId( userManager.isUserUnlocked(user) ? CONTENT_URI : SHADOW_CONTENT_URI, user.getIdentifier()); diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 2394531ad0a3..700c2d28b3dd 100755 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -6869,14 +6869,6 @@ public final class Settings { "hdmi_control_auto_device_off_enabled"; /** - * Whether to use the DHCP client from Lollipop and earlier instead of the newer Android DHCP - * client. - * (0 = false, 1 = true) - * @hide - */ - public static final String LEGACY_DHCP_CLIENT = "legacy_dhcp_client"; - - /** * Whether TV will switch to MHL port when a mobile device is plugged in. * (0 = false, 1 = true) * @hide @@ -6982,6 +6974,33 @@ public final class Settings { public static final String STORAGE_BENCHMARK_INTERVAL = "storage_benchmark_interval"; /** + * Sample validity in seconds to configure for the system DNS resolver. + * {@hide} + */ + public static final String DNS_RESOLVER_SAMPLE_VALIDITY_SECONDS = + "dns_resolver_sample_validity_seconds"; + + /** + * Success threshold in percent for use with the system DNS resolver. + * {@hide} + */ + public static final String DNS_RESOLVER_SUCCESS_THRESHOLD_PERCENT = + "dns_resolver_success_threshold_percent"; + + /** + * Minimum number of samples needed for statistics to be considered meaningful in the + * system DNS resolver. + * {@hide} + */ + public static final String DNS_RESOLVER_MIN_SAMPLES = "dns_resolver_min_samples"; + + /** + * Maximum number taken into account for statistics purposes in the system DNS resolver. + * {@hide} + */ + public static final String DNS_RESOLVER_MAX_SAMPLES = "dns_resolver_max_samples"; + + /** * Whether to disable the automatic scheduling of system updates. * 1 = system updates won't be automatically scheduled (will always * present notification instead). @@ -7706,6 +7725,15 @@ public final class Settings { public static final String CAPTIVE_PORTAL_SERVER = "captive_portal_server"; /** + * Whether to use HTTPS for network validation. This is enabled by default and the setting + * needs to be set to 0 to disable it. This setting is a misnomer because captive portals + * don't actually use HTTPS, but it's consistent with the other settings. + * + * @hide + */ + public static final String CAPTIVE_PORTAL_USE_HTTPS = "captive_portal_use_https"; + + /** * Whether network service discovery is enabled. * * @hide diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java index e708b0ad5aff..cf783d25251e 100644 --- a/core/java/android/service/notification/NotificationListenerService.java +++ b/core/java/android/service/notification/NotificationListenerService.java @@ -764,9 +764,9 @@ public abstract class NotificationListenerService extends Service { } mSystemContext = context; INotificationManager noMan = getNotificationInterface(); - noMan.registerListener(mWrapper, componentName, currentUser); - mCurrentUser = currentUser; mHandler = new MyHandler(context.getMainLooper()); + mCurrentUser = currentUser; + noMan.registerListener(mWrapper, componentName, currentUser); } /** diff --git a/core/java/android/view/DisplayInfo.java b/core/java/android/view/DisplayInfo.java index 27fe687c3a72..8aeeffd90643 100644 --- a/core/java/android/view/DisplayInfo.java +++ b/core/java/android/view/DisplayInfo.java @@ -380,7 +380,7 @@ public final class DisplayInfo implements Parcelable { for (int i = 0; i < nColorTransforms; i++) { supportedColorTransforms[i] = Display.ColorTransform.CREATOR.createFromParcel(source); } - hdrCapabilities = Display.HdrCapabilities.CREATOR.createFromParcel(source); + hdrCapabilities = source.readParcelable(null); logicalDensityDpi = source.readInt(); physicalXDpi = source.readFloat(); physicalYDpi = source.readFloat(); @@ -424,7 +424,7 @@ public final class DisplayInfo implements Parcelable { for (int i = 0; i < supportedColorTransforms.length; i++) { supportedColorTransforms[i].writeToParcel(dest, flags); } - hdrCapabilities.writeToParcel(dest, flags); + dest.writeParcelable(hdrCapabilities, flags); dest.writeInt(logicalDensityDpi); dest.writeFloat(physicalXDpi); dest.writeFloat(physicalYDpi); diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index a0384f2601d3..edf05ba5fc33 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -389,6 +389,8 @@ public final class ViewRootImpl implements ViewParent, /** Set to true once doDie() has been called. */ private boolean mRemoved; + private boolean mNeedsHwRendererSetup; + /** * Consistency verifier for debugging purposes. */ @@ -915,6 +917,11 @@ public final class ViewRootImpl implements ViewParent, mWindowAttributes.surfaceInsets.set( oldInsetLeft, oldInsetTop, oldInsetRight, oldInsetBottom); mWindowAttributes.hasManualSurfaceInsets = oldHasManualSurfaceInsets; + } else if (mWindowAttributes.surfaceInsets.left != oldInsetLeft + || mWindowAttributes.surfaceInsets.top != oldInsetTop + || mWindowAttributes.surfaceInsets.right != oldInsetRight + || mWindowAttributes.surfaceInsets.bottom != oldInsetBottom) { + mNeedsHwRendererSetup = true; } applyKeepScreenOnFlag(mWindowAttributes); @@ -1959,9 +1966,11 @@ public final class ViewRootImpl implements ViewParent, if (hardwareRenderer != null && hardwareRenderer.isEnabled()) { if (hwInitialized || mWidth != hardwareRenderer.getWidth() - || mHeight != hardwareRenderer.getHeight()) { + || mHeight != hardwareRenderer.getHeight() + || mNeedsHwRendererSetup) { hardwareRenderer.setup(mWidth, mHeight, mAttachInfo, mWindowAttributes.surfaceInsets); + mNeedsHwRendererSetup = false; } } diff --git a/core/java/android/webkit/WebChromeClient.java b/core/java/android/webkit/WebChromeClient.java index 4737e9be3f99..2d3b6abbd08a 100644 --- a/core/java/android/webkit/WebChromeClient.java +++ b/core/java/android/webkit/WebChromeClient.java @@ -284,6 +284,13 @@ public class WebChromeClient { * currently set for that origin. The host application should invoke the * specified callback with the desired permission state. See * {@link GeolocationPermissions} for details. + * + * <p>Note that for applications targeting Android N and later SDKs + * (API level > {@link android.os.Build.VERSION_CODES#M}) + * this method is only called for requests originating from secure + * origins such as https. On non-secure origins geolocation requests + * are automatically denied.</p> + * * @param origin The origin of the web content attempting to use the * Geolocation API. * @param callback The callback to use to set the permission state for the diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java index ada77318f297..f54edf14bbe1 100644 --- a/core/java/android/webkit/WebView.java +++ b/core/java/android/webkit/WebView.java @@ -255,6 +255,16 @@ import java.util.Map; * is loading. * </p> * + * <h3>HTML5 Geolocation API support</h3> + * + * <p>For applications targeting Android N and later releases + * (API level > {@link android.os.Build.VERSION_CODES#M}) the geolocation api is only supported on + * secure origins such as https. For such applications requests to geolocation api on non-secure + * origins are automatically denied without invoking the corresponding + * {@link WebChromeClient#onGeolocationPermissionsShowPrompt(String, GeolocationPermissions.Callback)} + * method. + * </p> + * * <h3>Layout size</h3> * <p> * It is recommended to set the WebView layout height to a fixed value or to diff --git a/core/java/android/widget/AbsSpinner.java b/core/java/android/widget/AbsSpinner.java index 1cb7f2ac60b1..18db54ec5da0 100644 --- a/core/java/android/widget/AbsSpinner.java +++ b/core/java/android/widget/AbsSpinner.java @@ -356,10 +356,18 @@ public abstract class AbsSpinner extends AdapterView<SpinnerAdapter> { return mFirstPosition + i; } } - } + } return INVALID_POSITION; } - + + @Override + protected void dispatchRestoreInstanceState(SparseArray<Parcelable> container) { + super.dispatchRestoreInstanceState(container); + // Restores the selected position when Spinner gets restored, + // rather than wait until the next measure/layout pass to do it. + handleDataChanged(); + } + static class SavedState extends BaseSavedState { long selectedId; int position; diff --git a/core/java/android/widget/AdapterView.java b/core/java/android/widget/AdapterView.java index 6ed7ab8fde68..2cfefba10c57 100644 --- a/core/java/android/widget/AdapterView.java +++ b/core/java/android/widget/AdapterView.java @@ -815,7 +815,6 @@ public abstract class AdapterView<T extends Adapter> extends ViewGroup { @Override protected void dispatchRestoreInstanceState(SparseArray<Parcelable> container) { dispatchThawSelfOnly(container); - handleDataChanged(); } class AdapterDataSetObserver extends DataSetObserver { diff --git a/core/java/android/widget/TimePickerClockDelegate.java b/core/java/android/widget/TimePickerClockDelegate.java index b6200a14abca..c21f1dfe0ed1 100644 --- a/core/java/android/widget/TimePickerClockDelegate.java +++ b/core/java/android/widget/TimePickerClockDelegate.java @@ -38,6 +38,7 @@ import android.view.ViewGroup; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityNodeInfo; import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction; +import android.widget.RadialTimePickerView.OnValueSelectedListener; import com.android.internal.R; import com.android.internal.widget.NumericTextView; @@ -48,8 +49,7 @@ import java.util.Calendar; /** * A delegate implementing the radial clock-based TimePicker. */ -class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate implements - RadialTimePickerView.OnValueSelectedListener { +class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate { /** * Delay in milliseconds before valid but potentially incomplete, for * example "1" but not "12", keyboard edits are propagated from the @@ -88,8 +88,8 @@ class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate impl private boolean mIsEnabled = true; private boolean mAllowAutoAdvance; - private int mInitialHourOfDay; - private int mInitialMinute; + private int mCurrentHour; + private int mCurrentMinute; private boolean mIs24Hour; private boolean mIsAmPmAtStart; @@ -189,8 +189,7 @@ class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate impl mRadialTimePickerView = (RadialTimePickerView) mainView.findViewById(R.id.radial_picker); mRadialTimePickerView.applyAttributes(attrs, defStyleAttr, defStyleRes); - - setupListeners(); + mRadialTimePickerView.setOnValueSelectedListener(mOnValueSelectedListener); mAllowAutoAdvance = true; @@ -324,28 +323,24 @@ class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate impl } private void initialize(int hourOfDay, int minute, boolean is24HourView, int index) { - mInitialHourOfDay = hourOfDay; - mInitialMinute = minute; + mCurrentHour = hourOfDay; + mCurrentMinute = minute; mIs24Hour = is24HourView; updateUI(index); } - private void setupListeners() { - mRadialTimePickerView.setOnValueSelectedListener(this); - } - private void updateUI(int index) { updateHeaderAmPm(); - updateHeaderHour(mInitialHourOfDay, false); + updateHeaderHour(mCurrentHour, false); updateHeaderSeparator(); - updateHeaderMinute(mInitialMinute, false); + updateHeaderMinute(mCurrentMinute, false); updateRadialPicker(index); mDelegator.invalidate(); } private void updateRadialPicker(int index) { - mRadialTimePickerView.initialize(mInitialHourOfDay, mInitialMinute, mIs24Hour); + mRadialTimePickerView.initialize(mCurrentHour, mCurrentMinute, mIs24Hour); setCurrentItemShowing(index, false, true); } @@ -358,7 +353,7 @@ class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate impl final boolean isAmPmAtStart = dateTimePattern.startsWith("a"); setAmPmAtStart(isAmPmAtStart); - updateAmPmLabelStates(mInitialHourOfDay < 12 ? AM : PM); + updateAmPmLabelStates(mCurrentHour < 12 ? AM : PM); } } @@ -388,15 +383,25 @@ class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate impl */ @Override public void setHour(int hour) { - if (mInitialHourOfDay != hour) { - mInitialHourOfDay = hour; - updateHeaderHour(hour, true); - updateHeaderAmPm(); + setHourInternal(hour, false, true); + } + + private void setHourInternal(int hour, boolean isFromPicker, boolean announce) { + if (mCurrentHour == hour) { + return; + } + + mCurrentHour = hour; + updateHeaderHour(hour, announce); + updateHeaderAmPm(); + + if (!isFromPicker) { mRadialTimePickerView.setCurrentHour(hour); - mRadialTimePickerView.setAmOrPm(mInitialHourOfDay < 12 ? AM : PM); - mDelegator.invalidate(); - onTimeChanged(); + mRadialTimePickerView.setAmOrPm(hour < 12 ? AM : PM); } + + mDelegator.invalidate(); + onTimeChanged(); } /** @@ -421,13 +426,23 @@ class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate impl */ @Override public void setMinute(int minute) { - if (mInitialMinute != minute) { - mInitialMinute = minute; - updateHeaderMinute(minute, true); + setMinuteInternal(minute, false); + } + + private void setMinuteInternal(int minute, boolean isFromPicker) { + if (mCurrentMinute == minute) { + return; + } + + mCurrentMinute = minute; + updateHeaderMinute(minute, true); + + if (!isFromPicker) { mRadialTimePickerView.setCurrentMinute(minute); - mDelegator.invalidate(); - onTimeChanged(); } + + mDelegator.invalidate(); + onTimeChanged(); } /** @@ -448,7 +463,7 @@ class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate impl public void setIs24Hour(boolean is24Hour) { if (mIs24Hour != is24Hour) { mIs24Hour = is24Hour; - mInitialHourOfDay = getHour(); + mCurrentHour = getHour(); updateHourFormat(); updateUI(mRadialTimePickerView.getCurrentItemShowing()); @@ -563,34 +578,6 @@ class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate impl } /** - * Called by the picker for updating the header display. - */ - @Override - public void onValueSelected(int pickerIndex, int newValue, boolean autoAdvance) { - switch (pickerIndex) { - case HOUR_INDEX: - if (mAllowAutoAdvance && autoAdvance) { - updateHeaderHour(newValue, false); - setCurrentItemShowing(MINUTE_INDEX, true, false); - mDelegator.announceForAccessibility(newValue + ". " + mSelectMinutes); - } else { - updateHeaderHour(newValue, true); - } - break; - case MINUTE_INDEX: - updateHeaderMinute(newValue, true); - break; - case AMPM_INDEX: - updateAmPmLabelStates(newValue); - break; - } - - if (mOnTimeChangedListener != null) { - mOnTimeChangedListener.onTimeChanged(mDelegator, getHour(), getMinute()); - } - } - - /** * Converts hour-of-day (0-23) time into a localized hour number. * <p> * The localized value may be in the range (0-23), (1-24), (0-11), or @@ -702,11 +689,43 @@ class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate impl private void setAmOrPm(int amOrPm) { updateAmPmLabelStates(amOrPm); - if (mRadialTimePickerView.setAmOrPm(amOrPm) && mOnTimeChangedListener != null) { - mOnTimeChangedListener.onTimeChanged(mDelegator, getHour(), getMinute()); + if (mRadialTimePickerView.setAmOrPm(amOrPm)) { + mCurrentHour = getHour(); + + if (mOnTimeChangedListener != null) { + mOnTimeChangedListener.onTimeChanged(mDelegator, getHour(), getMinute()); + } } } + /** Listener for RadialTimePickerView interaction. */ + private final OnValueSelectedListener mOnValueSelectedListener = new OnValueSelectedListener() { + @Override + public void onValueSelected(int pickerIndex, int newValue, boolean autoAdvance) { + switch (pickerIndex) { + case HOUR_INDEX: + final boolean isTransition = mAllowAutoAdvance && autoAdvance; + setHourInternal(newValue, true, !isTransition); + if (isTransition) { + setCurrentItemShowing(MINUTE_INDEX, true, false); + mDelegator.announceForAccessibility(newValue + ". " + mSelectMinutes); + } + break; + case MINUTE_INDEX: + setMinuteInternal(newValue, true); + break; + case AMPM_INDEX: + updateAmPmLabelStates(newValue); + break; + } + + if (mOnTimeChangedListener != null) { + mOnTimeChangedListener.onTimeChanged(mDelegator, getHour(), getMinute()); + } + } + }; + + /** Listener for keyboard interaction. */ private final OnValueChangedListener mDigitEnteredListener = new OnValueChangedListener() { @Override public void onValueChanged(NumericTextView view, int value, diff --git a/core/java/com/android/internal/app/IBatteryStats.aidl b/core/java/com/android/internal/app/IBatteryStats.aidl index a2a135b59a73..42b89d53c9b6 100644 --- a/core/java/com/android/internal/app/IBatteryStats.aidl +++ b/core/java/com/android/internal/app/IBatteryStats.aidl @@ -122,7 +122,8 @@ interface IBatteryStats { void noteNetworkInterfaceType(String iface, int type); void noteNetworkStatsEnabled(); void noteDeviceIdleMode(int mode, String activeReason, int activeUid); - void setBatteryState(int status, int health, int plugType, int level, int temp, int volt); + void setBatteryState(int status, int health, int plugType, int level, int temp, int volt, + int chargeCount); long getAwakeTimeBattery(); long getAwakeTimePlugged(); diff --git a/core/java/com/android/internal/content/PackageMonitor.java b/core/java/com/android/internal/content/PackageMonitor.java index 7bd64e504c3d..c6b6a7fb999f 100644 --- a/core/java/com/android/internal/content/PackageMonitor.java +++ b/core/java/com/android/internal/content/PackageMonitor.java @@ -45,6 +45,7 @@ public abstract class PackageMonitor extends android.content.BroadcastReceiver { sPackageFilt.addAction(Intent.ACTION_PACKAGE_CHANGED); sPackageFilt.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART); sPackageFilt.addAction(Intent.ACTION_PACKAGE_RESTARTED); + sPackageFilt.addAction(Intent.ACTION_PACKAGE_DATA_CLEARED); sPackageFilt.addDataScheme("package"); sNonDataFilt.addAction(Intent.ACTION_UID_REMOVED); sNonDataFilt.addAction(Intent.ACTION_USER_STOPPED); @@ -275,6 +276,9 @@ public abstract class PackageMonitor extends android.content.BroadcastReceiver { public void onFinishPackageChanges() { } + public void onPackageDataCleared(String packageName, int uid) { + } + public int getChangingUserId() { return mChangeUserId; } @@ -365,6 +369,12 @@ public abstract class PackageMonitor extends android.content.BroadcastReceiver { } onPackageModified(pkg); } + } else if (Intent.ACTION_PACKAGE_DATA_CLEARED.equals(action)) { + String pkg = getPackageName(intent); + int uid = intent.getIntExtra(Intent.EXTRA_UID, 0); + if (pkg != null) { + onPackageDataCleared(pkg, uid); + } } else if (Intent.ACTION_QUERY_PACKAGE_RESTART.equals(action)) { mDisappearingPackages = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES); mChangeType = PACKAGE_TEMPORARY_CHANGE; diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java index e69ed35ff90d..654a4f19e0dc 100644 --- a/core/java/com/android/internal/os/BatteryStatsImpl.java +++ b/core/java/com/android/internal/os/BatteryStatsImpl.java @@ -108,7 +108,7 @@ public class BatteryStatsImpl extends BatteryStats { private static final int MAGIC = 0xBA757475; // 'BATSTATS' // Current on-disk Parcel version - private static final int VERSION = 142 + (USE_OLD_HISTORY ? 1000 : 0); + private static final int VERSION = 144 + (USE_OLD_HISTORY ? 1000 : 0); // Maximum number of items we will record in the history. private static final int MAX_HISTORY_ITEMS = 2000; @@ -150,6 +150,13 @@ public class BatteryStatsImpl extends BatteryStats { public void batterySendBroadcast(Intent intent); } + public interface PlatformIdleStateCallback { + public String getPlatformLowPowerStats(); + } + + private final PlatformIdleStateCallback mPlatformIdleStateCallback; + + final class MyHandler extends Handler { public MyHandler(Looper looper) { super(looper, null, true); @@ -569,6 +576,7 @@ public class BatteryStatsImpl extends BatteryStats { mDailyFile = null; mHandler = null; mExternalSync = null; + mPlatformIdleStateCallback = null; clearHistoryLocked(); } @@ -2081,27 +2089,111 @@ public class BatteryStatsImpl extends BatteryStats { tag.poolIdx = index; } + /* + The history delta format uses flags to denote further data in subsequent ints in the parcel. + + There is always the first token, which may contain the delta time, or an indicator of + the length of the time (int or long) following this token. + + First token: always present, + 31 23 15 7 0 + █M|L|K|J|I|H|G|F█E|D|C|B|A|T|T|T█T|T|T|T|T|T|T|T█T|T|T|T|T|T|T|T█ + + T: the delta time if it is <= 0x7fffd. Otherwise 0x7fffe indicates an int immediately + follows containing the time, and 0x7ffff indicates a long immediately follows with the + delta time. + A: battery level changed and an int follows with battery data. + B: state changed and an int follows with state change data. + C: state2 has changed and an int follows with state2 change data. + D: wakelock/wakereason has changed and an wakelock/wakereason struct follows. + E: event data has changed and an event struct follows. + F: battery charge in coulombs has changed and an int with the charge follows. + G: state flag denoting that the mobile radio was active. + H: state flag denoting that the wifi radio was active. + I: state flag denoting that a wifi scan occurred. + J: state flag denoting that a wifi full lock was held. + K: state flag denoting that the gps was on. + L: state flag denoting that a wakelock was held. + M: state flag denoting that the cpu was running. + + Time int/long: if T in the first token is 0x7ffff or 0x7fffe, then an int or long follows + with the time delta. + + Battery level int: if A in the first token is set, + 31 23 15 7 0 + █L|L|L|L|L|L|L|T█T|T|T|T|T|T|T|T█T|V|V|V|V|V|V|V█V|V|V|V|V|V|V|D█ + + D: indicates that extra history details follow. + V: the battery voltage. + T: the battery temperature. + L: the battery level (out of 100). + + State change int: if B in the first token is set, + 31 23 15 7 0 + █S|S|S|H|H|H|P|P█F|E|D|C|B| | |A█ | | | | | | | █ | | | | | | | █ + + A: wifi multicast was on. + B: battery was plugged in. + C: screen was on. + D: phone was scanning for signal. + E: audio was on. + F: a sensor was active. + + State2 change int: if C in the first token is set, + 31 23 15 7 0 + █M|L|K|J|I|H|H|G█F|E|D|C| | | | █ | | | | | | | █ |B|B|B|A|A|A|A█ + + A: 4 bits indicating the wifi supplicant state: {@link BatteryStats#WIFI_SUPPL_STATE_NAMES}. + B: 3 bits indicating the wifi signal strength: 0, 1, 2, 3, 4. + C: a bluetooth scan was active. + D: the camera was active. + E: bluetooth was on. + F: a phone call was active. + G: the device was charging. + H: 2 bits indicating the device-idle (doze) state: off, light, full + I: the flashlight was on. + J: wifi was on. + K: wifi was running. + L: video was playing. + M: power save mode was on. + + Wakelock/wakereason struct: if D in the first token is set, + TODO(adamlesinski): describe wakelock/wakereason struct. + + Event struct: if E in the first token is set, + TODO(adamlesinski): describe the event struct. + + History step details struct: if D in the battery level int is set, + TODO(adamlesinski): describe the history step details struct. + + Battery charge int: if F in the first token is set, an int representing the battery charge + in coulombs follows. + */ + // Part of initial delta int that specifies the time delta. static final int DELTA_TIME_MASK = 0x7ffff; static final int DELTA_TIME_LONG = 0x7ffff; // The delta is a following long static final int DELTA_TIME_INT = 0x7fffe; // The delta is a following int static final int DELTA_TIME_ABS = 0x7fffd; // Following is an entire abs update. // Flag in delta int: a new battery level int follows. - static final int DELTA_BATTERY_LEVEL_FLAG = 0x00080000; + static final int DELTA_BATTERY_LEVEL_FLAG = 0x00080000; // Flag in delta int: a new full state and battery status int follows. - static final int DELTA_STATE_FLAG = 0x00100000; + static final int DELTA_STATE_FLAG = 0x00100000; // Flag in delta int: a new full state2 int follows. - static final int DELTA_STATE2_FLAG = 0x00200000; + static final int DELTA_STATE2_FLAG = 0x00200000; // Flag in delta int: contains a wakelock or wakeReason tag. - static final int DELTA_WAKELOCK_FLAG = 0x00400000; + static final int DELTA_WAKELOCK_FLAG = 0x00400000; // Flag in delta int: contains an event description. - static final int DELTA_EVENT_FLAG = 0x00800000; + static final int DELTA_EVENT_FLAG = 0x00800000; + // Flag in delta int: contains a coulomb charge count. + static final int DELTA_BATTERY_CHARGE_COULOMBS_FLAG = 0x01000000; // These upper bits are the frequently changing state bits. - static final int DELTA_STATE_MASK = 0xff000000; + static final int DELTA_STATE_MASK = 0xfe000000; // These are the pieces of battery state that are packed in to the upper bits of // the state int that have been packed in to the first delta int. They must fit - // in DELTA_STATE_MASK. + // in STATE_BATTERY_MASK. + static final int STATE_BATTERY_MASK = 0xff000000; static final int STATE_BATTERY_STATUS_MASK = 0x00000007; static final int STATE_BATTERY_STATUS_SHIFT = 29; static final int STATE_BATTERY_HEALTH_MASK = 0x00000007; @@ -2157,6 +2249,12 @@ public class BatteryStatsImpl extends BatteryStats { if (cur.eventCode != HistoryItem.EVENT_NONE) { firstToken |= DELTA_EVENT_FLAG; } + + final boolean batteryChargeCoulombsChanged = cur.batteryChargeCoulombs + != last.batteryChargeCoulombs; + if (batteryChargeCoulombsChanged) { + firstToken |= DELTA_BATTERY_CHARGE_COULOMBS_FLAG; + } dest.writeInt(firstToken); if (DEBUG) Slog.i(TAG, "WRITE DELTA: firstToken=0x" + Integer.toHexString(firstToken) + " deltaTime=" + deltaTime); @@ -2220,6 +2318,12 @@ public class BatteryStatsImpl extends BatteryStats { + cur.eventTag.string); } if (computeStepDetails) { + if (mPlatformIdleStateCallback != null) { + mCurHistoryStepDetails.statPlatformIdleState = + mPlatformIdleStateCallback.getPlatformLowPowerStats(); + if (DEBUG) Slog.i(TAG, "WRITE PlatformIdleState:" + + mCurHistoryStepDetails.statPlatformIdleState); + } computeHistoryStepDetails(mCurHistoryStepDetails, mLastHistoryStepDetails); if (includeStepDetails != 0) { mCurHistoryStepDetails.writeToParcel(dest); @@ -2233,6 +2337,12 @@ public class BatteryStatsImpl extends BatteryStats { mLastHistoryStepDetails = null; } mLastHistoryStepLevel = cur.batteryLevel; + + if (batteryChargeCoulombsChanged) { + if (DEBUG) Slog.i(TAG, "WRITE DELTA: batteryChargeCoulombs=" + + cur.batteryChargeCoulombs); + dest.writeInt(cur.batteryChargeCoulombs); + } } private int buildBatteryLevelInt(HistoryItem h) { @@ -2259,7 +2369,7 @@ public class BatteryStatsImpl extends BatteryStats { return ((h.batteryStatus&STATE_BATTERY_STATUS_MASK)<<STATE_BATTERY_STATUS_SHIFT) | ((h.batteryHealth&STATE_BATTERY_HEALTH_MASK)<<STATE_BATTERY_HEALTH_SHIFT) | ((plugType&STATE_BATTERY_PLUG_MASK)<<STATE_BATTERY_PLUG_SHIFT) - | (h.states&(~DELTA_STATE_MASK)); + | (h.states&(~STATE_BATTERY_MASK)); } private void computeHistoryStepDetails(final HistoryStepDetails out, @@ -2398,7 +2508,7 @@ public class BatteryStatsImpl extends BatteryStats { if ((firstToken&DELTA_STATE_FLAG) != 0) { int stateInt = src.readInt(); - cur.states = (firstToken&DELTA_STATE_MASK) | (stateInt&(~DELTA_STATE_MASK)); + cur.states = (firstToken&DELTA_STATE_MASK) | (stateInt&(~STATE_BATTERY_MASK)); cur.batteryStatus = (byte)((stateInt>>STATE_BATTERY_STATUS_SHIFT) & STATE_BATTERY_STATUS_MASK); cur.batteryHealth = (byte)((stateInt>>STATE_BATTERY_HEALTH_SHIFT) @@ -2424,7 +2534,7 @@ public class BatteryStatsImpl extends BatteryStats { + " batteryPlugType=" + cur.batteryPlugType + " states=0x" + Integer.toHexString(cur.states)); } else { - cur.states = (firstToken&DELTA_STATE_MASK) | (cur.states&(~DELTA_STATE_MASK)); + cur.states = (firstToken&DELTA_STATE_MASK) | (cur.states&(~STATE_BATTERY_MASK)); } if ((firstToken&DELTA_STATE2_FLAG) != 0) { @@ -2479,6 +2589,10 @@ public class BatteryStatsImpl extends BatteryStats { } else { cur.stepDetails = null; } + + if ((firstToken&DELTA_BATTERY_CHARGE_COULOMBS_FLAG) != 0) { + cur.batteryChargeCoulombs = src.readInt(); + } } @Override @@ -5597,12 +5711,12 @@ public class BatteryStatsImpl extends BatteryStats { mWifiControllerActivity.reset(false); } - if (mBsi.mBluetoothActivity != null) { - mBsi.mBluetoothActivity.reset(false); + if (mBluetoothControllerActivity != null) { + mBluetoothControllerActivity.reset(false); } - if (mBsi.mModemActivity != null) { - mBsi.mModemActivity.reset(false); + if (mModemControllerActivity != null) { + mModemControllerActivity.reset(false); } mUserCpuTime.reset(false); @@ -7372,11 +7486,16 @@ public class BatteryStatsImpl extends BatteryStats { } public BatteryStatsImpl(File systemDir, Handler handler, ExternalStatsSync externalSync) { - this(new SystemClocks(), systemDir, handler, externalSync); + this(new SystemClocks(), systemDir, handler, externalSync, null); + } + + public BatteryStatsImpl(File systemDir, Handler handler, ExternalStatsSync externalSync, + PlatformIdleStateCallback cb) { + this(new SystemClocks(), systemDir, handler, externalSync, cb); } public BatteryStatsImpl(Clocks clocks, File systemDir, Handler handler, - ExternalStatsSync externalSync) { + ExternalStatsSync externalSync, PlatformIdleStateCallback cb) { init(clocks); if (systemDir != null) { @@ -7462,6 +7581,7 @@ public class BatteryStatsImpl extends BatteryStats { initDischarge(); clearHistoryLocked(); updateDailyDeadlineLocked(); + mPlatformIdleStateCallback = cb; } public BatteryStatsImpl(Parcel p) { @@ -7477,6 +7597,7 @@ public class BatteryStatsImpl extends BatteryStats { mExternalSync = null; clearHistoryLocked(); readFromParcel(p); + mPlatformIdleStateCallback = null; } public void setPowerProfile(PowerProfile profile) { @@ -9189,7 +9310,7 @@ public class BatteryStatsImpl extends BatteryStats { public static final int BATTERY_PLUGGED_NONE = 0; public void setBatteryStateLocked(int status, int health, int plugType, int level, - int temp, int volt) { + int temp, int volt, int chargeCount) { final boolean onBattery = plugType == BATTERY_PLUGGED_NONE; final long uptime = mClocks.uptimeMillis(); final long elapsedRealtime = mClocks.elapsedRealtime(); @@ -9233,6 +9354,7 @@ public class BatteryStatsImpl extends BatteryStats { if (mDischargePlugLevel < 0) { mDischargePlugLevel = level; } + if (onBattery != mOnBattery) { mHistoryCur.batteryLevel = (byte)level; mHistoryCur.batteryStatus = (byte)status; @@ -9240,6 +9362,7 @@ public class BatteryStatsImpl extends BatteryStats { mHistoryCur.batteryPlugType = (byte)plugType; mHistoryCur.batteryTemperature = (short)temp; mHistoryCur.batteryVoltage = (char)volt; + mHistoryCur.batteryChargeCoulombs = chargeCount; setOnBatteryLocked(elapsedRealtime, uptime, onBattery, oldStatus, level); } else { boolean changed = false; @@ -9273,6 +9396,11 @@ public class BatteryStatsImpl extends BatteryStats { mHistoryCur.batteryVoltage = (char)volt; changed = true; } + if (chargeCount >= (mHistoryCur.batteryChargeCoulombs+10) + || chargeCount <= (mHistoryCur.batteryChargeCoulombs-10)) { + mHistoryCur.batteryChargeCoulombs = chargeCount; + changed = true; + } long modeBits = (((long)mInitStepMode) << STEP_LEVEL_INITIAL_MODE_SHIFT) | (((long)mModStepMode) << STEP_LEVEL_MODIFIED_MODE_SHIFT) | (((long)(level&0xff)) << STEP_LEVEL_LEVEL_SHIFT); diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java index 645ffda2cff5..68a1378b9381 100644 --- a/core/java/com/android/internal/policy/DecorView.java +++ b/core/java/com/android/internal/policy/DecorView.java @@ -78,6 +78,7 @@ import android.widget.PopupWindow; import static android.app.ActivityManager.StackId; import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID; +import static android.app.ActivityManager.StackId.PINNED_STACK_ID; import static android.app.ActivityManager.StackId.INVALID_STACK_ID; import static android.content.res.Configuration.ORIENTATION_PORTRAIT; import static android.os.Build.VERSION_CODES.M; @@ -2060,8 +2061,11 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind if (StackId.hasWindowShadow(mStackId) && !isResizing()) { elevation = hasWindowFocus() ? DECOR_SHADOW_FOCUSED_HEIGHT_IN_DIP : DECOR_SHADOW_UNFOCUSED_HEIGHT_IN_DIP; + // Add a maximum shadow height value to the top level view. + // Note that pinned stack doesn't have focus + // so maximum shadow height adjustment isn't needed. // TODO(skuhne): Remove this if clause once b/22668382 got fixed. - if (!mAllowUpdateElevation) { + if (!mAllowUpdateElevation && mStackId != PINNED_STACK_ID) { elevation = DECOR_SHADOW_FOCUSED_HEIGHT_IN_DIP; } // Convert the DP elevation into physical pixels. diff --git a/core/java/com/android/internal/view/FloatingActionMode.java b/core/java/com/android/internal/view/FloatingActionMode.java index b44baa2b8422..ccdb024820c8 100644 --- a/core/java/com/android/internal/view/FloatingActionMode.java +++ b/core/java/com/android/internal/view/FloatingActionMode.java @@ -24,6 +24,8 @@ import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.view.ViewConfiguration; +import android.view.ViewGroup; +import android.view.ViewParent; import com.android.internal.R; import com.android.internal.util.Preconditions; @@ -165,7 +167,17 @@ public class FloatingActionMode extends ActionMode { checkToolbarInitialized(); mContentRectOnScreen.set(mContentRect); - mContentRectOnScreen.offset(mViewPositionOnScreen[0], mViewPositionOnScreen[1]); + + // Offset the content rect into screen coordinates, taking into account any transformations + // that may be applied to the originating view or its ancestors. + final ViewParent parent = mOriginatingView.getParent(); + if (parent instanceof ViewGroup) { + ((ViewGroup) parent).getChildVisibleRect( + mOriginatingView, mContentRectOnScreen, null /* offset */); + mContentRectOnScreen.offset(mRootViewPositionOnScreen[0], mRootViewPositionOnScreen[1]); + } else { + mContentRectOnScreen.offset(mViewPositionOnScreen[0], mViewPositionOnScreen[1]); + } if (isContentRectWithinBounds()) { mFloatingToolbarVisibilityHelper.setOutOfBounds(false); diff --git a/core/java/com/android/internal/widget/FloatingToolbar.java b/core/java/com/android/internal/widget/FloatingToolbar.java index 1848fe88dea9..bc12391a2f79 100644 --- a/core/java/com/android/internal/widget/FloatingToolbar.java +++ b/core/java/com/android/internal/widget/FloatingToolbar.java @@ -592,9 +592,11 @@ public final class FloatingToolbar { private void refreshCoordinatesAndOverflowDirection(Rect contentRectOnScreen) { refreshViewPort(); - int x = contentRectOnScreen.centerX() - mPopupWindow.getWidth() / 2; - // Update x so that the toolbar isn't rendered behind the nav bar in landscape. - x = Math.max(0, Math.min(x, mViewPortOnScreen.right - mPopupWindow.getWidth())); + // Initialize x ensuring that the toolbar isn't rendered behind the nav bar in + // landscape. + final int x = Math.min( + contentRectOnScreen.centerX() - mPopupWindow.getWidth() / 2, + mViewPortOnScreen.right - mPopupWindow.getWidth()); final int y; @@ -684,7 +686,8 @@ public final class FloatingToolbar { int rootViewTopOnWindow = mTmpCoords[1]; int windowLeftOnScreen = rootViewLeftOnScreen - rootViewLeftOnWindow; int windowTopOnScreen = rootViewTopOnScreen - rootViewTopOnWindow; - mCoordsOnWindow.set(x - windowLeftOnScreen, y - windowTopOnScreen); + mCoordsOnWindow.set( + Math.max(0, x - windowLeftOnScreen), Math.max(0, y - windowTopOnScreen)); } /** diff --git a/core/jni/android_hardware_Camera.cpp b/core/jni/android_hardware_Camera.cpp index 91f003d59c46..94592573e61a 100644 --- a/core/jni/android_hardware_Camera.cpp +++ b/core/jni/android_hardware_Camera.cpp @@ -77,6 +77,7 @@ public: virtual void postData(int32_t msgType, const sp<IMemory>& dataPtr, camera_frame_metadata_t *metadata); virtual void postDataTimestamp(nsecs_t timestamp, int32_t msgType, const sp<IMemory>& dataPtr); + virtual void postRecordingFrameHandleTimestamp(nsecs_t timestamp, native_handle_t* handle); void postMetadata(JNIEnv *env, int32_t msgType, camera_frame_metadata_t *metadata); void addCallbackBuffer(JNIEnv *env, jbyteArray cbb, int msgType); void setCallbackMode(JNIEnv *env, bool installed, bool manualMode); @@ -349,6 +350,11 @@ void JNICameraContext::postDataTimestamp(nsecs_t timestamp, int32_t msgType, con postData(msgType, dataPtr, NULL); } +void JNICameraContext::postRecordingFrameHandleTimestamp(nsecs_t, native_handle_t*) { + // This is not needed at app layer. This should not be called because JNICameraContext cannot + // start video recording. +} + void JNICameraContext::postMetadata(JNIEnv *env, int32_t msgType, camera_frame_metadata_t *metadata) { jobjectArray obj = NULL; diff --git a/core/jni/android_hardware_SensorManager.cpp b/core/jni/android_hardware_SensorManager.cpp index 9793cdb66f71..f4237d20f47a 100644 --- a/core/jni/android_hardware_SensorManager.cpp +++ b/core/jni/android_hardware_SensorManager.cpp @@ -13,28 +13,25 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - #define LOG_TAG "SensorManager" -#include <map> +#include "JNIHelp.h" +#include "android_os_MessageQueue.h" +#include "core_jni_helpers.h" +#include "jni.h" #include <ScopedUtfChars.h> #include <ScopedLocalRef.h> - +#include <android_runtime/AndroidRuntime.h> +#include <gui/Sensor.h> +#include <gui/SensorEventQueue.h> +#include <gui/SensorManager.h> #include <utils/Log.h> #include <utils/Looper.h> #include <utils/Vector.h> -#include <gui/Sensor.h> -#include <gui/SensorManager.h> -#include <gui/SensorEventQueue.h> - -#include "jni.h" -#include "JNIHelp.h" -#include "android_os_MessageQueue.h" -#include <android_runtime/AndroidRuntime.h> - -#include "core_jni_helpers.h" +#include <endian.h> // htobe64 +#include <map> namespace { diff --git a/core/jni/android_hardware_location_ContextHubService.cpp b/core/jni/android_hardware_location_ContextHubService.cpp index 5c961d96cf56..98d6b247429c 100644 --- a/core/jni/android_hardware_location_ContextHubService.cpp +++ b/core/jni/android_hardware_location_ContextHubService.cpp @@ -44,7 +44,6 @@ static constexpr int HEADER_FIELD_MSG_TYPE=0; static constexpr int HEADER_FIELD_HUB_HANDLE=2; static constexpr int HEADER_FIELD_APP_INSTANCE=3; - namespace android { namespace { @@ -164,9 +163,20 @@ static int get_hub_id_for_app_instance(int id) { return db.hubInfo.hubs[hubHandle].hub_id; } +static int get_app_instance_for_app_id(uint64_t app_id) { + auto end = db.appInstances.end(); + for (auto current = db.appInstances.begin(); current != end; ++current) { + if (current->second.appInfo.app_name.id == app_id) { + return current->first; + } + } + ALOGD("Cannot find app for app instance %" PRIu64 ".", app_id); + return -1; +} + static int set_dest_app(hub_message_t *msg, int id) { if (!db.appInstances.count(id)) { - ALOGD("%s: Cannod find app for app instance %d", __FUNCTION__, id); + ALOGD("%s: Cannot find app for app instance %d", __FUNCTION__, id); return -1; } @@ -301,7 +311,7 @@ static void initContextHubService() { } } -static int onMessageReceipt(int *header, int headerLen, char *msg, int msgLen) { +static int onMessageReceipt(uint32_t *header, size_t headerLen, char *msg, size_t msgLen) { JNIEnv *env; if ((db.jniInfo.vm)->AttachCurrentThread(&env, nullptr) != JNI_OK) { @@ -396,14 +406,9 @@ static bool sanity_check_cookie(void *cookie, uint32_t hub_id) { int context_hub_callback(uint32_t hubId, const struct hub_message_t *msg, void *cookie) { - int msgHeader[MSG_HEADER_SIZE]; - if (!msg) { return -1; } - - msgHeader[HEADER_FIELD_MSG_TYPE] = msg->message_type; - if (!sanity_check_cookie(cookie, hubId)) { ALOGW("Incorrect cookie %" PRId32 " for cookie %p! Bailing", hubId, cookie); @@ -411,17 +416,22 @@ int context_hub_callback(uint32_t hubId, return -1; } - msgHeader[HEADER_FIELD_HUB_HANDLE] = *(uint32_t*)cookie; + uint32_t messageType = msg->message_type; + uint32_t hubHandle = *(uint32_t*) cookie; - if (msgHeader[HEADER_FIELD_MSG_TYPE] < CONTEXT_HUB_TYPE_PRIVATE_MSG_BASE && - msgHeader[HEADER_FIELD_MSG_TYPE] != 0 ) { - handle_os_message(msgHeader[HEADER_FIELD_MSG_TYPE], - msgHeader[HEADER_FIELD_HUB_HANDLE], - (char *)msg->message, - msg->message_len); + if (messageType < CONTEXT_HUB_TYPE_PRIVATE_MSG_BASE) { + handle_os_message(messageType, hubHandle, (char*) msg->message, msg->message_len); } else { - onMessageReceipt(msgHeader, sizeof(msgHeader), - (char *)msg->message, msg->message_len); + int appHandle = get_app_instance_for_app_id(msg->app_name.id); + if (appHandle < 0) { + ALOGE("Filtering out message due to invalid App Instance."); + } else { + uint32_t msgHeader[MSG_HEADER_SIZE] = {}; + msgHeader[HEADER_FIELD_MSG_TYPE] = messageType; + msgHeader[HEADER_FIELD_HUB_HANDLE] = hubHandle; + msgHeader[HEADER_FIELD_APP_INSTANCE] = appHandle; + onMessageReceipt(msgHeader, MSG_HEADER_SIZE, (char*) msg->message, msg->message_len); + } } return 0; diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp index f870a891b094..e0bfecb14040 100644 --- a/core/jni/android_os_Debug.cpp +++ b/core/jni/android_os_Debug.cpp @@ -597,6 +597,13 @@ static jlong android_os_Debug_getPss(JNIEnv *env, jobject clazz) static long get_allocated_vmalloc_memory() { char line[1024]; + // Ignored tags that don't actually consume memory (ie remappings) + static const char* const ignored_tags[] = { + "ioremap", + "map_lowmem", + "vm_map_ram", + NULL + }; long size, vmalloc_allocated_size = 0; FILE* fp = fopen("/proc/vmallocinfo", "r"); if (fp == NULL) { @@ -606,12 +613,17 @@ static long get_allocated_vmalloc_memory() { if (fgets(line, 1024, fp) == NULL) { break; } - - if (!strstr(line, "ioremap") && !strstr(line, "map_lowmem")) { - // Ignore ioremap and map_lowmem regions, since they don't actually consume memory - if (sscanf(line, "%*x-%*x %ld", &size) == 1) { - vmalloc_allocated_size += size; + bool valid_line = true; + int i = 0; + while (ignored_tags[i]) { + if (strstr(line, ignored_tags[i]) != NULL) { + valid_line = false; + break; } + i++; + } + if (valid_line && (sscanf(line, "%*x-%*x %ld", &size) == 1)) { + vmalloc_allocated_size += size; } } fclose(fp); diff --git a/core/res/res/drawable-nodpi/default_wallpaper.png b/core/res/res/drawable-nodpi/default_wallpaper.png Binary files differindex e9c4d5c6c696..91ad252507e5 100644 --- a/core/res/res/drawable-nodpi/default_wallpaper.png +++ b/core/res/res/drawable-nodpi/default_wallpaper.png diff --git a/core/res/res/drawable-sw600dp-nodpi/default_wallpaper.png b/core/res/res/drawable-sw600dp-nodpi/default_wallpaper.png Binary files differindex 9f3efa533b9e..af8e2512385a 100644 --- a/core/res/res/drawable-sw600dp-nodpi/default_wallpaper.png +++ b/core/res/res/drawable-sw600dp-nodpi/default_wallpaper.png diff --git a/core/res/res/drawable-sw720dp-nodpi/default_wallpaper.png b/core/res/res/drawable-sw720dp-nodpi/default_wallpaper.png Binary files differindex 8199e706cf95..cb00d82a826f 100644 --- a/core/res/res/drawable-sw720dp-nodpi/default_wallpaper.png +++ b/core/res/res/drawable-sw720dp-nodpi/default_wallpaper.png diff --git a/core/res/res/layout-sw600dp/date_picker_dialog.xml b/core/res/res/layout-sw600dp/date_picker_dialog.xml index f18485f756ee..5e3ca14dd96c 100644 --- a/core/res/res/layout-sw600dp/date_picker_dialog.xml +++ b/core/res/res/layout-sw600dp/date_picker_dialog.xml @@ -21,4 +21,5 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:spinnersShown="true" - android:calendarViewShown="true" /> + android:calendarViewShown="true" + android:datePickerMode="@integer/date_picker_mode" /> diff --git a/core/res/res/layout/date_picker_dialog.xml b/core/res/res/layout/date_picker_dialog.xml index 64ac1b954e3e..8f36e95a15c6 100644 --- a/core/res/res/layout/date_picker_dialog.xml +++ b/core/res/res/layout/date_picker_dialog.xml @@ -21,4 +21,5 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:spinnersShown="true" - android:calendarViewShown="false" /> + android:calendarViewShown="false" + android:datePickerMode="@integer/date_picker_mode" /> diff --git a/core/res/res/layout/time_picker_dialog.xml b/core/res/res/layout/time_picker_dialog.xml index 30fe91093c46..d1f3902bd2d2 100644 --- a/core/res/res/layout/time_picker_dialog.xml +++ b/core/res/res/layout/time_picker_dialog.xml @@ -21,4 +21,5 @@ android:id="@+id/timePicker" android:layout_gravity="center_horizontal" android:layout_width="wrap_content" - android:layout_height="wrap_content" /> + android:layout_height="wrap_content" + android:timePickerMode="@integer/time_picker_mode" /> diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml index 3fd75f70c089..191afe5fd521 100644 --- a/core/res/res/values/attrs_manifest.xml +++ b/core/res/res/values/attrs_manifest.xml @@ -2291,4 +2291,14 @@ <attr name="minimalHeight" format="dimension" /> </declare-styleable> + <!-- <code>restrict-update</code> tag restricts system apps from being updated unless the + SHA-512 hash equals the specified value. + @hide --> + <declare-styleable name="AndroidManifestRestrictUpdate" parent="AndroidManifest"> + <!-- The SHA-512 hash of the only APK that can be used to update a package. + <p>NOTE: This is only applicable to system packages. + @hide --> + <attr name="hash" format="string" /> + </declare-styleable> + </resources> diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml index 11df8e5fa589..c91e09fd39d0 100644 --- a/core/res/res/values/public.xml +++ b/core/res/res/values/public.xml @@ -2715,6 +2715,7 @@ <public type="attr" name="contentInsetEndWithActions" /> <public type="attr" name="numberPickerStyle" /> <public type="attr" name="enableVrMode" /> + <public type="attr" name="hash" /> <public type="style" name="Theme.Material.Light.DialogWhenLarge.DarkActionBar" /> <public type="style" name="Widget.Material.SeekBar.Discrete" /> diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index d36da9fedc53..dffab2c9c59b 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -626,7 +626,7 @@ <!-- Title for the capability of an accessibility service to request touch exploration. --> <string name="capability_title_canRequestTouchExploration">Turn on Explore by Touch</string> <!-- Description for the capability of an accessibility service to request touch exploration. --> - <string name="capability_desc_canRequestTouchExploration">Touched items will be spoken aloud + <string name="capability_desc_canRequestTouchExploration">Tapped items will be spoken aloud and the screen can be explored using gestures.</string> <!-- Title for the capability of an accessibility service to request enhanced web accessibility. --> @@ -1708,7 +1708,7 @@ <string name="keyguard_password_enter_pin_prompt">New PIN code</string> <!-- Displayed as hint in passwordEntry EditText on PasswordUnlockScreen [CHAR LIMIT=30]--> - <string name="keyguard_password_entry_touch_hint"><font size="17">Touch to type password</font></string> + <string name="keyguard_password_entry_touch_hint"><font size="17">Tap to type password</font></string> <!-- Instructions telling the user to enter their text password to unlock the keyguard. Displayed in one line in a large font. --> @@ -2428,41 +2428,49 @@ <!-- Phrase describing a time duration using minutes that is as short as possible, preferrably one character. If the language needs a space in between the integer and the unit, please also integrate it in the string, but preferably it should not have a space in between.[CHAR LIMIT=6] --> <plurals name="duration_minutes_shortest"> + <item quantity="one"><xliff:g example="1" id="count">%d</xliff:g>m</item> <item quantity="other"><xliff:g example="2" id="count">%d</xliff:g>m</item> </plurals> <!-- Phrase describing a time duration using hours that is as short as possible, preferrably one character. If the language needs a space in between the integer and the unit, please also integrate it in the string, but preferably it should not have a space in between.[CHAR LIMIT=6] --> <plurals name="duration_hours_shortest"> + <item quantity="one"><xliff:g example="1" id="count">%d</xliff:g>h</item> <item quantity="other"><xliff:g example="2" id="count">%d</xliff:g>h</item> </plurals> <!-- Phrase describing a time duration using days that is as short as possible, preferrably one character. If the language needs a space in between the integer and the unit, please also integrate it in the string, but preferably it should not have a space in between.[CHAR LIMIT=6] --> <plurals name="duration_days_shortest"> + <item quantity="one"><xliff:g example="1" id="count">%d</xliff:g>d</item> <item quantity="other"><xliff:g example="2" id="count">%d</xliff:g>d</item> </plurals> <!-- Phrase describing a time duration using years that is as short as possible, preferrably one character. If the language needs a space in between the integer and the unit, please also integrate it in the string, but preferably it should not have a space in between.[CHAR LIMIT=6] --> <plurals name="duration_years_shortest"> + <item quantity="one"><xliff:g example="1" id="count">%d</xliff:g>y</item> <item quantity="other"><xliff:g example="2" id="count">%d</xliff:g>y</item> </plurals> <!-- Phrase describing a time duration using minutes that is as short as possible, preferrably one character. This version should be a future point in time. If the language needs a space in between the integer and the unit, please also integrate it in the string, but preferably it should not have a space in between.[CHAR LIMIT=14] --> <plurals name="duration_minutes_shortest_future"> + <item quantity="one">in <xliff:g example="1" id="count">%d</xliff:g>m</item> <item quantity="other">in <xliff:g example="2" id="count">%d</xliff:g>m</item> </plurals> <!-- Phrase describing a time duration using hours that is as short as possible, preferrably one character. This version should be a future point in time. If the language needs a space in between the integer and the unit, please also integrate it in the string, but preferably it should not have a space in between.[CHAR LIMIT=14] --> <plurals name="duration_hours_shortest_future"> + <item quantity="one">in <xliff:g example="1" id="count">%d</xliff:g>h</item> <item quantity="other">in <xliff:g example="2" id="count">%d</xliff:g>h</item> </plurals> <!-- Phrase describing a time duration using days that is as short as possible, preferrably one character. This version should be a future point in time. If the language needs a space in between the integer and the unit, please also integrate it in the string, but preferably it should not have a space in between.[CHAR LIMIT=14] --> <plurals name="duration_days_shortest_future"> + <item quantity="one">in <xliff:g example="1" id="count">%d</xliff:g>d</item> <item quantity="other">in <xliff:g example="2" id="count">%d</xliff:g>d</item> </plurals> <!-- Phrase describing a time duration using years that is as short as possible, preferrably one character. This version should be a future point in time. If the language needs a space in between the integer and the unit, please also integrate it in the string, but preferably it should not have a space in between.[CHAR LIMIT=14] --> <plurals name="duration_years_shortest_future"> + <item quantity="one">in <xliff:g example="1" id="count">%d</xliff:g>y</item> <item quantity="other">in <xliff:g example="2" id="count">%d</xliff:g>y</item> </plurals> @@ -2569,7 +2577,7 @@ is running</string> <!-- [CHAR LIMIT=NONE] Stub notification text for an app running a service that has provided a bad bad notification for itself. --> - <string name="app_running_notification_text">Touch for more information + <string name="app_running_notification_text">Tap for more information or to stop the app.</string> <!-- Preference framework strings. --> @@ -2753,7 +2761,7 @@ <string name="heavy_weight_notification"><xliff:g id="app">%1$s</xliff:g> running</string> <!-- Notification details to tell the user that a heavy-weight application is running. --> - <string name="heavy_weight_notification_detail">Touch to switch to app</string> + <string name="heavy_weight_notification_detail">Tap to switch to app</string> <!-- Title of dialog prompting whether user wants to switch between heavy-weight apps. --> <string name="heavy_weight_switcher_title">Switch apps?</string> @@ -2774,7 +2782,7 @@ <!-- Notification details to tell the user that a process has exceeded its memory limit. --> <string name="dump_heap_notification_detail">Heap dump has been collected; - touch to share</string> + tap to share</string> <!-- Title of dialog prompting the user to share a heap dump. --> <string name="dump_heap_title">Share heap dump?</string> @@ -2857,7 +2865,7 @@ <string name="wifi_no_internet">Wi-Fi has no Internet access</string> <!-- A notification is shown when the user connects to a Wi-Fi network and the system detects that that network has no Internet access. This is the notification's message. --> - <string name="wifi_no_internet_detailed">Touch for options</string> + <string name="wifi_no_internet_detailed">Tap for options</string> <!-- A notification is shown when a user's selected SSID is later disabled due to connectivity problems. This is the notification's title / ticker. --> <string name="wifi_watchdog_network_disabled">Couldn\'t connect to Wi-Fi</string> @@ -2879,7 +2887,7 @@ <string name="wifi_p2p_turnon_message">Start Wi-Fi Direct. This will turn off Wi-Fi client/hotspot.</string> <string name="wifi_p2p_failed_message">Couldn\'t start Wi-Fi Direct.</string> <string name="wifi_p2p_enabled_notification_title">Wi-Fi Direct is on</string> - <string name="wifi_p2p_enabled_notification_message">Touch for settings</string> + <string name="wifi_p2p_enabled_notification_message">Tap for settings</string> <string name="accept">Accept</string> <string name="decline">Decline</string> @@ -2987,12 +2995,12 @@ <!-- USB_PREFERENCES: Notification for when a USB accessory is attached. This is the title --> <string name="usb_accessory_notification_title">Connected to a USB accessory</string> <!-- See USB_PREFERENCES. This is the message. --> - <string name="usb_notification_message">Touch for more options.</string> + <string name="usb_notification_message">Tap for more options.</string> <!-- Title of notification shown when ADB is actively connected to the phone. --> <string name="adb_active_notification_title">USB debugging connected</string> <!-- Message of notification shown when ADB is actively connected to the phone. --> - <string name="adb_active_notification_message">Touch to disable USB debugging.</string> + <string name="adb_active_notification_message">Tap to disable USB debugging.</string> <!-- Title of notification shown to indicate that bug report is being collected. --> <string name="taking_remote_bugreport_notification_title">Taking bug report\u2026</string> @@ -3049,12 +3057,12 @@ <!-- Notification title when external media is unmountable (corrupt) [CHAR LIMIT=30] --> <string name="ext_media_unmountable_notification_title">Corrupted <xliff:g id="name" example="SD card">%s</xliff:g></string> <!-- Notification body when external media is unmountable (corrupt) [CHAR LIMIT=NONE] --> - <string name="ext_media_unmountable_notification_message"><xliff:g id="name" example="SD card">%s</xliff:g> is corrupt. Touch to fix.</string> + <string name="ext_media_unmountable_notification_message"><xliff:g id="name" example="SD card">%s</xliff:g> is corrupt. Tap to fix.</string> <!-- Notification title when external media is unsupported [CHAR LIMIT=30] --> <string name="ext_media_unsupported_notification_title">Unsupported <xliff:g id="name" example="SD card">%s</xliff:g></string> <!-- Notification body when external media is unsupported [CHAR LIMIT=NONE] --> - <string name="ext_media_unsupported_notification_message">This device doesn\u2019t support this <xliff:g id="name" example="SD card">%s</xliff:g>. Touch to set up in a supported format.</string> + <string name="ext_media_unsupported_notification_message">This device doesn\u2019t support this <xliff:g id="name" example="SD card">%s</xliff:g>. Tap to set up in a supported format.</string> <!-- Notification title when external media is unsafely removed [CHAR LIMIT=30] --> <string name="ext_media_badremoval_notification_title"><xliff:g id="name" example="SD card">%s</xliff:g> unexpectedly removed</string> @@ -3140,7 +3148,7 @@ <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> + <string name="tutorial_double_tap_to_zoom_message_short">Tap twice for zoom control</string> <!-- Shown in gadget hosts (e.g. the home screen) when there was an error inflating @@ -3227,9 +3235,9 @@ <!-- The title of the notification when VPN is active with an application name. --> <string name="vpn_title_long">VPN is activated by <xliff:g id="app" example="FooVPN client">%s</xliff:g></string> <!-- The text of the notification when VPN is active. --> - <string name="vpn_text">Touch to manage the network.</string> + <string name="vpn_text">Tap to manage the network.</string> <!-- The text of the notification when VPN is active with a session name. --> - <string name="vpn_text_long">Connected to <xliff:g id="session" example="office">%s</xliff:g>. Touch to manage the network.</string> + <string name="vpn_text_long">Connected to <xliff:g id="session" example="office">%s</xliff:g>. Tap to manage the network.</string> <!-- Notification title when connecting to lockdown VPN. --> <string name="vpn_lockdown_connecting">Always-on VPN connecting\u2026</string> @@ -3238,7 +3246,7 @@ <!-- Notification title when error connecting to lockdown VPN. --> <string name="vpn_lockdown_error">Always-on VPN error</string> <!-- Notification body that indicates user can touch to configure lockdown VPN connection. --> - <string name="vpn_lockdown_config">Touch to configure</string> + <string name="vpn_lockdown_config">Tap to configure</string> <!-- Localized strings for WebView --> <!-- Label for button in a WebView that will open a chooser to choose a file to upload --> @@ -3253,12 +3261,12 @@ <!-- Strings for car mode notification --> <!-- Shown when car mode is enabled --> <string name="car_mode_disable_notification_title">Car mode enabled</string> - <string name="car_mode_disable_notification_message">Touch to exit car mode.</string> + <string name="car_mode_disable_notification_message">Tap to exit car mode.</string> <!-- Strings for tethered notification --> <!-- Shown when the device is tethered --> <string name="tethered_notification_title">Tethering or hotspot active</string> - <string name="tethered_notification_message">Touch to set up.</string> + <string name="tethered_notification_message">Tap to set up.</string> <!-- Strings for possible PreferenceActivity Back/Next buttons --> <string name="back_button_label">Back</string> @@ -3344,7 +3352,7 @@ <!-- Description of the button to decrease the NumberPicker value. [CHAR LIMIT=NONE] --> <string name="number_picker_decrement_button">Decrease</string> <!-- Description of the tap and hold action to get into scroll mode in NumberPicker. [CHAR LIMIT=NONE] --> - <string name="number_picker_increment_scroll_mode"><xliff:g id="value" example="3">%s</xliff:g> touch and hold.</string> + <string name="number_picker_increment_scroll_mode"><xliff:g id="value" example="3">%s</xliff:g> touch & hold.</string> <!-- Description of the scrolling action in NumberPicker. [CHAR LIMIT=NONE] --> <string name="number_picker_increment_scroll_action">Slide up to increase and down to decrease.</string> @@ -3462,7 +3470,7 @@ <!-- Notification title when data usage has exceeded warning threshold. [CHAR LIMIT=32] --> <string name="data_usage_warning_title">Data usage warning</string> <!-- Notification body when data usage has exceeded warning threshold. [CHAR LIMIT=32] --> - <string name="data_usage_warning_body">Touch to view usage and settings.</string> + <string name="data_usage_warning_body">Tap to view usage and settings.</string> <!-- Notification title when 2G-3G data usage has exceeded limit threshold, and has been disabled. [CHAR LIMIT=32] --> <string name="data_usage_3g_limit_title">2G-3G data limit reached</string> @@ -3489,7 +3497,7 @@ <!-- Notification title when background data usage is limited. [CHAR LIMIT=32] --> <string name="data_usage_restricted_title">Background data restricted</string> <!-- Notification body when background data usage is limited. [CHAR LIMIT=32] --> - <string name="data_usage_restricted_body">Touch to remove restriction.</string> + <string name="data_usage_restricted_body">Tap to remove restriction.</string> <!-- SSL Certificate dialogs --> <!-- Title for an SSL Certificate dialog --> @@ -4072,9 +4080,9 @@ <string name="date_picker_day_typeface">sans-serif-medium</string> <!-- Notify use that they are in Lock-to-app --> - <string name="lock_to_app_toast">To unpin this screen, touch and hold Back.</string> + <string name="lock_to_app_toast">To unpin this screen, touch & hold Back.</string> <!-- Notify use that they are in Lock-to-app in accessibility mode --> - <string name="lock_to_app_toast_accessible">To unpin this screen, touch and hold Overview.</string> + <string name="lock_to_app_toast_accessible">To unpin this screen, touch & hold Overview.</string> <!-- Notify user that they are locked in lock-to-app mode --> <string name="lock_to_app_toast_locked">App is pinned: Unpinning isn\'t allowed on this device.</string> <!-- Starting lock-to-app indication. --> diff --git a/core/res/res/values/styles_material.xml b/core/res/res/values/styles_material.xml index 8a33406eeaa7..6752e3c900b0 100644 --- a/core/res/res/values/styles_material.xml +++ b/core/res/res/values/styles_material.xml @@ -660,7 +660,7 @@ please see styles_device_defaults.xml. </style> <style name="Widget.Material.TimePicker"> - <item name="timePickerMode">@integer/time_picker_mode</item> + <item name="timePickerMode">clock</item> <item name="legacyLayout">@layout/time_picker_legacy_material</item> <!-- Attributes for new-style TimePicker. --> <item name="internalLayout">@layout/time_picker_material</item> @@ -674,7 +674,7 @@ please see styles_device_defaults.xml. </style> <style name="Widget.Material.DatePicker"> - <item name="datePickerMode">@integer/date_picker_mode</item> + <item name="datePickerMode">calendar</item> <item name="legacyLayout">@layout/date_picker_legacy_holo</item> <item name="calendarViewShown">true</item> <!-- Attributes for new-style DatePicker. --> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 4d86a9252ced..14c17f37e35a 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -2530,6 +2530,9 @@ <java-symbol type="string" name="profile_encrypted_message" /> <java-symbol type="drawable" name="ic_user_secure" /> + <java-symbol type="string" name="android_upgrading_notification_title" /> + <java-symbol type="string" name="android_upgrading_notification_body" /> + <java-symbol type="string" name="usb_mtp_launch_notification_title" /> <java-symbol type="string" name="usb_mtp_launch_notification_description" /> diff --git a/core/res/res/values/themes_holo.xml b/core/res/res/values/themes_holo.xml index 34c89fc662ec..677051aa0dd5 100644 --- a/core/res/res/values/themes_holo.xml +++ b/core/res/res/values/themes_holo.xml @@ -466,6 +466,9 @@ please see themes_device_defaults.xml. <item name="editTextColor">?attr/textColorPrimary</item> <item name="editTextBackground">@drawable/edit_text_holo_light</item> + <item name="textEditSuggestionItemLayout">@layout/text_edit_suggestion_item</item> + <item name="textEditSuggestionContainerLayout">@layout/text_edit_suggestion_container</item> + <item name="textEditSuggestionHighlightStyle">@style/TextAppearance.Holo.SuggestionHighlight</item> <item name="candidatesTextStyleSpans">@string/candidates_style</item> diff --git a/data/etc/platform.xml b/data/etc/platform.xml index 8a7d39b65edd..a26850f5a3af 100644 --- a/data/etc/platform.xml +++ b/data/etc/platform.xml @@ -172,6 +172,10 @@ access while in power save mode, even if they aren't in the foreground. --> <allow-in-power-save-except-idle package="com.android.providers.downloads" /> + <!-- These are the standard packages that are white-listed to always have internet + access while in data mode, even if they aren't in the foreground. --> + <allow-in-data-usage-save package="com.android.providers.downloads" /> + <!-- These are the packages that are white-listed to be able to run as system user --> <system-user-whitelisted-app package="com.android.settings" /> diff --git a/data/sounds/alarms/material/ogg/Awaken_OG7_1ch_48k.ogg b/data/sounds/alarms/material/ogg/Awaken_OG7_1ch_48k.ogg Binary files differnew file mode 100755 index 000000000000..47b1d346a682 --- /dev/null +++ b/data/sounds/alarms/material/ogg/Awaken_OG7_1ch_48k.ogg diff --git a/data/sounds/alarms/material/ogg/Bounce_OG7_1ch_48k.ogg b/data/sounds/alarms/material/ogg/Bounce_OG7_1ch_48k.ogg Binary files differnew file mode 100755 index 000000000000..6af4d7066ca9 --- /dev/null +++ b/data/sounds/alarms/material/ogg/Bounce_OG7_1ch_48k.ogg diff --git a/data/sounds/alarms/material/ogg/Drip_OG7_1ch_48k.ogg b/data/sounds/alarms/material/ogg/Drip_OG7_1ch_48k.ogg Binary files differnew file mode 100755 index 000000000000..de3eec256c7b --- /dev/null +++ b/data/sounds/alarms/material/ogg/Drip_OG7_1ch_48k.ogg diff --git a/data/sounds/alarms/material/ogg/Gallop_OG7_1ch_48k.ogg b/data/sounds/alarms/material/ogg/Gallop_OG7_1ch_48k.ogg Binary files differnew file mode 100755 index 000000000000..98549b37d38b --- /dev/null +++ b/data/sounds/alarms/material/ogg/Gallop_OG7_1ch_48k.ogg diff --git a/data/sounds/alarms/material/ogg/Nudge_OG7_1ch_48k.ogg b/data/sounds/alarms/material/ogg/Nudge_OG7_1ch_48k.ogg Binary files differnew file mode 100755 index 000000000000..7a3d7ed474c6 --- /dev/null +++ b/data/sounds/alarms/material/ogg/Nudge_OG7_1ch_48k.ogg diff --git a/data/sounds/alarms/material/ogg/Orbit_OG7_1ch_48k.ogg b/data/sounds/alarms/material/ogg/Orbit_OG7_1ch_48k.ogg Binary files differnew file mode 100755 index 000000000000..52e3918326ed --- /dev/null +++ b/data/sounds/alarms/material/ogg/Orbit_OG7_1ch_48k.ogg diff --git a/data/sounds/alarms/material/ogg/Rise_OG7_1ch_48k.ogg b/data/sounds/alarms/material/ogg/Rise_OG7_1ch_48k.ogg Binary files differnew file mode 100755 index 000000000000..a2d00cc8ddbc --- /dev/null +++ b/data/sounds/alarms/material/ogg/Rise_OG7_1ch_48k.ogg diff --git a/data/sounds/alarms/material/ogg/Sway_OG7_1ch_48k.ogg b/data/sounds/alarms/material/ogg/Sway_OG7_1ch_48k.ogg Binary files differnew file mode 100755 index 000000000000..273728a6e417 --- /dev/null +++ b/data/sounds/alarms/material/ogg/Sway_OG7_1ch_48k.ogg diff --git a/data/sounds/alarms/material/ogg/Wag_OG7_1ch_48k.ogg b/data/sounds/alarms/material/ogg/Wag_OG7_1ch_48k.ogg Binary files differnew file mode 100755 index 000000000000..f61d5b9b75f3 --- /dev/null +++ b/data/sounds/alarms/material/ogg/Wag_OG7_1ch_48k.ogg diff --git a/docs/html/_redirects.yaml b/docs/html/_redirects.yaml index adb31b8d237d..545923f2e2b1 100644 --- a/docs/html/_redirects.yaml +++ b/docs/html/_redirects.yaml @@ -24,11 +24,11 @@ redirects: - from: /tools/debugging/debugging-projects-cmdline.html to: /tools/debugging/index.html - from: /sdk/compatibility-library.html - to: /tools/support-library/index.html + to: /go/libraries/support-library/index.html - from: /tools/extras/support-library.html - to: /tools/support-library/index.html + to: /go/libraries/support-library/index.html - from: /training/basics/fragments/support-lib.html - to: /tools/support-library/setup.html + to: /go/libraries/support-library/setup.html - from: /sdk/eclipse-adt.html to: /tools/sdk/eclipse-adt.html - from: /sdk/RELEASENOTES.html @@ -72,13 +72,11 @@ redirects: - from: /tools/publishing/app-signing-eclipse.html to: /tools/help/adt.html - from: /tools/help/uiautomator/.* - to: /tools/testing-support-library/index.html + to: /go/libraries/testing-support/library/ - from: /tools/testing/testing_ui.html to: /training/testing/ui-testing/index.html - from: /tools/testing/activity_test.html to: /training/testing/ui-testing/index.html -- from: /tools/data-binding/index.html - to: /tools/data-binding/guide.html - from: /tools/testing/what_to_test.html to: /distribute/essentials/quality/core.html - from: /tools/testing/testing_accessibility.html @@ -725,3 +723,14 @@ redirects: to: https://commondatastorage.googleapis.com/androiddevelopers/shareables/ - from: /downloads/ to: https://commondatastorage.googleapis.com/androiddevelopers/ + +# Redirects for the new go/libraries/ area + +- from: /tools/support-library + to: /go/libraries/support-library + +- from: /tools/data-binding/... + to: /go/libraries/data-binding + +- from: /tools/testing-support-library + to: /go/libraries/testing-support-library diff --git a/docs/html/about/_book.yaml b/docs/html/about/_book.yaml index 04150bdf1c20..fdbe53faeaae 100644 --- a/docs/html/about/_book.yaml +++ b/docs/html/about/_book.yaml @@ -16,13 +16,19 @@ toc: path: /about/versions/android-5.1.html - title: Android 5.0 APIs path: /about/versions/android-5.0.html - custom_link_attributes: - - es-lang="API de Android 5.0" - - ja-lang="Android 5.0 API" - - ko-lang="Android 5.0 API" - - ru-lang="API для Android 5.0" - - zh-cn-lang="Android 5.0 API" - - zh-tw-lang="Android 5.0 API" + path_attributes: + - name: es-lang + value: API de Android 5.0 + - name: ja-lang + value: Android 5.0 API + - name: ko-lang + value: Android 5.0 API + - name: ru-lang + value: API для Android 5.0 + - name: zh-cn-lang + value: Android 5.0 API + - name: zh-tw-lang + value: Android 5.0 API - title: Android 5.0 Changes path: /about/versions/android-5.0-changes.html diff --git a/docs/html/about/dashboards/index.jd b/docs/html/about/dashboards/index.jd index f0e1a3c4348a..f5e21e3e5427 100644 --- a/docs/html/about/dashboards/index.jd +++ b/docs/html/about/dashboards/index.jd @@ -1,5 +1,5 @@ page.title=Dashboards -page.metaDescription=page.metaDescription=An overview of device characteristics and platform versions that are active in the Android ecosystem. +page.metaDescription=An overview of device characteristics and platform versions that are active in the Android ecosystem. page.tags="android, dashboard, platforms, versions" meta.tags="ecosystem, versions, whatsnew, dashboards" page.image=https://chart.googleapis.com/chart?chl=GL%202.0%7CGL%203.0%7CGL%203.1&chf=bg%2Cs%2C00000000&chd=t%3A51.6%2C40.7%2C7.7&chco=c4df9b%2C6fad0c&cht=p&chs=400x250 diff --git a/docs/html/design/_book.yaml b/docs/html/design/_book.yaml index 45754757cfec..df5406f269dd 100644 --- a/docs/html/design/_book.yaml +++ b/docs/html/design/_book.yaml @@ -4,24 +4,35 @@ toc: section: - title: Design Principles path: /design/get-started/principles.html - custom_link_attributes: - - es-lang="Principios de diseño para Android" - - ja-lang="Android デザイン指針" - - ko-lang="Android 디자인 원칙" - - pt-br-lang="Princípios de projeto para Android" - - ru-lang="Принципы проектирования Android" - - zh-cn-lang="Android 设计原则" - - zh-tw-lang="Android 設計原則" + path_attributes: + - name: es-lang + value: Principios de diseño para Android + - name: ja-lang + value: Android デザイン指針 + - name: ko-lang + value: Android 디자인 원칙 + - name: pt-br-lang + value: Princípios de projeto para Android + - name: ru-lang + value: Принципы проектирования Android + - name: zh-cn-lang + value: Android 设计原则 + - name: zh-tw-lang + value: Android 設計原則 - title: New in Android path: /design/patterns/new.html - title: Material for Android path: /design/material/index.html - custom_link_attributes: - - ja-lang="マテリアル デザイン" - - ko-lang="머티어리얼 디자인" - - zh-cn-lang="材料设计" - - zh-tw-lang="材料設計" + path_attributes: + - name: ja-lang + value: マテリアル デザイン + - name: ko-lang + value: 머티어리얼 디자인 + - name: zh-cn-lang + value: 材料设计 + - name: zh-tw-lang + value: 材料設計 - title: Devices path: /design/devices.html @@ -64,24 +75,38 @@ toc: path: /design/style/devices-displays.html - title: Navigation path: /design/patterns/navigation.html - custom_link_attributes: - - es-lang="Navegación con los botones Back y Up" - - ja-lang="Back と Up を使用したナビゲーション" - - ko-lang="뒤로 및 위로 탐색 기능이 포함된 탐색" - - pt-br-lang="Navegação com Voltar e Para cima" - - ru-lang="Навигация с помощью кнопок \"Назад\" и \"Вверх\"" - - zh-cn-lang="使用返回和向上导航" - - zh-tw-lang="使用 [返回] 及 [上一層] 導覽" + path_attributes: + - name: es-lang + value: Navegación con los botones Back y Up + - name: ja-lang + value: Back と Up を使用したナビゲーション + - name: ko-lang + value: 뒤로 및 위로 탐색 기능이 포함된 탐색 + - name: pt-br-lang + value: Navegação com Voltar e Para cima + - name: ru-lang + value: Навигация с помощью кнопок "Назад" и "Вверх" + - name: zh-cn-lang + value: 使用返回和向上导航 + - name: zh-tw-lang + value: 使用 [返回] 及 [上一層] 導覽 - title: Notifications path: /design/patterns/notifications.html - custom_link_attributes: - - es-lang="Notificaciones" - - ja-lang="通知" - - ko-lang="알림" - - pt-br-lang="Notificações" - - ru-lang="Уведомления" - - zh-cn-lang="通知" - - zh-tw-lang="通知" + path_attributes: + - name: es-lang + value: Notificaciones + - name: ja-lang + value: 通知 + - name: ko-lang + value: 알림 + - name: pt-br-lang + value: Notificações + - name: ru-lang + value: Уведомления + - name: zh-cn-lang + value: 通知 + - name: zh-tw-lang + value: 通知 - title: Widgets path: /design/patterns/widgets.html - title: Swipe Views @@ -90,14 +115,21 @@ toc: path: /design/patterns/fullscreen.html - title: Confirming & Acknowledging path: /design/patterns/confirming-acknowledging.html - custom_link_attributes: - - es-lang="Confirmación y reconocimiento" - - ja-lang="確認と通知" - - ko-lang="확인 및 승인하기" - - pt-br-lang="Confirmação e reconhecimento" - - ru-lang="Подтверждение и уведомление" - - zh-cn-lang="确认和确知" - - zh-tw-lang="確認及確認完成" + path_attributes: + - name: es-lang + value: Confirmación y reconocimiento + - name: ja-lang + value: 確認と通知 + - name: ko-lang + value: 확인 및 승인하기 + - name: pt-br-lang + value: Confirmação e reconhecimento + - name: ru-lang + value: Подтверждение и уведомление + - name: zh-cn-lang + value: 确认和确知 + - name: zh-tw-lang + value: 確認及確認完成 - title: Pure Android path: /design/patterns/pure-android.html - title: Compatibility diff --git a/docs/html/distribute/essentials/_book.yaml b/docs/html/distribute/essentials/_book.yaml index e8b781163f5f..6a2c8f52ebf2 100644 --- a/docs/html/distribute/essentials/_book.yaml +++ b/docs/html/distribute/essentials/_book.yaml @@ -1,13 +1,15 @@ toc: - title: Core App Quality path: /distribute/essentials/quality/core.html - custom_link_attributes: - - zh-cn-lang="应用的核心质量" + path_attributes: + - name: zh-cn-lang + value: 应用的核心质量 - title: Tablet App Quality path: /distribute/essentials/quality/tablets.html - custom_link_attributes: - - zh-cn-lang="平板电脑应用的质量" + path_attributes: + - name: zh-cn-lang + value: 平板电脑应用的质量 - title: Wear App Quality path: /distribute/essentials/quality/wear.html @@ -20,31 +22,36 @@ toc: - title: Launch Checklist path: /distribute/tools/launch-checklist.html - custom_link_attributes: - - zh-cn-lang="发布检查清单" + path_attributes: + - name: zh-cn-lang + value: 发布检查清单 - title: Localization Checklist path: /distribute/tools/localization-checklist.html - custom_link_attributes: - - zh-cn-lang="本地化检查清单" + path_attributes: + - name: zh-cn-lang + value: 本地化检查清单 - title: Brand Guidelines path: /distribute/tools/promote/brand.html - custom_link_attributes: - - zh-cn-lang="品牌指南" + path_attributes: + - name: zh-cn-lang + value: 品牌指南 - title: Device Art Generator path: /distribute/tools/promote/device-art.html - title: Google Play Badges path: https://play.google.com/intl/en_us/badges/ - custom_link_attributes: - - zh-cn-lang="Google Play 徽章生成器" + path_attributes: + - name: zh-cn-lang + value: Google Play 徽章生成器 - title: Linking to Your Products path: /distribute/tools/promote/linking.html - custom_link_attributes: - - zh-cn-lang="链接到您的商品" + path_attributes: + - name: zh-cn-lang + value: 链接到您的商品 - title: Alternative Distribution path: /distribute/tools/open-distribution.html diff --git a/docs/html/distribute/googleplay/_book.yaml b/docs/html/distribute/googleplay/_book.yaml index 009d1c07a466..ede18f4eb281 100644 --- a/docs/html/distribute/googleplay/_book.yaml +++ b/docs/html/distribute/googleplay/_book.yaml @@ -1,75 +1,119 @@ toc: - title: The Google Play Opportunity path: /distribute/googleplay/about.html - custom_link_attributes: - - es-lang="La oportunidad de Google Play" - - ja-lang="Google Play の可能性" - - ko-lang="Google Play 활용 기회" - - pt-br-lang="A oportunidade do Google Play" - - ru-lang="Возможности Google Play" - - zh-cn-lang="Google Play 蕴藏的机会" - - zh-tw-lang="Google Play商機" + path_attributes: + - name: es-lang + value: La oportunidad de Google Play + - name: ja-lang + value: Google Play の可能性 + - name: ko-lang + value: Google Play 활용 기회 + - name: pt-br-lang + value: A oportunidade do Google Play + - name: ru-lang + value: Возможности Google Play + - name: zh-cn-lang + value: Google Play 蕴藏的机会 + - name: zh-tw-lang + value: Google Play商機 - title: Get Started with Publishing path: /distribute/googleplay/start.html - custom_link_attributes: - - es-lang="Comienza a publicar" - - ja-lang="アプリを公開する" - - ko-lang="게시 시작하기" - - pt-br-lang="Introdução à publicação" - - ru-lang="Первые шаги в публикациях" - - zh-cn-lang="开始发布" - - zh-tw-lang="開始發行" + path_attributes: + - name: es-lang + value: Comienza a publicar + - name: ja-lang + value: アプリを公開する + - name: ko-lang + value: 게시 시작하기 + - name: pt-br-lang + value: Introdução à publicação + - name: ru-lang + value: Первые шаги в публикациях + - name: zh-cn-lang + value: 开始发布 + - name: zh-tw-lang + value: 開始發行 - title: Developer Console path: /distribute/googleplay/developer-console.html - custom_link_attributes: - - es-lang="Consola para desarrolladores" - - ja-lang="デベロッパー コンソール" - - ko-lang="개발자 콘솔" - - pt-br-lang="Console do Desenvolvedor" - - ru-lang="Консоль разработчика" - - zh-cn-lang="开发者控制台" + path_attributes: + - name: es-lang + value: Consola para desarrolladores + - name: ja-lang + value: デベロッパー コンソール + - name: ko-lang + value: 개발자 콘솔 + - name: pt-br-lang + value: Console do Desenvolvedor + - name: ru-lang + value: Консоль разработчика + - name: zh-cn-lang + value: 开发者控制台 - title: Distribute to Android Wear path: /distribute/googleplay/wear.html - custom_link_attributes: - - es-lang="Distribución para Android Wear" - - ja-lang="Android Wear への配布" - - ko-lang="Android Wear에 배포" - - pt-br-lang="Distribuindo para Android Wear" - - ru-lang="Распространение приложений Android Wear" - - zh-cn-lang="分发到 Android Wear" - - zh-tw-lang="散佈至 Android Wear" + path_attributes: + - name: es-lang + value: Distribución para Android Wear + - name: ja-lang + value: Android Wear への配布 + - name: ko-lang + value: Android Wear에 배포 + - name: pt-br-lang + value: Distribuindo para Android Wear + - name: ru-lang + value: Распространение приложений Android Wear + - name: zh-cn-lang + value: 分发到 Android Wear + - name: zh-tw-lang + value: 散佈至 Android Wear - title: Distribute to Android TV path: /distribute/googleplay/tv.html - custom_link_attributes: - - es-lang="Distribución para Android TV" - - ja-lang="Android TV への配布" - - ko-lang="Android TV에 배포" - - pt-br-lang="Distribuindo para Android TV" - - ru-lang="Распространение приложений в Android TV" - - zh-cn-lang="分发到 Android TV" - - zh-tw-lang="散佈至 Android 電視" + path_attributes: + - name: es-lang + value: Distribución para Android TV + - name: ja-lang + value: Android TV への配布 + - name: ko-lang + value: Android TV에 배포 + - name: pt-br-lang + value: Distribuindo para Android TV + - name: ru-lang + value: Распространение приложений в Android TV + - name: zh-cn-lang + value: 分发到 Android TV + - name: zh-tw-lang + value: 散佈至 Android 電視 - title: Distribute to Android Auto path: /distribute/googleplay/auto.html - custom_link_attributes: - - es-lang="Distribución para Android Auto" - - ja-lang="Android Auto への配布" - - ko-lang="Android Auto에 배포" - - pt-br-lang="Distribuindo para o Android Auto" - - ru-lang="Распространение приложений для Android Auto" - - zh-cn-lang="分发到 Android Auto" - - zh-tw-lang="散佈至 Android Auto" + path_attributes: + - name: es-lang + value: Distribución para Android Auto + - name: ja-lang + value: Android Auto への配布 + - name: ko-lang + value: Android Auto에 배포 + - name: pt-br-lang + value: Distribuindo para o Android Auto + - name: ru-lang + value: Распространение приложений для Android Auto + - name: zh-cn-lang + value: 分发到 Android Auto + - name: zh-tw-lang + value: 散佈至 Android Auto - title: Designed for Families path: /distribute/googleplay/families/about.html - custom_link_attributes: - - es-lang="Diseñado para la familia" - - ru-lang="Для всей семьи" - - zh-cn-lang="为家庭设计" + path_attributes: + - name: es-lang + value: Diseñado para la familia + - name: ru-lang + value: Для всей семьи + - name: zh-cn-lang + value: 为家庭设计 - title: Google Play for Work path: /distribute/googleplay/work/about.html @@ -90,11 +134,18 @@ toc: - title: Find Success on Google Play path: /distribute/googleplay/guide.html - custom_link_attributes: - - es-lang="Cómo tener éxito en Google Play" - - ja-lang="Google Play で成功を手にする" - - ko-lang="Google Play에서 성공 모색" - - pt-br-lang="Obtendo sucesso no Google Play" - - ru-lang="Найдите свой путь к успеху в Google Play" - - zh-cn-lang="在 Google Play 上取得成功" - - zh-tw-lang="在 Google Play 上尋找成功" + path_attributes: + - name: es-lang + value: Cómo tener éxito en Google Play + - name: ja-lang + value: Google Play で成功を手にする + - name: ko-lang + value: Google Play에서 성공 모색 + - name: pt-br-lang + value: Obtendo sucesso no Google Play + - name: ru-lang + value: Найдите свой путь к успеху в Google Play + - name: zh-cn-lang + value: 在 Google Play 上取得成功 + - name: zh-tw-lang + value: 在 Google Play 上尋找成功 diff --git a/docs/html/distribute/tools/_book.yaml b/docs/html/distribute/tools/_book.yaml index 57e03ba09cd2..4064c34d158b 100644 --- a/docs/html/distribute/tools/_book.yaml +++ b/docs/html/distribute/tools/_book.yaml @@ -1,31 +1,36 @@ toc: - title: Launch Checklist path: /distribute/tools/launch-checklist.html - custom_link_attributes: - - zh-cn-lang="发布检查清单" + path_attributes: + - name: zh-cn-lang + value: 发布检查清单 - title: Localization Checklist path: /distribute/tools/localization-checklist.html - custom_link_attributes: - - zh-cn-lang="本地化检查清单" + path_attributes: + - name: zh-cn-lang + value: 本地化检查清单 - title: Device Art Generator path: /distribute/tools/promote/device-art.html - title: Google Play Badges path: /distribute/tools/promote/badges.html - custom_link_attributes: - - zh-cn-lang="Google Play 徽章生成器" + path_attributes: + - name: zh-cn-lang + value: Google Play 徽章生成器 - title: Linking to Your Products path: /distribute/tools/promote/linking.html - custom_link_attributes: - - zh-cn-lang="链接到您的商品" + path_attributes: + - name: zh-cn-lang + value: 链接到您的商品 - title: Brand Guidelines path: /distribute/tools/promote/brand.html - custom_link_attributes: - - zh-cn-lang="品牌指南" + path_attributes: + - name: zh-cn-lang + value: 品牌指南 - title: Alternative Distribution path: /distribute/tools/open-distribution.html diff --git a/docs/html/go/libraries/_book.yaml b/docs/html/go/libraries/_book.yaml new file mode 100644 index 000000000000..209dae5980b5 --- /dev/null +++ b/docs/html/go/libraries/_book.yaml @@ -0,0 +1,17 @@ +toc: +- title: Support Library + path: /tools/support-library/index.html + section: + - title: Features + path: /tools/support-library/features.html + - title: Setup + path: /tools/support-library/setup.html + +- title: Data Binding Library + path: /tools/data-binding/guide.html + +- title: Testing Support Library + path: /tools/testing-support-library/index.html + section: + - title: API Reference + path: /reference/android/support/test/package-summary.html diff --git a/docs/html/tools/data-binding/guide.jd b/docs/html/go/libraries/data-binding/index.jd index 8bbd833e1589..ca8784ebfcfb 100644 --- a/docs/html/tools/data-binding/guide.jd +++ b/docs/html/go/libraries/data-binding/index.jd @@ -1,4 +1,5 @@ -page.title=Data Binding Guide +page.title=Data Binding Library +page.metaDescription=The Data Binding Library enables you to write declarative layouts. page.tags="databinding", "layouts" @jd:body diff --git a/docs/html/go/libraries/index.jd b/docs/html/go/libraries/index.jd new file mode 100644 index 000000000000..2831d15e2eab --- /dev/null +++ b/docs/html/go/libraries/index.jd @@ -0,0 +1,14 @@ +page.title=Android Libraries + +@jd:body + +<p>This section describes several useful Android libraries that are not +included with the Android Framework.</p> + +<div class="dynamic-grid"> + <div class="resource-widget resource-flow-layout landing col-12" + data-query="collection:go/libraries" + data-cardSizes="6x6" + data-maxResults="6"> + </div> +</div> diff --git a/docs/html/tools/support-library/features.jd b/docs/html/go/libraries/support-library/features.jd index a5f343e89eb9..089357a5465e 100755 --- a/docs/html/tools/support-library/features.jd +++ b/docs/html/go/libraries/support-library/features.jd @@ -34,11 +34,11 @@ page.title=Support Library Features <h2>See also</h2> <ol> - <li><a href="{@docRoot}tools/support-library/index.html#revisions"> + <li><a href="{@docRoot}go/libraries/support-library/index.html#revisions"> Support Library Revisions</a></li> - <li><a href="{@docRoot}tools/support-library/setup.html"> + <li><a href="{@docRoot}go/libraries/support-library/setup.html"> Support Library Setup</a></li> - <li><a href="{@docRoot}tools/testing-support-library/index.html"> + <li><a href="{@docRoot}go/libraries/testing-support-library/index.html"> Testing Support Library</a></li> </ol> diff --git a/docs/html/tools/support-library/index.jd b/docs/html/go/libraries/support-library/index.jd index 3afd7ac1651f..61f0bc2a30d6 100644 --- a/docs/html/tools/support-library/index.jd +++ b/docs/html/go/libraries/support-library/index.jd @@ -1,4 +1,5 @@ page.title=Support Library +page.metaDescription=The Android Support Library offers backward-compatible versions of a number of features that are not built into the framework. @jd:body @@ -8,7 +9,11 @@ page.title=Support Library <h2>In this document</h2> <ol> <li><a href="#overview">Overview</a></li> - <li><a href="#revisions">Revisions</a></li> + <li><a href="#backward">Backward Compatibility</a></li> + <li><a href="#layout-patterns">Support for General Layout Patterns</a></li> + <li><a href="#form-factors">Support for Different Form Factors</a></li> + <li><a href="#utils">General Utilities</a></li> + <li><a href="#revisions">Support Library Revision History</a></li> </ol> <h2>See also</h2> @@ -22,39 +27,161 @@ page.title=Support Library </div> </div> -<p>The Android Support Library package is a set of code libraries that provide - backward-compatible versions of Android framework APIs as well as features that are only available - through the library APIs. Each Support Library is backward-compatible to a specific Android API - level. This design means that your applications can use the libraries' features and still be - compatible with devices running Android 1.6 (API level 4) and up.</p> +<p> + The Android Support Library offers a number of features that are not built + into the framework. These libraries offer backward-compatible versions of + new features, provide useful UI elements that are not included in the + framework, and provide a range of utilities that apps can draw on. +</p> -<p>This guide provides information about what features are enabled by the Support Libraries, - how to use them in your development environment and information about library releases.</p> +<h2 id="overview">Overview</h2> +<p> + In many cases, a feature may be valuable to many app developers, but not + appropriate to include in the Android framework itself. For example, an app + might only need a feature for specialized use cases, such as to smooth the + transition between different versions of the Android system. +</p> -<h2 id="overview">Overview</h2> +<p> + To address these situations, the Android SDK includes several libraries + collectively called the <em>Android Support Library</em>. App developers + can include any of these libraries if they want to incorporate the + library functionality into their apps. +</p> + +<p> + Support libraries provide a range of different features: +</p> + +<ul> + <li> + <a href="#backward">Backward-compatible</a> versions of framework + components. + </li> + + <li>UI elements to implement the recommended Android <a href= + "#layout-patterns">layout patterns</a>. + </li> + + <li>Support for different <a href="#form-factors">form factors</a>. + </li> + + <li>Miscellaneous <a href="#utils">utility</a> functions. + </li> +</ul> + +<h2 id="backward">Backward Compatibility</h2> + +<div class="figure" style="width:300px"> + <img src="{@docRoot}images/tools/support-library/appbar-kitkat.png" + srcset="{@docRoot}images/tools/support-library/appbar-kitkat.png 1x, + {@docRoot}images/tools/support-library/appbar-kitkat_2x.png 2x" + alt="" width="300"> + <p class="img-caption"> + <strong>Figure 1.</strong> Because this app uses support library UI + elements its interface incorporates material design principles, even though + it is running on Android 4.4, which does not include native support for + material design. + </p> +</div> -<p>Including the Support Libraries in your Android project is considered a best practice for - application developers, depending on the range of platform versions your app is targeting - and the APIs that it uses. Using the features the libraries provide can help you improve the look - of your application, increase performance and broaden the reach of your application to more users. - If you use the Android - <a href="{@docRoot}tools/projects/templates.html">code template</a> tools, you will notice that - all the Android application templates include one or more of the Support Libraries by default.</p> - -<p>The Support Libraries each target a base Android API level and each provides a different set - of features. In order to effectively use the libraries, it is important to consider what features - you want to support and understand what features are supported by each library at what Android - API level. To get started, review the - <a href="{@docRoot}tools/support-library/features.html">Support Library Features</a> guide. - After that, go to the - <a href="{@docRoot}tools/support-library/setup.html">Support Library Setup</a> topic to - learn how to incorporate the Support Libraries into your application. For more details - about Support Library APIs, see the {@link android.support.v4.app android.support} - packages in the API reference.</p> - - -<h2 id="revisions">Revisions</h2> +<p> + Support libraries allow apps running on older versions of the Android + platform to support features made available on newer versions of the + platform. For example, an app running on a version of Android lower than 5.0 + (API level 21) that relies on framework classes cannot display + material-design elements, as that version of the Android framework doesn't + support material design. However, if the app incorporates the Support + Library's <a href="{@docRoot}tools/support-library/features.html">appcompat + library</a>, the app has access to many of the features available in API + level 21, including support for material design. As a result, your app can + deliver a more consistent experience across a broader range of platform + versions. +</p> + + +<p> + In some cases, the support library version of a class depends as much as + possible on the functionality that the framework provides. In these cases, + if an app calls one of the support class's methods, the support library's + behavior depends on what version of Android the app is running on. If the + framework provides the necessary functionality, the support library calls on + the framework to perform the task. If the app is running on an earlier + version of Android, and the framework doesn't expose the needed + functionality, the support library may try to provide the functionality + itself, or may act as a no-op. In either case, the app generally doesn't + need to check what version of Android it's running on; instead, the app + can rely on the support library to do those checks and choose appropriate + behavior. Generally, classes whose names end in + <code>…Compat</code> (like {@link android.support.v4.app.ActivityCompat}) + behave this way. +</p> + +<p> + In other cases, the support library class provides a complete, standalone + version of a framework class that does not rely on the availability of + any framework APIs. These + methods provide consistent behavior across all supported platforms. +</p> + +<p> + In either case, the app does not need to check the system version at run + time. The app can rely on the support library class to do the appropriate + system checks, and modify its behavior as necessary. +</p> + +<h2 id="layout-patterns">Support for General Layout Patterns</h2> + +<p> + Support libraries provide user interface elements not offered by + the Android framework. For example, the Android Support Library offers additional + layout classes, like {@link android.support.v4.widget.DrawerLayout}. These + classes follow recommended Android design practices; for example, the Design + Library follows the principles of material design in a way that works across + many versions of Android. +</p> + +<p> + By using these support library classes, you can avoid having to reinvent the + wheel; if your app has a particular user interface requirement, you can draw + on existing code, which provides a user interface that users will already be + familiar with. These elements also help you build an app that looks and feels + like a part of the Android ecosystem. For example, many apps need to display + arbitrarily long lists of elements, and need to be able to quickly and + efficiently reuse those elements as the list changes; this might be a list of + emails, contacts, music albums, and so on. Those apps can use the support + library {@link android.support.v7.widget.RecyclerView} widget to display the + list. This saves the app developer from having to develop the list from + scratch, and also ensures that the user will see a list that looks and + behaves like lists in other apps. +</p> + +<h2 id="form-factors">Support for Different Form Factors</h2> + +<p> + The Android SDK provides libraries for a number of different form factors, + such as TV and wearables. An app can depend on the appropriate support + library to provide functionality across a wide range of platform versions, + and can provide content on external screens, speakers, and other destination + devices. +</p> + +<h2 id="utils">General Utilities</h2> + +<p> + The Android Support Library provides backward-compatible utility functions. + Apps can use these utility functions to provide an appropriate user + experience across a wide range of Android system versions. For example, + support library permission methods behave appropriately depending on what + platform version your app is running on. If the platform supports the + runtime permissions model, these methods request the appropriate permission + from the user; on platform versions that do not support the runtime + permissions model, the methods check whether the appropriate permission was + granted at install time. +</p> + +<h2 id="revisions">Support Library Revision History</h2> <p>This section provides details about the Support Library package releases.</p> diff --git a/docs/html/tools/support-library/setup.jd b/docs/html/go/libraries/support-library/setup.jd index 8fbcee156d32..8fbcee156d32 100755 --- a/docs/html/tools/support-library/setup.jd +++ b/docs/html/go/libraries/support-library/setup.jd diff --git a/docs/html/tools/testing-support-library/index.jd b/docs/html/go/libraries/testing-support-library/index.jd index 35a3c7db8f2c..f69a35b7cf25 100644 --- a/docs/html/tools/testing-support-library/index.jd +++ b/docs/html/go/libraries/testing-support-library/index.jd @@ -1,4 +1,5 @@ page.title=Testing Support Library +page.metaDescription=The Android Testing Support Library provides an extensive framework for testing Android apps. page.image=images/tools/studio-test-module.png @jd:body diff --git a/docs/html/google/_book.yaml b/docs/html/google/_book.yaml index 01efa4f9fe93..92357e9730c6 100644 --- a/docs/html/google/_book.yaml +++ b/docs/html/google/_book.yaml @@ -1,17 +1,20 @@ toc: - title: Google Play In-app Billing path: /google/play/billing/index.html - custom_link_attributes: - - zh-cn-lang="应用内结算" + path_attributes: + - name: zh-cn-lang + value: 应用内结算 section: - title: Overview path: /google/play/billing/billing_overview.html - custom_link_attributes: - - zh-cn-lang="应用内结算概述" + path_attributes: + - name: zh-cn-lang + value: 应用内结算概述 - title: Version 3 API path: /google/play/billing/api.html - custom_link_attributes: - - zh-cn-lang="应用内结算 API" + path_attributes: + - name: zh-cn-lang + value: 应用内结算 API section: - title: Implementing the API path: /google/play/billing/billing_integrate.html @@ -23,29 +26,39 @@ toc: path: /google/play/billing/billing_promotions.html - title: Security and Design path: /google/play/billing/billing_best_practices.html - custom_link_attributes: - - zh-cn-lang="安全性和设计" + path_attributes: + - name: zh-cn-lang + value: 安全性和设计 - title: Testing In-app Billing path: /google/play/billing/billing_testing.html - custom_link_attributes: - - zh-cn-lang="测试应用内结算" + path_attributes: + - name: zh-cn-lang + value: 测试应用内结算 - title: Administering In-app Billing path: /google/play/billing/billing_admin.html - custom_link_attributes: - - zh-cn-lang="管理应用内结算" + path_attributes: + - name: zh-cn-lang + value: 管理应用内结算 - title: Version Notes path: /google/play/billing/versions.html - title: Filters on Google Play path: /google/play/filters.html - custom_link_attributes: - - es-lang="Filtros en Google Play" - - ja-lang="Google Play 上のフィルタ" - - ko-lang="Google Play 필터" - - pt-br-lang="Filtros no Google Play" - - ru-lang="Фильтры в Google Play" - - zh-cn-lang="Google Play 上的筛选器" - - zh-tw-lang="Google Play 上的篩選器" + path_attributes: + - name: es-lang + value: Filtros en Google Play + - name: ja-lang + value: Google Play 上のフィルタ + - name: ko-lang + value: Google Play 필터 + - name: pt-br-lang + value: Filtros no Google Play + - name: ru-lang + value: Фильтры в Google Play + - name: zh-cn-lang + value: Google Play 上的筛选器 + - name: zh-tw-lang + value: Google Play 上的篩選器 - title: Google Play Developer API path: /google/play/developer-api.html diff --git a/docs/html/guide/_book.yaml b/docs/html/guide/_book.yaml index 5017376366b1..4163f0f494b6 100644 --- a/docs/html/guide/_book.yaml +++ b/docs/html/guide/_book.yaml @@ -365,6 +365,12 @@ toc: - title: App Install Location path: /guide/topics/data/install-location.html + +- title: Libraries + path: /go/libraries/index.html + section: + - include: /go/libraries/_book.yaml + - title: Administration path: /guide/topics/admin/index.html section: @@ -387,14 +393,21 @@ toc: - title: Best Practices path: /guide/practices/index.html - custom_link_attributes: - - de-lang="Bewährte Verfahren" - - es-lang="Prácticas recomendadas" - - fr-lang="Meilleures pratiques" - - it-lang="Best practice" - - ja-lang="ベスト プラクティス" - - zh-cn-lang="最佳实践" - - zh-tw-lang="最佳實務" + path_attributes: + - name: de-lang + value: Bewährte Verfahren + - name: es-lang + value: Prácticas recomendadas + - name: fr-lang + value: Meilleures pratiques + - name: it-lang + value: Best practice + - name: ja-lang + value: ベスト プラクティス + - name: zh-cn-lang + value: 最佳实践 + - name: zh-tw-lang + value: 最佳實務 section: - title: Supporting Multiple Screens path: /guide/practices/screens_support.html diff --git a/docs/html/guide/guide_toc.cs b/docs/html/guide/guide_toc.cs index 549a1b6b02e4..9257a76e93f2 100644 --- a/docs/html/guide/guide_toc.cs +++ b/docs/html/guide/guide_toc.cs @@ -121,7 +121,7 @@ <li><a href="<?cs var:toroot ?>guide/topics/resources/overview.html"> <span class="en">Overview</span> </a></li> - <li><a href="<?cs var:toroot ?>guide/topics/resources/providing-resources.html"> + <li><a href="<?cs var:toroot ?>guide/topics/resources/providing-resources.html"> <span class="en">Providing Resources</span> </a></li> <li><a href="<?cs var:toroot ?>guide/topics/resources/accessing-resources.html"> @@ -129,10 +129,13 @@ </a></li> <li><a href="<?cs var:toroot ?>guide/topics/resources/runtime-changes.html"> <span class="en">Handling Runtime Changes</span> - </a></li> + </a></li> <li><a href="<?cs var:toroot ?>guide/topics/resources/localization.html"> <span class="en">Localization</span> </a></li> + <li><a href="<?cs var:toroot ?>guide/topics/resources/complex-xml-resources.html"> + <span class="en">Complex XML Resources</span> + </a></li> <li class="nav-section"> <div class="nav-section-header"><a href="<?cs var:toroot ?>guide/topics/resources/available-resources.html"> <span class="en">Resource Types</span> diff --git a/docs/html/guide/topics/resources/complex-xml-resources.jd b/docs/html/guide/topics/resources/complex-xml-resources.jd new file mode 100644 index 000000000000..66dcb58347ab --- /dev/null +++ b/docs/html/guide/topics/resources/complex-xml-resources.jd @@ -0,0 +1,117 @@ +page.title=Inline Complex XML Resources +parent.title=Application Resources +parent.link=index.html +@jd:body + +<p>Certain resource types are a composition of multiple complex resources represented by XML files. +One example is an animated vector drawable, which is a drawable resource encapsulating a vector +drawable and an animation. This requires the use of at least three XML files.</p> + +<dl> + +<dt><code>res/drawable/avd.xml</code></dt> +<dd> +<pre class="stx"> +<?xml version="1.0" encoding="utf-8"?> +<animated-vector xmlns:android="http://schemas.android.com/apk/res/android" + android:drawable="@drawable/vectordrawable" > + <target + android:name="rotationGroup" + android:animation="@anim/rotation" /> +</animated-vector> +</pre> +</dd> + +<dt><code>res/drawable/vectordrawable.xml</code></dt> +<dd> +<pre class="stx"> +<?xml version="1.0" encoding="utf-8"?> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:height="64dp" + android:width="64dp" + android:viewportHeight="600" + android:viewportWidth="600" > +
<group + android:name="rotationGroup" + android:pivotX="300.0" + android:pivotY="300.0" + android:rotation="45.0" > + <path + android:fillColor="#000000" + android:pathData="M300,70 l 0,-70 70,70 0,0 -70,70z" /> +
</group> +</vector> +</pre> +</dd> + +<dt><code>res/anim/rotation.xml</code></dt> +<dd> +<pre class="stx"> +<?xml version="1.0" encoding="utf-8"?> +<objectAnimator xmlns:android="http://schemas.android.com/apk/android" + android:duration="6000" + android:propertyName="rotation" + android:valueFrom="0" +
android:valueTo="360" /> +</pre> +</dd> + +</dl> + +<p>There are a lot of files here just to make a single animated vector drawable! +If the vector drawable and animations are re-used elsewhere, this is the best way to implement an +animated vector drawable. If they’re only ever used for this animated vector drawable, then there is +a more compact way to implement them.</p> + +<p>Using AAPT’s inline resource format, you can define all three resources in the same XML file. +Since we’re making an animated vector drawable, we put the file under <code>res/drawable/</code>.</p> + +<dl> + +<dt><code>res/drawable/avd.xml</code></dt> +<dd> +<pre class="stx"> +<?xml version="1.0" encoding="utf-8"?> +<animated-vector xmlns:android="http://schemas.android.com/apk/res/android" + <strong>xmlns:aapt="http://schemas.android.com/aapt"</strong> > + + <strong><aapt:attr name="android:drawable" ></strong> + <vector + android:height="64dp" + android:width="64dp" + android:viewportHeight="600" + android:viewportWidth="600" > +
<group + android:name="rotationGroup" + android:pivotX="300.0" + android:pivotY="300.0" + android:rotation="45.0" > + <path + android:fillColor="#000000" + android:pathData="M300,70 l 0,-70 70,70 0,0 -70,70z" /> +
</group> + </vector> + <strong><aapt:attr /></strong> + + <target + android:name="rotationGroup" /> + <strong><aapt:attr name="android:animation" ></strong> + <objectAnimator + android:duration="6000" + android:propertyName="rotation" + android:valueFrom="0" +
android:valueTo="360" /> + <strong><aapt:attr></strong> +</animated-vector> +</pre> +</dd> + +</dl> + +<p>The XML tag <code><aapt:attr ></code> tells AAPT that the tag’s child shall be treated as a +resource and extracted into its own resource file. The value in the attribute name specifies where +to use the inline resource within the parent tag.</p> + +<p>AAPT will generate resource files and names for all of the inline resources. +Applications built using this inline format are compatible with all versions of Android.</p> + diff --git a/docs/html/guide/topics/resources/overview.jd b/docs/html/guide/topics/resources/overview.jd index c3bd0bfb0581..c496797016af 100644 --- a/docs/html/guide/topics/resources/overview.jd +++ b/docs/html/guide/topics/resources/overview.jd @@ -9,6 +9,7 @@ page.title=Resources Overview <li><a href="accessing-resources.html">Accessing Resources</a></li> <li><a href="runtime-changes.html">Handling Runtime Changes</a></li> <li><a href="localization.html">Localization</a></li> + <li><a href="complex-xml-resources.html">Complex XML Resources</a></li> </ol> <h2>Reference</h2> @@ -79,6 +80,9 @@ code or from other XML resources.</dd> <dd>A bottom-up guide to localizing your application using alternative resources. While this is just one specific use of alternative resources, it is very important in order to reach more users.</dd> + <dt><strong><a href="complex-xml-resources.html">Complex XML Resources</a></strong></dt> + <dd>An XML format for building complex resources like animated vector drawables in a single +XML file.</dd> <dt><strong><a href="available-resources.html">Resource Types</a></strong></dt> <dd>A reference of various resource types you can provide, describing their XML elements, attributes, and syntax. For example, this reference shows you how to create a resource for diff --git a/docs/html/images/tools/am-androidmon2.png b/docs/html/images/tools/am-androidmon2.png Binary files differnew file mode 100644 index 000000000000..a4a757193b09 --- /dev/null +++ b/docs/html/images/tools/am-androidmon2.png diff --git a/docs/html/images/tools/am-cpumon2.png b/docs/html/images/tools/am-cpumon2.png Binary files differnew file mode 100644 index 000000000000..6ac6e0287a09 --- /dev/null +++ b/docs/html/images/tools/am-cpumon2.png diff --git a/docs/html/images/tools/am-dumpalloc2.png b/docs/html/images/tools/am-dumpalloc2.png Binary files differnew file mode 100644 index 000000000000..d936aa82996f --- /dev/null +++ b/docs/html/images/tools/am-dumpalloc2.png diff --git a/docs/html/images/tools/am-gc2.png b/docs/html/images/tools/am-gc2.png Binary files differnew file mode 100644 index 000000000000..a5e8b6e986d4 --- /dev/null +++ b/docs/html/images/tools/am-gc2.png diff --git a/docs/html/images/tools/am-gpumon2.png b/docs/html/images/tools/am-gpumon2.png Binary files differnew file mode 100644 index 000000000000..5cf51d9320b2 --- /dev/null +++ b/docs/html/images/tools/am-gpumon2.png diff --git a/docs/html/images/tools/am-icaptures.png b/docs/html/images/tools/am-icaptures.png Binary files differnew file mode 100644 index 000000000000..cf288d61bb9e --- /dev/null +++ b/docs/html/images/tools/am-icaptures.png diff --git a/docs/html/images/tools/am-igraphic.png b/docs/html/images/tools/am-igraphic.png Binary files differnew file mode 100644 index 000000000000..a3c43fab5a31 --- /dev/null +++ b/docs/html/images/tools/am-igraphic.png diff --git a/docs/html/images/tools/am-imaximize.png b/docs/html/images/tools/am-imaximize.png Binary files differnew file mode 100644 index 000000000000..38a6c6c6a6a6 --- /dev/null +++ b/docs/html/images/tools/am-imaximize.png diff --git a/docs/html/images/tools/am-imaxlogcat.png b/docs/html/images/tools/am-imaxlogcat.png Binary files differnew file mode 100644 index 000000000000..4522bd4c6d31 --- /dev/null +++ b/docs/html/images/tools/am-imaxlogcat.png diff --git a/docs/html/images/tools/am-iminimize.png b/docs/html/images/tools/am-iminimize.png Binary files differnew file mode 100644 index 000000000000..d0bbe4c0c451 --- /dev/null +++ b/docs/html/images/tools/am-iminimize.png diff --git a/docs/html/images/tools/am-imovedown.png b/docs/html/images/tools/am-imovedown.png Binary files differnew file mode 100644 index 000000000000..802c13b1ebdf --- /dev/null +++ b/docs/html/images/tools/am-imovedown.png diff --git a/docs/html/images/tools/am-imoveup.png b/docs/html/images/tools/am-imoveup.png Binary files differnew file mode 100644 index 000000000000..95f6ef319f6f --- /dev/null +++ b/docs/html/images/tools/am-imoveup.png diff --git a/docs/html/images/tools/am-logcatmon2.png b/docs/html/images/tools/am-logcatmon2.png Binary files differnew file mode 100644 index 000000000000..563593568f17 --- /dev/null +++ b/docs/html/images/tools/am-logcatmon2.png diff --git a/docs/html/images/tools/am-networkmon.png b/docs/html/images/tools/am-networkmon.png Binary files differindex 95b3a5b57f12..f55f853e51af 100644 --- a/docs/html/images/tools/am-networkmon.png +++ b/docs/html/images/tools/am-networkmon.png diff --git a/docs/html/images/tools/am-networkmon2.png b/docs/html/images/tools/am-networkmon2.png Binary files differnew file mode 100644 index 000000000000..d05fcd47cda8 --- /dev/null +++ b/docs/html/images/tools/am-networkmon2.png diff --git a/docs/html/images/tools/am-screenshot.png b/docs/html/images/tools/am-screenshot.png Binary files differnew file mode 100644 index 000000000000..5c2761742360 --- /dev/null +++ b/docs/html/images/tools/am-screenshot.png diff --git a/docs/html/images/tools/am-sysinfo.png b/docs/html/images/tools/am-sysinfo.png Binary files differnew file mode 100644 index 000000000000..9b5cd17207fb --- /dev/null +++ b/docs/html/images/tools/am-sysinfo.png diff --git a/docs/html/images/tools/am-video.png b/docs/html/images/tools/am-video.png Binary files differnew file mode 100644 index 000000000000..9787ef87c670 --- /dev/null +++ b/docs/html/images/tools/am-video.png diff --git a/docs/html/images/tools/support-library/appbar-kitkat.png b/docs/html/images/tools/support-library/appbar-kitkat.png Binary files differnew file mode 100644 index 000000000000..c89fd87d667f --- /dev/null +++ b/docs/html/images/tools/support-library/appbar-kitkat.png diff --git a/docs/html/images/tools/support-library/appbar-kitkat_2x.png b/docs/html/images/tools/support-library/appbar-kitkat_2x.png Binary files differnew file mode 100644 index 000000000000..c9718e6f548e --- /dev/null +++ b/docs/html/images/tools/support-library/appbar-kitkat_2x.png diff --git a/docs/html/jd_collections.js b/docs/html/jd_collections.js index 48c923d2f49f..f155521134ae 100644 --- a/docs/html/jd_collections.js +++ b/docs/html/jd_collections.js @@ -1,3 +1,11 @@ +/* + * THIS FILE IS DEPRECATED. + * + * Please add and edit resource collections in jd_extras_<lang>.js + * where lang matches the language code appropriate for the resource. + * Last sync'd with jd_extras_<lang>.js on 29 Apr 2016. + * + */ var RESOURCE_COLLECTIONS = { "index/carousel": { "title": "", @@ -1699,6 +1707,37 @@ var RESOURCE_COLLECTIONS = { "https://www.youtube.com/watch?v=j3QC6hcpy90" ] }, +"tools/help/log": { + "title": "", + "resources": [ + "tools/help/am-logcat.html" + ] + }, +"tools/help/monitor": { + "title": "", + "resources": [ + "tools/help/am-memory.html", + "tools/help/am-cpu.html", + "tools/help/am-gpu.html", + "tools/help/am-network.html" + ] + }, + "tools/help/data": { + "title": "", + "resources": [ + "tools/help/am-hprof.html", + "tools/help/am-allocation.html", + "tools/help/am-methodtrace.html", + "tools/help/am-sysinfo.html" + ] + }, + "tools/help/shot": { + "title": "", + "resources": [ + "tools/help/am-screenshot.html", + "tools/help/am-video.html" + ] + }, "tools/performance/rendering": { "title": "", "resources": [ diff --git a/docs/html/jd_extras.js b/docs/html/jd_extras.js index 9663fd0b2f46..d1768830129a 100644 --- a/docs/html/jd_extras.js +++ b/docs/html/jd_extras.js @@ -1,18 +1,11 @@ -/* Metadata represendations of resources that are outside of the autogenerated - local resource lists, or that override local resource representations. - - Resources listed here are referenced from sitemap sections and collections, - matched by url string if there is no resource existing in ALL_RESOURCES. - - Currently, these articles can override only the generated resources - in DISTRIBUTE_RESOURCES. A representation defined here will not be applied - when a collection or section specifies a url that's not in DISTRIBUTE_RESOURCEs. - Also - So if a section url refers to a static doc that's - not in a distribute section, you need to create an item for - it in this file. Fix is to compare across - ALL_RESOURCES_BY_URL. */ - +/* + * THIS FILE IS DEPRECATED. + * + * Please add and edit resource collections in jd_extras_<lang>.js + * where lang matches the language code appropriate for the resource. + * Last sync'd with jd_extras_<lang>.js on 29 Apr 2016. + * + */ DISTRIBUTE_RESOURCES = DISTRIBUTE_RESOURCES.concat([ /* TODO Remove standard resources from here, such as below */ diff --git a/docs/html/jd_extras_en.js b/docs/html/jd_extras_en.js index ad66f7973555..f11da20a71c0 100644 --- a/docs/html/jd_extras_en.js +++ b/docs/html/jd_extras_en.js @@ -1,22 +1,55 @@ -/* Metadata represendations of resources that are outside of the autogenerated - local resource lists, or that override local resource representations. +/* Metadata extensions for the specified language + as well as resource collection definitions. - Resources listed here are referenced from queries and collections, - matched by url string. + 'Extras' defined in this file are metadata represendations of + resources that are outside the autogenerated local resource lists, + or representations that override the default representations. + (Overriding the default is not recommended) - Currently, these articles can override only the generated resources - in DISTRIBUTE_RESOURCES. A representation defined here will not be applied - when a collection or section specifies a url that's not in DISTRIBUTE_RESOURCEs. - Also - So if a section url refers to a static doc that's - not in a distribute section, you need to create an item for - it in this file. Fix is to compare across - ALL_RESOURCES_BY_URL. */ + 'Collections' are a predefined set of resources that pages can + display by referencing the collection name in a data query. Urls + listed in a collection must map exactly to urls in local metadata + resources (either default or extras). + + 'Carousel overrides' are extras that override a default resource + for the purpose of customizing the text and display in carousels/heros. + Urls referenced must map exactly to urls in local metadata + resources (either default or extras). + + 'Static search results' are metadata objects that are returned in + the search results page when the user enters the object's keyword. + + The extras, collections, carousel overrides, and static search results + listed here are referenced from dynamic content queries, matched by + url string. + */ METADATA['en'].extras = METADATA['en'].extras.concat([ /* TODO Remove standard resources from here, such as below */ { + "title":"Writing More Code by Writing Less Code with Android Studio Live Templates", + "category":"", + "summary":"Unless you’re getting paid by the keystroke, no one wants to write repetitive boilerplate code.", + "url":"https://medium.com/google-developers/writing-more-code-by-writing-less-code-with-android-studio-live-templates-244f648d17c7#.hczcm02du", + "group":"", + "keywords": [], + "tags": ['studio'], + "image":"https://cdn-images-1.medium.com/max/800/1*JkrYXGs1AxZAbK0sCLrJAQ.gif", + "type":"medium" + }, + { + "title":"How Often Should You Update Android Studio?", + "category":"", + "summary":"One of the beauties of Android Studio is how quickly is evolves and improves.", + "url":"https://medium.com/google-developers/how-often-should-you-update-android-studio-db25785c488e#.8blbql35x", + "group":"", + "keywords": [], + "tags": ['studio'], + "image":"https://cdn-images-1.medium.com/max/2000/1*chMiA9mGa_FBUOoesHHk3Q.png", + "type":"medium" + }, + { "title":"Measure your app’s user acquisition channels", "category":"google", "summary":"Get details on how to use the Developer Console User Acquisitions reports to discover where your users come from.", @@ -642,7 +675,18 @@ METADATA['en'].extras = METADATA['en'].extras.concat([ "keywords": [], "tags": [], "image":"distribute/images/gp-edu-apps-image.jpg", - "type":"distribute" + "type":"google" + }, + { + "title":"Keeping Your App Responsive", + "category":"performance", + "summary":"This document describes how the Android system determines whether an application is not responding and provides guidelines for ensuring that your application stays responsive.", + "url":"training/articles/perf-anr.html", + "group":"", + "keywords": [], + "tags": [], + "image":"", + "type":"google" }, { "title":"Google Play Game Services", @@ -770,7 +814,7 @@ METADATA['en'].extras = METADATA['en'].extras.concat([ "type": "distribute", "category": "google play" }, -{ + { "lang": "en", "group": "", "tags": [], @@ -1266,7 +1310,7 @@ METADATA['en'].extras = METADATA['en'].extras.concat([ "lang": "en", "group": "", "tags": [ - "#gcm", + "gcm", ], "url": "https://developer.chrome.com/apps/cloudMessagingV2", "timestamp": 1383243492000, @@ -1277,12 +1321,11 @@ METADATA['en'].extras = METADATA['en'].extras.concat([ "type": "distribute", "category": "google" }, - { "lang": "en", "group": "", "tags": [ - "#sdkupdates" + "" ], "url": "https://android-developers.blogspot.com/2013/07/making-beautiful-android-app-icons.html", "timestamp": 1194884220000, @@ -1293,11 +1336,11 @@ METADATA['en'].extras = METADATA['en'].extras.concat([ "type": "blog", "category": "" }, - { + { "lang": "en", "group": "", "tags": [ - "#sdkupdates" + "" ], "url": "https://android-developers.blogspot.com/2012/12/localize-your-promotional-graphics-on.html", "timestamp": 1194884220000, @@ -1308,11 +1351,11 @@ METADATA['en'].extras = METADATA['en'].extras.concat([ "type": "blog", "category": "" }, - { + { "lang": "en", "group": "", "tags": [ - "#sdkupdates" + "" ], "url": "https://android-developers.blogspot.com/2013/10/making-your-app-content-more-accessible.html", "timestamp": 1194884220000, @@ -2901,6 +2944,18 @@ METADATA['en'].extras = METADATA['en'].extras.concat([ "type":"distribute" }, { + "title":"What’s New in Android N Developer Preview", + "category":"preview", + "summary":"Learn all about the new features in the Android N Preview.", + "url":"https://www.youtube.com/watch?v=CsulIu3UaUM", + "group":"", + "keywords": ["androidn"], + "tags": [], + "image":"https://i1.ytimg.com/vi/CsulIu3UaUM/maxresdefault.jpg", + "lang":"en", + "type":"youtube" + }, + { "title":"Developing for Android 6.0 (Marshmallow)", "category":"", "summary":"This video covers how to get started with the preview, important APIs to test and how to provide feedback on the preview.", @@ -3120,6 +3175,19 @@ METADATA['en'].extras = METADATA['en'].extras.concat([ "summary": "Learn how to get new users, using Universal app campaigns directly within the Google Play Developer Console to increase your installs from ads, and find out how your acquisition channels perform.", }, { + "lang": "en", + "group": "", + "tags": ["play,protips"], + "url": "shareables/distribute/secrets_play/v2/web/secrets_to_app_success_v2_en.pdf", + "timestamp": 1447437450, + "image": "images/distribute/secrets_v2_banner.jpg", + "title": "The Secrets to App Success on Google Play", + "summary": "Get the updated guide full of useful features, tips, and best practices that will help you grow a successful app or game business on Google Play.", + "keywords": ["secrets, success, play, google"], + "type": "Book", + "category": "distribute" + }, + { "url":"panel1", "image": "", "title": "", @@ -3198,28 +3266,28 @@ METADATA['en'].carousel = { "title": "Android 5.0 Lollipop", "summary": "The Android 5.0 update adds a variety of new features for your apps, such as notifications on the lock screen, an all-new camera API, OpenGL ES 3.1, the new naterial design interface, and much more.", }, - "http://www.youtube.com/watch?v=Pms0pcyPbAM": { + "https://www.youtube.com/watch?v=Pms0pcyPbAM": { "url":"https://www.youtube.com/watch?v=Pms0pcyPbAM&list=PLWz5rJ2EKKc9ofd2f-_-xmUi07wIGZa1c]", "image": "images/distribute/hero-carousel-giftedmom.jpg", "title": "Gifted Mom reaches more mothers across Africa with Android", "type":"youtube", "summary": "Gifted Mom is an app developed in Cameroon which provides users with critical information about pregnancy, breastfeeding and child vaccinations. Hear the creators explain how they built their business and launched on Google Play.", }, - "http://www.youtube.com/watch?v=9m6MoBM-sFI": { + "https://www.youtube.com/watch?v=9m6MoBM-sFI": { "url":"https://www.youtube.com/watch?v=9m6MoBM-sFI&list=PLWz5rJ2EKKc9ofd2f-_-xmUi07wIGZa1c&index=3", "image": "images/distribute/hero-carousel-sgn.jpg", "title": "SGN increases installs with Store Listing Experiments", "type" : "youtube", "summary": "Watch mobile game developer SGN talk about how using Store Listing Experiments to test multiple variants across their portfolio of games helped improve their ROI, conversion rates and gamer retention.", }, - "http://www.youtube.com/watch?v=e7t3svG9PTk": { + "https://www.youtube.com/watch?v=e7t3svG9PTk": { "url":"https://www.youtube.com/watch?v=e7t3svG9PTk&index=2&list=PLWz5rJ2EKKc9ofd2f-_-xmUi07wIGZa1c", "image": "images/distribute/hero-carousel-djit.jpg", "title": "DJiT builds higher quality experiences on Android", "type" : "youtube", "summary": "Learn how Music app developer DJiT create higher quality apps with improved latency on Android Marshmallow, as well as other Android and Google Play features.", }, - "http://www.youtube.com/watch?v=J3IvOfvH1ys": { + "https://www.youtube.com/watch?v=J3IvOfvH1ys": { "url":"https://www.youtube.com/watch?v=J3IvOfvH1ys&list=PLWz5rJ2EKKc9ofd2f-_-xmUi07wIGZa1c&index=1", "image": "images/distribute/hero-carousel-wego.jpg", "title": "Wego increases user retention with material design", @@ -3275,10 +3343,10 @@ METADATA['en'].collections = { "index/secondary/carousel": { "title": "", "resources": [ - "http://www.youtube.com/watch?v=Pms0pcyPbAM", - "http://www.youtube.com/watch?v=9m6MoBM-sFI", - "http://www.youtube.com/watch?v=e7t3svG9PTk", - "http://www.youtube.com/watch?v=J3IvOfvH1ys" + "https://www.youtube.com/watch?v=9m6MoBM-sFI", + "https://www.youtube.com/watch?v=Pms0pcyPbAM", + "https://www.youtube.com/watch?v=e7t3svG9PTk", + "https://www.youtube.com/watch?v=J3IvOfvH1ys" ] }, "index/multiscreen": { @@ -3379,7 +3447,6 @@ METADATA['en'].collections = { "title": "", "resources": [ "https://www.youtube.com/watch?v=K2dodTXARqc&list=PLWz5rJ2EKKc8I9gHTMh5yKkwRRGE8BjbQ", - "https://www.youtube.com/watch?v=3PIc-DuEU2s&list=PLWz5rJ2EKKc9e0d55YHgJFHXNZbGHEXJX", "https://www.youtube.com/watch?v=cD7NPxuuXYY&list=PLWz5rJ2EKKc8I9gHTMh5yKkwRRGE8BjbQ", "https://www.youtube.com/watch?v=JLLnhwtDoHw&list=PLWz5rJ2EKKc8I9gHTMh5yKkwRRGE8BjbQ", "https://www.youtube.com/watch?v=2I6fuD20qlY&list=PLWz5rJ2EKKc8I9gHTMh5yKkwRRGE8BjbQ", @@ -4456,6 +4523,14 @@ METADATA['en'].collections = { "https://support.google.com/googleplay/answer/2651410" ] }, + "go/libraries": { + "title": "", + "resources": [ + "go/libraries/support-library/index.html", + "go/libraries/testing-support-library/index.html", + "go/libraries/data-binding/index.html" + ] + }, "autolanding": { "title": "", "resources": [ @@ -4614,10 +4689,11 @@ METADATA['en'].collections = { "resources": [ "training/enterprise/app-compatibility.html", "training/enterprise/app-restrictions.html", + "training/enterprise/cosu.html", "https://www.youtube.com/watch?v=39NkpWkaH8M&index=2&list=PLOU2XLYxmsIKAK2Bhv19H2THwF-22O5WX", "samples/AppRestrictionSchema/index.html", - "samples/AppRestrictionEnforcer/index.html", - "https://www.youtube.com/watch?v=dH41OutAMNM" + "https://www.youtube.com/watch?v=dH41OutAMNM", + "samples/AppRestrictionEnforcer/index.html" ] }, "training/work/admin": { @@ -4628,6 +4704,37 @@ METADATA['en'].collections = { "https://www.youtube.com/watch?v=j3QC6hcpy90" ] }, +"tools/help/log": { + "title": "", + "resources": [ + "tools/help/am-logcat.html" + ] + }, +"tools/help/monitor": { + "title": "", + "resources": [ + "tools/help/am-memory.html", + "tools/help/am-cpu.html", + "tools/help/am-gpu.html", + "tools/help/am-network.html" + ] + }, + "tools/help/data": { + "title": "", + "resources": [ + "tools/help/am-hprof.html", + "tools/help/am-allocation.html", + "tools/help/am-methodtrace.html", + "tools/help/am-sysinfo.html" + ] + }, + "tools/help/shot": { + "title": "", + "resources": [ + "tools/help/am-screenshot.html", + "tools/help/am-video.html" + ] + }, "tools/performance/rendering": { "title": "", "resources": [ @@ -4730,6 +4837,7 @@ METADATA['en'].collections = { "preview/landing/more": { "title": "", "resources": [ + "https://www.youtube.com/watch?v=CsulIu3UaUM", "preview/features/multi-window.html", "preview/features/notification-updates.html", "preview/features/background-optimization.html", @@ -4746,6 +4854,9 @@ METADATA['en'].collections = { /** * Static search results. + + Metadata objects returned in search results page when the user enters + each object's keyword. */ METADATA['en'].searchHeroCollections = { "material": { diff --git a/docs/html/ndk/guides/_book.yaml b/docs/html/ndk/guides/_book.yaml index fdcfe46424e0..287a92d0114a 100644 --- a/docs/html/ndk/guides/_book.yaml +++ b/docs/html/ndk/guides/_book.yaml @@ -61,5 +61,14 @@ toc: - title: OpenSL ES for Android path: /ndk/guides/audio/opensl-for-android.html -- title: Graphics +- title: Vulkan path: /ndk/guides/graphics/index.html + section: + - title: Getting Started + path: /ndk/guides/graphics/getting-started.html + - title: Design Guidelines + path: /ndk/guides/graphics/design-notes.html + - title: Shader Compilers + path: /ndk/guides/graphics/shader-compilers.html + - title: Validation Layers + path: /ndk/guides/graphics/validation-layer.html diff --git a/docs/html/preview/_book.yaml b/docs/html/preview/_book.yaml index 9f538667f36b..cac6d1309881 100644 --- a/docs/html/preview/_book.yaml +++ b/docs/html/preview/_book.yaml @@ -1,96 +1,342 @@ toc: - title: Program Overview path: /preview/overview.html - custom_link_attributes: - - es-lang="Información general del programa" - - ja-lang="プログラム概要" - - ko-lang="프로그램 개요" - - pt-br-lang="Visão geral do programa" - - ru-lang="Обзор программы" - - zh-cn-lang="计划概览" - - zh-tw-lang="程式總覽" + path_attributes: + - name: es-lang + value: Información general del programa + - name: in-lang + value: Ikhtisar Program + - name: ja-lang + value: プログラム概要 + - name: ko-lang + value: 프로그램 개요 + - name: pt-br-lang + value: Visão geral do programa + - name: ru-lang + value: Обзор программы + - name: vi-lang + value: Tổng quan về Chương trình + - name: zh-cn-lang + value: 计划概览 + - name: zh-tw-lang + value: 程式總覽 - title: Support and Release Notes path: /preview/support.html - title: Set Up to Develop path: /preview/setup-sdk.html - custom_link_attributes: - - es-lang="Configurar el SDK de la versión preliminar" - - ja-lang="Preview SDK のセットアップ" - - ko-lang="미리 보기 SDK 설정하기" - - pt-br-lang="Configuração do Preview SDK" - - ru-lang="Настройка пакета SDK Preview" - - zh-cn-lang="设置预览版 SDK" - - zh-tw-lang="設定預覽版 SDK" + path_attributes: + - name: es-lang + value: Configurar el SDK de la versión preliminar + - name: in-lang + value: Menyiapkan Preview + - name: ja-lang + value: Preview SDK のセットアップ + - name: ko-lang + value: 미리 보기 SDK 설정하기 + - name: pt-br-lang + value: Configuração do Preview SDK + - name: ru-lang + value: Настройка пакета SDK Preview + - name: vi-lang + value: Kiểm thử trên Thiết bị + - name: zh-cn-lang + value: 设置预览版 SDK + - name: zh-tw-lang + value: 設定預覽版 SDK - title: Test on a Device path: /preview/download.html + path_attributes: + - name: es-lang + value: Pruebe en un dispositivo + - name: in-lang + value: Menguji pada Perangkat + - name: ja-lang + value: デバイス上でテストする + - name: ko-lang + value: 기기에서 테스트 + - name: pt-br-lang + value: Testar em um dispositivo + - name: ru-lang + value: Тестирование на устройстве + - name: vi-lang + value: Kiểm thử trên Thiết bị + - name: zh-cn-lang + value: 在设备上测试 + - name: zh-tw-lang + value: 在裝置上測試 - title: Behavior Changes path: /preview/behavior-changes.html - custom_link_attributes: - - es-lang="Cambios en los comportamientos" - - ja-lang="動作の変更点" - - ko-lang="동작 변경" - - pt-br-lang="Mudanças de comportamento" - - ru-lang="Изменения в работе" - - zh-cn-lang="行为变更" - - zh-tw-lang="行為變更" + path_attributes: + - name: es-lang + value: Cambios en los comportamientos + - name: in-lang + value: Perubahan Perilaku + - name: ja-lang + value: 動作の変更点 + - name: ko-lang + value: 동작 변경 + - name: pt-br-lang + value: Mudanças de comportamento + - name: ru-lang + value: Изменения в работе + - name: vi-lang + value: Các thay đổi Hành vi + - name: zh-cn-lang + value: 行为变更 + - name: zh-tw-lang + value: 行為變更 section: - title: Background Optimizations path: /preview/features/background-optimization.html + path_attributes: + - name: es-lang + value: Optimizaciones en segundo plano + - name: in-lang + value: Optimisasi Latar Belakang + - name: ja-lang + value: バックグラウンド処理の最適化 + - name: ko-lang + value: 백그라운드 최적화 + - name: pt-br-lang + value: Otimizações em segundo plano + - name: ru-lang + value: Оптимизация фоновых процессов + - name: vi-lang + value: Tối ưu hóa Chạy ngầm + - name: zh-cn-lang + value: 后台优化 + - name: zh-tw-lang + value: 背景最佳化 - title: Language and Locale path: /preview/features/multilingual-support.html + path_attributes: + - name: es-lang + value: Idioma y configuración regional + - name: in-lang + value: Bahasa dan Lokal + - name: ja-lang + value: 言語とロケール + - name: ko-lang + value: 언어 및 로케일 + - name: pt-br-lang + value: Idioma e localidade + - name: ru-lang + value: Язык и языковой стандарт + - name: vi-lang + value: Ngôn ngữ và Bản địa + - name: zh-cn-lang + value: 语言和区域设置 + - name: zh-tw-lang + value: 語言和地區設定 - title: Android N for Developers path: /preview/api-overview.html - custom_link_attributes: - - es-lang="Información general de la API" - - ja-lang="API の概要" - - ko-lang="API 개요" - - pt-br-lang="Visão geral da API" - - ru-lang="Обзор API-интерфейсов" - - zh-cn-lang="API 概览" - - zh-tw-lang="API 總覽" + path_attributes: + - name: es-lang + value: Información general de la API + - name: in-lang + value: Android N untuk Pengembang + - name: ja-lang + value: API の概要 + - name: ko-lang + value: API 개요 + - name: pt-br-lang + value: Visão geral da API + - name: ru-lang + value: Обзор API-интерфейсов + - name: vi-lang + value: Android N cho Nhà phát triển + - name: zh-cn-lang + value: API 概览 + - name: zh-tw-lang + value: API 總覽 section: - title: Multi-Window Support path: /preview/features/multi-window.html + path_attributes: + - name: es-lang + value: Compatibilidad con ventanas múltiples + - name: in-lang + value: Dukungan Multi-Jendela + - name: ja-lang + value: マルチ ウィンドウのサポート + - name: ko-lang + value: 다중 창 지원 + - name: pt-br-lang + value: Suporte a várias janelas + - name: ru-lang + value: Поддержка многооконного режима + - name: vi-lang + value: Hỗ trợ đa cửa sổ + - name: zh-cn-lang + value: 多窗口支持 + - name: zh-tw-lang + value: 多視窗支援 - title: Notifications path: /preview/features/notification-updates.html + path_attributes: + - name: es-lang + value: Notificaciones + - name: in-lang + value: Pemberitahuan + - name: ja-lang + value: 通知 + - name: ko-lang + value: 알림 + - name: pt-br-lang + value: Notificações + - name: ru-lang + value: Уведомления + - name: vi-lang + value: Thông báo + - name: zh-cn-lang + value: 通知 + - name: zh-tw-lang + value: 通知 - title: Data Saver path: /preview/features/data-saver.html - title: TV Recording path: /preview/features/tv-recording-api.html + path_attributes: + - name: es-lang + value: Grabación de TV + - name: in-lang + value: Perekaman TV + - name: ja-lang + value: TV の録画 + - name: ko-lang + value: TV 녹화 + - name: pt-br-lang + value: Gravação para TV + - name: ru-lang + value: Запись ТВ + - name: vi-lang + value: Ghi lại TV + - name: zh-cn-lang + value: TV 录制 + - name: zh-tw-lang + value: 電視錄製 - title: Network Security Configuration path: /preview/features/security-config.html + path_attributes: + - name: es-lang + value: Configuración de seguridad de la red + - name: ja-lang + value: ネットワーク セキュリティ構成 + - name: ko-lang + value: 네트워크 보안 구성 + - name: pt-br-lang + value: Configurações de segurança de rede + - name: ru-lang + value: Конфигурация сетевой безопасности + - name: vi-lang + value: Cấu hình Bảo mật mạng + - name: zh-cn-lang + value: 网络安全配置 + - name: zh-tw-lang + value: 網路安全性設定 - title: ICU4J Support path: /preview/features/icu4j-framework.html + path_attributes: + - name: es-lang + value: API de ICU4J del framework de Android + - name: in-lang + value: ICU4J Android Framework API + - name: ja-lang + value: ICU4J Android フレームワーク API + - name: ko-lang + value: ICU4J Android 프레임워크 API + - name: pt-br-lang + value: APIs de estrutura do Android para ICU4J + - name: ru-lang + value: API-интерфейсы ICU4J в платформе Android + - name: vi-lang + value: API Khuôn khổ Android ICU4J + - name: zh-cn-lang + value: ICU4J Android 框架 API + - name: zh-tw-lang + value: ICU4J Android 架構 API - title: Java 8 Language Features path: /preview/j8-jack.html + path_attributes: + - name: es-lang + value: Funciones del lenguaje Java 8 + - name: in-lang + value: Fitur Bahasa Java 8 + - name: ja-lang + value: Java 8 の機能 + - name: ko-lang + value: Java 8 언어 기능 + - name: pt-br-lang + value: Recursos de linguagem do Java 8 + - name: ru-lang + value: Возможности языка Java 8 + - name: vi-lang + value: Tính năng của Ngôn ngữ Java 8 + - name: zh-cn-lang + value: Java 8 语言功能 + - name: zh-tw-lang + value: Java 8 語言功能 - title: Android for Work Updates path: /preview/features/afw.html - title: Scoped Directory Access path: /preview/features/scoped-folder-access.html + path_attributes: + - name: es-lang + value: Acceso a directorios determinados + - name: ja-lang + value: 特定のディレクトリへのアクセス + - name: ko-lang + value: 범위가 지정된 디렉터리 액세스 + - name: pt-br-lang + value: Acesso a diretórios com escopo + - name: ru-lang + value: Доступ к выделенным каталогам + - name: vi-lang + value: Truy cập Thư mục theo Phạm vi + - name: zh-cn-lang + value: 作用域目录访问 + - name: zh-tw-lang + value: 限定範圍目錄存取 - title: Samples path: /preview/samples.html - custom_link_attributes: - - es-lang="Ejemplos" - - ja-lang="サンプル" - - ko-lang="샘플" - - pt-br-lang="Exemplos" - - ru-lang="Примеры" - - zh-cn-lang="示例" - - zh-tw-lang="範例" + path_attributes: + - name: es-lang + value: Ejemplos + - name: in-lang + value: Contoh + - name: ja-lang + value: サンプル + - name: ko-lang + value: 샘플 + - name: pt-br-lang + value: Exemplos + - name: ru-lang + value: Примеры + - name: zh-cn-lang + value: 示例 + - name: zh-tw-lang + value: 範例 - title: License Agreement path: /preview/license.html - custom_link_attributes: - - es-lang="Contrato de licencia" - - ja-lang="使用許諾契約" - - ko-lang="라이선스 계약" - - pt-br-lang="Contrato de licença" - - ru-lang="Лицензионное соглашение" - - zh-cn-lang="许可协议" - - zh-tw-lang="授權協議" + path_attributes: + - name: es-lang + value: Contrato de licencia + - name: ja-lang + value: 使用許諾契約 + - name: ko-lang + value: 라이선스 계약 + - name: pt-br-lang + value: Contrato de licença + - name: ru-lang + value: Лицензионное соглашение + - name: zh-cn-lang + value: 许可协议 + - name: zh-tw-lang + value: 授權協議 diff --git a/docs/html/preview/behavior-changes.jd b/docs/html/preview/behavior-changes.jd index 0cf5bc9de6f2..7c8bfe8ba29e 100644 --- a/docs/html/preview/behavior-changes.jd +++ b/docs/html/preview/behavior-changes.jd @@ -215,11 +215,17 @@ page.image=images/cards/card-n-changes_2x.png <ul> <li> - Private files’ file permissions can no longer be relaxed by the owner, and - an attempt to do so using + Private files’ file permissions should no longer be relaxed by the owner, + and an attempt to do so using {@link android.content.Context#MODE_WORLD_READABLE} and/or {@link android.content.Context#MODE_WORLD_WRITEABLE}, will trigger a {@link java.lang.SecurityException}. + <p class="note"> + <strong>Note:</strong> As of yet, this restriction is not fully enforced. + Apps may still modify permissions to their private directory using + native APIs or the {@link java.io.File File} API. However, we strongly + discourage relaxing the permissions to the private directory. + </p> </li> <li> Passing <code>file://</code> URIs outside the package domain may leave the diff --git a/docs/html/preview/download-ota.jd b/docs/html/preview/download-ota.jd index 55139f19e72a..7e70f570a5ba 100644 --- a/docs/html/preview/download-ota.jd +++ b/docs/html/preview/download-ota.jd @@ -248,10 +248,9 @@ This is the Android SDK Preview License Agreement (the “License Agreement”). <tr id="fugu"> <td>Nexus Player <br>"fugu"</td> <td><a href="#top" onclick="onDownload(this)" - >fugu-ota-2665432-f0f8fea4.zip</a><br> - <strong>Note:</strong> DP2 version not yet available.<br> - MD5: 4403af764b57502d89111fd68ecb7da5<br> - SHA-1: f0f8fea49ea3874b751cf67462ecc5d8e039875e + >fugu-ota-npc91o-b1d73dd5.zip</a><br> + MD5: d7fbccde75e0b6d860102320ea76d58f<br> + SHA-1: b1d73dd5a6498fb6c66e022bd0a6c8b6a6a2374b </td> </tr> diff --git a/docs/html/preview/download.jd b/docs/html/preview/download.jd index b673fc151ff0..b0f53694ea90 100644 --- a/docs/html/preview/download.jd +++ b/docs/html/preview/download.jd @@ -347,10 +347,9 @@ This is the Android SDK Preview License Agreement (the “License Agreement”). <tr id="fugu"> <td>Nexus Player <br>"fugu"</td> <td><a href="#top" onclick="onDownload(this)" - >fugu-npc56r-preview-7027d5b6.tgz</a><br> - <strong>Note:</strong> DP2 version not yet available.<br> - MD5: f5d3d8f75836ccfe4c70e8162e498be4<br> - SHA-1: 7027d5b662bceda4c80a91a0a14ef0e5a7ba795b + >fugu-npc91o-factory-3b8e3f56.tgz</a><br> + MD5: b88b70ecbfb80c983c90b97cb243628b<br> + SHA-1: 3b8e3f56a4c35b559783c2928e740df2aab8b377 </td> </tr> diff --git a/docs/html/preview/support.jd b/docs/html/preview/support.jd index 4caa6b22585c..f0da709b7043 100644 --- a/docs/html/preview/support.jd +++ b/docs/html/preview/support.jd @@ -23,7 +23,7 @@ page.image=images/cards/card-n-support_2x.png <div class="col-6of12"> <p> <em>Date: April 2016<br> - Builds: NPC91K<br> + Builds: NPC91K, NPC91O<br> Emulator support: x86 & ARM (32/64-bit)<br> Google Play services: 8.4</em> </p> @@ -325,7 +325,7 @@ page.image=images/cards/card-n-support_2x.png </dt> <dd> - Playback of Netflix HD content is known to fail on Nexus Player. + Playback of Netflix HD content may fail on Nexus Player. </dd> <dd> diff --git a/docs/html/sdk/index.jd b/docs/html/sdk/index.jd deleted file mode 100644 index 94b7e559f866..000000000000 --- a/docs/html/sdk/index.jd +++ /dev/null @@ -1,537 +0,0 @@ -page.title=Download Android Studio and SDK Tools -page.tags=sdk, android studio -page.template=sdk -section.landing=true -header.hide=1 -nonavpage=true -fullpage=true -page.image=images/cards/android-studio_2x.png -page.metaDescription=Download the official Android IDE and developer tools to build apps for Android phones, tablets, wearables, TVs, and more. - -@jd:body - -<style> -.download-bundle-button {line-height:18px;} -.download-bundle-button .small {font-size: 12px; opacity: 0.7;} -</style> - - <section class="dac-expand dac-hero dac-light"> - <div class="wrap"> - <div class="cols dac-hero-content"> - <div class="col-1of2 col-push-1of2 dac-hero-figure"> - <img class="dac-hero-image" src="/images/develop/hero_image_studio5_2x.png" srcset="/images/develop/hero_image_studio5.png 1x, /images/develop/hero_image_studio5_2x.png 2x"> - </div> - <div class="col-1of2 col-pull-1of2" style="margin-bottom:40px"> -<h1 class="dac-hero-title">Android Studio<br> -<span style="font-size: 65%;">The Official IDE for Android</span></h1> - -<p class="dac-hero-description">Android Studio provides the fastest tools for -building apps on every type of Android device.</p> - -<p class="dac-hero-description">World-class code editing, debugging, -performance tooling, a flexible build system, and an instant build/deploy -system all allow you to focus on building unique and high quality apps.</p> - -<p style="margin-top:24px"> - <a class="landing-button green download-bundle-button" - data-modal-toggle="studio_tos">Download Android Studio 2.1<br> - <span class="small"></span></a> -</p> - -<p style="margin:24px 0 0"> - <a class="dac-hero-cta" href="{@docRoot}tools/studio/index.html"> - <span class="dac-sprite dac-auto-chevron"></span> - Read the docs</a> - <a class="dac-hero-cta" href="{@docRoot}tools/revisions/studio.html"> - <span class="dac-sprite dac-auto-chevron"></span> - See the release notes</a> -</p> - </div> - </div> - </div> -</section> - - - - -<!-- start studio download modal --> -<div data-modal="studio_tos" class="dac-modal" id="langform"> - <div class="dac-modal-container"> - <div class="dac-modal-window"> - <header class="dac-modal-header"> - <div class="dac-modal-header-actions"> - <button class="dac-modal-header-close" data-modal-toggle></button> - </div> - <section class="dac-swap-section dac-active dac-down"> - <h2 class="norule dac-modal-header-title" id="tos-header">Download Android Studio</h2> - </section> - </header> - <section class="dac-swap-section dac-active dac-left"> - <section class="dac-modal-content"> - <fieldset class="dac-form-fieldset"> - <div class="cols"> - <div class="col-2of2 tos-leftCol"> - <p class="sdk-terms-intro">Before downloading, - you must agree to the following terms - and conditions.</p> - </div> - -<div class="sdk-terms" onfocus="this.blur()"> -<h2 class="norule">Terms and Conditions</h2> -This is the Android Software Development Kit License Agreement - -<h3>1. Introduction</h3> -1.1 The Android Software Development Kit (referred to in the License Agreement as the "SDK" and specifically including the Android system files, packaged APIs, and Google APIs add-ons) is licensed to you subject to the terms of the License Agreement. The License Agreement forms a legally binding contract between you and Google in relation to your use of the SDK. - -1.2 "Android" means the Android software stack for devices, as made available under the Android Open Source Project, which is located at the following URL: http://source.android.com/, as updated from time to time. - -1.3 A "compatible implementation" means any Android device that (i) complies with the Android Compatibility Definition document, which can be found at the Android compatibility website (http://source.android.com/compatibility) and which may be updated from time to time; and (ii) successfully passes the Android Compatibility Test Suite (CTS). - -1.4 "Google" means Google Inc., a Delaware corporation with principal place of business at 1600 Amphitheatre Parkway, Mountain View, CA 94043, United States. - - -<h3>2. Accepting this License Agreement</h3> -2.1 In order to use the SDK, you must first agree to the License Agreement. You may not use the SDK if you do not accept the License Agreement. - -2.2 By clicking to accept, you hereby agree to the terms of the License Agreement. - -2.3 You may not use the SDK and may not accept the License Agreement if you are a person barred from receiving the SDK under the laws of the United States or other countries, including the country in which you are resident or from which you use the SDK. - -2.4 If you are agreeing to be bound by the License Agreement on behalf of your employer or other entity, you represent and warrant that you have full legal authority to bind your employer or such entity to the License Agreement. If you do not have the requisite authority, you may not accept the License Agreement or use the SDK on behalf of your employer or other entity. - - -<h3>3. SDK License from Google</h3> -3.1 Subject to the terms of the License Agreement, Google grants you a limited, worldwide, royalty-free, non-assignable, non-exclusive, and non-sublicensable license to use the SDK solely to develop applications for compatible implementations of Android. - -3.2 You may not use this SDK to develop applications for other platforms (including non-compatible implementations of Android) or to develop another SDK. You are of course free to develop applications for other platforms, including non-compatible implementations of Android, provided that this SDK is not used for that purpose. - -3.3 You agree that Google or third parties own all legal right, title and interest in and to the SDK, including any Intellectual Property Rights that subsist in the SDK. "Intellectual Property Rights" means any and all rights under patent law, copyright law, trade secret law, trademark law, and any and all other proprietary rights. Google reserves all rights not expressly granted to you. - -3.4 You may not use the SDK for any purpose not expressly permitted by the License Agreement. Except to the extent required by applicable third party licenses, you may not: (a) copy (except for backup purposes), modify, adapt, redistribute, decompile, reverse engineer, disassemble, or create derivative works of the SDK or any part of the SDK; or (b) load any part of the SDK onto a mobile handset or any other hardware device except a personal computer, combine any part of the SDK with other software, or distribute any software or device incorporating a part of the SDK. - -3.5 Use, reproduction and distribution of components of the SDK licensed under an open source software license are governed solely by the terms of that open source software license and not the License Agreement. - -3.6 You agree that the form and nature of the SDK that Google provides may change without prior notice to you and that future versions of the SDK may be incompatible with applications developed on previous versions of the SDK. You agree that Google may stop (permanently or temporarily) providing the SDK (or any features within the SDK) to you or to users generally at Google's sole discretion, without prior notice to you. - -3.7 Nothing in the License Agreement gives you a right to use any of Google's trade names, trademarks, service marks, logos, domain names, or other distinctive brand features. - -3.8 You agree that you will not remove, obscure, or alter any proprietary rights notices (including copyright and trademark notices) that may be affixed to or contained within the SDK. - - -<h3>4. Use of the SDK by You</h3> -4.1 Google agrees that it obtains no right, title or interest from you (or your licensors) under the License Agreement in or to any software applications that you develop using the SDK, including any intellectual property rights that subsist in those applications. - -4.2 You agree to use the SDK and write applications only for purposes that are permitted by (a) the License Agreement and (b) any applicable law, regulation or generally accepted practices or guidelines in the relevant jurisdictions (including any laws regarding the export of data or software to and from the United States or other relevant countries). - -4.3 You agree that if you use the SDK to develop applications for general public users, you will protect the privacy and legal rights of those users. If the users provide you with user names, passwords, or other login information or personal information, you must make the users aware that the information will be available to your application, and you must provide legally adequate privacy notice and protection for those users. If your application stores personal or sensitive information provided by users, it must do so securely. If the user provides your application with Google Account information, your application may only use that information to access the user's Google Account when, and for the limited purposes for which, the user has given you permission to do so. - -4.4 You agree that you will not engage in any activity with the SDK, including the development or distribution of an application, that interferes with, disrupts, damages, or accesses in an unauthorized manner the servers, networks, or other properties or services of any third party including, but not limited to, Google or any mobile communications carrier. - -4.5 You agree that you are solely responsible for (and that Google has no responsibility to you or to any third party for) any data, content, or resources that you create, transmit or display through Android and/or applications for Android, and for the consequences of your actions (including any loss or damage which Google may suffer) by doing so. - -4.6 You agree that you are solely responsible for (and that Google has no responsibility to you or to any third party for) any breach of your obligations under the License Agreement, any applicable third party contract or Terms of Service, or any applicable law or regulation, and for the consequences (including any loss or damage which Google or any third party may suffer) of any such breach. - - -<h3>5. Your Developer Credentials</h3> -5.1 You agree that you are responsible for maintaining the confidentiality of any developer credentials that may be issued to you by Google or which you may choose yourself and that you will be solely responsible for all applications that are developed under your developer credentials. - - -<h3>6. Privacy and Information</h3> -6.1 In order to continually innovate and improve the SDK, Google may collect certain usage statistics from the software including but not limited to a unique identifier, associated IP address, version number of the software, and information on which tools and/or services in the SDK are being used and how they are being used. Before any of this information is collected, the SDK will notify you and seek your consent. If you withhold consent, the information will not be collected. - -6.2 The data collected is examined in the aggregate to improve the SDK and is maintained in accordance with Google's Privacy Policy. - - -<h3>7. Third Party Applications</h3> -7.1 If you use the SDK to run applications developed by a third party or that access data, content or resources provided by a third party, you agree that Google is not responsible for those applications, data, content, or resources. You understand that all data, content or resources which you may access through such third party applications are the sole responsibility of the person from which they originated and that Google is not liable for any loss or damage that you may experience as a result of the use or access of any of those third party applications, data, content, or resources. - -7.2 You should be aware the data, content, and resources presented to you through such a third party application may be protected by intellectual property rights which are owned by the providers (or by other persons or companies on their behalf). You may not modify, rent, lease, loan, sell, distribute or create derivative works based on these data, content, or resources (either in whole or in part) unless you have been specifically given permission to do so by the relevant owners. - -7.3 You acknowledge that your use of such third party applications, data, content, or resources may be subject to separate terms between you and the relevant third party. In that case, the License Agreement does not affect your legal relationship with these third parties. - - -<h3>8. Using Android APIs</h3> -8.1 Google Data APIs - -8.1.1 If you use any API to retrieve data from Google, you acknowledge that the data may be protected by intellectual property rights which are owned by Google or those parties that provide the data (or by other persons or companies on their behalf). Your use of any such API may be subject to additional Terms of Service. You may not modify, rent, lease, loan, sell, distribute or create derivative works based on this data (either in whole or in part) unless allowed by the relevant Terms of Service. - -8.1.2 If you use any API to retrieve a user's data from Google, you acknowledge and agree that you shall retrieve data only with the user's explicit consent and only when, and for the limited purposes for which, the user has given you permission to do so. - - -<h3>9. Terminating this License Agreement</h3> -9.1 The License Agreement will continue to apply until terminated by either you or Google as set out below. - -9.2 If you want to terminate the License Agreement, you may do so by ceasing your use of the SDK and any relevant developer credentials. - -9.3 Google may at any time, terminate the License Agreement with you if: -(A) you have breached any provision of the License Agreement; or -(B) Google is required to do so by law; or -(C) the partner with whom Google offered certain parts of SDK (such as APIs) to you has terminated its relationship with Google or ceased to offer certain parts of the SDK to you; or -(D) Google decides to no longer provide the SDK or certain parts of the SDK to users in the country in which you are resident or from which you use the service, or the provision of the SDK or certain SDK services to you by Google is, in Google's sole discretion, no longer commercially viable. - -9.4 When the License Agreement comes to an end, all of the legal rights, obligations and liabilities that you and Google have benefited from, been subject to (or which have accrued over time whilst the License Agreement has been in force) or which are expressed to continue indefinitely, shall be unaffected by this cessation, and the provisions of paragraph 14.7 shall continue to apply to such rights, obligations and liabilities indefinitely. - - -<h3>10. DISCLAIMER OF WARRANTIES</h3> -10.1 YOU EXPRESSLY UNDERSTAND AND AGREE THAT YOUR USE OF THE SDK IS AT YOUR SOLE RISK AND THAT THE SDK IS PROVIDED "AS IS" AND "AS AVAILABLE" WITHOUT WARRANTY OF ANY KIND FROM GOOGLE. - -10.2 YOUR USE OF THE SDK AND ANY MATERIAL DOWNLOADED OR OTHERWISE OBTAINED THROUGH THE USE OF THE SDK IS AT YOUR OWN DISCRETION AND RISK AND YOU ARE SOLELY RESPONSIBLE FOR ANY DAMAGE TO YOUR COMPUTER SYSTEM OR OTHER DEVICE OR LOSS OF DATA THAT RESULTS FROM SUCH USE. - -10.3 GOOGLE FURTHER EXPRESSLY DISCLAIMS ALL WARRANTIES AND CONDITIONS OF ANY KIND, WHETHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES AND CONDITIONS OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. - - -<h3>11. LIMITATION OF LIABILITY</h3> -11.1 YOU EXPRESSLY UNDERSTAND AND AGREE THAT GOOGLE, ITS SUBSIDIARIES AND AFFILIATES, AND ITS LICENSORS SHALL NOT BE LIABLE TO YOU UNDER ANY THEORY OF LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, CONSEQUENTIAL OR EXEMPLARY DAMAGES THAT MAY BE INCURRED BY YOU, INCLUDING ANY LOSS OF DATA, WHETHER OR NOT GOOGLE OR ITS REPRESENTATIVES HAVE BEEN ADVISED OF OR SHOULD HAVE BEEN AWARE OF THE POSSIBILITY OF ANY SUCH LOSSES ARISING. - - -<h3>12. Indemnification</h3> -12.1 To the maximum extent permitted by law, you agree to defend, indemnify and hold harmless Google, its affiliates and their respective directors, officers, employees and agents from and against any and all claims, actions, suits or proceedings, as well as any and all losses, liabilities, damages, costs and expenses (including reasonable attorneys fees) arising out of or accruing from (a) your use of the SDK, (b) any application you develop on the SDK that infringes any copyright, trademark, trade secret, trade dress, patent or other intellectual property right of any person or defames any person or violates their rights of publicity or privacy, and (c) any non-compliance by you with the License Agreement. - - -<h3>13. Changes to the License Agreement</h3> -13.1 Google may make changes to the License Agreement as it distributes new versions of the SDK. When these changes are made, Google will make a new version of the License Agreement available on the website where the SDK is made available. - - -<h3>14. General Legal Terms</h3> -14.1 The License Agreement constitutes the whole legal agreement between you and Google and governs your use of the SDK (excluding any services which Google may provide to you under a separate written agreement), and completely replaces any prior agreements between you and Google in relation to the SDK. - -14.2 You agree that if Google does not exercise or enforce any legal right or remedy which is contained in the License Agreement (or which Google has the benefit of under any applicable law), this will not be taken to be a formal waiver of Google's rights and that those rights or remedies will still be available to Google. - -14.3 If any court of law, having the jurisdiction to decide on this matter, rules that any provision of the License Agreement is invalid, then that provision will be removed from the License Agreement without affecting the rest of the License Agreement. The remaining provisions of the License Agreement will continue to be valid and enforceable. - -14.4 You acknowledge and agree that each member of the group of companies of which Google is the parent shall be third party beneficiaries to the License Agreement and that such other companies shall be entitled to directly enforce, and rely upon, any provision of the License Agreement that confers a benefit on (or rights in favor of) them. Other than this, no other person or company shall be third party beneficiaries to the License Agreement. - -14.5 EXPORT RESTRICTIONS. THE SDK IS SUBJECT TO UNITED STATES EXPORT LAWS AND REGULATIONS. YOU MUST COMPLY WITH ALL DOMESTIC AND INTERNATIONAL EXPORT LAWS AND REGULATIONS THAT APPLY TO THE SDK. THESE LAWS INCLUDE RESTRICTIONS ON DESTINATIONS, END USERS AND END USE. - -14.6 The rights granted in the License Agreement may not be assigned or transferred by either you or Google without the prior written approval of the other party. Neither you nor Google shall be permitted to delegate their responsibilities or obligations under the License Agreement without the prior written approval of the other party. - -14.7 The License Agreement, and your relationship with Google under the License Agreement, shall be governed by the laws of the State of California without regard to its conflict of laws provisions. You and Google agree to submit to the exclusive jurisdiction of the courts located within the county of Santa Clara, California to resolve any legal matter arising from the License Agreement. Notwithstanding this, you agree that Google shall still be allowed to apply for injunctive remedies (or an equivalent type of urgent legal relief) in any jurisdiction. - -<em>November 20, 2015</em> -</div><!-- close sdk-terms --> - - - -<div id="next-steps" style="display:none;position:absolute;width:inherit"> - <p>You're just a few steps away from building apps for Android!</p> - <p>In a moment, you'll be redirected to - <a id="next-link" href="{@docRoot}sdk/installing/index.html">Installing the Android SDK</a>.</p> -</div><!-- end next-steps --> - -<div id="sdk-terms-form"> -<p> -<input id="agree" type="checkbox" name="agree" value="1" onclick="onAgreeChecked()" /> -<label id="agreeLabel" for="agree">I have read and agree with the above terms and conditions</label> -</p> -<p><a href="" class="dac-button dac-raised dac-primary disabled ndk" id="downloadForRealz" onclick="return onDownloadForRealz(this);"></a></p> -</div><!-- end sdk-terms-form --> - - -</div><!-- end cols --> - - </fieldset> - </section> - </section> - </div><!-- end dac-modal-window --> - </div><!-- end dac-modal-container --> -</div><!-- end #langform, .dac-modal --> -<!-- end studio_tos modal --> - -<div id="useOldTemplates" class="actions-bar dac-expand dac-invert"> - <div class="wrap dac-offset-parent"> - <a class="dac-fab dac-scroll-button" data-scroll-button="" href="#features"> - <i class="dac-sprite dac-arrow-down-gray"></i> - </a> - <div class="actions"> - <div><a href="#features"> - <span class="dac-sprite dac-auto-chevron-large"></span> - Features - </a></div> - <div><a href="#latest"> - <span class="dac-sprite dac-auto-chevron-large"></span> - Latest - </a></div> - <div><a href="#resources"> - <span class="dac-sprite dac-auto-chevron-large"></span> - Resources - </a></div> - <div><a href="#videos"> - <span class="dac-sprite dac-auto-chevron-large"></span> - Videos - </a></div> - <div><a href="#downloads"> - <span class="dac-sprite dac-auto-chevron-large"></span> - Download Options - </a></div> - </div><!-- end .actions --> - </div><!-- end .wrap --> -</div> - - -<div id="useUpdatedTemplates" style="display:none" class="dac-section dac-slim dac-gray dac-expand"> - <div class="wrap dac-offset-parent"> - <a class="dac-fab dac-scroll-button" data-scroll-button href="#features"> - <i class="dac-sprite dac-arrow-down-gray"></i> - </a> - <ul class="dac-actions"> - <li class="dac-action"> - <a class="dac-action-link" href="#features"> - <i class="dac-action-sprite dac-sprite dac-auto-chevron-large"></i> - Features - </a> - </li> - <li class="dac-action"> - <a class="dac-action-link" href="#latest"> - <i class="dac-action-sprite dac-sprite dac-auto-chevron-large"></i> - Latest - </a> - </li> - <li class="dac-action"> - <a class="dac-action-link" href="#resources"> - <i class="dac-action-sprite dac-sprite dac-auto-chevron-large"></i> - Resources - </a> - </li> - <li class="dac-action"> - <a class="dac-action-link" href="#videos"> - <i class="dac-action-sprite dac-sprite dac-auto-chevron-large"></i> - Videos - </a> - </li> - <li class="dac-action"> - <a class="dac-action-link" href="#downloads"> - <i class="dac-action-sprite dac-sprite dac-auto-chevron-large"></i> - Download Options - </a> - </li> - </ul> - </div><!-- end .wrap --> -</div><!-- end new templates --> - - - -<section id="features" class="dac-section dac-small"> -<div class="dac-toggle"> - -<div class="wrap feature"> - <div class="cols dac-hero-content"> - <div class="col-1of2 col-push-1of2 dac-hero-figure"> - <img src="/images/tools/studio/studio-feature-instant-run_2x.png"> - </div> - <div class="col-1of2 col-pull-1of2"> - <div class="dac-hero-tag"></div> - <h1 class="dac-hero-title">Instant Run</h1> -<p class="dac-hero-description">Push code and resource -changes to your app running on a device or emulator and see the -changes instantly come to life.</p> -<p class="dac-hero-description">Instant Run dramatically speeds up your edit, -build, and run cycles, keeping you "in the flow."</p> - <a class="dac-hero-cta" - href="/tools/building/building-studio.html#instant-run"> - <span class="dac-sprite dac-auto-chevron"></span> - Learn more</a> - </div> - </div> -</div> - -<div class="wrap feature"> - <div class="cols dac-hero-content"> - <div class="col-1of2 dac-hero-figure"> - <img src="/images/tools/codeeditor-low.gif" > - </div> - <div class="col-1of2"> - <div class="dac-hero-tag"></div> - <h1 class="dac-hero-title">Intelligent code editor</h1> -<p class="dac-hero-description">Write better code, work faster, and be more productive with an intelligent code editor that helps you each step of the way.</p> -<p class="dac-hero-description">Android Studio is built on IntelliJ and is capable of advanced code completion, refactoring, and code analysis.</p> - </div> - </div> -</div> - -<div class="wrap feature"> - <div class="cols dac-hero-content"> - <div class="col-1of2 col-push-1of2 dac-hero-figure"> - <img src="/images/tools/studio/studio-feature-emulator_2x.jpg"> - </div> - <div class="col-1of2 col-pull-1of2"> - <div class="dac-hero-tag"></div> - <h1 class="dac-hero-title">Fast and feature-rich emulator</h1> -<p class="dac-hero-description">Install and run your apps faster than with a physical device and test your app on virtually any Android device configuration: Android phones, Android tablets, Android Wear, and Android TV devices.</p> -<p class="dac-hero-description">The new Android Emulator 2.0 is faster than ever and allows you to dynamically resize the emulator and access a suite of sensor controls.</p> - <a class="dac-hero-cta" - href="/tools/devices/emulator.html"> - <span class="dac-sprite dac-auto-chevron"></span> - Learn more</a> - </div> - </div> -</div> - -<div class="wrap feature"> - <div class="cols dac-hero-content"> - <div class="col-1of2 dac-hero-figure"> - <img src="/images/tools/studio/studio-feature-gradle_2x.png"> - </div> - <div class="col-1of2"> - <div class="dac-hero-tag"></div> - <h1 class="dac-hero-title">Robust and flexible build system</h1> -<p class="dac-hero-description">Easily configure your project to include code libraries and generate multiple build variants from a single project.</p> -<p class="dac-hero-description">With Gradle, Android Studio offers high-performance build automation, robust dependency management, and customizable build configurations.</p> - <a class="dac-hero-cta" - href="/tools/building/plugin-for-gradle.html"> - <span class="dac-sprite dac-auto-chevron"></span> - Learn more</a> - </div> - </div> -</div> - -<div class="dac-toggle-content clearfix"> - -<div class="wrap feature"> - <div class="cols dac-hero-content"> - <div class="col-1of2 col-push-1of2 dac-hero-figure"> - <img src="/images/tools/studio/studio-feature-devices_2x.png"> - </div> - <div class="col-1of2 col-pull-1of2"> - <div class="dac-hero-tag"></div> - <h1 class="dac-hero-title">Develop for all <wbr>Android devices</h1> -<p class="dac-hero-description">Target multiple form factors with a single -project to easily share code among your different versions of your app.</p> -<p class="dac-hero-description">Android Studio provides a unified environment -to develop apps for Android phones, tablets, Android Wear, Android TV, and -Android Auto.</p> - - <a class="dac-hero-cta" - href="/tools/building/configuring-gradle.html#workBuildVariants"> - <span class="dac-sprite dac-auto-chevron"></span> - Learn more</a> - </div> - </div> -</div> - -<div class="wrap feature"> - <div class="cols dac-hero-content"> - <div class="col-1of2 dac-hero-figure"> - <img src="/images/tools/studio/studio-feature-github_2x.png"> - </div> - <div class="col-1of2"> - <div class="dac-hero-tag"></div> - <h1 class="dac-hero-title">Code templates and GitHub integration</h1> - <p class="dac-hero-description">Start projects with code templates for patterns such as navigation drawer and view pagers, or import Google code samples from GitHub.</p> - <p class="dac-hero-description">Android Studio's project wizards make it easier than ever to add code in a new project.</p> - </div> - </div> -</div> - -</div><!-- end dac-toggle-content --> - -<div class="dac-section-links dac-text-center feature-more"> - <div class="dac-section-link" data-toggle="section"> - <span class="dac-toggle-expand">More - <i class="dac-sprite dac-auto-unfold-more"></i> - </span> - <span class="dac-toggle-collapse">Less - <i class="dac-sprite dac-auto-unfold-less"></i> - </span> - </div> -</div> - -</div> -</section><!-- end features --> - - - -<section id="latest" class="dac-section dac-light dac-small"><div class="wrap"> - <h1 class="dac-section-title">Latest News</h1> - <div class="resource-widget resource-flow-layout col-16" - data-query="collection:tools/landing/latest" - data-cardSizes="6x6" - data-items-per-page="3" - data-initial-results="3" - data-maxResults="3"></div> - </div> -</section> - -<section id="resources" class="dac-section dac-small"><div class="wrap"> - <h1 class="dac-section-title">Resources</h1> - <div class="resource-widget resource-flow-layout col-16" - data-query="collection:tools/landing/resources" - data-cardSizes="6x6" - data-initial-results="3" - data-items-per-page="3" - data-maxResults="3"></div> - </div> -</section> - -<section class="dac-section dac-light dac-small dac-gray" id="videos"><div class="wrap"> - <h1 class="dac-section-title">Videos</h1> - <div class="resource-widget resource-flow-layout col-16" - data-query="collection:develop/landing/tools" - data-sortOrder="-timestamp" - data-cardSizes="6x6" - data-maxResults="3"></div> - </div> -</section> - - - -<section id="Requirements" class="dac-section dac-light dac-small"> -<div class="wrap"> - -<h2 class="norule">System Requirements</h2> - -<div class="cols"> - -<div class="col-2of6"> -<h4>Windows</h4> -<ul> -<li>Microsoft® Windows® 7/8/10 (32- or 64-bit)</li> -<li>2 GB RAM minimum, 8 GB RAM recommended</li> -<li>2 GB of available disk space minimum,<br>4 GB Recommended -(500 MB for IDE + 1.5 GB for -Android SDK and emulator system image)</li> -<li>1280 x 800 minimum screen resolution</li> -<li>Java Development Kit (JDK) 8</li> -<li>For accelerated emulator: 64-bit operating system and -Intel® processor with support for Intel® -VT-x, Intel® EM64T (Intel® 64), and Execute Disable (XD) Bit functionality</li> -</ul> -</div> - -<div class="col-2of6"> -<h4>Mac</h4> -<ul> -<li>Mac® OS X® 10.8.5 or higher, up to 10.11.4 (El Capitan)</li> -<li>2 GB RAM minimum, 8 GB RAM recommended</li> -<li>2 GB of available disk space minimum,<br>4 GB Recommended -(500 MB for IDE + 1.5 GB for -Android SDK and emulator system image)</li> -<li>1280 x 800 minimum screen resolution</li> -<li>Java Development Kit (JDK) 6</li> -</ul> -</div> - -<div class="col-2of6"> -<h4>Linux</h4> -<ul> -<li>GNOME or KDE desktop -<p><i>Tested on Ubuntu® 12.04, Precise Pangolin (64-bit distribution -capable of running 32-bit applications)</i></li> -<li>64-bit distribution capable of running 32-bit applications</li> -<li>GNU C Library (glibc) 2.11 or later</li> -<li>2 GB RAM minimum, 8 GB RAM recommended</li> -<li>2 GB of available disk space minimum,<br>4 GB Recommended -(500 MB for IDE + 1.5 GB for -Android SDK and emulator system image)</li> -<li>1280 x 800 minimum screen resolution</li> -<li>Java Development Kit (JDK) 8</li> -<li>For accelerated emulator: Intel® processor with support for Intel® -VT-x, Intel® EM64T (Intel® 64), and Execute Disable (XD) Bit functionality, -or AMD processor with support for AMD Virtualization™ (AMD-V™)</li> -</ul> -</div> - -</div> -</div> - -</section> - diff --git a/docs/html/sdk/installing/bundle.jd b/docs/html/sdk/installing/bundle.jd deleted file mode 100644 index 22bdd117ae24..000000000000 --- a/docs/html/sdk/installing/bundle.jd +++ /dev/null @@ -1,3 +0,0 @@ -page.title=Setting Up the ADT Bundle - -@jd:body diff --git a/docs/html/sdk/installing/create-project.jd b/docs/html/sdk/installing/create-project.jd deleted file mode 100644 index a4de85ceb7e2..000000000000 --- a/docs/html/sdk/installing/create-project.jd +++ /dev/null @@ -1,377 +0,0 @@ -page.title=Managing Projects with Android Studio - -@jd:body - - <div id="qv-wrapper"> - <div id="qv"> - <h2>In this document</h2> - - <ol> - <li><a href="#CreatingAProject">Creating an Android Project</a></li> - - <li><a href="#CreatingAModule">Creating an Android Module</a></li> - - <li><a href="#SettingUpLibraryModule">Setting up a Library Module</a></li> - - <li><a href="#ReferencingLibraryModule">Referencing a Library Module</a></li> - - <li><a href="#ReferencingAppEngModule">Setting up an App Eng Module</a></li> - - <li><a href="#ProjectView">Using the Android Project View</a></li> - - </ol> - - </div> - </div> - - -<p>Android Studio provides graphical tools for creating and managing Android projects, which -contain everything that define your Android apps, from app source code to build configurations and -test code. Each project contains one or more different types of modules, such as - application modules, library modules, and test modules.</p> - -<p>This guide explains how to create Android projects and different modules using -<a href="{@docRoot}tools/studio/index.html">Android Studio</a>. -For more information about the Android project structure and module types, read <a href= -"{@docRoot}tools/projects/index.html">Managing Projects Overview</a>.</p> - - - -<h2 id="CreatingAProject">Creating an Android Project</h2> - -<p>Android Studio makes it easy to create Android apps for several form factors, such as phone, -tablet, TV, Wear, and Google Glass. The <em>New Project</em> wizard lets you choose the form factors -for your app and populates the project structure with everything you need to get started.</p> - -<p>Follow the steps in this section to create a project in Android Studio.</p> - -<h3 id="Step1CreatingAProject">Step 1: Create a New Project</h2> - -<p>If you didn't have a project opened, Android Studio shows the Welcome screen. -To create a new project, click <strong>New Project</strong>.</p> - -<p>If you had a project opened, Android Studio shows the development environment. -To create a new project, click <strong>File</strong> > <strong>New Project</strong>.</p> - -<p>The next window lets you configure the name of your app, the package name, and the location -of your project.</p> - -<img src="{@docRoot}images/tools/wizard2.png" alt="" width="500" height="381"> -<p class="img-caption"><strong>Figure 1.</strong> Choose a name for your project.</p> - -<p>Enter the values for your project then click <strong>Next</strong>.</p> - -<h3 id="Step2SelectFormFactor">Step 2: Select Form Factors and API Level</h2> - -<p>The next window lets you select the form factors supported by your app, such as phone, tablet, -TV, Wear, and Google Glass. The selected form factors become the application modules within the -project. For each form factor, you can also select the API Level for that app. To get more information, -click <strong>Help me choose</strong>.</p> - -<img src="{@docRoot}images/tools/wizard4.png" alt="" width="750" height="510"> -<p class="img-caption"><strong>Figure 2.</strong> Select the API Level.</p> - -<p>The API Level window shows the distribution of mobile devices running each version of Android, -as shown in figure 3. Click on an API level to see a list of features introduced in the corresponding -version of Android. This helps you choose the minimum API Level that has all the features that -your apps needs, so you can reach as many devices as possible. Then click <strong>OK</strong>.</p> - -<img src="{@docRoot}images/tools/wizard3.png" alt="" width="500" height="480"> -<p class="img-caption"><strong>Figure 3.</strong> Choose form factors for your app.</p> - -<p>Then, on the Form Factors Window, click <strong>Next</strong>.</p> - - -<h3 id="Step3AddActivity">Step 3: Add an Activity</h2> - -<p>The next screen lets you select an activity type to add to your app, as shown in figure 4. -This screen displays a different set of activities for each of the form factors you selected earlier.</p> - -<img src="{@docRoot}images/tools/wizard5.png" alt="" width="720" height="504"> -<p class="img-caption"><strong>Figure 4.</strong> Add an activity to your app.</p> - -<p>Choose an activity type then click <strong>Next</strong>.</p> - - <p class="note"><strong>Note:</strong> If you choose "Add No Activity", click <strong>Finish</strong> - to create the project.</p> - - -<h3 id="Step4ConfigureActivity">Step 4: Configure Your Activity</h2> - -<p>The next screen lets you configure the activity to add to your app, as shown in figure 5.</p> - -<img src="{@docRoot}images/tools/wizard6.png" alt="" width="450" height="385"> -<p class="img-caption"><strong>Figure 5.</strong> Choose a name for your activity.</p> - -<p>Enter the activity name, the layout name, and the activity title. Then click -<strong>Finish</strong>.</p> - - -<h3 id="Step5DevelopYourApp">Step 5: Develop Your App</h2> - -<p>Android Studio creates the default structure for your project and opens the development -environment. If your app supports more than one form factor, Android Studio creates a module folder -with complete source files for each of them as shown in figure 6.</p> - -<img src="{@docRoot}images/tools/wizard7.png" alt="" width="750" height="509"> -<p class="img-caption"><strong>Figure 6.</strong> The default project structure for a mobile app.</p> - -<p>Now you are ready to develop your app. For more information, see the following links:</p> - -<ul> -<li><a href="{@docRoot}training/">Training Lessons</a></li> -<li><a href="{@docRoot}training/building-wearables.html">Building Apps for Wearables</a></li> -<li><a href="{@docRoot}tv/">Android TV</a></li> -<li><a href="https://developers.google.com/glass/">Google Glass</a></li> -</ul> - - - <h2 id="CreatingAModule">Creating an Android Module</h2> - - <p>Android application modules contain the <code>src/main/</code>, <code>AndroidManifest.xml</code>, - <code>build.gradle</code>, build output and other files you need to generate your app's APK files. - Android Studio provides a <em>New Module Wizard</em> that you can use to quickly create a new - Android module (or a module from existing code) based on selected application settings, such as - minimum SDK level and activity template.</p> - - <p>To create a new module, select <strong>File</strong> > <strong>New</strong> > - <strong>Module</strong>. Select the desire module type then click Next to enter the basic module - settings:</p> - - <ul> - <li>Enter an <strong>Application Name</strong>. This name is used as the title of your - application launcher icon when it is installed on a device.</li> - - <li>Enter a <strong>Module Name</strong>. This text is used as the name of the folder where - your Java-based activity files are stored.</li> - - <li>Enter a <strong>Package Name</strong> and <strong>Package Location</strong>. This class - package namespace creates the initial - package structure for your applications code files and is added as the - <a href="{@docRoot}guide/topics/manifest/manifest-element.html#package">{@code package}</a> - attribute in your application's - <a href="{@docRoot}guide/topics/manifest/manifest-intro.html">Android manifest file</a>. - This manifest value serves as the unique identifier for your application app when you - distribute it to users. The package name must follow the same rules as packages in the Java - programming language.</li> - - <li>Select the <strong>Minimum required SDK</strong>. - This setting indicates the lowest version of the Android platform that your application - supports for the selected form factor. This value sets the - <code>minSdkVersion</code> attribute in the build.gradle file.</li> - - <p class="note"><strong>Note:</strong> You can manually change the minimum and target SDK - for your module at any time: Double-click the module's build.gradle in the Project Explorer, - set the <strong>targetSdkVersion</strong> and <em>targetSdkVersion</em> in the - <em>defaultConfig</em> section.</p> - - - <li>Select a <strong>Target SDK</strong>. This setting indicates the highest version of - Android with which you have tested with your application and sets the - <a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code - targetSdkVersion}</a> attribute in your application's' build.gradle file. - - - <li>Select a <strong>Compile With</strong> API version. This setting specifies what version - of the SDK to compile your project against. We strongly recommend using the most recent - version of the API.</li> - - <li>Select a <strong>Language Level</strong> API version. This setting specifies what version - of the SDK to compile your project against. We strongly recommend using the most recent - version of the API.</li> - - <li>Select a <strong>Theme</strong>. This setting specifies which standard Android - <a href="{@docRoot}design/style/themes.html">visual style</a> is applied to your - application. Select activity template. For more information about Android code templates, see - <a href="{@docRoot}tools/projects/templates.html">Using Code Templates</a>. Leave the - <strong>Create activity</strong> option checked so you can start your - application with some essential components. </li> - - <li>Click the check box for the required Support Libraries then click <strong>Next</strong>.</li> - - <li>In the <strong>Configure Launcher Icon</strong> page, create an icon and options, then click - <strong>Next</strong>.</li> - - <li>In the <strong>Create Activity</strong> page, select activity template then click - <strong>Next</strong>. For more information about Android code templates, see - <a href="{@docRoot}tools/projects/templates.html">Using Code Templates</a>. - </li> - - <li>Review the new module settings then click <strong>Finish</strong>.</li> - - </ul> - - <p>The wizard creates a new Android application module according to the options you have chosen.</p> - - - - <h2 id="SettingUpLibraryModule">Setting up a Library Module</h2> - - <p>A library module is a standard Android module, so you can create a new one in the same way - as you would a new application module, using the New Module wizard and selecting <em>Android - Library</em> as the module type. The created library module will appear in your project view - along with the other modules. </p> - - <p> You can easily change an existing application module to a library module by changing the - plugin assignment in the <strong>build.gradle</strong> file to <em>com.android.library</em>.</p> - -<pre> -apply plugin: 'com.android.application' - -android {...} -</pre> - -<pre> -apply plugin: 'com.android.library' - -android {...} -</pre> - - - <h3>Adding a dependency on a library module</h3> - - <p>The library dependency can be declared in the module's manifest file or in the - <strong<build.gradle</strong> file. </p> - - <p>A library modules's manifest file must declare all of the shared components that it includes, - just as would a standard Android application. For more information, see the documentation for - <a href="{@docRoot}guide/topics/manifest/manifest-intro.html">AndroidManifest.xml</a>.</p> - - <p>For example, the <a href= - "{@docRoot}resources/samples/TicTacToeLib/AndroidManifest.html">TicTacToeLib</a> example library - project declares the activity <code>GameActivity</code>:</p> - <pre> -<manifest> - ... - <application> - ... - <activity android:name="GameActivity" /> - ... - </application> -</manifest> -</pre> - - -<p>To add the dependency declaration to the build file, edit the build file for the <code>app</code> -module (<code>app/build.gradle</code>) and add a dependency on the <code>lib</code> module:</p> - -<pre> -... -dependencies { - ... - compile project(":lib") -} -</pre> - -<p>In this example, the <code>lib</code> module can still be built and tested independently, and -the build system creates an AAR package for it that you could reuse in other projects.</p> - -<p class="note"><strong>Note:</strong> The library settings in the <code>app/build.gradle</code> -file will override any shared library resources declared in the manifest file.</p> - - - <h2 id="ReferencingLibraryModule">Referencing a library module</h2> - - <p>If you are developing an application and want to include the shared code or resources from a - library module, you can also do so easily by adding a reference to the library module in the - module's dependency page.</p> - - <p>To add a reference to a library module, follow these steps:</p> - - <ol> - <li>Make sure that both the module library and the application module that depends on it are - in your project. If one of the modules is missing, import it into your project.</li> - - <li>In the project view, right-click the dependent module and select - <strong>Open</strong> > <strong>Module Settings</strong>.</li> - - <li>Right-click the plus icon to add a new dependencies. - <p>If you are adding references to multiple libraries, you can set their relative - priority (and merge order) by selecting a library and using the <strong>Up</strong> and - <strong>Down</strong> controls. The tools merge the referenced libraries with your application - starting from lowest priority (bottom of the list) to highest (top of the list). If more than one - library defines the same resource ID, the tools select the resource from the library with higher - priority. The application itself has highest priority and its resources are always used in - preference to identical resource IDs defined in libraries.</p> - </li> - - <li>Use the <strong>Scope</strong> drop-down to select how the dependency will be applied.</li> - - <li>Click <strong>Apply</strong> to create the dependency and <strong>OK</strong> to close the - <strong>Project Structure</strong> window.</li> - </ol> - - <p>Android Studio rebuilds the module, including the contents of the library module the next time - the project or module is built.</p> - - - - <h3>Declaring library components in the manifest file</h3> - - <p>In the manifest file of the application module, you must add declarations of all components - that the application will use that are imported from a library module. For example, you must - declare any <code><activity></code>, <code><service></code>, - <code><receiver></code>, <code><provider></code>, and so on, as well as - <code><permission></code>, <code><uses-library></code>, and similar elements.</p> - - <p>Declarations should reference the library components by their fully-qualified package names, - where appropriate.</p> - - <p>For example, the <a href= - "{@docRoot}resources/samples/TicTacToeMain/AndroidManifest.html">TicTacToeMain</a> example - application declares the library activity <code>GameActivity</code> like this:</p> - <pre> -<manifest> - ... - <application> - ... - <activity android:name="com.example.android.tictactoe.library.GameActivity" /> - ... - </application> -</manifest> -</pre> - - <p>For more information about the manifest file, see the documentation for <a href= - "{@docRoot}guide/topics/manifest/manifest-intro.html">AndroidManifest.xml</a>.</p> - - - <h2 id="ProjectView">Using the Android Project View</h2> - - -<p>The Android project view in Android Studio shows a flattened version of your project's structure -that provides quick access to the key source files of Android projects and helps you work with -the new <a href="{@docRoot}sdk/installing/studio-build.html">Gradle-based build system</a>. The -Android project view:</p> - -<ul> -<li>Groups the build files for all modules at the top level of the project hierarchy.</li> -<li>Shows the most important source directories at the top level of the module hierarchy.</li> -<li>Groups all the manifest files for each module.</li> -<li>Shows resource files from all Gradle source sets.</li> -<li>Groups resource files for different locales, orientations, and screen types in a single group -per resource type.</li> -</ul> - -<p>The <em>Android</em> project view is enabled by default and shows all the build files at -the top level of the project hierarchy under <strong>Gradle Scripts</strong>. The project module -appears as a folder at the top level of the project hierarchy and contains these three elements -at the top level:</p> - -<ul> -<li><code>manifests/</code> - Manifest files for the module.</li> -<li><code>java/</code> - Source files for the module.</li> -<li><code>res/</code> - Resource files for the module.</li> -</ul> - -<p>Notice how the Android project view groups all instances of the -<code>ic_launcher.png</code> resource for different screen densities under the same element.</p> - -<p class="note"><strong>Note:</strong> The Android project view shows a hierarchy that helps you -work with Android projects by providing a flattened structure that highlights the most commonly -used files while developing Android applications. However, the project structure on disk differs -from this representation and maintains the traditional project structure.</p> - -<img src="{@docRoot}images/tools/projectview-p1.png" alt="" style="width:240px" "/> - -<img src="{@docRoot}images/tools/projectview-p2.png" alt="" style="width:240px" " /> -<p class="img-caption"><strong>Figure 10:</strong> Android and Traditional project view </p> diff --git a/docs/html/sdk/installing/index.jd b/docs/html/sdk/installing/index.jd deleted file mode 100644 index e4d860b085c1..000000000000 --- a/docs/html/sdk/installing/index.jd +++ /dev/null @@ -1,218 +0,0 @@ -page.title=Install Android Studio -excludeFromSuggestions=true - -page.tags=sdk tools - -@jd:body - -<style> -.instruction-select { - float:right; - background: #f7f7f7; - padding: 15px; - margin: -15px 0 20px 40px; -} -</style> - -<div class="instruction-select"> -<p><strong>Instructions for</strong></p> -<select id="instructions-option" onchange="showInstructions(this.value)" style="padding:4px"> - <option value="windows">Windows</option> - <option value="mac">Mac</option> - <option value="linux">Linux</option> -</select> -</div> - -<p>Setting up Android Studio takes just a few clicks.</p> - -<p>While the <a href="{@docRoot}sdk/index.html">Android Studio download</a> -completes, verify which version of the JDK you have: -open a command line and type <code>javac -version</code>. If the JDK -is not available or the version is lower than 1.8, download the <a href= -"http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html" -class="external-link">Java SE Development Kit 8</a>.</p> - - -<div id="system-windows" style="display:none"> - -<p>To install Android Studio on Windows, proceed as follows:</p> -<ol> - <li>Launch the <code>.exe</code> file you downloaded.</li> - <li>Follow the setup wizard to install Android Studio and any necessary SDK tools. - - <p>On some Windows systems, the launcher script does not find where the JDK is installed. - If you encounter this problem, - you need to set an environment variable indicating the correct location.</p> - <p>Select <strong>Start menu > Computer > System Properties > - Advanced System Properties</strong>. Then open <strong>Advanced tab > Environment - Variables</strong> and add a new system variable <code>JAVA_HOME</code> that points to - your JDK folder, for example <code>C:\Program Files\Java\jdk1.8.0_77</code>.</p> - </p> - </li> -</ol> - -<p>That's it! -The following video shows each step of the recommended setup procedure.</p> - -<video controls style="margin:20px 0" onclick="this.play()"> - <source src="https://storage.googleapis.com/androiddevelopers/videos/studio-install-windows.mp4" type="video/mp4"> -</video> - -<p>As new tools and other APIs become available, Android Studio tells you -with a pop-up, or you can check for updates by clicking <strong>Help > -Check for Update</strong>.</p> - - -</div> -<!-- end windows --> - - - -<!-- #### MAC INSTRUCTIONS #### --> - -<div id="system-mac" style="display:none"> - -<p>There are, however, known stability issues in Android Studio on Mac -when using JDK 1.8. Until these issues are resolved, you can improve stability -by downgrading your JDK to an older version (but no lower than JDK 1.6).</p> - -<p>To install Android Studio on your Mac, proceed as follows:</p> - -<ol> - <li>Launch the Android Studio DMG file.</li> - <li>Drag and drop Android Studio into the Applications folder, then launch - Android Studio.</li> - <li>Select whether you want to import previous Android Studio settings, - then click <strong>OK</strong>.</li> - <li>The Android Studio Setup Wizard guides you though the rest of the - setup, which includes downloading Android SDK components - that are required for development.</li> -</ol> - -<p>That's it! -The following video shows each step of the recommended setup procedure.</p> - -<video controls style="margin:20px 0" onclick="this.play()"> - <source src="https://storage.googleapis.com/androiddevelopers/videos/studio-install-mac.mp4" type="video/mp4"> -</video> - -<p> -As new tools and other APIs become available, Android Studio tells you -with a pop-up, or you can check for updates by clicking <strong>Android Studio -> Check for Updates</strong>.</p> - -</div> -<!-- end mac --> - - - -<!-- #### LINUX INSTRUCTIONS #### --> - -<div id="system-linux" style="display:none"> - - -<p>To install Android Studio on Linux, proceed as follows:</p> - -<ol> - <li>Unpack the <code>.zip</code> file you downloaded to an - appropriate location for your applications, such as within - <code>/usr/local/</code> for your user profile, or <code>/opt/</code> - for shared users. - <li>To launch Android Studio, open a terminal, - navigate to the <code>android-studio/bin/</code> directory, - and execute <code>studio.sh</code>. - <p><strong>Tip:</strong> - Add <code>android-studio/bin/</code> to your <code>PATH</code> environment - variable so you can start Android Studio from any directory.</p> - </li> - <li>Select whether you want to import previous Android Studio settings - or not, then click <strong>OK</strong>.</li> - <li>The Android Studio Setup Wizard guides you though the rest of the - setup, which includes downloading Android SDK components - that are required for development.</li> - </li> -</ol> - -<div class="note"> -<p><strong>Note:</strong> -If you are running a 64-bit version of Ubuntu, you need to install some 32-bit -libraries with the following command:</p> -<pre>sudo apt-get install lib32z1 lib32ncurses5 lib32bz2-1.0 lib32stdc++6</pre> -<p>If you are running 64-bit Fedora, the command is:</p> -<pre>sudo yum install zlib.i686 ncurses-libs.i686 bzip2-libs.i686</pre> -</div> - -<p>That's it! -The following video shows each step of the recommended setup procedure.</p> - -<video controls style="margin:20px 0" onclick="this.play()"> - <source src="https://storage.googleapis.com/androiddevelopers/videos/studio-install-linux.mp4" type="video/mp4"> -</video> - -<p>As new tools and other APIs become available, Android Studio tells you -with a pop-up, or you can check for updates by clicking <strong>Help > -Check for Update</strong>.</p> - -</div><!-- end linux --> - -<p class="note"><strong>Note:</strong> -If you want to develop apps with the N Preview SDK, you must use -the preview version of Android Studio 2.1. For more information, see the -<a href="{@docRoot}preview/setup-sdk.html">N Preview setup guide</a>.</p> - - - -<h2>Start building apps</h2> - -<div class="cols" style="padding:10px 0"> -<div class="col-2of6"> -<img src="{@docRoot}images/tools/studio/ic_devices_grey.png" - style="width:100%;background:#eee;margin:0" /> -<h3>Build your first app</h3> -<p>Get started quickly and learn the basics of Android by following -the guide to <strong><a href="{@docRoot}training/basics/firstapp/index.html" ->Building Your First App</a></strong>.</p> - -</div> -<div class="col-2of6"> -<img src="{@docRoot}images/tools/studio/ic_school_grey.png" - style="width:100%;background:#eee;margin:0" /> -<h3>Learn with Udacity</h3> -<p>Ramp up on Android with interactive video training in the -<strong><a href="https://www.udacity.com/course/developing-android-apps--ud853">Android Fundamentals Udacity course</a></strong>.</p> - -</div> -<div class="col-2of6"> -<img src="{@docRoot}images/tools/studio/ic_explore_grey.png" - style="width:100%;background:#eee;margin:0" /> -<h3>Explore Studio</h3> -<p>Discover powerful Android Studio features and developer strategies in the -<strong><a href="{@docRoot}tools/studio/index.html">Android Studio Introduction</a></strong>.</p> - -</div> -</div><!-- end cols --> - - -<script> -/** Show the appropriate instructions for user **/ -function showInstructions(system) { - $("[id^=system-]").hide(); // hide all of them first - if (system == "linux") { - $("#system-linux").show(); - } else if (system == "mac") { - $("#system-mac").show(); - } else { - $("#system-windows").show(); - } - $("select#instructions-option").val(system); -} - -// Get operating system based on the user agent, default windows -var os = "windows"; -if (navigator.appVersion.indexOf("Linux")!=-1) { - os = "linux"; -} else if (navigator.appVersion.indexOf("Mac")!=-1) { - os = "mac"; -} -showInstructions(os); -</script> diff --git a/docs/html/sdk/installing/migrate.jd b/docs/html/sdk/installing/migrate.jd deleted file mode 100644 index 61e6798dc0e5..000000000000 --- a/docs/html/sdk/installing/migrate.jd +++ /dev/null @@ -1,267 +0,0 @@ -page.title=Migrating from Eclipse ADT - -@jd:body - -<div id="qv-wrapper"> -<div id="qv"> - - -<h2>In this document</h2> -<ol> - <li><a href="#overview">Migration Overview</a></li> - <li><a href="#prerequisites">Migration Prerequisites</a></li> - <li><a href="#migrate">Importing Projects to Android Studio</a></li> - <li><a href="#post-migration">Validating imported projects</a></li> -</ol> - - -<h2>See also</h2> -<ul> - <li><a href="{@docRoot}tools/studio/eclipse-transition-guide.html"> - Transition Guide for Eclipse ADT</a></li> - <li><a href="http://confluence.jetbrains.com/display/IntelliJIDEA/FAQ+on+Migrating+to+IntelliJ+IDEA" - class="external-link">IntelliJ FAQ on migrating to IntelliJ IDEA</a></li> - <li><a href="http://confluence.jetbrains.com/display/IntelliJIDEA/IntelliJ+IDEA+for+Eclipse+Users" - class="external-link">IntelliJ IDEA for Eclipse users</a></li> - <li><a href="{@docRoot}tools/studio/index.html">Android Studio Overview</a></li> -</ul> -</div> -</div> - - -<p>Migrating from Eclipse ADT to Android Studio requires adapting to a new project structure, -build system, and IDE functionality. To simplify the migration process, Android Studio provides an -import tool so you can quickly transition your Eclipse ADT workspaces and Ant build scripts to -Android Studio projects and <a href="http://www.gradle.org">Gradle</a>-based build files.</p> - -<p>This document provides an overview of the migration process and walks you -through a sample import procedure. For more information about Android Studio features and the -Gradle-based build system, see <a href="{@docRoot}tools/studio/index.html">Android Studio Overview</a> -and <a href="{@docRoot}tools/building/configuring-gradle.html">Configuring Gradle Builds</a>.</p> - - - -<h2 id="overview">Migration Overview </h2> -<p>Migrating from Eclipse to Android Studio requires that you change the structure of your -development projects, move to a new build system, and use a new user interface. Here are some of -the key changes you should be aware of as you prepare to migrate to Android Studio:</p> -<ul> - <li><strong>Project files</strong> - <p>Android Studio uses a different project structure. Each Eclipse ADT - project is called a module in Android Studio. Each instance of Android - Studio contains a project with one or more app modules. For more information see, - <a href="{@docRoot}tools/studio/eclipse-transition-guide.html#project-structure">Project - Structure</a>.</p></li> - - <li><strong>Manifest settings</strong> - <p>Several elements in the <code>AndroidManifest.xml</code> file are now properties in the - <code>defaultConfig</code> and <code>productFlavors</code> blocks in the - <code>build.gradle</code> file. These elements are still valid manifest entries and may - appear in manifests from older projects, imported projects, dependencies, and libraries. For - more information see, - <a href="{@docRoot}tools/studio/eclipse-transition-guide.html#manifest-settings">Manifest - Settings</a>.</p></li> - - <li><strong>Dependencies</strong> - <p>Library dependencies are handled differently in Android Studio, using Gradle dependency - declarations and Maven dependencies for well-known local source and binary libraries with - Maven coordinates. For more information see, - <a href="{@docRoot}tools/studio/eclipse-transition-guide.html#dependencies">Dependencies</a></p> - </li> - - <li><strong>Test code</strong> - <p>With Eclipse ADT, test code is written in separate projects and integrated through the - <code><instrumentation></code> element in your manifest file. Android Studio provides a - <code>AndroidTest</code> folder within your project so you can easily add and maintain your test - code within the same project view. JUnit tests can also be configured to run locally to reduce - testing cycles.</p></li> - - <li><strong>Gradle-based build system</strong> - <p>In place of XML-based Ant build files, Android Studio supports Gradle build files, which - use the Gradle Domain Specific Language (DSL) for ease of extensibility and customization. - The Android Studio build system also supports - <a href="{@docRoot}tools/building/configuring-gradle.html#workBuildVariants"> build variants</a>, - which are combinations of <code>productFlavor</code> and <code>buildTypes</code>, to customize - your build outputs.</p></li> - - <li><strong>User interface</strong> - <p>Android Studio provides an intuitive interface and menu options based on the - <a class="external-link" href="https://www.jetbrains.com/idea/" target="_blank">IntelliJ IDEA</a> - IDE. To become familiar with the IDE basics, such as navigation, code completion, and keyboard - shortcuts, see - <a class="external-link" href="https://www.jetbrains.com/idea/help/intellij-idea-quick-start-guide.html" - target="_blank">IntelliJ IDEA Quick Start Guide</a>.</p></li> - - <li><strong>Developer tools versioning</strong> - <p>Android Studio updates independently of the Gradle-based build system so different build - settings can be applied across different versions of command line, Android Studio, and - continuous integration builds. For more information, see - <a href="{@docRoot}tools/building/configuring-gradle.html">Configuring Gradle Builds</a>.</p> - </li> -</ul> - - - - -<h2 id="prerequisites">Migration Prerequisites</h2> -<p>Before migrating your Eclipse ADT app to Android Studio, review the following steps to make -sure your project is ready for conversion, and verify you have the tool configuration you need in -Android Studio:</p> - -<ul> - <li>In Eclipse ADT: - <ul> - <li>Make sure the Eclipse ADT root directory contains the <code>AndroidManifest.xml</code> - file. Also, the root directory must contain either the <code>.project</code> and - <code>.classpath</code> files from Eclipse or the <code>res/</code> and <code>src/</code> - directories.</li> - <li>Build your project to ensure your latest workspace and project updates are saved and - included in the import.</li> - <li>Comment out any references to Eclipse ADT workspace library files in the - <code>project.properties</code> or <code>.classpath</code> files for import. You can - add these references in the <code>build.gradle</code> file after the import. For more - information, see - <a href="{@docRoot}tools/building/configuring-gradle.html">Configuring Gradle Builds</a>.</li> - <li>It may be useful to record your workspace directory, path variables, and any actual path - maps that could be used to specify any unresolved relative paths, path variables, and - linked resource references. Android Studio allows you to manually specify any unresolved - paths during the import process.</li> - </ul> - </li> - <li>In Android Studio: - <ul> - <li>Make a note of any third-party Eclipse ADT plugins in use and check for equivalent features - in Android Studio or search for a compatible plugin in the - <a href="https://plugins.jetbrains.com/?androidstudio" class="external-link">IntelliJ Android - Studio Plugins</a> repository. Use the <strong>File > Settings > Plugins</strong> menu - option to manage plugins in Android Studio. Android Studio does not migrate any third-party - Eclipse ADT plugins.</li> - <li>If you plan to run Android Studio behind a firewall, be sure to set the proxy settings for - Android Studio and the SDK Manager. Android Studio requires an internet connection for - Setup Wizard synchronization, 3rd-party library access, access to remote repositories, - <a href="http://www.gradle.org" class="external-link">Gradle</a> - initialization and synchronization, and Android Studio version updates. For more information, - see <a href="{@docRoot}tools/studio/index.html#proxy">Proxy Settings</a>.</li> - <li>Use the <strong>File > Settings > System Settings</strong> menu option to verify the - current version and, if necessary, update Android Studio to the latest version from the - stable channel. To install Android Studio, please visit the - <a href="{@docRoot}sdk/index.html">Android Studio download page</a>.</li> - </ul> - </li> - </ul> - - - -<h2 id="migrate">Importing Projects to Android Studio</h2> -<p>Android Studio provides a function for importing Eclipse ADT projects, which creates a new -Android Studio project and app modules based on your current -Eclipse ADT workspace and projects. No changes are made to your Eclipse project files. The Eclipse -ADT workspace becomes a new Android Studio project, and each Eclipse ADT project within the workspace -becomes a new Android Studio module. Each instance of Android Studio contains a project with one or -more app modules.</p> - -<p>After selecting an Eclipse ADT project to import, Android Studio creates the Android -Studio project structure and app modules, generates the new Gradle-based build files and settings, -and configures the required dependencies. The import options also allow you to enter your workspace -directory and any actual path maps to handle any unresolved relative paths, path variables, and -linked resource references.</p> - -<p>Depending on the structure of your Eclipse ADT development project, you should select specific -files for importing:</p> -<ul> -<li>For workspaces with multiple projects, select the project folder for each Eclipse ADT - project individually to import the projects into the same Android Studio project. Android - Studio combines the Eclipse ADT projects into a single Android Studio project with different app - modules for each imported project.</li> - -<li>For Eclipse ADT projects with separate test projects, select the test project folder for - import. Android Studio imports the test project and then follows the dependency chain to import - the source project and any project dependencies.</li> - - <li>If Eclipse ADT projects share dependencies within the same workspace, import each - project individually into Android Studio. Android Studio maintains the shared dependencies - across the newly created modules as part of the import process.</li> -</ul> - -<p>To import a project to Android Studio:</p> - -<ol> - <li>Start Android Studio and close any open Android Studio projects.</li> - <li>From the Android Studio menu select <strong>File > New > Import Project</strong>. - <p>Alternatively, from the <em>Welcome</em> screen, select <strong>Import project - (Eclipse ADT, Gradle, etc.)</strong>.</p></li> - <li>Select the Eclipse ADT project folder with the <code>AndroidManifest.xml</code> file - and click <strong>Ok</strong>. - <p> <img src="{@docRoot}images/tools/studio-select-project-forimport.png" alt="" /></p> - </li> - <li>Select the destination folder and click <strong>Next</strong>. - <p> <img src="{@docRoot}images/tools/studio-import-destination-dir.png" alt="" /></p></li> - <li>Select the import options and click <strong>Finish</strong>. - <p>The import process prompts to migrate any library and project dependencies to Android Studio, - and add the dependency declarations to the <code>build.gradle</code> file. The import process - also replaces any well-known source libraries, binary libraries, and JAR files that have known - Maven coordinates with Maven dependencies, so you no longer need to maintain these dependencies - manually. The import options also allow you to enter your workspace directory and any actual - path maps to handle any unresolved relative paths, path variables, and linked resource - references.</p> - <p> <img src="{@docRoot}images/tools/studio-import-options.png" alt="" /></p></li> - - <li>Android Studio imports the app and displays the project import summary. Review the summary - for details about the project restructuring and the import process. - <p> <img src="{@docRoot}images/tools/studio-import-summary.png"/></p> - </li> -</ol> - -<p>After importing the project from Eclipse ADT to the new Android Studio project and module -structure, each app module folder in Android Studio contains the complete source set for that -module, including the {@code src/main} and {@code src/androidTest} directories, resources, build -file, and Android manifest. Before starting app development, you should resolve any issues shown in -the project import summary to make sure the project re-structuring and import process completed -properly.</p> - - - -<h3 id="post-migration">Validating imported projects</h3> -<p>After completing the import process, use the Android Studio <strong>Build</strong> and -<strong>Run</strong> menu options to build your project and verify the output. If your project -is not building properly, check the following settings:</p> - -<ul> -<ul> - <li>Use the <strong>Android SDK</strong> button in Android Studio to launch the <a href= - "{@docRoot}tools/help/sdk-manager.html">SDK Manager</a> and verify the installed versions of SDK - tools, build tools, and platform match the settings for your Eclipse ADT project. Android Studio - inherits the SDK Manager and JDK settings from your imported Eclipse project. - </li> - <li>Use the <strong>File > Project Structure</strong> menu option to verify additional - Android Studio settings: - <ul> - <li>Under <em>SDK Location</em> verify Android Studio has access to the correct SDK and - JDK locations and versions. </li> - <li>Under <em>Project</em> verify the Gradle version, Android Plugin version, and related - repositories.</li> - <li>Under <em>Modules</em> verify the app and module settings, such as signing configuration - and library dependencies. </li> - </ul> - </li> - <li>If your project depends on another project, make sure that dependency is defined properly in - the <code>build.gradle</code> file in the app module folder.</li> -</ul> - - -<p>If there still are unexpected issues when building and running your project in Android -Studio after you have checked these settings, consider modifying the Eclipse ADT project and -re-starting the import process. Importing an Eclipse ADT project to Android Studio creates a new -Android Studio project and does not impact the existing Eclipse ADT project. </p> - - - -<p>To get started using Android Studio, review the -<a href="{@docRoot}tools/studio/index.html">Android Studio</a> features and -<a href="http://www.gradle.org">Gradle</a>-based build system to become familiar with the new -project and module structure, flexible build settings, and other advanced Android development -capabilities. For a comparison of Eclipse ADT and Android Studio features and usage, see -<a href="{@docRoot}tools/studio/eclipse-transition-guide.html">Transitioning to Android Studio from -Eclipse</a>. For specific Android Studio how-to documentation, see the pages in the -<a href="{@docRoot}tools/workflow/index.html">Workflow</a> section. -</p> diff --git a/docs/html/sdk/installing/studio-androidview.jd b/docs/html/sdk/installing/studio-androidview.jd deleted file mode 100644 index 09aeabad9158..000000000000 --- a/docs/html/sdk/installing/studio-androidview.jd +++ /dev/null @@ -1,55 +0,0 @@ -page.title=Using the Android Project View - -@jd:body - - -<p>The Android project view in Android Studio shows a flattened version of your project's structure -that provides quick access to the key source files of Android projects and helps you work with -the new <a href="{@docRoot}sdk/installing/studio-build.html">Gradle-based build system</a>. The -Android project view:</p> - -<ul> -<li>Groups the build files for all modules at the top level of the project hierarchy.</li> -<li>Shows the most important source directories at the top level of the module hierarchy.</li> -<li>Groups all the manifest files for each module.</li> -<li>Shows resource files from all Gradle source sets.</li> -<li>Groups resource files for different locales, orientations, and screen types in a single group -per resource type.</li> -</ul> - -<div style="float:right;margin-left:30px;width:240px"> -<img src="{@docRoot}images/tools/projectview01.png" alt="" width="220" height="264"/> -<p class="img-caption"><strong>Figure 1:</strong> Show the Android project view.</p> -</div> - - -<h2 id="enable-view">Enable the Android Project View</h2> - -<p>The Android project view is not yet enabled by default. To show the Android project view, -click <strong>Project</strong> and select <strong>Android</strong>, as shown in Figure 1.</p> - - -<h2 id="project-view">Use the Android Project View</h2> - -<p>The Android project view shows all the build files at the top level of the project hierarchy -under <strong>Gradle Scripts</strong>. Each project module appears as a folder at the top -level of the project hierarchy and contains these three elements at the top level:</p> - -<ul> -<li><code>java/</code> - Source files for the module.</li> -<li><code>manifests/</code> - Manifest files for the module.</li> -<li><code>res/</code> - Resource files for the module.</li> -</ul> - -<p>Figure 2 shows how the Android project view groups all the instances of the -<code>ic_launcher.png</code> resource for different screen densities under the same element.</p> - -<p class="note"><strong>Note:</strong> The Android project view shows a hierarchy that helps you -work with Android projects by providing a flattened structure that highlights the most commonly -used files while developing Android applications. However, the project structure on disk differs -from this representation.</p> - -<img src="{@docRoot}images/tools/projectview03.png" alt="" - style="margin-top:10px" width="650" height="508"/> -<p class="img-caption"><strong>Figure 2:</strong> The traditional project view (left) and the -Android project view (right).</p>
\ No newline at end of file diff --git a/docs/html/sdk/installing/studio-build.jd b/docs/html/sdk/installing/studio-build.jd deleted file mode 100755 index 6464b28e893e..000000000000 --- a/docs/html/sdk/installing/studio-build.jd +++ /dev/null @@ -1,104 +0,0 @@ -page.title=Build System Overview - -@jd:body - -<div id="qv-wrapper"> -<div id="qv"> -<h2>In this document</h2> -<ol> - <li><a href="#detailed-build">A Detailed Look at the Build Process</a> </li> -</ol> -<h2>See also</h2> -<ul> - <li><a href="{@docRoot}sdk/installing/studio.html"> - Getting Started with Android Studio</a></li> - <li><a href="{@docRoot}tools/studio/index.html">Android Studio Basics</a></li> -</div> -</div> - -<a class="notice-developers-video" href="https://www.youtube.com/watch?v=LCJAgPkpmR0#t=504"> -<div> - <h3>Video</h3> - <p>The New Android SDK Build System</p> -</div> -</a> - -<p>The Android build system is the toolkit you use to build, test, run and package -your apps. The build system can run as an integrated tool from the Android Studio menu and -independently from the command line. You can use the features of the build system to:</p> - -<ul> - <li>Customize, configure, and extend the build process.</li> - <li>Create multiple APKs for your app with different features using the same project and - modules.</li> - <li>Reuse code and resources across source sets.</li> -</ul> - -<p>The flexibility of the Android build system enables you to achieve all of this without -modifying your app's core source files. To build an Android Studio project, see -<a href="{@docRoot}tools/building/building-studio.html">Building and Running from Android Studio</a>. -To configure custom build settings in an Android Studio project, see -<a href="{@docRoot}tools/building/configuring-gradle.html">Configuring Gradle Builds</a>.</p> - - -<h2 id="detailed-build">A Detailed Look at the Build Process</h2> - -<p>The build process involves many tools and processes that generate intermediate files on the -way to producing an <code>.apk</code>. If you are developing in Android Studio, the complete build -process is done every time you run the Gradle build task for your project or modules. The build -process is very flexible so it's useful, however, to understand what is happening under the hood -since much of the build process is configurable and extensible. The following diagram depicts the -different tools and processes that are involved in a build:</p> - - <img src="{@docRoot}images/build.png" /> - -<p>The general process for a typical build is outlined below. The build system merges all the -resources from the configured product flavors, build types, and dependencies. If different -folders contain resources with the same name or setting, the following override priority order is: -dependencies override build types, which override product flavors, which override the main source -directory.</p> - - <ul> - - <li>The Android Asset Packaging Tool (aapt) takes your application resource files, such as the - <code>AndroidManifest.xml</code> file and the XML files for your Activities, and compiles them. - An <code>R.java</code> is also produced so you can reference your resources from your Java code.</li> - - <li>The aidl tool converts any <code>.aidl</code> interfaces that you have into Java interfaces.</li> - - <li>All of your Java code, including the <code>R.java</code> and <code>.aidl</code> files, are - compiled by the Java compiler and .class files are output.</li> - - <li>The dex tool converts the .class files to Dalvik byte code. Any 3rd party libraries and - .class files that you have included in your module build are also converted into <code>.dex</code> - files so that they can be packaged into the final <code>.apk</code> file.</li> - - <li>All non-compiled resources (such as images), compiled resources, and the .dex files are - sent to the apkbuilder tool to be packaged into an <code>.apk</code> file.</li> - - <li>Once the <code>.apk</code> is built, it must be signed with either a debug or release key - before it can be installed to a device.</li> - - <li>Finally, if the application is being signed in release mode, you must align the - <code>.apk</code> with the zipalign tool. Aligning the final <code>.apk</code> decreases memory - usage when the application is -running on a device.</li> - </ul> - -<p class="note"><b>Note:</b> Apps are limited to a 64K method reference limit. If your app reaches -this limit, the build process outputs the following error message: - -<pre>Unable to execute dex: method ID not in [0, 0xffff]: 65536.</pre> - -To avoid this error, see -<a href="{@docRoot}tools/building/multidex.html">Building Apps with Over 64K Methods</a>. -</p> - - -<h3>Build output</h3> - -<p>The build generates an APK for each build variant in the <code>app/build</code> folder: -the <code>app/build/outputs/apk/</code> directory contains packages named -<code>app-<flavor>-<buildtype>.apk</code>; for example, <code>app-full-release.apk</code> and -<code>app-demo-debug.apk</code>.</p> - - diff --git a/docs/html/sdk/installing/studio-layout.jd b/docs/html/sdk/installing/studio-layout.jd deleted file mode 100644 index 60cbcb322cee..000000000000 --- a/docs/html/sdk/installing/studio-layout.jd +++ /dev/null @@ -1,157 +0,0 @@ -page.title=Using the Layout Editor - -@jd:body - -<div id="qv-wrapper"> -<div id="qv"> -<h2>See also</h2> -<ul> -<li><a href="{@docRoot}sdk/installing/studio.html"> -Getting Started with Android Studio</a></li> -<li><a href="{@docRoot}sdk/installing/studio-tips.html"> -Android Studio Tips and Tricks</a></li> -<li><a href="{@docRoot}sdk/installing/migrate.html"> -Migrating from Eclipse</a></li> -</div> -</div> - -<a class="notice-developers-video" -href="https://developers.google.com/events/io/sessions/324603352"> -<div> - <h3>Video</h3> - <p>What's New in Android Developer Tools</p> -</div> -</a> - -<p>Android Studio offers an advanced layout editor that allows you to drag-and-drop widgets -into your layout and preview your layout while editing the XML.</p> - -<p>Within the layout editor, you can switch between the <strong>Text</strong> view, where -you edit the XML file as text, and the <strong>Design</strong> view. Just click the -appropriate tab at the bottom of the window to display the desired editor.</p> - -<h2>Editing in the Text View</h2> - -<p>You can use the <strong>Text</strong> view to edit your layout file. This section describes -some of the features that are available in the <strong>Text</strong> view.</p> - -<h3>Preview</h3> - -<p>While editing in the <strong>Text</strong> view, you can preview the layout on devices -by opening the <strong>Preview</strong> pane available on the right side of the window. -Within the <strong>Preview</strong> pane, you can modify the preview by changing various -options at the top of the pane, including the preview device, layout theme, platform -version and more. To see a preview of how your app would look with a particular device -skin, click the preview icon -<img src="{@docRoot}images/tools/as-preview-icon.png" style="vertical-align:bottom;margin:0;height:19px" /> -and choose the desired device, such as Nexus 4:</p> - -<img src="{@docRoot}images/tools/as-preview-chrome.png" alt="" /> -<p class="img-caption"><strong>Figure 1.</strong> Previewing your app.</p> - -<p>To preview the layout on multiple devices simultaneously, select <strong>Preview All -Screen Sizes</strong> from the device drop-down. </p> - -<p>When you click in the preview image, the layout editor highlights the corresponding -section in the XML, and vice-versa.</p> - -<h3>Interactive error detection and recovery</h3> - -<p>As you edit the <strong>Text</strong> view of your layout XML file, Android Studio flags -typos and offers assistance.</p> - -<p>For example, suppose you are adding a button, and you misspell it as "Buttonn". -Android Studio helps you to correct it by displaying an error such as the following, -where you can click on "Change to Button" to fix the error in the XML file:</p> - -<img src="{@docRoot}images/tools/as-error.png" alt="" /> - -<p class="img-caption"><strong>Figure 2.</strong> Flagging errors.</p> - -<p>Android Studio also prompts you to supply missing information. For example, suppose you -start adding a fragment to your layout XML file. First of all, Android Studio displays -auto-complete suggestions as you type. Once it becomes clear that you are adding a fragment, -Android Studio displays an error panel with links that you can click to supply the missing -attributes. Clicking "Automatically add all missing attributes" in this case -does just that—it completes the fragment definition in your layout XML file:</p> - -<img src="{@docRoot}images/tools/as-frag-ex.png" alt="" /> - -<p class="img-caption"><strong>Figure 3.</strong> Supplying missing information</p> - -<h3>Picking a theme</h3> - -<p>To pick a theme for your app, click the Theme icon -<img src="{@docRoot}images/tools/as-theme-icon.png" style="vertical-align:bottom;margin:0;height:19px" />. -</p> - -<p>This displays the <strong>Select Theme</strong> dialog, where you can search for a -particular theme and/or select one from the list on the right hand side. The theme you -choose will be reflected in the previewed image.</p> - -<img src="{@docRoot}images/tools/as-theme-db.png" alt="" /> - -<p class="img-caption"><strong>Figure 4.</strong> Specifying a theme.</p> - -<h3>Localization</h3> - -<p>Android Studio provides built-in localization support. When you click the -localization icon -<img src="{@docRoot}images/tools/as-i18n-icon.png" style="vertical-align:bottom;margin:0;height:19px" />, -you can select a particular locale, add and edit translations, preview the locales your -app supports (all locales or just a single locale), and preview right-to-left layout for -languages that are RTL.</p> - -<p>See <a href="{@docRoot}training/basics/supporting-devices/languages.html">Supporting -Different Languages</a> for a description of how to support different locales in your app.</p> -<p>For example, here is a preview of a "Hello World" app for the -<img src="{@docRoot}images/tools/as-fr-icon.png" style="vertical-align:bottom;margin:0;height:19px" /> -locale:</p> - -<img src="{@docRoot}images/tools/as-fr-device.png" alt="" /> -<p class="img-caption"><strong>Figure 5.</strong> Previewing locales.</p> - -<h2>Editing in the Design View</h2> - -<p>You can switch to the graphical editor by clicking <strong>Design</strong> at the -bottom of the window. While editing in the <strong>Design</strong> view, you can show and -hide the widgets available to drag-and-drop by clicking <strong>Palette</strong> on the -left side of the window. Clicking <strong>Designer</strong> on the right side of the -window reveals a panel with a layout hierarchy and a list of properties for each view in -the layout.</p> - -<p>When you drag a widget into the graphical layout for your app, the display changes to -help you place the widget. What you see depends on the type of layout. For example, if -you're dragging a widget into a {@link android.widget.FrameLayout}, it displays a grid to -help you place the widget, as shown in figure 6:</p> - -<img src="{@docRoot}images/tools/as-grid-layout.png" alt="" /> - -<p class="img-caption"><strong>Figure 6.</strong> Using the grid layout to place a widget.</p> - -<p>Within the graphical editor, you can rearrange your app's UI by dragging widgets to -the desired location.</p> - -<h3>Multi-API Version Rendering</h3> - -<p>Android Studio supports multi-API version rendering. When you click the Android version icon <img src="{@docRoot}images/tools/as-api-level-preview.png" style="vertical-align:bottom;margin:0;height:19px" /> in the <b>Design</b> view, -Android Studio allows you to preview your Android layouts across multiple Android API levels. -</p> - -<p><img src="{@docRoot}images/tools/studio-api-version-rendering.png" /></p> - <p class="img-caption"><strong>Figure 7.</strong> Multi-API version rendering.</p> - -<h3>Taking a snapshot</h3> - -<p>When you run your app on a connected device, you can take a snapshot of it by clicking -the camera icon -<img src="{@docRoot}images/tools/as-camera-icon.png" style="vertical-align:bottom;margin:0;height:19px" /> -to the left of the logging -panel (at the bottom of the window by default). This takes a snapshot of your running app -(or whatever is currently displayed on your device) and displays it in a window. Check -<strong>Frame Screenshot</strong> to show your screenshot within the device skin of your -choice. You can also specify whether you want the image to have screen glare and/or a drop -shadow. Once you have the desired effect, you can save the image.</p> - -<p>You can use the same process to create a snapshot of your app's preview. Just click the -camera icon in the preview area and follow the steps for adding a device skin.</p> diff --git a/docs/html/sdk/installing/studio-tips.jd b/docs/html/sdk/installing/studio-tips.jd deleted file mode 100644 index 4cd6f8ce04bb..000000000000 --- a/docs/html/sdk/installing/studio-tips.jd +++ /dev/null @@ -1,342 +0,0 @@ -page.title=Android Studio Tips and Tricks -page.image=images/tools/studio-previewall.png -page.metaDescription=Tips to help you get started with Android Studio's most common tasks and productivity enhancements. -page.tags=studio,tips -meta.tags="studio", "tools" -@jd:body - -<div id="qv-wrapper"> -<div id="qv"> - - <h2>In this document</h2> - <ol> - <li><a href="#productivity-features">Productivity Shortcuts</a></li> - <li><a href="#intellij">Working with IntelliJ</a></li> - <li><a href="#key-commands">Key Commands</a></li> - </ol> - - <h2>See also</h2> - <ol> - <li><a href="{@docRoot}sdk/index.html">Download Android Studio</a></li> - <li><a href="http://wiki.jetbrains.net/intellij/Android">IntelliJ IDEA Android Tutorials</a></li> - <li><a href="http://confluence.jetbrains.com/display/IntelliJIDEA/FAQ+on+Migrating+to+IntelliJ+IDEA">IntelliJ FAQ on migrating to IntelliJ IDEA</a></li> - </ol> - -</div> -</div> - -<p>If you're unfamiliar with using Android Studio and the IntelliJ IDEA interface, this page -provides some tips to help you get started with some of the most common tasks and productivity -enhancements. </p> - - -<h2 id="productivity-features">Productivity Shortcuts</h2> - -<p>Android Studio includes a number of features to help you be more productive in your coding. -This section notes a few of the key features to help you work quickly and efficiently. -</p> - - -<h3>Smart Rendering</h3> -<p>With smart rendering, Android Studio displays links for quick fixes to rendering errors. -For example, if you add a button to the layout without specifying the <em>width</em> and -<em>height</em> attributes, Android Studio displays the rendering message <em>Automatically -add all missing attributes</em>. Clicking the message adds the missing attributes to the layout.</p> - - -<h3> Bitmap rendering in the debugger</h3> -<p>While debugging, you can now right-click on bitmap variables in your app and invoke -<em>View Bitmap</em>. This fetches the associated data from the debugged process and renders -the bitmap in the debugger. </p> -<p><img src="{@docRoot}images/tools/studio-bitmap-rendering.png" style="width:350px"/></p> -<p class="img-caption"><strong>Figure 1.</strong> Bitmap Rendering</p> - - -<h3>Creating new files</h3> -<p>You can quickly add new code and resource files by clicking the appropriate directory in the -<strong>Project</strong> pane and pressing <code>ALT + INSERT</code> on Windows and Linux or -<code>COMMAND + N</code> on Mac. Based on the type of directory selected, Android Studio -offers to create the appropriate file type.</p> - -<p>For example, if you select a layout directory, press <code>ALT + INSERT</code> on Windows, -and select <strong>Layout resource file</strong>, a dialog opens so you can name the file -(you can exclude the {@code .xml} suffix) and choose a root view element. The editor then -switches to the layout design editor so you can begin designing your layout.</p> - - -<h3>Output window message filtering</h3> -<p>When checking build results, you can filter messages by <em>message type</em> to quickly -locate messages of interest.</p> -<img src="{@docRoot}images/tools/studio-outputwindowmsgfiltering.png" style="width:200px"style="width:200px" /> -<p class="img-caption"><strong>Figure 2.</strong> Filter Build Messages</p> - - -<h3>Hierarchical parent setting</h3> -<p>The activity parent can now be set in the Activity Wizard when creating a new -activity. Setting a <em>hierarchal parent</em> sets the {@code Up} button to automatically -appear in the app's Action bar when viewing a child activity, so the {@code Up} -button no longer needs to be manually specified in the <em>menu.xml</em> file.</p> - - -<h3>Creating layouts</h3> -<p>Android Studio offers an advanced layout editor that allows you to drag-and-drop widgets -into your layout and preview your layout while editing the XML.</p> - -<p>While editing in the <strong>Text</strong> view, you can preview the layout on devices by -opening the <strong>Preview</strong> pane available on the right side of the window. Within the -Preview pane, you can modify the preview by changing various options at the top of the pane, -including the preview device, layout theme, platform version and more. To preview the layout on -multiple devices simultaneously, select <strong>Preview All Screen Sizes</strong> from the -device drop-down.</p> -<p><img src="{@docRoot}images/tools/studio-previewall.png" style="width:350px"/></p> -<p class="img-caption"><strong>Figure 3.</strong> Preview All Screens</p> - -<p>You can switch to the graphical editor by clicking <strong>Design</strong> at the -bottom of the window. While editing in the Design view, you can show and hide the -widgets available to drag-and-drop by clicking <strong>Palette</strong> on the left side of the -window. Clicking <strong>Designer</strong> on the right side of the window reveals a panel -with a layout hierarchy and a list of properties for each view in the layout.</p> - - -<h3>Annotations</h3> -<p>Android Studio provides coding assistance for using annotations from the -{@link android.support.annotation Support-Annotations} library, part of the -Support Repository. - -Adding a dependency for this library enables you to decorate your code with annotations to help -catch bugs, such as null pointer exceptions and resource type conflicts. You can also create -enumerated annotations to, for example, check that a passed parameter value matches a value from -a defined set of constants. For more information, see -<a href="{@docRoot}tools/debugging/annotations.html#annotations">Improving Code Inspection with -Annotations</a>. -</p> - - -<h3>Java class decompiling</h3> -<p>Android Studio allows you to look at what’s inside Java libraries when you don’t have access -to the source code. </p> - -<p>The decompiler is built into Android Studio for easy access. To use this feature, right-click -a class, method, or field from a library for which you do not have source file access and select -<strong>decompile</strong>.</p> The decompiled source code appears. </p> - -<p>To adjust the Java decompiler settings, select -<strong>File > Settings > Other Settings > Java Decompiler</strong>. </p> - - -<h3>Debugging and performance enhancements</h3> -<p>Android Studio offers debugging and performance enhancements such as:</p> -<ul> - <li>Custom keymaps. To modify the current keymap, choose - <strong>File > Settings > Keymap</strong>. </li> - <li>Support for high density (Retina) displays on Windows and Linux. </li> - <li>Scratch files for quick prototyping without creating any project files. - <p>Choose <strong>Tools > New Scratch File</strong> to open a scratch file to quickly - build and run code prototypes. Together with Android Studio coding assistance, scratch - files allow you to quickly run and debug code updates with the support of all file operations. - By embedding code created with scripting languages, you can run your code from within the - scratch file.</p> - </li> -</ul> - - -<h3 id="live-template">Live templates</h3> -<p>Live templates allow you to enter code snippets for fast insertion and completion of small chunks -of code. To insert a live template, type the template abbreviations and press the -Tab key. Android Studio inserts the code snippet associated with the template into -your code. </p> - -<p>For example, entering the <code>newInstance</code> abbreviation followed by the -Tab key inserts the code for a new fragment instance with argument placeholders. </p> - -<pre> -public static $fragment$ newInstance($args$) { - $nullChecks$ - Bundle args = new Bundle(); - $addArgs$ - $fragment$ fragment = new $fragment$(); - fragment.setArguments(args); - return fragment; -} -</pre> - -<p>Similarly, the <code>fbc</code> abbreviation inserts a <code>findViewById</code> call along -with cast and resource id syntax. </p> - -<pre> -() findViewById(R.id.); -</pre> - -<p>Use the <strong>File > Settings > Editor > Live Templates</strong> menu option to -display the full list of supported live templates and customize the inserted code. </p> - - - -<h2 id="intellij">Working with IntelliJ-based Coding Practices</h3> - -<p>This section list just a few of the code editing -practices you should consider using when creating Android Studio apps. </p> - -<p>For complete user documentation for the IntelliJ IDEA interface (upon which Android Studio -is based), refer to the -<a href="http://www.jetbrains.com/idea/documentation/index.jsp">IntelliJ IDEA documentation</a>.</p> - - -<h3><em>Alt + Enter</em> key binding</h3> -<p>For quick fixes to coding errors, the IntelliJ powered IDE implements the <em>Alt + Enter</em> -key binding to fix errors (missing imports, variable assignments, missing references, etc) when -possible, and if not, suggest the most probable solution. </p> - - -<h3><em>Ctrl + D</em> key binding</h3> -<p>The <em>Ctrl + D</em> key binding is great for quickly duplicating code lines or fragments. -Simply select the desired line or fragment and enter this key binding. </p> - - -<h3>Navigate menu</h3> -<p>In case you're not familiar with an API class, file or symbol, the <em>Navigate</em> menu lets -you jump directly to the class of a method or field name without having to search through -individual classes. </p> - - -<h3>Inspection scopes</h3> -<p>Scopes set the color of code segments for easy code identification and location. For example, -you can set a scope to identify all code related to a specific action bar. </p> - - -<h3>Injecting languages</h3> -<p>With language injection, the Android Studio IDE allows you to work with islands of different -languages embedded in the source code. This extends the syntax, error highlighting and coding -assistance to the embedded language. This can be especially useful for checking regular expression -values inline and validating XML.</p> - - -<h3>Code folding</h3> -<p>This allows you to selectively hide and display sections of the code for readability. For -example, resource expressions or code for a nested class can be folded or hidden in to one line -to make the outer class structure easier to read. The inner class can be later expanded for -updates. </p> - - -<h3>Image and color preview</h3> -<p>When referencing images and icons in your code, a preview of the image or icon appears -(in actual size at different densities) in the code margin to help you verify the image or icon -reference. Pressing {@code F1} with the preview image or icon selected displays resource asset -details, such as the <em>dp</em> settings. </p> - - -<h3>Quick F1 documentation</h3> -<p>You can now inspect theme attributes using <strong>View > Quick Documentation</strong> -(<strong>F1</strong>), -see the theme inheritance hierarchy, and resolve values for the various attributes.</p> - -<p>If you invoke <strong> View > Quick Documentation</strong> (usually bound to F1) on the theme -attribute <em>?android:textAppearanceLarge</em>, you will see the theme inheritance hierarchy and -resolved values for the various attributes that are pulled in.</p> - - - -<h3 id="key-commands">Keyboard Commands</h3> - -<p>The following tables list keyboard shortcuts for common operations.</p> - -<p class="note"><strong>Note:</strong> This section lists Android Studio keyboard shortcuts -for the default keymap. To change the default keymap on Windows and Linux, go to -<strong>File</strong> > <strong>Settings</strong> > <strong>Keymap</strong>. If you're -using Mac OS X, update your keymap to use the Mac OS X 10.5+ version keymaps under -<strong>Android Studio > Preferences > Keymap</strong>.</p> - - -<p class="table-caption"><strong>Table 1.</strong> Programming key commands</p> -<table> -<tr><th>Action</th><th>Android Studio Key Command</th></tr> - -<tr> - <td>Command look-up (autocomplete command name)</td> - <td>CTRL + SHIFT + A</td> -</tr> - -<tr> - <td>Project quick fix</td> - <td>ALT + ENTER</td> -</tr> - -<tr> - <td>Reformat code</td> - <td>CTRL + ALT + L (Win)<br> - OPTION + CMD + L (Mac)</td> -</tr> - -<tr> - <td>Show docs for selected API</td> - <td>CTRL + Q (Win)<br> - F1 (Mac)</td> -</tr> - -<tr> - <td>Show parameters for selected method</td> - <td>CTRL + P</td> -</tr> - -<tr> - <td>Generate method</td> - <td>ALT + Insert (Win)<br> - CMD + N (Mac)</td> -</tr> - -<tr> - <td>Jump to source</td> - <td>F4 (Win)<br> - CMD + down-arrow (Mac)</td> -</tr> - -<tr> - <td>Delete line</td> - <td>CTRL + Y (Win)<br> - CMD + Backspace (Mac)</td> -</tr> - -<tr> - <td>Search by symbol name</td> - <td>CTRL + ALT + SHIFT + N (Win)<br> - OPTION + CMD + O (Mac)</td> -</tr> - -</table> - - - - -<p class="table-caption"><strong>Table 2.</strong> Project and editor key commands</p> -<table> -<tr><th>Action</th><th>Android Studio Key Command</th></tr> - -<tr> - <td>Build</td> - <td>CTRL + F9 (Win)<br> - CMD + F9 (Mac)</td> -</tr> - -<tr> - <td>Build and run</td> - <td>SHIFT + F10 (Win)<br> - CTRL + R (Mac)</td> -</tr> - -<tr> - <td>Toggle project visibility</td> - <td>ALT + 1 (Win)<br> - CMD + 1 (Mac)</td> -</tr> - -<tr> - <td>Navigate open tabs</td> - <td>ALT + left-arrow; ALT + right-arrow (Win)<br> - CTRL + left-arrow; CTRL + right-arrow (Mac)</td> -</tr> - -</table> - -<p>For a complete keymap reference guide, see the -<a href="http://www.jetbrains.com/idea/documentation/index.jsp">IntelliJ IDEA</a> -documentation.</p> diff --git a/docs/html/sdk/sdk_vars.cs b/docs/html/sdk/sdk_vars.cs deleted file mode 100644 index 6e58ddd54b5e..000000000000 --- a/docs/html/sdk/sdk_vars.cs +++ /dev/null @@ -1,64 +0,0 @@ -<?cs -set:studio.version='2.1.0.9' ?><?cs -set:studio.release.date='April 26, 2016' ?><?cs - - -set:studio.linux_bundle_download='android-studio-ide-143.2790544-linux.zip' ?><?cs -set:studio.linux_bundle_bytes='298122012' ?><?cs -set:studio.linux_bundle_checksum='45dad9b76ad0506c354483aaa67ea0e2468d03a5' ?><?cs - -set:studio.mac_bundle_download='android-studio-ide-143.2790544-mac.dmg' ?><?cs -set:studio.mac_bundle_bytes='298589307' ?><?cs -set:studio.mac_bundle_checksum='d667d93ae2e4e0f3fc1b95743329a46222dbf11d' ?><?cs - -set:studio.win_bundle_download='android-studio-ide-143.2790544-windows.zip' ?><?cs -set:studio.win_bundle_bytes='300627540' ?><?cs -set:studio.win_bundle_checksum='9689ba415e5f09e2dcf5263ea302e7b1d98a8fc6' ?><?cs - -set:studio.win_bundle_exe_download='android-studio-bundle-143.2790544-windows.exe' ?><?cs -set:studio.win_bundle_exe_bytes='1238568304' ?><?cs -set:studio.win_bundle_exe_checksum='c6abe7980dbb7d1d9887f7341a2942c9e506f891' ?><?cs - -set:studio.win_notools_exe_download='android-studio-ide-143.2790544-windows.exe' ?><?cs -set:studio.win_notools_exe_bytes='283804056' ?><?cs -set:studio.win_notools_exe_checksum='a2065ba737ddcfb96f4921fee6a038278f46d2a7' ?><?cs - - - -set:sdk.linux_download='android-sdk_r24.4.1-linux.tgz' ?><?cs -set:sdk.linux_bytes='326412652' ?><?cs -set:sdk.linux_checksum='725bb360f0f7d04eaccff5a2d57abdd49061326d' ?><?cs - -set:sdk.mac_download='android-sdk_r24.4.1-macosx.zip' ?><?cs -set:sdk.mac_bytes='102781947' ?><?cs -set:sdk.mac_checksum='85a9cccb0b1f9e6f1f616335c5f07107553840cd' ?><?cs - -set:sdk.win_download='android-sdk_r24.4.1-windows.zip' ?><?cs -set:sdk.win_bytes='199701062' ?><?cs -set:sdk.win_checksum='66b6a6433053c152b22bf8cab19c0f3fef4eba49' ?><?cs -set:sdk.win_installer='installer_r24.4.1-windows.exe' ?><?cs -set:sdk.win_installer_bytes='151659917' ?><?cs -set:sdk.win_installer_checksum='f9b59d72413649d31e633207e31f456443e7ea0b' ?><?cs - - - -set:ndk.mac64_download='android-ndk-r11c-darwin-x86_64.zip' ?><?cs -set:ndk.mac64_bytes='772428792' ?><?cs -set:ndk.mac64_checksum='4ce8e7ed8dfe08c5fe58aedf7f46be2a97564696' ?><?cs - -set:ndk.linux64_download='android-ndk-r11c-linux-x86_64.zip' ?><?cs -set:ndk.linux64_bytes='794135138' ?><?cs -set:ndk.linux64_checksum='de5ce9bddeee16fb6af2b9117e9566352aa7e279' ?><?cs - -set:ndk.win64_download='android-ndk-r11c-windows-x86_64.zip' ?><?cs -set:ndk.win64_bytes='771407642' ?><?cs -set:ndk.win64_checksum='3d89deb97b3191c7e5555f1313ad35059479f071' ?><?cs -set:ndk.win32_download='android-ndk-r11c-windows-x86.zip' ?><?cs -set:ndk.win32_bytes='728899082' ?><?cs -set:ndk.win32_checksum='ff939bde6cd374eecbd2c3b2ad218697f9a5038c' -?> -<?cs -def:size_in_mb(bytes) - ?><?cs set:mb = bytes / 1024 / 1024 - ?><?cs var:mb ?><?cs -/def ?> diff --git a/docs/html/sdk/terms.jd b/docs/html/sdk/terms.jd deleted file mode 100644 index 149c243e091c..000000000000 --- a/docs/html/sdk/terms.jd +++ /dev/null @@ -1,144 +0,0 @@ -page.title=Terms and Conditions -hide_license_footer=true -fullpage=1 -@jd:body - -<div class="wrap" style="width:940px;"> - -<div class="sdk-terms fullsize" onfocus="this.blur()"> -<h1>Terms and Conditions</h1> - -This is the Android Software Development Kit License Agreement - -<h3>1. Introduction</h3> -1.1 The Android Software Development Kit (referred to in the License Agreement as the "SDK" and specifically including the Android system files, packaged APIs, and Google APIs add-ons) is licensed to you subject to the terms of the License Agreement. The License Agreement forms a legally binding contract between you and Google in relation to your use of the SDK. - -1.2 "Android" means the Android software stack for devices, as made available under the Android Open Source Project, which is located at the following URL: http://source.android.com/, as updated from time to time. - -1.3 A "compatible implementation" means any Android device that (i) complies with the Android Compatibility Definition document, which can be found at the Android compatibility website (http://source.android.com/compatibility) and which may be updated from time to time; and (ii) successfully passes the Android Compatibility Test Suite (CTS). - -1.4 "Google" means Google Inc., a Delaware corporation with principal place of business at 1600 Amphitheatre Parkway, Mountain View, CA 94043, United States. - - -<h3>2. Accepting this License Agreement</h3> -2.1 In order to use the SDK, you must first agree to the License Agreement. You may not use the SDK if you do not accept the License Agreement. - -2.2 By clicking to accept, you hereby agree to the terms of the License Agreement. - -2.3 You may not use the SDK and may not accept the License Agreement if you are a person barred from receiving the SDK under the laws of the United States or other countries, including the country in which you are resident or from which you use the SDK. - -2.4 If you are agreeing to be bound by the License Agreement on behalf of your employer or other entity, you represent and warrant that you have full legal authority to bind your employer or such entity to the License Agreement. If you do not have the requisite authority, you may not accept the License Agreement or use the SDK on behalf of your employer or other entity. - - -<h3>3. SDK License from Google</h3> -3.1 Subject to the terms of the License Agreement, Google grants you a limited, worldwide, royalty-free, non-assignable, non-exclusive, and non-sublicensable license to use the SDK solely to develop applications for compatible implementations of Android. - -3.2 You may not use this SDK to develop applications for other platforms (including non-compatible implementations of Android) or to develop another SDK. You are of course free to develop applications for other platforms, including non-compatible implementations of Android, provided that this SDK is not used for that purpose. - -3.3 You agree that Google or third parties own all legal right, title and interest in and to the SDK, including any Intellectual Property Rights that subsist in the SDK. "Intellectual Property Rights" means any and all rights under patent law, copyright law, trade secret law, trademark law, and any and all other proprietary rights. Google reserves all rights not expressly granted to you. - -3.4 You may not use the SDK for any purpose not expressly permitted by the License Agreement. Except to the extent required by applicable third party licenses, you may not: (a) copy (except for backup purposes), modify, adapt, redistribute, decompile, reverse engineer, disassemble, or create derivative works of the SDK or any part of the SDK; or (b) load any part of the SDK onto a mobile handset or any other hardware device except a personal computer, combine any part of the SDK with other software, or distribute any software or device incorporating a part of the SDK. - -3.5 Use, reproduction and distribution of components of the SDK licensed under an open source software license are governed solely by the terms of that open source software license and not the License Agreement. - -3.6 You agree that the form and nature of the SDK that Google provides may change without prior notice to you and that future versions of the SDK may be incompatible with applications developed on previous versions of the SDK. You agree that Google may stop (permanently or temporarily) providing the SDK (or any features within the SDK) to you or to users generally at Google's sole discretion, without prior notice to you. - -3.7 Nothing in the License Agreement gives you a right to use any of Google's trade names, trademarks, service marks, logos, domain names, or other distinctive brand features. - -3.8 You agree that you will not remove, obscure, or alter any proprietary rights notices (including copyright and trademark notices) that may be affixed to or contained within the SDK. - - -<h3>4. Use of the SDK by You</h3> -4.1 Google agrees that it obtains no right, title or interest from you (or your licensors) under the License Agreement in or to any software applications that you develop using the SDK, including any intellectual property rights that subsist in those applications. - -4.2 You agree to use the SDK and write applications only for purposes that are permitted by (a) the License Agreement and (b) any applicable law, regulation or generally accepted practices or guidelines in the relevant jurisdictions (including any laws regarding the export of data or software to and from the United States or other relevant countries). - -4.3 You agree that if you use the SDK to develop applications for general public users, you will protect the privacy and legal rights of those users. If the users provide you with user names, passwords, or other login information or personal information, you must make the users aware that the information will be available to your application, and you must provide legally adequate privacy notice and protection for those users. If your application stores personal or sensitive information provided by users, it must do so securely. If the user provides your application with Google Account information, your application may only use that information to access the user's Google Account when, and for the limited purposes for which, the user has given you permission to do so. - -4.4 You agree that you will not engage in any activity with the SDK, including the development or distribution of an application, that interferes with, disrupts, damages, or accesses in an unauthorized manner the servers, networks, or other properties or services of any third party including, but not limited to, Google or any mobile communications carrier. - -4.5 You agree that you are solely responsible for (and that Google has no responsibility to you or to any third party for) any data, content, or resources that you create, transmit or display through Android and/or applications for Android, and for the consequences of your actions (including any loss or damage which Google may suffer) by doing so. - -4.6 You agree that you are solely responsible for (and that Google has no responsibility to you or to any third party for) any breach of your obligations under the License Agreement, any applicable third party contract or Terms of Service, or any applicable law or regulation, and for the consequences (including any loss or damage which Google or any third party may suffer) of any such breach. - - -<h3>5. Your Developer Credentials</h3> -5.1 You agree that you are responsible for maintaining the confidentiality of any developer credentials that may be issued to you by Google or which you may choose yourself and that you will be solely responsible for all applications that are developed under your developer credentials. - - -<h3>6. Privacy and Information</h3> -6.1 In order to continually innovate and improve the SDK, Google may collect certain usage statistics from the software including but not limited to a unique identifier, associated IP address, version number of the software, and information on which tools and/or services in the SDK are being used and how they are being used. Before any of this information is collected, the SDK will notify you and seek your consent. If you withhold consent, the information will not be collected. - -6.2 The data collected is examined in the aggregate to improve the SDK and is maintained in accordance with Google's Privacy Policy. - - -<h3>7. Third Party Applications</h3> -7.1 If you use the SDK to run applications developed by a third party or that access data, content or resources provided by a third party, you agree that Google is not responsible for those applications, data, content, or resources. You understand that all data, content or resources which you may access through such third party applications are the sole responsibility of the person from which they originated and that Google is not liable for any loss or damage that you may experience as a result of the use or access of any of those third party applications, data, content, or resources. - -7.2 You should be aware the data, content, and resources presented to you through such a third party application may be protected by intellectual property rights which are owned by the providers (or by other persons or companies on their behalf). You may not modify, rent, lease, loan, sell, distribute or create derivative works based on these data, content, or resources (either in whole or in part) unless you have been specifically given permission to do so by the relevant owners. - -7.3 You acknowledge that your use of such third party applications, data, content, or resources may be subject to separate terms between you and the relevant third party. In that case, the License Agreement does not affect your legal relationship with these third parties. - - -<h3>8. Using Android APIs</h3> -8.1 Google Data APIs - -8.1.1 If you use any API to retrieve data from Google, you acknowledge that the data may be protected by intellectual property rights which are owned by Google or those parties that provide the data (or by other persons or companies on their behalf). Your use of any such API may be subject to additional Terms of Service. You may not modify, rent, lease, loan, sell, distribute or create derivative works based on this data (either in whole or in part) unless allowed by the relevant Terms of Service. - -8.1.2 If you use any API to retrieve a user's data from Google, you acknowledge and agree that you shall retrieve data only with the user's explicit consent and only when, and for the limited purposes for which, the user has given you permission to do so. - - -<h3>9. Terminating this License Agreement</h3> -9.1 The License Agreement will continue to apply until terminated by either you or Google as set out below. - -9.2 If you want to terminate the License Agreement, you may do so by ceasing your use of the SDK and any relevant developer credentials. - -9.3 Google may at any time, terminate the License Agreement with you if: -(A) you have breached any provision of the License Agreement; or -(B) Google is required to do so by law; or -(C) the partner with whom Google offered certain parts of SDK (such as APIs) to you has terminated its relationship with Google or ceased to offer certain parts of the SDK to you; or -(D) Google decides to no longer provide the SDK or certain parts of the SDK to users in the country in which you are resident or from which you use the service, or the provision of the SDK or certain SDK services to you by Google is, in Google's sole discretion, no longer commercially viable. - -9.4 When the License Agreement comes to an end, all of the legal rights, obligations and liabilities that you and Google have benefited from, been subject to (or which have accrued over time whilst the License Agreement has been in force) or which are expressed to continue indefinitely, shall be unaffected by this cessation, and the provisions of paragraph 14.7 shall continue to apply to such rights, obligations and liabilities indefinitely. - - -<h3>10. DISCLAIMER OF WARRANTIES</h3> -10.1 YOU EXPRESSLY UNDERSTAND AND AGREE THAT YOUR USE OF THE SDK IS AT YOUR SOLE RISK AND THAT THE SDK IS PROVIDED "AS IS" AND "AS AVAILABLE" WITHOUT WARRANTY OF ANY KIND FROM GOOGLE. - -10.2 YOUR USE OF THE SDK AND ANY MATERIAL DOWNLOADED OR OTHERWISE OBTAINED THROUGH THE USE OF THE SDK IS AT YOUR OWN DISCRETION AND RISK AND YOU ARE SOLELY RESPONSIBLE FOR ANY DAMAGE TO YOUR COMPUTER SYSTEM OR OTHER DEVICE OR LOSS OF DATA THAT RESULTS FROM SUCH USE. - -10.3 GOOGLE FURTHER EXPRESSLY DISCLAIMS ALL WARRANTIES AND CONDITIONS OF ANY KIND, WHETHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES AND CONDITIONS OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. - - -<h3>11. LIMITATION OF LIABILITY</h3> -11.1 YOU EXPRESSLY UNDERSTAND AND AGREE THAT GOOGLE, ITS SUBSIDIARIES AND AFFILIATES, AND ITS LICENSORS SHALL NOT BE LIABLE TO YOU UNDER ANY THEORY OF LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, CONSEQUENTIAL OR EXEMPLARY DAMAGES THAT MAY BE INCURRED BY YOU, INCLUDING ANY LOSS OF DATA, WHETHER OR NOT GOOGLE OR ITS REPRESENTATIVES HAVE BEEN ADVISED OF OR SHOULD HAVE BEEN AWARE OF THE POSSIBILITY OF ANY SUCH LOSSES ARISING. - - -<h3>12. Indemnification</h3> -12.1 To the maximum extent permitted by law, you agree to defend, indemnify and hold harmless Google, its affiliates and their respective directors, officers, employees and agents from and against any and all claims, actions, suits or proceedings, as well as any and all losses, liabilities, damages, costs and expenses (including reasonable attorneys fees) arising out of or accruing from (a) your use of the SDK, (b) any application you develop on the SDK that infringes any copyright, trademark, trade secret, trade dress, patent or other intellectual property right of any person or defames any person or violates their rights of publicity or privacy, and (c) any non-compliance by you with the License Agreement. - - -<h3>13. Changes to the License Agreement</h3> -13.1 Google may make changes to the License Agreement as it distributes new versions of the SDK. When these changes are made, Google will make a new version of the License Agreement available on the website where the SDK is made available. - - -<h3>14. General Legal Terms</h3> -14.1 The License Agreement constitutes the whole legal agreement between you and Google and governs your use of the SDK (excluding any services which Google may provide to you under a separate written agreement), and completely replaces any prior agreements between you and Google in relation to the SDK. - -14.2 You agree that if Google does not exercise or enforce any legal right or remedy which is contained in the License Agreement (or which Google has the benefit of under any applicable law), this will not be taken to be a formal waiver of Google's rights and that those rights or remedies will still be available to Google. - -14.3 If any court of law, having the jurisdiction to decide on this matter, rules that any provision of the License Agreement is invalid, then that provision will be removed from the License Agreement without affecting the rest of the License Agreement. The remaining provisions of the License Agreement will continue to be valid and enforceable. - -14.4 You acknowledge and agree that each member of the group of companies of which Google is the parent shall be third party beneficiaries to the License Agreement and that such other companies shall be entitled to directly enforce, and rely upon, any provision of the License Agreement that confers a benefit on (or rights in favor of) them. Other than this, no other person or company shall be third party beneficiaries to the License Agreement. - -14.5 EXPORT RESTRICTIONS. THE SDK IS SUBJECT TO UNITED STATES EXPORT LAWS AND REGULATIONS. YOU MUST COMPLY WITH ALL DOMESTIC AND INTERNATIONAL EXPORT LAWS AND REGULATIONS THAT APPLY TO THE SDK. THESE LAWS INCLUDE RESTRICTIONS ON DESTINATIONS, END USERS AND END USE. - -14.6 The rights granted in the License Agreement may not be assigned or transferred by either you or Google without the prior written approval of the other party. Neither you nor Google shall be permitted to delegate their responsibilities or obligations under the License Agreement without the prior written approval of the other party. - -14.7 The License Agreement, and your relationship with Google under the License Agreement, shall be governed by the laws of the State of California without regard to its conflict of laws provisions. You and Google agree to submit to the exclusive jurisdiction of the courts located within the county of Santa Clara, California to resolve any legal matter arising from the License Agreement. Notwithstanding this, you agree that Google shall still be allowed to apply for injunctive remedies (or an equivalent type of urgent legal relief) in any jurisdiction. - - -<em>November 20, 2015</em> -</div> - -</div>
\ No newline at end of file diff --git a/docs/html/sdk/win-usb.jd b/docs/html/sdk/win-usb.jd deleted file mode 100644 index d4948eb1f7b6..000000000000 --- a/docs/html/sdk/win-usb.jd +++ /dev/null @@ -1,308 +0,0 @@ -page.title=Google USB Driver -@jd:body - - - -<div style="position:relative;height:660px;"> - - -<div class="wrap" id="tos" style="position:absolute;display:none;width:inherit;"> - -<div class="col-13" style="margin:0;"> </div><!-- provides top margin for content --> - - -<p class="sdk-terms-intro">Before downloading the Google USB Driver, -you must agree to the following terms and conditions.</p> - -<div class="sdk-terms" onfocus="this.blur()"> -<h2 class="norule">Terms and Conditions</h2> -This is the Android Software Development Kit License Agreement - -<h3>1. Introduction</h3> -1.1 The Android Software Development Kit (referred to in the License Agreement as the "SDK" and specifically including the Android system files, packaged APIs, and Google APIs add-ons) is licensed to you subject to the terms of the License Agreement. The License Agreement forms a legally binding contract between you and Google in relation to your use of the SDK. - -1.2 "Android" means the Android software stack for devices, as made available under the Android Open Source Project, which is located at the following URL: http://source.android.com/, as updated from time to time. - -1.3 A "compatible implementation" means any Android device that (i) complies with the Android Compatibility Definition document, which can be found at the Android compatibility website (http://source.android.com/compatibility) and which may be updated from time to time; and (ii) successfully passes the Android Compatibility Test Suite (CTS). - -1.4 "Google" means Google Inc., a Delaware corporation with principal place of business at 1600 Amphitheatre Parkway, Mountain View, CA 94043, United States. - - -<h3>2. Accepting this License Agreement</h3> -2.1 In order to use the SDK, you must first agree to the License Agreement. You may not use the SDK if you do not accept the License Agreement. - -2.2 By clicking to accept, you hereby agree to the terms of the License Agreement. - -2.3 You may not use the SDK and may not accept the License Agreement if you are a person barred from receiving the SDK under the laws of the United States or other countries, including the country in which you are resident or from which you use the SDK. - -2.4 If you are agreeing to be bound by the License Agreement on behalf of your employer or other entity, you represent and warrant that you have full legal authority to bind your employer or such entity to the License Agreement. If you do not have the requisite authority, you may not accept the License Agreement or use the SDK on behalf of your employer or other entity. - - -<h3>3. SDK License from Google</h3> -3.1 Subject to the terms of the License Agreement, Google grants you a limited, worldwide, royalty-free, non-assignable, non-exclusive, and non-sublicensable license to use the SDK solely to develop applications for compatible implementations of Android. - -3.2 You may not use this SDK to develop applications for other platforms (including non-compatible implementations of Android) or to develop another SDK. You are of course free to develop applications for other platforms, including non-compatible implementations of Android, provided that this SDK is not used for that purpose. - -3.3 You agree that Google or third parties own all legal right, title and interest in and to the SDK, including any Intellectual Property Rights that subsist in the SDK. "Intellectual Property Rights" means any and all rights under patent law, copyright law, trade secret law, trademark law, and any and all other proprietary rights. Google reserves all rights not expressly granted to you. - -3.4 You may not use the SDK for any purpose not expressly permitted by the License Agreement. Except to the extent required by applicable third party licenses, you may not: (a) copy (except for backup purposes), modify, adapt, redistribute, decompile, reverse engineer, disassemble, or create derivative works of the SDK or any part of the SDK; or (b) load any part of the SDK onto a mobile handset or any other hardware device except a personal computer, combine any part of the SDK with other software, or distribute any software or device incorporating a part of the SDK. - -3.5 Use, reproduction and distribution of components of the SDK licensed under an open source software license are governed solely by the terms of that open source software license and not the License Agreement. - -3.6 You agree that the form and nature of the SDK that Google provides may change without prior notice to you and that future versions of the SDK may be incompatible with applications developed on previous versions of the SDK. You agree that Google may stop (permanently or temporarily) providing the SDK (or any features within the SDK) to you or to users generally at Google's sole discretion, without prior notice to you. - -3.7 Nothing in the License Agreement gives you a right to use any of Google's trade names, trademarks, service marks, logos, domain names, or other distinctive brand features. - -3.8 You agree that you will not remove, obscure, or alter any proprietary rights notices (including copyright and trademark notices) that may be affixed to or contained within the SDK. - - -<h3>4. Use of the SDK by You</h3> -4.1 Google agrees that it obtains no right, title or interest from you (or your licensors) under the License Agreement in or to any software applications that you develop using the SDK, including any intellectual property rights that subsist in those applications. - -4.2 You agree to use the SDK and write applications only for purposes that are permitted by (a) the License Agreement and (b) any applicable law, regulation or generally accepted practices or guidelines in the relevant jurisdictions (including any laws regarding the export of data or software to and from the United States or other relevant countries). - -4.3 You agree that if you use the SDK to develop applications for general public users, you will protect the privacy and legal rights of those users. If the users provide you with user names, passwords, or other login information or personal information, you must make the users aware that the information will be available to your application, and you must provide legally adequate privacy notice and protection for those users. If your application stores personal or sensitive information provided by users, it must do so securely. If the user provides your application with Google Account information, your application may only use that information to access the user's Google Account when, and for the limited purposes for which, the user has given you permission to do so. - -4.4 You agree that you will not engage in any activity with the SDK, including the development or distribution of an application, that interferes with, disrupts, damages, or accesses in an unauthorized manner the servers, networks, or other properties or services of any third party including, but not limited to, Google or any mobile communications carrier. - -4.5 You agree that you are solely responsible for (and that Google has no responsibility to you or to any third party for) any data, content, or resources that you create, transmit or display through Android and/or applications for Android, and for the consequences of your actions (including any loss or damage which Google may suffer) by doing so. - -4.6 You agree that you are solely responsible for (and that Google has no responsibility to you or to any third party for) any breach of your obligations under the License Agreement, any applicable third party contract or Terms of Service, or any applicable law or regulation, and for the consequences (including any loss or damage which Google or any third party may suffer) of any such breach. - - -<h3>5. Your Developer Credentials</h3> -5.1 You agree that you are responsible for maintaining the confidentiality of any developer credentials that may be issued to you by Google or which you may choose yourself and that you will be solely responsible for all applications that are developed under your developer credentials. - - -<h3>6. Privacy and Information</h3> -6.1 In order to continually innovate and improve the SDK, Google may collect certain usage statistics from the software including but not limited to a unique identifier, associated IP address, version number of the software, and information on which tools and/or services in the SDK are being used and how they are being used. Before any of this information is collected, the SDK will notify you and seek your consent. If you withhold consent, the information will not be collected. - -6.2 The data collected is examined in the aggregate to improve the SDK and is maintained in accordance with Google's Privacy Policy. - - -<h3>7. Third Party Applications</h3> -7.1 If you use the SDK to run applications developed by a third party or that access data, content or resources provided by a third party, you agree that Google is not responsible for those applications, data, content, or resources. You understand that all data, content or resources which you may access through such third party applications are the sole responsibility of the person from which they originated and that Google is not liable for any loss or damage that you may experience as a result of the use or access of any of those third party applications, data, content, or resources. - -7.2 You should be aware the data, content, and resources presented to you through such a third party application may be protected by intellectual property rights which are owned by the providers (or by other persons or companies on their behalf). You may not modify, rent, lease, loan, sell, distribute or create derivative works based on these data, content, or resources (either in whole or in part) unless you have been specifically given permission to do so by the relevant owners. - -7.3 You acknowledge that your use of such third party applications, data, content, or resources may be subject to separate terms between you and the relevant third party. In that case, the License Agreement does not affect your legal relationship with these third parties. - - -<h3>8. Using Android APIs</h3> -8.1 Google Data APIs - -8.1.1 If you use any API to retrieve data from Google, you acknowledge that the data may be protected by intellectual property rights which are owned by Google or those parties that provide the data (or by other persons or companies on their behalf). Your use of any such API may be subject to additional Terms of Service. You may not modify, rent, lease, loan, sell, distribute or create derivative works based on this data (either in whole or in part) unless allowed by the relevant Terms of Service. - -8.1.2 If you use any API to retrieve a user's data from Google, you acknowledge and agree that you shall retrieve data only with the user's explicit consent and only when, and for the limited purposes for which, the user has given you permission to do so. - - -<h3>9. Terminating this License Agreement</h3> -9.1 The License Agreement will continue to apply until terminated by either you or Google as set out below. - -9.2 If you want to terminate the License Agreement, you may do so by ceasing your use of the SDK and any relevant developer credentials. - -9.3 Google may at any time, terminate the License Agreement with you if: -(A) you have breached any provision of the License Agreement; or -(B) Google is required to do so by law; or -(C) the partner with whom Google offered certain parts of SDK (such as APIs) to you has terminated its relationship with Google or ceased to offer certain parts of the SDK to you; or -(D) Google decides to no longer provide the SDK or certain parts of the SDK to users in the country in which you are resident or from which you use the service, or the provision of the SDK or certain SDK services to you by Google is, in Google's sole discretion, no longer commercially viable. - -9.4 When the License Agreement comes to an end, all of the legal rights, obligations and liabilities that you and Google have benefited from, been subject to (or which have accrued over time whilst the License Agreement has been in force) or which are expressed to continue indefinitely, shall be unaffected by this cessation, and the provisions of paragraph 14.7 shall continue to apply to such rights, obligations and liabilities indefinitely. - - -<h3>10. DISCLAIMER OF WARRANTIES</h3> -10.1 YOU EXPRESSLY UNDERSTAND AND AGREE THAT YOUR USE OF THE SDK IS AT YOUR SOLE RISK AND THAT THE SDK IS PROVIDED "AS IS" AND "AS AVAILABLE" WITHOUT WARRANTY OF ANY KIND FROM GOOGLE. - -10.2 YOUR USE OF THE SDK AND ANY MATERIAL DOWNLOADED OR OTHERWISE OBTAINED THROUGH THE USE OF THE SDK IS AT YOUR OWN DISCRETION AND RISK AND YOU ARE SOLELY RESPONSIBLE FOR ANY DAMAGE TO YOUR COMPUTER SYSTEM OR OTHER DEVICE OR LOSS OF DATA THAT RESULTS FROM SUCH USE. - -10.3 GOOGLE FURTHER EXPRESSLY DISCLAIMS ALL WARRANTIES AND CONDITIONS OF ANY KIND, WHETHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES AND CONDITIONS OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. - - -<h3>11. LIMITATION OF LIABILITY</h3> -11.1 YOU EXPRESSLY UNDERSTAND AND AGREE THAT GOOGLE, ITS SUBSIDIARIES AND AFFILIATES, AND ITS LICENSORS SHALL NOT BE LIABLE TO YOU UNDER ANY THEORY OF LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, CONSEQUENTIAL OR EXEMPLARY DAMAGES THAT MAY BE INCURRED BY YOU, INCLUDING ANY LOSS OF DATA, WHETHER OR NOT GOOGLE OR ITS REPRESENTATIVES HAVE BEEN ADVISED OF OR SHOULD HAVE BEEN AWARE OF THE POSSIBILITY OF ANY SUCH LOSSES ARISING. - - -<h3>12. Indemnification</h3> -12.1 To the maximum extent permitted by law, you agree to defend, indemnify and hold harmless Google, its affiliates and their respective directors, officers, employees and agents from and against any and all claims, actions, suits or proceedings, as well as any and all losses, liabilities, damages, costs and expenses (including reasonable attorneys fees) arising out of or accruing from (a) your use of the SDK, (b) any application you develop on the SDK that infringes any copyright, trademark, trade secret, trade dress, patent or other intellectual property right of any person or defames any person or violates their rights of publicity or privacy, and (c) any non-compliance by you with the License Agreement. - - -<h3>13. Changes to the License Agreement</h3> -13.1 Google may make changes to the License Agreement as it distributes new versions of the SDK. When these changes are made, Google will make a new version of the License Agreement available on the website where the SDK is made available. - - -<h3>14. General Legal Terms</h3> -14.1 The License Agreement constitutes the whole legal agreement between you and Google and governs your use of the SDK (excluding any services which Google may provide to you under a separate written agreement), and completely replaces any prior agreements between you and Google in relation to the SDK. - -14.2 You agree that if Google does not exercise or enforce any legal right or remedy which is contained in the License Agreement (or which Google has the benefit of under any applicable law), this will not be taken to be a formal waiver of Google's rights and that those rights or remedies will still be available to Google. - -14.3 If any court of law, having the jurisdiction to decide on this matter, rules that any provision of the License Agreement is invalid, then that provision will be removed from the License Agreement without affecting the rest of the License Agreement. The remaining provisions of the License Agreement will continue to be valid and enforceable. - -14.4 You acknowledge and agree that each member of the group of companies of which Google is the parent shall be third party beneficiaries to the License Agreement and that such other companies shall be entitled to directly enforce, and rely upon, any provision of the License Agreement that confers a benefit on (or rights in favor of) them. Other than this, no other person or company shall be third party beneficiaries to the License Agreement. - -14.5 EXPORT RESTRICTIONS. THE SDK IS SUBJECT TO UNITED STATES EXPORT LAWS AND REGULATIONS. YOU MUST COMPLY WITH ALL DOMESTIC AND INTERNATIONAL EXPORT LAWS AND REGULATIONS THAT APPLY TO THE SDK. THESE LAWS INCLUDE RESTRICTIONS ON DESTINATIONS, END USERS AND END USE. - -14.6 The rights granted in the License Agreement may not be assigned or transferred by either you or Google without the prior written approval of the other party. Neither you nor Google shall be permitted to delegate their responsibilities or obligations under the License Agreement without the prior written approval of the other party. - -14.7 The License Agreement, and your relationship with Google under the License Agreement, shall be governed by the laws of the State of California without regard to its conflict of laws provisions. You and Google agree to submit to the exclusive jurisdiction of the courts located within the county of Santa Clara, California to resolve any legal matter arising from the License Agreement. Notwithstanding this, you agree that Google shall still be allowed to apply for injunctive remedies (or an equivalent type of urgent legal relief) in any jurisdiction. - -<em>November 20, 2015</em> -</div><!-- thin wrapper around tos doc --> - - -<div id="usb-terms-form"> -<p> -<input id="agree" type="checkbox" name="agree" value="1" onclick="onAgreeChecked()" /> -<label id="agreeLabel" for="agree">I have read and agree with the above terms and conditions</label> -</p> -<p><a href="" class="dac-button dac-raised dac-primary disabled ndk" id="downloadForRealz" onclick="return onDownloadForRealz(this);"></a></p> -</div> - - - -</div><!-- end TOS --> - - - -<div class="wrap col-13" style="margin:0" id="main"> - - -<div id="qv-wrapper"> -<div id="qv"> - <h2>In this document</h2> - <ol> - <li><a href="#WinUsbDriver">Downloading the Google USB Driver</a></li> - </ol> - <h2>See also</h2> - <ol> - <li><a href="{@docRoot}tools/extras/oem-usb.html#InstallingDriver">Installing a USB Driver</a></li> - <li><a href="{@docRoot}guide/developing/device.html">Using Hardware Devices</a></li> - </ol> - -<h2>Get it</h2> - -<div class="download-box"> - <a onclick="return onDownload(this)" - href="https://dl-ssl.google.com//android/repository/latest_usb_driver_windows.zip" - class="button" id="usbDriverButton"> - Download Google USB Driver - </a> - <p class="filename">latest_usb_driver_windows.zip</p> -</div> - -</div> -</div> - -<p>The Google USB Driver is <strong>required for Windows only</strong> in order to perform -<a href="{@docRoot}tools/help/adb.html">adb</a> debugging with any of -the <strong>Google Nexus devices</strong>. The one exception is the -Galaxy Nexus: the driver for Galaxy Nexus is distributed by <a -href="http://www.samsung.com/us/support/downloads/verizon-wireless/SCH-I515MSAVZW">Samsung</a> -(listed as model SCH-I515).</p> - -<p>Windows drivers for all other devices are provided by the respective hardware -manufacturer, as listed in the <a href="{@docRoot}tools/extras/oem-usb.html">OEM USB Drivers</a> -document.</p> - - - -<p class="note"><strong>Note:</strong> -If you're developing on Mac OS X or Linux, then you <strong>do not</strong> need to install a USB -driver. To start developing with your device, read -<a href="{@docRoot}guide/developing/device.html">Using Hardware Devices</a>.</p> - - -<h2 id="WinUsbDriver">Downloading the Google USB Driver</h2> - -<p>The Google USB Driver for Windows is available for download as an optional SDK -component. You need the driver only if you are developing on Windows and -want to connect a Google Android-powered device (such as a Nexus 7) to your -development environment over USB.</p> - -<div class="figure" style="width:536px;margin:0"> - <img src="{@docRoot}images/developing/sdk-usb-driver.png" alt="" /> - <p class="img-caption"><strong>Figure 1.</strong> The SDK Manager - with the Google USB Driver selected.</p> -</div> - -<p>You can download the Google USB Driver for Windows in one of two ways:</p> -<ul> - <li> - <a onclick="$('#usbDriverButton').trigger('click');return false;" href="#"> - Click here to download the latest Google USB Driver ZIP file</a>.</li> - <li>Or, use the Android SDK Manager tool that is -included with the <a href="{@docRoot}sdk/index.html">Android SDK</a>. Using the SDK Manager -helps you keep the driver up to date by notifying you when your current driver is out of date. - <ol> - <li>Launch the Android SDK Manager by double-clicking <code>SDK Manager.exe</code>, - at the root of your SDK directory.</li> - <li>Expand <em>Extras</em>.</li> - <li>Check <strong>Google USB Driver package</strong> and click <strong>Install</strong>.</li> - <li>Proceed to install the package. When done, the driver files are - downloaded into the <code><sdk>\extras\google\usb_driver\</code> directory.</li> - </ol> - </li> -</ul> - -<p>For installation information, read -<a href="{@docRoot}tools/extras/oem-usb.html#InstallingDriver">Installing a USB Driver</a>.</p> - - - -</div><!-- end wrap "main" for document content --> - -</div><!-- end outter wrapper for page contents --> - - - - -<script> - - - function onDownload(link) { - - /* set text for download button */ - $("#downloadForRealz").html($(link).text()); - $("#downloadForRealz").attr('href',$(link).attr('href')); - - $("#tos").fadeIn('fast'); - $("#main").fadeOut('fast'); - - location.hash = "download"; - return false; - } - - - function onAgreeChecked() { - /* verify that the TOS is agreed and a bit version is chosen */ - if ($("input#agree").is(":checked")) { - /* reveal the download button */ - $("a#downloadForRealz").removeClass('disabled'); - } else { - $("a#downloadForRealz").addClass('disabled'); - } - } - - function onDownloadForRealz(link) { - if ($("input#agree").is(':checked')) { - // OK, start the download and reset the page - $("input#agree").attr('checked',false); - $("a#downloadForRealz").addClass('disabled'); - $("#tos").fadeOut('fast'); - $("#main").fadeIn('fast'); - location.hash = "top"; - } else { - // Have not agreed to tos, make the checkbox blink - $("label#agreeLabel").parent().stop().animate({color: "#258AAF"}, 200, - function() {$("label#agreeLabel").parent().stop().animate({color: "#222"}, 200)} - ); - return false; - } - } - - $(window).hashchange( function(){ - if (location.hash == "") { - location.reload(); - } - }); - -</script>
\ No newline at end of file diff --git a/docs/html/tools/_book.yaml b/docs/html/tools/_book.yaml index 5395cc8d335f..fb257f3b5917 100644 --- a/docs/html/tools/_book.yaml +++ b/docs/html/tools/_book.yaml @@ -2,10 +2,8 @@ toc: - title: Download path: /sdk/index.html section: - - title: Installing the SDK + - title: Install Android Studio path: /sdk/installing/index.html - - title: Adding SDK Packages - path: /sdk/installing/adding-packages.html - title: Workflow path: /tools/workflow/index.html @@ -27,13 +25,15 @@ toc: path: /tools/debugging/index.html - title: Publishing path: /tools/publishing/publishing_overview.html - custom_link_attributes: - - zh-cn-lang="发布概述" + path_attributes: + - name: zh-cn-lang + value: 发布概述 section: - title: Preparing for Release path: /tools/publishing/preparing.html - custom_link_attributes: - - zh-cn-lang="准备发布" + path_attributes: + - name: zh-cn-lang + value: 准备发布 - title: Versioning Your Apps path: /tools/publishing/versioning.html - title: Signing Your Apps @@ -65,7 +65,9 @@ toc: path: /tools/debugging/improving-w-lint.html - title: Improving Code Inspection with Annotations path: /tools/debugging/annotations.html - - title: Deep Link and App Indexing API Support + - title: Shrink Your Code and Resources + path: /tools/help/proguard.html + - title: Supporting URLs and App Indexing in Android Studio path: /tools/help/app-link-indexing.html - title: UI Tools path: /tools/studio/ui-tools.html @@ -82,6 +84,11 @@ toc: path: /tools/help/image-asset-studio.html - title: AVD Manager path: /tools/devices/managing-avds.html + - title: Android Emulator + path: /tools/devices/emulator.html + section: + - title: Android Emulator Command-Line Features + path: /tools/help/emulator.html - title: Debugging Tools path: /tools/debugging/debugging-studio.html section: @@ -152,15 +159,8 @@ toc: path: /tools/debugging/debugging-log.html - title: mksdcard path: /tools/help/mksdcard.html - - title: ProGuard - path: /tools/help/proguard.html - title: Tracer for OpenGL ES path: /tools/help/gltracer.html - - title: Virtual Device Emulator - path: /tools/devices/emulator.html - section: - - title: Command Reference - path: /tools/help/emulator.html - title: zipalign path: /tools/help/zipalign.html diff --git a/docs/html/tools/help/am-allocation.jd b/docs/html/tools/help/am-allocation.jd new file mode 100644 index 000000000000..20570c3be2e1 --- /dev/null +++ b/docs/html/tools/help/am-allocation.jd @@ -0,0 +1,220 @@ +page.title=Allocation Tracker +parent.title=Android Monitor +parent.link=android-monitor.html +meta.tags="android, performance, profiling, tools, monitor" +page.tags="android", "performance", "profiling", "tools", "monitor" +page.metaDescription=Use the Memory Monitor to capture allocation data about your app. The Allocation Tracker displays each method responsible for an allocation, as well as the allocation size and number of instances. +page.image=tools/help/thumbnails/am_alloctracker.png +page.article=true + +@jd:body + +<div id="qv-wrapper"> +<div id="qv"> + <h2>In this document</h2> +<ol> + <li><a href="#display">Understanding the Allocation Tracker Display</a></li> + <li><a href="#alloc-snapshot">Taking and Displaying a Snapshot of Allocation Data</a></li> + <li><a href="#alloc-viewing">Viewing a Saved Allocation Tracking File</a></li> + <li><a href="#alloc-sorting">Sorting Allocation Data</a></li> + <li><a href="#alloc-source">Displaying Java Source</a></li> + <li><a href="#alloc-files">Working with Allocation Tracking Files</a></li> +</ol> + + <h2>See also</h2> + <ol> + <li><a href="{@docRoot}training/articles/memory.html">Managing Your App's Memory</a></li> + <li><a href="{@docRoot}guide/practices/verifying-apps-art.html#GC_Migration">Addressing Garbage Collection Issues</a></li> + <li><a href="{@docRoot}tools/debugging/debugging-memory.html">Investigating Your RAM Usage</a></li> + </ol> + +</div> +</div> + + + + +<p>Android Studio allows you to track memory allocation as it monitors memory use. Tracking memory + allocation allows you to monitor where objects are being allocated when you perform certain + actions. Knowing these allocations enables you to adjust the method calls related to those actions + to optimize app performance and memory use.</p> + +<p>The Allocation Tracker does the following:</p> +<ul> +<li>Shows when and where your code allocates object types, their size, allocating thread, and stack + traces.</li> +<li>Helps recognize memory churn through recurring allocation/deallocation patterns.</li> +<li>Helps you track down memory leaks when used in combination with the HPROF Viewer. For example, + if you see a bitmap object resident on the heap, you can find its allocation location with + Allocation Tracker.</li> +</ul> + + +<p>However, it takes time and experience to learn to interpret the output from this tool.</p> + +<h2 id="display"> + Understanding the Allocation Tracker Display +</h2> + +<p> + The Allocation Tracker looks similar to the following figure: +</p> +<img src="{@docRoot}images/tools/am-alloctracker.png" /> +<p> + + +<p>The tool displays the following information: </p> + +<table> + <tr> + <th scope="col">Column</th> + <th scope="col">Description</th> + </tr> + + <tr> + <td><strong>Method</strong></td> + <td>The Java method responsible for the allocation.</td> + </tr> + <tr> + <td><strong>Count</strong></td> + <td>Total number of instances allocated.</td> + </tr> + <tr> + <td><strong>Size</strong></td> + <td>The total amount of allocated memory in bytes.</td> + </tr> + +</table> + +<h2 id="alloc-snapshot">Taking and Displaying a Snapshot of Allocation Data</h2> + +<p>To examine allocation data:</p> +<ol> + <li><a href="{@docRoot}tools/help/am-memory.html#displaying">Display a running app in the Memory + Monitor</a>.</li> +<li>Click Start Allocation Tracking + <img src="{@docRoot}images/tools/am-ialloctracking.png" + style="vertical-align:sub;margin:0;height:17px" alt="Start Allocation Tracking icon" />. </li> +<li>Click Start Allocation Tracking + <img src="{@docRoot}images/tools/am-ialloctracking.png" + style="vertical-align:sub;margin:0;height:17px" alt="Start Allocation Tracking icon" /> again to + deselect it and end the snapshot. </li> + + <p>The Memory Monitor displays the period when it took the snapshot. In the following + figure, you can see the snapshot period, as shown on the left. By comparison, when you dump the + Java heap, the Memory Monitor displays just the point where the heap snapshot was taken, as + shown on the right.</p> + <img src="{@docRoot}images/tools/am-dumpalloc2.png" /> + +<p>Android Studio creates the heap snapshot file with the + filename <code><em>package_yyyy.mm.dd_hh.mm.ss</em>.alloc</code> using the activity package (or + project) name, year, month, day, + hour, minute, and second of the capture, for example, + <code>com.android.calc_2015.11.17_14.58.48.alloc</code>.</p> + + The Allocation Tracker appears. +</p> + +<li>Optionally click the graphic icon <img src="{@docRoot}images/tools/am-igraphic.png" +style="vertical-align:sub;margin:0;height:17px" + alt="graphic icon" /> to display a visual representation of the data. + </li> + + + + +<li>Select the Group By menu option you want to display: </li> +<ul> +<li><strong>Group by Allocator</strong> </li> +<li><strong>Group by Method</strong></li> +</ul> + +</ol> + + +<h2 id="alloc-viewing">Viewing a Saved Allocation Tracking File</h2> +<p>After you capture allocation data, Android Studio automatically stores it so +you can view it again.</p> +<p>To view an allocation tracking file in the Allocation Tracker:</p> + + +<ol> +<li>Click +<img src="{@docRoot}images/tools/am-icaptures.png" +style="vertical-align:sub;margin:0;height:17px" + alt="Captures icon" /> in the main window.</li> + +<p>Or select <strong>View</strong> > <strong>Tools Windows</strong> > +<strong>Captures</strong>.</p> +<p>The <em>Captures</em> window appears.</p> +<li>Open the <strong>Allocation Tracking</strong> folder.</li> +<li>Double-click the file to view it.</li> +</ol> + +<h2 id="alloc-sorting">Sorting Allocation Data</h2> + +<p>To sort allocation data:</p> +<ul> +<li>In the Allocation Tracker, click a column heading to sort the table by ascending or + descending order. </li> +</ul> + + +<h2 id="alloc-source">Displaying Java Source</h2> +<p>For some items displayed in the Allocation Tracker, you can view the Java source.</p> +<p>To display Java source:</p> +<ul> +<li>In the Allocation Tracker, right-click a method and then select <strong>Jump to Source</strong>. +</li> +<li>In the Allocation Tracker, select a method and then click Jump to Source + <img src="{@docRoot}images/tools/am-ijumptosource.png" + style="vertical-align:sub;margin:0;height:17px" alt="Jump to Source icon" />. </li> +</ul> + +<p>The source code appears in the Code Editor.</p> + + +<h2 id="alloc-files">Working with Allocation Tracking Files</h2> +<p>You can rename, locate, and delete an allocation tracking file from within +Android Studio.</p> + +<h3 id="alloc-renaming">Renaming an allocation tracking file</h3> + +<p>If you rename a file from within Android Studio, it continues to appear in the <em>Captures</em> + window.</p> +<p>To rename an allocation tracking file:</p> +<ol> +<li>In the <em>Captures</em> window, right-click the file and select <strong>Rename</strong>.</li> +<li>In the <em>Rename</em> dialog, specify the name of the file and click <strong>OK</strong>.</li> +</ol> + + +<h3 id="alloc-locating">Locating an allocation tracking file</h3> +<p>You can quickly discover where Android Studio stored allocation tracking files on disk.</p> + + +<p>To locate an allocation tracking file from Android Studio: </p> +<ul> +<li>In the <em>Captures</em> window, right-click allocation file and select + <strong>Show</strong> or <strong>Reveal</strong>.</li> + +<p>Android Studio opens an operating system file browser displaying the location where the file + resides.</p> +</ul> + +<p class="note"><strong>Note:</strong> If you move an allocation tracking file, Android Studio + no longer displays it in the <em>Captures</em> window. To display the file, use + <strong>File</strong> + > <strong>Open</strong>. Also, rename the file from the <em>Captures</em> + window and not in the operating system file browser. </p> + +<h3 id="alloc-deleting">Deleting an allocation tracking file</h3> + + +<p>To delete an allocation tracking file: </p> +<ul> +<li>In the <em>Captures</em> window, right-click an allocation tracking file and select + <strong>Delete</strong>.</li> + +<p>Android Studio deletes the file from the <em>Captures</em> dialog and from disk. </p> +</ul> diff --git a/docs/html/tools/help/am-basics.jd b/docs/html/tools/help/am-basics.jd new file mode 100644 index 000000000000..4bacecfe5136 --- /dev/null +++ b/docs/html/tools/help/am-basics.jd @@ -0,0 +1,329 @@ +page.title=Android Monitor Basics +parent.title=Android Monitor +parent.link=index.html +page.tags=monitor +@jd:body + +<div id="qv-wrapper"> +<div id="qv"> + <h2>In this document</h2> +<ol> + <li><a href="#byb">Prerequisites and Dependencies</a></li> + <li><a href="#displaying">Displaying Android Monitor</a></li> + <li><a href="#profiling">Profiling a Running App in Android Monitor</a></li> + <li><a href="#switching">Switching between Devices and Apps</a></li> + <li><a href="#rearranging">Rearranging Android Monitor Windows</a></li> + <li><a href="#terminating">Terminating an App</a></li> + <li><a href="#removing">Removing an App from a Device</a></li> + <li><a href="#other">Using Other Main Window Features</a></li> +</ol> + + + + + +</div> +</div> + +<p> + Android Monitor has a main window that contains the logcat, Memory, CPU, GPU, and Network + Monitors. From this window, you can select a device and app process to work with, terminate an + app, collect <code>dumpsys</code> system information, and create screenshots and videos of the + running app. +</p> + + +<h2 id="byb"> + Prerequisites and Dependencies +</h2> + +<p> + Before you start using Android Monitor, you need to set up your environment, as well as the + hardware device or emulator. All of the monitors require the following: +</p> + <ul> + <li>If you want to run your app on a hardware device (as opposed to the emulator), connect it + to the USB port. Make sure your development computer + <a href="{@docRoot}tools/device.html#setting-up">detects your device</a>, which often + happens automatically when you connect it. + </li> + <li>Enable ADB integration by selecting <strong>Tools</strong> > <strong>Android</strong> + > <strong>Enable ADB Integration</strong>. <strong>Enable ADB Integration</strong> + should have a check mark next to it in the menu to indicate it's enabled. + </li> + <li> + <a href="{@docRoot}tools/help/monitor.html">Android Device Monitor</a> can’t be running. + </li> + </ul> + + <p> + All but the logcat Monitor have these additional requirements: +</p> +<ul> + <li> + <a href="{@docRoot}tools/device.html#device-developer-options">Enable</a> <strong><a href= + "{@docRoot}tools/device.html#device-developer-options">USB debugging</a></strong> in + <strong>Developer Options</strong> on the device or emulator. + </li> + + <li>In your app, set the <code>debuggable</code> property to <code>true</code> in the manifest or + <code>build.gradle</code> file (it’s initially set by default). + </li> +</ul> + + +<p> + The GPU Monitor has this requirement as well: +</p> +<ul> + <li>For Android 5.0 (API level 21) and Android 5.1 (API level 22), in <strong>Developer + Options</strong> on the device or emulator, set <strong>Profile GPU rendering</strong> to + <strong>In adb shell dumpsys gfxinfo</strong>. + </li> +</ul> +<p> + The Network Monitor and the Video Capture tool work with a hardware device + only, not the emulator. +</p> + + + +<h2 id="displaying"> + Displaying Android Monitor +</h2> + +<p> + Android Monitor is integrated into the Android Studio main window: +</p> + +<ul> + <li>To display Android Monitor, click <img src="{@docRoot}images/tools/am-icon.png" + style="vertical-align:sub;margin:0;height:17px" alt="Android Monitor icon" />, + which by default is at the bottom of the main window. + </li> + + <li>To hide Android Monitor, click <img src="{@docRoot}images/tools/am-icon.png" + style="vertical-align:sub;margin:0;height:17px" alt="Android Monitor icon" /> again. + </li> + <li>Or select <strong>View</strong> > <strong>Tool Windows</strong> > + <strong>Android Monitor</strong>.</li> +</ul> + <p class="note"> + <strong>Note:</strong> If you don't see the sidebar buttons, you can + display them by selecting <strong>View</strong> > + <strong>Tool Buttons</strong>. + </p> +<p> + Android Monitor looks like the following figure: +</p> +<img src="{@docRoot}images/tools/am-androidmon2.png" style="vertical-align:sub;margin:0" /> + +<h2 id="profiling"> + Profiling a Running App in Android Monitor +</h2> + +<p> + After you've met the prerequisites and optionally connected a hardware device, you're ready + to profile an app in Android Monitor: +</p> + +<ol> + + <li>Open an app project and <a href= + "{@docRoot}tools/building/building-studio.html#RunningApp">run the app</a> on a device or + emulator. + </li> + + <li>Display Android Monitor and click the tab for the monitor you want to view. + </li> + <li>Follow the instructions about using the monitor: + </li> + <ul> + <li><a href="{@docRoot}tools/help/am-logcat.html">logcat Monitor</a> + </li> + + <li><a href="{@docRoot}tools/help/am-memory.html">Memory Monitor</a> + </li> + + <li><a href="{@docRoot}tools/help/am-cpu.html">CPU Monitor</a> + </li> + + <li><a href="{@docRoot}tools/help/am-gpu.html">GPU Monitor</a> + </li> + + <li> + <a href="{@docRoot}tools/help/am-network.html">Network Monitor</a> + </li> + </ul> +</ol> + <h2 id="switching"> + Switching between Devices and Apps + </h2> + + <p> + By default, Android Monitor displays data for your most recently run app. You can switch to + another device and app as needed. In addition to currently running apps, you can view + information about apps that are no longer running so you can continue to see any information + about them that you gathered previously. + </p> + + <p> + At the top of the Android Monitor main window are two menus listing devices and processes. To + switch to another device, process, or both: + </p> + + <ol> + <li>Select the device or emulator. + </li> + + <p> + The Device menu lists the devices and emulators that are running or have run during your + current session. There are various status messages that can appear in the Device menu: + </p> + + <ul> + <li> + <strong>DISCONNECTED</strong> - You closed an emulator or unplugged a device from the + computer. + </li> + + <li> + <strong>UNAUTHORIZED</strong> - A device needs you to accept the incoming computer + connection. For example, if the connected device displays an <em>Allow USB Debugging</em> + dialog, click <strong>OK</strong> to allow the connection. + </li> + + <li> + <strong>OFFLINE</strong> - Android Monitor can’t communicate with a device, even though it + has detected that device. + </li> + </ul> + + <li>Select the process. + </li> + <p> + The Process menu lists the processes that are running or have run during your current session. If + a process is no longer running, the menu displays a status of <strong>DEAD</strong>. +</p> +</ol> + + + + +<h2 id="rearranging"> + Rearranging Android Monitor Windows +</h2> + +<p> + You can rearrange the Android Monitor windows for optimal viewing during your + tests: +</p> +<ul> + <li>To move a monitor up or down, click Move Monitor Up + <img src="{@docRoot}images/tools/am-imoveup.png" style="vertical-align:sub;margin:0;height:17px" + alt="Move Monitor Up icon" /> or Move Monitor Down + <img src="{@docRoot}images/tools/am-imovedown.png" style="vertical-align:sub;margin:0;height:17px" + alt="Move Monitor Down icon" />. + </li> + <li>To minimize or maximize a monitor, click Minimize Monitor + <img src="{@docRoot}images/tools/am-iminimize.png" style="vertical-align:sub;margin:0;height:17px" + alt="Minimize Monitor icon" /> + or Maximize Monitor + <img src="{@docRoot}images/tools/am-imaximize.png" style="vertical-align:sub;margin:0;height:17px" + alt="Maximize Monitor icon" />. + </li> +</ul> + +<p> + To rearrange the <strong>logcat</strong> and <strong>Monitors</strong> tabs: +</p> +<ul> + <li>To reorder the logcat or monitor group, move the tabs back and forth. + </li> + + <li>To move the logcat or monitor group to a standalone window, drag a tab + to a different location on the screen. Or, select + <img src="{@docRoot}images/tools/am-igear.png" style="vertical-align:sub;margin:0;height:17px" + alt="Gear menu icon" /> > <strong>Floating Mode</strong>. + </li> + + + <li>To dock a standalone window, drag it to the Android Monitor + tab area.</li> + + + <li>To combine the logcat and monitor group displays together, drag a tab and + move it onto another monitor. + </li> + + <li>To hide a tab, click the + <img src="{@docRoot}images/tools/am-ihide.png" style="vertical-align:sub;margin:0;height:17px" + alt="Hide icon" /> icon. To make it reappear, click Restore Monitors View + <img src="{@docRoot}images/tools/am-imaximize.png" style="vertical-align:sub;margin:0;height:17px" + alt="Restore Monitors View icon" /> + or the Restore logcat View + <img src="{@docRoot}images/tools/am-imaxlogcat.png" style="vertical-align:sub;margin:0;height:17px" + alt="Restore logcat View icon" /> + on the far right of the row of tabs. + </li> +</ul> + +<h2 id="terminating"> + Terminating an App +</h2> + +<p> + To stop an app you’ve run from Android Studio: +</p> + +<ol> + <li> + <a href="#switching">Select the device and the process</a> in the Android Monitor + menus, if needed. + </li> + + <li>Click Terminate Application <img src="{@docRoot}images/tools/am-iterminate.png" + style="vertical-align:sub;margin:0;height:17px" alt="Terminate App icon" />. + </li> + + +<p> + The process status changes to <strong>DEAD</strong> in the Processes menu. The emulator or device + continues to run, but the app closes. Any running monitors in Android Monitor stop. +</p> +</ol> + +<h2 id="removing"> + Removing an App from a Device +</h2> + +<p> + To remove an app from a device you use for development, use the normal uninstall procedure on the + device. +</p> + +<p> + If you run a new version of an app from Android Studio that’s been already installed on a + hardware device, the device displays an <em>Application Installation Failed</em> dialog. Click + <strong>OK</strong> to install the new version of the app. +</p> + +<h2 id="other"> + Using Other Main Window Features +</h2> +<p> + From the Android Monitor main window, you can also do the following: +</p> + +<ul> + <li> + <a href="{@docRoot}tools/help/am-sysinfo.html">Examine <code>dumpsys</code> system information</a>. + </li> + <li> + <a href="{@docRoot}tools/help/am-screenshot.html">Take a screen capture of the device</a>. + </li> + <li> + <a href="{@docRoot}tools/help/am-video.html">Record a video from the screen</a>. + </li> +</ul> + diff --git a/docs/html/tools/help/am-cpu.jd b/docs/html/tools/help/am-cpu.jd index 62b35909a315..420d6f8139ab 100644 --- a/docs/html/tools/help/am-cpu.jd +++ b/docs/html/tools/help/am-cpu.jd @@ -1,7 +1,12 @@ page.title=CPU Monitor parent.title=Android Monitor parent.link=android-monitor.html -page.tags=monitor +meta.tags="android, performance, profiling, tools, monitor" +page.tags="android", "performance", "profiling", "tools", "monitor" +page.metaDescription=Use the CPU Monitor to display CPU usage in real time and the percentage of total CPU time (including all cores) used in user and kernel mode. +page.image=tools/help/thumbnails/am-cpumon.png +page.article=true + @jd:body <div id="qv-wrapper"> @@ -9,63 +14,9 @@ page.tags=monitor <h2>In this document</h2> <ol> <li><a href="#running">Displaying a Running App in the CPU Monitor</a></li> - <li><a href="#trace">Performing a Method Trace in the CPU Monitor</a></li> - <li><a href="#viewtrace">Viewing a Saved Method Trace</a></li> - <li><a href="#sorttrace">Sorting Method Trace Data</a></li> - <li><a href="#renametrace">Renaming a Method Trace File</a></li> - <li><a href="#locatetrace">Locating a Method Trace File on Disk</a></li> - <li><a href="#deletetrace">Deleting a Method Trace File</a></li> + <li><a href="#snapshot">Recording Call Stack Changes</a></li> </ol> - <h2>See also</h2> - <ol> - <li> - <a href="{@docRoot}tools/help/android-monitor.html">Android Monitor</a> - </li> - <li><a href="{@docRoot}tools/help/am-logcat.html">logcat Monitor</a> - </li> - - <li><a href="{@docRoot}tools/help/am-memory.html">Memory Monitor</a> - </li> - - <li><a href="{@docRoot}tools/help/am-gpu.html">GPU Monitor</a> - </li> - - <li> - <a href="{@docRoot}tools/help/am-network.html">Network Monitor</a> - </li> - </ol> - - -<h2> - Dependencies and Prerequisites -</h2> - -<ul> - <li>Make sure your development computer detects your hardware device, which often happens - automatically when you connect it to a USB port. - </li> - - <li> - <a href="{@docRoot}tools/device.html#device-developer-options">Enable</a> <strong><a href= - "{@docRoot}tools/device.html#device-developer-options">USB debugging</a></strong> in - <strong>Developer Options</strong> on the device or emulator. - </li> - - <li>In your app, set the <code>debuggable</code> property to <code>true</code> in the manifest or - <code>build.gradle</code> file (it’s initially set by default). - </li> - -<li>Enable ADB integration through <strong>Tools</strong> > <strong>Android</strong> > - <strong>Enable ADB Integration</strong>. - </li> - - <li> - <a href="{@docRoot}tools/help/monitor.html">Android Device Monitor</a> can’t be running. - </li> - -</ul> - </div> </div> @@ -73,253 +24,66 @@ page.tags=monitor <p> The CPU Monitor lets you easily monitor the central processing unit (CPU) usage of your app. It displays CPU usage in real time and displays the percentage of total CPU time (including all cores) - used by user and kernel mode. In user mode, the code must use system APIs to access hardware or - memory, and crashes are usually recoverable. In kernel mode, the code can directly access - hardware, including memory addresses; crashes halt the device. + used in user and kernel mode. In user mode, the code must use system APIs to access hardware or + memory, has access to virtual memory addresses only, and crashes are usually + recoverable. In kernel mode, the code can directly access + hardware, including physical memory addresses; crashes halt the device. </p> + <h2 id="running"> Displaying a Running App in the CPU Monitor </h2> <p> - Follow these steps: + To display an app running on a particular device or emulator in the CPU Monitor: </p> <ol> - <li>Optionally connect a hardware device. + <li>Meet the <a href= + "{@docRoot}tools/help/am-basics.html#byb">prerequisites and dependencies</a>. + </li> + <li>Open an app project. + </li> + <li><a href= + "{@docRoot}tools/building/building-studio.html#RunningApp">Run the app</a> on a hardware device or + emulator. </li> - <li> - <a href="{@docRoot}tools/help/android-monitor.html#displaying">Display Android Monitor</a>. + <a href="{@docRoot}tools/help/am-basics.html#displaying">Display Android Monitor</a>. </li> - - <li>Click the <strong>CPU</strong> tab. + <li>Click the <strong>Monitors</strong> tab and <a href= + "{@docRoot}tools/help/am-basics.html#rearranging">display the CPU Monitor</a>. </li> - <li>Open an app project and <a href= - "{@docRoot}tools/building/building-studio.html#RunningApp">run it</a> on a hardware device or - emulator. - </li> <li>Enable the CPU Monitor by clicking Pause <img src="{@docRoot}images/tools/am-ipause.png" - style="vertical-align:sub;margin:0;height:17px" alt="Pause icon" /> to deselect - it. + style="vertical-align:sub;margin:0;height:17px" alt="Pause icon" /> to deselect it. </li> + <p> The CPU Monitor starts to display any CPU usage. In the graph, the y-axis displays the percentage of CPU used. The x-axis records the time elapsed and starts with seconds, and then minutes and seconds, and so on. </p> -<img src="{@docRoot}images/tools/am-cpumon.png" style="vertical-align:sub;margin:0;width:450px" /> +<img src="{@docRoot}images/tools/am-cpumon2.png" style="vertical-align:sub;margin:0" /> <li>To stop the CPU Monitor, click Pause <img src="{@docRoot}images/tools/am-ipause.png" style="vertical-align:sub;margin:0;height:17px" alt="Pause icon" /> again to select it. </li> </ol> - -<h2 id="trace"> - Performing a Method Trace in the CPU Monitor -</h2> - -<p> - Follow these steps: -</p> - -<ol> - <li> - <a href="{@docRoot}tools/help/android-monitor.html#displaying">Display a running app in the CPU - Monitor</a>. - </li> - - <li>Start a trace by clicking Start Method Tracing <img src="{@docRoot}images/tools/am-imethodtrace.png" - style="vertical-align:sub;margin:0;height:17px" alt="Start Method Tracing icon" /> to - select it. - </li> - - <li>To stop the trace, click Stop Method Tracing <img src="{@docRoot}images/tools/am-imethodtrace.png" - style="vertical-align:sub;margin:0;height:17px" alt="Stop Method Tracing icon" /> to - deselect it. - </li> - -<p> - The method trace appears in the Code Editor area: -</p> -<img src="{@docRoot}images/tools/am-methodtrace.png" alt="Method Trace" /> -<p> - Android Studio creates the method trace file - with the filename <code>Trace_<em>yyyy.mm.dd_hh.mm.ss</em>.trace</code> - using the year, month, day, hour, minute, and second of the capture, for example, - <code>Trace_2015.11.17_14.58.48.trace</code>. -</p> - <li>Specify display options: - <ul> - <li>Select a <strong>Thread</strong>. - </li> - - <li>Select an <strong>x-axis</strong> time for the graphic and the method list: - </li> - - <ul> - <li> - <strong>Wall Clock Time</strong> - Total CPU time elapsed between the method call and - return. - </li> - - <li> - <strong>Thread Time</strong> - Total time during which the JRE scheduled the - thread during call processing. It’s less than or equal to the Wall Clock Time: less if - the JRE interrupted the thread, and equal if it didn’t. - The thread might not run continuously; when it’s not executing, that time is excluded. - If threads are interrupted often and it’s not by design, the interruptions affect app - performance. However, an example of a by-design use is synchronous operations that take - a long time, such as file transfers and reads from disk, where the method could be the - asynchronous wrapper for the synchronous reader. - </li> - </ul> - - <li> - Optionally select <strong>Color by inclusive time</strong>. - </li> - </ul> - - <p> - The display shows the following information: - </p> -<table> - <tr> - <th scope="col">Field</th> - <th scope="col">Description</th> - </tr> - - <tr> - <td><strong>Name</strong></td> - <td>The name of the method.</td> - </tr> - - <tr> - <td><strong>Invocation Count</strong></td> - <td>How many times the method was called.</td> - </tr> - - <tr> - <td><strong>Inclusive Time (microseconds)</strong></td> - <td>Time spent in the method and all of its children, either wall clock or thread time, - depending on your selection in the <strong>x-axis</strong> menu.</td> - </tr> - - <tr> - <td><strong>Exclusive Time (microseconds)</strong></td> - <td>Time spent just in the method (excluding time spent in its children), either wall clock - or thread time, depending on your selection in the <strong>x-axis</strong> menu.</td> - </tr> -</table> -<p class="note"><strong>Note:</strong> Running the method trace significantly affects CPU timings. - Use the method trace to understand the flow of the program, but not for performance timings.</p> - <p> - The graphic represents the wall clock or thread time for each method. Hover the cursor - over the display to receive information about the method. This information also appears - in the table. - </p> -</ol> - <h2 id="viewtrace"> - Viewing a Saved Method Trace - </h2> - - <p> - After you do a method trace, Android Studio automatically stores it so you can view it - again. To examine the trace, follow these steps: - </p> - - <ol> - <li>Click <strong>Captures</strong> in the main window. - </li> - - <p> - The <em>Captures</em> window appears. - </p> - - <li>Open the <strong>Methods Tracing</strong> folder. - </li> - - <li>Double-click the file to view it. - </li> -</ol> - -<h2 id="sorttrace"> - Sorting Method Trace Data -</h2> - -<p> - You can sort the data by method name, count, inclusive time, and exclusive time. Follow this step: -</p> - - -<ul> - <li>Click a column heading to sort the table by ascending or descending order. - </li> -</ul> - -<h2 id="renametrace"> - Renaming a Method Trace File -</h2> - -<p> - Rename a method trace file from within Android Studio so it - continues to appear in the <em>Captures</em> window. Follow these steps: -</p> - -<ol> - <li>In the <em>Captures</em> window, right-click the file and select <strong>Rename</strong>. - </li> - - <li>In the dialog, specify the name of the file and click <strong>OK</strong>. - </li> -</ol> - -<h2 id="locatetrace"> - Locating a Method Trace File on Disk +<h2 id="snapshot"> + Recording Call Stack Changes </h2> <p> - You can quickly discover where Android Studio stored method trace files on disk. Follow this step: -</p> - - - -<ul> - <li>In the <em>Captures</em> window, right-click a method trace file and select <strong>Show in - files</strong>. - </li> - -<p> - Android Studio opens an operating system file browser displaying the location where the file - resides. -</p> -</ul> -<p class="note"> - <strong>Note:</strong> If you move a method trace file, Android Studio no longer displays the file - in the <em>Captures</em> window. To display it, use <strong>File</strong> > - <strong>Open</strong>. Also, rename a file from the <em>Captures</em> - window and not in the operating system file browser. + You can capture a record of the changes on the call stack during a particular + time period while the CPU Monitor is running. For more information, see + <a href="{@docRoot}tools/help/am-methodtrace.html">Method Trace</a>. </p> -<h2 id="deletetrace"> - Deleting a Method Trace File -</h2> -<p> - Follow this step in Android Studio: -</p> -<ul> - <li>In the <em>Captures</em> window, right-click a method trace file and select - <strong>Delete</strong>. - </li> -</ul> -<p> - Android Studio deletes the file from the <em>Captures</em> dialog and from disk. -</p>
\ No newline at end of file diff --git a/docs/html/tools/help/am-gpu.jd b/docs/html/tools/help/am-gpu.jd index a244b224d49d..fb140ad8b9b2 100644 --- a/docs/html/tools/help/am-gpu.jd +++ b/docs/html/tools/help/am-gpu.jd @@ -1,7 +1,12 @@ page.title=GPU Monitor parent.title=Android Monitor parent.link=android-monitor.html -page.tags=monitor +meta.tags="android, performance, profiling, tools, monitor" +page.tags="android", "performance", "profiling", "tools", "monitor" +page.metaDescription=Use the GPU Monitor for a visual representation of how much time it takes to render the frames of a UI window. Use this information to optimize the code that displays graphics and conserve memory. +page.image=tools/help/thumbnails/am-gpumon.png +page.article=true + @jd:body <div id="qv-wrapper"> @@ -11,59 +16,6 @@ page.tags=monitor <li><a href="#running">Displaying a Running App in the GPU Monitor</a></li> </ol> - <h2>See also</h2> - <ol> - <li> - <a href="{@docRoot}tools/help/android-monitor.html">Android Monitor</a> - </li> - <li><a href="{@docRoot}tools/help/am-logcat.html">logcat Monitor</a> - </li> - - <li><a href="{@docRoot}tools/help/am-memory.html">Memory Monitor</a> - </li> - - <li><a href="{@docRoot}tools/help/am-cpu.html">CPU Monitor</a> - </li> - - <li> - <a href="{@docRoot}tools/help/am-network.html">Network Monitor</a> - </li> - </ol> - -<h2> - Dependencies and Prerequisites -</h2> - -<ul> - <li>Make sure your development computer detects your hardware device, which often happens - automatically when you connect it to a USB port. - </li> - - <li> - <a href="{@docRoot}tools/device.html#device-developer-options">Enable</a> <strong><a href= - "{@docRoot}tools/device.html#device-developer-options">USB debugging</a></strong> in - <strong>Developer Options</strong> on the device or emulator. - </li> - - <li>For Android 5.0 (API level 21) and Android 5.1 (API level 22), in <strong>Developer - Options</strong> on the device or emulator, set <strong>Profile GPU rendering</strong> to - <strong>In adb shell dumpsys gfxinfo</strong>. - </li> - - <li>In your app, set the <code>debuggable</code> property to <code>true</code> in the manifest or - <code>build.gradle</code> file (it’s initially set by default). - </li> - - - <li>Enable ADB integration through <strong>Tools</strong> > <strong>Android</strong> > - <strong>Enable ADB Integration</strong>. - </li> - - <li> - <a href="{@docRoot}tools/help/monitor.html">Android Device Monitor</a> can’t be running. - </li> -</ul> - </div> </div> @@ -96,33 +48,34 @@ page.tags=monitor </h2> <p> - Follow these steps: + To display an app running on a particular device or emulator in the GPU Monitor: </p> <ol> - <li>Optionally connect a hardware device. - </li> - - <li> - <a href="{@docRoot}tools/help/android-monitor.html#displaying">Display Android Monitor</a>. + <li>Meet the <a href= + "{@docRoot}tools/help/am-basics.html#byb">prerequisites and dependencies</a>. </li> - - <li>Click the <strong>GPU</strong> tab. + <li>Open an app project. </li> - - <li>Open an app project and <a href= - "{@docRoot}tools/building/building-studio.html#RunningApp">run it</a> on a hardware device or + <li><a href= + "{@docRoot}tools/building/building-studio.html#RunningApp">Run the app</a> on a hardware device or emulator. </li> + <li> + <a href="{@docRoot}tools/help/am-basics.html#displaying">Display Android Monitor</a>. + </li> + <li>Click the <strong>Monitors</strong> tab and <a href= + "{@docRoot}tools/help/am-basics.html#rearranging">display the GPU Monitor</a>. + </li> - <li>Enable the GPU Monitor by clicking Pause <img src="{@docRoot}images/tools/am-ipause.png" style="vertical-align:sub;margin:0;height:17px" alt="Pause icon" /> to deselect - it. + <li>Enable the GPU Monitor by clicking Pause <img src="{@docRoot}images/tools/am-ipause.png" + style="vertical-align:sub;margin:0;height:17px" alt="Pause icon" /> to deselect it. </li> <p> Any GPU usage begins to appear in the GPU Monitor: </p> - <img src="{@docRoot}images/tools/am-gpumon.png" style="vertical-align:sub;margin:0;width:450px" /> + <img src="{@docRoot}images/tools/am-gpumon2.png" style="vertical-align:sub;margin:0" /> <p> The y-axis is the amount of time it takes the GPU to execute, process, prepare, and draw frames, diff --git a/docs/html/tools/help/am-hprof.jd b/docs/html/tools/help/am-hprof.jd new file mode 100644 index 000000000000..1eef6ab76c91 --- /dev/null +++ b/docs/html/tools/help/am-hprof.jd @@ -0,0 +1,355 @@ +page.title=HPROF Viewer and Analyzer +parent.title=Android Monitor +parent.link=android-monitor.html +meta.tags="android, performance, profiling, tools, monitor" +page.tags="android", "performance", "profiling", "tools", "monitor" +page.metaDescription=Use the Memory Monitor to dump the Java heap to an HPROF file. The HPROF Viewer displays classes, instances of each class, and a reference tree to help you track memory usage and find memory leaks. +page.image=tools/help/thumbnails/am_hprofviewer.png +page.article=true + +@jd:body + +<div id="qv-wrapper"> +<div id="qv"> + <h2>In this document</h2> +<ol> + <li><a href="#why">Why Look at the Java Heap?</a></li> + <li><a href="#display">Understanding the HPROF Viewer Display</a></li> + <li><a href="#hprof-snapshot">Taking a Snapshot of the Java Heap</a></li> + <li><a href="#hprof-viewing">Viewing a Saved HPROF File</a></li> + <li><a href="#hprof-diving">Diving into Heap Dump Data in the HPROF Viewer</a></li> + <li><a href="#hprof-analyzing">Analyzing Heap Dump Data in the HPROF Analyzer</a></li> + <li><a href="#hprof-sorting">Sorting Heap Dump Data</a></li> + <li><a href="#hprof-source">Displaying Java Source</a></li> + <li><a href="#hprof-files">Working with HPROF Files</a></li> + +</ol> + + <h2>See also</h2> + <ol> + <li><a href="{@docRoot}training/articles/memory.html">Managing Your App's Memory</a></li> + <li><a href="{@docRoot}guide/practices/verifying-apps-art.html#GC_Migration">Addressing Garbage Collection Issues</a></li> + <li><a href="{@docRoot}tools/debugging/debugging-memory.html">Investigating Your RAM Usage</a></li> + </ol> + +</div> +</div> + + +<p> + When you're monitoring memory usage in the Memory Monitor you can, at the same time, dump a + snapshot of the Java heap to an Android-specific Heap/CPU Profiling (HPROF) file. The HPROF Viewer + displays classes, instances of each class, and a reference tree to help you track memory usage + and find memory leaks. HPROF is a binary heap dump format originally supported by J2SE. +</p> +<h2 id="why"> + Why Look at the Java Heap? +</h2> +<p>The Java heap display does the following:</p> + +<ul> + <li>Shows snapshots of a number of objects allocated by type. + </li> + + <li>Samples data every time a garbage collection event occurs naturally or is triggered by you. + </li> + + <li>Helps identify which object types might be involved in memory leaks. + </li> +</ul> + +<p> + However, you have to look for changes over time yourself by tracking what's happening in the + graph. +</p> + +<p> + The HPROF Analyzer finds the following potential issues: +</p> + +<ul> + <li>All destroyed activity instances that are reachable from garbage collection roots. + </li> + + <li>Where the target program has strings that repeat values. + </li> +</ul> + +<p> + A dominator is at the top of a tree. If you remove it, you also remove the branches of the tree + it dominates, so it’s a potential way to free memory. +</p> + +<h2 id="display"> + Understanding the HPROF Viewer Display +</h2> + +<p> + The HPROF Viewer looks similar to the following figure: +</p> +<img src="{@docRoot}images/tools/am-hprofviewer.png" /> +<p> + The tool displays the following information: +</p> + +<table> + <tr> + <th scope="col">Column</th> + <th scope="col">Description</th> + </tr> + + <tr> + <td><strong>Class Name</strong></td> + <td>The Java class responsible for the memory.</td> + </tr> + + <tr> + <td><strong>Total Count</strong></td> + <td>Total number of instances outstanding.</td> + </tr> + <tr> + <td><strong>Heap Count</strong></td> + <td>Number of instances in the selected heap.</td> + </tr> + <tr> + <td><strong>Sizeof</strong></td> + <td>Size of the instances (currently, 0 if the size is variable).</td> + </tr> + <tr> + <td><strong>Shallow Size</strong></td> + <td>Total size of all instances in this heap.</td> + </tr> + <tr> + <td><strong>Retained Size</strong></td> + <td>Size of memory that all instances of this class is dominating.</td> + </tr> + <tr> + <td><strong>Instance</strong></td> + <td>A specific instance of the class.</td> + </tr> + <tr> + <td><strong>Reference Tree</strong></td> + <td>References that point to the selected instance, as well as references pointing to the + references.</td> + </tr> + <tr> + <td><strong>Depth</strong></td> + <td>The shortest number of hops from any GC root to the selected instance.</td> + </tr> + <tr> + <td><strong>Shallow Size</strong></td> + <td>Size of this instance.</td> + </tr> + <tr> + <td><strong>Dominating Size</strong></td> + <td>Size of memory that this instance is dominating.</td> + </tr> +</table> + +<p>If you click <strong>Capture Analysis</strong>, the HPROF Analyzer appears: </p> +<img src="{@docRoot}images/tools/am-hprofanalyzer.png" /> +<p>You can detect leaked activities and find duplicate strings with the HPROF Analyzer.</p> + +<h2 id="hprof-snapshot"> + Taking and Displaying a Snapshot of the Java Heap +</h2> + +<p> + To examine a snapshot of the Java heap: +</p> + +<ol> + <li><a href="{@docRoot}tools/help/am-memory.html#displaying">Display a running app in the Memory + Monitor</a>.</li> + <li>Click Dump Java Heap + <img src="{@docRoot}images/tools/am-idump.png" + style="vertical-align:sub;margin:0;height:17px" alt="Dump Java Heap icon" />. + </li> + + +<p> + When the icon on the Memory Monitor display changes from + <img src="{@docRoot}images/tools/am-idumpstart.png" + style="vertical-align:sub;margin:0;height:17px" alt="Dump Java Heap Start icon" /> to + <img src="{@docRoot}images/tools/am-idumpend.png" style="vertical-align:sub;margin:0;height:17px" + alt="Dump Java Heap End icon" />, the file is ready. Android Studio creates the heap snapshot + file with the + filename <code><em>package_yyyy.mm.dd_hh.mm.ss</em>.hprof</code> using + the activity package (or project) name, year, month, day, hour, minute, and second of the + capture, for example, + <code>com.android.calc_2015.11.17_14.58.48.hprof</code>. +</p> +<p> + The HPROF Viewer appears. +</p> +</ol> + +<h2 id="hprof-viewing">Viewing a Saved HPROF File</h2> +<p>After you do a heap dump, Android Studio automatically stores it so you can view it again. + </p> + <p>To view an HPROF file in the HPROF Viewer:</p> + +<ol> +<li>Click +<img src="{@docRoot}images/tools/am-icaptures.png" +style="vertical-align:sub;margin:0;height:17px" + alt="Captures icon" /> in the main window.</li> +<p>Or select <strong>View</strong> > <strong>Tools Windows</strong> > +<strong>Captures</strong>.</p> +<p>The <em>Captures</em> window appears.</p> +<li>Open the <strong>Heap Snapshot</strong> folder.</li> + + + <li>Double-click the file to view it in the HPROF Viewer. + </li> +<p> + The HPROF Viewer appears. +</p> + + + <li>Select the Heap menu option you want to display: + <ul> + <li> + <strong>App heap</strong> - The heap used by the current app. + </li> + + <li><strong>Image heap</strong> - The memory mapped copy of the + current app on disk. + </li> + + + <li> + <strong>Zygote heap</strong> - The common set of libraries and runtime classes and data that + all apps are forked + from. The zygote space is created during device startup and is never allocated into. + </li> + + </ul> + + <li>Select the View menu option you want to display: + <ul> + <li> + <strong>Class List View</strong> + </li> + + <li> + <strong>Package Tree View</strong> + </li> + </ul> + </ol> + + +<h2 id="hprof-diving"> + Diving into Heap Dump Data in the HPROF Viewer +</h2> +<p>The following steps outline the typical workflow:</p> +<ol> +<li>In the HPROF Viewer, select a class name. </li> +<li>Select an instance of that class.</li> +<li>Examine the reference tree.</li> +<li>Right-click an item to <strong>Jump to source</strong> or <strong>Go to instance</strong>, + as needed.</li> +</ol> + + + +<h2 id="hprof-analyzing">Analyzing Heap Dump Data in the HPROF Analyzer</h2> +<p>You can detect leaked activities and find duplicate strings with the HPROF Analyzer. + </p> + <p>To use the HPROF Analyzer:</p> +<ol> +<li>In the <em>Captures</em> window, double-click an <code>.hprof</code> file to display it in the + HPROF Viewer. </li> +<li>Click <strong>Capture Analysis</strong> on the right side of the main Android Studio window.</li> + + +<p>The HPROF Analyzer appears to the right of the HPROF Analyzer, by default.</p> + + + +<li>In the <strong>Analyzer Tasks</strong> list, select the items you want to find.</li> +<li>Click Perform Analysis <img src="{@docRoot}images/tools/am-iperformanalysis.png" + style="vertical-align:sub;margin:0;height:17px" alt="Perform Analysis icon" />.</li> +<li>Examine the items in <strong>Analysis Results</strong>. Click an item to display it in the + HPROF Viewer.</li> +</ol> + + + +<h2 id="hprof-sorting">Sorting Heap Dump Data</h2> +<p>To sort heap dump data:</p> +<ul> +<li>In the HPROF Viewer, click a column heading to sort the table by ascending or descending + order. </li> +</ul> + + +<h2 id="hprof-source">Displaying Java Source</h2> +<p>For some items displayed in the HPROF Viewer, you can go straight to its +source code. +</p> +<p>To display Java source:</p> +<ul> +<li>In the HPROF Viewer, right-click a class, instance, or item in the reference tree, and then + select <strong>Jump to Source</strong>. </li> + + +<p>The source code appears in the Code Editor.</p> +</ul> + +<h2 id="hprof-files">Working with HPROF Files</h2> +<p>You can rename, locate, and delete an HPROF file from within Android Studio. +You can also convert it to standard HPROF format to use with other analysis +tools.</p> + +<h3 id="hprof-renaming">Renaming an HPROF file</h3> + +<p>If you rename a file from within Android Studio, it continues to appear in +the <em>Captures</em> window.</p> +<p>To rename an HPROF file:</p> +<ol> +<li>In the <em>Captures</em> window, right-click the file and select <strong>Rename</strong>. </li> +<li>In the dialog, specify the name of the file and click <strong>OK</strong>.</li> +</ol> + + +<h3 id="hprof-locating">Locating a heap dump file on disk</h3> +<p>You can quickly discover where Android Studio stored HPROF files on disk.</p> + + +<p>To locate an HPROF file on disk: </p> +<ul> +<li>In the <em>Captures</em> window, right-click a heap snapshot file and select + <strong>Show</strong> or <strong>Reveal</strong>.</li> + +<p>Android Studio opens an operating system file browser displaying the location where the file + resides.</p> +</ul> +<p class="note"><strong>Note:</strong> If you move an HPROF file, Android Studio no longer + displays it in the <em>Captures</em> window. To display it, use + <strong>File</strong> > <strong>Open</strong>. Also, if you want to rename the file, do it + from the <em>Captures</em> window and not in the operating system file browser. </p> + +<h3 id="hprof-deleting">Deleting a heap dump file</h3> + +<p>To delete a heap dump file: </p> +<ul> +<li>In the <em>Captures</em> window, right-click a heap snapshot file and select + <strong>Delete</strong>.</li> + +<p>Android Studio deletes the file from the <em>Captures</em> dialog and from disk. </p> +</ul> + +<h3 id="hprof-converting">Converting a heap dump file to standard HPROF format</h3> +<p>You can convert an HPROF file to standard format so you can use it outside of Android Studio with + other analysis tools. </p> + <p>To convert an HPROF file:</p> +<ol> +<li>In the <em>Captures</em> window, right-click a heap snapshot file and select <strong>Export to + standard .hprof</strong>.</li> +<li>In the <em>Convert Android Java Heap Dump</em> dialog, specify a filename and click + <strong>OK</strong>.</li> + + +<p>Android Studio creates a binary HPROF file in the location you specified.</p> +</ol> diff --git a/docs/html/tools/help/am-logcat.jd b/docs/html/tools/help/am-logcat.jd index 57da848ae1d7..9e26bca6053b 100644 --- a/docs/html/tools/help/am-logcat.jd +++ b/docs/html/tools/help/am-logcat.jd @@ -1,7 +1,12 @@ page.title=logcat Monitor parent.title=Android Monitor parent.link=android-monitor.html -page.tags=monitor +meta.tags="android, performance, profiling, tools, monitor" +page.tags="android", "performance", "profiling", "tools", "monitor" +page.metaDescription=Use the logcat Monitor to view system and user-defined log messages. You can filter the messages to display just the items that interest you. +page.image=tools/help/thumbnails/am-logcatmon2.png +page.article=true + @jd:body <div id="qv-wrapper"> <div id="qv"> @@ -43,16 +48,13 @@ page.tags=monitor </li> <li> - <a href="#printing">Printing the Log</a> + <a href="#printing">Printing and Writing to a File</a> </li> <li> - <a href="#clearing">Clearing the Log</a> + <a href="#clearing">Clearing and Restarting the Log</a> </li> - <li> - <a href="#restarting">Restarting the Log</a> - </li> </ol> <h2> @@ -63,58 +65,31 @@ page.tags=monitor <li> <a href="{@docRoot}tools/debugging/debugging-log.html">Reading and Writing Logs</a> </li> - <li> - <a href="{@docRoot}tools/help/android-monitor.html">Android Monitor</a> - </li> - - <li><a href="{@docRoot}tools/help/am-memory.html">Memory Monitor</a> - </li> - - <li><a href="{@docRoot}tools/help/am-cpu.html">CPU Monitor</a> - </li> - - <li><a href="{@docRoot}tools/help/am-gpu.html">GPU Monitor</a> - </li> - - <li> - <a href="{@docRoot}tools/help/am-network.html">Network Monitor</a> - </li> </ol> - <h2> - Dependencies and Prerequisites - </h2> - - <ul> - <li>Enable ADB integration through <strong>Tools</strong> > <strong>Android</strong> > - <strong>Enable ADB Integration</strong>. - </li> - <li> - <a href="{@docRoot}tools/help/monitor.html">Android Device Monitor</a> can’t be running. - </li> - </ul> </div> </div> <p> The Android logging system provides a mechanism for collecting and viewing system debug output. - logcat Monitor displays messages that you added to your app by using the <a href= - "{@docRoot}reference/android/util/Log.html">Log</a> class, as well as system - messages, such as stack traces when the emulator throws an error or a garbage collection occurs. - The monitor displays messages in real time and also keeps a history so you can view older + The logcat Monitor displays system messages, such as when a garbage collection occurs, as well as + messages that you added to your app by using the <a href= + "{@docRoot}reference/android/util/Log.html">Log</a> class. + It displays messages in real time and also keeps a history so you can view older messages. </p> <p> To display just the information of interest, you can create filters, modify how much information is displayed in messages, set priority levels, display messages produced by app code - only, and search the log. By default, logcat Monitor shows the log output related to the running - application only. + only, and search the log. By default, the logcat Monitor shows the log output related to the + most recently run app only. </p> <p> - You can traverse the stack trace when your app throws an exception, as well as view the - associated code. This feature can help you fix exceptions and improve app operation. + When an app throws an exception, the logcat Monitor shows a message followed by the associated + stack trace containing links to + the code. This feature can help you fix errors and improve app operation. </p> <h2 id="format"> @@ -125,9 +100,9 @@ page.tags=monitor Every Android log message has a tag and a priority associated with it. The tag of a system log message is a short string indicating the system component from which the message originates (for example, - <code>ActivityManager</code>). A user-defined tag can be any string that you find helpful, such - as the name of the current class (the recommended tag). You define it in a <code>Log</code> - method call, for example: + {@link android.app.ActivityManager}). A user-defined tag can be any string that you find helpful, + such as the name of the current class (the recommended tag). You define it in a + {@link android.util.Log} method call, for example: </p> <pre> @@ -189,31 +164,38 @@ Log.d(tag, message); </h2> <p> - Follow these steps: + To display the log messages for a particular app: </p> <ol> - <li>Optionally connect a hardware device. + <li>Meet the <a href= + "{@docRoot}tools/help/am-basics.html#byb">prerequisites and dependencies</a>. + </li> + <li>Open an app project. + </li> + <li><a href= + "{@docRoot}tools/building/building-studio.html#RunningApp">Run the app</a> on a hardware device or + emulator. </li> - <li> - <a href="{@docRoot}tools/help/android-monitor.html#displaying">Display Android Monitor</a>. + <a href="{@docRoot}tools/help/am-basics.html#displaying">Display Android Monitor</a>. </li> <li>Click the <strong>logcat</strong> tab. </li> - <li>Open an app project and <a href= - "{@docRoot}tools/building/building-studio.html#RunningApp">run it</a> on a hardware device or - emulator. - </li> + <p> - By default, the logcat Monitor displays messages for the app running on the device or emulator: + By default, the logcat Monitor displays just the log messages for your app running on the + device or emulator: </p> -<img src="{@docRoot}images/tools/am-logcatmon.png" /> +<img src="{@docRoot}images/tools/am-logcatmon2.png" /> <p> To change this default, see <a href="#filtering">Filtering logcat Messages</a>. </p> +<li>Optionally <a href= + "{@docRoot}tools/help/am-basics.html#switching">select a different device, emulator, or process</a>. + </li> </ol> <h2 id="level"> @@ -221,17 +203,17 @@ Log.d(tag, message); </h2> <p> - You can control how many messages appear in logcat Monitor by setting the log level. You can + You can control how many messages appear in the logcat Monitor by setting the log level. You can display all messages, or just the messages indicating the most severe conditions. </p> <p> - Remember that logcat Monitor continues to collect all messages regardless of the log level setting. - The setting just determines what logcat Monitor displays. + Remember that the logcat Monitor continues to collect all messages regardless of the log level setting. + The setting just determines what the logcat Monitor displays. </p> <p> - Follow this step: + To set the log level: </p> <ul> @@ -259,7 +241,7 @@ Log.d(tag, message); </li> <li> - <strong>Error</strong> - Show issues that have caused errors, as well as the message levels + <strong>Error</strong> - Show issues that have caused errors, as well as the message level lower in this list. </li> @@ -275,7 +257,7 @@ Log.d(tag, message); </h2> <p> - You can search the messages currently displayed in logcat Monitor. Follow these steps: + To search the messages currently displayed in the logcat Monitor: </p> <ol> @@ -292,7 +274,7 @@ Log.d(tag, message); </p> </li> - <li>Press <strong>Enter</strong> to store the sequence in the menu during this session. + <li>Press Enter to store the search string in the menu during this session. </li> <li>To repeat a search, choose it from the search menu. Select or deselect @@ -310,12 +292,12 @@ Log.d(tag, message); <p class="note"> <strong>Note:</strong> The filter applies to your full logcat history, not just those messages - currently displayed in logcat Monitor. Make sure your other display options are set + currently displayed in the logcat Monitor. Make sure your other display options are set appropriately so you can see the filter output you want to examine. </p> <p> - To define and apply a filter, follow these steps: + To define and apply a filter: </p> <ol> @@ -323,15 +305,18 @@ Log.d(tag, message); <ul> <li> <strong>Show only selected application</strong> - Display the messages produced by the - app code only. + app code only (the default). The logcat Monitor filters the log messages using the PID + of the active app. </li> <li> - <strong>No Filters</strong> - Apply no filters (the default). + <strong>No Filters</strong> - Apply no filters. The logcat Monitor + displays all log messages from the device, regardless of which process you selected. </li> <li> - <strong>Edit Filter Configuration</strong> - Create or modify a custom filter. + <strong>Edit Filter Configuration</strong> - Create or modify a custom filter. For + example, you could create a filter to view log messages from two apps at the same time. </li> </ul> @@ -386,7 +371,7 @@ Log.d(tag, message); </ul> <li> - Click <strong>+</strong> to add it to the left pane. + Click <strong>+</strong> to add the filter definition to the left pane. </li> <p> @@ -398,6 +383,14 @@ Log.d(tag, message); <strong>Cancel</strong>, any filter additions or modifications are lost. </li> </ol> + <li> + Make sure you see the log messages you want to examine. + </li> + <p> + If you don't think you see the log messages you want, try selecting + <strong>No filters</strong> and <a href="#searching">searching</a> for particular + log messages. + </p> </ol> <h2 id="logheader"> @@ -405,7 +398,7 @@ Log.d(tag, message); </h2> <p> - You can customize the header display to show just the information you’re interested + To customize the header display to show just the information you’re interested in: </p> @@ -440,7 +433,9 @@ Log.d(tag, message); in the Code Editor. If needed (and possible), the decompiler derives source code that you can view. </p> - + <p> + To move up and down the stack trace, and view the associated code in the Code Editor: + </p> <ul> <li>Click Up the Stack Trace <img src="{@docRoot}images/tools/am-iupstack.png" style="vertical-align:sub;margin:0;height:17px" alt="Up the Stack Trace icon" /> @@ -460,8 +455,11 @@ Log.d(tag, message); </h2> <p> - Clicking a particular message stops the display of messages. You can quickly move to - the end of the log to see the real-time message flow. + Clicking a particular message stops the display of messages. + </p> + <p> + To quickly move to + the end of the log to see the real-time message flow: </p> <ul> @@ -477,25 +475,48 @@ Log.d(tag, message); </ul> <h2 id="printing"> - Printing the Log + Printing and Writing to a File </h2> <p> - Follow these steps: + To preserve log information, you can send the log to a printer, write the log to a PDF file, or + copy and paste the log into a text file. +</p> +<p> + To print the log or write it to a PDF file: </p> <ol> <li>Click Print <img src="{@docRoot}images/tools/am-iprint.png" style="vertical-align:sub;margin:0;height:17px" alt="Print icon" />. </li> <li> - In the <em>Print</em> dialog, optionally change print parameters, and then click + In the Android Studio <em>Print</em> dialog, optionally change print parameters, and then click <strong>Print</strong>. + </li> + <li> + In the operating system <em>Print</em> dialog, optionally change print parameters, and then click + <strong>Print</strong>. + </li> + <p> + You can set the parameters to send the log to a printer or write it to a PDF file. +</p> +</ol> +<p> + To copy the log to a text file: +</p> +<ol> + <li>In the logcat Monitor, select and then copy log text. + </li> + <p>Press Ctrl+A (⌘A) to select all.</p> + <li> + Open a text editor and paste the text into a file. + </li> </ol> <h2 id="clearing"> - Clearing the Log + Clearing and Restarting the Log </h2> <p> - To clear (flush) the entire log, follow this step: + To clear (flush) the entire log: </p> <ul> <li>Click Clear logcat <img src="{@docRoot}images/tools/am-iclear.png" @@ -504,14 +525,8 @@ Log.d(tag, message); </ul> - -<h2 id="restarting"> - Restarting the Log -</h2> - <p> - If there is a problem and the log is no longer progressing, you can restart the log. Follow this - step: + If there's a problem and the log is no longer progressing, you can restart the log: </p> <ul> diff --git a/docs/html/tools/help/am-memory.jd b/docs/html/tools/help/am-memory.jd index 24006cdbbb70..20c6934a52d7 100644 --- a/docs/html/tools/help/am-memory.jd +++ b/docs/html/tools/help/am-memory.jd @@ -1,7 +1,12 @@ page.title=Memory Monitor parent.title=Android Monitor parent.link=android-monitor.html -page.tags=monitor +meta.tags="android, performance, profiling, tools, monitor" +page.tags="android", "performance", "profiling", "tools", "monitor" +page.metaDescription=Use the Memory Monitor to evaluate memory usage and find deallocated objects, locate memory leaks, and track the amount of memory the connected device is using. +page.image=tools/help/thumbnails/am-memorymon.png +page.article=true + @jd:body <div id="qv-wrapper"> @@ -17,31 +22,7 @@ page.tags=monitor </li> <li><a href="#displaying">Displaying a Running App in the Memory Monitor</a></li> <li><a href="#forcing">Forcing a Garbage Collection Event</a></li> - <li><a href="#dumping">Dumping and Analyzing the Java Heap</a> - <ol> - <li><a href="#hprof-snapshot">Taking and displaying a snapshot of the Java heap</a></li> - <li><a href="#hprof-diving">Diving into heap dump data in the HPROF Viewer</a></li> - <li><a href="#hprof-analyzing">Analyzing heap dump data in the HPROF Analyzer</a></li> - <li><a href="#hprof-sorting">Sorting heap dump data</a></li> - <li><a href="#hprof-source">Displaying Java source</a></li> - <li><a href="#hprof-viewing">Viewing a saved HPROF file</a></li> - <li><a href="#hprof-renaming">Renaming an HPROF file</a></li> - <li><a href="#hprof-locating">Locating a heap dump file on disk</a></li> - <li><a href="#hprof-deleting">Deleting a heap dump file</a></li> - <li><a href="#hprof-converting">Converting a heap dump file to standard HPROF format</a></li> - </ol> - </li> - <li><a href="#tracking">Tracking and Analyzing Memory Allocation</a> - <ol> - <li><a href="#alloc-snapshot">Taking and displaying a snapshot of allocation data</a></li> - <li><a href="#alloc-sorting">Sorting allocation data</a></li> - <li><a href="#alloc-source">Displaying Java source</a></li> - <li><a href="#alloc-viewing">Viewing a saved allocation tracking file</a></li> - <li><a href="#alloc-renaming">Renaming an allocation tracking file</a></li> - <li><a href="#alloc-locating">Locating an allocation tracking file</a></li> - <li><a href="#alloc-deleting">Deleting an allocation tracking file</a></li> - </ol> - </li> + <li><a href="#snapshot">Taking a Snapshot of the Java Heap and Memory Allocation</a></li> </ol> <h2>See also</h2> @@ -49,53 +30,8 @@ page.tags=monitor <li><a href="{@docRoot}training/articles/memory.html">Managing Your App's Memory</a></li> <li><a href="{@docRoot}guide/practices/verifying-apps-art.html#GC_Migration">Addressing Garbage Collection Issues</a></li> <li><a href="{@docRoot}tools/debugging/debugging-memory.html">Investigating Your RAM Usage</a></li> - - <li> - <a href="{@docRoot}tools/help/android-monitor.html">Android Monitor</a> - </li> - <li><a href="{@docRoot}tools/help/am-logcat.html">logcat Monitor</a> - </li> - - <li><a href="{@docRoot}tools/help/am-cpu.html">CPU Monitor</a> - </li> - - <li><a href="{@docRoot}tools/help/am-gpu.html">GPU Monitor</a> - </li> - - <li> - <a href="{@docRoot}tools/help/am-network.html">Network Monitor</a> - </li> </ol> - -<h2> - Dependencies and Prerequisites -</h2> - -<ul> - <li> - Make sure your development computer detects your hardware device, which often happens - automatically when you connect it to a USB port. - </li> -<li> - <a href="{@docRoot}tools/device.html#device-developer-options">Enable</a> <strong><a href= - "{@docRoot}tools/device.html#device-developer-options">USB debugging</a></strong> in - <strong>Developer Options</strong> on the device or emulator. - </li> - - <li>In your app, set the <code>debuggable</code> property to <code>true</code> in the manifest or - <code>build.gradle</code> file (it’s initially set by default). - </li> - - <li>Enable ADB integration through <strong>Tools</strong> > <strong>Android</strong> > - <strong>Enable ADB Integration</strong>. - </li> - - <li> - <a href="{@docRoot}tools/help/monitor.html">Android Device Monitor</a> can’t be running. - </li> -</ul> - </div> </div> @@ -107,7 +43,7 @@ page.tags=monitor </p> <ul> - <li>Show a graph of available and allocated memory over time. + <li>Show a graph of available and allocated Java memory over time. </li> <li>Show garbage collection (GC) events over time. @@ -227,10 +163,7 @@ page.tags=monitor <p> One way to optimize memory usage is to analyze large arrays. For example, can you reduce the size - of individual elements in the array to save memory? Does a dominator object point to - an element in the array, preventing it from being garbage-collected? If the dominator object - directly points to an element in the array, the dominator is either the contiguous memory - representing the underlying data of the array, some part of the array, or the array itself. + of individual elements in the array to save memory? </p> <p> @@ -347,25 +280,26 @@ page.tags=monitor </h2> <p> - Follow these steps: + To display an app running on a particular device or emulator in the Memory Monitor: </p> <ol> - <li>Optionally connect a hardware device. + <li>Meet the <a href= + "{@docRoot}tools/help/am-basics.html#byb">prerequisites and dependencies</a>. + </li> + <li>Open an app project. + </li> + <li><a href= + "{@docRoot}tools/building/building-studio.html#RunningApp">Run the app</a> on a hardware device or + emulator. </li> - <li> - <a href= - "{@docRoot}tools/help/android-monitor.html#displaying">Display Android Monitor</a>. + <a href="{@docRoot}tools/help/am-basics.html#displaying">Display Android Monitor</a>. </li> - - <li>Click the <strong>Memory</strong> tab. + <li>Click the <strong>Monitors</strong> tab and <a href= + "{@docRoot}tools/help/am-basics.html#rearranging">display the Memory Monitor</a>. </li> - <li>Open an app project and <a href= - "{@docRoot}tools/building/building-studio.html#RunningApp">run it</a> on a - hardware device or emulator. - </li> <li>Enable the Memory Monitor by clicking Pause <img src="{@docRoot}images/tools/am-ipause.png" style="vertical-align:sub;margin:0;height:17px" alt="Pause icon" /> to deselect it. @@ -389,10 +323,10 @@ page.tags=monitor <p>In the following figure, the VM initiated the first garbage collection event, while the developer forced the second. </p> -<img src="{@docRoot}images/tools/am-gc.png" /> +<img src="{@docRoot}images/tools/am-gc2.png" /> <li>Interact with your app and watch how it affects memory usage in the Memory Monitor. You can - identify garbage collection patterns for your app and determine whether they are healthy and what + identify garbage collection patterns for your app and determine whether they're healthy and what you expect. </li> @@ -452,465 +386,20 @@ page.tags=monitor </li> </ul> -<h2 id="dumping"> - Dumping and Analyzing the Java Heap +<h2 id="snapshot"> + Taking a Snapshot of the Java Heap and Memory Allocation </h2> <p> - When you're monitoring memory usage in Android Studio you can, at the same time, dump the Java - heap to a heap snapshot in an Android-specific HPROF binary format file. The HPROF Viewer - displays classes, instances of each class, and a reference tree to help you track memory usage - and find memory leaks. HPROF is a heap dump format originally supported by J2SE. -</p> -<p>The Java heap display does the following:</p> - -<ul> - <li>Shows snapshots of a number of objects allocated by type. - </li> - - <li>Samples data every time a garbage collection event occurs naturally or is triggered by you. - </li> - - <li>Helps identify which object types might be involved in memory leaks. - </li> -</ul> - -<p> - However, you have to look for changes over time yourself by tracking what's happening in the - graph. -</p> - -<p> - The HPROF Analyzer finds the following potential issues: + You can take snapshots while the Memory Monitor is running or paused: </p> <ul> - <li>All destroyed activity instances that are reachable from garbage collection roots. + <li>To take and display a snapshot of the Java heap, see <a href= + "{@docRoot}tools/help/am-hprof.html">HPROF Viewer and Analyzer</a>. </li> - - <li>Where the target program has strings that repeat values. + <li>To take and display a snapshot of memory allocation, see <a href= + "{@docRoot}tools/help/am-allocation.html">Allocation Tracker</a>. </li> </ul> -<p> - A dominator is at the top of a tree. If you remove it, you also remove the branches of the tree - it dominates, so it’s a potential way to free memory. -</p> - -<h3 id="hprof-snapshot"> - Taking and displaying a snapshot of the Java heap -</h3> - -<p> - To see a snapshot of the Java heap, follow these steps: -</p> - -<ol> - <li>While the Memory Monitor is running, click Dump Java Heap - <img src="{@docRoot}images/tools/am-idump.png" - style="vertical-align:sub;margin:0;height:17px" alt="Dump Java Heap icon" />. - </li> - - -<p> - When the icon on the Memory Monitor display changes from - <img src="{@docRoot}images/tools/am-idumpstart.png" - style="vertical-align:sub;margin:0;height:17px" alt="Dump Java Heap Start icon" /> to - <img src="{@docRoot}images/tools/am-idumpend.png" style="vertical-align:sub;margin:0;height:17px" - alt="Dump Java Heap End icon" />, the file is ready. Android Studio creates the heap snapshot - file with the - filename <code>Snapshot_<em>yyyy.mm.dd_hh.mm.ss</em>.hprof</code> using - the year, month, day, hour, minute, and second of the capture, for example, - <code>Snapshot_2015.11.17_14.58.48.hprof</code>. -</p> - - <li>Click <strong>Captures</strong> in the main window. - </li> - -<p> - The <em>Captures</em> window appears. -</p> - - <li>Double-click the file to view it in the HPROF Viewer. - </li> - -<p> - The HPROF Viewer appears: -</p> -<img src="{@docRoot}images/tools/am-hprofviewer.png" /> -<p> - The tool displays the following information: -</p> - -<table> - <tr> - <th scope="col">Column</th> - <th scope="col">Description</th> - </tr> - - <tr> - <td><strong>Class Name</strong></td> - <td>The Java class responsible for the memory.</td> - </tr> - - <tr> - <td><strong>Total Count</strong></td> - <td>Total number of instances outstanding.</td> - </tr> - <tr> - <td><strong>Heap Count</strong></td> - <td>Number of instances in the selected heap.</td> - </tr> - <tr> - <td><strong>Sizeof</strong></td> - <td>Size of the instances (currently, 0 if the size is variable).</td> - </tr> - <tr> - <td><strong>Shallow Size</strong></td> - <td>Total size of all instances in this heap.</td> - </tr> - <tr> - <td><strong>Retained Size</strong></td> - <td>Size of memory that all instances of this class is dominating.</td> - </tr> - <tr> - <td><strong>Instance</strong></td> - <td>A specific instance of the class.</td> - </tr> - <tr> - <td><strong>Reference Tree</strong></td> - <td>References that point to the selected instance, as well as references pointing to the - references.</td> - </tr> - <tr> - <td><strong>Depth</strong></td> - <td>The shortest number of hops from any GC root to the selected instance.</td> - </tr> - <tr> - <td><strong>Shallow Size</strong></td> - <td>Size of this instance.</td> - </tr> - <tr> - <td><strong>Dominating Size</strong></td> - <td>Size of memory that this instance is dominating.</td> - </tr> -</table> - - <li>Select the Heap menu option you want to display: - <ul> - <li> - <strong>App heap</strong> - The heap used by the current app. - </li> - - <li><strong>Image heap</strong> - The memory mapped copy of the - current app on disk. - </li> - - - <li> - <strong>Zygote heap</strong> - The common set of libraries and runtime classes and data that - all apps are forked - from. The zygote space is created during device startup and is never allocated into. - </li> - - </ul> - - <li>Select the View menu option you want to display: - <ul> - <li> - <strong>Class List View</strong> - </li> - - <li> - <strong>Package Tree View</strong> - </li> - </ul> - </ol> - - -<h3 id="hprof-diving"> - Diving into heap dump data in the HPROF Viewer -</h3> -<p>The following steps outline the typical workflow:</p> -<ol> -<li>In the HPROF viewer, select a class name. </li> -<li>Select an instance of that class.</li> -<li>Examine the reference tree.</li> -<li>Right-click an item to <strong>Jump to source</strong> or <strong>Go to instance</strong>, - as needed.</li> -</ol> - - - -<h3 id="hprof-analyzing">Analyzing heap dump data in the HPROF Analyzer</h3> -<p>You can detect leaked activities and find duplicate strings with the HPROF Analyzer. - Follow these steps: </p> -<ol> -<li>In the <em>Captures</em> window, double-click an <code>.hprof</code> file to display it in the - HPROF Viewer. </li> -<li>Click <strong>Capture Analysis</strong> on the right side of the main Android Studio window.</li> - - -<p>The HPROF Analyzer appears to the right of the HPROF Analyzer, by default: </p> - -<img src="{@docRoot}images/tools/am-hprofanalyzer.png" /> - -<li>In the <strong>Analyzer Tasks</strong> list, select the items you want to find.</li> -<li>Click Perform Analysis <img src="{@docRoot}images/tools/am-iperformanalysis.png" - style="vertical-align:sub;margin:0;height:17px" alt="Perform Analysis icon" />.</li> -<li>Examine the items in <strong>Analysis Results</strong>. Click an item to display it in the - HPROF Viewer.</li> -</ol> - - - -<h3 id="hprof-sorting">Sorting heap dump data</h3> -<p>Follow this step:</p> -<ul> -<li>In the HPROF Viewer, click a column heading to sort the table by ascending or descending - order. </li> -</ul> - - -<h3 id="hprof-source">Displaying Java source</h3> -<p>For some items displayed in the HPROF Viewer, you can go straight to its source code. - Follow this step:</p> -<ul> -<li>In the HPROF Viewer, right-click a class, instance, or item in the reference tree, and then - select <strong>Jump to Source</strong>. </li> - - -<p>The source code appears in the Code Editor.</p> -</ul> - -<h3 id="hprof-viewing">Viewing a saved HPROF file</h3> -<p>After you do a heap dump, Android Studio automatically stores it so you can view it again. - Follow these steps:</p> - -<ol> -<li>Click <strong>Captures</strong> in the main window.</li> - -<p>The <em>Captures</em> window appears.</p> -<li>Open the <strong>Heap Snapshot</strong> folder.</li> -<li>Double-click the file to view it.</li> -</ol> - - -<h3 id="hprof-renaming">Renaming an HPROF file</h3> - -<p>If you rename a file from within Android Studio, it continues to appear in <em>Captures</em> - window. Follow these steps:</p> -<ol> -<li>In the <em>Captures</em> window, right-click the file and select <strong>Rename</strong>. </li> -<li>In the dialog, specify the name of the file and click <strong>OK</strong>.</li> -</ol> - - -<h3 id="hprof-locating">Locating a heap dump file on disk</h3> -<p>You can quickly discover where Android Studio stored HPROF files on disk.</p> - - -<p>Follow this step in Android Studio: </p> -<ul> -<li>In the <em>Captures</em> window, right-click a heap snapshot file and select - <strong>Show in files</strong>.</li> - -<p>Android Studio opens an operating system file browser displaying the location where the file - resides.</p> -</ul> -<p class="note"><strong>Note:</strong> If you move an HPROF file, Android Studio no longer - displays it in the <em>Captures</em> window. To display it, use - <strong>File</strong> > <strong>Open</strong>. Also, if you want to rename the file, do it - from the <em>Captures</em> window and not in the operating system file browser. </p> - -<h3 id="hprof-deleting">Deleting a heap dump file</h3> - -<p>To delete a heap dump file, follow this step: </p> -<ul> -<li>In the <em>Captures</em> window, right-click a heap snapshot file and select - <strong>Delete</strong>.</li> - -<p>Android Studio deletes the file from the <em>Captures</em> dialog and from disk. </p> -</ul> - -<h3 id="hprof-converting">Converting a heap dump file to standard HPROF format</h3> -<p>You can convert an HPROF file to standard format so you can use it outside of Android Studio with - other analysis tools. Follow these steps: </p> -<ol> -<li>In the <em>Captures</em> window, right-click a heap snapshot file and select <strong>Export to - standard .hprof</strong>.</li> -<li>In the <em>Convert Android Java Heap Dump</em> dialog, specify a filename and click - <strong>OK</strong>.</li> - - -<p>Android Studio creates a binary HPROF file in the location you specified.</p> -</ol> - -<h2 id="tracking"> - Tracking and Analyzing Memory Allocation -</h2> - -<p>Android Studio allows you to track memory allocation as it monitors memory use. Tracking memory - allocation allows you to monitor where objects are being allocated when you perform certain - actions. Knowing these allocations enables you to adjust the method calls related to those actions - to optimize app performance and memory use.</p> - -<p>The Allocation Tracker does the following:</p> -<ul> -<li>Shows when and where your code allocates object types, their size, allocating thread, and stack - traces.</li> -<li>Helps recognize memory churn through recurring allocation/deallocation patterns.</li> -<li>Help you track down memory leaks when used in combination with the HPROF Viewer. For example, - if you see a bitmap object resident on the heap, you can find its allocation location with - Allocation Tracker.</li> -</ul> - - -<p>However, it takes time and experience to learn to interpret the output from this tool.</p> - -<h3 id="alloc-snapshot">Taking and displaying a snapshot of allocation data</h3> - -<p>Follow these steps:</p> -<ol> -<li>While the Memory Monitor is running, click Start Allocation Tracking - <img src="{@docRoot}images/tools/am-ialloctracking.png" - style="vertical-align:sub;margin:0;height:17px" alt="Start Allocation Tracking icon" />. </li> -<li>Click Start Allocation Tracking - <img src="{@docRoot}images/tools/am-ialloctracking.png" - style="vertical-align:sub;margin:0;height:17px" alt="Start Allocation Tracking icon" /> again to - deselect it and end the snapshot. </li> - - <p>The Memory Monitor displays the period when it took the snapshot. In the following - figure, you can see the snapshot period, as shown on the left. By comparison, when you dump the - Java heap, the Memory Monitor displays just the point where the heap snapshot was taken, as - shown on the right.</p> - <img src="{@docRoot}images/tools/am-dumpalloc.png" /> - -<p>Android Studio creates the heap snapshot file with the - filename <code>Allocations_<em>yyyy.mm.dd_hh.mm.ss</em>.alloc</code> using the year, month, day, - hour, minute, and second of the capture, for example, - <code>Allocations_2015.11.17_14.58.48.alloc</code>.</p> -<li>Click <strong>Captures</strong> in the main window.</li> - - -<p>The <em>Captures</em> window appears.</p> -<li>Double-click the file to view it in the Allocation Tracker. </li> -<li>Optionally click the graphic icon to display a visual representation of the data. - </li> -<p> - The Allocation Tracker appears: -</p> -<img src="{@docRoot}images/tools/am-alloctracker.png" /> -<p> - - -<p>The tool displays the following information: </p> - -<table> - <tr> - <th scope="col">Column</th> - <th scope="col">Description</th> - </tr> - - <tr> - <td><strong>Method</strong></td> - <td>The Java method responsible for the allocation.</td> - </tr> - <tr> - <td><strong>Count</strong></td> - <td>Total number of instances allocated.</td> - </tr> - <tr> - <td><strong>Size</strong></td> - <td>The total amount of allocated memory in bytes.</td> - </tr> - -</table> - - -<li>Select the Group By menu option you want to display: </li> -<ul> -<li><strong>Group by Allocator</strong> </li> -<li><strong>Group by Method</strong></li> -</ul> - -</ol> - - - -<h3 id="alloc-sorting">Sorting allocation data</h3> - -<p>Follow this step:</p> -<ul> -<li>In the Allocation Tracker, click a column heading to sort the table by ascending or - descending order. </li> -</ul> - - -<h3 id="alloc-source">Displaying Java source</h3> -<p>For some items displayed in the Allocation Tracker, you can view the Java source. Follow one of - these steps:</p> -<ul> -<li>In the Allocation Tracker, right-click a method and then select <strong>Jump to Source</strong>. -</li> -<li>In the Allocation Tracker, select a method and then click Jump to Source - <img src="{@docRoot}images/tools/am-ijumptosource.png" - style="vertical-align:sub;margin:0;height:17px" alt="Jump to Source icon" />. </li> -</ul> - -<p>The source code appears in the Code Editor.</p> - -<h3 id="alloc-viewing">Viewing a saved allocation tracking file</h3> -<p>After you monitor allocation tracking, Android Studio automatically stores it so you can view it - again. Follow these steps:</p> - - -<ol> -<li>Click <strong>Captures</strong> in the main window.</li> - - -<p>The <em>Captures</em> window appears.</p> -<li>Open the <strong>Allocation Tracking</strong> folder.</li> -<li>Double-click the file to view it.</li> -</ol> - - -<h3 id="alloc-renaming">Renaming an allocation tracking file</h3> - -<p>If you rename a file from within Android Studio, it continues to appear in the <em>Captures</em> - window. Follow these steps:</p> -<ol> -<li>In the <em>Captures</em> window, right-click the file and select <strong>Rename</strong>.</li> -<li>In the <em>Rename</em> dialog, specify the name of the file and click <strong>OK</strong>.</li> -</ol> - - -<h3 id="alloc-locating">Locating an allocation tracking file</h3> -<p>You can quickly discover where Android Studio stored allocation tracking files on disk.</p> - - -<p>Follow this step in Android Studio: </p> -<ul> -<li>In the <em>Captures</em> window, right-click allocation file and select - <strong>Show in Files</strong>.</li> - -<p>Android Studio opens an operating system file browser displaying the location where the file - resides.</p> -</ul> - -<p class="note"><strong>Note:</strong> If you move an allocation tracking file, Android Studio - no longer displays it in the <em>Captures</em> window. To display the file, use - <strong>File</strong> - > <strong>Open</strong>. Also, rename the file from the <em>Captures</em> - window and not in the operating system file browser. </p> - -<h3 id="alloc-deleting">Deleting an allocation tracking file</h3> - - -<p>Follow this step: </p> -<ul> -<li>In the <em>Captures</em> window, right-click an allocation tracking file and select - <strong>Delete</strong>.</li> - -<p>Android Studio deletes the file from the <em>Captures</em> dialog and from disk. </p> -</ul> diff --git a/docs/html/tools/help/am-methodtrace.jd b/docs/html/tools/help/am-methodtrace.jd new file mode 100644 index 000000000000..7d5f070b5979 --- /dev/null +++ b/docs/html/tools/help/am-methodtrace.jd @@ -0,0 +1,266 @@ +page.title=Method Trace +parent.title=Android Monitor +parent.link=android-monitor.html +meta.tags="android, performance, profiling, tools, monitor" +page.tags="android", "performance", "profiling", "tools", "monitor" +page.metaDescription=Use the CPU Monitor to perform a method trace on your app. View call stack and timing information in the method trace display. +page.image=tools/help/thumbnails/am_methodtrace.png +page.article=true + +@jd:body + +<div id="qv-wrapper"> +<div id="qv"> + <h2>In this document</h2> +<ol> +<li><a href="#display">Understanding the Method Trace Display</a></li> + <li><a href="#trace">Performing a Method Trace in the CPU Monitor</a></li> + <li><a href="#viewtrace">Viewing a Saved Method Trace</a></li> + <li><a href="#sorttrace">Sorting Method Trace Data</a></li> + <li><a href="#trace-files">Working with Method Trace Files</a></li> +</ol> + +</div> +</div> + + +<p> + You can start a method trace from the CPU Monitor. It lets you view the call stack and timing + information for your app. This information can help you optimize and debug your app. +</p> + +<h2 id="display"> + Understanding the Method Trace Display +</h2> + +<p> + The method trace looks similar to the following figure: +</p> +<img src="{@docRoot}images/tools/am-methodtrace.png" alt="Method Trace" /> +<p></p> + +<p>The display shows the following information:</p> + +<table> + <tr> + <th scope="col">Field</th> + <th scope="col">Description</th> + </tr> + + <tr> + <td><strong>Name</strong></td> + <td>The name of the method.</td> + </tr> + + <tr> + <td><strong>Invocation Count</strong></td> + <td>How many times the method was called.</td> + </tr> + + <tr> + <td><strong>Inclusive Time (microseconds)</strong></td> + <td>Time spent in the method and all of its children, either wall clock or thread time, + depending on your selection in the <strong>x-axis</strong> menu.</td> + </tr> + + <tr> + <td><strong>Exclusive Time (microseconds)</strong></td> + <td>Time spent just in the method (excluding time spent in its children), either wall clock + or thread time, depending on your selection in the <strong>x-axis</strong> menu.</td> + </tr> +</table> + +<p class="note"><strong>Note:</strong> Running the method trace significantly affects CPU timings. + Use the method trace to understand the flow of the program, but not for performance timings.</p> + +<h2 id="trace"> + Performing a Method Trace in the CPU Monitor +</h2> + +<p> + To perform a method trace: +</p> + +<ol> + <li> + <a href="{@docRoot}tools/help/am-cpu.html#running">Display a running app in the CPU + Monitor</a>. + </li> + + <li>Start a trace by clicking Start Method Tracing <img src="{@docRoot}images/tools/am-imethodtrace.png" + style="vertical-align:sub;margin:0;height:17px" alt="Start Method Tracing icon" /> to + select it. + </li> + + <li>To stop the trace, click Stop Method Tracing <img src="{@docRoot}images/tools/am-imethodtrace.png" + style="vertical-align:sub;margin:0;height:17px" alt="Stop Method Tracing icon" /> to + deselect it. + </li> + +<p> + The method trace appears in the Code Editor area. +</p> + +<p> + Android Studio creates the method trace file + with the filename <code><em>package_yyyy.mm.dd_hh.mm.ss</em>.trace</code> + using the activity package (or project) name, year, month, day, hour, minute, and second of + the capture, for example, + <code>com.android.calc_2015.11.17_14.58.48.trace</code>. +</p> + <li>Specify display options: + <ul> + <li>Select a <strong>Thread</strong>. + </li> + + <li>Select an <strong>x-axis</strong> time for the graphic and the method list: + </li> + + <ul> + <li> + <strong>Wall Clock Time</strong> - Total CPU time elapsed between the method call and + return. + </li> + + <li> + <strong>Thread Time</strong> - Total time during which the JRE scheduled the + thread during call processing. It’s less than or equal to the Wall Clock Time: less if + the JRE interrupted the thread, and equal if it didn’t. + The thread might not run continuously; when it’s not executing, that time is excluded. + If threads are interrupted often and it’s not by design, the interruptions affect app + performance. However, an example of a by-design use is synchronous operations that take + a long time, such as file transfers and reads from disk, where the method could be the + asynchronous wrapper for the synchronous reader. + </li> + </ul> + + <li> + Optionally select <strong>Color by inclusive time</strong>. + </li> + </ul> + + + + <p> + The graphic represents the wall clock or thread time for each method. Hover the cursor + over the display to receive information about the method. This information also appears + in the table. + </p> +</ol> + <h2 id="viewtrace"> + Viewing a Saved Method Trace + </h2> + + <p> + After you do a method trace, Android Studio automatically stores it so you can view it + again.</p> + + <p>To examine a saved method trace: + </p> + + <ol> + <li>Click + <img src="{@docRoot}images/tools/am-icaptures.png" + style="vertical-align:sub;margin:0;height:17px" + alt="Captures icon" /> in the main window. + </li> + <p>Or select <strong>View</strong> > <strong>Tools Windows</strong> > + <strong>Captures</strong>.</p> + + <p> + The <em>Captures</em> window appears. + </p> + + <li>Open the <strong>Methods Tracing</strong> folder. + </li> + + <li>Double-click the file to view it. + </li> +</ol> + +<h2 id="sorttrace"> + Sorting Method Trace Data +</h2> + +<p> + You can sort the data by method name, count, inclusive time, and exclusive + time.</p> + + <p>To sort method trace data:</p> + + +<ul> + <li>Click a column heading to sort the table by ascending or descending order. + </li> +</ul> + +<h2 id="trace-files">Working with Method Trace Files</h2> +<p>You can rename, locate, and delete a method trace file from within Android +Studio.</p> + +<h3 id="renametrace"> + Renaming a method trace file +</h3> + +<p> + Rename a method trace file from within Android Studio so it + continues to appear in the <em>Captures</em> window.</p> + + <p>To rename a method trace file: +</p> + +<ol> + <li>In the <em>Captures</em> window, right-click the file and select <strong>Rename</strong>. + </li> + + <li>In the dialog, specify the name of the file and click <strong>OK</strong>. + </li> +</ol> + +<h3 id="locatetrace"> + Locating a method trace file on disk +</h3> + +<p> + You can quickly discover where Android Studio stored method trace files on + disk.</p> + + <p>To locate a method trace file on disk: +</p> + + + +<ul> + <li>In the <em>Captures</em> window, right-click a method trace file and + select <strong>Show</strong> or <strong>Reveal</strong>. + </li> + +<p> + Android Studio opens an operating system file browser displaying the location where the file + resides. +</p> +</ul> +<p class="note"> + <strong>Note:</strong> If you move a method trace file, Android Studio no longer displays the file + in the <em>Captures</em> window. To display it, use <strong>File</strong> > + <strong>Open</strong>. Also, rename a file from the <em>Captures</em> + window and not in the operating system file browser. +</p> + +<h3 id="deletetrace"> + Deleting a method trace file +</h3> + +<p> + To delete a method trace file: +</p> + +<ul> + <li>In the <em>Captures</em> window, right-click a method trace file and select + <strong>Delete</strong>. + </li> +</ul> + +<p> + Android Studio deletes the file from the <em>Captures</em> dialog and from disk. +</p>
\ No newline at end of file diff --git a/docs/html/tools/help/am-network.jd b/docs/html/tools/help/am-network.jd index ae116ac4e58e..812999207f7b 100644 --- a/docs/html/tools/help/am-network.jd +++ b/docs/html/tools/help/am-network.jd @@ -1,7 +1,12 @@ page.title=Network Monitor parent.title=Android Monitor parent.link=android-monitor.html -page.tags=monitor +meta.tags="android, performance, profiling, tools, monitor" +page.tags="android", "performance", "profiling", "tools", "monitor" +page.metaDescription=Use the Network Monitor to analyze network requests, including how and when your app transfers data. Preserve battery life by optimizing network use. +page.image=tools/help/thumbnails/am-networkmon.png +page.article=true + @jd:body <div id="qv-wrapper"> @@ -11,63 +16,12 @@ page.tags=monitor <li><a href="#running">Displaying a Running App in the Network Monitor</a></li> </ol> - <h2>See also</h2> - <ol> - <li> - <a href="{@docRoot}tools/help/android-monitor.html">Android Monitor</a> - </li> - <li><a href="{@docRoot}tools/help/am-logcat.html">logcat Monitor</a> - </li> - - <li><a href="{@docRoot}tools/help/am-memory.html">Memory Monitor</a> - </li> - - <li><a href="{@docRoot}tools/help/am-cpu.html">CPU Monitor</a> - </li> - - <li><a href="{@docRoot}tools/help/am-gpu.html">GPU Monitor</a> - </li> - </ol> - <h2>Video</h2> <ol> <li><a href="https://www.youtube.com/watch?v=fEEulSk1kNY" class="external-link">Battery Drain and Networking</a></li> </ol> -<h2> - Dependencies and Prerequisites -</h2> - -<ul> - <li> - <a href="{@docRoot}tools/building/building-studio.html#RunningOnDeviceStudio">Connect a - hardware device</a> to your development computer. - </li> - - <li>Make sure your development computer detects your hardware device, which often happens - automatically when you connect it to a USB port. - </li> - - <li> - <a href="{@docRoot}tools/device.html#device-developer-options">Enable</a> <strong><a href= - "{@docRoot}tools/device.html#device-developer-options">USB debugging</a></strong> in - <strong>Developer Options</strong> on the device. - </li> - - <li>In your app, set the <code>debuggable</code> property to <code>true</code> in the manifest or - <code>build.gradle</code> file (it’s initially set by default). - </li> - - <li>Enable ADB integration through <strong>Tools</strong> > <strong>Android</strong> > - <strong>Enable ADB Integration</strong>. - </li> - - <li> - <a href="{@docRoot}tools/help/monitor.html">Android Device Monitor</a> can’t be running. - </li> -</ul> - </div> </div> @@ -91,32 +45,35 @@ page.tags=monitor </h2> <p> - Follow these steps: + To display an app running on a particular device in the Network Monitor: </p> <ol> - <li>Connect a hardware device. + <li>Meet the <a href= + "{@docRoot}tools/help/am-basics.html#byb">prerequisites and dependencies</a>. + </li> + <p>Connect a hardware device; the Network Monitor doesn't monitor an emulator. + </p> + <li>Open an app project. + </li> + <li><a href= + "{@docRoot}tools/building/building-studio.html#RunningApp">Run the app</a> on the hardware device. </li> - <li> - <a href="{@docRoot}tools/help/android-monitor.html#displaying">Display Android Monitor</a>. + <a href="{@docRoot}tools/help/am-basics.html#displaying">Display Android Monitor</a>. </li> - - <li>Click the <strong>Network</strong> tab. + <li>Click the <strong>Monitors</strong> tab and <a href= + "{@docRoot}tools/help/am-basics.html#rearranging">display the Network Monitor</a>. </li> - <li>Open an app project and <a href= - "{@docRoot}tools/building/building-studio.html#RunningApp">run it</a> on the hardware device. + <li>Enable the Network Monitor by clicking Pause <img src="{@docRoot}images/tools/am-ipause.png" + style="vertical-align:sub;margin:0;height:17px" alt="Pause icon" /> to deselect it. </li> - <li>To start the Network Monitor, click Pause <img src="{@docRoot}images/tools/am-ipause.png" - style="vertical-align:sub;margin:0;height:17px" alt="Pause icon" /> to - deselect it. - </li> <p> Any network traffic begins to appear in the Network Monitor: </p> - <img src="{@docRoot}images/tools/am-networkmon.png" style="vertical-align:sub;margin:0;width:450px" /> + <img src="{@docRoot}images/tools/am-networkmon2.png" style="vertical-align:sub;margin:0" /> <p> The Network Monitor adds up the amount of time it takes for the device to transmit and receive kilobytes of data. diff --git a/docs/html/tools/help/am-screenshot.jd b/docs/html/tools/help/am-screenshot.jd new file mode 100644 index 000000000000..322616e23e24 --- /dev/null +++ b/docs/html/tools/help/am-screenshot.jd @@ -0,0 +1,89 @@ +page.title=Screen Capture +parent.title=Android Monitor +parent.link=android-monitor.html +meta.tags="android, performance, profiling, tools, monitor" +page.tags="android", "performance", "profiling", "tools", "monitor" +page.metaDescription=Use the Screen Capture tool to take a screenshot of the display on a hardware device or the emulator. Optionally display the screenshot within a graphic of a device. +page.image=tools/help/thumbnails/am_screenshot.png +page.article=true +@jd:body + + +<p> + You can take a PNG screenshot of the display on a connected device or the emulator. You can use + the images for your marketing materials as well as for debugging, for example. +</p> + + +<h2 id="screencapture"> + Taking a Screen Capture of the Device +</h2> + + +<p> + To take a screen capture: +</p> +<ol> + <li>Meet the <a href= + "{@docRoot}tools/help/am-basics.html#byb">prerequisites and dependencies</a>. + </li> + <li>Open an app project. + </li> + <li><a href= + "{@docRoot}tools/building/building-studio.html#RunningApp">Run the app</a> on + a hardware device or emulator. + </li> + <li> + <a href="{@docRoot}tools/help/am-basics.html#displaying">Display Android Monitor</a>. + </li> + + <li>Interact with the display on the device or emulator to stage the image you want. + </li> + + <li>Click Screen Capture <img src="{@docRoot}images/tools/am-iscreencapture.png" + style="vertical-align:sub;margin:0;height:17px" alt="Screen Capture icon" /> in the + Android Monitor toolbar. + </li> + <p>The screenshot appears in a <em>Screenshot Editor</em> window.</p> + +<img src="{@docRoot}images/tools/am-screenshot.png" alt="Screen Capture" /> + + <li>Optionally change the image: + <ul> + <li> + <strong>Recapture</strong> - Click to take a new screenshot. + </li> + + <li> + <strong>Rotate</strong> - Click to rotate the image 90 degrees clockwise. + </li> + + <li> + <strong>Frame Screenshot</strong> - Select this option and choose a device to add an image + of the device to the outside of the screenshot. Select <strong>Drop Shadow</strong>, + <strong>Screen Glare</strong>, or both to add these effects to your image. + </li> + + <li> + <strong>Chessboard</strong> and <strong>Grid</strong> - Select an option to display these + behind your image. + </li> + + <li> + <strong>Zoom In</strong>, <strong>Zoom Out</strong>, or <strong>Actual Size</strong> - + Click these options to get different perspectives of your image without changing the image + itself. + </li> + </ul> + </li> + <li>Click <strong>Save</strong> to save the image. + </li> + </li> + <li>In the <em>Save as PNG</em> dialog, specify the location and filename, + and then click <strong>OK</strong>. + </li> + <p>The screenshot file appears in the Code Editor area.</p> +</ol> + + + diff --git a/docs/html/tools/help/am-sysinfo.jd b/docs/html/tools/help/am-sysinfo.jd new file mode 100644 index 000000000000..166cc082ee5b --- /dev/null +++ b/docs/html/tools/help/am-sysinfo.jd @@ -0,0 +1,205 @@ +page.title=System Information +parent.title=Android Monitor +parent.link=android-monitor.html +meta.tags="android, performance, profiling, tools, monitor" +page.tags="android", "performance", "profiling", "tools", "monitor" +page.metaDescription=Use the System Information tool to capture <code>dumpsys</code> information about your app. View activity manager, package, memory usage, and graphics state information. +page.image=tools/help/thumbnails/am_sysinfo.png +page.article=true +@jd:body +<div id="qv-wrapper"> +<div id="qv"> + <h2>In this document</h2> +<ol> + <li><a href="#sysinfo">Examining System Information for a Running App</a></li> + <li><a href="#viewsysinfo">Viewing Saved System Information</a></li> + <li><a href="#sysinfo-files">Working with System Information Files</a></li> +</ol> + +</div> +</div> + +<p> + You can capture <code>dumpsys</code> output from within Android Monitor and + display the file in the Code Editor. The <em>Captures</em> window lists the + system information files so you can retrieve the information later for + analysis. +</p> + + + +<h2 id="sysinfo"> + Examining System Information for a Running App +</h2> +<p> + To capture and view a snapshot of system information: +</p> + +<ol> + <li>Meet the <a href= + "{@docRoot}tools/help/am-basics.html#byb">prerequisites and dependencies</a>. + </li> + <li>Open an app project. + </li> + <li><a href= + "{@docRoot}tools/building/building-studio.html#RunningApp">Run the app</a> on + a hardware device or emulator. + </li> + <li> + <a href="{@docRoot}tools/help/am-basics.html#displaying">Display Android Monitor</a>. + </li> + + <li>In the toolbar of the Android Monitor main window, click System Information + <img src="{@docRoot}images/tools/am-isysteminfo.png" + style="vertical-align:sub;margin:0;height:17px" alt="System Information icon" /> + and then select a menu item. + </li> + +<p> + The menu items display different types of <code><a href= + "https://source.android.com/devices/tech/debug/dumpsys.html">dumpsys</a></code> + output: +</p> + +<ul> + <li> + <strong>Activity Manager State</strong> - <code>dumpsys activity</code> + </li> + + <li> + <strong>Package Information</strong> - <code>dumpsys package</code> + </li> + + <li> + <strong>Memory Usage</strong> - <code><a href= + "{@docRoot}tools/debugging/debugging-memory.html#ViewingAllocations">dumpsys + meminfo</a></code> + </li> + + <li> + <strong>Memory Use Over Time</strong> - <code><a href= + "http://android-developers.blogspot.com/2014/01/process-stats-understanding-how-your.html">dumpsys + procstats</a></code> + </li> + + <li> + <strong>Graphics State</strong> - <code><a href= + "{@docRoot}training/testing/performance.html">dumpsys gfxinfo</a></code> + </li> +</ul> + +<p> + The information appears in an editable text file in the Code Editor. +</p> +<img src="{@docRoot}images/tools/am-sysinfo.png" alt="System Information" /> +<p>Android Studio creates the system information file with the + filename <code><em>package_yyyy.mm.dd_hh.mm.ss</em>.txt</code> using the + activity package (or project) name, year, month, day, + hour, minute, and second of the capture, for example, + <code>com.android.calc_2015.11.17_14.58.48.txt</code>.</p> +</ol> + +<h2 id="viewsysinfo"> +Viewing Saved System Information +</h2> + +<p> +After you take a snapshot of system information, Android Studio automatically +stores it so you can view it again.</p> + +<p>To examine a saved system information file:</p> + +<ol> + <li>Click + <img src="{@docRoot}images/tools/am-icaptures.png" + style="vertical-align:sub;margin:0;height:17px" + alt="Captures icon" /> in the main window. + </li> + <p>Or select <strong>View</strong> > <strong>Tools Windows</strong> > + <strong>Captures</strong>.</p> + + <p> + The <em>Captures</em> window appears. + </p> + + <li>Open the <strong>System Information</strong> folder. + </li> + + <li>Double-click the file to view it. + </li> +</ol> + + +<h2 id="sysinfo-files">Working with System Information Files</h2> +<p>You can rename, locate, and delete a system information file from within +Android Studio.</p> + +<h3 id="renamesysinfo"> + Renaming a system information file +</h3> + +<p> + Rename a system information file from within Android Studio so it + continues to appear in the <em>Captures</em> window.</p> + + <p>To rename a system information file: +</p> + +<ol> + <li>In the <em>Captures</em> window, right-click the file and select + <strong>Rename</strong>. + </li> + + <li>In the dialog, specify the name of the file and click <strong>OK</strong>. + </li> +</ol> + +<h3 id="locatesysinfo"> + Locating a system information file on disk +</h3> + +<p> + You can quickly discover where Android Studio stored system information files + on disk.</p> + + <p>To locate a system information file on disk: +</p> + + + +<ul> + <li>In the <em>Captures</em> window, right-click a system information file and + select <strong>Show</strong> or <strong>Reveal</strong>. + </li> + +<p> + Android Studio opens an operating system file browser displaying the location + where the file resides. +</p> +</ul> +<p class="note"> + <strong>Note:</strong> If you move a system information file, Android Studio + no longer displays the file + in the <em>Captures</em> window. To display it, use <strong>File</strong> > + <strong>Open</strong>. Also, rename a file from the <em>Captures</em> + window and not in the operating system file browser. +</p> + +<h3 id="deletesysinfo"> + Deleting a system information file +</h3> + +<p> + To delete a system information file: +</p> + +<ul> + <li>In the <em>Captures</em> window, right-click a system information file + and select <strong>Delete</strong>. + </li> +</ul> + +<p> + Android Studio deletes the file from the <em>Captures</em> dialog and from + disk. +</p> diff --git a/docs/html/tools/help/am-video.jd b/docs/html/tools/help/am-video.jd new file mode 100644 index 000000000000..5ecdd11ad40a --- /dev/null +++ b/docs/html/tools/help/am-video.jd @@ -0,0 +1,78 @@ +page.title=Video Capture +parent.title=Android Monitor +parent.link=android-monitor.html +meta.tags="android, performance, profiling, tools, monitor" +page.tags="android", "performance", "profiling", "tools", "monitor" +page.metaDescription=Use the Video tool to make a video of the display on a hardware device. +page.image=tools/help/thumbnails/am_video.png +page.article=true +@jd:body + + +<p> + Android Studio lets you record an MP4 video from your hardware device for a maximum of three + minutes. You can use the video for your marketing materials as well as for debugging, for + example. +</p> +<img src="{@docRoot}images/tools/am-video.png" width="230" alt="Device Video" /> + + + +<h2 id="video"> + Recording a Video from the Screen +</h2> + +<p> + To record a video from a hardware device: +</p> +<ol> + <li>Meet the <a href= + "{@docRoot}tools/help/am-basics.html#byb">prerequisites and dependencies</a>. + </li> + <li>Open an app project. + </li> + <li><a href= + "{@docRoot}tools/building/building-studio.html#RunningApp">Run the app</a> on + a hardware device. + </li> + <li> + <a href="{@docRoot}tools/help/am-basics.html#displaying">Display Android Monitor</a>. + </li> + + <li>Interact with the display on the hardware device to stage the start of the video. + </li> + + <li>Click Screen Record <img src="{@docRoot}images/tools/am-ivideo.png" + style="vertical-align:sub;margin:0;height:17px" alt="Screen Record icon" /> in the + Android Monitor toolbar. + </li> + <p>The screenshot appears in a Screenshot Editor window.</p> + + <li>In the <em>Screen Recorder Options</em> dialog, optionally change the recording options: + </li> +<ul> + <li> + <strong>Bit Rate</strong> - Type a bit rate. The default is 4 Mbps. + </li> + + <li> + <strong>Resolution</strong> - Type a width and height value in pixels. The value must be a + multiple of 16. The default is the resolution of the device. + </li> +</ul> + <li>Click <strong>Start Recording</strong> to start the recording. + </li> + + <li>Click <strong>Stop Recording</strong> to stop the recording. + </li> + + <li>In the <em>Save As</em> dialog, save the MP4 file. + </li> + + <li>In the <em>Screen Recorder</em> dialog, click one of the buttons to show the file location, + open the recording in a player, or to dismiss the dialog. + </li> +</ol> + + + diff --git a/docs/html/tools/help/android-monitor.jd b/docs/html/tools/help/android-monitor.jd index 4c9f80f82995..2820db8b086a 100644 --- a/docs/html/tools/help/android-monitor.jd +++ b/docs/html/tools/help/android-monitor.jd @@ -8,63 +8,16 @@ page.tags=monitor <div id="qv"> <h2>In this document</h2> <ol> - <li><a href="#displaying">Displaying Android Monitor</a></li> - <li><a href="#profiling">Profiling a Running App in Android Monitor</a></li> - <li><a href="#switching">Switching between Devices and Apps</a></li> - <li><a href="#screencapture">Taking a Screen Capture of the Device</a></li> - <li><a href="#video">Recording a Video from the Screen</a></li> - <li><a href="#sysinfo">Examining System Information</a></li> - <li><a href="#terminating">Terminating the App</a></li> - <li><a href="#rearranging">Rearranging Android Monitor Windows</a></li> - <li><a href="#removing">Removing an App from a Device</a></li> + <li><a href="#logcat">Log Messages</a></li> + <li><a href="#monitors">Performance Monitors</a></li> + <li><a href="#data">Data Analysis</a></li> + <li><a href="#shots">Screen and Video Captures</a></li> + <li><a href="#getstarted">Get Started</a></li> </ol> - <h2>See also</h2> - <ol> - <li><a href="{@docRoot}tools/help/am-logcat.html">logcat Monitor</a> - </li> - <li><a href="{@docRoot}tools/help/am-memory.html">Memory Monitor</a> - </li> - <li><a href="{@docRoot}tools/help/am-cpu.html">CPU Monitor</a> - </li> - <li><a href="{@docRoot}tools/help/am-gpu.html">GPU Monitor</a> - </li> - - <li> - <a href="{@docRoot}tools/help/am-network.html">Network Monitor</a> - </li> - </ol> - - -<h2> - Dependencies and Prerequisites -</h2> - -<ul> - <li>In your app, set the <code>debuggable</code> property to <code>true</code> in the manifest or - <code>build.gradle</code> file (it’s initially set by default). - </li> - - <li>Enable ADB integration through <strong>Tools</strong> > <strong>Android</strong> > - <strong>Enable ADB Integration</strong>. - </li> - - <li>Make sure your development computer detects your hardware device, which often happens - automatically when you connect it to a USB port. - </li> - <li> - <a href="{@docRoot}tools/device.html#device-developer-options">Enable</a> <strong><a href= - "{@docRoot}tools/device.html#device-developer-options">USB debugging</a></strong> in - <strong>Developer Options</strong> on the device or emulator. - </li> - - <li> - <a href="{@docRoot}tools/help/monitor.html">Android Device Monitor</a> can’t be running. - </li> -</ul> </div> </div> @@ -72,7 +25,7 @@ page.tags=monitor <p> Android Monitor helps you to profile the performance of your apps so you can optimize, debug, and improve them. It lets you monitor the following aspects of your apps from a hardware device or - the Android Studio emulator: + the <a href="{@docRoot}tools/devices/emulator.html">Android Emulator</a>: </p> <ul> @@ -88,375 +41,66 @@ page.tags=monitor </li> </ul> -<p> - Android Monitor contains the logcat, Memory, CPU, GPU, and Network Monitors that you can use - separately to examine these aspects of your apps. -</p> - - -<h2 id="displaying"> - Displaying Android Monitor -</h2> - -<p> - Android Monitor is integrated into the Android Studio main window: -</p> - -<ul> - <li>To display Android Monitor, click <img src="{@docRoot}images/tools/am-icon.png" - style="vertical-align:sub;margin:0;height:17px" alt="Android Monitor icon" />, which by default - is at the bottom of the main window. - </li> - - <li>To hide Android Monitor, click <img src="{@docRoot}images/tools/am-icon.png" - style="vertical-align:sub;margin:0;height:17px" alt="Android Monitor icon" /> again. - </li> -</ul> -<img src="{@docRoot}images/tools/am-androidmon.png" style="vertical-align:sub;margin:0;width:480px" /> - -<h2 id="profiling"> - Profiling a Running App in Android Monitor -</h2> - -<p> - Follow these steps: -</p> - -<ol> - <li>Optionally connect a hardware device. - </li> - - <li> - <a href="#displaying">Display Android Monitor</a>. - </li> - - <li>Open an app project and <a href= - "{@docRoot}tools/building/building-studio.html#RunningApp">run the app</a> on a device or - emulator. - </li> - - <li>Click the tab for the monitor you want to view and start the monitor, if needed: - <ul> - <li><a href="{@docRoot}tools/help/am-logcat.html">logcat Monitor</a> - </li> - - <li><a href="{@docRoot}tools/help/am-memory.html">Memory Monitor</a> - </li> - - <li><a href="{@docRoot}tools/help/am-cpu.html">CPU Monitor</a> - </li> - - <li><a href="{@docRoot}tools/help/am-gpu.html">GPU Monitor</a> - </li> - - <li> - <a href="{@docRoot}tools/help/am-network.html">Network Monitor</a> - </li> - </ul> -</ol> - <h2 id="switching"> - Switching between Devices and Apps - </h2> - - <p> - By default, Android Monitor displays data for your most recently run app. You can switch to - another device and app as needed. In addition to currently running apps, you can view - information about apps that are no longer running so you can continue to view any information - about them that you gathered previously. - </p> - - <p> - At the top of the Android Monitor main window are two menus listing devices and processes. To - switch to another device, process, or both, follow these steps: - </p> - - <ol> - <li>Select the device or emulator. - </li> - - <p> - The Device menu lists the devices and emulators that are running or have run during your - current session. There are various status messages that can appear in the Device menu: - </p> - - <ul> - <li> - <strong>DISCONNECTED</strong> - You closed an emulator or unplugged a device from the - computer. - </li> - - <li> - <strong>UNAUTHORIZED</strong> - A device needs you to accept the incoming computer - connection. For example, if the connected device displays an <em>Allow USB Debugging</em> - dialog, click <strong>OK</strong> to allow the connection. - </li> - - <li> - <strong>OFFLINE</strong> - Android Monitor can’t communicate with a device, even though it - has detected that device. - </li> - </ul> - - <li>Select the process. - </li> -</ol> - -<p> - The Process menu lists the processes that are running or have run during your current session. If - a process is no longer running, the menu displays a status of <strong>DEAD</strong>. -</p> - -<h2 id="screencapture"> - Taking a Screen Capture of the Device -</h2> - -<p> - You can take a PNG screenshot of the display on a connected device or the emulator. You can use - the images for your marketing materials as well as for debugging, for example. -</p> -<p> - Follow these steps: -</p> -<ol> - <li> - <a href="{@docRoot}training/basics/firstapp/running-app.html">Run your - app</a> from within Android Studio. - </li> - - <li> - <a href="#switching">Select the device and the process</a> in the Android Monitor - menus, if needed. - </li> - - <li>Interact with the display on the device or emulator to stage the image you want. - </li> - - <li>Click Screen Capture <img src="{@docRoot}images/tools/am-iscreencapture.png" - style="vertical-align:sub;margin:0;height:17px" alt="Screen Capture icon" /> in the - Android Monitor toolbar. - </li> - <p>The screenshot appears in a <em>Screenshot Editor</em> window.</p> - - <li>Optionally change the image: - <ul> - <li> - <strong>Reload</strong> - Click to take a new screenshot. - </li> - - <li> - <strong>Rotate</strong> - Click to rotate the image 90 degrees clockwise. - </li> - - <li> - <strong>Frame Screenshot</strong> - Select this option and choose a device to add an image - of the device to the outside of the screenshot. Select <strong>Drop Shadow</strong>, - <strong>Screen Glare</strong>, or both to add these effects to your image. - </li> - - <li> - <strong>Chessboard</strong> and <strong>Grid</strong> - Select an option to display these - behind your image. - </li> - - <li> - <strong>Zoom In</strong>, <strong>Zoom Out</strong>, or <strong>Actual Size</strong> - - Click these options to get different perspectives of your image without changing the image - itself. - </li> - </ul> - </li> - <li>Click <strong>Save</strong> to save the image. - </li> -</ol> - -<h2 id="video"> - Recording a Video from the Screen -</h2> - -<p> - Android Studio lets you record an MP4 video from your hardware device for a maximum of three - minutes. You can use the video for your marketing materials as well as for debugging, for - example. -</p> -<p> - Follow these steps: -</p> -<ol> - <li> - <a href="{@docRoot}training/basics/firstapp/running-app.html">Run your - app</a> from within Android Studio. - </li> - - <li> - <a href="#switching">Select the device and the process</a> in the Android Monitor - menus, if needed. - </li> - - <li>Interact with the display on the device or emulator to stage the start of the video. - </li> - - <li>Click Screen Record <img src="{@docRoot}images/tools/am-ivideo.png" style="vertical-align:sub;margin:0;height:17px" alt="Screen Record icon" /> in the Android Monitor toolbar. - </li> - <p>The screenshot appears in a Screenshot Editor window.</p> - - <li>In the <em>Screen Recorder Options</em> dialog, optionally change the recording options: - </li> -<ul> - <li> - <strong>Bit Rate</strong> - Type a bit rate. The default is 4 Mbps. - </li> - - <li> - <strong>Resolution</strong> - Type a width and height value in pixels. The value must be a - multiple of 16. The default is the resolution of the device. - </li> -</ul> - <li>Click <strong>Start Recording</strong> to start the recording. - </li> - - <li>Click <strong>Stop Recording</strong> to stop the recording. - </li> - - <li>In the <em>Save As</em> dialog, save the MP4 file. - </li> - - <li>In the <em>Screen Recorder</em> dialog, click one of the buttons to show the file location, - open the recording in a player, or to dismiss the dialog. - </li> -</ol> - -<h2 id="sysinfo"> - Examining System Information -</h2> -<p> - You can view <code>dumpsys</code> output from within Android Monitor. Follow these steps: -</p> - -<ol> - <li> - <a href="{@docRoot}training/basics/firstapp/running-app.html">Run your - app</a> from within Android Studio. - </li> - - <li> - <a href="#switching">Select the device and the process</a> in the Android Monitor - menus, if needed. - </li> - - <li>Click System Information <img src="{@docRoot}images/tools/am-isysteminfo.png" - style="vertical-align:sub;margin:0;height:17px" alt="System Information icon" /> and then a - menu item in the Android Monitor - toolbar. - </li> - -<p> - The menu items display different types of <code><a href= - "https://source.android.com/devices/tech/debug/dumpsys.html">dumpsys</a></code> output: -</p> - -<ul> - <li> - <strong>Activity Manager State</strong> - <code>dumpsys activity</code> - </li> - - <li> - <strong>Package Information</strong> - <code>dumpsys package</code> - </li> - - <li> - <strong>Memory Usage</strong> - <code><a href= - "{@docRoot}tools/debugging/debugging-memory.html#ViewingAllocations">dumpsys - meminfo</a></code> - </li> - - <li> - <strong>Memory Use Over Time</strong> - <code><a href= - "http://android-developers.blogspot.com/2014/01/process-stats-understanding-how-your.html">dumpsys - procstats</a></code> - </li> - - <li> - <strong>Graphics State</strong> - <code><a href= - "{@docRoot}training/testing/performance.html">dumpsys gfxinfo</a></code> - </li> -</ul> - -<p> - The information appears in an editable text file in the Code Editor. -</p> -</ol> -<h2 id="terminating"> - Terminating the App -</h2> +<p>Android Monitor provides various tools that provide real-time information about your app. It + lets you capture data as your app runs and stores it in a file that you can analyze in various + viewers. You can also capture screen shots and videos of your app as it runs.</p> -<p> - If you want to stop an app you’ve run from Android Studio, follow these steps: -</p> +<h2 id="logcat">Log Messages</h2> -<ol> - <li> - <a href="#switching">Select the device and the process</a> in the Android Monitor - menus, if needed. - </li> - - <li>Click Terminate Application <img src="{@docRoot}images/tools/am-iterminate.png" - style="vertical-align:sub;margin:0;height:17px" alt="Terminate App icon" />. - </li> +<p>View log messages — in real time and historically — which is useful for debugging.</p> +<div class="dynamic-grid"> + <div class="resource-widget resource-flow-layout landing col-12" + data-query="collection:tools/help/log" + data-cardSizes="12x6" + data-maxResults="6"> + </div> +</div> -<p> - The process status changes to <strong>DEAD</strong> in the Processes menu. The emulator or device - continues to run, but the app closes. Any running monitors in Android Monitor stop. -</p> -</ol> - -<h2 id="rearranging"> - Rearranging Android Monitor Windows -</h2> - -<p> - You can rearrange the Android Monitor windows for optimal viewing during your tests: -</p> - -<ul> - <li>To reorder the monitors, move the tabs back and forth. - </li> - - <li>To move a monitor to a standalone window, grab a tab and move it to a different location on - the screen. Or, select <img src="{@docRoot}images/tools/am-igear.png" style="vertical-align:sub;margin:0;height:17px" alt="Gear menu icon" /> > <strong>Floating Mode</strong>. - </li> +<h2 id="monitors">Performance Monitors</h2> - <li>To dock a standalone window, grab it and move it to the Android Monitor area. Or, select - <img src="{@docRoot}images/tools/am-igear.png" style="vertical-align:sub;margin:0;height:17px" - alt="Gear menu icon"> > <strong>Floating Mode</strong> to deselect it. - </li> +<p>Visualize the behavior and performance of your app.</p> +<div class="dynamic-grid"> + <div class="resource-widget resource-flow-layout landing col-12" + data-query="collection:tools/help/monitor" + data-cardSizes="9x6" + data-maxResults="6"> + </div> +</div> - <li>To combine two monitor displays together, grab a tab and move it onto another monitor. - </li> +<h2 id="data">Data Analysis</h2> - <li>To hide a monitor, click the <img src="{@docRoot}images/tools/am-ihide.png" style="vertical-align:sub;margin:0;height:17px" alt="Hide icon" /> icon. To make it reappear, click the icon of - the monitor on the far right of the row of tabs. - </li> -</ul> +<p>Android Monitor lets you capture various types of data about your app while it's running and + stores it in a file, which you can access whenever is convenient. + It lists these files in the <em>Captures</em> window.</p> -<h2 id="removing"> - Removing an App from a Device -</h2> +<div class="dynamic-grid"> + <div class="resource-widget resource-flow-layout landing col-12" + data-query="collection:tools/help/data" + data-cardSizes="9x6" + data-maxResults="6"> + </div> +</div> -<p> - To remove an app from a device you use for development, use the normal uninstall procedure on the - device. -</p> +<h2 id="shots">Screen and Video Captures</h2> -<p> - If you run a new version of an app from Android Studio that’s been already installed on a - hardware device, the device displays an <em>Application Installation Failed</em> dialog. Click - <strong>OK</strong> to install the new version of the app. -</p> +<p>Create screen captures and videos of your app to help with marketing and debugging. + </p> +<div class="dynamic-grid"> + <div class="resource-widget resource-flow-layout landing col-12" + data-query="collection:tools/help/shot" + data-cardSizes="9x3" + data-maxResults="2"> + </div> +</div> +<h2 id="getstarted">Get Started</h2> +<p>To begin using Android Monitor, start with <a href= + "{@docRoot}tools/help/am-basics.html">Android Monitor Basics</a>. + </p> diff --git a/docs/html/tools/help/thumbnails/am-androidmon2.png b/docs/html/tools/help/thumbnails/am-androidmon2.png Binary files differnew file mode 100644 index 000000000000..a4a757193b09 --- /dev/null +++ b/docs/html/tools/help/thumbnails/am-androidmon2.png diff --git a/docs/html/tools/help/thumbnails/am-cpumon.png b/docs/html/tools/help/thumbnails/am-cpumon.png Binary files differnew file mode 100644 index 000000000000..59908c854db9 --- /dev/null +++ b/docs/html/tools/help/thumbnails/am-cpumon.png diff --git a/docs/html/tools/help/thumbnails/am-cpumon2.png b/docs/html/tools/help/thumbnails/am-cpumon2.png Binary files differnew file mode 100644 index 000000000000..6ac6e0287a09 --- /dev/null +++ b/docs/html/tools/help/thumbnails/am-cpumon2.png diff --git a/docs/html/tools/help/thumbnails/am-gc2.png b/docs/html/tools/help/thumbnails/am-gc2.png Binary files differnew file mode 100644 index 000000000000..a5e8b6e986d4 --- /dev/null +++ b/docs/html/tools/help/thumbnails/am-gc2.png diff --git a/docs/html/tools/help/thumbnails/am-gpumon.png b/docs/html/tools/help/thumbnails/am-gpumon.png Binary files differnew file mode 100644 index 000000000000..a414fe5e45fb --- /dev/null +++ b/docs/html/tools/help/thumbnails/am-gpumon.png diff --git a/docs/html/tools/help/thumbnails/am-gpumon2.png b/docs/html/tools/help/thumbnails/am-gpumon2.png Binary files differnew file mode 100644 index 000000000000..5cf51d9320b2 --- /dev/null +++ b/docs/html/tools/help/thumbnails/am-gpumon2.png diff --git a/docs/html/tools/help/thumbnails/am-logcatmon2.png b/docs/html/tools/help/thumbnails/am-logcatmon2.png Binary files differnew file mode 100644 index 000000000000..563593568f17 --- /dev/null +++ b/docs/html/tools/help/thumbnails/am-logcatmon2.png diff --git a/docs/html/tools/help/thumbnails/am-memorymon.png b/docs/html/tools/help/thumbnails/am-memorymon.png Binary files differnew file mode 100644 index 000000000000..0fefb27cd553 --- /dev/null +++ b/docs/html/tools/help/thumbnails/am-memorymon.png diff --git a/docs/html/tools/help/thumbnails/am-networkmon.png b/docs/html/tools/help/thumbnails/am-networkmon.png Binary files differnew file mode 100644 index 000000000000..db9c647b7f0c --- /dev/null +++ b/docs/html/tools/help/thumbnails/am-networkmon.png diff --git a/docs/html/tools/help/thumbnails/am_alloctracker.png b/docs/html/tools/help/thumbnails/am_alloctracker.png Binary files differnew file mode 100644 index 000000000000..b94713d3cc28 --- /dev/null +++ b/docs/html/tools/help/thumbnails/am_alloctracker.png diff --git a/docs/html/tools/help/thumbnails/am_androidmon.png b/docs/html/tools/help/thumbnails/am_androidmon.png Binary files differnew file mode 100644 index 000000000000..6b0523019b19 --- /dev/null +++ b/docs/html/tools/help/thumbnails/am_androidmon.png diff --git a/docs/html/tools/help/thumbnails/am_cpumon.png b/docs/html/tools/help/thumbnails/am_cpumon.png Binary files differnew file mode 100644 index 000000000000..c8c0415535d1 --- /dev/null +++ b/docs/html/tools/help/thumbnails/am_cpumon.png diff --git a/docs/html/tools/help/thumbnails/am_gpumon.png b/docs/html/tools/help/thumbnails/am_gpumon.png Binary files differnew file mode 100644 index 000000000000..e453e7de63c6 --- /dev/null +++ b/docs/html/tools/help/thumbnails/am_gpumon.png diff --git a/docs/html/tools/help/thumbnails/am_hprofviewer.png b/docs/html/tools/help/thumbnails/am_hprofviewer.png Binary files differnew file mode 100644 index 000000000000..342590fd41b2 --- /dev/null +++ b/docs/html/tools/help/thumbnails/am_hprofviewer.png diff --git a/docs/html/tools/help/thumbnails/am_iscreencapture.png b/docs/html/tools/help/thumbnails/am_iscreencapture.png Binary files differnew file mode 100644 index 000000000000..68135a711a74 --- /dev/null +++ b/docs/html/tools/help/thumbnails/am_iscreencapture.png diff --git a/docs/html/tools/help/thumbnails/am_isysteminfo.png b/docs/html/tools/help/thumbnails/am_isysteminfo.png Binary files differnew file mode 100644 index 000000000000..37d77db9c036 --- /dev/null +++ b/docs/html/tools/help/thumbnails/am_isysteminfo.png diff --git a/docs/html/tools/help/thumbnails/am_ivideo.png b/docs/html/tools/help/thumbnails/am_ivideo.png Binary files differnew file mode 100644 index 000000000000..901eaf140021 --- /dev/null +++ b/docs/html/tools/help/thumbnails/am_ivideo.png diff --git a/docs/html/tools/help/thumbnails/am_logcatmon.png b/docs/html/tools/help/thumbnails/am_logcatmon.png Binary files differnew file mode 100644 index 000000000000..ca7063cb0ba0 --- /dev/null +++ b/docs/html/tools/help/thumbnails/am_logcatmon.png diff --git a/docs/html/tools/help/thumbnails/am_methodtrace.png b/docs/html/tools/help/thumbnails/am_methodtrace.png Binary files differnew file mode 100644 index 000000000000..8d5ca4e6089e --- /dev/null +++ b/docs/html/tools/help/thumbnails/am_methodtrace.png diff --git a/docs/html/tools/help/thumbnails/am_networkmon2.png b/docs/html/tools/help/thumbnails/am_networkmon2.png Binary files differnew file mode 100644 index 000000000000..f55f853e51af --- /dev/null +++ b/docs/html/tools/help/thumbnails/am_networkmon2.png diff --git a/docs/html/tools/help/thumbnails/am_screenshot.png b/docs/html/tools/help/thumbnails/am_screenshot.png Binary files differnew file mode 100644 index 000000000000..66afff91facb --- /dev/null +++ b/docs/html/tools/help/thumbnails/am_screenshot.png diff --git a/docs/html/tools/help/thumbnails/am_sysinfo.png b/docs/html/tools/help/thumbnails/am_sysinfo.png Binary files differnew file mode 100644 index 000000000000..9b5cd17207fb --- /dev/null +++ b/docs/html/tools/help/thumbnails/am_sysinfo.png diff --git a/docs/html/tools/help/thumbnails/am_video.png b/docs/html/tools/help/thumbnails/am_video.png Binary files differnew file mode 100644 index 000000000000..209cb0c7d10d --- /dev/null +++ b/docs/html/tools/help/thumbnails/am_video.png diff --git a/docs/html/tools/tools_toc.cs b/docs/html/tools/tools_toc.cs index c390523b2490..73d4ff3738c9 100644 --- a/docs/html/tools/tools_toc.cs +++ b/docs/html/tools/tools_toc.cs @@ -147,6 +147,9 @@ <div class="nav-section-header"> <a href="<?cs var:toroot ?>tools/help/android-monitor.html">Android Monitor</a></div> <ul> + <li><a href="<?cs var:toroot ?>tools/help/am-basics.html"><span + class="en">Android Monitor Basics</span></a> + </li> <li><a href="<?cs var:toroot ?>tools/help/am-logcat.html"><span class="en">logcat Monitor</span></a> </li> @@ -162,6 +165,25 @@ <li><a href="<?cs var:toroot ?>tools/help/am-network.html"><span class="en">Network Monitor</span></a> </li> + <li><a href="<?cs var:toroot ?>tools/help/am-hprof.html"><span + class="en">HPROF Viewer and Analyzer</span></a> + </li> + <li><a href="<?cs var:toroot ?>tools/help/am-allocation.html"><span + class="en">Allocation Tracker</span></a> + </li> + <li><a href="<?cs var:toroot ?>tools/help/am-methodtrace.html"><span + class="en">Method Trace</span></a> + </li> + <li><a href="<?cs var:toroot ?>tools/help/am-sysinfo.html"><span + class="en">System Information</span></a> + </li> + <li><a href="<?cs var:toroot ?>tools/help/am-screenshot.html"><span + class="en">Screen Capture</span></a> + </li> + <li><a href="<?cs var:toroot ?>tools/help/am-video.html"><span + class="en">Video Capture</span></a> + </li> + </li> </ul> </li> @@ -217,6 +239,7 @@ class="en">Tools Help</span></a></div> </li> <li><a href="<?cs var:toroot ?>tools/help/hprof-conv.html">hprof-conv</a></li> + <li><a href="<?cs var:toroot ?>tools/help/image-asset-studio.html">Image Asset Studio</a></li> <li><a href="<?cs var:toroot ?>tools/help/jobb.html">jobb</a></li> <li><a href="<?cs var:toroot ?>tools/help/lint.html">lint</span></a></li> <li class="nav-section"> diff --git a/docs/html/training/_book.yaml b/docs/html/training/_book.yaml index cd4df4360865..8f8fab20ad12 100644 --- a/docs/html/training/_book.yaml +++ b/docs/html/training/_book.yaml @@ -4,8 +4,9 @@ toc: section: - title: Building Your First App path: /training/basics/firstapp/index.html - custom_link_attributes: - - description="After you've installed the Android SDK, start with this class to learn the basics about Android app development." + path_attributes: + - name: description + value: After you've installed the Android SDK, start with this class to learn the basics about Android app development. section: - title: Creating an Android Project path: /training/basics/firstapp/creating-project.html @@ -17,8 +18,9 @@ toc: path: /training/basics/firstapp/starting-activity.html - title: Supporting Different Devices path: /training/basics/supporting-devices/index.html - custom_link_attributes: - - description="How to build your app with alternative resources that provide an optimized user experience on multiple device form factors using a single APK." + path_attributes: + - name: description + value: How to build your app with alternative resources that provide an optimized user experience on multiple device form factors using a single APK. section: - title: Supporting Different Languages path: /training/basics/supporting-devices/languages.html @@ -28,137 +30,215 @@ toc: path: /training/basics/supporting-devices/platforms.html - title: Managing the Activity Lifecycle path: /training/basics/activity-lifecycle/index.html - custom_link_attributes: - - ja-lang="アクティビティのライフサイクル 管理" - - ko-lang="액티비티 수명 주기 관리하기" - - pt-br-lang="Como gerenciar o ciclo de vida da atividade" - - ru-lang="Управление жизненным циклом операций" - - zh-cn-lang="管理活动生命周期" - - zh-tw-lang="管理應用行為顯示生命週期" - - description="How Android activities live and die and how to create a seamless user experience by implementing lifecycle callback methods." + path_attributes: + - name: ja-lang + value: アクティビティのライフサイクル 管理 + - name: ko-lang + value: 액티비티 수명 주기 관리하기 + - name: pt-br-lang + value: Como gerenciar o ciclo de vida da atividade + - name: ru-lang + value: Управление жизненным циклом операций + - name: zh-cn-lang + value: 管理活动生命周期 + - name: zh-tw-lang + value: 管理應用行為顯示生命週期 + - name: description + value: How Android activities live and die and how to create a seamless user experience by implementing lifecycle callback methods. section: - title: Starting an Activity path: /training/basics/activity-lifecycle/starting.html - custom_link_attributes: - - ja-lang="アクティビティを開始する" - - ko-lang="액티비티 시작하기" - - pt-br-lang="Iniciando uma atividade" - - ru-lang="Запуск операции" - - zh-cn-lang="开始活动" - - zh-tw-lang="啟動應用行為顯示" + path_attributes: + - name: ja-lang + value: アクティビティを開始する + - name: ko-lang + value: 액티비티 시작하기 + - name: pt-br-lang + value: Iniciando uma atividade + - name: ru-lang + value: Запуск операции + - name: zh-cn-lang + value: 开始活动 + - name: zh-tw-lang + value: 啟動應用行為顯示 - title: Pausing and Resuming an Activity path: /training/basics/activity-lifecycle/pausing.html - title: Stopping and Restarting an Activity path: /training/basics/activity-lifecycle/stopping.html - custom_link_attributes: - - ja-lang="アクティビティの一時停止と再開" - - ko-lang="액티비티 일시정지 및 재개하기" - - pt-br-lang="Pausando e reiniciando uma atividade" - - ru-lang="Приостановка и возобновление операции" - - zh-cn-lang="暂停和继续活动" - - zh-tw-lang="暫停並繼續應用行為顯示" + path_attributes: + - name: ja-lang + value: アクティビティの一時停止と再開 + - name: ko-lang + value: 액티비티 일시정지 및 재개하기 + - name: pt-br-lang + value: Pausando e reiniciando uma atividade + - name: ru-lang + value: Приостановка и возобновление операции + - name: zh-cn-lang + value: 暂停和继续活动 + - name: zh-tw-lang + value: 暫停並繼續應用行為顯示 - title: Recreating an Activity path: /training/basics/activity-lifecycle/recreating.html - custom_link_attributes: - - ja-lang="アクティビティを再作成する" - - ko-lang="액티비티 재생성하기" - - pt-br-lang="Recriando uma atividade" - - ru-lang="Воссоздание операции" - - zh-cn-lang="重新创建活动" - - zh-tw-lang="重新建立應用行為顯示" + path_attributes: + - name: ja-lang + value: アクティビティを再作成する + - name: ko-lang + value: 액티비티 재생성하기 + - name: pt-br-lang + value: Recriando uma atividade + - name: ru-lang + value: Воссоздание операции + - name: zh-cn-lang + value: 重新创建活动 + - name: zh-tw-lang + value: 重新建立應用行為顯示 - title: Building a Dynamic UI with Fragments path: /training/basics/fragments/index.html - custom_link_attributes: - - description="How to build a user interface for your app that is flexible enough to present multiple UI components on large screens and a more constrained set of UI components on smaller screens—essential for building a single APK for both phones and tablets." + path_attributes: + - name: description + value: How to build a user interface for your app that is flexible enough to present multiple UI components on large screens and a more constrained set of UI components on smaller screens—essential for building a single APK for both phones and tablets. section: - title: Creating a Fragment path: /training/basics/fragments/creating.html - title: Building a Flexible UI path: /training/basics/fragments/fragment-ui.html - custom_link_attributes: - - zh-cn-lang="构建灵活的界面" + path_attributes: + - name: zh-cn-lang + value: 构建灵活的界面 - title: Communicating with Other Fragments path: /training/basics/fragments/communicating.html - title: Saving Data path: /training/basics/data-storage/index.html - custom_link_attributes: - - ja-lang="データの保存" - - ko-lang="데이터 저장하기" - - pt-br-lang="Salvando dados" - - ru-lang="Сохранение данных" - - zh-cn-lang="保存数据" - - zh-tw-lang="儲存資料" - - description="How to save data on the device, whether it's temporary files, downloaded app assets, user media, structured data, or something else." + path_attributes: + - name: ja-lang + value: データの保存 + - name: ko-lang + value: 데이터 저장하기 + - name: pt-br-lang + value: Salvando dados + - name: ru-lang + value: Сохранение данных + - name: zh-cn-lang + value: 保存数据 + - name: zh-tw-lang + value: 儲存資料 + - name: description + value: How to save data on the device, whether it's temporary files, downloaded app assets, user media, structured data, or something else. section: - title: Saving Key-Value Sets path: /training/basics/data-storage/shared-preferences.html - custom_link_attributes: - - ja-lang="キー値セットを保存する" - - ko-lang="키-값 세트 저장하기" - - pt-br-lang="Salvando conjuntos de valor-chave" - - ru-lang="Сохранение наборов \"ключ-значение\"" - - zh-cn-lang="保存键值集" - - zh-tw-lang="儲存索引鍵值組" + path_attributes: + - name: ja-lang + value: キー値セットを保存する + - name: ko-lang + value: 키-값 세트 저장하기 + - name: pt-br-lang + value: Salvando conjuntos de valor-chave + - name: ru-lang + value: Сохранение наборов "ключ-значение" + - name: zh-cn-lang + value: 保存键值集 + - name: zh-tw-lang + value: 儲存索引鍵值組 - title: Saving Files path: /training/basics/data-storage/files.html - custom_link_attributes: - - ja-lang="ファイルを保存する" - - ko-lang="파일 저장하기" - - pt-br-lang="Salvando arquivos" - - ru-lang="Сохранение файлов" - - zh-cn-lang="保存文件" - - zh-tw-lang="儲存檔案" + path_attributes: + - name: ja-lang + value: ファイルを保存する + - name: ko-lang + value: 파일 저장하기 + - name: pt-br-lang + value: Salvando arquivos + - name: ru-lang + value: Сохранение файлов + - name: zh-cn-lang + value: 保存文件 + - name: zh-tw-lang + value: 儲存檔案 - title: Saving Data in SQL Databases path: /training/basics/data-storage/databases.html - custom_link_attributes: - - ja-lang="SQL データベースにデータを保存する" - - ko-lang="SQL 데이터베이스에 데이터 저장하기" - - pt-br-lang="Salvando dados em bancos de dados do SQL" - - ru-lang="Сохранение данных в базах данных SQL" - - zh-cn-lang="在 SQL 数据库中保存数据" - - zh-tw-lang="在 SQL 資料庫中儲存資料" + path_attributes: + - name: ja-lang + value: SQL データベースにデータを保存する + - name: ko-lang + value: SQL 데이터베이스에 데이터 저장하기 + - name: pt-br-lang + value: Salvando dados em bancos de dados do SQL + - name: ru-lang + value: Сохранение данных в базах данных SQL + - name: zh-cn-lang + value: 在 SQL 数据库中保存数据 + - name: zh-tw-lang + value: 在 SQL 資料庫中儲存資料 - title: Interacting with Other Apps path: /training/basics/intents/index.html - custom_link_attributes: - - ja-lang="他のアプリとの相互操作" - - ko-lang="액티비티 수명 주기 관리하기" - - pt-br-lang="Interagindo com outros aplicativos" - - ru-lang="Взаимодействие с другими приложениями" - - zh-cn-lang="与其他应用交互" - - zh-tw-lang="與其他應用程式互動" - - description="How to build a user experience that leverages other apps available on the device to perform advanced user tasks, such as capture a photo or view an address on a map." + path_attributes: + - name: ja-lang + value: 他のアプリとの相互操作 + - name: ko-lang + value: 액티비티 수명 주기 관리하기 + - name: pt-br-lang + value: Interagindo com outros aplicativos + - name: ru-lang + value: Взаимодействие с другими приложениями + - name: zh-cn-lang + value: 与其他应用交互 + - name: zh-tw-lang + value: 與其他應用程式互動 + - name: description + value: How to build a user experience that leverages other apps available on the device to perform advanced user tasks, such as capture a photo or view an address on a map. section: - title: Sending the User to Another App path: /training/basics/intents/sending.html - custom_link_attributes: - - ja-lang="別のアプリにユーザーを送る" - - ko-lang="다른 앱으로 사용자 보내기" - - pt-br-lang="Enviando o usuário para outro aplicativo" - - ru-lang="Направление пользователя в другое приложение" - - zh-cn-lang="向另一个应用发送用户" - - zh-tw-lang="將使用者傳送至其他應用程式" + path_attributes: + - name: ja-lang + value: 別のアプリにユーザーを送る + - name: ko-lang + value: 다른 앱으로 사용자 보내기 + - name: pt-br-lang + value: Enviando o usuário para outro aplicativo + - name: ru-lang + value: Направление пользователя в другое приложение + - name: zh-cn-lang + value: 向另一个应用发送用户 + - name: zh-tw-lang + value: 將使用者傳送至其他應用程式 - title: Getting a Result from the Activity path: /training/basics/intents/result.html - custom_link_attributes: - - ja-lang="アクティビティから結果を取得する" - - ko-lang="액티비티로부터 결과 가져오기" - - pt-br-lang="Obtendo resultados de uma atividade" - - ru-lang="Получение результата операции" - - zh-cn-lang="获取活动的结果" - - zh-tw-lang="從應用行為顯示取得結果" + path_attributes: + - name: ja-lang + value: アクティビティから結果を取得する + - name: ko-lang + value: 액티비티로부터 결과 가져오기 + - name: pt-br-lang + value: Obtendo resultados de uma atividade + - name: ru-lang + value: Получение результата операции + - name: zh-cn-lang + value: 获取活动的结果 + - name: zh-tw-lang + value: 從應用行為顯示取得結果 - title: Allowing Other Apps to Start Your Activity path: /training/basics/intents/filters.html - custom_link_attributes: - - ja-lang="他のアプリからのアクティビティの開始を許可する" - - ko-lang="다른 앱이 자신의 액티비티를 시작하도록 허용하기" - - pt-br-lang="Permitindo que outros aplicativos iniciem sua atividade" - - ru-lang="Разрешение другим приложениям на запуск вашей операции" - - zh-cn-lang="允许其他应用开始您的活动" - - zh-tw-lang="允許其他應用程式啟動您的應用行為顯示" + path_attributes: + - name: ja-lang + value: 他のアプリからのアクティビティの開始を許可する + - name: ko-lang + value: 다른 앱이 자신의 액티비티를 시작하도록 허용하기 + - name: pt-br-lang + value: Permitindo que outros aplicativos iniciem sua atividade + - name: ru-lang + value: Разрешение другим приложениям на запуск вашей операции + - name: zh-cn-lang + value: 允许其他应用开始您的活动 + - name: zh-tw-lang + value: 允許其他應用程式啟動您的應用行為顯示 - title: Working with System Permissions path: /training/permissions/index.html - custom_link_attributes: - - description="How to declare that your app needs access to features and resources outside of its 'sandbox', and how to request those privileges at runtime." + path_attributes: + - name: description + value: How to declare that your app needs access to features and resources outside of its 'sandbox', and how to request those privileges at runtime. section: - title: Declaring Permissions path: /training/permissions/declaring.html @@ -172,8 +252,9 @@ toc: section: - title: Sharing Simple Data path: /training/sharing/index.html - custom_link_attributes: - - description="How to take your app interaction to the next level by sharing information with other apps, receive information back, and provide a simple and scalable way to perform Share actions with user content." + path_attributes: + - name: description + value: How to take your app interaction to the next level by sharing information with other apps, receive information back, and provide a simple and scalable way to perform Share actions with user content. section: - title: Sending Simple Data to Other Apps path: /training/sharing/send.html @@ -183,8 +264,9 @@ toc: path: /training/sharing/shareaction.html - title: Sharing Files path: /training/secure-file-sharing/index.html - custom_link_attributes: - - description="How to provide secure access to a file associated with your app using a content URI and temporary access permissions." + path_attributes: + - name: description + value: How to provide secure access to a file associated with your app using a content URI and temporary access permissions. section: - title: Setting Up File Sharing path: /training/secure-file-sharing/setup-sharing.html @@ -196,8 +278,9 @@ toc: path: /training/secure-file-sharing/retrieve-info.html - title: Sharing Files with NFC path: /training/beam-files/index.html - custom_link_attributes: - - description="How to transfer files between devices using the NFC Android Beam feature." + path_attributes: + - name: description + value: How to transfer files between devices using the NFC Android Beam feature. section: - title: Sending Files to Another Device path: /training/beam-files/send-files.html @@ -209,8 +292,9 @@ toc: section: - title: Managing Audio Playback path: /training/managing-audio/index.html - custom_link_attributes: - - description="How to respond to hardware audio key presses, request audio focus when playing audio, and respond appropriately to changes in audio focus." + path_attributes: + - name: description + value: How to respond to hardware audio key presses, request audio focus when playing audio, and respond appropriately to changes in audio focus. section: - title: Controlling Your App's Volume and Playback path: /training/managing-audio/volume-playback.html @@ -220,8 +304,9 @@ toc: path: /training/managing-audio/audio-output.html - title: Capturing Photos path: /training/camera/index.html - custom_link_attributes: - - description="How to leverage existing camera apps on the user's device to capture photos or control the camera hardware directly and build your own camera app." + path_attributes: + - name: description + value: How to leverage existing camera apps on the user's device to capture photos or control the camera hardware directly and build your own camera app. section: - title: Taking Photos Simply path: /training/camera/photobasics.html @@ -231,8 +316,9 @@ toc: path: /training/camera/cameradirect.html - title: Printing Content path: /training/printing/index.html - custom_link_attributes: - - description="How to print photos, HTML documents, and custom documents from your app." + path_attributes: + - name: description + value: How to print photos, HTML documents, and custom documents from your app. section: - title: Photos path: /training/printing/photos.html @@ -246,8 +332,9 @@ toc: section: - title: Displaying Bitmaps Efficiently path: /training/displaying-bitmaps/index.html - custom_link_attributes: - - description="How to load and process bitmaps while keeping your user interface responsive and avoid exceeding memory limits." + path_attributes: + - name: description + value: How to load and process bitmaps while keeping your user interface responsive and avoid exceeding memory limits. section: - title: Loading Large Bitmaps Efficiently path: /training/displaying-bitmaps/load-bitmap.html @@ -261,8 +348,9 @@ toc: path: /training/displaying-bitmaps/display-bitmap.html - title: Displaying Graphics with OpenGL ES path: /training/graphics/opengl/index.html - custom_link_attributes: - - description="How to create OpenGL graphics within the Android app framework and respond to touch input." + path_attributes: + - name: description + value: How to create OpenGL graphics within the Android app framework and respond to touch input. section: - title: Building an OpenGL ES Environment path: /training/graphics/opengl/environment.html @@ -278,8 +366,9 @@ toc: path: /training/graphics/opengl/touch.html - title: Animating Views Using Scenes and Transitions path: /training/transitions/index.html - custom_link_attributes: - - description="How to animate state changes in a view hierarchy using transitions." + path_attributes: + - name: description + value: How to animate state changes in a view hierarchy using transitions. section: - title: The Transitions Framework path: /training/transitions/overview.html @@ -291,8 +380,9 @@ toc: path: /training/transitions/custom-transitions.html - title: Adding Animations path: /training/animation/index.html - custom_link_attributes: - - description="How to add transitional animations to your user interface." + path_attributes: + - name: description + value: How to add transitional animations to your user interface. section: - title: Crossfading Two Views path: /training/animation/crossfade.html @@ -310,8 +400,9 @@ toc: section: - title: Connecting Devices Wirelessly path: /training/connect-devices-wirelessly/index.html - custom_link_attributes: - - description="How to find and connect to local devices using Network Service Discovery and how to create peer-to-peer connections with Wi-Fi." + path_attributes: + - name: description + value: How to find and connect to local devices using Network Service Discovery and how to create peer-to-peer connections with Wi-Fi. section: - title: Using Network Service Discovery path: /training/connect-devices-wirelessly/nsd.html @@ -321,8 +412,9 @@ toc: path: /training/connect-devices-wirelessly/nsd-wifi-direct.html - title: Performing Network Operations path: /training/basics/network-ops/index.html - custom_link_attributes: - - description="How to create a network connection, monitor the connection for changes in connectivity, and perform transactions with XML data." + path_attributes: + - name: description + value: How to create a network connection, monitor the connection for changes in connectivity, and perform transactions with XML data. section: - title: Connecting to the Network path: /training/basics/network-ops/connecting.html @@ -332,8 +424,9 @@ toc: path: /training/basics/network-ops/xml.html - title: Transferring Data Without Draining the Battery path: /training/efficient-downloads/index.html - custom_link_attributes: - - description="How to minimize your app's impact on the battery when performing downloads and other network transactions." + path_attributes: + - name: description + value: How to minimize your app's impact on the battery when performing downloads and other network transactions. section: - title: Optimizing Downloads for Efficient Network Access path: /training/efficient-downloads/efficient-network-access.html @@ -345,8 +438,9 @@ toc: path: /training/efficient-downloads/connectivity_patterns.html - title: Syncing to the Cloud path: /training/backup/index.html - custom_link_attributes: - - description="How to sync and back up app and user data to remote web services in the cloud and how to restore the data back to multiple devices." + path_attributes: + - name: description + value: How to sync and back up app and user data to remote web services in the cloud and how to restore the data back to multiple devices. section: - title: Configuring Auto Backup path: /training/backup/autosyncapi.html @@ -354,12 +448,14 @@ toc: path: /training/backup/backupapi.html - title: Resolving Cloud Save Conflicts path: /training/cloudsave/conflict-res.html - custom_link_attributes: - - description="How to design a robust conflict resolution strategy for apps that save data to the cloud." + path_attributes: + - name: description + value: How to design a robust conflict resolution strategy for apps that save data to the cloud. - title: Transferring Data Using Sync Adapters path: /training/sync-adapters/index.html - custom_link_attributes: - - description="How to transfer data between the cloud and the device using the Android sync adapter framework" + path_attributes: + - name: description + value: How to transfer data between the cloud and the device using the Android sync adapter framework section: - title: Creating a Stub Authenticator path: /training/sync-adapters/creating-authenticator.html @@ -371,8 +467,9 @@ toc: path: /training/sync-adapters/running-sync-adapter.html - title: Transmitting Network Data Using Volley path: /training/volley/index.html - custom_link_attributes: - - description="How to perform fast, scalable UI operations over the network using Volley" + path_attributes: + - name: description + value: How to perform fast, scalable UI operations over the network using Volley section: - title: Sending a Simple Request path: /training/volley/simple.html @@ -388,8 +485,9 @@ toc: section: - title: Making Your App Location-Aware path: /training/location/index.html - custom_link_attributes: - - description="How to add location-aware features to your app by getting the user's current location." + path_attributes: + - name: description + value: How to add location-aware features to your app by getting the user's current location. section: - title: Getting the Last Known Location path: /training/location/retrieve-current.html @@ -403,16 +501,18 @@ toc: path: /training/location/geofencing.html - title: Adding Maps path: /training/maps/index.html - custom_link_attributes: - - description="How to add maps and mapping information to your app." + path_attributes: + - name: description + value: How to add maps and mapping information to your app. - title: Building Apps with User Info & Sign-In path: /training/building-userinfo.html section: - title: Accessing Contacts Data path: /training/contacts-provider/index.html - custom_link_attributes: - - description="How to use Android's central address book, the Contacts Provider, to display contacts and their details and modify contact information." + path_attributes: + - name: description + value: How to use Android's central address book, the Contacts Provider, to display contacts and their details and modify contact information. section: - title: Retrieving a List of Contacts path: /training/contacts-provider/retrieve-names.html @@ -424,16 +524,18 @@ toc: path: /training/contacts-provider/display-contact-badge.html - title: Adding Sign-In path: /training/sign-in/index.html - custom_link_attributes: - - description="How to add user sign-in functionality to your app." + path_attributes: + - name: description + value: How to add user sign-in functionality to your app. - title: Building Apps for Wearables path: /training/building-wearables.html section: - title: Adding Wearable Features to Notifications path: /training/wearables/notifications/index.html - custom_link_attributes: - - description="How to build handheld notifications that are synced to and look great on wearables." + path_attributes: + - name: description + value: How to build handheld notifications that are synced to and look great on wearables. section: - title: Creating a Notification path: /training/wearables/notifications/creating.html @@ -445,8 +547,9 @@ toc: path: /training/wearables/notifications/stacks.html - title: Creating Wearable Apps path: /training/wearables/apps/index.html - custom_link_attributes: - - description="How to build apps that run directly on wearables." + path_attributes: + - name: description + value: How to build apps that run directly on wearables. section: - title: Creating and Running a Wearable App path: /training/wearables/apps/creating.html @@ -462,8 +565,9 @@ toc: path: /training/wearables/apps/bt-debugging.html - title: Creating Custom UIs path: /training/wearables/ui/index.html - custom_link_attributes: - - description="How to create custom user interfaces for wearable apps." + path_attributes: + - name: description + value: How to create custom user interfaces for wearable apps. section: - title: Defining Layouts path: /training/wearables/ui/layouts.html @@ -479,8 +583,9 @@ toc: path: /training/wearables/ui/exit.html - title: Sending and Syncing Data path: /training/wearables/data-layer/index.html - custom_link_attributes: - - description="How to sync data between handhelds and wearables." + path_attributes: + - name: description + value: How to sync data between handhelds and wearables. section: - title: Accessing the Wearable Data Layer path: /training/wearables/data-layer/accessing.html @@ -494,8 +599,9 @@ toc: path: /training/wearables/data-layer/events.html - title: Creating Watch Faces path: /training/wearables/watch-faces/index.html - custom_link_attributes: - - description="How to create watch faces for wearables." + path_attributes: + - name: description + value: How to create watch faces for wearables. section: - title: Designing Watch Faces path: /training/wearables/watch-faces/designing.html @@ -515,70 +621,85 @@ toc: path: /training/wearables/watch-faces/performance.html - title: Detecting Location path: /training/articles/wear-location-detection.html - custom_link_attributes: - - description="How to detect location data on Android Wear devices." + path_attributes: + - name: description + value: How to detect location data on Android Wear devices. - title: Requesting Permissions path: /training/articles/wear-permissions.html - custom_link_attributes: - - description="How to request permissions on Android Wear devices." + path_attributes: + - name: description + value: How to request permissions on Android Wear devices. - title: Using the Speaker path: /training/wearables/wearable-sounds.html - custom_link_attributes: - - description="How to use the speaker on Android Wear devices." + path_attributes: + - name: description + value: How to use the speaker on Android Wear devices. - title: Building Apps for TV path: /training/tv/index.html section: - title: Building TV Apps path: /training/tv/start/index.html - custom_link_attributes: - - ja-lang="TV アプリのビルド" - - description="How to start building TV apps or extend your existing app to run on TV devices." + path_attributes: + - name: ja-lang + value: TV アプリのビルド + - name: description + value: How to start building TV apps or extend your existing app to run on TV devices. section: - title: Getting Started with TV Apps path: /training/tv/start/start.html - custom_link_attributes: - - ja-lang="TV アプリのビルドを開始する" + path_attributes: + - name: ja-lang + value: TV アプリのビルドを開始する - title: Handling TV Hardware path: /training/tv/start/hardware.html - custom_link_attributes: - - ja-lang="TV ハードウェアを処理する" + path_attributes: + - name: ja-lang + value: TV ハードウェアを処理する - title: Building TV Layouts path: /training/tv/start/layouts.html - custom_link_attributes: - - ja-lang="TV 向けレイアウトをビルドする" + path_attributes: + - name: ja-lang + value: TV 向けレイアウトをビルドする - title: Creating TV Navigation path: /training/tv/start/navigation.html - custom_link_attributes: - - ja-lang="TV 用のナビゲーションを作成する" + path_attributes: + - name: ja-lang + value: TV 用のナビゲーションを作成する - title: Building TV Playback Apps path: /training/tv/playback/index.html - custom_link_attributes: - - ja-lang="TV 再生アプリのビルド" - - description="How to build apps that provide media catalogs and play content." + path_attributes: + - name: ja-lang + value: TV 再生アプリのビルド + - name: description + value: How to build apps that provide media catalogs and play content. section: - title: Creating a Catalog Browser path: /training/tv/playback/browse.html - custom_link_attributes: - - ja-lang="カタログ ブラウザを作成する" + path_attributes: + - name: ja-lang + value: カタログ ブラウザを作成する - title: Providing a Card View path: /training/tv/playback/card.html - title: Building a Details View path: /training/tv/playback/details.html - custom_link_attributes: - - ja-lang="詳細ビューをビルドする" + path_attributes: + - name: ja-lang + value: 詳細ビューをビルドする - title: Displaying a Now Playing Card path: /training/tv/playback/now-playing.html - custom_link_attributes: - - ja-lang="再生中カードを表示する" + path_attributes: + - name: ja-lang + value: 再生中カードを表示する - title: Adding a Guided Step path: /training/tv/playback/guided-step.html - title: Enabling Background Playback path: /training/tv/playback/options.html - title: Helping Users Find Content on TV path: /training/tv/discovery/index.html - custom_link_attributes: - - description="How to help users discover content from your app." + path_attributes: + - name: description + value: How to help users discover content from your app. section: - title: Recommending TV Content path: /training/tv/discovery/recommendations.html @@ -588,12 +709,14 @@ toc: path: /training/tv/discovery/in-app-search.html - title: Building TV Games path: /training/tv/games/index.html - custom_link_attributes: - - description="How to build games for TV." + path_attributes: + - name: description + value: How to build games for TV. - title: Building TV Channels path: /training/tv/tif/index.html - custom_link_attributes: - - description="How to build channels for TV." + path_attributes: + - name: description + value: How to build channels for TV. section: - title: Developing a TV Input Service path: /training/tv/tif/tvinput.html @@ -603,24 +726,28 @@ toc: path: /training/tv/tif/ui.html - title: TV Apps Checklist path: /training/tv/publishing/checklist.html - custom_link_attributes: - - description="An itemized list of requirements for TV apps." + path_attributes: + - name: description + value: An itemized list of requirements for TV apps. - title: Building Apps for Auto path: /training/auto/index.html section: - title: Getting Started with Auto path: /training/auto/start/index.html - custom_link_attributes: - - description="How to start building or extending apps that work with Auto devices." + path_attributes: + - name: description + value: How to start building or extending apps that work with Auto devices. - title: Playing Audio for Auto path: /training/auto/audio/index.html - custom_link_attributes: - - description="How to extend audio apps to play content on Auto devices." + path_attributes: + - name: description + value: How to extend audio apps to play content on Auto devices. - title: Messaging for Auto path: /training/auto/messaging/index.html - custom_link_attributes: - - description="How to extend text messaging apps to work with Auto devices." + path_attributes: + - name: description + value: How to extend text messaging apps to work with Auto devices. - title: Building Apps for Work path: /training/enterprise/index.html @@ -639,8 +766,9 @@ toc: section: - title: Designing Effective Navigation path: /training/design-navigation/index.html - custom_link_attributes: - - description="How to plan your app's screen hierarchy and forms of navigation so users can effectively and intuitively traverse your app content using various navigation patterns." + path_attributes: + - name: description + value: How to plan your app's screen hierarchy and forms of navigation so users can effectively and intuitively traverse your app content using various navigation patterns. section: - title: Planning Screens and Their Relationships path: /training/design-navigation/screen-planning.html @@ -654,8 +782,9 @@ toc: path: /training/design-navigation/wireframing.html - title: Implementing Effective Navigation path: /training/implementing-navigation/index.html - custom_link_attributes: - - description="How to implement various navigation patterns such as swipe views, a navigation drawer, and up navigation." + path_attributes: + - name: description + value: How to implement various navigation patterns such as swipe views, a navigation drawer, and up navigation. section: - title: Creating Swipe Views with Tabs path: /training/implementing-navigation/lateral.html @@ -669,8 +798,9 @@ toc: path: /training/implementing-navigation/descendant.html - title: Notifying the User path: /training/notify-user/index.html - custom_link_attributes: - - description="How to display messages called notifications outside of your application's UI." + path_attributes: + - name: description + value: How to display messages called notifications outside of your application's UI. section: - title: Building a Notification path: /training/notify-user/build-notification.html @@ -684,8 +814,9 @@ toc: path: /training/notify-user/display-progress.html - title: Supporting Swipe-to-Refresh path: /training/swipe/index.html - custom_link_attributes: - - description="How to modify your app's layout to support manual content updates triggered by the swipe-to-refresh gesture." + path_attributes: + - name: description + value: How to modify your app's layout to support manual content updates triggered by the swipe-to-refresh gesture. section: - title: Adding Swipe-to-Refresh To Your App path: /training/swipe/add-swipe-interface.html @@ -693,8 +824,9 @@ toc: path: /training/swipe/respond-refresh-request.html - title: Adding Search Functionality path: /training/search/index.html - custom_link_attributes: - - description="How to properly add a search interface to your app and create a searchable database." + path_attributes: + - name: description + value: How to properly add a search interface to your app and create a searchable database. section: - title: Setting up the Search Interface path: /training/search/setup.html @@ -704,8 +836,9 @@ toc: path: /training/search/backward-compat.html - title: Making Your App Content Searchable by Google path: /training/app-indexing/index.html - custom_link_attributes: - - description="How to enable deep linking and indexing of your application content so that users can open this content directly from their mobile search results." + path_attributes: + - name: description + value: How to enable deep linking and indexing of your application content so that users can open this content directly from their mobile search results. section: - title: Enabling Deep Links for App Content path: /training/app-indexing/deep-linking.html @@ -713,47 +846,64 @@ toc: path: /training/app-indexing/enabling-app-indexing.html - title: Optimizing Content for the Assistant path: /training/articles/assistant.html - custom_link_attributes: - - description="Support contextually relevant actions through the Assist API." + path_attributes: + - name: description + value: Support contextually relevant actions through the Assist API. - title: Handling App Links path: /training/app-links/index.html - custom_link_attributes: - - description="How to enable the system to handle web requests by taking the user directly to your app instead of your website." + path_attributes: + - name: description + value: How to enable the system to handle web requests by taking the user directly to your app instead of your website. - title: Best Practices for User Interface path: /training/best-ui.html section: - title: Designing for Multiple Screens path: /training/multiscreen/index.html - custom_link_attributes: - - es-lang="Cómo diseñar aplicaciones para varias pantallas" - - ja-lang="複数画面のデザイン" - - zh-cn-lang="针对多种屏幕进行设计" - - description="How to build a user interface that's flexible enough to fit perfectly on any screen and how to create different interaction patterns that are optimized for different screen sizes." + path_attributes: + - name: es-lang + value: Cómo diseñar aplicaciones para varias pantallas + - name: ja-lang + value: 複数画面のデザイン + - name: zh-cn-lang + value: 针对多种屏幕进行设计 + - name: description + value: How to build a user interface that's flexible enough to fit perfectly on any screen and how to create different interaction patterns that are optimized for different screen sizes. section: - title: Supporting Different Screen Sizes path: /training/multiscreen/screensizes.html - custom_link_attributes: - - es-lang="Cómo admitir varios tamaños de pantalla" - - ja-lang="さまざまな画面サイズのサポート" - - ko-lang="다양한 화면 크기 지원" - - zh-cn-lang="支持各种屏幕尺寸" + path_attributes: + - name: es-lang + value: Cómo admitir varios tamaños de pantalla + - name: ja-lang + value: さまざまな画面サイズのサポート + - name: ko-lang + value: 다양한 화면 크기 지원 + - name: zh-cn-lang + value: 支持各种屏幕尺寸 - title: Supporting Different Screen Densities path: /training/multiscreen/screendensities.html - custom_link_attributes: - - es-lang="Cómo admitir varias densidades de pantalla" - - ja-lang="さまざまな画面密度のサポート" - - zh-cn-lang="支持各种屏幕密度" + path_attributes: + - name: es-lang + value: Cómo admitir varias densidades de pantalla + - name: ja-lang + value: さまざまな画面密度のサポート + - name: zh-cn-lang + value: 支持各种屏幕密度 - title: Implementing Adaptive UI Flows path: /training/multiscreen/adaptui.html - custom_link_attributes: - - es-lang="Cómo implementar interfaces de usuario adaptables" - - ja-lang="順応性のある UI フローの実装" - - zh-cn-lang="实施自适应用户界面流程" + path_attributes: + - name: es-lang + value: Cómo implementar interfaces de usuario adaptables + - name: ja-lang + value: 順応性のある UI フローの実装 + - name: zh-cn-lang + value: 实施自适应用户界面流程 - title: Adding the App Bar path: /training/appbar/index.html - custom_link_attributes: - - description="How to use the support library's toolbar widget to implement an app bar that displays properly on a wide range of devices." + path_attributes: + - name: description + value: How to use the support library's toolbar widget to implement an app bar that displays properly on a wide range of devices. section: - title: Setting Up the App Bar path: /training/appbar/setting-up.html @@ -765,8 +915,9 @@ toc: path: /training/appbar/action-views.html - title: Showing Pop-Up Messages path: /training/snackbar/index.html - custom_link_attributes: - - description="How to use the support library's Snackbar widget to display a brief pop-up message." + path_attributes: + - name: description + value: How to use the support library's Snackbar widget to display a brief pop-up message. section: - title: Building and Displaying a Pop-Up Message path: /training/snackbar/showing.html @@ -774,8 +925,9 @@ toc: path: /training/snackbar/action.html - title: Creating Custom Views path: /training/custom-views/index.html - custom_link_attributes: - - description="How to build custom UI widgets that are interactive and smooth." + path_attributes: + - name: description + value: How to build custom UI widgets that are interactive and smooth. section: - title: Creating a Custom View Class path: /training/custom-views/create-view.html @@ -787,8 +939,9 @@ toc: path: /training/custom-views/optimizing-view.html - title: Creating Backward-Compatible UIs path: /training/backward-compatible-ui/index.html - custom_link_attributes: - - description="How to use UI components and other APIs from the more recent versions of Android while remaining compatible with older versions of the platform." + path_attributes: + - name: description + value: How to use UI components and other APIs from the more recent versions of Android while remaining compatible with older versions of the platform. section: - title: Abstracting the New APIs path: /training/backward-compatible-ui/abstracting.html @@ -800,8 +953,9 @@ toc: path: /training/backward-compatible-ui/using-component.html - title: Implementing Accessibility path: /training/accessibility/index.html - custom_link_attributes: - - description="How to make your app accessible to users with vision impairment or other physical disabilities." + path_attributes: + - name: description + value: How to make your app accessible to users with vision impairment or other physical disabilities. section: - title: Developing Accessible Applications path: /training/accessibility/accessible-app.html @@ -811,8 +965,9 @@ toc: path: /training/accessibility/testing.html - title: Managing the System UI path: /training/system-ui/index.html - custom_link_attributes: - - description="How to hide and show status and navigation bars across different versions of Android, while managing the display of other screen components." + path_attributes: + - name: description + value: How to hide and show status and navigation bars across different versions of Android, while managing the display of other screen components. section: - title: Dimming the System Bars path: /training/system-ui/dim.html @@ -826,110 +981,184 @@ toc: path: /training/system-ui/visibility.html - title: Creating Apps with Material Design path: /training/material/index.html - custom_link_attributes: - - es-lang="Crear aplicaciones con Material Design" - - in-lang="Desain Bahan untuk Pengembang" - - ja-lang="マテリアル デザインでのアプリ作成" - - ko-lang="개발자를 위한 머티리얼 디자인" - - pt-br-lang="Material Design para desenvolvedores" - - ru-lang="Создание приложений с помощью Material Design" - - vi-lang="Material Design cho Nhà phát triển" - - zh-cn-lang="面向开发者的材料设计" - - zh-tw-lang="開發人員材料設計" - - description="How to implement material design on Android." + path_attributes: + - name: es-lang + value: Crear aplicaciones con Material Design + - name: in-lang + value: Desain Bahan untuk Pengembang + - name: ja-lang + value: マテリアル デザインでのアプリ作成 + - name: ko-lang + value: 개발자를 위한 머티리얼 디자인 + - name: pt-br-lang + value: Material Design para desenvolvedores + - name: ru-lang + value: Создание приложений с помощью Material Design + - name: vi-lang + value: Material Design cho Nhà phát triển + - name: zh-cn-lang + value: 面向开发者的材料设计 + - name: zh-tw-lang + value: 開發人員材料設計 + - name: description + value: How to implement material design on Android. section: - title: Getting Started path: /training/material/get-started.html - custom_link_attributes: - - es-lang="Comencemos" - - in-lang="Memulai" - - ja-lang="スタート ガイド" - - ko-lang="시작하기" - - pt-br-lang="Como iniciar" - - ru-lang="Начало работы" - - vi-lang="Bắt đầu" - - zh-cn-lang="入门指南" - - zh-tw-lang="開始使用" + path_attributes: + - name: es-lang + value: Comencemos + - name: in-lang + value: Memulai + - name: ja-lang + value: スタート ガイド + - name: ko-lang + value: 시작하기 + - name: pt-br-lang + value: Como iniciar + - name: ru-lang + value: Начало работы + - name: vi-lang + value: Bắt đầu + - name: zh-cn-lang + value: 入门指南 + - name: zh-tw-lang + value: 開始使用 - title: Using the Material Theme path: /training/material/theme.html - custom_link_attributes: - - es-lang="Usar el tema Material" - - in-lang="Menggunakan Tema Bahan" - - ja-lang="マテリアル テーマの使用" - - ko-lang="머티어리얼 테마 사용" - - pt-br-lang="Como usar o tema do Material" - - ru-lang="Использование темы Material Design" - - vi-lang="Sử dụng Chủ đề Material" - - zh-cn-lang="使用材料主题" - - zh-tw-lang="使用材料設計風格" + path_attributes: + - name: es-lang + value: Usar el tema Material + - name: in-lang + value: Menggunakan Tema Bahan + - name: ja-lang + value: マテリアル テーマの使用 + - name: ko-lang + value: 머티어리얼 테마 사용 + - name: pt-br-lang + value: Como usar o tema do Material + - name: ru-lang + value: Использование темы Material Design + - name: vi-lang + value: Sử dụng Chủ đề Material + - name: zh-cn-lang + value: 使用材料主题 + - name: zh-tw-lang + value: 使用材料設計風格 - title: Creating Lists and Cards path: /training/material/lists-cards.html - custom_link_attributes: - - es-lang="Crear listas y tarjetas" - - in-lang="Membuat Daftar dan Kartu" - - ja-lang="リストとカードの作成" - - ko-lang="목록 및 카드 생성" - - pt-br-lang="Como criar listas e cartões" - - ru-lang="Создание списков и подсказок" - - vi-lang="Tạo Danh sách và Thẻ" - - zh-cn-lang="创建列表与卡片" - - zh-tw-lang="建立清單和卡片" + path_attributes: + - name: es-lang + value: Crear listas y tarjetas + - name: in-lang + value: Membuat Daftar dan Kartu + - name: ja-lang + value: リストとカードの作成 + - name: ko-lang + value: 목록 및 카드 생성 + - name: pt-br-lang + value: Como criar listas e cartões + - name: ru-lang + value: Создание списков и подсказок + - name: vi-lang + value: Tạo Danh sách và Thẻ + - name: zh-cn-lang + value: 创建列表与卡片 + - name: zh-tw-lang + value: 建立清單和卡片 - title: Defining Shadows and Clipping Views path: /training/material/shadows-clipping.html - custom_link_attributes: - - es-lang="Definir vistas de recorte y sombras" - - in-lang="Mendefinisikan Bayangan dan Memangkas Tampilan" - - ja-lang="シャドウとクリッピング ビューの定義" - - ko-lang="그림자 정의 및 뷰 클리핑" - - pt-br-lang="Como definir sombras e recortar visualizações" - - ru-lang="Определение теней и обрезка представлений" - - vi-lang="Định nghĩa Đổ bóng và Dạng xem Cắt hình" - - zh-cn-lang="定义阴影与裁剪视图" - - zh-tw-lang="定義陰影和裁剪檢視" + path_attributes: + - name: es-lang + value: Definir vistas de recorte y sombras + - name: in-lang + value: Mendefinisikan Bayangan dan Memangkas Tampilan + - name: ja-lang + value: シャドウとクリッピング ビューの定義 + - name: ko-lang + value: 그림자 정의 및 뷰 클리핑 + - name: pt-br-lang + value: Como definir sombras e recortar visualizações + - name: ru-lang + value: Определение теней и обрезка представлений + - name: vi-lang + value: Định nghĩa Đổ bóng và Dạng xem Cắt hình + - name: zh-cn-lang + value: 定义阴影与裁剪视图 + - name: zh-tw-lang + value: 定義陰影和裁剪檢視 - title: Working with Drawables path: /training/material/drawables.html - custom_link_attributes: - - es-lang="Trabajar con interfaces dibujables" - - in-lang="Bekerja dengan Drawable" - - ja-lang="ドローアブルの使用" - - ko-lang="Drawable 사용" - - pt-br-lang="Como trabalhar com desenháveis" - - ru-lang="Работа с элементами дизайна" - - vi-lang="Làm việc với Nội dung vẽ được" - - zh-cn-lang="使用 Drawables" - - zh-tw-lang="使用可繪項目" + path_attributes: + - name: es-lang + value: Trabajar con interfaces dibujables + - name: in-lang + value: Bekerja dengan Drawable + - name: ja-lang + value: ドローアブルの使用 + - name: ko-lang + value: Drawable 사용 + - name: pt-br-lang + value: Como trabalhar com desenháveis + - name: ru-lang + value: Работа с элементами дизайна + - name: vi-lang + value: Làm việc với Nội dung vẽ được + - name: zh-cn-lang + value: 使用 Drawables + - name: zh-tw-lang + value: 使用可繪項目 - title: Defining Custom Animations path: /training/material/animations.html - custom_link_attributes: - - es-lang="Definir animaciones personalizadas" - - in-lang="Mendefinisikan Animasi Custom" - - ja-lang="カスタム アニメーションの定義" - - ko-lang="사용자지정 애니메이션 정의" - - pt-br-lang="Como definir animações personalizadas" - - ru-lang="Определение настраиваемой анимации" - - vi-lang="Định nghĩa Hoạt hình Tùy chỉnh" - - zh-cn-lang="定义定制动画" - - zh-tw-lang="定義自訂動畫" + path_attributes: + - name: es-lang + value: Definir animaciones personalizadas + - name: in-lang + value: Mendefinisikan Animasi Custom + - name: ja-lang + value: カスタム アニメーションの定義 + - name: ko-lang + value: 사용자지정 애니메이션 정의 + - name: pt-br-lang + value: Como definir animações personalizadas + - name: ru-lang + value: Определение настраиваемой анимации + - name: vi-lang + value: Định nghĩa Hoạt hình Tùy chỉnh + - name: zh-cn-lang + value: 定义定制动画 + - name: zh-tw-lang + value: 定義自訂動畫 - title: Maintaining Compatibility path: /training/material/compatibility.html - custom_link_attributes: - - es-lang="Mantener la compatibilidad" - - in-lang="Mempertahankan Kompatibilitas" - - ja-lang="互換性の維持" - - ko-lang="호환성 유지" - - pt-br-lang="Como manter a compatibilidade" - - ru-lang="Обеспечение совместимости" - - vi-lang="Duy trì Tính tương thích" - - zh-cn-lang="维护兼容性" - - zh-tw-lang="維持相容性" + path_attributes: + - name: es-lang + value: Mantener la compatibilidad + - name: in-lang + value: Mempertahankan Kompatibilitas + - name: ja-lang + value: 互換性の維持 + - name: ko-lang + value: 호환성 유지 + - name: pt-br-lang + value: Como manter a compatibilidade + - name: ru-lang + value: Обеспечение совместимости + - name: vi-lang + value: Duy trì Tính tương thích + - name: zh-cn-lang + value: 维护兼容性 + - name: zh-tw-lang + value: 維持相容性 - title: Best Practices for User Input path: /training/best-user-input.html section: - title: Using Touch Gestures path: /training/gestures/index.html - custom_link_attributes: - - description="How to write apps that allow users to interact with the touch screen via touch gestures." + path_attributes: + - name: description + value: How to write apps that allow users to interact with the touch screen via touch gestures. section: - title: Detecting Common Gestures path: /training/gestures/detector.html @@ -945,8 +1174,9 @@ toc: path: /training/gestures/viewgroup.html - title: Handling Keyboard Input path: /training/keyboard-input/index.html - custom_link_attributes: - - description="How to specify the appearance and behaviors of soft input methods (such as on-screen keyboards) and how to optimize the experience with hardware keyboards." + path_attributes: + - name: description + value: How to specify the appearance and behaviors of soft input methods (such as on-screen keyboards) and how to optimize the experience with hardware keyboards. section: - title: Specifying the Input Method Type path: /training/keyboard-input/style.html @@ -958,8 +1188,9 @@ toc: path: /training/keyboard-input/commands.html - title: Supporting Game Controllers path: /training/game-controllers/index.html - custom_link_attributes: - - description="How to write apps that support game controllers." + path_attributes: + - name: description + value: How to write apps that support game controllers. section: - title: Handling Controller Actions path: /training/game-controllers/controller-input.html @@ -973,8 +1204,9 @@ toc: section: - title: Running in a Background Service path: /training/run-background-service/index.html - custom_link_attributes: - - description="How to improve UI performance and responsiveness by sending work to a Service running in the background" + path_attributes: + - name: description + value: How to improve UI performance and responsiveness by sending work to a Service running in the background section: - title: Creating a Background Service path: /training/run-background-service/create-service.html @@ -984,8 +1216,9 @@ toc: path: /training/run-background-service/report-status.html - title: Loading Data in the Background path: /training/load-data-background/index.html - custom_link_attributes: - - description="How to use CursorLoader to query data without affecting UI responsiveness." + path_attributes: + - name: description + value: How to use CursorLoader to query data without affecting UI responsiveness. section: - title: Running a Query with a CursorLoader path: /training/load-data-background/setup-loader.html @@ -993,8 +1226,9 @@ toc: path: /training/load-data-background/handle-results.html - title: Managing Device Awake State path: /training/scheduling/index.html - custom_link_attributes: - - description="How to use repeating alarms and wake locks to run background jobs." + path_attributes: + - name: description + value: How to use repeating alarms and wake locks to run background jobs. section: - title: Keeping the Device Awake path: /training/scheduling/wakelock.html @@ -1006,16 +1240,19 @@ toc: section: - title: Managing Your App's Memory path: /training/articles/memory.html - custom_link_attributes: - - description="How to keep your app's memory footprint small in order to improve performance on a variety of mobile devices." + path_attributes: + - name: description + value: How to keep your app's memory footprint small in order to improve performance on a variety of mobile devices. - title: Performance Tips path: /training/articles/perf-tips.html - custom_link_attributes: - - description="How to optimize your app's performance in various ways to improve its responsiveness and battery efficiency." + path_attributes: + - name: description + value: How to optimize your app's performance in various ways to improve its responsiveness and battery efficiency. - title: Improving Layout Performance path: /training/improving-layouts/index.html - custom_link_attributes: - - description="How to identify problems in your app's layout performance and improve the UI responsiveness." + path_attributes: + - name: description + value: How to identify problems in your app's layout performance and improve the UI responsiveness. section: - title: Optimizing Layout Hierarchies path: /training/improving-layouts/optimizing-layout.html @@ -1027,11 +1264,15 @@ toc: path: /training/improving-layouts/smooth-scrolling.html - title: Optimizing Battery Life path: /training/monitoring-device-state/index.html - custom_link_attributes: - - es-lang="Cómo optimizar la duración de la batería" - - ja-lang="電池消費量の最適化" - - zh-cn-lang="优化电池使用时间" - - 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." + path_attributes: + - name: es-lang + value: Cómo optimizar la duración de la batería + - name: ja-lang + value: 電池消費量の最適化 + - name: zh-cn-lang + value: 优化电池使用时间 + - name: description + value: How to minimize the amount of power your app requires by adapting to current power conditions and performing power-hungry tasks at proper intervals. section: - title: Reducing Network Battery Drain path: /training/performance/battery/network/index.html @@ -1052,32 +1293,45 @@ toc: path: /training/monitoring-device-state/doze-standby.html - title: Monitoring the Battery Level and Charging State path: /training/monitoring-device-state/battery-monitoring.html - custom_link_attributes: - - es-lang="Cómo controlar el nivel de batería y el estado de carga" - - ja-lang="電池残量と充電状態の監視" - - zh-cn-lang="监控电池电量和充电状态" + path_attributes: + - name: es-lang + value: Cómo controlar el nivel de batería y el estado de carga + - name: ja-lang + value: 電池残量と充電状態の監視 + - name: zh-cn-lang + value: 监控电池电量和充电状态 - title: Determining and Monitoring the Docking State and Type path: /training/monitoring-device-state/docking-monitoring.html - custom_link_attributes: - - es-lang="Cómo determinar y controlar el tipo de conector y el estado de la conexión" - - ja-lang="ホルダーの装着状態とタイプの特定と監視" - - zh-cn-lang="确定和监控基座对接状态和类型" + path_attributes: + - name: es-lang + value: Cómo determinar y controlar el tipo de conector y el estado de la conexión + - name: ja-lang + value: ホルダーの装着状態とタイプの特定と監視 + - name: zh-cn-lang + value: 确定和监控基座对接状态和类型 - title: Determining and Monitoring the Connectivity Status path: /training/monitoring-device-state/connectivity-monitoring.html - custom_link_attributes: - - es-lang="Cómo determinar y controlar el estado de la conectividad" - - ja-lang="接続状態の特定と監視" - - zh-cn-lang="确定和监控网络连接状态" + path_attributes: + - name: es-lang + value: Cómo determinar y controlar el estado de la conectividad + - name: ja-lang + value: 接続状態の特定と監視 + - name: zh-cn-lang + value: 确定和监控网络连接状态 - title: Manipulating Broadcast Receivers On Demand path: /training/monitoring-device-state/manifest-receivers.html - custom_link_attributes: - - es-lang="Cómo manipular los receptores de emisión bajo demanda" - - ja-lang="オンデマンドでのブロードキャスト レシーバ操作" - - zh-cn-lang="根据需要操作广播接收器" + path_attributes: + - name: es-lang + value: Cómo manipular los receptores de emisión bajo demanda + - name: ja-lang + value: オンデマンドでのブロードキャスト レシーバ操作 + - name: zh-cn-lang + value: 根据需要操作广播接收器 - title: Sending Operations to Multiple Threads path: /training/multiple-threads/index.html - custom_link_attributes: - - description="How to improve the performance and scalability of long-running operations by dispatching work to multiple threads." + path_attributes: + - name: description + value: How to improve the performance and scalability of long-running operations by dispatching work to multiple threads. section: - title: Specifying the Code to Run on a Thread path: /training/multiple-threads/define-runnable.html @@ -1089,68 +1343,81 @@ toc: path: /training/multiple-threads/communicate-ui.html - title: Keeping Your App Responsive path: /training/articles/perf-anr.html - custom_link_attributes: - - description="How to keep your app responsive to user interaction so the UI does not lock-up and display an \"Application Not Responding\" dialog." + path_attributes: + - name: description + value: How to keep your app responsive to user interaction so the UI does not lock-up and display an "Application Not Responding" dialog. - title: JNI Tips path: /training/articles/perf-jni.html - custom_link_attributes: - - description="How to efficiently use the Java Native Interface with the Android NDK." + path_attributes: + - name: description + value: How to efficiently use the Java Native Interface with the Android NDK. - title: SMP Primer for Android path: /training/articles/smp.html - custom_link_attributes: - - description="Tips for coding Android apps on symmetric multiprocessor systems." + path_attributes: + - name: description + value: Tips for coding Android apps on symmetric multiprocessor systems. - title: Best Practices for Security & Privacy path: /training/best-security.html section: - title: Security Tips path: /training/articles/security-tips.html - custom_link_attributes: - - description="How to perform various tasks and keep your app's data and your user's data secure." + path_attributes: + - name: description + value: How to perform various tasks and keep your app's data and your user's data secure. - title: Security with HTTPS and SSL path: /training/articles/security-ssl.html - custom_link_attributes: - - description="How to ensure that your app is secure when performing network transactions." + path_attributes: + - name: description + value: How to ensure that your app is secure when performing network transactions. - title: Updating Your Security Provider to Protect Against SSL Exploits path: /training/articles/security-gms-provider.html - custom_link_attributes: - - description="How to use and update Google Play services security provider, to protect against SSL exploits." + path_attributes: + - name: description + value: How to use and update Google Play services security provider, to protect against SSL exploits. - title: Checking Device Compatibility with SafetyNet path: /training/safetynet/index.html - custom_link_attributes: - - description="How to use the SafetyNet service to analyze a device where your app is running and get information about its compatibility with your app." + path_attributes: + - name: description + value: How to use the SafetyNet service to analyze a device where your app is running and get information about its compatibility with your app. - title: Enhancing Security with Device Management Policies path: /training/enterprise/device-management-policy.html - custom_link_attributes: - - description="How to create an application that enforces security policies on devices." + path_attributes: + - name: description + value: How to create an application that enforces security policies on devices. - title: Best Practices for Permissions & Identifiers path: /training/best-permissions-ids.html section: - title: Permissions and User Data path: /training/articles/user-data-overview.html - custom_link_attributes: - - description="Overview of app permissions on Android and how they affect your users." + path_attributes: + - name: description + value: Overview of app permissions on Android and how they affect your users. - title: Best Practices for App Permissions path: /training/articles/user-data-permissions.html - custom_link_attributes: - - description="How to manage permissions the right way for users." + path_attributes: + - name: description + value: How to manage permissions the right way for users. - title: Best Practices for Unique Identifiers path: /training/articles/user-data-ids.html - custom_link_attributes: - - description="Unique identifiers available and how to choose the right one for your use case." + path_attributes: + - name: description + value: Unique identifiers available and how to choose the right one for your use case. - title: Best Practices for Testing path: /training/testing/index.html section: - title: Getting Started with Testing path: /training/testing/start/index.html - custom_link_attributes: - - description="How to get started with testing your Android applications." + path_attributes: + - name: description + value: How to get started with testing your Android applications. - title: Building Effective Unit Tests path: /training/testing/unit-testing/index.html - custom_link_attributes: - - description="How to build effective unit tests for Android apps." + path_attributes: + - name: description + value: How to build effective unit tests for Android apps. section: - title: Building Local Unit Tests path: /training/testing/unit-testing/local-unit-tests.html @@ -1158,8 +1425,9 @@ toc: path: /training/testing/unit-testing/instrumented-unit-tests.html - title: Automating UI Tests path: /training/testing/ui-testing/index.html - custom_link_attributes: - - description="How to automate your user interface tests for Android apps." + path_attributes: + - name: description + value: How to automate your user interface tests for Android apps. section: - title: Testing UI for a Single App path: /training/testing/ui-testing/espresso-testing.html @@ -1167,8 +1435,9 @@ toc: path: /training/testing/ui-testing/uiautomator-testing.html - title: Testing App Component Integrations path: /training/testing/integration-testing/index.html - custom_link_attributes: - - description="How to build effective integration tests for Android apps." + path_attributes: + - name: description + value: How to build effective integration tests for Android apps. section: - title: Testing Your Service path: /training/testing/integration-testing/service-testing.html @@ -1176,16 +1445,18 @@ toc: path: /training/testing/integration-testing/content-provider-testing.html - title: Testing Display Performance path: /training/testing/performance.html - custom_link_attributes: - - description="How to automate UI performance testing." + path_attributes: + - name: description + value: How to automate UI performance testing. - title: Using Google Play to Distribute & Monetize path: /training/distribute.html section: - title: Selling In-app Products path: /training/in-app-billing/index.html - custom_link_attributes: - - description="How to sell in-app products from your application using In-app Billing." + path_attributes: + - name: description + value: How to sell in-app products from your application using In-app Billing. section: - title: Preparing Your App path: /training/in-app-billing/preparing-iab-app.html @@ -1197,8 +1468,9 @@ toc: path: /training/in-app-billing/test-iab-app.html - title: Maintaining Multiple APKs path: /training/multiple-apks/index.html - custom_link_attributes: - - description="How to publish your app on Google Play with separate APKs that target different devices, while using a single app listing." + path_attributes: + - name: description + value: How to publish your app on Google Play with separate APKs that target different devices, while using a single app listing. section: - title: Creating Multiple APKs for Different API Levels path: /training/multiple-apks/api.html diff --git a/docs/image_sources/tools/support-library/appbar-kitkat-orig.png b/docs/image_sources/tools/support-library/appbar-kitkat-orig.png Binary files differnew file mode 100644 index 000000000000..ab680ce67f75 --- /dev/null +++ b/docs/image_sources/tools/support-library/appbar-kitkat-orig.png diff --git a/graphics/java/android/graphics/pdf/PdfRenderer.java b/graphics/java/android/graphics/pdf/PdfRenderer.java index feb805260cb7..520ebe5f2db8 100644 --- a/graphics/java/android/graphics/pdf/PdfRenderer.java +++ b/graphics/java/android/graphics/pdf/PdfRenderer.java @@ -129,6 +129,10 @@ public final class PdfRenderer implements AutoCloseable { * <strong>Note:</strong> This class takes ownership of the passed in file descriptor * and is responsible for closing it when the renderer is closed. * </p> + * <p> + * If the file is from an untrusted source it is recommended to run the renderer in a separate, + * isolated process with minimal permissions to limit the impact of security exploits. + * </p> * * @param input Seekable file descriptor to read from. * diff --git a/graphics/java/android/view/PixelCopy.java b/graphics/java/android/view/PixelCopy.java index 95c930c5264d..29bf963842da 100644 --- a/graphics/java/android/view/PixelCopy.java +++ b/graphics/java/android/view/PixelCopy.java @@ -123,6 +123,9 @@ public final class PixelCopy { public static void request(@NonNull Surface source, @NonNull Bitmap dest, @NonNull OnPixelCopyFinishedListener listener, @NonNull Handler listenerThread) { validateBitmapDest(dest); + if (!source.isValid()) { + throw new IllegalArgumentException("Surface isn't valid, source.isValid() == false"); + } // TODO: Make this actually async and fast and cool and stuff int result = ThreadedRenderer.copySurfaceInto(source, dest); listenerThread.post(new Runnable() { diff --git a/include/androidfw/ZipUtils.h b/include/androidfw/ZipUtils.h index 094eaa8dd214..55575d774522 100644 --- a/include/androidfw/ZipUtils.h +++ b/include/androidfw/ZipUtils.h @@ -21,6 +21,7 @@ #define __LIBS_ZIPUTILS_H #include <stdint.h> +#include <string.h> #include <stdio.h> #include <time.h> @@ -63,16 +64,21 @@ public: /* * Utility function to convert ZIP's time format to a timespec struct. + * + * NOTE: this method will clear all existing state from |timespec|. */ static inline void zipTimeToTimespec(uint32_t when, struct tm* timespec) { const uint32_t date = when >> 16; + + memset(timespec, 0, sizeof(struct tm)); timespec->tm_year = ((date >> 9) & 0x7F) + 80; // Zip is years since 1980 - timespec->tm_mon = (date >> 5) & 0x0F; + timespec->tm_mon = ((date >> 5) & 0x0F) - 1; timespec->tm_mday = date & 0x1F; timespec->tm_hour = (when >> 11) & 0x1F; timespec->tm_min = (when >> 5) & 0x3F; timespec->tm_sec = (when & 0x1F) << 1; + timespec->tm_isdst = -1; } private: ZipUtils() {} diff --git a/libs/androidfw/tests/ZipUtils_test.cpp b/libs/androidfw/tests/ZipUtils_test.cpp index c6038b597f4e..7293843e066a 100644 --- a/libs/androidfw/tests/ZipUtils_test.cpp +++ b/libs/androidfw/tests/ZipUtils_test.cpp @@ -45,7 +45,7 @@ TEST_F(ZipUtilsTest, ZipTimeConvertSuccess) { EXPECT_EQ(2011, t.tm_year + 1900) << "Year was improperly converted."; - EXPECT_EQ(6, t.tm_mon) + EXPECT_EQ(5, t.tm_mon) << "Month was improperly converted."; EXPECT_EQ(29, t.tm_mday) @@ -59,6 +59,11 @@ TEST_F(ZipUtilsTest, ZipTimeConvertSuccess) { EXPECT_EQ(40, t.tm_sec) << "Second was improperly converted."; + + // We don't have enough information to determine timezone related info. + EXPECT_EQ(-1, t.tm_isdst); + EXPECT_EQ(0, t.tm_gmtoff); + EXPECT_EQ(nullptr, t.tm_zone); } } diff --git a/libs/hwui/GlopBuilder.cpp b/libs/hwui/GlopBuilder.cpp index fdbe76a5e459..0a8e3f3b4db3 100644 --- a/libs/hwui/GlopBuilder.cpp +++ b/libs/hwui/GlopBuilder.cpp @@ -471,18 +471,19 @@ GlopBuilder& GlopBuilder::setFillTextureLayer(Layer& layer, float alpha) { return *this; } -GlopBuilder& GlopBuilder::setFillExternalTexture(Texture& texture) { +GlopBuilder& GlopBuilder::setFillExternalTexture(Texture& texture, Matrix4& textureTransform) { TRIGGER_STAGE(kFillStage); REQUIRE_STAGES(kMeshStage | kRoundRectClipStage); mOutGlop->fill.texture = { &texture, GL_TEXTURE_EXTERNAL_OES, GL_LINEAR, GL_CLAMP_TO_EDGE, - nullptr }; + &textureTransform }; setFill(SK_ColorWHITE, 1.0f, SkXfermode::kSrc_Mode, Blend::ModeOrderSwap::NoSwap, nullptr, nullptr); mDescription.modulate = mOutGlop->fill.color.a < 1.0f; + mDescription.hasTextureTransform = true; return *this; } diff --git a/libs/hwui/GlopBuilder.h b/libs/hwui/GlopBuilder.h index b6c186d85e76..a9dd56f385b1 100644 --- a/libs/hwui/GlopBuilder.h +++ b/libs/hwui/GlopBuilder.h @@ -73,7 +73,7 @@ public: // TODO: Texture should probably know and own its target. // setFillLayer() forces it to GL_TEXTURE which isn't always correct. // Similarly setFillLayer normally forces its own wrap & filter mode - GlopBuilder& setFillExternalTexture(Texture& texture); + GlopBuilder& setFillExternalTexture(Texture& texture, Matrix4& textureTransform); GlopBuilder& setTransform(const Snapshot& snapshot, const int transformFlags) { return setTransform(*snapshot.transform, transformFlags); diff --git a/libs/hwui/Matrix.h b/libs/hwui/Matrix.h index 36007cd5dc0e..9cde5d6aa04e 100644 --- a/libs/hwui/Matrix.h +++ b/libs/hwui/Matrix.h @@ -236,6 +236,8 @@ public: static const Matrix4& identity(); + void invalidateType() { mType = kTypeUnknown; } + private: mutable uint8_t mType; diff --git a/libs/hwui/Readback.cpp b/libs/hwui/Readback.cpp index 49596e143ebf..55f823dfe226 100644 --- a/libs/hwui/Readback.cpp +++ b/libs/hwui/Readback.cpp @@ -101,7 +101,10 @@ CopyResult Readback::copySurfaceInto(renderthread::RenderThread& renderThread, // Setup the source sp<GraphicBuffer> sourceBuffer; sp<Fence> sourceFence; - status_t err = surface.getLastQueuedBuffer(&sourceBuffer, &sourceFence); + Matrix4 texTransform; + status_t err = surface.getLastQueuedBuffer(&sourceBuffer, &sourceFence, + texTransform.data); + texTransform.invalidateType(); if (err != NO_ERROR) { ALOGW("Failed to get last queued buffer, error = %d", err); return CopyResult::UnknownError; @@ -163,8 +166,8 @@ CopyResult Readback::copySurfaceInto(renderthread::RenderThread& renderThread, Glop glop; GlopBuilder(renderState, caches, &glop) .setRoundRectClipState(nullptr) - .setMeshTexturedUvQuad(nullptr, Rect(0, 1, 1, 0)) // TODO: simplify with VBO - .setFillExternalTexture(sourceTexture) + .setMeshTexturedUnitQuad(nullptr) + .setFillExternalTexture(sourceTexture, texTransform) .setTransform(Matrix4::identity(), TransformFlags::None) .setModelViewMapUnitToRect(destRect) .build(); diff --git a/media/java/android/media/MediaCodecInfo.java b/media/java/android/media/MediaCodecInfo.java index 05e12a143034..b9ed269fe9dc 100644 --- a/media/java/android/media/MediaCodecInfo.java +++ b/media/java/android/media/MediaCodecInfo.java @@ -1247,7 +1247,8 @@ public final class MediaCodecInfo { private Range<Double> estimateFrameRatesFor(int width, int height) { Size size = findClosestSize(width, height); Range<Long> range = mMeasuredFrameRates.get(size); - Double ratio = (double)(size.getWidth() * size.getHeight()) / (width * height); + Double ratio = getBlockCount(size.getWidth(), size.getHeight()) + / (double)Math.max(getBlockCount(width, height), 1); return Range.create(range.getLower() * ratio, range.getUpper() * ratio); } @@ -2688,20 +2689,20 @@ public final class MediaCodecInfo { public static final int VP9Profile3HDR = 0x2000; // from OMX_VIDEO_VP9LEVELTYPE - public static final int VP9Level1 = 0x0; - public static final int VP9Level11 = 0x1; - public static final int VP9Level2 = 0x2; - public static final int VP9Level21 = 0x4; - public static final int VP9Level3 = 0x8; - public static final int VP9Level31 = 0x10; - public static final int VP9Level4 = 0x20; - public static final int VP9Level41 = 0x40; - public static final int VP9Level5 = 0x80; - public static final int VP9Level51 = 0x100; - public static final int VP9Level52 = 0x200; - public static final int VP9Level6 = 0x400; - public static final int VP9Level61 = 0x800; - public static final int VP9Level62 = 0x1000; + public static final int VP9Level1 = 0x1; + public static final int VP9Level11 = 0x2; + public static final int VP9Level2 = 0x4; + public static final int VP9Level21 = 0x8; + public static final int VP9Level3 = 0x10; + public static final int VP9Level31 = 0x20; + public static final int VP9Level4 = 0x40; + public static final int VP9Level41 = 0x80; + public static final int VP9Level5 = 0x100; + public static final int VP9Level51 = 0x200; + public static final int VP9Level52 = 0x400; + public static final int VP9Level6 = 0x800; + public static final int VP9Level61 = 0x1000; + public static final int VP9Level62 = 0x2000; // from OMX_VIDEO_HEVCPROFILETYPE public static final int HEVCProfileMain = 0x01; @@ -2744,6 +2745,7 @@ public final class MediaCodecInfo { public static final int DolbyVisionProfileDvheDtr = 0x10; public static final int DolbyVisionProfileDvheStn = 0x20; public static final int DolbyVisionProfileDvheDth = 0x40; + public static final int DolbyVisionProfileDvheDtb = 0x80; // from OMX_VIDEO_DOLBYVISIONLEVELTYPE public static final int DolbyVisionLevelHd24 = 0x1; diff --git a/media/java/android/media/MediaFormat.java b/media/java/android/media/MediaFormat.java index 346f083f696b..93c595f1ca2b 100644 --- a/media/java/android/media/MediaFormat.java +++ b/media/java/android/media/MediaFormat.java @@ -46,7 +46,8 @@ import java.util.Map; * <tr><td>{@link #KEY_HEIGHT}</td><td>Integer</td><td></td></tr> * <tr><td>{@link #KEY_COLOR_FORMAT}</td><td>Integer</td><td>set by the user * for encoders, readable in the output format of decoders</b></td></tr> - * <tr><td>{@link #KEY_FRAME_RATE}</td><td>Integer or Float</td><td><b>encoder-only</b></td></tr> + * <tr><td>{@link #KEY_FRAME_RATE}</td><td>Integer or Float</td><td>required for <b>encoders</b>, + * optional for <b>decoders</b></td></tr> * <tr><td>{@link #KEY_CAPTURE_RATE}</td><td>Integer</td><td></td></tr> * <tr><td>{@link #KEY_I_FRAME_INTERVAL}</td><td>Integer</td><td><b>encoder-only</b></td></tr> * <tr><td>{@link #KEY_INTRA_REFRESH_PERIOD}</td><td>Integer</td><td><b>encoder-only</b>, optional</td></tr> @@ -197,7 +198,19 @@ public final class MediaFormat { /** * A key describing the frame rate of a video format in frames/sec. - * The associated value is an integer or a float. + * The associated value is normally an integer when the value is used by the platform, + * but video codecs also accept float configuration values. + * Specifically, {@link MediaExtractor#getTrackFormat MediaExtractor} provides an integer + * value corresponding to the frame rate information of the track if specified and non-zero. + * Otherwise, this key is not present. {@link MediaCodec#configure MediaCodec} accepts both + * float and integer values. This represents the desired operating frame rate if the + * {@link #KEY_OPERATING_RATE} is not present and {@link #KEY_PRIORITY} is {@code 0} + * (realtime). For video encoders this value corresponds to the intended frame rate, + * although encoders are expected + * to support variable frame rate based on {@link MediaCodec.BufferInfo#presentationTimeUs + * buffer timestamp}. This key is not used in the {@code MediaCodec} + * {@link MediaCodec#getInputFormat input}/{@link MediaCodec#getOutputFormat output} formats, + * nor by {@link MediaMuxer#addTrack MediaMuxer}. */ public static final String KEY_FRAME_RATE = "frame-rate"; diff --git a/media/java/android/media/tv/TvInputManager.java b/media/java/android/media/tv/TvInputManager.java index 1d894e16a0f4..22bb5f1bdcef 100644 --- a/media/java/android/media/tv/TvInputManager.java +++ b/media/java/android/media/tv/TvInputManager.java @@ -188,6 +188,9 @@ public final class TvInputManager { RECORDING_ERROR_RESOURCE_BUSY}) public @interface RecordingError {} + static final int RECORDING_ERROR_START = 0; + static final int RECORDING_ERROR_END = 2; + /** * Error for {@link TvInputService.RecordingSession#notifyError(int)} and * {@link TvRecordingClient.RecordingCallback#onError(int)}: The requested operation cannot be @@ -195,7 +198,7 @@ public final class TvInputManager { * for the problem is defined on the higher version than application's * <code>android:targetSdkVersion</code>. */ - public static final int RECORDING_ERROR_UNKNOWN = 0; + public static final int RECORDING_ERROR_UNKNOWN = RECORDING_ERROR_START; /** * Error for {@link TvInputService.RecordingSession#notifyError(int)} and @@ -209,7 +212,7 @@ public final class TvInputManager { * {@link TvRecordingClient.RecordingCallback#onError(int)}: Recording cannot proceed because * a required recording resource was not able to be allocated. */ - public static final int RECORDING_ERROR_RESOURCE_BUSY = 2; + public static final int RECORDING_ERROR_RESOURCE_BUSY = RECORDING_ERROR_END; /** @hide */ @Retention(RetentionPolicy.SOURCE) diff --git a/media/java/android/media/tv/TvInputService.java b/media/java/android/media/tv/TvInputService.java index 488b2849b2a1..168fcdcbd76d 100644 --- a/media/java/android/media/tv/TvInputService.java +++ b/media/java/android/media/tv/TvInputService.java @@ -1613,7 +1613,14 @@ public abstract class TvInputService extends Service { * <li>{@link TvInputManager#RECORDING_ERROR_RESOURCE_BUSY} * </ul> */ - public void notifyError(@TvInputManager.RecordingError final int error) { + public void notifyError(@TvInputManager.RecordingError int error) { + if (error < TvInputManager.RECORDING_ERROR_START + || error > TvInputManager.RECORDING_ERROR_END) { + Log.w(TAG, "notifyError - invalid error code (" + error + + ") is changed to RECORDING_ERROR_UNKNOWN."); + error = TvInputManager.RECORDING_ERROR_UNKNOWN; + } + final int validError = error; executeOrPostRunnableOnMainThread(new Runnable() { @MainThread @Override @@ -1621,7 +1628,7 @@ public abstract class TvInputService extends Service { try { if (DEBUG) Log.d(TAG, "notifyError"); if (mSessionCallback != null) { - mSessionCallback.onError(error); + mSessionCallback.onError(validError); } } catch (RemoteException e) { Log.w(TAG, "error in notifyError", e); diff --git a/packages/ExtServices/src/android/ext/services/notification/Ranker.java b/packages/ExtServices/src/android/ext/services/notification/Ranker.java index 3ef2aea43a0d..fefedf8fc487 100644 --- a/packages/ExtServices/src/android/ext/services/notification/Ranker.java +++ b/packages/ExtServices/src/android/ext/services/notification/Ranker.java @@ -68,9 +68,7 @@ public final class Ranker extends NotificationRankerService { if (notificationsForPackage == null) { notificationsForPackage = new LinkedHashSet<>(); } - if (notificationsForPackage.contains(sbn.getKey())) { - return; - } + notificationsForPackage.add(sbn.getKey()); mUnbundledNotifications.put(sbn.getPackageName(), notificationsForPackage); diff --git a/packages/PrintSpooler/AndroidManifest.xml b/packages/PrintSpooler/AndroidManifest.xml index ed6fdb7ce4d8..2da4d6a25dd3 100644 --- a/packages/PrintSpooler/AndroidManifest.xml +++ b/packages/PrintSpooler/AndroidManifest.xml @@ -57,7 +57,7 @@ <activity android:name=".ui.PrintActivity" - android:configChanges="screenSize|smallestScreenSize|orientation|locale|keyboard|keyboardHidden|fontScale|uiMode|layoutDirection" + android:configChanges="mnc|mnc|touchscreen|navigation|screenLayout|screenSize|smallestScreenSize|orientation|locale|keyboard|keyboardHidden|fontScale|uiMode|layoutDirection|density" android:permission="android.permission.BIND_PRINT_SPOOLER_SERVICE" android:theme="@style/Theme.PrintActivity"> <intent-filter> diff --git a/packages/PrintSpooler/src/com/android/printspooler/model/PageContentRepository.java b/packages/PrintSpooler/src/com/android/printspooler/model/PageContentRepository.java index bb359176bdf1..999d82d592ea 100644 --- a/packages/PrintSpooler/src/com/android/printspooler/model/PageContentRepository.java +++ b/packages/PrintSpooler/src/com/android/printspooler/model/PageContentRepository.java @@ -510,7 +510,12 @@ public final class PageContentRepository { public void destroy() { if (mBoundToService) { mBoundToService = false; - mContext.unbindService(AsyncRenderer.this); + try { + mContext.unbindService(AsyncRenderer.this); + } catch (IllegalArgumentException e) { + // Service might have been forcefully unbound in onDestroy() + Log.e(LOG_TAG, "Cannot unbind service", e); + } } mPageContentCache.invalidate(); diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java index c4111864ba2d..cc0b4ca46d48 100644 --- a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java +++ b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java @@ -268,7 +268,7 @@ public class PrintActivity extends Activity implements RemotePrintDocument.Updat new Runnable() { @Override public void run() { - if (isFinishing()) { + if (isFinishing() || isDestroyed()) { // onPause might have not been able to cancel the job, see PrintActivity#onPause // To be sure, cancel the job again. Double canceling does no harm. mSpoolerProvider.getSpooler().setPrintJobState(mPrintJob.getId(), @@ -288,12 +288,8 @@ public class PrintActivity extends Activity implements RemotePrintDocument.Updat // the first batch of results which will be delivered // after reading historical data. This should be pretty // fast, so just wait before showing the UI. - mPrinterRegistry = new PrinterRegistry(PrintActivity.this, - new Runnable() { - @Override - public void run() { - onPrinterRegistryReady(documentAdapter); - } + mPrinterRegistry = new PrinterRegistry(PrintActivity.this, () -> { + (new Handler(getMainLooper())).post(() -> onPrinterRegistryReady(documentAdapter)); }, LOADER_ID_PRINT_REGISTRY, LOADER_ID_PRINT_REGISTRY_INT); } @@ -324,7 +320,8 @@ public class PrintActivity extends Activity implements RemotePrintDocument.Updat // If we are finishing or we are in a state that we do not need any // data from the printing app, then no need to finish. - if (isFinishing() || (isFinalState(mState) && !mPrintedDocument.isUpdating())) { + if (isFinishing() || isDestroyed() || + (isFinalState(mState) && !mPrintedDocument.isUpdating())) { return; } setState(STATE_PRINT_CANCELED); @@ -622,6 +619,17 @@ public class PrintActivity extends Activity implements RemotePrintDocument.Updat } @Override + protected void onDestroy() { + if (mPrintedDocument != null) { + mPrintedDocument.cancel(true); + } + + doFinish(); + + super.onDestroy(); + } + + @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { switch (requestCode) { case ACTIVITY_REQUEST_CREATE_FILE: { @@ -964,7 +972,7 @@ public class PrintActivity extends Activity implements RemotePrintDocument.Updat } private void ensureProgressUiShown() { - if (isFinishing()) { + if (isFinishing() || isDestroyed()) { return; } if (mUiState != UI_STATE_PROGRESS) { @@ -976,7 +984,7 @@ public class PrintActivity extends Activity implements RemotePrintDocument.Updat } private void ensurePreviewUiShown() { - if (isFinishing()) { + if (isFinishing() || isDestroyed()) { return; } if (mUiState != UI_STATE_PREVIEW) { @@ -987,7 +995,7 @@ public class PrintActivity extends Activity implements RemotePrintDocument.Updat } private void ensureErrorUiShown(CharSequence message, int action) { - if (isFinishing()) { + if (isFinishing() || isDestroyed()) { return; } if (mUiState != UI_STATE_ERROR) { @@ -1267,6 +1275,7 @@ public class PrintActivity extends Activity implements RemotePrintDocument.Updat mPageRangeTitle = (TextView) findViewById(R.id.page_range_title); mPageRangeEditText = (EditText) findViewById(R.id.page_range_edittext); mPageRangeEditText.setVisibility(View.INVISIBLE); + mPageRangeTitle.setVisibility(View.INVISIBLE); mPageRangeEditText.setOnFocusChangeListener(mSelectAllOnFocusListener); mPageRangeEditText.addTextChangedListener(new RangeTextWatcher()); @@ -1353,7 +1362,7 @@ public class PrintActivity extends Activity implements RemotePrintDocument.Updat @Override public void onLoaderReset(Loader<List<PrintServiceInfo>> loader) { - if (!isFinishing()) { + if (!(isFinishing() || isDestroyed())) { onLoadFinished(loader, null); } } @@ -2036,7 +2045,9 @@ public class PrintActivity extends Activity implements RemotePrintDocument.Updat mSpoolerProvider.destroy(); } - setState(mProgressMessageController.cancel()); + if (mProgressMessageController != null) { + setState(mProgressMessageController.cancel()); + } if (mState != STATE_INITIALIZING) { mPrintedDocument.finish(); diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml index 74c98e4f5988..efa34ff8ec08 100644 --- a/packages/SettingsLib/res/values/strings.xml +++ b/packages/SettingsLib/res/values/strings.xml @@ -421,8 +421,6 @@ <string name="wifi_aggressive_handover">Aggressive Wi\u2011Fi to Cellular handover</string> <!-- Setting Checkbox title whether to enable WiFi Scanning in the presence of traffic. [CHAR LIMIT=80] --> <string name="wifi_allow_scan_with_traffic">Always allow Wi\u2011Fi Roam Scans</string> - <!-- Setting Checkbox title whether to enable WiFi Scanning in the presence of traffic. [CHAR LIMIT=80] --> - <string name="legacy_dhcp_client">Use legacy DHCP client</string> <!-- Setting Checkbox title whether to always keep cellular data active. [CHAR LIMIT=80] --> <string name="mobile_data_always_on">Cellular data always active</string> <!-- Setting Checkbox title for disabling Bluetooth absolute volume --> diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java b/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java index bcbc6ac28f0a..bf750467d991 100644 --- a/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java +++ b/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java @@ -52,7 +52,7 @@ public class SettingsDrawerActivity extends Activity { protected static final boolean DEBUG_TIMING = false; private static final String TAG = "SettingsDrawerActivity"; - static final String EXTRA_SHOW_MENU = "show_drawer_menu"; + public static final String EXTRA_SHOW_MENU = "show_drawer_menu"; private static List<DashboardCategory> sDashboardCategories; private static HashMap<Pair<String, String>, Tile> sTileCache; diff --git a/packages/SystemUI/res/color/remote_input_text.xml b/packages/SystemUI/res/color/remote_input_text.xml index 11ce0b7effa9..8e18e16f8abc 100644 --- a/packages/SystemUI/res/color/remote_input_text.xml +++ b/packages/SystemUI/res/color/remote_input_text.xml @@ -16,6 +16,6 @@ --> <selector xmlns:android="http://schemas.android.com/apk/res/android"> - <item android:state_enabled="true" android:color="@android:color/white" /> + <item android:state_enabled="true" android:color="@color/remote_input_text_enabled" /> <!-- white --> <item android:color="#99ffffff" /> <!-- 60% white --> </selector>
\ No newline at end of file diff --git a/packages/SystemUI/res/layout/volume_dialog_row.xml b/packages/SystemUI/res/layout/volume_dialog_row.xml index f0ae1c997efc..be05a3ac259c 100644 --- a/packages/SystemUI/res/layout/volume_dialog_row.xml +++ b/packages/SystemUI/res/layout/volume_dialog_row.xml @@ -18,6 +18,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:clipChildren="false" + android:clipToPadding="false" android:id="@+id/volume_dialog_row" android:paddingEnd="@dimen/volume_button_size" > diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml index c75741c1d487..cb5164945923 100644 --- a/packages/SystemUI/res/values/colors.xml +++ b/packages/SystemUI/res/values/colors.xml @@ -157,6 +157,7 @@ <color name="minimize_dock_shadow_end">#00000000</color> <color name="default_remote_input_background">@*android:color/notification_default_color</color> + <color name="remote_input_text_enabled">#ffffffff</color> <color name="remote_input_hint">#99ffffff</color> <color name="remote_input_accent">#eeeeee</color> diff --git a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java index c72f5d2f18cd..0962d8488188 100644 --- a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java +++ b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java @@ -158,6 +158,7 @@ public class ImageWallpaper extends WallpaperService { private int mLastRequestedHeight = -1; private AsyncTask<Void, Void, Bitmap> mLoader; private boolean mNeedsDrawAfterLoadingWallpaper; + private boolean mSurfaceValid; public DrawableEngine() { super(); @@ -249,11 +250,6 @@ public class ImageWallpaper extends WallpaperService { } @Override - public void onTouchEvent(MotionEvent event) { - super.onTouchEvent(event); - } - - @Override public void onOffsetsChanged(float xOffset, float yOffset, float xOffsetStep, float yOffsetStep, int xPixels, int yPixels) { @@ -288,13 +284,23 @@ public class ImageWallpaper extends WallpaperService { @Override public void onSurfaceDestroyed(SurfaceHolder holder) { super.onSurfaceDestroyed(holder); + if (DEBUG) { + Log.i(TAG, "onSurfaceDestroyed"); + } + mLastSurfaceWidth = mLastSurfaceHeight = -1; + mSurfaceValid = false; } @Override public void onSurfaceCreated(SurfaceHolder holder) { super.onSurfaceCreated(holder); + if (DEBUG) { + Log.i(TAG, "onSurfaceCreated"); + } + mLastSurfaceWidth = mLastSurfaceHeight = -1; + mSurfaceValid = true; } @Override @@ -314,6 +320,9 @@ public class ImageWallpaper extends WallpaperService { } void drawFrame() { + if (!mSurfaceValid) { + return; + } try { DisplayInfo displayInfo = getDefaultDisplayInfo(); int newRotation = displayInfo.rotation; diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java index 716185f343b5..b2aa966c7449 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java +++ b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java @@ -106,6 +106,7 @@ public class QSCustomizer extends LinearLayout implements OnMenuItemClickListene public void setHost(QSTileHost host) { mHost = host; mPhoneStatusBar = host.getPhoneStatusBar(); + mTileAdapter.setHost(host); } public void setContainer(NotificationsQuickSettingsContainer notificationsQsContainer) { diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java index 41b49d824a99..ec0eefb6e662 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java +++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java @@ -81,6 +81,7 @@ public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileSta private Holder mCurrentDrag; private boolean mAccessibilityMoving; private int mAccessibilityFromIndex; + private QSTileHost mHost; public TileAdapter(Context context) { mContext = context; @@ -88,6 +89,10 @@ public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileSta mItemTouchHelper = new ItemTouchHelper(mCallbacks); } + public void setHost(QSTileHost host) { + mHost = host; + } + @Override public long getItemId(int position) { return mTiles.get(position) != null ? mAllTiles.indexOf(mTiles.get(position)) @@ -108,7 +113,7 @@ public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileSta newSpecs.add(mTiles.get(i).spec); } host.changeTiles(mCurrentSpecs, newSpecs); - setTileSpecs(newSpecs); + mCurrentSpecs = newSpecs; } public void setTileSpecs(List<String> currentSpecs) { @@ -285,6 +290,7 @@ public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileSta move(mAccessibilityFromIndex, position, v); notifyItemChanged(mAccessibilityFromIndex); notifyItemMoved(mAccessibilityFromIndex, position); + saveSpecs(mHost); } private void showAccessibilityDialog(final int position, final View v) { @@ -373,6 +379,7 @@ public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileSta fromLabel, (to + 1)); } v.announceForAccessibility(announcement); + saveSpecs(mHost); return true; } diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java index 54dd0157e899..23a3ca128de2 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java @@ -40,9 +40,11 @@ import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.MetricsProto.MetricsEvent; import com.android.systemui.R; import com.android.systemui.qs.QSTile; +import com.android.systemui.qs.external.TileLifecycleManager.TileChangeListener; import com.android.systemui.statusbar.phone.QSTileHost; +import libcore.util.Objects; -public class CustomTile extends QSTile<QSTile.State> { +public class CustomTile extends QSTile<QSTile.State> implements TileChangeListener { public static final String PREFIX = "custom("; private static final boolean DEBUG = false; @@ -58,7 +60,7 @@ public class CustomTile extends QSTile<QSTile.State> { private final IQSTileService mService; private final TileServiceManager mServiceManager; private final int mUser; - private final android.graphics.drawable.Icon mDefaultIcon; + private android.graphics.drawable.Icon mDefaultIcon; private boolean mListening; private boolean mBound; @@ -71,26 +73,66 @@ public class CustomTile extends QSTile<QSTile.State> { mComponent = ComponentName.unflattenFromString(action); mServiceManager = host.getTileServices().getTileWrapper(this); mService = mServiceManager.getTileService(); + mServiceManager.setTileChangeListener(this); mTile = new Tile(mComponent); mUser = ActivityManager.getCurrentUser(); - android.graphics.drawable.Icon defaultIcon; + setTileIcon(); + try { + mService.setQSTile(mTile); + } catch (RemoteException e) { + // Called through wrapper, won't happen here. + } + } + + private void setTileIcon() { try { PackageManager pm = mContext.getPackageManager(); ServiceInfo info = pm.getServiceInfo(mComponent, PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE); - defaultIcon = info.icon != 0 ? android.graphics.drawable.Icon + // Update the icon if its not set or is the default icon. + boolean updateIcon = mTile.getIcon() == null + || iconEquals(mTile.getIcon(), mDefaultIcon); + mDefaultIcon = info.icon != 0 ? android.graphics.drawable.Icon .createWithResource(mComponent.getPackageName(), info.icon) : null; - mTile.setIcon(defaultIcon); - mTile.setLabel(info.loadLabel(pm)); + if (updateIcon) { + mTile.setIcon(mDefaultIcon); + } + // Update the label if there is no label. + if (mTile.getLabel() == null) { + mTile.setLabel(info.loadLabel(pm)); + } } catch (Exception e) { - defaultIcon = null; + mDefaultIcon = null; } - mDefaultIcon = defaultIcon; - try { - mService.setQSTile(mTile); - } catch (RemoteException e) { - // Called through wrapper, won't happen here. + } + + /** + * Compare two icons, only works for resources. + */ + private boolean iconEquals(android.graphics.drawable.Icon icon1, + android.graphics.drawable.Icon icon2) { + if (icon1 == icon2) { + return true; + } + if (icon1 == null || icon2 == null) { + return false; + } + if (icon1.getType() != android.graphics.drawable.Icon.TYPE_RESOURCE + || icon2.getType() != android.graphics.drawable.Icon.TYPE_RESOURCE) { + return false; } + if (icon1.getResId() != icon2.getResId()) { + return false; + } + if (!Objects.equal(icon1.getResPackage(), icon2.getResPackage())) { + return false; + } + return true; + } + + @Override + public void onTileChanged(ComponentName tile) { + setTileIcon(); } @Override @@ -136,6 +178,8 @@ public class CustomTile extends QSTile<QSTile.State> { mListening = listening; try { if (listening) { + setTileIcon(); + refreshState(); if (!mServiceManager.isActiveTile()) { mServiceManager.setBindRequested(true); mService.onStartListening(); diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java index 590321889c36..212f1790fd2d 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java +++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java @@ -80,6 +80,7 @@ public class TileLifecycleManager extends BroadcastReceiver implements boolean mReceiverRegistered; private IQSService mService; private boolean mUnbindImmediate; + private TileChangeListener mChangeListener; public TileLifecycleManager(Handler handler, Context context, Intent intent, UserHandle user) { mContext = context; @@ -168,7 +169,7 @@ public class TileLifecycleManager extends BroadcastReceiver implements @Override public void onServiceDisconnected(ComponentName name) { if (DEBUG) Log.d(TAG, "onServiceDisconnected " + name); - mWrapper = null; + handleDeath(); } private void handlePendingMessages() { @@ -279,6 +280,10 @@ public class TileLifecycleManager extends BroadcastReceiver implements mReceiverRegistered = false; } + public void setTileChangeListener(TileChangeListener changeListener) { + mChangeListener = changeListener; + } + @Override public void onReceive(Context context, Intent intent) { if (DEBUG) Log.d(TAG, "onReceive: " + intent); @@ -289,6 +294,9 @@ public class TileLifecycleManager extends BroadcastReceiver implements return; } } + if (Intent.ACTION_PACKAGE_CHANGED.equals(intent.getAction()) && mChangeListener != null) { + mChangeListener.onTileChanged(mIntent.getComponent()); + } stopPackageListening(); if (mBound) { // Trying to bind again will check the state of the package before bothering to bind. @@ -401,4 +409,8 @@ public class TileLifecycleManager extends BroadcastReceiver implements if (DEBUG) Log.d(TAG, "binderDeath"); handleDeath(); } + + public interface TileChangeListener { + void onTileChanged(ComponentName tile); + } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java index f34df75a9ab9..82a5622ddf18 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java +++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java @@ -27,6 +27,7 @@ import android.os.UserHandle; import android.service.quicksettings.IQSTileService; import android.support.annotation.VisibleForTesting; import android.util.Log; +import com.android.systemui.qs.external.TileLifecycleManager.TileChangeListener; import libcore.util.Objects; /** @@ -81,6 +82,10 @@ public class TileServiceManager { new UserHandle(ActivityManager.getCurrentUser()), filter, null, mHandler); } + public void setTileChangeListener(TileChangeListener changeListener) { + mStateManager.setTileChangeListener(changeListener); + } + public boolean isActiveTile() { return mStateManager.isActiveTile(); } diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java index be06ad07f899..46b2612ee7f0 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java +++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java @@ -414,8 +414,8 @@ public class SystemServicesProxy { } try { - return mIam.moveTaskToDockedStack( - taskId, createMode, true /* onTop */, false /* animate */, initialBounds); + return mIam.moveTaskToDockedStack(taskId, createMode, true /* onTop */, + false /* animate */, initialBounds, true /* moveHomeStackFront */ ); } catch (RemoteException e) { e.printStackTrace(); } diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivityController.java b/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivityController.java index 9294ecdfb86a..34a37ba51bf1 100644 --- a/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivityController.java +++ b/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivityController.java @@ -111,6 +111,7 @@ public class ForcedResizableInfoActivityController { Intent intent = new Intent(mContext, ForcedResizableInfoActivity.class); ActivityOptions options = ActivityOptions.makeBasic(); options.setLaunchTaskId(mPendingTaskIds.valueAt(i)); + options.setAvoidMoveToFront(true); mContext.startActivity(intent, options.toBundle()); } mPendingTaskIds.clear(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java index 81303fe6be9c..5e9a8bc9bc4a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java @@ -56,15 +56,6 @@ public class NotificationContentView extends FrameLayout { private final Rect mClipBounds = new Rect(); private final int mMinContractedHeight; private final int mNotificationContentMarginEnd; - private final OnLayoutChangeListener mLayoutUpdater = new OnLayoutChangeListener() { - @Override - public void onLayoutChange(View v, int left, int top, int right, int bottom, - int oldLeft, - int oldTop, int oldRight, int oldBottom) { - selectLayout(false /* animate */, false /* force */); - } - }; - private View mContractedChild; private View mExpandedChild; @@ -119,6 +110,7 @@ public class NotificationContentView extends FrameLayout { private int mTransformationStartVisibleType; private boolean mUserExpanding; private int mSingleLineWidthIndention; + private boolean mForceSelectNextLayout = true; private PendingIntent mPreviousExpandedRemoteInputIntent; private PendingIntent mPreviousHeadsUpRemoteInputIntent; @@ -270,6 +262,8 @@ public class NotificationContentView extends FrameLayout { super.onLayout(changed, left, top, right, bottom); updateClipping(); invalidateOutline(); + selectLayout(false /* animate */, mForceSelectNextLayout /* force */); + mForceSelectNextLayout = false; } @Override @@ -317,44 +311,35 @@ public class NotificationContentView extends FrameLayout { public void setContractedChild(View child) { if (mContractedChild != null) { mContractedChild.animate().cancel(); - mContractedChild.removeOnLayoutChangeListener(mLayoutUpdater); removeView(mContractedChild); } addView(child); mContractedChild = child; - mContractedChild.addOnLayoutChangeListener(mLayoutUpdater); mContractedWrapper = NotificationViewWrapper.wrap(getContext(), child, mContainingNotification); - selectLayout(false /* animate */, true /* force */); mContractedWrapper.setDark(mDark, false /* animate */, 0 /* delay */); } public void setExpandedChild(View child) { if (mExpandedChild != null) { mExpandedChild.animate().cancel(); - mExpandedChild.removeOnLayoutChangeListener(mLayoutUpdater); removeView(mExpandedChild); } addView(child); mExpandedChild = child; - mExpandedChild.addOnLayoutChangeListener(mLayoutUpdater); mExpandedWrapper = NotificationViewWrapper.wrap(getContext(), child, mContainingNotification); - selectLayout(false /* animate */, true /* force */); } public void setHeadsUpChild(View child) { if (mHeadsUpChild != null) { mHeadsUpChild.animate().cancel(); - mHeadsUpChild.removeOnLayoutChangeListener(mLayoutUpdater); removeView(mHeadsUpChild); } addView(child); mHeadsUpChild = child; - mHeadsUpChild.addOnLayoutChangeListener(mLayoutUpdater); mHeadsUpWrapper = NotificationViewWrapper.wrap(getContext(), child, mContainingNotification); - selectLayout(false /* animate */, true /* force */); } @Override @@ -408,7 +393,8 @@ public class NotificationContentView extends FrameLayout { updateBackgroundColor(true /* animate */); } if (mTransformationStartVisibleType != UNDEFINED - && mVisibleType != mTransformationStartVisibleType) { + && mVisibleType != mTransformationStartVisibleType + && getViewForVisibleType(mTransformationStartVisibleType) != null) { final TransformableView shownView = getTransformableViewForVisibleType(mVisibleType); final TransformableView hiddenView = getTransformableViewForVisibleType( mTransformationStartVisibleType); @@ -501,26 +487,66 @@ public class NotificationContentView extends FrameLayout { } if (mUserExpanding) { updateContentTransformation(); - return; - } - int visibleType = calculateVisibleType(); - if (visibleType != mVisibleType || force) { + } else { + int visibleType = calculateVisibleType(); + if (visibleType != mVisibleType || force) { View visibleView = getViewForVisibleType(visibleType); if (visibleView != null) { visibleView.setVisibility(VISIBLE); transferRemoteInputFocus(visibleType); } - if (animate && ((visibleType == VISIBLE_TYPE_EXPANDED && mExpandedChild != null) - || (visibleType == VISIBLE_TYPE_HEADSUP && mHeadsUpChild != null) - || (visibleType == VISIBLE_TYPE_SINGLELINE && mSingleLineView != null) - || visibleType == VISIBLE_TYPE_CONTRACTED)) { - animateToVisibleType(visibleType); + if (animate && ((visibleType == VISIBLE_TYPE_EXPANDED && mExpandedChild != null) + || (visibleType == VISIBLE_TYPE_HEADSUP && mHeadsUpChild != null) + || (visibleType == VISIBLE_TYPE_SINGLELINE && mSingleLineView != null) + || visibleType == VISIBLE_TYPE_CONTRACTED)) { + animateToVisibleType(visibleType); + } else { + updateViewVisibilities(visibleType); + } + mVisibleType = visibleType; + updateBackgroundColor(animate); + } + } + if (mForceSelectNextLayout) { + forceUpdateVisibilities(); + } + } + + private void forceUpdateVisibilities() { + boolean contractedVisible = mVisibleType == VISIBLE_TYPE_CONTRACTED + || mTransformationStartVisibleType == VISIBLE_TYPE_CONTRACTED; + boolean expandedVisible = mVisibleType == VISIBLE_TYPE_EXPANDED + || mTransformationStartVisibleType == VISIBLE_TYPE_EXPANDED; + boolean headsUpVisible = mVisibleType == VISIBLE_TYPE_HEADSUP + || mTransformationStartVisibleType == VISIBLE_TYPE_HEADSUP; + boolean singleLineVisible = mVisibleType == VISIBLE_TYPE_SINGLELINE + || mTransformationStartVisibleType == VISIBLE_TYPE_SINGLELINE; + if (!contractedVisible) { + mContractedChild.setVisibility(View.INVISIBLE); + } else { + mContractedWrapper.setVisible(true); + } + if (mExpandedChild != null) { + if (!expandedVisible) { + mExpandedChild.setVisibility(View.INVISIBLE); } else { - updateViewVisibilities(visibleType); + mExpandedWrapper.setVisible(true); + } + } + if (mHeadsUpChild != null) { + if (!headsUpVisible) { + mHeadsUpChild.setVisibility(View.INVISIBLE); + } else { + mHeadsUpWrapper.setVisible(true); + } + } + if (mSingleLineView != null) { + if (!singleLineVisible) { + mSingleLineView.setVisibility(View.INVISIBLE); + } else { + mSingleLineView.setVisible(true); } - mVisibleType = visibleType; - updateBackgroundColor(animate); } } @@ -558,7 +584,7 @@ public class NotificationContentView extends FrameLayout { private void animateToVisibleType(int visibleType) { final TransformableView shownView = getTransformableViewForVisibleType(visibleType); final TransformableView hiddenView = getTransformableViewForVisibleType(mVisibleType); - if (shownView == hiddenView) { + if (shownView == hiddenView || hiddenView == null) { shownView.setVisible(true); return; } @@ -647,8 +673,9 @@ public class NotificationContentView extends FrameLayout { height = mContentHeight; } int expandedVisualType = getVisualTypeForHeight(height); - int collapsedVisualType = getVisualTypeForHeight( - mContainingNotification.getCollapsedHeight()); + int collapsedVisualType = mIsChildInGroup && !isGroupExpanded() + ? VISIBLE_TYPE_SINGLELINE + : getVisualTypeForHeight(mContainingNotification.getCollapsedHeight()); return mTransformationStartVisibleType == collapsedVisualType ? expandedVisualType : collapsedVisualType; @@ -762,7 +789,7 @@ public class NotificationContentView extends FrameLayout { mHeadsUpWrapper.notifyContentUpdated(entry.notification); } updateShowingLegacyBackground(); - selectLayout(false /* animate */, true /* force */); + mForceSelectNextLayout = true; setDark(mDark, false /* animate */, 0 /* delay */); mPreviousExpandedRemoteInputIntent = null; mPreviousHeadsUpRemoteInputIntent = null; @@ -846,7 +873,7 @@ public class NotificationContentView extends FrameLayout { color = mContext.getColor(R.color.default_remote_input_background); } existing.setBackgroundColor(NotificationColorUtil.ensureTextBackgroundColor(color, - mContext.getColor(R.color.remote_input_text), + mContext.getColor(R.color.remote_input_text_enabled), mContext.getColor(R.color.remote_input_hint))); if (existingPendingIntent != null || existing.isActive()) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java index 6d76763edc84..ce0163e66eaf 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java @@ -327,7 +327,14 @@ public class StatusBarIconView extends AnimatedImageView { public static String contentDescForNotification(Context c, Notification n) { Notification.Builder builder = Notification.Builder.recoverBuilder(c, n); String appName = builder.loadHeaderAppName(); + + CharSequence title = n.extras.getString(Notification.EXTRA_TITLE); CharSequence ticker = n.tickerText; - return c.getString(R.string.accessibility_desc_notification_icon, appName, ticker); + + CharSequence desc = !TextUtils.isEmpty(ticker) ? ticker + : !TextUtils.isEmpty(title) ? title : ""; + + return c.getString(R.string.accessibility_desc_notification_icon, appName, desc); } + } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java index f04fe5e11231..8207215ec4a9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java @@ -100,8 +100,17 @@ public class TransformState { boolean transformY = (transformationFlags & TRANSOFORM_Y) != 0; boolean transformScale = transformScale(); // lets animate the positions correctly - if (transformationAmount == 0.0f) { - int[] otherPosition = otherState.getLocationOnScreen(); + if (transformationAmount == 0.0f + || transformX && getTransformationStartX() == UNDEFINED + || transformY && getTransformationStartY() == UNDEFINED + || transformScale && getTransformationStartScaleX() == UNDEFINED + || transformScale && getTransformationStartScaleY() == UNDEFINED) { + int[] otherPosition; + if (transformationAmount != 0.0f) { + otherPosition = otherState.getLaidOutLocationOnScreen(); + } else { + otherPosition = otherState.getLocationOnScreen(); + } int[] ownStablePosition = getLaidOutLocationOnScreen(); if (customTransformation == null || !customTransformation.initTransformation(this, otherState)) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java index 23e3561710a3..6fc32de100e2 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java @@ -409,6 +409,9 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, if (mKeyguardBottomArea != null) { mKeyguardBottomArea.setUserSetupComplete(mUserSetup); } + if (mNetworkController != null) { + mNetworkController.setUserSetupComplete(mUserSetup); + } } if (mIconPolicy != null) { mIconPolicy.setCurrentUserSetup(mUserSetup); @@ -838,6 +841,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, } }); mNetworkController = new NetworkControllerImpl(mContext, mHandlerThread.getLooper()); + mNetworkController.setUserSetupComplete(mUserSetup); mHotspotController = new HotspotControllerImpl(mContext); mBluetoothController = new BluetoothControllerImpl(mContext, mHandlerThread.getLooper()); mSecurityController = new SecurityControllerImpl(mContext); @@ -1437,7 +1441,11 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, public void removeNotification(String key, RankingMap ranking) { boolean deferRemoval = false; if (mHeadsUpManager.isHeadsUp(key)) { - deferRemoval = !mHeadsUpManager.removeNotification(key); + // A cancel() in repsonse to a remote input shouldn't be delayed, as it makes the + // sending look longer than it takes. + boolean ignoreEarliestRemovalTime = mRemoteInputController.isSpinning(key) + && !FORCE_REMOTE_INPUT_HISTORY; + deferRemoval = !mHeadsUpManager.removeNotification(key, ignoreEarliestRemovalTime); } if (key.equals(mMediaNotificationKey)) { clearCurrentMediaNotification(); @@ -1985,19 +1993,29 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, artworkDrawable = new BitmapDrawable(mBackdropBack.getResources(), artworkBitmap); } } + boolean allowWhenShade = false; if (ENABLE_LOCKSCREEN_WALLPAPER && artworkDrawable == null) { Bitmap lockWallpaper = mLockscreenWallpaper.getBitmap(); if (lockWallpaper != null) { artworkDrawable = new LockscreenWallpaper.WallpaperDrawable( mBackdropBack.getResources(), lockWallpaper); + // We're in the SHADE mode on the SIM screen - yet we still need to show + // the lockscreen wallpaper in that mode. + allowWhenShade = mStatusBarKeyguardViewManager != null + && mStatusBarKeyguardViewManager.isShowing(); } } + boolean hideBecauseOccluded = mStatusBarKeyguardViewManager != null + && mStatusBarKeyguardViewManager.isOccluded(); + final boolean hasArtwork = artworkDrawable != null; - if ((hasArtwork || DEBUG_MEDIA_FAKE_ARTWORK) && mState != StatusBarState.SHADE + if ((hasArtwork || DEBUG_MEDIA_FAKE_ARTWORK) + && (mState != StatusBarState.SHADE || allowWhenShade) && mFingerprintUnlockController.getMode() - != FingerprintUnlockController.MODE_WAKE_AND_UNLOCK_PULSING) { + != FingerprintUnlockController.MODE_WAKE_AND_UNLOCK_PULSING + && !hideBecauseOccluded) { // time to show some art! if (mBackdrop.getVisibility() != View.VISIBLE) { mBackdrop.setVisibility(View.VISIBLE); @@ -2065,7 +2083,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, Log.v(TAG, "DEBUG_MEDIA: Fading out album artwork"); } if (mFingerprintUnlockController.getMode() - == FingerprintUnlockController.MODE_WAKE_AND_UNLOCK_PULSING) { + == FingerprintUnlockController.MODE_WAKE_AND_UNLOCK_PULSING + || hideBecauseOccluded) { // We are unlocking directly - no animation! mBackdrop.setVisibility(View.GONE); @@ -2353,7 +2372,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, if (wasHeadsUp) { if (!shouldPeek) { // We don't want this to be interrupting anymore, lets remove it - mHeadsUpManager.removeNotification(key); + mHeadsUpManager.removeNotification(key, false /* ignoreEarliestRemovalTime */); } else { mHeadsUpManager.updateNotification(entry, alertAgain); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java index 117e2b325ef7..dcad75aff116 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java @@ -247,6 +247,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb } } mOccluded = occluded; + mPhoneStatusBar.updateMediaMetaData(false, false); mStatusBarWindowManager.setKeyguardOccluded(occluded); reset(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java index 52fb47022275..d3ae54984e99 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java @@ -264,9 +264,9 @@ public class HeadsUpManager implements ViewTreeObserver.OnComputeInternalInsetsL * @return true if the notification was removed and false if it still needs to be kept around * for a bit since it wasn't shown long enough */ - public boolean removeNotification(String key) { + public boolean removeNotification(String key, boolean ignoreEarliestRemovalTime) { if (DEBUG) Log.v(TAG, "remove"); - if (wasShownLongEnough(key)) { + if (wasShownLongEnough(key) || ignoreEarliestRemovalTime) { releaseImmediately(key); return true; } else { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java index 80dcfb6dfe2c..83e25ebd7497 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java @@ -114,6 +114,11 @@ public class MobileSignalController extends SignalController< notifyListenersIfNecessary(); } + public void setUserSetupComplete(boolean userSetup) { + mCurrentState.userSetup = userSetup; + notifyListenersIfNecessary(); + } + @Override public void updateConnectivity(BitSet connectedTransports, BitSet validatedTransports) { boolean isValidated = validatedTransports.get(mTransportType); @@ -204,11 +209,13 @@ public class MobileSignalController extends SignalController< String contentDescription = getStringIfExists(getContentDescription()); String dataContentDescription = getStringIfExists(icons.mDataContentDescription); + final boolean dataDisabled = mCurrentState.iconGroup == TelephonyIcons.DATA_DISABLED + && mCurrentState.userSetup; - // Show icon in QS when we are connected or need to show roaming. + // Show icon in QS when we are connected or need to show roaming or data is disabled. boolean showDataIcon = mCurrentState.dataConnected || mCurrentState.iconGroup == TelephonyIcons.ROAMING - || mCurrentState.iconGroup == TelephonyIcons.DATA_DISABLED; + || dataDisabled; IconState statusIcon = new IconState(mCurrentState.enabled && !mCurrentState.airplaneMode, getCurrentIconId(), contentDescription); @@ -230,7 +237,7 @@ public class MobileSignalController extends SignalController< && mCurrentState.activityOut; showDataIcon &= mCurrentState.isDefault || mCurrentState.iconGroup == TelephonyIcons.ROAMING - || mCurrentState.iconGroup == TelephonyIcons.DATA_DISABLED; + || dataDisabled; int typeIcon = showDataIcon ? icons.mDataType : 0; callback.setMobileDataIndicators(statusIcon, qsIcon, typeIcon, qsTypeIcon, activityIn, activityOut, dataContentDescription, description, icons.mIsWide, @@ -511,6 +518,7 @@ public class MobileSignalController extends SignalController< boolean airplaneMode; boolean carrierNetworkChangeMode; boolean isDefault; + boolean userSetup; @Override public void copyFrom(State s) { @@ -524,6 +532,7 @@ public class MobileSignalController extends SignalController< isEmergency = state.isEmergency; airplaneMode = state.airplaneMode; carrierNetworkChangeMode = state.carrierNetworkChangeMode; + userSetup = state.userSetup; } @Override @@ -537,7 +546,9 @@ public class MobileSignalController extends SignalController< builder.append("isDefault=").append(isDefault).append(','); builder.append("isEmergency=").append(isEmergency).append(','); builder.append("airplaneMode=").append(airplaneMode).append(','); - builder.append("carrierNetworkChangeMode=").append(carrierNetworkChangeMode); + builder.append("carrierNetworkChangeMode=").append(carrierNetworkChangeMode) + .append(','); + builder.append("userSetup=").append(userSetup); } @Override @@ -550,6 +561,7 @@ public class MobileSignalController extends SignalController< && ((MobileState) o).isEmergency == isEmergency && ((MobileState) o).airplaneMode == airplaneMode && ((MobileState) o).carrierNetworkChangeMode == carrierNetworkChangeMode + && ((MobileState) o).userSetup == userSetup && ((MobileState) o).isDefault == isDefault; } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java index 40dacd3b991d..a63324134512 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java @@ -130,6 +130,7 @@ public class NetworkControllerImpl extends BroadcastReceiver @VisibleForTesting ServiceState mLastServiceState; + private boolean mUserSetup; /** * Construct this controller object and register for updates. @@ -490,6 +491,7 @@ public class NetworkControllerImpl extends BroadcastReceiver MobileSignalController controller = new MobileSignalController(mContext, mConfig, mHasMobileDataFeature, mPhone, mCallbackHandler, this, subscriptions.get(i), mSubDefaults, mReceiverHandler.getLooper()); + controller.setUserSetupComplete(mUserSetup); mMobileSignalControllers.put(subId, controller); if (subscriptions.get(i).getSimSlotIndex() == 0) { mDefaultSignalController = controller; @@ -516,6 +518,23 @@ public class NetworkControllerImpl extends BroadcastReceiver updateAirplaneMode(true /* force */); } + public void setUserSetupComplete(final boolean userSetup) { + mReceiverHandler.post(new Runnable() { + @Override + public void run() { + handleSetUserSetupComplete(userSetup); + } + }); + } + + @VisibleForTesting + void handleSetUserSetupComplete(boolean userSetup) { + mUserSetup = userSetup; + for (MobileSignalController controller : mMobileSignalControllers.values()) { + controller.setUserSetupComplete(mUserSetup); + } + } + @VisibleForTesting boolean hasCorrectMobileControllers(List<SubscriptionInfo> allSubscriptions) { if (allSubscriptions.size() != mMobileSignalControllers.size()) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java index 0fdd99fe7f58..a855aed88694 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java @@ -44,6 +44,8 @@ import android.widget.LinearLayout; import android.widget.ProgressBar; import android.widget.TextView; +import com.android.internal.logging.MetricsLogger; +import com.android.internal.logging.MetricsProto; import com.android.systemui.R; import com.android.systemui.statusbar.NotificationData; import com.android.systemui.statusbar.RemoteInputController; @@ -89,8 +91,6 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene mEditText.setOnEditorActionListener(new TextView.OnEditorActionListener() { @Override public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { - - // Check if this was the result of hitting the enter key final boolean isSoftImeEvent = event == null && (actionId == EditorInfo.IME_ACTION_DONE || actionId == EditorInfo.IME_ACTION_NEXT @@ -100,7 +100,10 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene && event.getAction() == KeyEvent.ACTION_DOWN; if (isSoftImeEvent || isKeyboardEnterKey) { - sendRemoteInput(); + if (mEditText.length() > 0) { + sendRemoteInput(); + } + // Consume action to prevent IME from closing. return true; } return false; @@ -127,10 +130,14 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene mEditText.mShowImeOnInputConnection = false; mController.remoteInputSent(mEntry); + MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_REMOTE_INPUT_SEND, + mEntry.notification.getPackageName()); try { mPendingIntent.send(mContext, 0, fillInIntent); } catch (PendingIntent.CanceledException e) { Log.i(TAG, "Unable to send remote input result", e); + MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_REMOTE_INPUT_FAIL, + mEntry.notification.getPackageName()); } } @@ -165,6 +172,8 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene mController.removeRemoteInput(mEntry); mEntry.remoteInputText = mEditText.getText(); setVisibility(INVISIBLE); + MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_REMOTE_INPUT_CLOSE, + mEntry.notification.getPackageName()); } @Override @@ -198,6 +207,9 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene } public void focus() { + MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_REMOTE_INPUT_OPEN, + mEntry.notification.getPackageName()); + setVisibility(VISIBLE); mController.addRemoteInput(mEntry); mEditText.setInnerFocusable(true); @@ -252,6 +264,7 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene findScrollContainer(); if (mScrollContainer != null) { mScrollContainer.requestDisallowLongPress(); + mScrollContainer.requestDisallowDismiss(); } } return super.onInterceptTouchEvent(ev); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java index c82ba3b16890..6800772b754f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java @@ -119,7 +119,7 @@ public class UserSwitcherController { filter.addAction(Intent.ACTION_USER_REMOVED); filter.addAction(Intent.ACTION_USER_INFO_CHANGED); filter.addAction(Intent.ACTION_USER_SWITCHED); - filter.addAction(Intent.ACTION_USER_STOPPING); + filter.addAction(Intent.ACTION_USER_STOPPED); filter.addAction(Intent.ACTION_USER_UNLOCKED); mContext.registerReceiverAsUser(mReceiver, UserHandle.SYSTEM, filter, null /* permission */, null /* scheduler */); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java index 9603e81c1e5d..0a4dce8b1f22 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java @@ -232,6 +232,7 @@ public class NotificationStackScrollLayout extends ViewGroup * animating. */ private boolean mOnlyScrollingInThisMotion; + private boolean mDisallowDismissInThisMotion; private boolean mInterceptDelegateEnabled; private boolean mDelegateToScrollView; private boolean mDisallowScrollingInThisMotion; @@ -1031,7 +1032,8 @@ public class NotificationStackScrollLayout extends ViewGroup if (!mIsBeingDragged && !mExpandingNotification && !mExpandedInThisMotion - && !mOnlyScrollingInThisMotion) { + && !mOnlyScrollingInThisMotion + && !mDisallowDismissInThisMotion) { horizontalSwipeWantsIt = mSwipeHelper.onTouchEvent(ev); } return horizontalSwipeWantsIt || scrollerWantsIt || expandWantsIt || super.onTouchEvent(ev); @@ -2013,7 +2015,8 @@ public class NotificationStackScrollLayout extends ViewGroup if (!mIsBeingDragged && !mExpandingNotification && !mExpandedInThisMotion - && !mOnlyScrollingInThisMotion) { + && !mOnlyScrollingInThisMotion + && !mDisallowDismissInThisMotion) { swipeWantsIt = mSwipeHelper.onInterceptTouchEvent(ev); } return swipeWantsIt || scrollWantsIt || expandWantsIt || super.onInterceptTouchEvent(ev); @@ -2041,6 +2044,7 @@ public class NotificationStackScrollLayout extends ViewGroup mExpandedInThisMotion = false; mOnlyScrollingInThisMotion = !mScroller.isFinished(); mDisallowScrollingInThisMotion = false; + mDisallowDismissInThisMotion = false; mTouchIsClick = true; mInitialTouchX = ev.getX(); mInitialTouchY = ev.getY(); @@ -2705,6 +2709,11 @@ public class NotificationStackScrollLayout extends ViewGroup removeLongPressCallback(); } + @Override + public void requestDisallowDismiss() { + mDisallowDismissInThisMotion = true; + } + public void removeLongPressCallback() { mSwipeHelper.removeLongPressCallback(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/ScrollContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/ScrollContainer.java index a35465e85075..64efa697de71 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/ScrollContainer.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/ScrollContainer.java @@ -33,4 +33,9 @@ public interface ScrollContainer { * Request that the view is made visible by scrolling to it. */ void scrollTo(View v); + + /** + * Request that the view does not dismiss for the current touch. + */ + void requestDisallowDismiss(); } diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipRecentsOverlayManager.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipRecentsOverlayManager.java index dd12360a0196..fe5d8bce1741 100644 --- a/packages/SystemUI/src/com/android/systemui/tv/pip/PipRecentsOverlayManager.java +++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipRecentsOverlayManager.java @@ -134,7 +134,8 @@ public class PipRecentsOverlayManager { */ public void requestFocus(boolean allowRecentsFocusable) { mRecentsView.setVisibility(allowRecentsFocusable ? View.VISIBLE : View.GONE); - if (!mIsPipRecentsOverlayShown || !mIsRecentsShown || mIsPipFocusedInRecent) { + if (!mIsPipRecentsOverlayShown || !mIsRecentsShown || mIsPipFocusedInRecent + || !mPipManager.isPipShown()) { return; } mIsPipFocusedInRecent = true; @@ -153,7 +154,8 @@ public class PipRecentsOverlayManager { * This should be called only by {@link com.android.systemui.recents.tv.RecentsTvActivity}. */ public void clearFocus() { - if (!mIsPipRecentsOverlayShown || !mIsRecentsShown || !mIsPipFocusedInRecent) { + if (!mIsPipRecentsOverlayShown || !mIsRecentsShown || !mIsPipFocusedInRecent + || !mPipManager.isPipShown()) { return; } if (!mRecentsView.hasFocus()) { diff --git a/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java b/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java index 2c53e2962049..36dd72793428 100644 --- a/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java +++ b/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java @@ -654,8 +654,9 @@ public class StorageNotification extends SystemUI { intent.putExtra(PackageManager.EXTRA_MOVE_ID, move.moveId); final VolumeInfo vol = mStorageManager.findVolumeByQualifiedUuid(move.volumeUuid); - intent.putExtra(VolumeInfo.EXTRA_VOLUME_ID, vol.getId()); - + if (vol != null) { + intent.putExtra(VolumeInfo.EXTRA_VOLUME_ID, vol.getId()); + } return PendingIntent.getActivityAsUser(mContext, move.moveId, intent, PendingIntent.FLAG_CANCEL_CURRENT, null, UserHandle.CURRENT); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java index 60d33fa0f191..38cac1e74031 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java @@ -111,6 +111,7 @@ public class NetworkControllerBaseTest extends SysuiTestCase { when(mMockTm.getDataEnabled(mSubId)).thenReturn(true); setDefaultSubId(mSubId); setSubscriptions(mSubId); + mNetworkController.handleSetUserSetupComplete(true); mMobileSignalController = mNetworkController.mMobileSignalControllers.get(mSubId); mPhoneStateListener = mMobileSignalController.mPhoneStateListener; } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java index d5eca95e2cbf..542c39021ee9 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java @@ -1,9 +1,9 @@ package com.android.systemui.statusbar.policy; +import android.net.NetworkCapabilities; import android.os.Looper; import android.telephony.TelephonyManager; import android.test.suitebuilder.annotation.SmallTest; - import com.android.settingslib.net.DataUsageController; import org.mockito.Mockito; @@ -99,6 +99,29 @@ public class NetworkControllerDataTest extends NetworkControllerBaseTest { TelephonyIcons.QS_DATA_4G); } + public void testDataDisabledIcon() { + setupNetworkController(); + Mockito.when(mMockTm.getDataEnabled(mSubId)).thenReturn(false); + setupDefaultSignal(); + updateDataConnectionState(TelephonyManager.DATA_DISCONNECTED, 0); + setConnectivity(NetworkCapabilities.TRANSPORT_CELLULAR, false, false); + + verifyDataIndicators(TelephonyIcons.ICON_DATA_DISABLED, + TelephonyIcons.QS_ICON_DATA_DISABLED); + } + + public void testDataDisabledIcon_UserNotSetup() { + setupNetworkController(); + Mockito.when(mMockTm.getDataEnabled(mSubId)).thenReturn(false); + setupDefaultSignal(); + updateDataConnectionState(TelephonyManager.DATA_DISCONNECTED, 0); + setConnectivity(NetworkCapabilities.TRANSPORT_CELLULAR, false, false); + mNetworkController.handleSetUserSetupComplete(false); + + // Don't show the X until the device is setup. + verifyDataIndicators(0, 0); + } + public void test4gDataIconConfigChange() { setupDefaultSignal(); updateDataConnectionState(TelephonyManager.DATA_CONNECTED, @@ -145,7 +168,6 @@ public class NetworkControllerDataTest extends NetworkControllerBaseTest { verifyLastMobileDataIndicators(true, DEFAULT_SIGNAL_STRENGTH, DEFAULT_ICON); verifyLastQsMobileDataIndicators(true, DEFAULT_QS_SIGNAL_STRENGTH, DEFAULT_QS_ICON, in, out); - } private void verifyDataIndicators(int dataIcon, int qsDataIcon) { diff --git a/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java b/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java index 2f79079c9188..a3ea592ebe5d 100644 --- a/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java +++ b/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java @@ -22,22 +22,28 @@ import android.app.backup.BackupDataInput; import android.app.backup.BackupDataOutput; import android.app.backup.FullBackupDataOutput; import android.content.Context; +import android.graphics.Rect; import android.os.Environment; import android.os.ParcelFileDescriptor; import android.os.UserHandle; import android.system.Os; import android.util.Slog; +import android.util.Xml; + +import org.xmlpull.v1.XmlPullParser; import java.io.File; +import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; +import java.nio.charset.StandardCharsets; public class WallpaperBackupAgent extends BackupAgent { private static final String TAG = "WallpaperBackup"; private static final boolean DEBUG = false; // NB: must be kept in sync with WallpaperManagerService but has no - // compile-time visiblity. + // compile-time visibility. // Target filenames within the system's wallpaper directory static final String WALLPAPER = "wallpaper_orig"; @@ -107,11 +113,7 @@ public class WallpaperBackupAgent extends BackupAgent { } // We use the default onRestoreFile() implementation that will recreate our stage files, - // then postprocess in onRestoreFinished() to move them on top of the live data. - // - // NOTE: this relies on our local files dir being on the same filesystem as the live - // system wallpaper data. If this is not the case then an actual copy operation will - // be needed. + // then post-process in onRestoreFinished() to apply the new wallpaper. @Override public void onRestoreFinished() { if (DEBUG) { @@ -125,19 +127,25 @@ public class WallpaperBackupAgent extends BackupAgent { // to back up the original image on the source device. if (imageStage.exists()) { if (DEBUG) { - Slog.v(TAG, "Got restored wallpaper; renaming into place"); + Slog.v(TAG, "Got restored wallpaper; applying"); + } + + // Parse the restored info file to find the crop hint. Note that this currently + // relies on a priori knowledge of the wallpaper info file schema. + Rect cropHint = parseCropHint(infoStage); + if (cropHint != null) { + if (DEBUG) { + Slog.v(TAG, "Restored crop hint " + cropHint + "; now writing data"); + } + WallpaperManager wm = getSystemService(WallpaperManager.class); + try (FileInputStream in = new FileInputStream(imageStage)) { + wm.setStream(in, cropHint, true, WallpaperManager.FLAG_SYSTEM); + } finally {} // auto-closes 'in' } - // Rename the image file into place last because that is the trigger for - // the wallpaper observer to generate a new crop/scale - Os.rename(infoStage.getCanonicalPath(), mWallpaperInfo.getCanonicalPath()); - Os.rename(imageStage.getCanonicalPath(), mWallpaperFile.getCanonicalPath()); } } catch (Exception e) { Slog.e(TAG, "Unable to restore wallpaper: " + e.getMessage()); - mWm.clearWallpaper(WallpaperManager.FLAG_SYSTEM, UserHandle.USER_SYSTEM); } finally { - // These "should" not exist because of the renames, but make sure - // in case of errors/exceptions/etc. if (DEBUG) { Slog.v(TAG, "Removing restore stage files"); } @@ -146,8 +154,41 @@ public class WallpaperBackupAgent extends BackupAgent { } } + private Rect parseCropHint(File wallpaperInfo) { + Rect cropHint = new Rect(); + try (FileInputStream stream = new FileInputStream(wallpaperInfo)) { + XmlPullParser parser = Xml.newPullParser(); + parser.setInput(stream, StandardCharsets.UTF_8.name()); + + int type; + do { + type = parser.next(); + if (type == XmlPullParser.START_TAG) { + String tag = parser.getName(); + if ("wp".equals(tag)) { + cropHint.left = getAttributeInt(parser, "cropLeft", 0); + cropHint.top = getAttributeInt(parser, "cropTop", 0); + cropHint.right = getAttributeInt(parser, "cropRight", 0); + cropHint.bottom = getAttributeInt(parser, "cropBottom", 0); + } + } + } while (type != XmlPullParser.END_DOCUMENT); + } catch (Exception e) { + // Whoops; can't process the info file at all. Report failure. + Slog.w(TAG, "Failed to parse restored metadata: " + e.getMessage()); + return null; + } + + return cropHint; + } + + private int getAttributeInt(XmlPullParser parser, String name, int defValue) { + final String value = parser.getAttributeValue(null, name); + return (value == null) ? defValue : Integer.parseInt(value); + } + // - // Key/value API: abstract, so required, but not used + // Key/value API: abstract, therefore required; but not used // @Override diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto index 7b3fd66f3236..c417fe8ae5cc 100644 --- a/proto/src/metrics_constants.proto +++ b/proto/src/metrics_constants.proto @@ -2169,6 +2169,28 @@ message MetricsEvent { // User blacklisted an app for Data Saver mode; action pass package name of app. ACTION_DATA_SAVER_BLACKLIST = 396; + // User opened a remote input view associated with a notification. Passes package name of app + // that posted the notification. Note that this can also happen transiently during notification + // reinflation. + ACTION_REMOTE_INPUT_OPEN = 397; + + // User attempt to send data through a remote input view associated with a notification. + // Passes package name of app that posted the notification. May succeed or fail. + ACTION_REMOTE_INPUT_SEND = 398; + + // Failed attempt to send data through a remote input view associated with a + // notification. Passes package name of app that posted the notification. + ACTION_REMOTE_INPUT_FAIL = 399; + + // User closed a remote input view associated with a notification. Passes package name of app + // that posted the notification. Note that this can also happen transiently during notification + // reinflation. + ACTION_REMOTE_INPUT_CLOSE = 400; + + // OPEN: Settings > Accounts > Work profile settings + // CATEGORY: SETTINGS + ACCOUNTS_WORK_PROFILE_SETTINGS = 401; + // Add new aosp constants above this line. // END OF AOSP CONSTANTS } diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java index fc2e95dc7ca5..ae314386bc7f 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java @@ -1245,8 +1245,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { private void updateServicesLocked(UserState userState) { Map<ComponentName, Service> componentNameToServiceMap = userState.mComponentNameToServiceMap; - boolean isUnlocked = mContext.getSystemService(UserManager.class) - .isUserUnlocked(userState.mUserId); + boolean isUnlockingOrUnlocked = mContext.getSystemService(UserManager.class) + .isUserUnlockingOrUnlocked(userState.mUserId); for (int i = 0, count = userState.mInstalledServices.size(); i < count; i++) { AccessibilityServiceInfo installedService = userState.mInstalledServices.get(i); @@ -1256,7 +1256,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { Service service = componentNameToServiceMap.get(componentName); // Ignore non-encryption-aware services until user is unlocked - if (!isUnlocked && !installedService.isDirectBootAware()) { + if (!isUnlockingOrUnlocked && !installedService.isDirectBootAware()) { Slog.d(LOG_TAG, "Ignoring non-encryption-aware service " + componentName); continue; } diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java index 0428ecfeb779..c62689c22b0d 100644 --- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java +++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java @@ -335,7 +335,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku Provider provider = installedProviders.get(i); final int userId = provider.getUserId(); - if (!mUserManager.isUserUnlocked(userId) || + if (!mUserManager.isUserUnlockingOrUnlocked(userId) || isProfileWithLockedParent(userId)) { continue; } @@ -369,7 +369,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku } private void onPackageBroadcastReceived(Intent intent, int userId) { - if (!mUserManager.isUserUnlocked(userId) || + if (!mUserManager.isUserUnlockingOrUnlocked(userId) || isProfileWithLockedParent(userId)) { return; } @@ -455,7 +455,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku * userId must be the group parent. */ private void reloadWidgetsMaskedStateForGroup(int userId) { - if (!mUserManager.isUserUnlocked(userId)) { + if (!mUserManager.isUserUnlockingOrUnlocked(userId)) { return; } synchronized (mLock) { @@ -472,7 +472,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku try { UserInfo user = mUserManager.getUserInfo(userId); - boolean lockedProfile = !mUserManager.isUserUnlocked(userId); + boolean lockedProfile = !mUserManager.isUserUnlockingOrUnlocked(userId); boolean quietProfile = user.isQuietModeEnabled(); final int N = mProviders.size(); for (int i = 0; i < N; i++) { @@ -656,11 +656,15 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku } private void ensureGroupStateLoadedLocked(int userId) { - if (!mUserManager.isUserUnlocked(userId)) { + ensureGroupStateLoadedLocked(userId, /* enforceUserUnlockingOrUnlocked */ true ); + } + + private void ensureGroupStateLoadedLocked(int userId, boolean enforceUserUnlockingOrUnlocked) { + if (enforceUserUnlockingOrUnlocked && !mUserManager.isUserUnlockingOrUnlocked(userId)) { throw new IllegalStateException( "User " + userId + " must be unlocked for widgets to be available"); } - if (isProfileWithLockedParent(userId)) { + if (enforceUserUnlockingOrUnlocked && isProfileWithLockedParent(userId)) { throw new IllegalStateException( "Profile " + userId + " must have unlocked parent"); } @@ -3363,7 +3367,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku if (userInfo != null && userInfo.isManagedProfile()) { UserInfo parentInfo = mUserManager.getProfileParent(userId); if (parentInfo != null - && !mUserManager.isUserUnlocked(parentInfo.getUserHandle())) { + && !mUserManager.isUserUnlockingOrUnlocked(parentInfo.getUserHandle())) { return true; } } @@ -3378,7 +3382,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku if (userInfo != null && userInfo.isManagedProfile()) { UserInfo parentInfo = mUserManager.getProfileParent(userId); if (parentInfo != null - && mUserManager.isUserUnlocked(parentInfo.getUserHandle())) { + && mUserManager.isUserUnlockingOrUnlocked(parentInfo.getUserHandle())) { return true; } } @@ -3945,7 +3949,9 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku @Override public void run() { synchronized (mLock) { - ensureGroupStateLoadedLocked(mUserId); + // No need to enforce unlocked state when there is no caller. User can be in the + // stopping state or removed by the time the message is processed + ensureGroupStateLoadedLocked(mUserId, false /* enforceUserUnlockingOrUnlocked */ ); saveStateLocked(mUserId); } } diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java index 6288b56d1f1d..1b63cd4958dc 100644 --- a/services/backup/java/com/android/server/backup/BackupManagerService.java +++ b/services/backup/java/com/android/server/backup/BackupManagerService.java @@ -3706,7 +3706,7 @@ public class BackupManagerService { result = BackupTransport.TRANSPORT_OK; } } catch (IOException e) { - Slog.e(TAG, "Error backing up " + mPkg.packageName, e); + Slog.e(TAG, "Error backing up " + mPkg.packageName + ": " + e.getMessage()); result = BackupTransport.AGENT_ERROR; } finally { try { @@ -4466,7 +4466,6 @@ public class BackupManagerService { } } - // If we've lost our running criteria, tell the transport to cancel // and roll back this (partial) backup payload; otherwise tell it // that we've reached the clean finish state. @@ -4484,14 +4483,16 @@ public class BackupManagerService { } } - // TRANSPORT_ERROR here means that we've hit an error that the runner - // doesn't know about, so it's still moving data but we're pulling the + // A transport-originated error here means that we've hit an error that the + // runner doesn't know about, so it's still moving data but we're pulling the // rug out from under it. Don't ask for its result: we already know better // and we'll hang if we block waiting for it, since it relies on us to // read back the data it's writing into the engine. Just proceed with // a graceful failure. The runner/engine mechanism will tear itself - // down cleanly when we close the pipes from this end. - if (backupPackageStatus != BackupTransport.TRANSPORT_ERROR) { + // down cleanly when we close the pipes from this end. Transport-level + // errors take precedence over agent/app-specific errors for purposes of + // determining our course of action. + if (backupPackageStatus == BackupTransport.TRANSPORT_OK) { // We still could fail in backup runner thread, getting result from there. int backupRunnerResult = backupRunner.getBackupResultBlocking(); if (backupRunnerResult != BackupTransport.TRANSPORT_OK) { @@ -4499,10 +4500,14 @@ public class BackupManagerService { // not TRANSPORT_ERROR here, overwrite it. backupPackageStatus = backupRunnerResult; } + } else { + if (MORE_DEBUG) { + Slog.i(TAG, "Transport-level failure; cancelling agent work"); + } } if (MORE_DEBUG) { - Slog.i(TAG, "Done trying to send backup data: result=" + Slog.i(TAG, "Done delivering backup data: result=" + backupPackageStatus); } @@ -7706,6 +7711,11 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF // when we're finished. private int mPmToken; + // When this is restore-during-install, we need to tell the package manager + // whether we actually launched the app, because this affects notifications + // around externally-visible state transitions. + private boolean mDidLaunch; + // Is this a whole-system restore, i.e. are we establishing a new ancestral // dataset to base future restore-at-install operations from? private boolean mIsSystemRestore; @@ -7769,6 +7779,7 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF mTargetPackage = targetPackage; mIsSystemRestore = isFullSystemRestore; mFinished = false; + mDidLaunch = false; if (targetPackage != null) { // Single package restore @@ -8149,6 +8160,9 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF return; } + // Whatever happens next, we've launched the target app now; remember that. + mDidLaunch = true; + // And then finally start the restore on this agent try { initiateOneRestore(mCurrentPackage, metaInfo.versionCode); @@ -8430,6 +8444,10 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF // Now we're really done with this one too IoUtils.closeQuietly(mEnginePipes[0]); + // In all cases we want to remember whether we launched + // the target app as part of our work so far. + mDidLaunch = (mEngine.getAgent() != null); + // If we hit a transport-level error, we are done with everything; // if we hit an agent error we just go back to running the queue. if (status == BackupTransport.TRANSPORT_OK) { @@ -8522,7 +8540,7 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF if (mPmToken > 0) { if (MORE_DEBUG) Slog.v(TAG, "finishing PM token " + mPmToken); try { - mPackageManagerBinder.finishPackageInstall(mPmToken); + mPackageManagerBinder.finishPackageInstall(mPmToken, mDidLaunch); } catch (RemoteException e) { /* can't happen */ } } else { // We were invoked via an active restore session, not by the Package @@ -9682,7 +9700,7 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF // Manager to proceed with the post-install handling for this package. if (DEBUG) Slog.v(TAG, "Finishing install immediately"); try { - mPackageManagerBinder.finishPackageInstall(token); + mPackageManagerBinder.finishPackageInstall(token, false); } catch (RemoteException e) { /* can't happen */ } } } diff --git a/services/core/java/com/android/server/BatteryService.java b/services/core/java/com/android/server/BatteryService.java index 87539921be78..6b517210ef31 100644 --- a/services/core/java/com/android/server/BatteryService.java +++ b/services/core/java/com/android/server/BatteryService.java @@ -358,7 +358,7 @@ public final class BatteryService extends SystemService { try { mBatteryStats.setBatteryState(mBatteryProps.batteryStatus, mBatteryProps.batteryHealth, mPlugType, mBatteryProps.batteryLevel, mBatteryProps.batteryTemperature, - mBatteryProps.batteryVoltage); + mBatteryProps.batteryVoltage, mBatteryProps.batteryChargeCounter); } catch (RemoteException e) { // Should never happen. } diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 0287332bb5a4..00dcdeae3a27 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -29,8 +29,12 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED; import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED; import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL; +import static android.net.NetworkPolicyManager.RULE_ALLOW_METERED; import static android.net.NetworkPolicyManager.RULE_REJECT_ALL; import static android.net.NetworkPolicyManager.RULE_REJECT_METERED; +import static android.net.NetworkPolicyManager.RULE_TEMPORARY_ALLOW_METERED; +import static android.net.NetworkPolicyManager.RULE_UNKNOWN; + import android.annotation.Nullable; import android.app.BroadcastOptions; import android.app.Notification; @@ -96,8 +100,10 @@ import android.security.Credentials; import android.security.KeyStore; import android.telephony.TelephonyManager; import android.text.TextUtils; +import android.util.ArraySet; import android.util.LocalLog; import android.util.LocalLog.ReadOnlyLocalLog; +import android.util.Log; import android.util.Pair; import android.util.Slog; import android.util.SparseArray; @@ -121,9 +127,9 @@ import com.android.internal.util.XmlUtils; import com.android.server.am.BatteryStatsService; import com.android.server.connectivity.DataConnectionStats; import com.android.server.connectivity.KeepaliveTracker; -import com.android.server.connectivity.NetworkDiagnostics; import com.android.server.connectivity.Nat464Xlat; import com.android.server.connectivity.NetworkAgentInfo; +import com.android.server.connectivity.NetworkDiagnostics; import com.android.server.connectivity.NetworkMonitor; import com.android.server.connectivity.PacManager; import com.android.server.connectivity.PermissionMonitor; @@ -131,8 +137,8 @@ import com.android.server.connectivity.Tethering; import com.android.server.connectivity.Vpn; import com.android.server.net.BaseNetworkObserver; import com.android.server.net.LockdownVpnTracker; + import com.google.android.collect.Lists; -import com.google.android.collect.Sets; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; @@ -152,11 +158,11 @@ import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; -import java.util.SortedSet; -import java.util.TreeSet; import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.SortedSet; +import java.util.TreeSet; /** * @hide @@ -202,9 +208,14 @@ public class ConnectivityService extends IConnectivityManager.Stub /** Lock around {@link #mUidRules} and {@link #mMeteredIfaces}. */ private Object mRulesLock = new Object(); /** Currently active network rules by UID. */ + @GuardedBy("mRulesLock") private SparseIntArray mUidRules = new SparseIntArray(); /** Set of ifaces that are costly. */ - private HashSet<String> mMeteredIfaces = Sets.newHashSet(); + @GuardedBy("mRulesLock") + private ArraySet<String> mMeteredIfaces = new ArraySet<>(); + /** Flag indicating if background data is restricted. */ + @GuardedBy("mRulesLock") + private boolean mRestrictBackground; final private Context mContext; private int mNetworkPreference; @@ -651,7 +662,8 @@ public class ConnectivityService extends IConnectivityManager.Stub mTelephonyManager = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE); try { - mPolicyManager.registerListener(mPolicyListener); + mPolicyManager.setConnectivityListener(mPolicyListener); + mRestrictBackground = mPolicyManager.getRestrictBackground(); } catch (RemoteException e) { // ouch, no rules updates means some processes may never get network loge("unable to register INetworkPolicyListener" + e.toString()); @@ -730,7 +742,7 @@ public class ConnectivityService extends IConnectivityManager.Stub //set up the listener for user state for creating user VPNs IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(Intent.ACTION_USER_STARTING); - intentFilter.addAction(Intent.ACTION_USER_STOPPING); + intentFilter.addAction(Intent.ACTION_USER_STOPPED); intentFilter.addAction(Intent.ACTION_USER_ADDED); intentFilter.addAction(Intent.ACTION_USER_REMOVED); intentFilter.addAction(Intent.ACTION_USER_UNLOCKED); @@ -819,7 +831,7 @@ public class ConnectivityService extends IConnectivityManager.Stub throw new IllegalStateException("No free netIds"); } - private NetworkState getFilteredNetworkState(int networkType, int uid) { + private NetworkState getFilteredNetworkState(int networkType, int uid, boolean ignoreBlocked) { if (mLegacyTypeTracker.isTypeSupported(networkType)) { final NetworkAgentInfo nai = mLegacyTypeTracker.getNetworkForType(networkType); final NetworkState state; @@ -834,7 +846,7 @@ public class ConnectivityService extends IConnectivityManager.Stub state = new NetworkState(info, new LinkProperties(), new NetworkCapabilities(), null, null, null); } - filterNetworkStateForUid(state, uid); + filterNetworkStateForUid(state, uid, ignoreBlocked); return state; } else { return NetworkState.EMPTY; @@ -890,22 +902,36 @@ public class ConnectivityService extends IConnectivityManager.Stub /** * Check if UID should be blocked from using the network with the given LinkProperties. */ - private boolean isNetworkWithLinkPropertiesBlocked(LinkProperties lp, int uid) { - final boolean networkCostly; + private boolean isNetworkWithLinkPropertiesBlocked(LinkProperties lp, int uid, + boolean ignoreBlocked) { + // Networks aren't blocked when ignoring blocked status + if (ignoreBlocked) return false; + // Networks are never blocked for system services + if (uid < Process.FIRST_APPLICATION_UID) return false; + + final boolean networkMetered; final int uidRules; final String iface = (lp == null ? "" : lp.getInterfaceName()); synchronized (mRulesLock) { - networkCostly = mMeteredIfaces.contains(iface); - uidRules = mUidRules.get(uid, RULE_ALLOW_ALL); + networkMetered = mMeteredIfaces.contains(iface); + uidRules = mUidRules.get(uid, RULE_UNKNOWN); } - if (uidRules == RULE_REJECT_ALL) { - return true; - } else if ((uidRules == RULE_REJECT_METERED) && networkCostly) { - return true; - } else { - return false; + switch (uidRules) { + case RULE_ALLOW_ALL: + case RULE_ALLOW_METERED: + case RULE_TEMPORARY_ALLOW_METERED: + return false; + case RULE_REJECT_METERED: + return networkMetered; + case RULE_REJECT_ALL: + return true; + case RULE_UNKNOWN: + default: + // When background data is restricted device-wide, the default + // behavior for apps should be like RULE_REJECT_METERED + return mRestrictBackground ? networkMetered : false; } } @@ -930,10 +956,10 @@ public class ConnectivityService extends IConnectivityManager.Stub * on {@link #isNetworkWithLinkPropertiesBlocked}, or * {@link NetworkInfo#isMetered()} based on network policies. */ - private void filterNetworkStateForUid(NetworkState state, int uid) { + private void filterNetworkStateForUid(NetworkState state, int uid, boolean ignoreBlocked) { if (state == null || state.networkInfo == null || state.linkProperties == null) return; - if (isNetworkWithLinkPropertiesBlocked(state.linkProperties, uid)) { + if (isNetworkWithLinkPropertiesBlocked(state.linkProperties, uid, ignoreBlocked)) { state.networkInfo.setDetailedState(DetailedState.BLOCKED, null, null); } if (mLockdownTracker != null) { @@ -962,7 +988,7 @@ public class ConnectivityService extends IConnectivityManager.Stub enforceAccessPermission(); final int uid = Binder.getCallingUid(); final NetworkState state = getUnfilteredActiveNetworkState(uid); - filterNetworkStateForUid(state, uid); + filterNetworkStateForUid(state, uid, false); maybeLogBlockedNetworkInfo(state.networkInfo, uid); return state.networkInfo; } @@ -970,16 +996,16 @@ public class ConnectivityService extends IConnectivityManager.Stub @Override public Network getActiveNetwork() { enforceAccessPermission(); - return getActiveNetworkForUidInternal(Binder.getCallingUid()); + return getActiveNetworkForUidInternal(Binder.getCallingUid(), false); } @Override - public Network getActiveNetworkForUid(int uid) { + public Network getActiveNetworkForUid(int uid, boolean ignoreBlocked) { enforceConnectivityInternalPermission(); - return getActiveNetworkForUidInternal(uid); + return getActiveNetworkForUidInternal(uid, ignoreBlocked); } - private Network getActiveNetworkForUidInternal(final int uid) { + private Network getActiveNetworkForUidInternal(final int uid, boolean ignoreBlocked) { final int user = UserHandle.getUserId(uid); int vpnNetId = NETID_UNSET; synchronized (mVpns) { @@ -994,7 +1020,10 @@ public class ConnectivityService extends IConnectivityManager.Stub if (nai != null) return nai.network; } nai = getDefaultNetwork(); - if (nai != null && isNetworkWithLinkPropertiesBlocked(nai.linkProperties, uid)) nai = null; + if (nai != null + && isNetworkWithLinkPropertiesBlocked(nai.linkProperties, uid, ignoreBlocked)) { + nai = null; + } return nai != null ? nai.network : null; } @@ -1006,10 +1035,10 @@ public class ConnectivityService extends IConnectivityManager.Stub } @Override - public NetworkInfo getActiveNetworkInfoForUid(int uid) { + public NetworkInfo getActiveNetworkInfoForUid(int uid, boolean ignoreBlocked) { enforceConnectivityInternalPermission(); final NetworkState state = getUnfilteredActiveNetworkState(uid); - filterNetworkStateForUid(state, uid); + filterNetworkStateForUid(state, uid, ignoreBlocked); return state.networkInfo; } @@ -1023,22 +1052,21 @@ public class ConnectivityService extends IConnectivityManager.Stub // getUnfilteredActiveNetworkState. final NetworkState state = getUnfilteredActiveNetworkState(uid); if (state.networkInfo != null && state.networkInfo.getType() == networkType) { - filterNetworkStateForUid(state, uid); + filterNetworkStateForUid(state, uid, false); return state.networkInfo; } } - final NetworkState state = getFilteredNetworkState(networkType, uid); + final NetworkState state = getFilteredNetworkState(networkType, uid, false); return state.networkInfo; } @Override - public NetworkInfo getNetworkInfoForNetwork(Network network) { + public NetworkInfo getNetworkInfoForUid(Network network, int uid, boolean ignoreBlocked) { enforceAccessPermission(); - final int uid = Binder.getCallingUid(); final NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network); if (nai != null) { final NetworkState state = nai.getNetworkState(); - filterNetworkStateForUid(state, uid); + filterNetworkStateForUid(state, uid, ignoreBlocked); return state.networkInfo; } else { return null; @@ -1063,8 +1091,8 @@ public class ConnectivityService extends IConnectivityManager.Stub public Network getNetworkForType(int networkType) { enforceAccessPermission(); final int uid = Binder.getCallingUid(); - NetworkState state = getFilteredNetworkState(networkType, uid); - if (!isNetworkWithLinkPropertiesBlocked(state.linkProperties, uid)) { + NetworkState state = getFilteredNetworkState(networkType, uid, false); + if (!isNetworkWithLinkPropertiesBlocked(state.linkProperties, uid, false)) { return state.network; } return null; @@ -1381,6 +1409,11 @@ public class ConnectivityService extends IConnectivityManager.Stub if (LOGD_RULES) { log("onRestrictBackgroundChanged(restrictBackground=" + restrictBackground + ")"); } + + synchronized (mRulesLock) { + mRestrictBackground = restrictBackground; + } + if (restrictBackground) { log("onRestrictBackgroundChanged(true): disabling tethering"); mTethering.untetherAll(); @@ -1824,6 +1857,10 @@ public class ConnectivityService extends IConnectivityManager.Stub pw.decreaseIndent(); pw.println(); + pw.print("Restrict background: "); + pw.println(mRestrictBackground); + pw.println(); + pw.println("Network Requests:"); pw.increaseIndent(); for (NetworkRequestInfo nri : mNetworkRequests.values()) { @@ -2765,7 +2802,7 @@ public class ConnectivityService extends IConnectivityManager.Stub // which isn't meant to work on uncreated networks. if (!nai.created) return; - if (isNetworkWithLinkPropertiesBlocked(nai.linkProperties, uid)) return; + if (isNetworkWithLinkPropertiesBlocked(nai.linkProperties, uid, false)) return; nai.networkMonitor.sendMessage(NetworkMonitor.CMD_FORCE_REEVALUATION, uid); } @@ -3619,7 +3656,7 @@ public class ConnectivityService extends IConnectivityManager.Stub synchronized(mVpns) { Vpn userVpn = mVpns.get(userId); if (userVpn == null) { - loge("Stopping user has no VPN"); + loge("Stopped user has no VPN"); return; } mVpns.delete(userId); @@ -3664,7 +3701,7 @@ public class ConnectivityService extends IConnectivityManager.Stub if (Intent.ACTION_USER_STARTING.equals(action)) { onUserStart(userId); - } else if (Intent.ACTION_USER_STOPPING.equals(action)) { + } else if (Intent.ACTION_USER_STOPPED.equals(action)) { onUserStop(userId); } else if (Intent.ACTION_USER_ADDED.equals(action)) { onUserAdded(userId); @@ -4280,10 +4317,10 @@ public class ConnectivityService extends IConnectivityManager.Stub Collection<InetAddress> dnses = newLp.getDnsServers(); if (DBG) log("Setting DNS servers for network " + netId + " to " + dnses); try { - mNetd.setDnsServersForNetwork( + mNetd.setDnsConfigurationForNetwork( netId, NetworkUtils.makeStrings(dnses), newLp.getDomains()); } catch (Exception e) { - loge("Exception in setDnsServersForNetwork: " + e); + loge("Exception in setDnsConfigurationForNetwork: " + e); } final NetworkAgentInfo defaultNai = getDefaultNetwork(); if (defaultNai != null && defaultNai.network.netId == netId) { diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java index 79d16da00ee7..a584f707f9a9 100644 --- a/services/core/java/com/android/server/InputMethodManagerService.java +++ b/services/core/java/com/android/server/InputMethodManagerService.java @@ -1020,7 +1020,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub // If the system is not ready or the device is not yed unlocked by the user, then we use // copy-on-write settings. final boolean useCopyOnWriteSettings = - !mSystemReady || !mUserManager.isUserUnlocked(newUserId); + !mSystemReady || !mUserManager.isUserUnlockingOrUnlocked(newUserId); mSettings.switchCurrentUser(newUserId, useCopyOnWriteSettings); updateCurrentProfileIds(); // InputMethodFileManager should be reset when the user is changed @@ -1077,7 +1077,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub mSystemReady = true; final int currentUserId = mSettings.getCurrentUserId(); mSettings.switchCurrentUser(currentUserId, - !mUserManager.isUserUnlocked(currentUserId)); + !mUserManager.isUserUnlockingOrUnlocked(currentUserId)); mKeyguardManager = mContext.getSystemService(KeyguardManager.class); mNotificationManager = mContext.getSystemService(NotificationManager.class); mStatusBar = statusBar; diff --git a/services/core/java/com/android/server/LockSettingsService.java b/services/core/java/com/android/server/LockSettingsService.java index a3ef6b6b53fa..cbf7e8038b5b 100644 --- a/services/core/java/com/android/server/LockSettingsService.java +++ b/services/core/java/com/android/server/LockSettingsService.java @@ -256,13 +256,13 @@ public class LockSettingsService extends ILockSettings.Stub { for (int i = 0; i < users.size(); i++) { UserInfo user = users.get(i); UserHandle userHandle = user.getUserHandle(); - if (!mUserManager.isUserUnlocked(userHandle)) { + if (!mUserManager.isUserUnlockingOrUnlocked(userHandle)) { if (!user.isManagedProfile()) { showEncryptionNotification(userHandle); } else { UserInfo parent = mUserManager.getProfileParent(user.id); if (parent != null && - mUserManager.isUserUnlocked(parent.getUserHandle()) && + mUserManager.isUserUnlockingOrUnlocked(parent.getUserHandle()) && !mUserManager.isQuietModeEnabled(userHandle)) { // Only show notifications for managed profiles once their parent // user is unlocked. @@ -350,7 +350,7 @@ public class LockSettingsService extends ILockSettings.Stub { UserInfo profile = profiles.get(i); if (profile.isManagedProfile()) { UserHandle userHandle = profile.getUserHandle(); - if (!mUserManager.isUserUnlocked(userHandle) && + if (!mUserManager.isUserUnlockingOrUnlocked(userHandle) && !mUserManager.isQuietModeEnabled(userHandle)) { showEncryptionNotificationForProfile(userHandle); } @@ -1281,8 +1281,14 @@ public class LockSettingsService extends ILockSettings.Stub { // service can't connect to vold, it restarts, and then the new instance // does successfully connect. final IMountService service = getMountService(); - String password = service.getPassword(); - service.clearPassword(); + String password; + long identity = Binder.clearCallingIdentity(); + try { + password = service.getPassword(); + service.clearPassword(); + } finally { + Binder.restoreCallingIdentity(identity); + } if (password == null) { return false; } diff --git a/services/core/java/com/android/server/MountService.java b/services/core/java/com/android/server/MountService.java index ec05dae68a85..7253870d2f12 100644 --- a/services/core/java/com/android/server/MountService.java +++ b/services/core/java/com/android/server/MountService.java @@ -2648,6 +2648,8 @@ class MountService extends IMountService.Stub */ @Override public int getPasswordType() { + mContext.enforceCallingOrSelfPermission(Manifest.permission.STORAGE_INTERNAL, + "no permission to access the crypt keeper"); waitForReady(); @@ -2672,6 +2674,8 @@ class MountService extends IMountService.Stub */ @Override public void setField(String field, String contents) throws RemoteException { + mContext.enforceCallingOrSelfPermission(Manifest.permission.STORAGE_INTERNAL, + "no permission to access the crypt keeper"); waitForReady(); @@ -2690,6 +2694,8 @@ class MountService extends IMountService.Stub */ @Override public String getField(String field) throws RemoteException { + mContext.enforceCallingOrSelfPermission(Manifest.permission.STORAGE_INTERNAL, + "no permission to access the crypt keeper"); waitForReady(); @@ -2714,6 +2720,8 @@ class MountService extends IMountService.Stub */ @Override public boolean isConvertibleToFBE() throws RemoteException { + mContext.enforceCallingOrSelfPermission(Manifest.permission.STORAGE_INTERNAL, + "no permission to access the crypt keeper"); waitForReady(); @@ -2728,8 +2736,9 @@ class MountService extends IMountService.Stub @Override public String getPassword() throws RemoteException { - mContext.enforceCallingOrSelfPermission(Manifest.permission.ACCESS_KEYGUARD_SECURE_STORAGE, + mContext.enforceCallingOrSelfPermission(Manifest.permission.STORAGE_INTERNAL, "only keyguard can retrieve password"); + if (!isReady()) { return new String(); } @@ -2752,6 +2761,9 @@ class MountService extends IMountService.Stub @Override public void clearPassword() throws RemoteException { + mContext.enforceCallingOrSelfPermission(Manifest.permission.STORAGE_INTERNAL, + "only keyguard can clear password"); + if (!isReady()) { return; } @@ -2816,17 +2828,19 @@ class MountService extends IMountService.Stub enforcePermission(android.Manifest.permission.STORAGE_INTERNAL); waitForReady(); - // When a user has secure lock screen, require a challenge token to - // actually unlock. This check is mostly in place for emulation mode. - if (mLockPatternUtils.isSecure(userId) && ArrayUtils.isEmpty(token)) { - throw new IllegalStateException("Token required to unlock secure user " + userId); - } + if (StorageManager.isFileEncryptedNativeOrEmulated()) { + // When a user has secure lock screen, require a challenge token to + // actually unlock. This check is mostly in place for emulation mode. + if (mLockPatternUtils.isSecure(userId) && ArrayUtils.isEmpty(token)) { + throw new IllegalStateException("Token required to unlock secure user " + userId); + } - try { - mCryptConnector.execute("cryptfs", "unlock_user_key", userId, serialNumber, - encodeBytes(token), encodeBytes(secret)); - } catch (NativeDaemonConnectorException e) { - throw e.rethrowAsParcelableException(); + try { + mCryptConnector.execute("cryptfs", "unlock_user_key", userId, serialNumber, + encodeBytes(token), encodeBytes(secret)); + } catch (NativeDaemonConnectorException e) { + throw e.rethrowAsParcelableException(); + } } synchronized (mLock) { @@ -2852,12 +2866,8 @@ class MountService extends IMountService.Stub @Override public boolean isUserKeyUnlocked(int userId) { - if (StorageManager.isFileEncryptedNativeOrEmulated()) { - synchronized (mLock) { - return ArrayUtils.contains(mLocalUnlockedUsers, userId); - } - } else { - return true; + synchronized (mLock) { + return ArrayUtils.contains(mLocalUnlockedUsers, userId); } } diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java index 9fc17a2a3a29..2418160255f8 100644 --- a/services/core/java/com/android/server/NetworkManagementService.java +++ b/services/core/java/com/android/server/NetworkManagementService.java @@ -47,6 +47,7 @@ import static com.android.server.NetworkManagementService.NetdResponseCode.TtyLi import static com.android.server.NetworkManagementSocketTagger.PROP_QTAGUID_ENABLED; import android.annotation.NonNull; import android.app.ActivityManagerNative; +import android.content.ContentResolver; import android.content.Context; import android.net.ConnectivityManager; import android.net.INetd; @@ -76,6 +77,7 @@ import android.os.ServiceSpecificException; import android.os.StrictMode; import android.os.SystemClock; import android.os.SystemProperties; +import android.provider.Settings; import android.telephony.DataConnectionRealTimeInfo; import android.telephony.PhoneStateListener; import android.telephony.SubscriptionManager; @@ -175,6 +177,12 @@ public class NetworkManagementService extends INetworkManagementService.Stub public static final int StrictCleartext = 617; } + /* Defaults for resolver parameters. */ + public static final int DNS_RESOLVER_DEFAULT_SAMPLE_VALIDITY_SECONDS = 1800; + public static final int DNS_RESOLVER_DEFAULT_SUCCESS_THRESHOLD_PERCENT = 25; + public static final int DNS_RESOLVER_DEFAULT_MIN_SAMPLES = 8; + public static final int DNS_RESOLVER_DEFAULT_MAX_SAMPLES = 64; + /** * String indicating a softap command. */ @@ -1927,6 +1935,51 @@ public class NetworkManagementService extends INetworkManagementService.Stub } @Override + public void setDnsConfigurationForNetwork(int netId, String[] servers, String domains) { + mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); + + ContentResolver resolver = mContext.getContentResolver(); + + int sampleValidity = Settings.Global.getInt(resolver, + Settings.Global.DNS_RESOLVER_SAMPLE_VALIDITY_SECONDS, + DNS_RESOLVER_DEFAULT_SAMPLE_VALIDITY_SECONDS); + if (sampleValidity < 0 || sampleValidity > 65535) { + Slog.w(TAG, "Invalid sampleValidity=" + sampleValidity + ", using default=" + + DNS_RESOLVER_DEFAULT_SAMPLE_VALIDITY_SECONDS); + sampleValidity = DNS_RESOLVER_DEFAULT_SAMPLE_VALIDITY_SECONDS; + } + + int successThreshold = Settings.Global.getInt(resolver, + Settings.Global.DNS_RESOLVER_SUCCESS_THRESHOLD_PERCENT, + DNS_RESOLVER_DEFAULT_SUCCESS_THRESHOLD_PERCENT); + if (successThreshold < 0 || successThreshold > 100) { + Slog.w(TAG, "Invalid successThreshold=" + successThreshold + ", using default=" + + DNS_RESOLVER_DEFAULT_SUCCESS_THRESHOLD_PERCENT); + successThreshold = DNS_RESOLVER_DEFAULT_SUCCESS_THRESHOLD_PERCENT; + } + + int minSamples = Settings.Global.getInt(resolver, + Settings.Global.DNS_RESOLVER_MIN_SAMPLES, DNS_RESOLVER_DEFAULT_MIN_SAMPLES); + int maxSamples = Settings.Global.getInt(resolver, + Settings.Global.DNS_RESOLVER_MAX_SAMPLES, DNS_RESOLVER_DEFAULT_MAX_SAMPLES); + if (minSamples < 0 || minSamples > maxSamples || maxSamples > 64) { + Slog.w(TAG, "Invalid sample count (min, max)=(" + minSamples + ", " + maxSamples + + "), using default=(" + DNS_RESOLVER_DEFAULT_MIN_SAMPLES + ", " + + DNS_RESOLVER_DEFAULT_MAX_SAMPLES + ")"); + minSamples = DNS_RESOLVER_DEFAULT_MIN_SAMPLES; + maxSamples = DNS_RESOLVER_DEFAULT_MAX_SAMPLES; + } + + final String[] domainStrs = domains == null ? new String[0] : domains.split(" "); + final int[] params = { sampleValidity, successThreshold, minSamples, maxSamples }; + try { + mNetdService.setResolverConfiguration(netId, servers, domainStrs, params); + } catch (RemoteException e) { + throw new RuntimeException(e); + } + } + + @Override public void setDnsServersForNetwork(int netId, String[] servers, String domains) { mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); @@ -2048,13 +2101,13 @@ public class NetworkManagementService extends INetworkManagementService.Stub } } - private void closeSocketsForFirewallChain(int chain, String chainName) { + private void closeSocketsForFirewallChainLocked(int chain, String chainName) { // UID ranges to close sockets on. UidRange[] ranges; // UID ranges whose sockets we won't touch. int[] exemptUids; - SparseIntArray rules = getUidFirewallRules(chain); + final SparseIntArray rules = getUidFirewallRules(chain); int numUids = 0; if (getFirewallType(chain) == FIREWALL_TYPE_WHITELIST) { @@ -2119,7 +2172,7 @@ public class NetworkManagementService extends INetworkManagementService.Stub mFirewallChainStates.put(chain, enable); final String operation = enable ? "enable_chain" : "disable_chain"; - String chainName; + final String chainName; switch(chain) { case FIREWALL_CHAIN_STANDBY: chainName = FIREWALL_CHAIN_NAME_STANDBY; @@ -2146,7 +2199,7 @@ public class NetworkManagementService extends INetworkManagementService.Stub // whitelist and blacklist chains allow RSTs through. if (enable) { if (DBG) Slog.d(TAG, "Closing sockets after enabling chain " + chainName); - closeSocketsForFirewallChain(chain, chainName); + closeSocketsForFirewallChainLocked(chain, chainName); } } } diff --git a/services/core/java/com/android/server/TextServicesManagerService.java b/services/core/java/com/android/server/TextServicesManagerService.java index a62874779c04..4b0d4be11b14 100644 --- a/services/core/java/com/android/server/TextServicesManagerService.java +++ b/services/core/java/com/android/server/TextServicesManagerService.java @@ -166,7 +166,7 @@ public class TextServicesManagerService extends ITextServicesManager.Stub { mMonitor = new TextServicesMonitor(); mMonitor.register(context, null, true); final boolean useCopyOnWriteSettings = - !mSystemReady || !mUserManager.isUserUnlocked(userId); + !mSystemReady || !mUserManager.isUserUnlockingOrUnlocked(userId); mSettings = new TextServicesSettings(context.getContentResolver(), userId, useCopyOnWriteSettings); @@ -176,7 +176,7 @@ public class TextServicesManagerService extends ITextServicesManager.Stub { private void resetInternalState(@UserIdInt int userId) { final boolean useCopyOnWriteSettings = - !mSystemReady || !mUserManager.isUserUnlocked(userId); + !mSystemReady || !mUserManager.isUserUnlockingOrUnlocked(userId); mSettings.switchCurrentUser(userId, useCopyOnWriteSettings); updateCurrentProfileIds(); unbindServiceLocked(); diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java index 480da72d9579..98b3b088399a 100644 --- a/services/core/java/com/android/server/accounts/AccountManagerService.java +++ b/services/core/java/com/android/server/accounts/AccountManagerService.java @@ -304,7 +304,7 @@ public class AccountManagerService } private final SparseArray<UserAccounts> mUsers = new SparseArray<>(); - private final SparseBooleanArray mUnlockedUsers = new SparseBooleanArray(); + private final SparseBooleanArray mLocalUnlockedUsers = new SparseBooleanArray(); private static AtomicReference<AccountManagerService> sThis = new AtomicReference<>(); private static final Account[] EMPTY_ACCOUNT_ARRAY = new Account[]{}; @@ -409,7 +409,6 @@ public class AccountManagerService */ public void validateAccounts(int userId) { final UserAccounts accounts = getUserAccounts(userId); - // Invalidate user-specific cache to make sure we catch any // removed authenticators. validateAccountsInternal(accounts, true /* invalidateAuthenticatorCache */); @@ -424,17 +423,15 @@ public class AccountManagerService if (Log.isLoggable(TAG, Log.DEBUG)) { Log.d(TAG, "validateAccountsInternal " + accounts.userId + " isCeDatabaseAttached=" + accounts.openHelper.isCeDatabaseAttached() - + " userLocked=" + mUnlockedUsers.get(accounts.userId)); + + " userLocked=" + mLocalUnlockedUsers.get(accounts.userId)); } + if (invalidateAuthenticatorCache) { mAuthenticatorCache.invalidateCache(accounts.userId); } - final HashMap<String, Integer> knownAuth = new HashMap<>(); - for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> service : - mAuthenticatorCache.getAllServices(accounts.userId)) { - knownAuth.put(service.type.type, service.uid); - } + final HashMap<String, Integer> knownAuth = getAuthenticatorTypeAndUIDForUser( + mAuthenticatorCache, accounts.userId); synchronized (accounts.cacheLock) { final SQLiteDatabase db = accounts.openHelper.getWritableDatabase(); @@ -452,6 +449,7 @@ public class AccountManagerService // Create a list of authenticator type whose previous uid no longer exists HashSet<String> obsoleteAuthType = Sets.newHashSet(); try { + SparseBooleanArray knownUids = null; while (metaCursor.moveToNext()) { String type = TextUtils.split(metaCursor.getString(0), META_KEY_DELIMITER)[1]; String uid = metaCursor.getString(1); @@ -466,23 +464,48 @@ public class AccountManagerService // Remove it from the knownAuth list if it's unchanged. knownAuth.remove(type); } else { - // Only add it to the list if it no longer exists or uid different - obsoleteAuthType.add(type); - // And delete it from the TABLE_META - db.delete( - TABLE_META, - META_KEY + "=? AND " + META_VALUE + "=?", - new String[] { - META_KEY_FOR_AUTHENTICATOR_UID_FOR_TYPE_PREFIX + type, - uid} - ); + /* + * The authenticator is presently not cached and should only be triggered + * when we think an authenticator has been removed (or is being updated). + * But we still want to check if any data with the associated uid is + * around. This is an (imperfect) signal that the package may be updating. + * + * A side effect of this is that an authenticator sharing a uid with + * multiple apps won't get its credentials wiped as long as some app with + * that uid is still on the device. But I suspect that this is a rare case. + * And it isn't clear to me how an attacker could really exploit that + * feature. + * + * The upshot is that we don't have to worry about accounts getting + * uninstalled while the authenticator's package is being updated. + * + */ + if (knownUids == null) { + knownUids = getUidsOfInstalledOrUpdatedPackagesAsUser(accounts.userId); + } + if (!knownUids.get(Integer.parseInt(uid))) { + // The authenticator is not presently available to the cache. And the + // package no longer has a data directory (so we surmise it isn't updating). + // So purge its data from the account databases. + obsoleteAuthType.add(type); + // And delete it from the TABLE_META + db.delete( + TABLE_META, + META_KEY + "=? AND " + META_VALUE + "=?", + new String[] { + META_KEY_FOR_AUTHENTICATOR_UID_FOR_TYPE_PREFIX + type, + uid} + ); + } } } } finally { metaCursor.close(); } - // Add the newly registered authenticator to TABLE_META + // Add the newly registered authenticator to TABLE_META. If old authenticators have + // been renabled (after being updated for example), then we just overwrite the old + // values. Iterator<Entry<String, Integer>> iterator = knownAuth.entrySet().iterator(); while (iterator.hasNext()) { Entry<String, Integer> entry = iterator.next(); @@ -490,7 +513,7 @@ public class AccountManagerService values.put(META_KEY, META_KEY_FOR_AUTHENTICATOR_UID_FOR_TYPE_PREFIX + entry.getKey()); values.put(META_VALUE, entry.getValue()); - db.insert(TABLE_META, null, values); + db.insertWithOnConflict(TABLE_META, null, values, SQLiteDatabase.CONFLICT_REPLACE); } Cursor cursor = db.query(TABLE_ACCOUNTS, @@ -544,10 +567,32 @@ public class AccountManagerService } } + private SparseBooleanArray getUidsOfInstalledOrUpdatedPackagesAsUser(int userId) { + // Get the UIDs of all apps that might have data on the device. We want + // to preserve user data if the app might otherwise be storing data. + List<PackageInfo> pkgsWithData = + mPackageManager.getInstalledPackagesAsUser( + PackageManager.MATCH_UNINSTALLED_PACKAGES, userId); + SparseBooleanArray knownUids = new SparseBooleanArray(pkgsWithData.size()); + for (PackageInfo pkgInfo : pkgsWithData) { + if (pkgInfo.applicationInfo != null + && (pkgInfo.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED) != 0) { + knownUids.put(pkgInfo.applicationInfo.uid, true); + } + } + return knownUids; + } + private static HashMap<String, Integer> getAuthenticatorTypeAndUIDForUser( Context context, int userId) { AccountAuthenticatorCache authCache = new AccountAuthenticatorCache(context); + return getAuthenticatorTypeAndUIDForUser(authCache, userId); + } + + private static HashMap<String, Integer> getAuthenticatorTypeAndUIDForUser( + IAccountAuthenticatorCache authCache, + int userId) { HashMap<String, Integer> knownAuth = new HashMap<>(); for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> service : authCache .getAllServices(userId)) { @@ -575,7 +620,7 @@ public class AccountManagerService validateAccounts = true; } // open CE database if necessary - if (!accounts.openHelper.isCeDatabaseAttached() && mUnlockedUsers.get(userId)) { + if (!accounts.openHelper.isCeDatabaseAttached() && mLocalUnlockedUsers.get(userId)) { Log.i(TAG, "User " + userId + " is unlocked - opening CE database"); synchronized (accounts.cacheLock) { File preNDatabaseFile = new File(getPreNDatabaseName(userId)); @@ -648,8 +693,8 @@ public class AccountManagerService synchronized (mUsers) { accounts = mUsers.get(userId); mUsers.remove(userId); - userUnlocked = mUnlockedUsers.get(userId); - mUnlockedUsers.delete(userId); + userUnlocked = mLocalUnlockedUsers.get(userId); + mLocalUnlockedUsers.delete(userId); } if (accounts != null) { synchronized (accounts.cacheLock) { @@ -686,7 +731,7 @@ public class AccountManagerService Log.v(TAG, "onUserUnlocked " + userId); } synchronized (mUsers) { - mUnlockedUsers.put(userId, true); + mLocalUnlockedUsers.put(userId, true); } if (userId < 1) return; syncSharedAccounts(userId); @@ -746,7 +791,7 @@ public class AccountManagerService if (account == null) { return null; } - if (!isUserUnlocked(accounts.userId)) { + if (!isLocalUnlockedUser(accounts.userId)) { Log.w(TAG, "Password is not available - user " + accounts.userId + " data is locked"); return null; } @@ -828,7 +873,7 @@ public class AccountManagerService account.type); throw new SecurityException(msg); } - if (!isUserUnlocked(userId)) { + if (!isLocalUnlockedUser(userId)) { Log.w(TAG, "User " + userId + " data is locked. callingUid " + callingUid); return null; } @@ -1109,7 +1154,7 @@ public class AccountManagerService if (account == null) { return false; } - if (!isUserUnlocked(accounts.userId)) { + if (!isLocalUnlockedUser(accounts.userId)) { Log.w(TAG, "Account " + account + " cannot be added - user " + accounts.userId + " is locked. callingUid=" + callingUid); return false; @@ -1176,9 +1221,9 @@ public class AccountManagerService return true; } - private boolean isUserUnlocked(int userId) { + private boolean isLocalUnlockedUser(int userId) { synchronized (mUsers) { - return mUnlockedUsers.get(userId); + return mLocalUnlockedUsers.get(userId); } } @@ -1193,7 +1238,7 @@ public class AccountManagerService for (UserInfo user : users) { if (user.isRestricted() && (parentUserId == user.restrictedProfileParentId)) { addSharedAccountAsUser(account, user.id); - if (getUserManager().isUserUnlocked(user.id)) { + if (isLocalUnlockedUser(user.id)) { mMessageHandler.sendMessage(mMessageHandler.obtainMessage( MESSAGE_COPY_SHARED_ACCOUNT, parentUserId, user.id, account)); } @@ -1597,7 +1642,7 @@ public class AccountManagerService private boolean removeAccountInternal(UserAccounts accounts, Account account, int callingUid) { int deleted; - boolean userUnlocked = isUserUnlocked(accounts.userId); + boolean userUnlocked = isLocalUnlockedUser(accounts.userId); if (!userUnlocked) { Slog.i(TAG, "Removing account " + account + " while user "+ accounts.userId + " is still locked. CE data will be removed later"); @@ -1792,7 +1837,7 @@ public class AccountManagerService account.type); throw new SecurityException(msg); } - if (!isUserUnlocked(userId)) { + if (!isLocalUnlockedUser(userId)) { Log.w(TAG, "Authtoken not available - user " + userId + " data is locked. callingUid " + callingUid); return null; @@ -4037,8 +4082,7 @@ public class AccountManagerService return false; } - final ActivityManager am = mContext.getSystemService(ActivityManager.class); - if (am.isUserRunningAndLocked(mAccounts.userId) + if (!isLocalUnlockedUser(mAccounts.userId) && !authenticatorInfo.componentInfo.directBootAware) { Slog.w(TAG, "Blocking binding to authenticator " + authenticatorInfo.componentName + " which isn't encryption aware"); diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 9d7ddc7b96c1..07f7e29876d6 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -1946,9 +1946,7 @@ public final class ActivityManagerService extends ActivityManagerNative startPersistentApps(PackageManager.MATCH_DIRECT_BOOT_UNAWARE); } installEncryptionUnawareProviders(userId); - if (msg.obj instanceof ProgressReporter) { - ((ProgressReporter) msg.obj).finish(); - } + mUserController.finishUserUnlocked((UserState) msg.obj); break; } case SYSTEM_USER_CURRENT_MSG: { @@ -5949,6 +5947,15 @@ public final class ActivityManagerService extends ActivityManagerNative } + final boolean clearBroadcastQueueForUserLocked(int userId) { + boolean didSomething = false; + for (int i = mBroadcastQueues.length - 1; i >= 0; i--) { + didSomething |= mBroadcastQueues[i].cleanupDisabledPackageReceiversLocked( + null, null, userId, true); + } + return didSomething; + } + final boolean forceStopPackageLocked(String packageName, int appId, boolean callerWillRestart, boolean purgeCache, boolean doit, boolean evenPersistent, boolean uninstalling, int userId, String reason) { @@ -6304,7 +6311,11 @@ public final class ActivityManagerService extends ActivityManagerNative app.debugging = false; app.cached = false; app.killedByAm = false; - app.unlocked = mContext.getSystemService(UserManager.class).isUserUnlocked(app.userId); + + // We carefully use the same state that PackageManager uses for + // filtering, since we use this flag to decide if we need to install + // providers when user is unlocked later + app.unlocked = StorageManager.isUserKeyUnlocked(app.userId); mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app); @@ -9689,7 +9700,7 @@ public final class ActivityManagerService extends ActivityManagerNative */ @Override public boolean moveTaskToDockedStack(int taskId, int createMode, boolean toTop, boolean animate, - Rect initialBounds) { + Rect initialBounds, boolean moveHomeStackFront) { enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "moveTaskToDockedStack()"); synchronized (this) { long ident = Binder.clearCallingIdentity(); @@ -9697,9 +9708,16 @@ public final class ActivityManagerService extends ActivityManagerNative if (DEBUG_STACK) Slog.d(TAG_STACK, "moveTaskToDockedStack: moving task=" + taskId + " to createMode=" + createMode + " toTop=" + toTop); mWindowManager.setDockedStackCreateState(createMode, initialBounds); - return mStackSupervisor.moveTaskToStackLocked( - taskId, DOCKED_STACK_ID, toTop, !FORCE_FOCUS, - "moveTaskToDockedStack", animate); + final boolean moved = mStackSupervisor.moveTaskToStackLocked( + taskId, DOCKED_STACK_ID, toTop, !FORCE_FOCUS, "moveTaskToDockedStack", + animate, DEFER_RESUME); + if (moved) { + if (moveHomeStackFront) { + mStackSupervisor.moveHomeStackToFront("moveTaskToDockedStack"); + } + mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS); + } + return moved; } finally { Binder.restoreCallingIdentity(ident); } @@ -11024,14 +11042,6 @@ public final class ActivityManagerService extends ActivityManagerNative * belonging to any running apps. */ private void installEncryptionUnawareProviders(int userId) { - if (!StorageManager.isFileEncryptedNativeOrEmulated()) { - // TODO: eventually pivot this back to look at current user state, - // similar to the comment in UserManager.isUserUnlocked(), but for - // now, if we started apps when "unlocked" then unaware providers - // have already been spun up. - return; - } - // We're only interested in providers that are encryption unaware, and // we don't care about uninstalled apps, since there's no way they're // running at this point. @@ -17178,6 +17188,7 @@ public final class ActivityManagerService extends ActivityManagerNative if (isProtectedBroadcast || Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action) || Intent.ACTION_DISMISS_KEYBOARD_SHORTCUTS.equals(action) + || Intent.ACTION_MEDIA_BUTTON.equals(action) || Intent.ACTION_MEDIA_SCANNER_SCAN_FILE.equals(action) || Intent.ACTION_SHOW_KEYBOARD_SHORTCUTS.equals(action) || AppWidgetManager.ACTION_APPWIDGET_CONFIGURE.equals(action) diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java index a41a8ef0cb13..fa69b4a857df 100755 --- a/services/core/java/com/android/server/am/ActivityRecord.java +++ b/services/core/java/com/android/server/am/ActivityRecord.java @@ -21,6 +21,7 @@ import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID; import static android.app.ActivityManager.StackId.PINNED_STACK_ID; import static android.content.pm.ActivityInfo.RESIZE_MODE_CROP_WINDOWS; import static android.content.pm.ActivityInfo.FLAG_ALWAYS_FOCUSABLE; +import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE; import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_AND_PIPABLE; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_CONFIGURATION; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SWITCH; @@ -591,7 +592,7 @@ final class ActivityRecord { ActivityRecord _resultTo, String _resultWho, int _reqCode, boolean _componentSpecified, boolean _rootVoiceInteraction, ActivityStackSupervisor supervisor, - ActivityContainer container, ActivityOptions options) { + ActivityContainer container, ActivityOptions options, ActivityRecord sourceRecord) { service = _service; appToken = new Token(this, service); info = aInfo; @@ -704,21 +705,7 @@ final class ActivityRecord { noDisplay = ent != null && ent.array.getBoolean( com.android.internal.R.styleable.Window_windowNoDisplay, false); - if ((!_componentSpecified || _launchedFromUid == Process.myUid() - || _launchedFromUid == 0) && - Intent.ACTION_MAIN.equals(_intent.getAction()) && - _intent.hasCategory(Intent.CATEGORY_HOME) && - _intent.getCategories().size() == 1 && - _intent.getData() == null && - _intent.getType() == null && - !isResolverActivity()) { - // This sure looks like a home activity! - mActivityType = HOME_ACTIVITY_TYPE; - } else if (realActivity.getClassName().contains(RECENTS_PACKAGE_NAME)) { - mActivityType = RECENTS_ACTIVITY_TYPE; - } else { - mActivityType = APPLICATION_ACTIVITY_TYPE; - } + setActivityType(_componentSpecified, _launchedFromUid, _intent, sourceRecord); immersive = (aInfo.flags & ActivityInfo.FLAG_IMMERSIVE) != 0; @@ -739,6 +726,36 @@ final class ActivityRecord { } } + private boolean isHomeIntent(Intent intent) { + return Intent.ACTION_MAIN.equals(intent.getAction()) + && intent.hasCategory(Intent.CATEGORY_HOME) + && intent.getCategories().size() == 1 + && intent.getData() == null + && intent.getType() == null; + } + + private boolean canLaunchHomeActivity(int uid, ActivityRecord sourceRecord) { + if (uid == Process.myUid() || uid == 0) { + // System process can launch home activity. + return true; + } + // Resolver activity can launch home activity. + return sourceRecord != null && sourceRecord.isResolverActivity(); + } + + private void setActivityType(boolean componentSpecified, + int launchedFromUid, Intent intent, ActivityRecord sourceRecord) { + if ((!componentSpecified || canLaunchHomeActivity(launchedFromUid, sourceRecord)) + && isHomeIntent(intent) && !isResolverActivity()) { + // This sure looks like a home activity! + mActivityType = HOME_ACTIVITY_TYPE; + } else if (realActivity.getClassName().contains(RECENTS_PACKAGE_NAME)) { + mActivityType = RECENTS_ACTIVITY_TYPE; + } else { + mActivityType = APPLICATION_ACTIVITY_TYPE; + } + } + void setTask(TaskRecord newTask, TaskRecord taskToAffiliateWith) { if (task != null && task.removeActivity(this) && task != newTask && task.stack != null) { task.stack.removeTask(task, "setTask"); @@ -822,6 +839,11 @@ final class ActivityRecord { return !isHomeActivity() && (isResizeable() || service.mForceResizableActivities); } + boolean isNonResizableOrForced() { + return !isHomeActivity() && info.resizeMode != RESIZE_MODE_RESIZEABLE + && info.resizeMode != RESIZE_MODE_RESIZEABLE_AND_PIPABLE; + } + boolean supportsPictureInPicture() { return !isHomeActivity() && info.resizeMode == RESIZE_MODE_RESIZEABLE_AND_PIPABLE; } @@ -1467,7 +1489,7 @@ final class ActivityRecord { } final ActivityRecord r = new ActivityRecord(service, /*caller*/null, launchedFromUid, launchedFromPackage, intent, resolvedType, aInfo, service.getConfiguration(), - null, null, 0, componentSpecified, false, stackSupervisor, null, null); + null, null, 0, componentSpecified, false, stackSupervisor, null, null, null); r.persistentState = persistentState; r.taskDescription = taskDescription; diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java index 37bd401eca57..d751a32ccfa2 100644 --- a/services/core/java/com/android/server/am/ActivityStack.java +++ b/services/core/java/com/android/server/am/ActivityStack.java @@ -3438,7 +3438,9 @@ final class ActivityStack { mWindowManager.prepareAppTransition(transit, false); mWindowManager.setAppVisibility(r.appToken, false); mWindowManager.executeAppTransition(); - mStackSupervisor.mWaitingVisibleActivities.add(r); + if (!mStackSupervisor.mWaitingVisibleActivities.contains(r)) { + mStackSupervisor.mWaitingVisibleActivities.add(r); + } } return finishCurrentActivityLocked(r, (r.visible || r.nowVisible) ? FINISH_AFTER_VISIBLE : FINISH_AFTER_PAUSE, oomAdj) == null; @@ -3457,8 +3459,11 @@ final class ActivityStack { // First things first: if this activity is currently visible, // and the resumed activity is not yet visible, then hold off on // finishing until the resumed one becomes visible. + + final ActivityRecord next = mStackSupervisor.topRunningActivityLocked(); + if (mode == FINISH_AFTER_VISIBLE && (r.visible || r.nowVisible) - && !mStackSupervisor.allResumedActivitiesVisible()) { + && next != null && !next.nowVisible) { if (!mStackSupervisor.mStoppingActivities.contains(r)) { addToStopping(r, false /* immediate */); } @@ -3483,11 +3488,10 @@ final class ActivityStack { r.state = ActivityState.FINISHING; if (mode == FINISH_IMMEDIATELY - || (mode == FINISH_AFTER_PAUSE && prevState == ActivityState.PAUSED) + || (prevState == ActivityState.PAUSED + && (mode == FINISH_AFTER_PAUSE || mStackId == PINNED_STACK_ID)) || prevState == ActivityState.STOPPED || prevState == ActivityState.INITIALIZING) { - // If this activity is already stopped, we can just finish - // it right now. r.makeFinishingLocked(); boolean activityRemoved = destroyActivityLocked(r, true, "finish-imm"); if (activityRemoved) { diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java index f192a9ddb3b2..20ef0e865254 100644 --- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java @@ -3508,6 +3508,7 @@ public final class ActivityStackSupervisor implements DisplayListener { return; } + final ActivityRecord topActivity = task.getTopActivity(); if (!task.canGoInDockedStack() || forceNonResizable) { // Display a warning toast that we tried to put a non-dockable task in the docked stack. mService.mHandler.sendEmptyMessage(NOTIFY_ACTIVITY_DISMISSING_DOCKED_STACK_MSG); @@ -3515,9 +3516,9 @@ public final class ActivityStackSupervisor implements DisplayListener { // Dismiss docked stack. If task appeared to be in docked stack but is not resizable - // we need to move it to top of fullscreen stack, otherwise it will be covered. moveTasksToFullscreenStackLocked(DOCKED_STACK_ID, actualStackId == DOCKED_STACK_ID); - } else if (task.mResizeMode == RESIZE_MODE_FORCE_RESIZEABLE) { - String packageName = task.getTopActivity() != null - ? task.getTopActivity().appInfo.packageName : null; + } else if (topActivity != null && topActivity.isNonResizableOrForced() + && !topActivity.noDisplay) { + String packageName = topActivity.appInfo.packageName; mService.mHandler.obtainMessage(NOTIFY_FORCED_RESIZABLE_MSG, task.taskId, 0, packageName).sendToTarget(); } diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java index 6622b34c1106..c15effb83c10 100644 --- a/services/core/java/com/android/server/am/ActivityStarter.java +++ b/services/core/java/com/android/server/am/ActivityStarter.java @@ -171,6 +171,7 @@ class ActivityStarter { private boolean mMovedToFront; private boolean mNoAnimation; private boolean mKeepCurTransition; + private boolean mAvoidMoveToFront; private IVoiceInteractionSession mVoiceSession; private IVoiceInteractor mVoiceInteractor; @@ -207,6 +208,7 @@ class ActivityStarter { mMovedToFront = false; mNoAnimation = false; mKeepCurTransition = false; + mAvoidMoveToFront = false; mVoiceSession = null; mVoiceInteractor = null; @@ -490,7 +492,7 @@ class ActivityStarter { ActivityRecord r = new ActivityRecord(mService, callerApp, callingUid, callingPackage, intent, resolvedType, aInfo, mService.mConfiguration, resultRecord, resultWho, requestCode, componentSpecified, voiceSession != null, mSupervisor, container, - options); + options, sourceRecord); if (outActivity != null) { outActivity[0] = r; } @@ -683,8 +685,8 @@ class ActivityStarter { Binder.restoreCallingIdentity(token); } if (parent != null - && userManager.isUserUnlocked(parent.getUserHandle()) - && !userManager.isUserUnlocked(userInfo.getUserHandle())) { + && userManager.isUserUnlockingOrUnlocked(parent.getUserHandle()) + && !userManager.isUserUnlockingOrUnlocked(userInfo.getUserHandle())) { rInfo = mSupervisor.resolveIntent(intent, resolvedType, userId, PackageManager.MATCH_DIRECT_BOOT_AWARE | PackageManager.MATCH_DIRECT_BOOT_UNAWARE); @@ -1223,6 +1225,18 @@ class ActivityStarter { mDoResume = false; } + if (mOptions != null && mOptions.getLaunchTaskId() != -1 && mOptions.getAvoidMoveToFront()) { + final TaskRecord task = mSupervisor.anyTaskForIdLocked(mOptions.getLaunchTaskId()); + final ActivityRecord top = task != null ? task.getTopActivity() : null; + if (top != null && !top.visible) { + + // The caller specifies that we'd like to be avoided to be moved to the front, so be + // it! + mDoResume = false; + mAvoidMoveToFront = true; + } + } + mNotTop = (mLaunchFlags & FLAG_ACTIVITY_PREVIOUS_IS_TOP) != 0 ? r : null; mInTask = inTask; @@ -1419,8 +1433,9 @@ class ActivityStarter { ActivityRecord curTop = (focusStack == null) ? null : focusStack.topRunningNonDelayedActivityLocked(mNotTop); - if (curTop != null && (curTop.task != intentActivity.task || - curTop.task != focusStack.topTask())) { + if (curTop != null + && (curTop.task != intentActivity.task || curTop.task != focusStack.topTask()) + && !mAvoidMoveToFront) { mStartActivity.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT); if (mSourceRecord == null || (mSourceStack.topActivity() != null && mSourceStack.topActivity().task == mSourceRecord.task)) { @@ -1582,9 +1597,6 @@ class ActivityStarter { private void setTaskFromReuseOrCreateNewTask(TaskRecord taskToAffiliate) { mTargetStack = computeStackFocus(mStartActivity, true, mLaunchBounds, mLaunchFlags, mOptions); - if (mDoResume) { - mTargetStack.moveToFront("startingNewTask"); - } if (mReuseTask == null) { final TaskRecord task = mTargetStack.createTaskRecord( @@ -1631,7 +1643,7 @@ class ActivityStarter { mTargetStack.moveToFront("sourceStackToFront"); } final TaskRecord topTask = mTargetStack.topTask(); - if (topTask != sourceTask) { + if (topTask != sourceTask && !mAvoidMoveToFront) { mTargetStack.moveTaskToFrontLocked(sourceTask, mNoAnimation, mOptions, mStartActivity.appTimeTracker, "sourceTaskToFront"); } diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java index e9ed34b18baa..3ed996992e2e 100644 --- a/services/core/java/com/android/server/am/AppErrors.java +++ b/services/core/java/com/android/server/am/AppErrors.java @@ -304,6 +304,15 @@ class AppErrors { * @param crashInfo describing the failure */ void crashApplication(ProcessRecord r, ApplicationErrorReport.CrashInfo crashInfo) { + final long origId = Binder.clearCallingIdentity(); + try { + crashApplicationInner(r, crashInfo); + } finally { + Binder.restoreCallingIdentity(origId); + } + } + + void crashApplicationInner(ProcessRecord r, ApplicationErrorReport.CrashInfo crashInfo) { long timeMillis = System.currentTimeMillis(); String shortMsg = crashInfo.exceptionClassName; String longMsg = crashInfo.exceptionMessage; @@ -317,49 +326,20 @@ class AppErrors { AppErrorResult result = new AppErrorResult(); TaskRecord task; synchronized (mService) { - if (mService.mController != null) { - try { - String name = r != null ? r.processName : null; - int pid = r != null ? r.pid : Binder.getCallingPid(); - int uid = r != null ? r.info.uid : Binder.getCallingUid(); - if (!mService.mController.appCrashed(name, pid, - shortMsg, longMsg, timeMillis, crashInfo.stackTrace)) { - if ("1".equals(SystemProperties.get(SYSTEM_DEBUGGABLE, "0")) - && "Native crash".equals(crashInfo.exceptionClassName)) { - Slog.w(TAG, "Skip killing native crashed app " + name - + "(" + pid + ") during testing"); - } else { - Slog.w(TAG, "Force-killing crashed app " + name - + " at watcher's request"); - if (r != null) { - r.kill("crash", true); - } else { - // Huh. - Process.killProcess(pid); - ActivityManagerService.killProcessGroup(uid, pid); - } - } - return; - } - } catch (RemoteException e) { - mService.mController = null; - Watchdog.getInstance().setActivityController(null); - } + /** + * If crash is handled by instance of {@link android.app.IActivityController}, + * finish now and don't show the app error dialog. + */ + if (handleAppCrashInActivityController(r, crashInfo, shortMsg, longMsg, stackTrace, + timeMillis)) { + return; } - final long origId = Binder.clearCallingIdentity(); - - // If this process is running instrumentation, finish it. + /** + * If this process was running instrumentation, finish now - it will be handled in + * {@link ActivityManagerService#handleAppDiedLocked}. + */ if (r != null && r.instrumentationClass != null) { - Slog.w(TAG, "Error in app " + r.processName - + " running instrumentation " + r.instrumentationClass + ":"); - if (shortMsg != null) Slog.w(TAG, " " + shortMsg); - if (longMsg != null) Slog.w(TAG, " " + longMsg); - Bundle info = new Bundle(); - info.putString("shortMsg", shortMsg); - info.putString("longMsg", longMsg); - mService.finishInstrumentationLocked(r, Activity.RESULT_CANCELED, info); - Binder.restoreCallingIdentity(origId); return; } @@ -375,7 +355,6 @@ class AppErrors { // If we can't identify the process or it's already exceeded its crash quota, // quit right away without showing a crash dialog. if (r == null || !makeAppCrashingLocked(r, shortMsg, longMsg, stackTrace, data)) { - Binder.restoreCallingIdentity(origId); return; } @@ -385,97 +364,90 @@ class AppErrors { task = data.task; msg.obj = data; mService.mUiHandler.sendMessage(msg); - - Binder.restoreCallingIdentity(origId); } int res = result.get(); Intent appErrorIntent = null; - final long ident = Binder.clearCallingIdentity(); - try { - MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_APP_CRASH, res); - if (res == AppErrorDialog.TIMEOUT) { - res = AppErrorDialog.FORCE_QUIT; - } - if (res == AppErrorDialog.RESET) { - String[] packageList = r.getPackageList(); - if (packageList != null) { - PackageManager pm = mContext.getPackageManager(); - final Semaphore s = new Semaphore(0); - for (int i = 0; i < packageList.length; i++) { - if (i < packageList.length - 1) { - pm.deleteApplicationCacheFiles(packageList[i], null); - } else { - pm.deleteApplicationCacheFiles(packageList[i], - new IPackageDataObserver.Stub() { - @Override - public void onRemoveCompleted(String packageName, - boolean succeeded) { - s.release(); - } - }); - - // Wait until cache has been cleared before we restart. - try { - s.acquire(); - } catch (InterruptedException e) { - } - } - } - } - // If there was nothing to reset, just restart; - res = AppErrorDialog.RESTART; - } - synchronized (mService) { - if (res == AppErrorDialog.MUTE) { - stopReportingCrashesLocked(r); - } - if (res == AppErrorDialog.RESTART) { - mService.removeProcessLocked(r, false, true, "crash"); - if (task != null) { + MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_APP_CRASH, res); + if (res == AppErrorDialog.TIMEOUT) { + res = AppErrorDialog.FORCE_QUIT; + } + if (res == AppErrorDialog.RESET) { + String[] packageList = r.getPackageList(); + if (packageList != null) { + PackageManager pm = mContext.getPackageManager(); + final Semaphore s = new Semaphore(0); + for (int i = 0; i < packageList.length; i++) { + if (i < packageList.length - 1) { + pm.deleteApplicationCacheFiles(packageList[i], null); + } else { + pm.deleteApplicationCacheFiles(packageList[i], + new IPackageDataObserver.Stub() { + @Override + public void onRemoveCompleted(String packageName, + boolean succeeded) { + s.release(); + } + }); + + // Wait until cache has been cleared before we restart. try { - mService.startActivityFromRecents(task.taskId, - ActivityOptions.makeBasic().toBundle()); - } catch (IllegalArgumentException e) { - // Hmm, that didn't work, app might have crashed before creating a - // recents entry. Let's see if we have a safe-to-restart intent. - if (task.intent.getCategories().contains( - Intent.CATEGORY_LAUNCHER)) { - mService.startActivityInPackage(task.mCallingUid, - task.mCallingPackage, task.intent, - null, null, null, 0, 0, - ActivityOptions.makeBasic().toBundle(), - task.userId, null, null); - } + s.acquire(); + } catch (InterruptedException e) { } } } - if (res == AppErrorDialog.FORCE_QUIT) { - long orig = Binder.clearCallingIdentity(); + } + // If there was nothing to reset, just restart; + res = AppErrorDialog.RESTART; + } + synchronized (mService) { + if (res == AppErrorDialog.MUTE) { + stopReportingCrashesLocked(r); + } + if (res == AppErrorDialog.RESTART) { + mService.removeProcessLocked(r, false, true, "crash"); + if (task != null) { try { - // Kill it with fire! - mService.mStackSupervisor.handleAppCrashLocked(r); - if (!r.persistent) { - mService.removeProcessLocked(r, false, false, "crash"); - mService.mStackSupervisor.resumeFocusedStackTopActivityLocked(); + mService.startActivityFromRecents(task.taskId, + ActivityOptions.makeBasic().toBundle()); + } catch (IllegalArgumentException e) { + // Hmm, that didn't work, app might have crashed before creating a + // recents entry. Let's see if we have a safe-to-restart intent. + if (task.intent.getCategories().contains( + Intent.CATEGORY_LAUNCHER)) { + mService.startActivityInPackage(task.mCallingUid, + task.mCallingPackage, task.intent, + null, null, null, 0, 0, + ActivityOptions.makeBasic().toBundle(), + task.userId, null, null); } - } finally { - Binder.restoreCallingIdentity(orig); } } - if (res == AppErrorDialog.FORCE_QUIT_AND_REPORT) { - appErrorIntent = createAppErrorIntentLocked(r, timeMillis, crashInfo); - } - if (r != null && !r.isolated && res != AppErrorDialog.RESTART) { - // XXX Can't keep track of crash time for isolated processes, - // since they don't have a persistent identity. - mProcessCrashTimes.put(r.info.processName, r.uid, - SystemClock.uptimeMillis()); + } + if (res == AppErrorDialog.FORCE_QUIT) { + long orig = Binder.clearCallingIdentity(); + try { + // Kill it with fire! + mService.mStackSupervisor.handleAppCrashLocked(r); + if (!r.persistent) { + mService.removeProcessLocked(r, false, false, "crash"); + mService.mStackSupervisor.resumeFocusedStackTopActivityLocked(); + } + } finally { + Binder.restoreCallingIdentity(orig); } } - } finally { - Binder.restoreCallingIdentity(ident); + if (res == AppErrorDialog.FORCE_QUIT_AND_REPORT) { + appErrorIntent = createAppErrorIntentLocked(r, timeMillis, crashInfo); + } + if (r != null && !r.isolated && res != AppErrorDialog.RESTART) { + // XXX Can't keep track of crash time for isolated processes, + // since they don't have a persistent identity. + mProcessCrashTimes.put(r.info.processName, r.uid, + SystemClock.uptimeMillis()); + } } if (appErrorIntent != null) { @@ -487,6 +459,47 @@ class AppErrors { } } + private boolean handleAppCrashInActivityController(ProcessRecord r, + ApplicationErrorReport.CrashInfo crashInfo, + String shortMsg, String longMsg, + String stackTrace, long timeMillis) { + if (mService.mController == null) { + return false; + } + + try { + String name = r != null ? r.processName : null; + int pid = r != null ? r.pid : Binder.getCallingPid(); + int uid = r != null ? r.info.uid : Binder.getCallingUid(); + if (!mService.mController.appCrashed(name, pid, + shortMsg, longMsg, timeMillis, crashInfo.stackTrace)) { + if ("1".equals(SystemProperties.get(SYSTEM_DEBUGGABLE, "0")) + && "Native crash".equals(crashInfo.exceptionClassName)) { + Slog.w(TAG, "Skip killing native crashed app " + name + + "(" + pid + ") during testing"); + } else { + Slog.w(TAG, "Force-killing crashed app " + name + + " at watcher's request"); + if (r != null) { + if (!makeAppCrashingLocked(r, shortMsg, longMsg, stackTrace, null)) + { + r.kill("crash", true); + } + } else { + // Huh. + Process.killProcess(pid); + ActivityManagerService.killProcessGroup(uid, pid); + } + } + return true; + } + } catch (RemoteException e) { + mService.mController = null; + Watchdog.getInstance().setActivityController(null); + } + return false; + } + private boolean makeAppCrashingLocked(ProcessRecord app, String shortMsg, String longMsg, String stackTrace, AppErrorDialog.Data data) { app.crashing = true; diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java index 2516f5df4cbf..d34ec868dc1c 100644 --- a/services/core/java/com/android/server/am/BatteryStatsService.java +++ b/services/core/java/com/android/server/am/BatteryStatsService.java @@ -79,7 +79,8 @@ import java.util.concurrent.TimeoutException; * battery life. */ public final class BatteryStatsService extends IBatteryStats.Stub - implements PowerManagerInternal.LowPowerModeListener { + implements PowerManagerInternal.LowPowerModeListener, + BatteryStatsImpl.PlatformIdleStateCallback { static final String TAG = "BatteryStatsService"; /** @@ -173,6 +174,33 @@ public final class BatteryStatsService extends IBatteryStats.Stub } } + private native int getPlatformLowPowerStats(ByteBuffer outBuffer); + private CharsetDecoder mDecoderStat = StandardCharsets.UTF_8 + .newDecoder() + .onMalformedInput(CodingErrorAction.REPLACE) + .onUnmappableCharacter(CodingErrorAction.REPLACE) + .replaceWith("?"); + private ByteBuffer mUtf8BufferStat = ByteBuffer.allocateDirect(MAX_LOW_POWER_STATS_SIZE); + private CharBuffer mUtf16BufferStat = CharBuffer.allocate(MAX_LOW_POWER_STATS_SIZE); + private static final int MAX_LOW_POWER_STATS_SIZE = 512; + + @Override + public String getPlatformLowPowerStats() { + mUtf8BufferStat.clear(); + mUtf16BufferStat.clear(); + mDecoderStat.reset(); + int bytesWritten = getPlatformLowPowerStats(mUtf8BufferStat); + if (bytesWritten < 0) { + return null; + } else if (bytesWritten == 0) { + return "Empty"; + } + mUtf8BufferStat.limit(bytesWritten); + mDecoderStat.decode(mUtf8BufferStat, mUtf16BufferStat, true); + mUtf16BufferStat.flip(); + return mUtf16BufferStat.toString(); + } + BatteryStatsService(File systemDir, Handler handler) { // Our handler here will be accessing the disk, use a different thread than // what the ActivityManagerService gave us (no I/O on that one!). @@ -182,9 +210,9 @@ public final class BatteryStatsService extends IBatteryStats.Stub mHandler = new BatteryStatsHandler(thread.getLooper()); // BatteryStatsImpl expects the ActivityManagerService handler, so pass that one through. - mStats = new BatteryStatsImpl(systemDir, handler, mHandler); + mStats = new BatteryStatsImpl(systemDir, handler, mHandler, this); } - + public void publish(Context context) { mContext = context; mStats.setRadioScanningTimeout(mContext.getResources().getInteger( @@ -946,7 +974,7 @@ public final class BatteryStatsService extends IBatteryStats.Stub @Override public void setBatteryState(final int status, final int health, final int plugType, - final int level, final int temp, final int volt) { + final int level, final int temp, final int volt, final int chargeCount) { enforceCallingPermission(); // BatteryService calls us here and we may update external state. It would be wrong @@ -959,7 +987,8 @@ public final class BatteryStatsService extends IBatteryStats.Stub if (mStats.isOnBattery() == onBattery) { // The battery state has not changed, so we don't need to sync external // stats immediately. - mStats.setBatteryStateLocked(status, health, plugType, level, temp, volt); + mStats.setBatteryStateLocked(status, health, plugType, level, temp, volt, + chargeCount); return; } } @@ -968,7 +997,8 @@ public final class BatteryStatsService extends IBatteryStats.Stub // immediately here, we may not collect the relevant data later. updateExternalStatsSync("battery-state", BatteryStatsImpl.ExternalStatsSync.UPDATE_ALL); synchronized (mStats) { - mStats.setBatteryStateLocked(status, health, plugType, level, temp, volt); + mStats.setBatteryStateLocked(status, health, plugType, level, temp, volt, + chargeCount); } } }); diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java index 75d49c3ba8fc..bfa5b42b79c3 100644 --- a/services/core/java/com/android/server/am/UserController.java +++ b/services/core/java/com/android/server/am/UserController.java @@ -220,6 +220,7 @@ final class UserController { private void finishUserBoot(UserState uss, IIntentReceiver resultTo) { final int userId = uss.mHandle.getIdentifier(); + Slog.d(TAG, "Finishing user boot " + userId); synchronized (mService) { // Bail if we ended up with a stale user if (mStartedUsers.get(userId) != uss) return; @@ -248,7 +249,8 @@ final class UserController { + "): attempting unlock because parent is unlocked"); maybeUnlockUser(userId); } else { - Slog.d(TAG, "User " + userId + " (parent " + parent.id + String parentId = (parent == null) ? "<null>" : String.valueOf(parent.id); + Slog.d(TAG, "User " + userId + " (parent " + parentId + "): delaying unlock because parent is locked"); } } else { @@ -268,7 +270,7 @@ final class UserController { if (mStartedUsers.get(uss.mHandle.getIdentifier()) != uss) return; // Only keep marching forward if user is actually unlocked - if (!isUserKeyUnlocked(userId)) return; + if (!StorageManager.isUserKeyUnlocked(userId)) return; if (uss.setState(STATE_RUNNING_LOCKED, STATE_RUNNING_UNLOCKING)) { uss.mUnlockProgress.start(); @@ -279,9 +281,29 @@ final class UserController { mUserManager.onBeforeUnlockUser(userId); uss.mUnlockProgress.setProgress(20); - // Dispatch unlocked to system services - mHandler.obtainMessage(SYSTEM_USER_UNLOCK_MSG, userId, 0, uss.mUnlockProgress) + // Dispatch unlocked to system services; when fully dispatched, + // that calls through to the next "unlocked" phase + mHandler.obtainMessage(SYSTEM_USER_UNLOCK_MSG, userId, 0, uss) .sendToTarget(); + } + } + } + + /** + * Step from {@link UserState#STATE_RUNNING_UNLOCKING} to + * {@link UserState#STATE_RUNNING_UNLOCKED}. + */ + void finishUserUnlocked(final UserState uss) { + final int userId = uss.mHandle.getIdentifier(); + synchronized (mService) { + // Bail if we ended up with a stale user + if (mStartedUsers.get(uss.mHandle.getIdentifier()) != uss) return; + + // Only keep marching forward if user is actually unlocked + if (!StorageManager.isUserKeyUnlocked(userId)) return; + + if (uss.setState(STATE_RUNNING_UNLOCKING, STATE_RUNNING_UNLOCKED)) { + uss.mUnlockProgress.finish(); // Dispatch unlocked to external apps final Intent unlockedIntent = new Intent(Intent.ACTION_USER_UNLOCKED); @@ -308,47 +330,67 @@ final class UserController { } } - // Send PRE_BOOT broadcasts if fingerprint changed + // Send PRE_BOOT broadcasts if user fingerprint changed; we + // purposefully block sending BOOT_COMPLETED until after all + // PRE_BOOT receivers are finished to avoid ANR'ing apps final UserInfo info = getUserInfo(userId); if (!Objects.equals(info.lastLoggedInFingerprint, Build.FINGERPRINT)) { new PreBootBroadcaster(mService, userId, null) { @Override public void onFinished() { - finishUserUnlocked(uss); + finishUserUnlockedCompleted(uss); } }.sendNext(); } else { - finishUserUnlocked(uss); + finishUserUnlockedCompleted(uss); } } } } - /** - * Step from {@link UserState#STATE_RUNNING_UNLOCKING} to - * {@link UserState#STATE_RUNNING_UNLOCKED}. - */ - private void finishUserUnlocked(UserState uss) { + private void finishUserUnlockedCompleted(UserState uss) { final int userId = uss.mHandle.getIdentifier(); synchronized (mService) { // Bail if we ended up with a stale user if (mStartedUsers.get(uss.mHandle.getIdentifier()) != uss) return; + final UserInfo userInfo = getUserInfo(userId); + if (userInfo == null) { + return; + } // Only keep marching forward if user is actually unlocked - if (!isUserKeyUnlocked(userId)) return; - - if (uss.setState(STATE_RUNNING_UNLOCKING, STATE_RUNNING_UNLOCKED)) { - // Remember that we logged in - mUserManager.onUserLoggedIn(userId); - - final Intent bootIntent = new Intent(Intent.ACTION_BOOT_COMPLETED, null); - bootIntent.putExtra(Intent.EXTRA_USER_HANDLE, userId); - bootIntent.addFlags(Intent.FLAG_RECEIVER_NO_ABORT - | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND); - mService.broadcastIntentLocked(null, null, bootIntent, null, null, 0, null, null, - new String[] { android.Manifest.permission.RECEIVE_BOOT_COMPLETED }, - AppOpsManager.OP_NONE, null, true, false, MY_PID, SYSTEM_UID, userId); + if (!StorageManager.isUserKeyUnlocked(userId)) return; + + // Remember that we logged in + mUserManager.onUserLoggedIn(userId); + + if (!userInfo.isInitialized()) { + if (userId != UserHandle.USER_SYSTEM) { + Slog.d(TAG, "Initializing user #" + userId); + Intent intent = new Intent(Intent.ACTION_USER_INITIALIZE); + intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND); + mService.broadcastIntentLocked(null, null, intent, null, + new IIntentReceiver.Stub() { + @Override + public void performReceive(Intent intent, int resultCode, + String data, Bundle extras, boolean ordered, + boolean sticky, int sendingUser) { + // Note: performReceive is called with mService lock held + getUserManager().makeInitialized(userInfo.id); + } + }, 0, null, null, null, AppOpsManager.OP_NONE, + null, true, false, MY_PID, SYSTEM_UID, userId); + } } + + Slog.d(TAG, "Sending BOOT_COMPLETE user #" + userId); + final Intent bootIntent = new Intent(Intent.ACTION_BOOT_COMPLETED, null); + bootIntent.putExtra(Intent.EXTRA_USER_HANDLE, userId); + bootIntent.addFlags(Intent.FLAG_RECEIVER_NO_ABORT + | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND); + mService.broadcastIntentLocked(null, null, bootIntent, null, null, 0, null, null, + new String[] { android.Manifest.permission.RECEIVE_BOOT_COMPLETED }, + AppOpsManager.OP_NONE, null, true, false, MY_PID, SYSTEM_UID, userId); } } @@ -458,6 +500,8 @@ final class UserController { }); } }; + // Clear broadcast queue for the user to avoid delivering stale broadcasts + mService.clearBroadcastQueueForUserLocked(userId); // Kick things off. mService.broadcastIntentLocked(null, null, stoppingIntent, null, stoppingReceiver, 0, null, null, @@ -655,20 +699,35 @@ final class UserController { return IMountService.Stub.asInterface(ServiceManager.getService("mount")); } - private boolean isUserKeyUnlocked(int userId) { - final IMountService mountService = getMountService(); - if (mountService != null) { - try { - return mountService.isUserKeyUnlocked(userId); - } catch (RemoteException e) { - throw e.rethrowAsRuntimeException(); - } - } else { - Slog.w(TAG, "Mount service not published; guessing locked state based on property"); - return !StorageManager.isFileEncryptedNativeOrEmulated(); - } - } - + /** + * Start user, if its not already running. + * <p>The user will be brought to the foreground, if {@code foreground} parameter is set. + * When starting the user, multiple intents will be broadcast in the following order:</p> + * <ul> + * <li>{@link Intent#ACTION_USER_STARTED} - sent to registered receivers of the new user + * <li>{@link Intent#ACTION_USER_BACKGROUND} - sent to registered receivers of the outgoing + * user and all profiles of this user. Sent only if {@code foreground} parameter is true + * <li>{@link Intent#ACTION_USER_FOREGROUND} - sent to registered receivers of the new + * user and all profiles of this user. Sent only if {@code foreground} parameter is true + * <li>{@link Intent#ACTION_USER_SWITCHED} - sent to registered receivers of the new user. + * Sent only if {@code foreground} parameter is true + * <li>{@link Intent#ACTION_USER_STARTING} - ordered broadcast sent to registered receivers + * of the new fg user + * <li>{@link Intent#ACTION_LOCKED_BOOT_COMPLETED} - ordered broadcast sent to receivers of + * the new user + * <li>{@link Intent#ACTION_USER_UNLOCKED} - sent to registered receivers of the new user + * <li>{@link Intent#ACTION_PRE_BOOT_COMPLETED} - ordered broadcast sent to receivers of the + * new user. Sent only when the user is booting after a system update. + * <li>{@link Intent#ACTION_USER_INITIALIZE} - ordered broadcast sent to receivers of the + * new user. Sent only the first time a user is starting. + * <li>{@link Intent#ACTION_BOOT_COMPLETED} - ordered broadcast sent to receivers of the new + * user. Indicates that the user has finished booting. + * </ul> + * + * @param userId ID of the user to start + * @param foreground true if user should be brought to the foreground + * @return true if the user has been successfully started + */ boolean startUser(final int userId, final boolean foreground) { if (mService.checkCallingPermission(INTERACT_ACROSS_USERS_FULL) != PackageManager.PERMISSION_GRANTED) { @@ -680,7 +739,7 @@ final class UserController { throw new SecurityException(msg); } - if (DEBUG_MU) Slog.i(TAG, "starting userid:" + userId + " fore:" + foreground); + Slog.i(TAG, "Starting userid:" + userId + " fg:" + foreground); final long ident = Binder.clearCallingIdentity(); try { @@ -790,36 +849,8 @@ final class UserController { null, false, false, MY_PID, SYSTEM_UID, userId); } - if ((userInfo.flags&UserInfo.FLAG_INITIALIZED) == 0) { - if (userId != UserHandle.USER_SYSTEM) { - Intent intent = new Intent(Intent.ACTION_USER_INITIALIZE); - intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND); - mService.broadcastIntentLocked(null, null, intent, null, - new IIntentReceiver.Stub() { - @Override - public void performReceive(Intent intent, int resultCode, - String data, Bundle extras, boolean ordered, - boolean sticky, int sendingUser) { - mHandler.post(new Runnable() { - @Override - public void run() { - onUserInitialized(uss, foreground, - oldUserId, userId); - } - }); - } - }, 0, null, null, null, AppOpsManager.OP_NONE, - null, true, false, MY_PID, SYSTEM_UID, userId); - uss.initializing = true; - } else { - getUserManager().makeInitialized(userInfo.id); - } - } - if (foreground) { - if (!uss.initializing) { - moveUserToForegroundLocked(uss, oldUserId, userId); - } + moveUserToForegroundLocked(uss, oldUserId, userId); } else { mService.mUserController.finishUserBoot(uss); } @@ -909,7 +940,7 @@ final class UserController { } } - if (!isUserKeyUnlocked(userId)) { + if (!StorageManager.isUserKeyUnlocked(userId)) { final UserInfo userInfo = getUserInfo(userId); final IMountService mountService = getMountService(); try { @@ -996,8 +1027,8 @@ final class UserController { } } - void dispatchUserSwitch(final UserState uss, final int oldUserId, - final int newUserId) { + void dispatchUserSwitch(final UserState uss, final int oldUserId, final int newUserId) { + Slog.d(TAG, "Dispatch onUserSwitching oldUser #" + oldUserId + " newUser #" + newUserId); final int observerCount = mUserSwitchObservers.beginBroadcast(); if (observerCount > 0) { final IRemoteCallback callback = new IRemoteCallback.Stub() { @@ -1041,39 +1072,14 @@ final class UserController { } void continueUserSwitch(UserState uss, int oldUserId, int newUserId) { - completeSwitchAndInitialize(uss, oldUserId, newUserId, false, true); - } - - void onUserInitialized(UserState uss, boolean foreground, int oldUserId, int newUserId) { + Slog.d(TAG, "Continue user switch oldUser #" + oldUserId + ", newUser #" + newUserId); synchronized (mService) { - if (foreground) { - moveUserToForegroundLocked(uss, oldUserId, newUserId); - } - } - completeSwitchAndInitialize(uss, oldUserId, newUserId, true, false); - } - - void completeSwitchAndInitialize(UserState uss, int oldUserId, int newUserId, - boolean clearInitializing, boolean clearSwitching) { - boolean unfrozen = false; - synchronized (mService) { - if (clearInitializing) { - uss.initializing = false; - getUserManager().makeInitialized(uss.mHandle.getIdentifier()); - } - if (clearSwitching) { - uss.switching = false; - } - if (!uss.switching && !uss.initializing) { - mService.mWindowManager.stopFreezingScreen(); - unfrozen = true; - } - } - if (unfrozen) { - mHandler.removeMessages(REPORT_USER_SWITCH_COMPLETE_MSG); - mHandler.sendMessage(mHandler.obtainMessage(REPORT_USER_SWITCH_COMPLETE_MSG, - newUserId, 0)); + mService.mWindowManager.stopFreezingScreen(); } + uss.switching = false; + mHandler.removeMessages(REPORT_USER_SWITCH_COMPLETE_MSG); + mHandler.sendMessage(mHandler.obtainMessage(REPORT_USER_SWITCH_COMPLETE_MSG, + newUserId, 0)); stopGuestOrEphemeralUserIfBackground(); stopBackgroundUsersIfEnforced(oldUserId); } @@ -1320,30 +1326,31 @@ final class UserController { if ((flags & ActivityManager.FLAG_OR_STOPPED) != 0) { return true; } - - final boolean unlocked; - switch (state.state) { - case UserState.STATE_STOPPING: - case UserState.STATE_SHUTDOWN: - default: - return false; - - case UserState.STATE_BOOTING: - case UserState.STATE_RUNNING_LOCKED: - unlocked = false; - break; - - case UserState.STATE_RUNNING_UNLOCKING: - case UserState.STATE_RUNNING_UNLOCKED: - unlocked = true; - break; - } - if ((flags & ActivityManager.FLAG_AND_LOCKED) != 0) { - return !unlocked; + switch (state.state) { + case UserState.STATE_BOOTING: + case UserState.STATE_RUNNING_LOCKED: + return true; + default: + return false; + } + } + if ((flags & ActivityManager.FLAG_AND_UNLOCKING_OR_UNLOCKED) != 0) { + switch (state.state) { + case UserState.STATE_RUNNING_UNLOCKING: + case UserState.STATE_RUNNING_UNLOCKED: + return true; + default: + return false; + } } if ((flags & ActivityManager.FLAG_AND_UNLOCKED) != 0) { - return unlocked; + switch (state.state) { + case UserState.STATE_RUNNING_UNLOCKED: + return true; + default: + return false; + } } // One way or another, we're running! diff --git a/services/core/java/com/android/server/am/UserState.java b/services/core/java/com/android/server/am/UserState.java index 56abd95179d1..952283eb7290 100644 --- a/services/core/java/com/android/server/am/UserState.java +++ b/services/core/java/com/android/server/am/UserState.java @@ -54,7 +54,6 @@ public final class UserState { public int state = STATE_BOOTING; public int lastState = STATE_BOOTING; public boolean switching; - public boolean initializing; /** * The last time that a provider was reported to usage stats as being brought to important @@ -103,7 +102,6 @@ public final class UserState { pw.print(prefix); pw.print("state="); pw.print(stateToString(state)); if (switching) pw.print(" SWITCHING"); - if (initializing) pw.print(" INITIALIZING"); pw.println(); } } diff --git a/services/core/java/com/android/server/connectivity/MetricsLoggerService.java b/services/core/java/com/android/server/connectivity/MetricsLoggerService.java index ac5c4ae982d5..6d1c5311fa8e 100644 --- a/services/core/java/com/android/server/connectivity/MetricsLoggerService.java +++ b/services/core/java/com/android/server/connectivity/MetricsLoggerService.java @@ -144,8 +144,13 @@ public class MetricsLoggerService extends SystemService { boolean dumpSerializedSize = false; boolean dumpEvents = false; + boolean dumpDebugInfo = false; for (String arg : args) { switch (arg) { + case "--debug": + dumpDebugInfo = true; + break; + case "--events": dumpEvents = true; break; @@ -155,6 +160,7 @@ public class MetricsLoggerService extends SystemService { break; case "--all": + dumpDebugInfo = true; dumpEvents = true; dumpSerializedSize = true; break; @@ -163,6 +169,7 @@ public class MetricsLoggerService extends SystemService { synchronized (mEvents) { pw.println("Number of events: " + mEvents.size()); + pw.println("Counter: " + mEventCounter); if (mEvents.size() > 0) { pw.println("Time span: " + DateUtils.formatElapsedTime( @@ -171,16 +178,12 @@ public class MetricsLoggerService extends SystemService { } if (dumpSerializedSize) { - long dataSize = 0; Parcel p = Parcel.obtain(); for (ConnectivityMetricsEvent e : mEvents) { - dataSize += 16; // timestamp and 2 stamps - - p.writeParcelable(e.data, 0); + p.writeParcelable(e, 0); } - dataSize += p.dataSize(); + pw.println("Serialized data size: " + p.dataSize()); p.recycle(); - pw.println("Serialized data size: " + dataSize); } if (dumpEvents) { @@ -192,11 +195,28 @@ public class MetricsLoggerService extends SystemService { } } - if (!mPendingIntents.isEmpty()) { - pw.println(); - pw.println("Pending intents:"); - for (PendingIntent pi : mPendingIntents) { - pw.println(pi.toString()); + if (dumpDebugInfo) { + synchronized (mThrottlingCounters) { + pw.println(); + for (int i = 0; i < ConnectivityMetricsLogger.NUMBER_OF_COMPONENTS; i++) { + if (mThrottlingCounters[i] > 0) { + pw.println("Throttling Counter #" + i + ": " + mThrottlingCounters[i]); + } + } + pw.println("Throttling Time Remaining: " + + DateUtils.formatElapsedTime( + (mThrottlingIntervalBoundaryMillis - System.currentTimeMillis()) + / 1000)); + } + } + + synchronized (mPendingIntents) { + if (!mPendingIntents.isEmpty()) { + pw.println(); + pw.println("Pending intents:"); + for (PendingIntent pi : mPendingIntents) { + pw.println(pi.toString()); + } } } @@ -327,9 +347,9 @@ public class MetricsLoggerService extends SystemService { result[i++] = e; } } - } - reference.setValue(mLastEventReference); + reference.setValue(mLastEventReference); + } return result; } diff --git a/services/core/java/com/android/server/connectivity/NetworkMonitor.java b/services/core/java/com/android/server/connectivity/NetworkMonitor.java index f7784acc09c7..f4e14246cd8a 100644 --- a/services/core/java/com/android/server/connectivity/NetworkMonitor.java +++ b/services/core/java/com/android/server/connectivity/NetworkMonitor.java @@ -71,7 +71,11 @@ import com.android.server.connectivity.NetworkAgentInfo; import java.io.IOException; import java.net.HttpURLConnection; import java.net.InetAddress; +import java.net.MalformedURLException; +import java.net.UnknownHostException; import java.net.URL; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicReference; import java.util.List; import java.util.Random; @@ -228,7 +232,8 @@ public class NetworkMonitor extends StateMachine { private final AlarmManager mAlarmManager; private final NetworkRequest mDefaultRequest; - private boolean mIsCaptivePortalCheckEnabled = false; + private boolean mIsCaptivePortalCheckEnabled; + private boolean mUseHttps; // Set if the user explicitly selected "Do not use this network" in captive portal sign-in app. private boolean mUserDoesNotWant = false; @@ -276,6 +281,8 @@ public class NetworkMonitor extends StateMachine { mIsCaptivePortalCheckEnabled = Settings.Global.getInt(mContext.getContentResolver(), Settings.Global.CAPTIVE_PORTAL_DETECTION_ENABLED, 1) == 1; + mUseHttps = Settings.Global.getInt(mContext.getContentResolver(), + Settings.Global.CAPTIVE_PORTAL_USE_HTTPS, 1) == 1; start(); } @@ -324,6 +331,21 @@ public class NetworkMonitor extends StateMachine { return HANDLED; case CMD_CAPTIVE_PORTAL_APP_FINISHED: log("CaptivePortal App responded with " + message.arg1); + + // If the user has seen and acted on a captive portal notification, and the + // captive portal app is now closed, disable HTTPS probes. This avoids the + // following pathological situation: + // + // 1. HTTP probe returns a captive portal, HTTPS probe fails or times out. + // 2. User opens the app and logs into the captive portal. + // 3. HTTP starts working, but HTTPS still doesn't work for some other reason - + // perhaps due to the network blocking HTTPS? + // + // In this case, we'll fail to validate the network even after the app is + // dismissed. There is now no way to use this network, because the app is now + // gone, so the user cannot select "Use this network as is". + mUseHttps = false; + switch (message.arg1) { case APP_RETURN_DISMISSED: sendMessage(CMD_FORCE_REEVALUATION, 0 /* no UID */, 0); @@ -424,6 +446,8 @@ public class NetworkMonitor extends StateMachine { */ @VisibleForTesting public static final class CaptivePortalProbeResult { + static final CaptivePortalProbeResult FAILED = new CaptivePortalProbeResult(599, null); + final int mHttpResponseCode; // HTTP response code returned from Internet probe. final String mRedirectUrl; // Redirect destination returned from Internet probe. @@ -431,6 +455,11 @@ public class NetworkMonitor extends StateMachine { mHttpResponseCode = httpResponseCode; mRedirectUrl = redirectUrl; } + + boolean isSuccessful() { return mHttpResponseCode == 204; } + boolean isPortal() { + return !isSuccessful() && mHttpResponseCode >= 200 && mHttpResponseCode <= 399; + } } // Being in the EvaluatingState State indicates the Network is being evaluated for internet @@ -481,6 +510,7 @@ public class NetworkMonitor extends StateMachine { // expensive metered network, or unwanted leaking of the User Agent string. if (!mDefaultRequest.networkCapabilities.satisfiedByNetworkCapabilities( mNetworkAgentInfo.networkCapabilities)) { + validationLog("Network would not satisfy default request, not validating"); transitionTo(mValidatedState); return HANDLED; } @@ -492,10 +522,9 @@ public class NetworkMonitor extends StateMachine { // will be unresponsive. isCaptivePortal() could be executed on another Thread // if this is found to cause problems. CaptivePortalProbeResult probeResult = isCaptivePortal(); - if (probeResult.mHttpResponseCode == 204) { + if (probeResult.isSuccessful()) { transitionTo(mValidatedState); - } else if (probeResult.mHttpResponseCode >= 200 && - probeResult.mHttpResponseCode <= 399) { + } else if (probeResult.isPortal()) { mConnectivityServiceHandler.sendMessage(obtainMessage(EVENT_NETWORK_TESTED, NETWORK_TEST_RESULT_INVALID, mNetId, probeResult.mRedirectUrl)); transitionTo(mCaptivePortalState); @@ -659,72 +688,127 @@ public class NetworkMonitor extends StateMachine { } } - public static String getCaptivePortalServerUrl(Context context) { + private static String getCaptivePortalServerUrl(Context context, boolean isHttps) { String server = Settings.Global.getString(context.getContentResolver(), Settings.Global.CAPTIVE_PORTAL_SERVER); if (server == null) server = DEFAULT_SERVER; - return "http://" + server + "/generate_204"; + return (isHttps ? "https" : "http") + "://" + server + "/generate_204"; + } + + public static String getCaptivePortalServerUrl(Context context) { + return getCaptivePortalServerUrl(context, false); } - /** - * Do a URL fetch on a known server to see if we get the data we expect. - * Returns HTTP response code. - */ @VisibleForTesting protected CaptivePortalProbeResult isCaptivePortal() { if (!mIsCaptivePortalCheckEnabled) return new CaptivePortalProbeResult(204, null); - HttpURLConnection urlConnection = null; - int httpResponseCode = 599; - String redirectUrl = null; - final Stopwatch probeTimer = new Stopwatch().start(); - try { - URL url = new URL(getCaptivePortalServerUrl(mContext)); - // On networks with a PAC instead of fetching a URL that should result in a 204 - // response, we instead simply fetch the PAC script. This is done for a few reasons: - // 1. At present our PAC code does not yet handle multiple PACs on multiple networks - // until something like https://android-review.googlesource.com/#/c/115180/ lands. - // Network.openConnection() will ignore network-specific PACs and instead fetch - // using NO_PROXY. If a PAC is in place, the only fetch we know will succeed with - // NO_PROXY is the fetch of the PAC itself. - // 2. To proxy the generate_204 fetch through a PAC would require a number of things - // happen before the fetch can commence, namely: - // a) the PAC script be fetched - // b) a PAC script resolver service be fired up and resolve the captive portal - // server. - // Network validation could be delayed until these prerequisities are satisifed or - // could simply be left to race them. Neither is an optimal solution. - // 3. PAC scripts are sometimes used to block or restrict Internet access and may in - // fact block fetching of the generate_204 URL which would lead to false negative - // results for network validation. - boolean fetchPac = false; - final ProxyInfo proxyInfo = mNetworkAgentInfo.linkProperties.getHttpProxy(); - if (proxyInfo != null && !Uri.EMPTY.equals(proxyInfo.getPacFileUrl())) { - url = new URL(proxyInfo.getPacFileUrl().toString()); - fetchPac = true; + URL pacUrl = null, httpUrl = null, httpsUrl = null; + + // On networks with a PAC instead of fetching a URL that should result in a 204 + // response, we instead simply fetch the PAC script. This is done for a few reasons: + // 1. At present our PAC code does not yet handle multiple PACs on multiple networks + // until something like https://android-review.googlesource.com/#/c/115180/ lands. + // Network.openConnection() will ignore network-specific PACs and instead fetch + // using NO_PROXY. If a PAC is in place, the only fetch we know will succeed with + // NO_PROXY is the fetch of the PAC itself. + // 2. To proxy the generate_204 fetch through a PAC would require a number of things + // happen before the fetch can commence, namely: + // a) the PAC script be fetched + // b) a PAC script resolver service be fired up and resolve the captive portal + // server. + // Network validation could be delayed until these prerequisities are satisifed or + // could simply be left to race them. Neither is an optimal solution. + // 3. PAC scripts are sometimes used to block or restrict Internet access and may in + // fact block fetching of the generate_204 URL which would lead to false negative + // results for network validation. + final ProxyInfo proxyInfo = mNetworkAgentInfo.linkProperties.getHttpProxy(); + if (proxyInfo != null && !Uri.EMPTY.equals(proxyInfo.getPacFileUrl())) { + try { + pacUrl = new URL(proxyInfo.getPacFileUrl().toString()); + } catch (MalformedURLException e) { + validationLog("Invalid PAC URL: " + proxyInfo.getPacFileUrl().toString()); + return CaptivePortalProbeResult.FAILED; } - final StringBuffer connectInfo = new StringBuffer(); - String hostToResolve = null; - // Only resolve a host if HttpURLConnection is about to, to avoid any potentially - // unnecessary resolution. - if (proxyInfo == null || fetchPac) { - hostToResolve = url.getHost(); - } else if (proxyInfo != null) { - hostToResolve = proxyInfo.getHost(); + } + + if (pacUrl == null) { + try { + httpUrl = new URL(getCaptivePortalServerUrl(mContext, false)); + httpsUrl = new URL(getCaptivePortalServerUrl(mContext, true)); + } catch (MalformedURLException e) { + validationLog("Bad validation URL: " + getCaptivePortalServerUrl(mContext, false)); + return CaptivePortalProbeResult.FAILED; } - if (!TextUtils.isEmpty(hostToResolve)) { - connectInfo.append(", " + hostToResolve + "="); - final InetAddress[] addresses = - mNetworkAgentInfo.network.getAllByName(hostToResolve); + } + + long startTime = SystemClock.elapsedRealtime(); + + // Pre-resolve the captive portal server host so we can log it. + // Only do this if HttpURLConnection is about to, to avoid any potentially + // unnecessary resolution. + String hostToResolve = null; + if (pacUrl != null) { + hostToResolve = pacUrl.getHost(); + } else if (proxyInfo != null) { + hostToResolve = proxyInfo.getHost(); + } else { + hostToResolve = httpUrl.getHost(); + } + + if (!TextUtils.isEmpty(hostToResolve)) { + String probeName = ValidationProbeEvent.getProbeName(ValidationProbeEvent.PROBE_DNS); + final Stopwatch dnsTimer = new Stopwatch().start(); + try { + InetAddress[] addresses = mNetworkAgentInfo.network.getAllByName(hostToResolve); + long dnsLatency = dnsTimer.stop(); + ValidationProbeEvent.logEvent(mNetId, dnsLatency, + ValidationProbeEvent.PROBE_DNS, ValidationProbeEvent.DNS_SUCCESS); + final StringBuffer connectInfo = new StringBuffer(", " + hostToResolve + "="); for (InetAddress address : addresses) { connectInfo.append(address.getHostAddress()); if (address != addresses[addresses.length-1]) connectInfo.append(","); } + validationLog(probeName + " OK " + dnsLatency + "ms" + connectInfo); + } catch (UnknownHostException e) { + long dnsLatency = dnsTimer.stop(); + ValidationProbeEvent.logEvent(mNetId, dnsLatency, + ValidationProbeEvent.PROBE_DNS, ValidationProbeEvent.DNS_FAILURE); + validationLog(probeName + " FAIL " + dnsLatency + "ms, " + hostToResolve); } - validationLog("Checking " + url.toString() + " on " + - mNetworkAgentInfo.networkInfo.getExtraInfo() + connectInfo); + } + + CaptivePortalProbeResult result; + if (pacUrl != null) { + result = sendHttpProbe(pacUrl, ValidationProbeEvent.PROBE_PAC); + } else if (mUseHttps) { + result = sendParallelHttpProbes(httpsUrl, httpUrl); + } else { + result = sendHttpProbe(httpUrl, ValidationProbeEvent.PROBE_HTTP); + } + + long endTime = SystemClock.elapsedRealtime(); + + sendNetworkConditionsBroadcast(true /* response received */, + result.isPortal() /* isCaptivePortal */, + startTime, endTime); + + return result; + } + + /** + * Do a URL fetch on a known server to see if we get the data we expect. + * Returns HTTP response code. + */ + @VisibleForTesting + protected CaptivePortalProbeResult sendHttpProbe(URL url, int probeType) { + HttpURLConnection urlConnection = null; + int httpResponseCode = 599; + String redirectUrl = null; + final Stopwatch probeTimer = new Stopwatch().start(); + try { urlConnection = (HttpURLConnection) mNetworkAgentInfo.network.openConnection(url); - urlConnection.setInstanceFollowRedirects(fetchPac); + urlConnection.setInstanceFollowRedirects(probeType == ValidationProbeEvent.PROBE_PAC); urlConnection.setConnectTimeout(SOCKET_TIMEOUT_MS); urlConnection.setReadTimeout(SOCKET_TIMEOUT_MS); urlConnection.setUseCaches(false); @@ -738,7 +822,9 @@ public class NetworkMonitor extends StateMachine { // Time how long it takes to get a response to our request long responseTimestamp = SystemClock.elapsedRealtime(); - validationLog("isCaptivePortal: ret=" + httpResponseCode + + validationLog(ValidationProbeEvent.getProbeName(probeType) + " " + url + + " time=" + (responseTimestamp - requestTimestamp) + "ms" + + " ret=" + httpResponseCode + " headers=" + urlConnection.getHeaderFields()); // NOTE: We may want to consider an "HTTP/1.0 204" response to be a captive // portal. The only example of this seen so far was a captive portal. For @@ -756,14 +842,10 @@ public class NetworkMonitor extends StateMachine { httpResponseCode = 204; } - if (httpResponseCode == 200 && fetchPac) { + if (httpResponseCode == 200 && probeType == ValidationProbeEvent.PROBE_PAC) { validationLog("PAC fetch 200 response interpreted as 204 response."); httpResponseCode = 204; } - - sendNetworkConditionsBroadcast(true /* response received */, - httpResponseCode != 204 /* isCaptivePortal */, - requestTimestamp, responseTimestamp); } catch (IOException e) { validationLog("Probably not a portal: exception " + e); if (httpResponseCode == 599) { @@ -774,11 +856,68 @@ public class NetworkMonitor extends StateMachine { urlConnection.disconnect(); } } - final int probeType = ValidationProbeEvent.PROBE_HTTP; ValidationProbeEvent.logEvent(mNetId, probeTimer.stop(), probeType, httpResponseCode); return new CaptivePortalProbeResult(httpResponseCode, redirectUrl); } + private CaptivePortalProbeResult sendParallelHttpProbes(URL httpsUrl, URL httpUrl) { + // Number of probes to wait for. We might wait for all of them, but we might also return if + // only one of them has replied. For example, we immediately return if the HTTP probe finds + // a captive portal, even if the HTTPS probe is timing out. + final CountDownLatch latch = new CountDownLatch(2); + + // Which probe result we're going to use. This doesn't need to be atomic, but it does need + // to be final because otherwise we can't set it from the ProbeThreads. + final AtomicReference<CaptivePortalProbeResult> finalResult = new AtomicReference<>(); + + final class ProbeThread extends Thread { + private final boolean mIsHttps; + private volatile CaptivePortalProbeResult mResult; + + public ProbeThread(boolean isHttps) { + mIsHttps = isHttps; + } + + public CaptivePortalProbeResult getResult() { + return mResult; + } + + @Override + public void run() { + if (mIsHttps) { + mResult = sendHttpProbe(httpsUrl, ValidationProbeEvent.PROBE_HTTPS); + } else { + mResult = sendHttpProbe(httpUrl, ValidationProbeEvent.PROBE_HTTP); + } + if ((mIsHttps && mResult.isSuccessful()) || (!mIsHttps && mResult.isPortal())) { + // HTTPS succeeded, or HTTP found a portal. Don't wait for the other probe. + finalResult.compareAndSet(null, mResult); + latch.countDown(); + } + // Signal that one probe has completed. If we've already made a decision, or if this + // is the second probe, the latch will be at zero and we'll return a result. + latch.countDown(); + } + } + + ProbeThread httpsProbe = new ProbeThread(true); + ProbeThread httpProbe = new ProbeThread(false); + httpsProbe.start(); + httpProbe.start(); + + try { + latch.await(); + } catch (InterruptedException e) { + validationLog("Error: probe wait interrupted!"); + return CaptivePortalProbeResult.FAILED; + } + + // If there was no deciding probe, that means that both probes completed. Return HTTPS. + finalResult.compareAndSet(null, httpsProbe.getResult()); + + return finalResult.get(); + } + /** * @param responseReceived - whether or not we received a valid HTTP response to our request. * If false, isCaptivePortal and responseTimestampMs are ignored diff --git a/services/core/java/com/android/server/content/ContentService.java b/services/core/java/com/android/server/content/ContentService.java index 03eb019bd3f8..2103cce63233 100644 --- a/services/core/java/com/android/server/content/ContentService.java +++ b/services/core/java/com/android/server/content/ContentService.java @@ -352,6 +352,10 @@ public final class ContentService extends IContentService.Stub { if (DEBUG) Slog.d(TAG, "Notifying update of " + uri + " for user " + userHandle + " from observer " + observer + ", flags " + Integer.toHexString(flags)); + if (uri == null) { + throw new NullPointerException("Uri must not be null"); + } + final int uid = Binder.getCallingUid(); final int pid = Binder.getCallingPid(); final int callingUserHandle = UserHandle.getCallingUserId(); diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java index fcf216240a07..493fc4a4bb8c 100644 --- a/services/core/java/com/android/server/content/SyncManager.java +++ b/services/core/java/com/android/server/content/SyncManager.java @@ -396,8 +396,8 @@ public class SyncManager { onUserRemoved(userId); } else if (Intent.ACTION_USER_UNLOCKED.equals(action)) { onUserUnlocked(userId); - } else if (Intent.ACTION_USER_STOPPING.equals(action)) { - onUserStopping(userId); + } else if (Intent.ACTION_USER_STOPPED.equals(action)) { + onUserStopped(userId); } } }; @@ -550,7 +550,7 @@ public class SyncManager { intentFilter = new IntentFilter(); intentFilter.addAction(Intent.ACTION_USER_REMOVED); intentFilter.addAction(Intent.ACTION_USER_UNLOCKED); - intentFilter.addAction(Intent.ACTION_USER_STOPPING); + intentFilter.addAction(Intent.ACTION_USER_STOPPED); mContext.registerReceiverAsUser( mUserIntentReceiver, UserHandle.ALL, intentFilter, null, null); @@ -1422,7 +1422,7 @@ public class SyncManager { } } - private void onUserStopping(int userId) { + private void onUserStopped(int userId) { updateRunningAccounts(null /* Don't sync any target */); cancelActiveSync( diff --git a/services/core/java/com/android/server/fingerprint/EnrollClient.java b/services/core/java/com/android/server/fingerprint/EnrollClient.java index b636ce56e01c..6a533c9b4e7b 100644 --- a/services/core/java/com/android/server/fingerprint/EnrollClient.java +++ b/services/core/java/com/android/server/fingerprint/EnrollClient.java @@ -51,7 +51,8 @@ public abstract class EnrollClient extends ClientMonitor { " getGroupId():" + getGroupId()); } if (remaining == 0) { - FingerprintUtils.getInstance().addFingerprintForUser(getContext(), fingerId, groupId); + FingerprintUtils.getInstance().addFingerprintForUser(getContext(), fingerId, + getTargetUserId()); } return sendEnrollResult(fingerId, groupId, remaining); } diff --git a/services/core/java/com/android/server/fingerprint/FingerprintService.java b/services/core/java/com/android/server/fingerprint/FingerprintService.java index 9a2db8e32cc9..ae01635c0905 100644 --- a/services/core/java/com/android/server/fingerprint/FingerprintService.java +++ b/services/core/java/com/android/server/fingerprint/FingerprintService.java @@ -540,13 +540,15 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe startClient(client, true /* initiatedByClient */); } - private void startEnrollment(IBinder token, byte [] cryptoToken, int callingUserId, int groupId, + private void startEnrollment(IBinder token, byte [] cryptoToken, int userId, IFingerprintServiceReceiver receiver, int flags, boolean restricted, String opPackageName) { - updateActiveGroup(groupId, opPackageName); + updateActiveGroup(userId, opPackageName); + + final int groupId = userId; // default group for fingerprint enrollment EnrollClient client = new EnrollClient(getContext(), mHalDeviceId, token, receiver, - callingUserId, groupId, cryptoToken, restricted, opPackageName) { + userId, groupId, cryptoToken, restricted, opPackageName) { @Override public IFingerprintDaemon getFingerprintDaemon() { @@ -680,15 +682,14 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe } @Override // Binder call - public void enroll(final IBinder token, final byte[] cryptoToken, final int groupId, + public void enroll(final IBinder token, final byte[] cryptoToken, final int userId, final IFingerprintServiceReceiver receiver, final int flags, final String opPackageName) { checkPermission(MANAGE_FINGERPRINT); final int limit = mContext.getResources().getInteger( com.android.internal.R.integer.config_fingerprintMaxTemplatesPerUser); - final int callingUserId = UserHandle.getCallingUserId(); - final int enrolled = FingerprintService.this. - getEnrolledFingerprints(callingUserId).size(); + + final int enrolled = FingerprintService.this.getEnrolledFingerprints(userId).size(); if (enrolled >= limit) { Slog.w(TAG, "Too many fingerprints registered"); return; @@ -696,7 +697,7 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe // Group ID is arbitrarily set to parent profile user ID. It just represents // the default fingerprints for the user. - if (!isCurrentUserOrProfile(groupId)) { + if (!isCurrentUserOrProfile(userId)) { return; } @@ -704,7 +705,7 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe mHandler.post(new Runnable() { @Override public void run() { - startEnrollment(token, cryptoToken, callingUserId, groupId, receiver, flags, + startEnrollment(token, cryptoToken, userId, receiver, flags, restricted, opPackageName); } }); diff --git a/services/core/java/com/android/server/job/JobStore.java b/services/core/java/com/android/server/job/JobStore.java index 5ad988a42792..1f7d3128d655 100644 --- a/services/core/java/com/android/server/job/JobStore.java +++ b/services/core/java/com/android/server/job/JobStore.java @@ -333,6 +333,7 @@ public class JobStore { out.attribute(null, "sourceUserId", String.valueOf(jobStatus.getSourceUserId())); out.attribute(null, "uid", Integer.toString(jobStatus.getUid())); out.attribute(null, "priority", String.valueOf(jobStatus.getPriority())); + out.attribute(null, "flags", String.valueOf(jobStatus.getFlags())); } private void writeBundleToXml(PersistableBundle extras, XmlSerializer out) @@ -543,6 +544,10 @@ public class JobStore { if (val != null) { jobBuilder.setPriority(Integer.parseInt(val)); } + val = parser.getAttributeValue(null, "flags"); + if (val != null) { + jobBuilder.setFlags(Integer.parseInt(val)); + } val = parser.getAttributeValue(null, "sourceUserId"); sourceUserId = val == null ? -1 : Integer.parseInt(val); } catch (NumberFormatException e) { diff --git a/services/core/java/com/android/server/job/controllers/ConnectivityController.java b/services/core/java/com/android/server/job/controllers/ConnectivityController.java index 88cf322ed913..f5aac087f9b0 100644 --- a/services/core/java/com/android/server/job/controllers/ConnectivityController.java +++ b/services/core/java/com/android/server/job/controllers/ConnectivityController.java @@ -16,6 +16,7 @@ package com.android.server.job.controllers; +import android.app.job.JobInfo; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; @@ -97,7 +98,9 @@ public class ConnectivityController extends StateController implements } private boolean updateConstraintsSatisfied(JobStatus jobStatus) { - final NetworkInfo info = mConnManager.getActiveNetworkInfoForUid(jobStatus.getSourceUid()); + final boolean ignoreBlocked = (jobStatus.getFlags() & JobInfo.FLAG_WILL_BE_FOREGROUND) != 0; + final NetworkInfo info = mConnManager.getActiveNetworkInfoForUid(jobStatus.getSourceUid(), + ignoreBlocked); final boolean connected = (info != null) && info.isConnected(); final boolean unmetered = connected && !info.isMetered(); final boolean notRoaming = connected && !info.isRoaming(); diff --git a/services/core/java/com/android/server/job/controllers/JobStatus.java b/services/core/java/com/android/server/job/controllers/JobStatus.java index 590d075446cf..19bede97c503 100644 --- a/services/core/java/com/android/server/job/controllers/JobStatus.java +++ b/services/core/java/com/android/server/job/controllers/JobStatus.java @@ -297,6 +297,10 @@ public final class JobStatus { return job.getPriority(); } + public int getFlags() { + return job.getFlags(); + } + public boolean hasConnectivityConstraint() { return (requiredConstraints&CONSTRAINT_CONNECTIVITY) != 0; } @@ -416,12 +420,12 @@ public final class JobStatus { // satisfied). // AppNotIdle implicit constraint must be satisfied // DeviceNotDozing implicit constraint must be satisfied - return (isConstraintsSatisfied() - || (!job.isPeriodic() - && hasDeadlineConstraint() && (satisfiedConstraints&CONSTRAINT_DEADLINE) != 0) - ) - && (satisfiedConstraints & CONSTRAINT_APP_NOT_IDLE) != 0 - && (satisfiedConstraints & CONSTRAINT_DEVICE_NOT_DOZING) != 0; + final boolean deadlineSatisfied = (!job.isPeriodic() && hasDeadlineConstraint() + && (satisfiedConstraints & CONSTRAINT_DEADLINE) != 0); + final boolean notIdle = (satisfiedConstraints & CONSTRAINT_APP_NOT_IDLE) != 0; + final boolean notDozing = (satisfiedConstraints & CONSTRAINT_DEVICE_NOT_DOZING) != 0 + || (job.getFlags() & JobInfo.FLAG_WILL_BE_FOREGROUND) != 0; + return (isConstraintsSatisfied() || deadlineSatisfied) && notIdle && notDozing; } static final int CONSTRAINTS_OF_INTEREST = @@ -561,6 +565,10 @@ public final class JobStatus { if (job.getPriority() != 0) { pw.print(prefix); pw.print(" Priority: "); pw.println(job.getPriority()); } + if (job.getFlags() != 0) { + pw.print(prefix); pw.print(" Flags: "); + pw.println(Integer.toHexString(job.getFlags())); + } pw.print(prefix); pw.print(" Requires: charging="); pw.print(job.isRequireCharging()); pw.print(" deviceIdle="); pw.println(job.isRequireDeviceIdle()); @@ -613,6 +621,9 @@ public final class JobStatus { pw.print(prefix); pw.print("Satisfied constraints:"); dumpConstraints(pw, satisfiedConstraints); pw.println(); + pw.print(prefix); pw.print("Unsatisfied constraints:"); + dumpConstraints(pw, (requiredConstraints & ~satisfiedConstraints)); + pw.println(); } if (changedAuthorities != null) { pw.print(prefix); pw.println("Changed authorities:"); diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java index 0b1ece5ab2dd..50d936853fed 100644 --- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java +++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java @@ -48,7 +48,6 @@ import static android.net.NetworkPolicyManager.FIREWALL_RULE_DEFAULT; import static android.net.NetworkPolicyManager.FIREWALL_RULE_DENY; import static android.net.NetworkPolicyManager.POLICY_NONE; import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND; -import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL; import static android.net.NetworkPolicyManager.RULE_ALLOW_METERED; import static android.net.NetworkPolicyManager.RULE_REJECT_METERED; import static android.net.NetworkPolicyManager.RULE_TEMPORARY_ALLOW_METERED; @@ -349,6 +348,9 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { /** Foreground at UID granularity. */ final SparseIntArray mUidState = new SparseIntArray(); + /** Higher priority listener before general event dispatch */ + private INetworkPolicyListener mConnectivityListener; + private final RemoteCallbackList<INetworkPolicyListener> mListeners = new RemoteCallbackList<>(); @@ -465,7 +467,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { continue; } for (int j = 0; j < numberUsers; j++) { - final UserInfo user = users.get(i); + final UserInfo user = users.get(j); final int uid = UserHandle.getUid(user.id, app.uid); mDefaultRestrictBackgroundWhitelistUids.append(uid, true); if (LOGD) Slog.d(TAG, "revoked whistelist status for uid " + uid + ": " @@ -1391,6 +1393,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { final String tag = in.getName(); if (type == START_TAG) { if (TAG_POLICY_LIST.equals(tag)) { + final boolean oldValue = mRestrictBackground; version = readIntAttribute(in, ATTR_VERSION); if (version >= VERSION_ADDED_RESTRICT_BACKGROUND) { mRestrictBackground = readBooleanAttribute( @@ -1398,6 +1401,12 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } else { mRestrictBackground = false; } + if (mRestrictBackground != oldValue) { + // Some early services may have read the default value, + // so notify them that it's changed + mHandler.obtainMessage(MSG_RESTRICT_BACKGROUND_CHANGED, + mRestrictBackground ? 1 : 0, 0).sendToTarget(); + } } else if (TAG_NETWORK_POLICY.equals(tag)) { final int networkTemplate = readIntAttribute(in, ATTR_NETWORK_TEMPLATE); @@ -1766,20 +1775,25 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } @Override + public void setConnectivityListener(INetworkPolicyListener listener) { + mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); + if (mConnectivityListener != null) { + throw new IllegalStateException("Connectivity listener already registered"); + } + mConnectivityListener = listener; + } + + @Override public void registerListener(INetworkPolicyListener listener) { // TODO: create permission for observing network policy mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); - mListeners.register(listener); - - // TODO: consider dispatching existing rules to new listeners } @Override public void unregisterListener(INetworkPolicyListener listener) { // TODO: create permission for observing network policy mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); - mListeners.unregister(listener); } @@ -2754,8 +2768,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { final boolean isBlacklisted = (uidPolicy & POLICY_REJECT_METERED_BACKGROUND) != 0; final boolean isWhitelisted = mRestrictBackgroundWhitelistUids.get(uid); - int newRule = RULE_ALLOW_ALL; - final int oldRule = mUidRules.get(uid); + int newRule = RULE_UNKNOWN; + final int oldRule = mUidRules.get(uid, RULE_UNKNOWN); // First step: define the new rule based on user restrictions and foreground state. if (isForeground) { @@ -2777,8 +2791,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { + ", oldRule: " + ruleToString(oldRule)); } - - if (newRule == RULE_ALLOW_ALL) { + if (newRule == RULE_UNKNOWN) { mUidRules.delete(uid); } else { mUidRules.put(uid, newRule); @@ -2858,6 +2871,45 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } } + private void dispatchUidRulesChanged(INetworkPolicyListener listener, int uid, int uidRules) { + if (listener != null) { + try { + listener.onUidRulesChanged(uid, uidRules); + } catch (RemoteException ignored) { + } + } + } + + private void dispatchMeteredIfacesChanged(INetworkPolicyListener listener, + String[] meteredIfaces) { + if (listener != null) { + try { + listener.onMeteredIfacesChanged(meteredIfaces); + } catch (RemoteException ignored) { + } + } + } + + private void dispatchRestrictBackgroundChanged(INetworkPolicyListener listener, + boolean restrictBackground) { + if (listener != null) { + try { + listener.onRestrictBackgroundChanged(restrictBackground); + } catch (RemoteException ignored) { + } + } + } + + private void dispatchRestrictBackgroundWhitelistChanged(INetworkPolicyListener listener, + int uid, boolean whitelisted) { + if (listener != null) { + try { + listener.onRestrictBackgroundWhitelistChanged(uid, whitelisted); + } catch (RemoteException ignored) { + } + } + } + private Handler.Callback mHandlerCallback = new Handler.Callback() { @Override public boolean handleMessage(Message msg) { @@ -2865,30 +2917,22 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { case MSG_RULES_CHANGED: { final int uid = msg.arg1; final int uidRules = msg.arg2; + dispatchUidRulesChanged(mConnectivityListener, uid, uidRules); final int length = mListeners.beginBroadcast(); for (int i = 0; i < length; i++) { final INetworkPolicyListener listener = mListeners.getBroadcastItem(i); - if (listener != null) { - try { - listener.onUidRulesChanged(uid, uidRules); - } catch (RemoteException e) { - } - } + dispatchUidRulesChanged(listener, uid, uidRules); } mListeners.finishBroadcast(); return true; } case MSG_METERED_IFACES_CHANGED: { final String[] meteredIfaces = (String[]) msg.obj; + dispatchMeteredIfacesChanged(mConnectivityListener, meteredIfaces); final int length = mListeners.beginBroadcast(); for (int i = 0; i < length; i++) { final INetworkPolicyListener listener = mListeners.getBroadcastItem(i); - if (listener != null) { - try { - listener.onMeteredIfacesChanged(meteredIfaces); - } catch (RemoteException e) { - } - } + dispatchMeteredIfacesChanged(listener, meteredIfaces); } mListeners.finishBroadcast(); return true; @@ -2915,15 +2959,11 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } case MSG_RESTRICT_BACKGROUND_CHANGED: { final boolean restrictBackground = msg.arg1 != 0; + dispatchRestrictBackgroundChanged(mConnectivityListener, restrictBackground); final int length = mListeners.beginBroadcast(); for (int i = 0; i < length; i++) { final INetworkPolicyListener listener = mListeners.getBroadcastItem(i); - if (listener != null) { - try { - listener.onRestrictBackgroundChanged(restrictBackground); - } catch (RemoteException e) { - } - } + dispatchRestrictBackgroundChanged(listener, restrictBackground); } mListeners.finishBroadcast(); final Intent intent = @@ -2947,18 +2987,16 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { final boolean changed = msg.arg2 == 1; final Boolean whitelisted = (Boolean) msg.obj; + // First notify internal listeners... if (whitelisted != null) { + final boolean whitelistedBool = whitelisted.booleanValue(); + dispatchRestrictBackgroundWhitelistChanged(mConnectivityListener, uid, + whitelistedBool); final int length = mListeners.beginBroadcast(); for (int i = 0; i < length; i++) { - // First notify internal listeners... final INetworkPolicyListener listener = mListeners.getBroadcastItem(i); - if (listener != null) { - try { - listener.onRestrictBackgroundWhitelistChanged(uid, - whitelisted.booleanValue()); - } catch (RemoteException e) { - } - } + dispatchRestrictBackgroundWhitelistChanged(listener, uid, + whitelistedBool); } mListeners.finishBroadcast(); } diff --git a/services/core/java/com/android/server/pm/OtaDexoptService.java b/services/core/java/com/android/server/pm/OtaDexoptService.java index 50b86708c14a..649a27cb7cd6 100644 --- a/services/core/java/com/android/server/pm/OtaDexoptService.java +++ b/services/core/java/com/android/server/pm/OtaDexoptService.java @@ -22,9 +22,7 @@ import static com.android.server.pm.InstructionSets.getDexCodeInstructionSets; import static com.android.server.pm.PackageManagerServiceCompilerMapping.getCompilerFilterForReason; import android.content.Context; -import android.content.pm.ApplicationInfo; import android.content.pm.IOtaDexopt; -import android.content.pm.PackageManager; import android.content.pm.PackageParser; import android.os.Environment; import android.os.RemoteException; diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java index 83681853898c..83af0173c514 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerService.java +++ b/services/core/java/com/android/server/pm/PackageInstallerService.java @@ -866,8 +866,9 @@ public class PackageInstallerService extends IPackageInstaller.Stub { if ((callingUid != Process.SHELL_UID) && (callingUid != Process.ROOT_UID)) { mAppOps.checkPackage(callingUid, callerPackageName); final String installerPackageName = mPm.getInstallerPackageName(packageName); - allowSilentUninstall = installerPackageName != null - && installerPackageName.equals(callerPackageName); + allowSilentUninstall = mPm.isOrphaned(packageName) || + (installerPackageName != null + && installerPackageName.equals(callerPackageName)); } // Check whether the caller is device owner, in which case we do it silently. diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 4b0eeedbe125..8fb7da48f437 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -266,6 +266,7 @@ 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.FileReader; @@ -274,6 +275,7 @@ import java.io.IOException; import java.io.InputStream; import java.io.PrintWriter; import java.nio.charset.StandardCharsets; +import java.security.DigestInputStream; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.PublicKey; @@ -437,6 +439,8 @@ public class PackageManagerService extends IPackageManager.Stub { */ private static final int DEFAULT_VERIFICATION_RESPONSE = PackageManager.VERIFICATION_ALLOW; + static final String PLATFORM_PACKAGE_NAME = "android"; + static final String DEFAULT_CONTAINER_PACKAGE = "com.android.defcontainer"; static final ComponentName DEFAULT_CONTAINER_COMPONENT = new ComponentName( @@ -498,8 +502,8 @@ public class PackageManagerService extends IPackageManager.Stub { public static final int REASON_LAST = REASON_FORCED_DEXOPT; - // Special String to skip shared libraries check during compilation. - private static final String SPECIAL_SHARED_LIBRARY = "&"; + /** Special library name that skips shared libraries check during compilation. */ + private static final String SKIP_SHARED_LIBRARY_CHECK = "&"; final ServiceThread mHandlerThread; @@ -1570,6 +1574,7 @@ public class PackageManagerService extends IPackageManager.Stub { if (DEBUG_INSTALL) Log.v(TAG, "Handling post-install for " + msg.arg1); PostInstallData data = mRunningInstalls.get(msg.arg1); + final boolean didRestore = (msg.arg2 != 0); mRunningInstalls.delete(msg.arg1); if (data != null) { @@ -1584,7 +1589,8 @@ public class PackageManagerService extends IPackageManager.Stub { // Handle the parent package handlePackagePostInstall(parentRes, grantPermissions, killApp, - grantedPermissions, args.observer); + grantedPermissions, didRestore, args.installerPackageName, + args.observer); // Handle the child packages final int childCount = (parentRes.addedChildPackages != null) @@ -1592,7 +1598,8 @@ public class PackageManagerService extends IPackageManager.Stub { for (int i = 0; i < childCount; i++) { PackageInstalledInfo childRes = parentRes.addedChildPackages.valueAt(i); handlePackagePostInstall(childRes, grantPermissions, killApp, - grantedPermissions, args.observer); + grantedPermissions, false, args.installerPackageName, + args.observer); } // Log tracing if needed @@ -1788,6 +1795,7 @@ public class PackageManagerService extends IPackageManager.Stub { private void handlePackagePostInstall(PackageInstalledInfo res, boolean grantPermissions, boolean killApp, String[] grantedPermissions, + boolean launchedForRestore, String installerPackage, IPackageInstallObserver2 installObserver) { if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) { // Send the removed broadcasts @@ -1872,6 +1880,14 @@ public class PackageManagerService extends IPackageManager.Stub { null /*package*/, null /*extras*/, 0 /*flags*/, packageName /*targetPackage*/, null /*finishedReceiver*/, updateUsers); + } else if (launchedForRestore && !isSystemApp(res.pkg)) { + // First-install and we did a restore, so we're responsible for the + // first-launch broadcast. + if (DEBUG_BACKUP) { + Slog.i(TAG, "Post-restore of " + packageName + + " sending FIRST_LAUNCH in " + Arrays.toString(firstUsers)); + } + sendFirstLaunchBroadcast(packageName, installerPackage, firstUsers); } // Send broadcast package appeared if forward locked/external for all users @@ -2336,7 +2352,7 @@ public class PackageManagerService extends IPackageManager.Stub { dexoptNeeded, DEXOPT_PUBLIC /*dexFlags*/, getCompilerFilterForReason(REASON_SHARED_APK), StorageManager.UUID_PRIVATE_INTERNAL, - SPECIAL_SHARED_LIBRARY); + SKIP_SHARED_LIBRARY_CHECK); } } catch (FileNotFoundException e) { Slog.w(TAG, "Library not found: " + lib); @@ -2662,14 +2678,8 @@ public class PackageManagerService extends IPackageManager.Stub { // Prepare storage for system user really early during boot, // since core system apps like SettingsProvider and SystemUI // can't wait for user to start - final int storageFlags; - if (StorageManager.isFileEncryptedNativeOrEmulated()) { - storageFlags = StorageManager.FLAG_STORAGE_DE; - } else { - storageFlags = StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE; - } reconcileAppsDataLI(StorageManager.UUID_PRIVATE_INTERNAL, UserHandle.USER_SYSTEM, - storageFlags); + StorageManager.FLAG_STORAGE_DE); // If this is first boot after an OTA, and a normal boot, then // we need to clear code cache directories. @@ -3100,7 +3110,7 @@ public class PackageManagerService extends IPackageManager.Stub { @Override public void checkPackageStartable(String packageName, int userId) { - final boolean userKeyUnlocked = isUserKeyUnlocked(userId); + final boolean userKeyUnlocked = StorageManager.isUserKeyUnlocked(userId); synchronized (mPackages) { final PackageSetting ps = mSettings.mPackages.get(packageName); @@ -3451,30 +3461,6 @@ public class PackageManagerService extends IPackageManager.Stub { } /** - * Return if the user key is currently unlocked. - */ - private boolean isUserKeyUnlocked(int userId) { - if (StorageManager.isFileEncryptedNativeOrEmulated()) { - final IMountService mount = IMountService.Stub - .asInterface(ServiceManager.getService("mount")); - if (mount == null) { - Slog.w(TAG, "Early during boot, assuming locked"); - return false; - } - final long token = Binder.clearCallingIdentity(); - try { - return mount.isUserKeyUnlocked(userId); - } catch (RemoteException e) { - throw e.rethrowAsRuntimeException(); - } finally { - Binder.restoreCallingIdentity(token); - } - } else { - return true; - } - } - - /** * Update given flags based on encryption status of current user. */ private int updateFlags(int flags, int userId) { @@ -3485,7 +3471,7 @@ public class PackageManagerService extends IPackageManager.Stub { // give them what they want } else { // Caller expressed no opinion, so match based on user state - if (isUserKeyUnlocked(userId)) { + if (StorageManager.isUserKeyUnlocked(userId)) { flags |= PackageManager.MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE; } else { flags |= PackageManager.MATCH_DIRECT_BOOT_AWARE; @@ -9743,7 +9729,9 @@ public class PackageManagerService extends IPackageManager.Stub { switch (grant) { case GRANT_INSTALL: { // Revoke this as runtime permission to handle the case of - // a runtime permission being downgraded to an install one. Also in permission review mode we keep dangerous permissions for legacy apps + // a runtime permission being downgraded to an install one. + // Also in permission review mode we keep dangerous permissions + // for legacy apps for (int userId : UserManagerService.getInstance().getUserIds()) { if (origPermissions.getRuntimePermissionState( bp.name, userId) != null) { @@ -9791,10 +9779,21 @@ public class PackageManagerService extends IPackageManager.Stub { && !appSupportsRuntimePermissions) { // For legacy apps that need a permission review, every new // runtime permission is granted but it is pending a review. - if ((flags & FLAG_PERMISSION_REVIEW_REQUIRED) == 0) { - permissionsState.grantRuntimePermission(bp, userId); - flags |= FLAG_PERMISSION_REVIEW_REQUIRED; - // We changed the permission and flags, hence have to write. + // We also need to review only platform defined runtime + // permissions as these are the only ones the platform knows + // how to disable the API to simulate revocation as legacy + // apps don't expect to run with revoked permissions. + if (PLATFORM_PACKAGE_NAME.equals(bp.sourcePackage)) { + if ((flags & FLAG_PERMISSION_REVIEW_REQUIRED) == 0) { + flags |= FLAG_PERMISSION_REVIEW_REQUIRED; + // We changed the flags, hence have to write. + changedRuntimePermissionUserIds = ArrayUtils.appendInt( + changedRuntimePermissionUserIds, userId); + } + } + if (permissionsState.grantRuntimePermission(bp, userId) + != PermissionsState.PERMISSION_OPERATION_FAILURE) { + // We changed the permission, hence have to write. changedRuntimePermissionUserIds = ArrayUtils.appendInt( changedRuntimePermissionUserIds, userId); } @@ -11723,7 +11722,7 @@ public class PackageManagerService extends IPackageManager.Stub { } @Override - public void finishPackageInstall(int token) { + public void finishPackageInstall(int token, boolean didLaunch) { enforceSystemOrRoot("Only the system is allowed to finish installs"); if (DEBUG_INSTALL) { @@ -11731,7 +11730,7 @@ public class PackageManagerService extends IPackageManager.Stub { } Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "restore", token); - final Message msg = mHandler.obtainMessage(POST_INSTALL, token, 0); + final Message msg = mHandler.obtainMessage(POST_INSTALL, token, didLaunch ? 1 : 0); mHandler.sendMessage(msg); } @@ -12060,6 +12059,54 @@ public class PackageManagerService extends IPackageManager.Stub { }); } + /** + * Callback from PackageSettings whenever an app is first transitioned out of the + * 'stopped' state. Normally we just issue the broadcast, but we can't do that if + * the app was "launched" for a restoreAtInstall operation. Therefore we check + * here whether the app is the target of an ongoing install, and only send the + * broadcast immediately if it is not in that state. If it *is* undergoing a restore, + * the first-launch broadcast will be sent implicitly on that basis in POST_INSTALL + * handling. + */ + void notifyFirstLaunch(final String pkgName, final String installerPackage, final int userId) { + // Serialize this with the rest of the install-process message chain. In the + // restore-at-install case, this Runnable will necessarily run before the + // POST_INSTALL message is processed, so the contents of mRunningInstalls + // are coherent. In the non-restore case, the app has already completed install + // and been launched through some other means, so it is not in a problematic + // state for observers to see the FIRST_LAUNCH signal. + mHandler.post(new Runnable() { + @Override + public void run() { + for (int i = 0; i < mRunningInstalls.size(); i++) { + final PostInstallData data = mRunningInstalls.valueAt(i); + if (pkgName.equals(data.res.pkg.applicationInfo.packageName)) { + // right package; but is it for the right user? + for (int uIndex = 0; uIndex < data.res.newUsers.length; uIndex++) { + if (userId == data.res.newUsers[uIndex]) { + if (DEBUG_BACKUP) { + Slog.i(TAG, "Package " + pkgName + + " being restored so deferring FIRST_LAUNCH"); + } + return; + } + } + } + } + // didn't find it, so not being restored + if (DEBUG_BACKUP) { + Slog.i(TAG, "Package " + pkgName + " sending normal FIRST_LAUNCH"); + } + sendFirstLaunchBroadcast(pkgName, installerPackage, new int[] {userId}); + } + }); + } + + private void sendFirstLaunchBroadcast(String pkgName, String installerPkg, int[] userIds) { + sendPackageBroadcast(Intent.ACTION_PACKAGE_FIRST_LAUNCH, pkgName, null, 0, + installerPkg, null, userIds); + } + private abstract class HandlerParams { private static final int MAX_RETRIES = 4; @@ -13787,6 +13834,13 @@ public class PackageManagerService extends IPackageManager.Stub { return false; } + private static void updateDigest(MessageDigest digest, File file) throws IOException { + try (DigestInputStream digestStream = + new DigestInputStream(new FileInputStream(file), digest)) { + while (digestStream.read() != -1) {} // nothing to do; just plow through the file + } + } + private void replacePackageLIF(PackageParser.Package pkg, final int policyFlags, int scanFlags, UserHandle user, String installerPackageName, PackageInstalledInfo res) { final boolean isEphemeral = (policyFlags & PackageParser.PARSE_IS_EPHEMERAL) != 0; @@ -13841,6 +13895,32 @@ public class PackageManagerService extends IPackageManager.Stub { } } + // don't allow a system upgrade unless the upgrade hash matches + if (oldPackage.restrictUpdateHash != null && oldPackage.isSystemApp()) { + byte[] digestBytes = null; + try { + final MessageDigest digest = MessageDigest.getInstance("SHA-512"); + updateDigest(digest, new File(pkg.baseCodePath)); + if (!ArrayUtils.isEmpty(pkg.splitCodePaths)) { + for (String path : pkg.splitCodePaths) { + updateDigest(digest, new File(path)); + } + } + digestBytes = digest.digest(); + } catch (NoSuchAlgorithmException | IOException e) { + res.setError(INSTALL_FAILED_INVALID_APK, + "Could not compute hash: " + pkgName); + return; + } + if (!Arrays.equals(oldPackage.restrictUpdateHash, digestBytes)) { + res.setError(INSTALL_FAILED_INVALID_APK, + "New package fails restrict-update check: " + pkgName); + return; + } + // retain upgrade restriction + pkg.restrictUpdateHash = oldPackage.restrictUpdateHash; + } + // Check for shared user id changes String invalidPackageName = getParentOrChildPackageChangedSharedUser(oldPackage, pkg); @@ -16046,7 +16126,7 @@ public class PackageManagerService extends IPackageManager.Stub { final UserManager um = mContext.getSystemService(UserManager.class); final int flags; - if (um.isUserUnlocked(userId)) { + if (um.isUserUnlockingOrUnlocked(userId)) { flags = StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE; } else if (um.isUserRunning(userId)) { flags = StorageManager.FLAG_STORAGE_DE; @@ -17445,6 +17525,13 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); } } + public boolean isOrphaned(String packageName) { + // reader + synchronized (mPackages) { + return mSettings.isOrphaned(packageName); + } + } + @Override public int getApplicationEnabledSetting(String packageName, int userId) { if (!sUserManager.exists(userId)) return COMPONENT_ENABLED_STATE_DISABLED; @@ -18730,7 +18817,7 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); final UserManager um = mContext.getSystemService(UserManager.class); for (UserInfo user : um.getUsers()) { final int flags; - if (um.isUserUnlocked(user.id)) { + if (um.isUserUnlockingOrUnlocked(user.id)) { flags = StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE; } else if (um.isUserRunning(user.id)) { flags = StorageManager.FLAG_STORAGE_DE; @@ -19044,7 +19131,7 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); // First look for stale data that doesn't belong, and check if things // have changed since we did our last restorecon if ((flags & StorageManager.FLAG_STORAGE_CE) != 0) { - if (!isUserKeyUnlocked(userId)) { + if (!StorageManager.isUserKeyUnlocked(userId)) { throw new RuntimeException( "Yikes, someone asked us to reconcile CE storage while " + userId + " was still locked; this would have caused massive data loss!"); @@ -19152,7 +19239,7 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); final UserManager um = mContext.getSystemService(UserManager.class); for (UserInfo user : um.getUsers()) { final int flags; - if (um.isUserUnlocked(user.id)) { + if (um.isUserUnlockingOrUnlocked(user.id)) { flags = StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE; } else if (um.isUserRunning(user.id)) { flags = StorageManager.FLAG_STORAGE_DE; diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java index 9d04472a63a4..851f0859753b 100644 --- a/services/core/java/com/android/server/pm/PackageSettingBase.java +++ b/services/core/java/com/android/server/pm/PackageSettingBase.java @@ -125,6 +125,8 @@ abstract class PackageSettingBase extends SettingBase { /** Package name of the app that installed this package */ String installerPackageName; + /** Indicates if the package that installed this app has been uninstalled */ + boolean isOrphaned; /** UUID of {@link VolumeInfo} hosting this app */ String volumeUuid; @@ -182,6 +184,7 @@ abstract class PackageSettingBase extends SettingBase { origPackage = base.origPackage; installerPackageName = base.installerPackageName; + isOrphaned = base.isOrphaned; volumeUuid = base.volumeUuid; keySetData = new PackageKeySetData(base.keySetData); diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java index f20a36e1f3c0..e2e6c7be2580 100644 --- a/services/core/java/com/android/server/pm/Settings.java +++ b/services/core/java/com/android/server/pm/Settings.java @@ -1117,6 +1117,7 @@ final class Settings { if (installerPackageName != null && installerPackageName.equals(packageName)) { ps.setInstallerPackageName(null); + ps.isOrphaned = true; } } mInstallerPackages.remove(packageName); @@ -2647,6 +2648,9 @@ final class Settings { if (pkg.installerPackageName != null) { serializer.attribute(null, "installer", pkg.installerPackageName); } + if (pkg.isOrphaned) { + serializer.attribute(null, "isOrphaned", "true"); + } if (pkg.volumeUuid != null) { serializer.attribute(null, "volumeUuid", pkg.volumeUuid); } @@ -3522,6 +3526,7 @@ final class Settings { String cpuAbiOverrideString = null; String systemStr = null; String installerPackageName = null; + String isOrphaned = null; String volumeUuid = null; String uidError = null; int pkgFlags = 0; @@ -3563,6 +3568,7 @@ final class Settings { } } installerPackageName = parser.getAttributeValue(null, "installer"); + isOrphaned = parser.getAttributeValue(null, "isOrphaned"); volumeUuid = parser.getAttributeValue(null, "volumeUuid"); systemStr = parser.getAttributeValue(null, "publicFlags"); @@ -3713,6 +3719,7 @@ final class Settings { if (packageSetting != null) { packageSetting.uidError = "true".equals(uidError); packageSetting.installerPackageName = installerPackageName; + packageSetting.isOrphaned = "true".equals(isOrphaned); packageSetting.volumeUuid = volumeUuid; packageSetting.legacyNativeLibraryPathString = legacyNativeLibraryPathStr; packageSetting.primaryCpuAbiString = primaryCpuAbiString; @@ -4115,6 +4122,14 @@ final class Settings { return pkg.installerPackageName; } + boolean isOrphaned(String packageName) { + final PackageSetting pkg = mPackages.get(packageName); + if (pkg == null) { + throw new IllegalArgumentException("Unknown package: " + packageName); + } + return pkg.isOrphaned; + } + int getApplicationEnabledSettingLPr(String packageName, int userId) { final PackageSetting pkg = mPackages.get(packageName); if (pkg == null) { @@ -4133,7 +4148,7 @@ final class Settings { return pkg.getCurrentEnabledStateLPr(classNameStr, userId); } - boolean setPackageStoppedStateLPw(PackageManagerService yucky, String packageName, + boolean setPackageStoppedStateLPw(PackageManagerService pm, String packageName, boolean stopped, boolean allowedByPermission, int uid, int userId) { int appId = UserHandle.getAppId(uid); final PackageSetting pkgSetting = mPackages.get(packageName); @@ -4158,9 +4173,7 @@ final class Settings { // pkgSetting.pkg.mSetStopped = stopped; if (pkgSetting.getNotLaunched(userId)) { if (pkgSetting.installerPackageName != null) { - yucky.sendPackageBroadcast(Intent.ACTION_PACKAGE_FIRST_LAUNCH, - pkgSetting.name, null, 0, - pkgSetting.installerPackageName, null, new int[] {userId}); + pm.notifyFirstLaunch(pkgSetting.name, pkgSetting.installerPackageName, userId); } pkgSetting.setNotLaunched(false, userId); } diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java index 57641614cda8..c0874efe211c 100644 --- a/services/core/java/com/android/server/pm/ShortcutService.java +++ b/services/core/java/com/android/server/pm/ShortcutService.java @@ -1561,48 +1561,46 @@ public class ShortcutService extends IShortcutService.Stub { // === House keeping === - @VisibleForTesting - void cleanUpPackageLocked(String packageName, int owningUserId, int packageUserId) { - cleanUpPackageLocked(packageName, owningUserId, packageUserId, - /* forceForCommandLine= */ false); + private void cleanUpPackageForAllLoadedUsers(String packageName, @UserIdInt int packageUserId) { + synchronized (mLock) { + forEachLoadedUserLocked(user -> + cleanUpPackageLocked(packageName, user.getUserId(), packageUserId)); + } } /** * Remove all the information associated with a package. This will really remove all the * information, including the restore information (i.e. it'll remove packages even if they're * shadow). + * + * This is called when an app is uninstalled, or an app gets "clear data"ed. */ - private void cleanUpPackageLocked(String packageName, int owningUserId, int packageUserId, - boolean forceForCommandLine) { - if (!forceForCommandLine && isPackageInstalled(packageName, packageUserId)) { - wtf("Package " + packageName + " is still installed for user " + packageUserId); - return; - } - + @VisibleForTesting + void cleanUpPackageLocked(String packageName, int owningUserId, int packageUserId) { final boolean wasUserLoaded = isUserLoadedLocked(owningUserId); - final ShortcutUser mUser = getUserShortcutsLocked(owningUserId); + final ShortcutUser user = getUserShortcutsLocked(owningUserId); boolean doNotify = false; // First, remove the package from the package list (if the package is a publisher). if (packageUserId == owningUserId) { - if (mUser.removePackage(this, packageName) != null) { + if (user.removePackage(this, packageName) != null) { doNotify = true; } } // Also remove from the launcher list (if the package is a launcher). - mUser.removeLauncher(packageUserId, packageName); + user.removeLauncher(packageUserId, packageName); // Then remove pinned shortcuts from all launchers. - final ArrayMap<PackageWithUser, ShortcutLauncher> launchers = mUser.getAllLaunchers(); + final ArrayMap<PackageWithUser, ShortcutLauncher> launchers = user.getAllLaunchers(); for (int i = launchers.size() - 1; i >= 0; i--) { launchers.valueAt(i).cleanUpPackage(packageName, packageUserId); } // Now there may be orphan shortcuts because we removed pinned shortucts at the previous // step. Remove them too. - for (int i = mUser.getAllPackages().size() - 1; i >= 0; i--) { - mUser.getAllPackages().valueAt(i).refreshPinnedFlags(this); + for (int i = user.getAllPackages().size() - 1; i >= 0; i--) { + user.getAllPackages().valueAt(i).refreshPinnedFlags(this); } scheduleSaveUser(owningUserId); @@ -1842,6 +1840,11 @@ public class ShortcutService extends IShortcutService.Stub { public void onPackageRemoved(String packageName, int uid) { handlePackageRemoved(packageName, getChangingUserId()); } + + @Override + public void onPackageDataCleared(String packageName, int uid) { + handlePackageDataCleared(packageName, getChangingUserId()); + } }; /** @@ -1915,16 +1918,15 @@ public class ShortcutService extends IShortcutService.Stub { Slog.d(TAG, String.format("handlePackageRemoved: %s user=%d", packageName, packageUserId)); } - handlePackageRemovedInner(packageName, packageUserId, /* forceForCommandLine =*/ false); + cleanUpPackageForAllLoadedUsers(packageName, packageUserId); } - private void handlePackageRemovedInner(String packageName, @UserIdInt int packageUserId, - boolean forceForCommandLine) { - synchronized (mLock) { - forEachLoadedUserLocked(user -> - cleanUpPackageLocked(packageName, user.getUserId(), packageUserId, - forceForCommandLine)); + private void handlePackageDataCleared(String packageName, int packageUserId) { + if (DEBUG) { + Slog.d(TAG, String.format("handlePackageDataCleared: %s user=%d", packageName, + packageUserId)); } + cleanUpPackageForAllLoadedUsers(packageName, packageUserId); } // === PackageManager interaction === @@ -2390,8 +2392,7 @@ public class ShortcutService extends IShortcutService.Stub { Slog.i(TAG, "cmd: handleClearShortcuts: " + mUserId + ", " + packageName); - ShortcutService.this.handlePackageRemovedInner(packageName, mUserId, - /* forceForCommandLine= */ true); + ShortcutService.this.cleanUpPackageForAllLoadedUsers(packageName, mUserId); } } diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java index a085370b7164..a2d859b79d30 100644 --- a/services/core/java/com/android/server/pm/UserManagerService.java +++ b/services/core/java/com/android/server/pm/UserManagerService.java @@ -692,7 +692,7 @@ public class UserManagerService extends IUserManager.Stub { @Override public boolean trySetQuietModeDisabled(int userHandle, IntentSender target) { final int credentialOwnerUserId = getCredentialOwnerProfile(userHandle); - if (mContext.getSystemService(StorageManager.class).isUserKeyUnlocked(userHandle) + if (StorageManager.isUserKeyUnlocked(userHandle) || !mLockPatternUtils.isSecure(credentialOwnerUserId)) { // if the user is already unlocked, no need to show a profile challenge setQuietModeEnabled(userHandle, false); diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index df74ed1a43b5..2636d0959066 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -4317,11 +4317,25 @@ public class PhoneWindowManager implements WindowManagerPolicy { pf.top = df.top = of.top = mUnrestrictedScreenTop; pf.right = df.right = of.right = mUnrestrictedScreenLeft + mUnrestrictedScreenWidth; pf.bottom = df.bottom = of.bottom = mUnrestrictedScreenTop + mUnrestrictedScreenHeight; - cf.bottom = vf.bottom = mStableBottom; - // Note: In Phone landscape mode, the button bar should also be excluded. - cf.right = vf.right = mStableRight; - cf.left = vf.left = mStableLeft; - cf.top = vf.top = mStableTop; + if (adjust != SOFT_INPUT_ADJUST_RESIZE) { + cf.left = mDockLeft; + cf.top = mDockTop; + cf.right = mDockRight; + cf.bottom = mDockBottom; + } else { + cf.left = mContentLeft; + cf.top = mContentTop; + cf.right = mContentRight; + cf.bottom = mContentBottom; + } + if (adjust != SOFT_INPUT_ADJUST_NOTHING) { + vf.left = mCurLeft; + vf.top = mCurTop; + vf.right = mCurRight; + vf.bottom = mCurBottom; + } else { + vf.set(cf); + } } else if (win == mStatusBar) { pf.left = df.left = of.left = mUnrestrictedScreenLeft; pf.top = df.top = of.top = mUnrestrictedScreenTop; @@ -5145,7 +5159,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { mKeyguardOccluded = false; mKeyguardDelegate.setOccluded(false); mStatusBar.getAttrs().privateFlags |= PRIVATE_FLAG_KEYGUARD; - mStatusBar.getAttrs().flags |= FLAG_SHOW_WALLPAPER; return true; } else if (!wasOccluded && isOccluded && showing) { mKeyguardOccluded = true; diff --git a/services/core/java/com/android/server/search/SearchManagerService.java b/services/core/java/com/android/server/search/SearchManagerService.java index e3e1097cd04d..4d91814af44a 100644 --- a/services/core/java/com/android/server/search/SearchManagerService.java +++ b/services/core/java/com/android/server/search/SearchManagerService.java @@ -112,7 +112,7 @@ public class SearchManagerService extends ISearchManager.Stub { if (um.getUserInfo(userId) == null) { throw new IllegalStateException("User " + userId + " doesn't exist"); } - if (!um.isUserUnlocked(userId)) { + if (!um.isUserUnlockingOrUnlocked(userId)) { throw new IllegalStateException("User " + userId + " isn't unlocked"); } } finally { diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java index d6ace91f64d4..4c7f9eb705c6 100644 --- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java +++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java @@ -73,6 +73,8 @@ import android.service.wallpaper.IWallpaperConnection; import android.service.wallpaper.IWallpaperEngine; import android.service.wallpaper.IWallpaperService; import android.service.wallpaper.WallpaperService; +import android.system.ErrnoException; +import android.system.Os; import android.util.EventLog; import android.util.Slog; import android.util.SparseArray; @@ -224,6 +226,17 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { + " whichPending=0x" + Integer.toHexString(wallpaper.whichPending) + " written=" + written); } + + if (moved && lockWallpaperChanged) { + // We just migrated sys -> lock to preserve imagery for an impending + // new system-only wallpaper. Tell keyguard about it but that's it. + if (DEBUG) { + Slog.i(TAG, "Sys -> lock MOVED_TO"); + } + notifyLockWallpaperChanged(); + return; + } + synchronized (mLock) { if (sysWallpaperChanged || lockWallpaperChanged) { notifyCallbacksLocked(wallpaper); @@ -276,14 +289,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { mLockWallpaperMap.remove(wallpaper.userId); } // and in any case, tell keyguard about it - final IWallpaperManagerCallback cb = mKeyguardListener; - if (cb != null) { - try { - cb.onWallpaperChanged(); - } catch (RemoteException e) { - // Oh well it went away; no big deal - } - } + notifyLockWallpaperChanged(); } saveSettingsLocked(wallpaper.userId); } @@ -293,6 +299,17 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { } } + void notifyLockWallpaperChanged() { + final IWallpaperManagerCallback cb = mKeyguardListener; + if (cb != null) { + try { + cb.onWallpaperChanged(); + } catch (RemoteException e) { + // Oh well it went away; no big deal + } + } + } + /** * Once a new wallpaper has been written via setWallpaper(...), it needs to be cropped * for display. @@ -862,7 +879,6 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { IntentFilter userFilter = new IntentFilter(); userFilter.addAction(Intent.ACTION_USER_REMOVED); - userFilter.addAction(Intent.ACTION_USER_STOPPING); mContext.registerReceiver(new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { @@ -871,12 +887,6 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { onRemoveUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL)); } - // TODO: Race condition causing problems when cleaning up on stopping a user. - // Comment this out for now. - // else if (Intent.ACTION_USER_STOPPING.equals(action)) { - // onStoppingUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, - // UserHandle.USER_NULL)); - // } } }, userFilter); @@ -1341,6 +1351,17 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { if (DEBUG) Slog.v(TAG, "setWallpaper which=0x" + Integer.toHexString(which)); WallpaperData wallpaper; + /* If we're setting system but not lock, and lock is currently sharing the system + * wallpaper, we need to migrate that image over to being lock-only before + * the caller here writes new bitmap data. + */ + if (which == FLAG_SYSTEM && mLockWallpaperMap.get(userId) == null) { + if (DEBUG) { + Slog.i(TAG, "Migrating system->lock to preserve"); + } + migrateSystemToLockWallpaperLocked(userId); + } + wallpaper = getWallpaperSafeLocked(userId, which); final long ident = Binder.clearCallingIdentity(); try { @@ -1361,6 +1382,38 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { } } + private void migrateSystemToLockWallpaperLocked(int userId) { + WallpaperData sysWP = mWallpaperMap.get(userId); + if (sysWP == null) { + if (DEBUG) { + Slog.i(TAG, "No system wallpaper? Not tracking for lock-only"); + } + return; + } + + // We know a-priori that there is no lock-only wallpaper currently + WallpaperData lockWP = new WallpaperData(userId, + WALLPAPER_LOCK_ORIG, WALLPAPER_LOCK_CROP); + lockWP.wallpaperId = sysWP.wallpaperId; + lockWP.cropHint.set(sysWP.cropHint); + lockWP.width = sysWP.width; + lockWP.height = sysWP.height; + lockWP.allowBackup = false; + + // Migrate the bitmap files outright; no need to copy + try { + Os.rename(sysWP.wallpaperFile.getAbsolutePath(), lockWP.wallpaperFile.getAbsolutePath()); + Os.rename(sysWP.cropFile.getAbsolutePath(), lockWP.cropFile.getAbsolutePath()); + } catch (ErrnoException e) { + Slog.e(TAG, "Can't migrate system wallpaper: " + e.getMessage()); + lockWP.wallpaperFile.delete(); + lockWP.cropFile.delete(); + return; + } + + mLockWallpaperMap.put(userId, lockWP); + } + ParcelFileDescriptor updateWallpaperBitmapLocked(String name, WallpaperData wallpaper, Bundle extras) { if (name == null) name = ""; diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java index 9199d10aa575..094b217aafa0 100644 --- a/services/core/java/com/android/server/wm/AppTransition.java +++ b/services/core/java/com/android/server/wm/AppTransition.java @@ -39,6 +39,7 @@ import static com.android.internal.R.styleable.WindowAnimation_wallpaperIntraOpe import static com.android.internal.R.styleable.WindowAnimation_wallpaperIntraOpenExitAnimation; import static com.android.internal.R.styleable.WindowAnimation_wallpaperOpenEnterAnimation; import static com.android.internal.R.styleable.WindowAnimation_wallpaperOpenExitAnimation; +import static com.android.server.wm.AppWindowAnimator.PROLONG_ANIMATION_AT_START; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; @@ -228,6 +229,7 @@ public class AppTransition implements Dump { private int mLastClipRevealMaxTranslation; private boolean mLastHadClipReveal; + private boolean mProlongedAnimationsEnded; AppTransition(Context context, WindowManagerService service) { mContext = context; @@ -371,6 +373,22 @@ public class AppTransition implements Dump { topClosingAppAnimator != null ? topClosingAppAnimator.animation : null); mService.getDefaultDisplayContentLocked().getDockedDividerController() .notifyAppTransitionStarting(openingApps, closingApps); + + // Prolong the start for the transition when docking a task from recents, unless recents + // ended it already then we don't need to wait. + if (mNextAppTransition == TRANSIT_DOCK_TASK_FROM_RECENTS && !mProlongedAnimationsEnded) { + for (int i = openingApps.size() - 1; i >= 0; i--) { + final AppWindowAnimator appAnimator = openingApps.valueAt(i).mAppAnimator; + appAnimator.startProlongAnimation(PROLONG_ANIMATION_AT_START); + } + } + } + + /** + * Let the transitions manager know that the somebody wanted to end the prolonged animations. + */ + void notifyProlongedAnimationsEnded() { + mProlongedAnimationsEnded = true; } void clear() { @@ -380,6 +398,7 @@ public class AppTransition implements Dump { mNextAppTransitionAnimationsSpecsFuture = null; mDefaultNextAppTransitionAnimationSpec = null; mAnimationFinishedCallback = null; + mProlongedAnimationsEnded = false; } void freeze() { @@ -1914,14 +1933,6 @@ public class AppTransition implements Dump { setAppTransition(transit); } } - if (transit != TRANSIT_DOCK_TASK_FROM_RECENTS - && mNextAppTransition == TRANSIT_DOCK_TASK_FROM_RECENTS) { - - // Somebody is trying to start another transition while we are waiting for the docking - // window to be drawn. Because TRANSIT_DOCK_TASK_FROM_RECENTS starts prolonged - // animations, we need to override it or our prolonged animations will never be ended. - setAppTransition(transit); - } boolean prepared = prepare(); if (isTransitionSet()) { mService.mH.removeMessages(H.APP_TRANSITION_TIMEOUT); diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java index 3b1f34a30529..b4ead440405e 100644 --- a/services/core/java/com/android/server/wm/AppWindowToken.java +++ b/services/core/java/com/android/server/wm/AppWindowToken.java @@ -390,8 +390,8 @@ class AppWindowToken extends WindowToken { } boolean hasSavedSurface() { - for (int i = windows.size() -1; i >= 0; i--) { - final WindowState ws = windows.get(i); + for (int i = allAppWindows.size() -1; i >= 0; i--) { + final WindowState ws = allAppWindows.get(i); if (ws.hasSavedSurface()) { return true; } @@ -408,8 +408,8 @@ class AppWindowToken extends WindowToken { // Check if we have enough drawn windows to mark allDrawn= true. int numInteresting = 0; int numDrawn = 0; - for (int i = windows.size() - 1; i >= 0; i--) { - WindowState w = windows.get(i); + for (int i = allAppWindows.size() - 1; i >= 0; i--) { + WindowState w = allAppWindows.get(i); if (w.hasSavedSurface()) { w.restoreSavedSurface(); } @@ -429,8 +429,8 @@ class AppWindowToken extends WindowToken { } void destroySavedSurfaces() { - for (int i = windows.size() - 1; i >= 0; i--) { - WindowState win = windows.get(i); + for (int i = allAppWindows.size() - 1; i >= 0; i--) { + WindowState win = allAppWindows.get(i); win.destroySavedSurface(); } mAnimatingWithSavedSurface = false; diff --git a/services/core/java/com/android/server/wm/BoundsAnimationController.java b/services/core/java/com/android/server/wm/BoundsAnimationController.java index debb38257817..220a6de1d888 100644 --- a/services/core/java/com/android/server/wm/BoundsAnimationController.java +++ b/services/core/java/com/android/server/wm/BoundsAnimationController.java @@ -24,10 +24,12 @@ import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; import android.animation.Animator; import android.animation.ValueAnimator; import android.graphics.Rect; +import android.os.IBinder; import android.os.Debug; import android.util.ArrayMap; import android.util.Slog; import android.view.animation.LinearInterpolator; +import android.view.WindowManagerInternal; /** * Enables animating bounds of objects. @@ -49,6 +51,32 @@ public class BoundsAnimationController { // Only accessed on UI thread. private ArrayMap<AnimateBoundsUser, BoundsAnimator> mRunningAnimations = new ArrayMap<>(); + private final WindowManagerInternal.AppTransitionListener mAppTransitionNotifier + = new WindowManagerInternal.AppTransitionListener() { + public void onAppTransitionCancelledLocked() { + animationFinished(); + } + public void onAppTransitionFinishedLocked(IBinder token) { + animationFinished(); + } + private void animationFinished() { + if (mFinishAnimationAfterTransition) { + for (int i = 0; i < mRunningAnimations.size(); i++) { + BoundsAnimator b = mRunningAnimations.valueAt(i); + b.onAnimationEnd(null); + } + } + } + }; + + private final AppTransition mAppTransition; + private boolean mFinishAnimationAfterTransition = false; + + BoundsAnimationController(AppTransition transition) { + mAppTransition = transition; + mAppTransition.registerListenerLocked(mAppTransitionNotifier); + } + private final class BoundsAnimator extends ValueAnimator implements ValueAnimator.AnimatorUpdateListener, ValueAnimator.AnimatorListener { private final AnimateBoundsUser mTarget; @@ -129,6 +157,7 @@ public class BoundsAnimationController { public void onAnimationStart(Animator animation) { if (DEBUG) Slog.d(TAG, "onAnimationStart: mTarget=" + mTarget + " mReplacement=" + mReplacement); + mFinishAnimationAfterTransition = false; // Ensure that we have prepared the target for animation before // we trigger any size changes, so it can swap surfaces // in to appropriate modes, or do as it wishes otherwise. @@ -150,10 +179,21 @@ public class BoundsAnimationController { if (DEBUG) Slog.d(TAG, "onAnimationEnd: mTarget=" + mTarget + " mMoveToFullScreen=" + mMoveToFullScreen + " mWillReplace=" + mWillReplace); - finishAnimation(); + // There could be another animation running. For example in the + // move to fullscreen case, recents will also be closing while the + // previous task will be taking its place in the fullscreen stack. + // we have to ensure this is completed before we finish the animation + // and take our place in the fullscreen stack. + if (mAppTransition.isRunning() && !mFinishAnimationAfterTransition) { + mFinishAnimationAfterTransition = true; + return; + } + if (mMoveToFullScreen && !mWillReplace) { mTarget.moveToFullscreen(); } + + finishAnimation(); } @Override diff --git a/services/core/java/com/android/server/wm/DockedStackDividerController.java b/services/core/java/com/android/server/wm/DockedStackDividerController.java index 8174c139cf64..c640b2a2a56e 100644 --- a/services/core/java/com/android/server/wm/DockedStackDividerController.java +++ b/services/core/java/com/android/server/wm/DockedStackDividerController.java @@ -377,7 +377,7 @@ public class DockedStackDividerController implements DimLayerUser { // If the app that having visibility change is not the top visible one in the task, // it does not affect whether the docked stack is minimized, ignore it. - if (task.getTopVisibleAppToken() == null || task.getTopVisibleAppToken() != wtoken) { + if (task.getTopAppToken() == null || task.getTopAppToken() != wtoken) { return; } @@ -598,7 +598,7 @@ public class DockedStackDividerController implements DimLayerUser { } private boolean animateForMinimizedDockedStack(long now) { - final TaskStack stack = mDisplayContent.getDockedStackVisibleForUserLocked(); + final TaskStack stack = mService.mStackIdToStack.get(DOCKED_STACK_ID); if (!mAnimationStarted) { mAnimationStarted = true; mAnimationStartTime = now; diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index 6925fa597c4b..8d41dab431f7 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -719,6 +719,10 @@ class Task implements DimLayer.DimLayerUser { return null; } + AppWindowToken getTopAppToken() { + return mAppTokens.size() > 0 ? mAppTokens.get(mAppTokens.size() - 1) : null; + } + @Override public boolean isFullscreen() { if (useCurrentBounds()) { diff --git a/services/core/java/com/android/server/wm/TaskPositioner.java b/services/core/java/com/android/server/wm/TaskPositioner.java index ae70aa8fa6b7..222087d08061 100644 --- a/services/core/java/com/android/server/wm/TaskPositioner.java +++ b/services/core/java/com/android/server/wm/TaskPositioner.java @@ -204,7 +204,7 @@ class TaskPositioner implements DimLayer.DimLayerUser { : DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT; mService.mActivityManager.moveTaskToDockedStack( mTask.mTaskId, createMode, true /*toTop*/, true /* animate */, - null /* initialBounds */); + null /* initialBounds */, false /* moveHomeStackFront */); } } catch(RemoteException e) {} diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java index 6f8207e23c5b..4224c57a95ed 100644 --- a/services/core/java/com/android/server/wm/TaskStack.java +++ b/services/core/java/com/android/server/wm/TaskStack.java @@ -110,11 +110,6 @@ public class TaskStack implements DimLayer.DimLayerUser, /** Detach this stack from its display when animation completes. */ boolean mDeferDetach; - // Display rotation as of the last time the display information was updated for this stack. - private int mLastUpdateDisplayInfoRotation = -1; - // Display rotation as of the last time the configuration was updated for this stack. - private int mLastConfigChangedRotation = -1; - // Whether the stack and all its tasks is currently being drag-resized private boolean mDragResizing; @@ -371,36 +366,27 @@ public class TaskStack implements DimLayer.DimLayerUser, final int newDensity = mDisplayContent.getDisplayInfo().logicalDensityDpi; if (mRotation == newRotation && mDensity == newDensity) { setBounds(mTmpRect2); - } else { - mLastUpdateDisplayInfoRotation = newRotation; - updateBoundsAfterConfigChange(true); } + + // If the rotation or density didn't match, we'll update it in onConfigurationChanged. } boolean onConfigurationChanged() { - mLastConfigChangedRotation = getDisplayInfo().rotation; - return updateBoundsAfterConfigChange(false); + return updateBoundsAfterConfigChange(); } - boolean updateBoundsAfterConfigChange(boolean scheduleResize) { + private boolean updateBoundsAfterConfigChange() { if (mFullscreen) { // Bounds will already be set correctly when display info is updated in the case of // fullscreen. return false; } - if (mLastConfigChangedRotation != mLastUpdateDisplayInfoRotation) { - // We wait for the rotation values after configuration change and display info. update - // to be equal before updating the bounds due to rotation change otherwise things might - // get out of alignment... - return false; - } - final int newRotation = getDisplayInfo().rotation; final int newDensity = getDisplayInfo().logicalDensityDpi; if (mRotation == newRotation && mDensity == newDensity) { - // Nothing to do here if the rotation didn't change + // Nothing to do here as we already update the state in updateDisplayInfo. return false; } @@ -416,16 +402,7 @@ public class TaskStack implements DimLayer.DimLayerUser, } } - if (scheduleResize) { - // Post message to inform activity manager of the bounds change simulating - // a one-way call. We do this to prevent a deadlock between window manager - // lock and activity manager lock been held. - mService.mH.obtainMessage(RESIZE_STACK, mStackId, - 0 /*allowResizeInDockedMode*/, mTmpRect2).sendToTarget(); - } else { - mBoundsAfterRotation.set(mTmpRect2); - } - + mBoundsAfterRotation.set(mTmpRect2); return true; } @@ -1121,6 +1098,14 @@ public class TaskStack implements DimLayer.DimLayerUser, pw.println(prefix + "mDeferDetach=" + mDeferDetach); pw.println(prefix + "mFullscreen=" + mFullscreen); pw.println(prefix + "mBounds=" + mBounds.toShortString()); + if (mMinimizeAmount != 0f) { + pw.println(prefix + "mMinimizeAmout=" + mMinimizeAmount); + } + if (mAdjustedForIme) { + pw.println(prefix + "mAdjustedForIme=true"); + pw.println(prefix + "mAdjustImeAmount=" + mAdjustImeAmount); + pw.println(prefix + "mAdjustDividerAmount=" + mAdjustDividerAmount); + } if (!mAdjustedBounds.isEmpty()) { pw.println(prefix + "mAdjustedBounds=" + mAdjustedBounds.toShortString()); } diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 0c91307e88e1..57f551cff098 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -715,8 +715,7 @@ public class WindowManagerService extends IWindowManager.Stub final WindowAnimator mAnimator; - private final BoundsAnimationController mBoundsAnimationController = - new BoundsAnimationController(); + private final BoundsAnimationController mBoundsAnimationController; SparseArray<Task> mTaskIdToTask = new SparseArray<>(); @@ -974,6 +973,8 @@ public class WindowManagerService extends IWindowManager.Stub mAppTransition = new AppTransition(context, this); mAppTransition.registerListenerLocked(mActivityManagerAppTransitionNotifier); + mBoundsAnimationController = new BoundsAnimationController(mAppTransition); + mActivityManager = ActivityManagerNative.getDefault(); mAmInternal = LocalServices.getService(ActivityManagerInternal.class); mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE); @@ -3625,8 +3626,7 @@ public class WindowManagerService extends IWindowManager.Stub // disregarding font scale, which should remain set to // the value of the previous configuration. mTempConfiguration.setToDefaults(); - mTempConfiguration.fontScale = currentConfig.fontScale; - mTempConfiguration.uiMode = currentConfig.uiMode; + mTempConfiguration.updateFrom(currentConfig); computeScreenConfigurationLocked(mTempConfiguration); if (currentConfig.diff(mTempConfiguration) != 0) { mWaitingForConfig = true; @@ -3689,11 +3689,15 @@ public class WindowManagerService extends IWindowManager.Stub } synchronized(mWindowMap) { - mCurConfiguration = new Configuration(config); if (mWaitingForConfig) { mWaitingForConfig = false; mLastFinishedFreezeSource = "new-config"; } + boolean configChanged = mCurConfiguration.diff(config) != 0; + if (!configChanged) { + return null; + } + mCurConfiguration = new Configuration(config); return onConfigurationChanged(); } } @@ -3941,6 +3945,7 @@ public class WindowManagerService extends IWindowManager.Stub appToken.mAppAnimator.endProlongedAnimation(); } } + mAppTransition.notifyProlongedAnimationsEnded(); } } @@ -4330,15 +4335,21 @@ public class WindowManagerService extends IWindowManager.Stub } } - if (visibilityChanged && !delayed) { - if (visible) { + if (visibilityChanged) { + if (visible && !delayed) { // The token was made immediately visible, there will be no entrance animation. // We need to inform the client the enter animation was finished. wtoken.mEnteringAnimation = true; mActivityManagerAppTransitionNotifier.onAppTransitionFinishedLocked(wtoken.token); } - getDefaultDisplayContentLocked().getDockedDividerController() - .notifyAppVisibilityChanged(wtoken, visible); + + if (!mClosingApps.contains(wtoken) && !mOpeningApps.contains(wtoken)) { + // The token is not closing nor opening, so even if there is an animation set, that + // doesn't mean that it goes through the normal app transition cycle so we have + // to inform the docked controller about visibility change. + getDefaultDisplayContentLocked().getDockedDividerController() + .notifyAppVisibilityChanged(wtoken, visible); + } } return delayed; @@ -6287,9 +6298,11 @@ public class WindowManagerService extends IWindowManager.Stub + maxLayer + " appToken=" + appToken); for (int i = 0; i < windows.size(); i++) { WindowState win = windows.get(i); + WindowSurfaceController controller = win.mWinAnimator.mSurfaceController; Slog.i(TAG_WM, win + ": " + win.mLayer + " animLayer=" + win.mWinAnimator.mAnimLayer - + " surfaceLayer=" + win.mWinAnimator.mSurfaceController.getLayer()); + + " surfaceLayer=" + ((controller == null) + ? "null" : controller.getLayer())); } } @@ -8877,8 +8890,7 @@ public class WindowManagerService extends IWindowManager.Stub boolean configChanged = updateOrientationFromAppTokensLocked(false); mTempConfiguration.setToDefaults(); - mTempConfiguration.fontScale = mCurConfiguration.fontScale; - mTempConfiguration.uiMode = mCurConfiguration.uiMode; + mTempConfiguration.updateFrom(mCurConfiguration); computeScreenConfigurationLocked(mTempConfiguration); configChanged |= mCurConfiguration.diff(mTempConfiguration) != 0; diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java index 1493bc73a17f..a0784b5008db 100644 --- a/services/core/java/com/android/server/wm/WindowStateAnimator.java +++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java @@ -1441,6 +1441,18 @@ class WindowStateAnimator { return; } + // Do not change surface properties of opening apps if we are waiting for the + // transition to be ready. transitionGoodToGo could be not ready even after all + // opening apps are drawn. It's only waiting on isFetchingAppTransitionsSpecs() + // to get the animation spec. (For example, go into Recents and immediately open + // the same app again before the app's surface is destroyed or saved, the surface + // is always ready in the whole process.) If we go ahead here, the opening app + // will be shown with the full size before the correct animation spec arrives. + if (mService.mAppTransition.isTransitionSet() && isDummyAnimation() && + mService.mOpeningApps.contains(w.mAppToken)) { + return; + } + boolean displayed = false; computeShownFrameLocked(); diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java index 8937f09d37ac..a45ae6002692 100644 --- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java +++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java @@ -1251,10 +1251,6 @@ class WindowSurfacePlacer { if (mService.mAppTransition.isNextAppTransitionThumbnailUp()) { createThumbnailAppAnimator(transit, wtoken, topOpeningLayer, topClosingLayer); } - if (mService.mAppTransition.getAppTransition() - == AppTransition.TRANSIT_DOCK_TASK_FROM_RECENTS) { - appAnimator.startProlongAnimation(PROLONG_ANIMATION_AT_START); - } } return topOpeningApp; } diff --git a/services/core/jni/com_android_server_am_BatteryStatsService.cpp b/services/core/jni/com_android_server_am_BatteryStatsService.cpp index 5c4365979644..183a370bac0d 100644 --- a/services/core/jni/com_android_server_am_BatteryStatsService.cpp +++ b/services/core/jni/com_android_server_am_BatteryStatsService.cpp @@ -27,8 +27,10 @@ #include <utils/misc.h> #include <utils/Log.h> #include <hardware/hardware.h> +#include <hardware/power.h> #include <suspend/autosuspend.h> +#include <inttypes.h> #include <stdio.h> #include <errno.h> #include <fcntl.h> @@ -47,6 +49,7 @@ namespace android static bool wakeup_init = false; static sem_t wakeup_sem; +extern struct power_module* gPowerModule; static void wakeup_callback(bool success) { @@ -170,8 +173,122 @@ static jint nativeWaitWakeup(JNIEnv *env, jobject clazz, jobject outBuf) return mergedreasonpos - mergedreason; } +static jint getPlatformLowPowerStats(JNIEnv* env, jobject /* clazz */, jobject outBuf) { + int num_modes = -1; + char *output = (char*)env->GetDirectBufferAddress(outBuf), *offset = output; + int remaining = (int)env->GetDirectBufferCapacity(outBuf); + power_state_platform_sleep_state_t *list; + size_t *voter_list; + int total_added = -1; + + if (outBuf == NULL) { + jniThrowException(env, "java/lang/NullPointerException", "null argument"); + goto error; + } + + if (!gPowerModule) { + ALOGE("%s: gPowerModule not loaded", POWER_HARDWARE_MODULE_ID); + goto error; + } + + if (! (gPowerModule->get_platform_low_power_stats && gPowerModule->get_number_of_platform_modes + && gPowerModule->get_voter_list)) { + ALOGE("%s: Missing API", POWER_HARDWARE_MODULE_ID); + goto error; + } + + if (gPowerModule->get_number_of_platform_modes) { + num_modes = gPowerModule->get_number_of_platform_modes(gPowerModule); + } + + if (num_modes < 1) { + ALOGE("%s: Platform does not even have one low power mode", POWER_HARDWARE_MODULE_ID); + goto error; + } + + list = (power_state_platform_sleep_state_t *)calloc(num_modes, + sizeof(power_state_platform_sleep_state_t)); + if (!list) { + ALOGE("%s: power_state_platform_sleep_state_t allocation failed", POWER_HARDWARE_MODULE_ID); + goto error; + } + + voter_list = (size_t *)calloc(num_modes, sizeof(*voter_list)); + if (!voter_list) { + ALOGE("%s: voter_list allocation failed", POWER_HARDWARE_MODULE_ID); + goto err_free; + } + + gPowerModule->get_voter_list(gPowerModule, voter_list); + + for (int i = 0; i < num_modes; i++) { + list[i].voters = (power_state_voter_t *)calloc(voter_list[i], + sizeof(power_state_voter_t)); + if (!list[i].voters) { + ALOGE("%s: voter_t allocation failed", POWER_HARDWARE_MODULE_ID); + goto err_free; + } + } + + if (!gPowerModule->get_platform_low_power_stats(gPowerModule, list)) { + for (int i = 0; i < num_modes; i++) { + int added; + + added = snprintf(offset, remaining, "%s_time=%" PRIu64 " %s_count=%" PRIu64 " ", + list[i].name, list[i].residency_in_msec_since_boot, list[i].name, + list[i].total_transitions); + if (added < 0) { + break; + } + if (added > remaining) { + added = remaining; + } + offset += added; + remaining -= added; + total_added += added; + + for (unsigned int j = 0; j < list[i].number_of_voters; j++) { + added = snprintf(offset, remaining, "%s_time=%" PRIu64 " %s_count=%" PRIu64 " ", + list[i].voters[j].name, + list[i].voters[j].total_time_in_msec_voted_for_since_boot, + list[i].voters[j].name, + list[i].voters[j].total_number_of_times_voted_since_boot); + if (added < 0) { + break; + } + if (added > remaining) { + added = remaining; + } + offset += added; + remaining -= added; + total_added += added; + } + + if (remaining <= 0) { + /* rewrite NULL character*/ + offset--; + total_added--; + ALOGE("%s module: buffer not enough", POWER_HARDWARE_MODULE_ID); + break; + } + } + } + *offset = 0; + total_added += 1; + +err_free: + for (int i = 0; i < num_modes; i++) { + free(list[i].voters); + } + free(list); + free(voter_list); +error: + return total_added; +} + static const JNINativeMethod method_table[] = { { "nativeWaitWakeup", "(Ljava/nio/ByteBuffer;)I", (void*)nativeWaitWakeup }, + { "getPlatformLowPowerStats", "(Ljava/nio/ByteBuffer;)I", (void*)getPlatformLowPowerStats }, }; int register_android_server_BatteryStatsService(JNIEnv *env) diff --git a/services/core/jni/com_android_server_power_PowerManagerService.cpp b/services/core/jni/com_android_server_power_PowerManagerService.cpp index 2fdb8e2469cd..cbbfda6aa159 100644 --- a/services/core/jni/com_android_server_power_PowerManagerService.cpp +++ b/services/core/jni/com_android_server_power_PowerManagerService.cpp @@ -48,7 +48,7 @@ static struct { // ---------------------------------------------------------------------------- static jobject gPowerManagerServiceObj; -static struct power_module* gPowerModule; +struct power_module* gPowerModule; static nsecs_t gLastEventTime[USER_ACTIVITY_EVENT_LAST + 1]; diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 56e2001872e1..93fbe5cd7e7a 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -6224,6 +6224,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } private void enforceUserUnlocked(int userId) { + // Since we're doing this operation on behalf of an app, we only + // want to use the actual "unlocked" state. Preconditions.checkState(mUserManager.isUserUnlocked(userId), "User must be running and unlocked"); } diff --git a/services/net/java/android/net/dhcp/DhcpClient.java b/services/net/java/android/net/dhcp/DhcpClient.java index 77cd9b6b355d..db521e2d5179 100644 --- a/services/net/java/android/net/dhcp/DhcpClient.java +++ b/services/net/java/android/net/dhcp/DhcpClient.java @@ -724,6 +724,7 @@ public class DhcpClient extends StateMachine { mOffer = null; Log.d(TAG, "Confirmed lease: " + mDhcpLease); setDhcpLeaseExpiry(packet); + notifySuccess(); transitionTo(mConfiguringInterfaceState); } } else if (packet instanceof DhcpNakPacket) { @@ -794,7 +795,6 @@ public class DhcpClient extends StateMachine { @Override public void enter() { super.enter(); - notifySuccess(); // TODO: DhcpStateMachine only supported renewing at 50% of the lease time, // and did not support rebinding. Now that the legacy DHCP client is gone, fix this. scheduleRenew(); @@ -850,6 +850,7 @@ public class DhcpClient extends StateMachine { if (!isValidPacket(packet)) return; if ((packet instanceof DhcpAckPacket)) { setDhcpLeaseExpiry(packet); + notifySuccess(); transitionTo(mDhcpBoundState); } else if (packet instanceof DhcpNakPacket) { transitionTo(mDhcpInitState); diff --git a/services/net/java/android/net/ip/IpManager.java b/services/net/java/android/net/ip/IpManager.java index 0444686e89e7..34152cff6c80 100644 --- a/services/net/java/android/net/ip/IpManager.java +++ b/services/net/java/android/net/ip/IpManager.java @@ -282,7 +282,12 @@ public class IpManager extends StateMachine { } public Builder withPreDhcpAction() { - mConfig.mRequestedPreDhcpAction = true; + mConfig.mRequestedPreDhcpActionMs = DEFAULT_TIMEOUT_MS; + return this; + } + + public Builder withPreDhcpAction(int dhcpActionTimeoutMs) { + mConfig.mRequestedPreDhcpActionMs = dhcpActionTimeoutMs; return this; } @@ -307,7 +312,7 @@ public class IpManager extends StateMachine { } /* package */ boolean mUsingIpReachabilityMonitor = true; - /* package */ boolean mRequestedPreDhcpAction; + /* package */ int mRequestedPreDhcpActionMs; /* package */ StaticIpConfiguration mStaticIpConfig; /* package */ ApfCapabilities mApfCapabilities; /* package */ int mProvisioningTimeoutMs = DEFAULT_TIMEOUT_MS; @@ -316,7 +321,7 @@ public class IpManager extends StateMachine { public ProvisioningConfiguration(ProvisioningConfiguration other) { mUsingIpReachabilityMonitor = other.mUsingIpReachabilityMonitor; - mRequestedPreDhcpAction = other.mRequestedPreDhcpAction; + mRequestedPreDhcpActionMs = other.mRequestedPreDhcpActionMs; mStaticIpConfig = other.mStaticIpConfig; mApfCapabilities = other.mApfCapabilities; mProvisioningTimeoutMs = other.mProvisioningTimeoutMs; @@ -326,7 +331,7 @@ public class IpManager extends StateMachine { public String toString() { return new StringJoiner(", ", getClass().getSimpleName() + "{", "}") .add("mUsingIpReachabilityMonitor: " + mUsingIpReachabilityMonitor) - .add("mRequestedPreDhcpAction: " + mRequestedPreDhcpAction) + .add("mRequestedPreDhcpActionMs: " + mRequestedPreDhcpActionMs) .add("mStaticIpConfig: " + mStaticIpConfig) .add("mApfCapabilities: " + mApfCapabilities) .add("mProvisioningTimeoutMs: " + mProvisioningTimeoutMs) @@ -346,6 +351,7 @@ public class IpManager extends StateMachine { private static final int CMD_UPDATE_HTTP_PROXY = 7; private static final int CMD_SET_MULTICAST_FILTER = 8; private static final int EVENT_PROVISIONING_TIMEOUT = 9; + private static final int EVENT_DHCPACTION_TIMEOUT = 10; private static final int MAX_LOG_RECORDS = 500; @@ -369,6 +375,7 @@ public class IpManager extends StateMachine { private final INetworkManagementService mNwService; private final NetlinkTracker mNetlinkTracker; private final WakeupMessage mProvisioningTimeoutAlarm; + private final WakeupMessage mDhcpActionTimeoutAlarm; private final LocalLog mLocalLog; private NetworkInterface mNetworkInterface; @@ -445,6 +452,8 @@ public class IpManager extends StateMachine { mProvisioningTimeoutAlarm = new WakeupMessage(mContext, getHandler(), mTag + ".EVENT_PROVISIONING_TIMEOUT", EVENT_PROVISIONING_TIMEOUT); + mDhcpActionTimeoutAlarm = new WakeupMessage(mContext, getHandler(), + mTag + ".EVENT_DHCPACTION_TIMEOUT", EVENT_DHCPACTION_TIMEOUT); // Super simple StateMachine. addState(mStoppedState); @@ -1023,6 +1032,7 @@ public class IpManager extends StateMachine { @Override public void exit() { mProvisioningTimeoutAlarm.cancel(); + mDhcpActionTimeoutAlarm.cancel(); if (mIpReachabilityMonitor != null) { mIpReachabilityMonitor.stop(); @@ -1042,6 +1052,18 @@ public class IpManager extends StateMachine { resetLinkProperties(); } + private void startDhcpAction() { + mCallback.onPreDhcpAction(); + final long alarmTime = SystemClock.elapsedRealtime() + + mConfiguration.mRequestedPreDhcpActionMs; + mDhcpActionTimeoutAlarm.schedule(alarmTime); + } + + private void stopDhcpAction() { + mDhcpActionTimeoutAlarm.cancel(); + mCallback.onPostDhcpAction(); + } + @Override public boolean processMessage(Message msg) { switch (msg.what) { @@ -1104,10 +1126,14 @@ public class IpManager extends StateMachine { handleProvisioningFailure(); break; + case EVENT_DHCPACTION_TIMEOUT: + stopDhcpAction(); + break; + case DhcpClient.CMD_PRE_DHCP_ACTION: if (VDBG) { Log.d(mTag, "onPreDhcpAction()"); } - if (mConfiguration.mRequestedPreDhcpAction) { - mCallback.onPreDhcpAction(); + if (mConfiguration.mRequestedPreDhcpActionMs > 0) { + startDhcpAction(); } else { sendMessage(EVENT_PRE_DHCP_ACTION_COMPLETE); } @@ -1123,17 +1149,23 @@ public class IpManager extends StateMachine { mDhcpClient.sendMessage(DhcpClient.EVENT_LINKADDRESS_CONFIGURED); } else { Log.e(mTag, "Failed to set IPv4 address!"); + dispatchCallback(ProvisioningChange.LOST_PROVISIONING, + new LinkProperties(mLinkProperties)); transitionTo(mStoppingState); } break; } + // This message is only received when: + // + // a) initial address acquisition succeeds, + // b) renew succeeds, + // c) renew fails, + // + // but never when initial address acquisition fails. The latter + // condition is now governed by the provisioning timeout. case DhcpClient.CMD_POST_DHCP_ACTION: { - // Note that onPostDhcpAction() is likely to be - // asynchronous, and thus there is no guarantee that we - // will be able to observe any of its effects here. - if (VDBG) { Log.d(mTag, "onPostDhcpAction()"); } - mCallback.onPostDhcpAction(); + stopDhcpAction(); final DhcpResults dhcpResults = (DhcpResults) msg.obj; switch (msg.arg1) { diff --git a/services/print/java/com/android/server/print/PrintManagerService.java b/services/print/java/com/android/server/print/PrintManagerService.java index 4d02928920c6..1feb81664e95 100644 --- a/services/print/java/com/android/server/print/PrintManagerService.java +++ b/services/print/java/com/android/server/print/PrintManagerService.java @@ -727,7 +727,7 @@ public final class PrintManagerService extends SystemService { @Override public void onPackageModified(String packageName) { - if (!mUserManager.isUserUnlocked(getChangingUserId())) return; + if (!mUserManager.isUserUnlockingOrUnlocked(getChangingUserId())) return; UserState userState = getOrCreateUserStateLocked(getChangingUserId(), false); synchronized (mLock) { @@ -742,7 +742,7 @@ public final class PrintManagerService extends SystemService { @Override public void onPackageRemoved(String packageName, int uid) { - if (!mUserManager.isUserUnlocked(getChangingUserId())) return; + if (!mUserManager.isUserUnlockingOrUnlocked(getChangingUserId())) return; UserState userState = getOrCreateUserStateLocked(getChangingUserId(), false); synchronized (mLock) { @@ -757,7 +757,7 @@ public final class PrintManagerService extends SystemService { @Override public boolean onHandleForceStop(Intent intent, String[] stoppedPackages, int uid, boolean doit) { - if (!mUserManager.isUserUnlocked(getChangingUserId())) return false; + if (!mUserManager.isUserUnlockingOrUnlocked(getChangingUserId())) return false; synchronized (mLock) { // A background user/profile's print jobs are running but there is // no UI shown. Hence, if the packages of such a user change we need @@ -795,7 +795,7 @@ public final class PrintManagerService extends SystemService { @Override public void onPackageAdded(String packageName, int uid) { - if (!mUserManager.isUserUnlocked(getChangingUserId())) return; + if (!mUserManager.isUserUnlockingOrUnlocked(getChangingUserId())) return; synchronized (mLock) { if (hasPrintService(packageName)) { UserState userState = getOrCreateUserStateLocked(getChangingUserId(), @@ -812,7 +812,7 @@ public final class PrintManagerService extends SystemService { } private UserState getOrCreateUserStateLocked(int userId, boolean lowPriority) { - if (!mUserManager.isUserUnlocked(userId)) { + if (!mUserManager.isUserUnlockingOrUnlocked(userId)) { throw new IllegalStateException( "User " + userId + " must be unlocked for printing to be available"); } @@ -836,6 +836,8 @@ public final class PrintManagerService extends SystemService { BackgroundThread.getHandler().post(new Runnable() { @Override public void run() { + if (!mUserManager.isUserUnlockingOrUnlocked(userId)) return; + UserState userState; synchronized (mLock) { userState = getOrCreateUserStateLocked(userId, true); diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest.java index bc43576c7caf..13518b555c76 100644 --- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest.java @@ -1061,6 +1061,12 @@ public class ShortcutManagerTest extends InstrumentationTestCase { i.putExtra(Intent.EXTRA_REPLACING, true); return i; } + private Intent genPackageDataClear(String packageName, int userId) { + Intent i = new Intent(Intent.ACTION_PACKAGE_DATA_CLEARED); + i.setData(Uri.parse("package:" + packageName)); + i.putExtra(Intent.EXTRA_USER_HANDLE, userId); + return i; + } private ShortcutInfo parceled(ShortcutInfo si) { Parcel p = Parcel.obtain(); @@ -4159,6 +4165,79 @@ public class ShortcutManagerTest extends InstrumentationTestCase { assertFalse(bitmapDirectoryExists(CALLING_PACKAGE_3, USER_10)); } + /** Almost ame as testHandlePackageDelete, except it doesn't uninstall packages. */ + public void testHandlePackageClearData() { + final Icon bmp32x32 = Icon.createWithBitmap(BitmapFactory.decodeResource( + getTestContext().getResources(), R.drawable.black_32x32)); + setCaller(CALLING_PACKAGE_1, USER_0); + assertTrue(mManager.addDynamicShortcuts(list( + makeShortcutWithIcon("s1", bmp32x32), makeShortcutWithIcon("s2", bmp32x32) + ))); + + setCaller(CALLING_PACKAGE_2, USER_0); + assertTrue(mManager.addDynamicShortcuts(list(makeShortcutWithIcon("s1", bmp32x32)))); + + setCaller(CALLING_PACKAGE_3, USER_0); + assertTrue(mManager.addDynamicShortcuts(list(makeShortcutWithIcon("s1", bmp32x32)))); + + setCaller(CALLING_PACKAGE_1, USER_10); + assertTrue(mManager.addDynamicShortcuts(list(makeShortcutWithIcon("s1", bmp32x32)))); + + setCaller(CALLING_PACKAGE_2, USER_10); + assertTrue(mManager.addDynamicShortcuts(list(makeShortcutWithIcon("s1", bmp32x32)))); + + setCaller(CALLING_PACKAGE_3, USER_10); + assertTrue(mManager.addDynamicShortcuts(list(makeShortcutWithIcon("s1", bmp32x32)))); + + assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_0)); + assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_0)); + assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_0)); + assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_10)); + assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_10)); + assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_10)); + + assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_1, USER_0)); + assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_2, USER_0)); + assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_3, USER_0)); + assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_1, USER_10)); + assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_2, USER_10)); + assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_3, USER_10)); + + mService.mPackageMonitor.onReceive(getTestContext(), + genPackageDataClear(CALLING_PACKAGE_1, USER_0)); + + assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_0)); + assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_0)); + assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_0)); + assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_10)); + assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_10)); + assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_10)); + + assertFalse(bitmapDirectoryExists(CALLING_PACKAGE_1, USER_0)); + assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_2, USER_0)); + assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_3, USER_0)); + assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_1, USER_10)); + assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_2, USER_10)); + assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_3, USER_10)); + + mService.mPackageMonitor.onReceive(getTestContext(), + genPackageDataClear(CALLING_PACKAGE_2, USER_10)); + + assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_0)); + assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_0)); + assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_0)); + assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_10)); + assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_10)); + assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_10)); + + assertFalse(bitmapDirectoryExists(CALLING_PACKAGE_1, USER_0)); + assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_2, USER_0)); + assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_3, USER_0)); + assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_1, USER_10)); + assertFalse(bitmapDirectoryExists(CALLING_PACKAGE_2, USER_10)); + assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_3, USER_10)); + } + public void testHandlePackageUpdate() throws Throwable { // Set up shortcuts and launchers. diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java index 612e5e84d0be..f58de26a22bc 100644 --- a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java +++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java @@ -501,7 +501,10 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener { if (status != STATUS_OK) { Slog.w(TAG, "Error stopping keyphrase model: " + model.getHandle()); } - model.clearState(); + model.setStopped(); + model.setRequested(false); + model.clearCallback(); + model.setRecognitionConfig(null); } } internalClearGlobalStateLocked(); diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml index b9e9ac856185..3785cdc44b0c 100644 --- a/tests/HwAccelerationTest/AndroidManifest.xml +++ b/tests/HwAccelerationTest/AndroidManifest.xml @@ -383,6 +383,15 @@ </activity> <activity + android:name="VideoViewCaptureActivity" + android:label="SurfaceView/GetBitmap with Video source"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="com.android.test.hwui.TEST" /> + </intent-filter> + </activity> + + <activity android:name="GLTextureViewActivity" android:label="TextureView/OpenGL"> <intent-filter> diff --git a/tests/HwAccelerationTest/res/drawable/default_wallpaper.png b/tests/HwAccelerationTest/res/drawable/default_wallpaper.png Binary files differindex 187a6c07704a..91ad252507e5 100644 --- a/tests/HwAccelerationTest/res/drawable/default_wallpaper.png +++ b/tests/HwAccelerationTest/res/drawable/default_wallpaper.png diff --git a/tests/HwAccelerationTest/res/raw/colorgrid_video.mp4 b/tests/HwAccelerationTest/res/raw/colorgrid_video.mp4 Binary files differnew file mode 100644 index 000000000000..1be8bee39fd4 --- /dev/null +++ b/tests/HwAccelerationTest/res/raw/colorgrid_video.mp4 diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/GetBitmapSurfaceViewActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/GetBitmapSurfaceViewActivity.java index f658b7c05e66..6fe2cb472a97 100644 --- a/tests/HwAccelerationTest/src/com/android/test/hwui/GetBitmapSurfaceViewActivity.java +++ b/tests/HwAccelerationTest/src/com/android/test/hwui/GetBitmapSurfaceViewActivity.java @@ -23,6 +23,7 @@ import android.os.Bundle; import android.os.Environment; import android.view.Gravity; import android.view.PixelCopy; +import android.view.Surface; import android.view.SurfaceHolder; import android.view.SurfaceView; import android.view.View; @@ -87,9 +88,42 @@ public class GetBitmapSurfaceViewActivity extends Activity implements SurfaceHol android.util.Log.e("TextureView", "Cannot set preview texture target!", t); } + setCameraDisplayOrientation(this, 0, mCamera); mCamera.startPreview(); } + public static void setCameraDisplayOrientation(Activity activity, + int cameraId, android.hardware.Camera camera) { + android.hardware.Camera.CameraInfo info = new android.hardware.Camera.CameraInfo(); + android.hardware.Camera.getCameraInfo(cameraId, info); + int rotation = activity.getWindowManager().getDefaultDisplay() + .getRotation(); + int degrees = 0; + switch (rotation) { + case Surface.ROTATION_0: + degrees = 0; + break; + case Surface.ROTATION_90: + degrees = 90; + break; + case Surface.ROTATION_180: + degrees = 180; + break; + case Surface.ROTATION_270: + degrees = 270; + break; + } + + int result; + if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) { + result = (info.orientation + degrees) % 360; + result = (360 - result) % 360; // compensate the mirror + } else { // back-facing + result = (info.orientation - degrees + 360) % 360; + } + camera.setDisplayOrientation(result); + } + @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { } diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/VideoViewCaptureActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/VideoViewCaptureActivity.java new file mode 100644 index 000000000000..b87be8058d81 --- /dev/null +++ b/tests/HwAccelerationTest/src/com/android/test/hwui/VideoViewCaptureActivity.java @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.test.hwui; + +import android.app.Activity; +import android.graphics.Bitmap; +import android.net.Uri; +import android.os.Bundle; +import android.os.Environment; +import android.view.PixelCopy; +import android.view.View; +import android.widget.Button; +import android.widget.FrameLayout; +import android.widget.LinearLayout; +import android.widget.Toast; +import android.widget.VideoView; + +import java.io.FileOutputStream; + +public class VideoViewCaptureActivity extends Activity { + private VideoView mVideoView; + private int mVideoWidth, mVideoHeight; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + mVideoView = new VideoView(this); + mVideoView.setOnPreparedListener(mp -> { + mp.setLooping(true); + mVideoWidth = mp.getVideoWidth(); + mVideoHeight = mp.getVideoHeight(); + mVideoView.start(); + }); + + Uri uri = Uri.parse("android.resource://com.android.test.hwui/" + R.raw.colorgrid_video); + mVideoView.setVideoURI(uri); + + Button button = new Button(this); + button.setText("Copy bitmap to /sdcard/surfaceview.png"); + button.setOnClickListener((View v) -> { + final Bitmap b = Bitmap.createBitmap( + mVideoWidth, mVideoHeight, + Bitmap.Config.ARGB_8888); + PixelCopy.request(mVideoView, b, + (int result) -> { + if (result != PixelCopy.SUCCESS) { + Toast.makeText(VideoViewCaptureActivity.this, + "Failed to copy", Toast.LENGTH_SHORT).show(); + return; + } + try { + try (FileOutputStream out = new FileOutputStream( + Environment.getExternalStorageDirectory() + "/surfaceview.png");) { + b.compress(Bitmap.CompressFormat.PNG, 100, out); + } + } catch (Exception e) { + // Ignore + } + }, mVideoView.getHandler()); + }); + + FrameLayout content = new FrameLayout(this); + LinearLayout layout = new LinearLayout(this); + layout.setOrientation(LinearLayout.VERTICAL); + layout.addView(button, LinearLayout.LayoutParams.MATCH_PARENT, + LinearLayout.LayoutParams.WRAP_CONTENT); + layout.addView(mVideoView, LinearLayout.LayoutParams.MATCH_PARENT, + LinearLayout.LayoutParams.MATCH_PARENT); + + content.addView(layout, new FrameLayout.LayoutParams( + FrameLayout.LayoutParams.MATCH_PARENT, + FrameLayout.LayoutParams.MATCH_PARENT)); + setContentView(content); + } +} diff --git a/tools/aapt/Bundle.h b/tools/aapt/Bundle.h index ca06ac440731..653c1b4d6f97 100644 --- a/tools/aapt/Bundle.h +++ b/tools/aapt/Bundle.h @@ -55,7 +55,7 @@ public: mCompressionMethod(0), mJunkPath(false), mOutputAPKFile(NULL), mManifestPackageNameOverride(NULL), mInstrumentationPackageNameOverride(NULL), mAutoAddOverlay(false), mGenDependencies(false), mNoVersionVectors(false), - mCrunchedOutputDir(NULL), mProguardFile(NULL), + mCrunchedOutputDir(NULL), mProguardFile(NULL), mMainDexProguardFile(NULL), mAndroidManifestFile(NULL), mPublicOutputFile(NULL), mRClassDir(NULL), mResourceIntermediatesDir(NULL), mManifestMinSdkVersion(NULL), mMinSdkVersion(NULL), mTargetSdkVersion(NULL), mMaxSdkVersion(NULL), @@ -146,6 +146,8 @@ public: void setCrunchedOutputDir(const char* dir) { mCrunchedOutputDir = dir; } const char* getProguardFile() const { return mProguardFile; } void setProguardFile(const char* file) { mProguardFile = file; } + const char* getMainDexProguardFile() const { return mMainDexProguardFile; } + void setMainDexProguardFile(const char* file) { mMainDexProguardFile = file; } const android::Vector<const char*>& getResourceSourceDirs() const { return mResourceSourceDirs; } void addResourceSourceDir(const char* dir) { mResourceSourceDirs.insertAt(dir,0); } const char* getAndroidManifestFile() const { return mAndroidManifestFile; } @@ -299,6 +301,7 @@ private: bool mNoVersionVectors; const char* mCrunchedOutputDir; const char* mProguardFile; + const char* mMainDexProguardFile; const char* mAndroidManifestFile; const char* mPublicOutputFile; const char* mRClassDir; diff --git a/tools/aapt/Command.cpp b/tools/aapt/Command.cpp index db40416111d5..9976d00fa872 100644 --- a/tools/aapt/Command.cpp +++ b/tools/aapt/Command.cpp @@ -2631,6 +2631,12 @@ int doPackage(Bundle* bundle) goto bail; } + // Write out the Main Dex ProGuard file + err = writeMainDexProguardFile(bundle, assets); + if (err < 0) { + goto bail; + } + // Write the apk if (outputAPKFile) { // Gather all resources and add them to the APK Builder. The builder will then diff --git a/tools/aapt/Main.cpp b/tools/aapt/Main.cpp index c424cc516b56..984d98e30f29 100644 --- a/tools/aapt/Main.cpp +++ b/tools/aapt/Main.cpp @@ -67,6 +67,7 @@ void usage(void) " [--max-res-version VAL] \\\n" " [-I base-package [-I base-package ...]] \\\n" " [-A asset-source-dir] [-G class-list-file] [-P public-definitions-file] \\\n" + " [-D main-dex-class-list-file] \\\n" " [-S resource-sources [-S resource-sources ...]] \\\n" " [-F apk-file] [-J R-file-dir] \\\n" " [--product product1,product2,...] \\\n" @@ -120,6 +121,7 @@ void usage(void) " localization=\"suggested\"\n" " -A additional directory in which to find raw asset files\n" " -G A file to output proguard options into.\n" + " -D A file to output proguard options for the main dex into.\n" " -F specify the apk file to output\n" " -I add an existing package to base include set\n" " -J specify where to output R.java resource constant definitions\n" @@ -390,6 +392,17 @@ int main(int argc, char* const argv[]) convertPath(argv[0]); bundle.setProguardFile(argv[0]); break; + case 'D': + argc--; + argv++; + if (!argc) { + fprintf(stderr, "ERROR: No argument supplied for '-D' option\n"); + wantUsage = true; + goto bail; + } + convertPath(argv[0]); + bundle.setMainDexProguardFile(argv[0]); + break; case 'I': argc--; argv++; diff --git a/tools/aapt/Main.h b/tools/aapt/Main.h index e84c4c503cd2..a493842b8d10 100644 --- a/tools/aapt/Main.h +++ b/tools/aapt/Main.h @@ -54,6 +54,7 @@ extern android::status_t writeResourceSymbols(Bundle* bundle, bool includePrivate, bool emitCallback); extern android::status_t writeProguardFile(Bundle* bundle, const sp<AaptAssets>& assets); +extern android::status_t writeMainDexProguardFile(Bundle* bundle, const sp<AaptAssets>& assets); extern bool isValidResourceType(const String8& type); diff --git a/tools/aapt/Resource.cpp b/tools/aapt/Resource.cpp index 18a194326de7..8e7045bd07e1 100644 --- a/tools/aapt/Resource.cpp +++ b/tools/aapt/Resource.cpp @@ -2832,7 +2832,7 @@ addProguardKeepMethodRule(ProguardKeepSet* keep, const String8& memberName, } status_t -writeProguardForAndroidManifest(ProguardKeepSet* keep, const sp<AaptAssets>& assets) +writeProguardForAndroidManifest(ProguardKeepSet* keep, const sp<AaptAssets>& assets, bool mainDex) { status_t err; ResXMLTree tree; @@ -2844,6 +2844,7 @@ writeProguardForAndroidManifest(ProguardKeepSet* keep, const sp<AaptAssets>& ass sp<AaptGroup> assGroup; sp<AaptFile> assFile; String8 pkg; + String8 defaultProcess; // First, look for a package file to parse. This is required to // be able to generate the resource information. @@ -2900,6 +2901,15 @@ writeProguardForAndroidManifest(ProguardKeepSet* keep, const sp<AaptAssets>& ass addProguardKeepRule(keep, agent, pkg.string(), assFile->getPrintableSource(), tree.getLineNumber()); } + + if (mainDex) { + defaultProcess = AaptXml::getAttribute(tree, + "http://schemas.android.com/apk/res/android", "process", &error); + if (error != "") { + fprintf(stderr, "ERROR: %s\n", error.string()); + return -1; + } + } } else if (tag == "instrumentation") { keepTag = true; } @@ -2916,7 +2926,23 @@ writeProguardForAndroidManifest(ProguardKeepSet* keep, const sp<AaptAssets>& ass fprintf(stderr, "ERROR: %s\n", error.string()); return -1; } - if (name.length() > 0) { + + keepTag = name.length() > 0; + + if (keepTag && mainDex) { + String8 componentProcess = AaptXml::getAttribute(tree, + "http://schemas.android.com/apk/res/android", "process", &error); + if (error != "") { + fprintf(stderr, "ERROR: %s\n", error.string()); + return -1; + } + + const String8& process = + componentProcess.length() > 0 ? componentProcess : defaultProcess; + keepTag = process.length() > 0 && process.find(":") != 0; + } + + if (keepTag) { addProguardKeepRule(keep, name, pkg.string(), assFile->getPrintableSource(), tree.getLineNumber()); } @@ -3099,6 +3125,31 @@ writeProguardForLayouts(ProguardKeepSet* keep, const sp<AaptAssets>& assets) } status_t +writeProguardSpec(const char* filename, const ProguardKeepSet& keep, status_t err) +{ + FILE* fp = fopen(filename, "w+"); + if (fp == NULL) { + fprintf(stderr, "ERROR: Unable to open class file %s: %s\n", + filename, strerror(errno)); + return UNKNOWN_ERROR; + } + + const KeyedVector<String8, SortedVector<String8> >& rules = keep.rules; + const size_t N = rules.size(); + for (size_t i=0; i<N; i++) { + const SortedVector<String8>& locations = rules.valueAt(i); + const size_t M = locations.size(); + for (size_t j=0; j<M; j++) { + fprintf(fp, "# %s\n", locations.itemAt(j).string()); + } + fprintf(fp, "%s\n\n", rules.keyAt(i).string()); + } + fclose(fp); + + return err; +} + +status_t writeProguardFile(Bundle* bundle, const sp<AaptAssets>& assets) { status_t err = -1; @@ -3109,7 +3160,7 @@ writeProguardFile(Bundle* bundle, const sp<AaptAssets>& assets) ProguardKeepSet keep; - err = writeProguardForAndroidManifest(&keep, assets); + err = writeProguardForAndroidManifest(&keep, assets, false); if (err < 0) { return err; } @@ -3119,26 +3170,26 @@ writeProguardFile(Bundle* bundle, const sp<AaptAssets>& assets) return err; } - FILE* fp = fopen(bundle->getProguardFile(), "w+"); - if (fp == NULL) { - fprintf(stderr, "ERROR: Unable to open class file %s: %s\n", - bundle->getProguardFile(), strerror(errno)); - return UNKNOWN_ERROR; + return writeProguardSpec(bundle->getProguardFile(), keep, err); +} + +status_t +writeMainDexProguardFile(Bundle* bundle, const sp<AaptAssets>& assets) +{ + status_t err = -1; + + if (!bundle->getMainDexProguardFile()) { + return NO_ERROR; } - const KeyedVector<String8, SortedVector<String8> >& rules = keep.rules; - const size_t N = rules.size(); - for (size_t i=0; i<N; i++) { - const SortedVector<String8>& locations = rules.valueAt(i); - const size_t M = locations.size(); - for (size_t j=0; j<M; j++) { - fprintf(fp, "# %s\n", locations.itemAt(j).string()); - } - fprintf(fp, "%s\n\n", rules.keyAt(i).string()); + ProguardKeepSet keep; + + err = writeProguardForAndroidManifest(&keep, assets, true); + if (err < 0) { + return err; } - fclose(fp); - return err; + return writeProguardSpec(bundle->getMainDexProguardFile(), keep, err); } // Loops through the string paths and writes them to the file pointer diff --git a/tools/aapt2/link/Link.cpp b/tools/aapt2/link/Link.cpp index 8c8bffafdc45..49971201fb3c 100644 --- a/tools/aapt2/link/Link.cpp +++ b/tools/aapt2/link/Link.cpp @@ -1459,6 +1459,21 @@ int link(const std::vector<StringPiece>& args) { return 1; } + // Expand all argument-files passed into the command line. These start with '@'. + std::vector<std::string> argList; + for (const std::string& arg : flags.getArgs()) { + if (util::stringStartsWith<char>(arg, "@")) { + const std::string path = arg.substr(1, arg.size() - 1); + std::string error; + if (!file::appendArgsFromFile(path, &argList, &error)) { + context.getDiagnostics()->error(DiagMessage(path) << error); + return 1; + } + } else { + argList.push_back(arg); + } + } + if (verbose) { context.setVerbose(verbose); } @@ -1568,7 +1583,7 @@ int link(const std::vector<StringPiece>& args) { } LinkCommand cmd(&context, options); - return cmd.run(flags.getArgs()); + return cmd.run(argList); } } // namespace aapt diff --git a/tools/aapt2/util/Files.cpp b/tools/aapt2/util/Files.cpp index bb093abbce63..f5e49f11c082 100644 --- a/tools/aapt2/util/Files.cpp +++ b/tools/aapt2/util/Files.cpp @@ -18,6 +18,7 @@ #include "util/Util.h" #include <algorithm> +#include <android-base/file.h> #include <cerrno> #include <cstdio> #include <dirent.h> @@ -190,6 +191,23 @@ Maybe<android::FileMap> mmapPath(const StringPiece& path, std::string* outError) return std::move(fileMap); } +bool appendArgsFromFile(const StringPiece& path, std::vector<std::string>* outArgList, + std::string* outError) { + std::string contents; + if (!android::base::ReadFileToString(path.toString(), &contents)) { + if (outError) *outError = "failed to read argument-list file"; + return false; + } + + for (StringPiece line : util::tokenize<char>(contents, ' ')) { + line = util::trimWhitespace(line); + if (!line.empty()) { + outArgList->push_back(line.toString()); + } + } + return true; +} + bool FileFilter::setPattern(const StringPiece& pattern) { mPatternTokens = util::splitAndLowercase(pattern, ':'); return true; diff --git a/tools/aapt2/util/Files.h b/tools/aapt2/util/Files.h index c2e611543b1e..4d8a1feb63b1 100644 --- a/tools/aapt2/util/Files.h +++ b/tools/aapt2/util/Files.h @@ -95,6 +95,12 @@ std::string packageToPath(const StringPiece& package); */ Maybe<android::FileMap> mmapPath(const StringPiece& path, std::string* outError); +/** + * Reads the file at path and appends each line to the outArgList vector. + */ +bool appendArgsFromFile(const StringPiece& path, std::vector<std::string>* outArgList, + std::string* outError); + /* * Filter that determines which resource files/directories are * processed by AAPT. Takes a pattern string supplied by the user. diff --git a/tools/fonts/fontchain_lint.py b/tools/fonts/fontchain_lint.py index 81ab3ccf3ec5..fe7c3b9b400f 100755 --- a/tools/fonts/fontchain_lint.py +++ b/tools/fonts/fontchain_lint.py @@ -330,7 +330,7 @@ def check_emoji_defaults(default_emoji): 0x2764, # HEAVY BLACK HEART } assert missing_text_chars == set(), ( - 'Text style version of some emoji characters are missing.') + 'Text style version of some emoji characters are missing: ' + repr(missing_text_chars)) # Setting reverse to true returns a dictionary that maps the values to sets of @@ -411,6 +411,20 @@ def parse_ucd(ucd_path): _emoji_zwj_sequences = parse_unicode_datafile( path.join(ucd_path, 'emoji-zwj-sequences.txt')) + # filter modern pentathlon, as it seems likely to be removed from final spec + def is_excluded(n): + return n == 0x1f93b + + def contains_excluded(t): + if type(t) == int: + return is_excluded(t) + return any(is_excluded(cp) for cp in t) + + # filter modern pentathlon, as it seems likely to be removed from final spec + _emoji_properties['Emoji'] = set( + t for t in _emoji_properties['Emoji'] if not contains_excluded(t)) + _emoji_sequences = dict( + (t, v) for (t, v) in _emoji_sequences.items() if not contains_excluded(t)) def flag_sequence(territory_code): return tuple(0x1F1E6 + ord(ch) - ord('A') for ch in territory_code) diff --git a/tools/layoutlib/Android.mk b/tools/layoutlib/Android.mk index 663e1e25e603..f87f6c53c8dc 100644 --- a/tools/layoutlib/Android.mk +++ b/tools/layoutlib/Android.mk @@ -16,8 +16,6 @@ LOCAL_PATH := $(my-dir) include $(CLEAR_VARS) -LOCAL_JAVA_LANGUAGE_VERSION := 1.8 - # # Define rules to build temp_layoutlib.jar, which contains a subset of # the classes in framework.jar. The layoutlib_create tool is used to diff --git a/tools/layoutlib/bridge/Android.mk b/tools/layoutlib/bridge/Android.mk index 16e5913ab81d..3dd8002bcff5 100644 --- a/tools/layoutlib/bridge/Android.mk +++ b/tools/layoutlib/bridge/Android.mk @@ -18,7 +18,6 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES := $(call all-java-files-under,src) LOCAL_JAVA_RESOURCE_DIRS := resources -LOCAL_JAVA_LANGUAGE_VERSION := 1.8 LOCAL_JAVA_LIBRARIES := \ layoutlib_api-prebuilt \ 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 80e230cd8b86..f87269b7c9f7 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 @@ -861,7 +861,9 @@ public final class BridgeContext extends Context { resValue = mRenderResources.resolveResValue(resValue); if (defaultPropMap != null) { - defaultPropMap.put(attrName, + defaultPropMap.put( + frameworkAttr ? SdkConstants.PREFIX_ANDROID + attrName : + attrName, new Property(preResolve, resValue.getValue())); } @@ -932,7 +934,8 @@ public final class BridgeContext extends Context { @Nullable StyleResourceValue style, int[] attrs) throws Resources.NotFoundException { List<Pair<String, Boolean>> attributes = searchAttrs(attrs); - BridgeTypedArray ta = Resources_Delegate.newTypeArray(mSystemResources, attrs.length, false); + BridgeTypedArray ta = + Resources_Delegate.newTypeArray(mSystemResources, attrs.length, false); PropertiesMap defaultPropMap = new PropertiesMap(); // for each attribute, get its name so that we can search it in the style @@ -943,11 +946,11 @@ public final class BridgeContext extends Context { // look for the value in the given style ResourceValue resValue; String attrName = attribute.getFirst(); + boolean frameworkAttr = attribute.getSecond(); if (style != null) { - resValue = mRenderResources.findItemInStyle(style, attrName, - attribute.getSecond()); + resValue = mRenderResources.findItemInStyle(style, attrName, frameworkAttr); } else { - resValue = mRenderResources.findItemInTheme(attrName, attribute.getSecond()); + resValue = mRenderResources.findItemInTheme(attrName, frameworkAttr); } if (resValue != null) { @@ -955,8 +958,10 @@ public final class BridgeContext extends Context { String preResolve = resValue.getValue(); // resolve it to make sure there are no references left. resValue = mRenderResources.resolveResValue(resValue); - ta.bridgeSetValue(i, attrName, attribute.getSecond(), resValue); - defaultPropMap.put(attrName, new Property(preResolve, resValue.getValue())); + ta.bridgeSetValue(i, attrName, frameworkAttr, resValue); + defaultPropMap.put( + frameworkAttr ? SdkConstants.ANDROID_PREFIX + attrName : attrName, + new Property(preResolve, resValue.getValue())); } } } diff --git a/tools/layoutlib/bridge/tests/Android.mk b/tools/layoutlib/bridge/tests/Android.mk index 5c062d0c7042..8a81d0b684db 100644 --- a/tools/layoutlib/bridge/tests/Android.mk +++ b/tools/layoutlib/bridge/tests/Android.mk @@ -16,8 +16,6 @@ LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) -LOCAL_JAVA_LANGUAGE_VERSION := 1.8 - # Only compile source java files in this lib. LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_JAVA_RESOURCE_DIRS := res diff --git a/tools/layoutlib/create/Android.mk b/tools/layoutlib/create/Android.mk index 47377ae42d01..c7f2c4137687 100644 --- a/tools/layoutlib/create/Android.mk +++ b/tools/layoutlib/create/Android.mk @@ -16,8 +16,6 @@ LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) -LOCAL_JAVA_LANGUAGE_VERSION := 1.8 - LOCAL_SRC_FILES := $(call all-java-files-under,src) LOCAL_JAR_MANIFEST := manifest.txt diff --git a/tools/layoutlib/create/tests/Android.mk b/tools/layoutlib/create/tests/Android.mk index c59528e81ef2..dafb9c6f9402 100644 --- a/tools/layoutlib/create/tests/Android.mk +++ b/tools/layoutlib/create/tests/Android.mk @@ -15,8 +15,6 @@ LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) -LOCAL_JAVA_LANGUAGE_VERSION := 1.8 - # Only compile source java files in this lib. LOCAL_SRC_FILES := $(call all-java-files-under, com) |