summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/animation/ValueAnimator.java20
-rw-r--r--core/java/android/app/Activity.java20
-rw-r--r--core/java/android/app/ActivityThread.java72
-rw-r--r--core/java/android/app/AppOpsManager.java9
-rw-r--r--core/java/android/app/LoadedApk.java18
-rw-r--r--core/java/android/app/Notification.java26
-rw-r--r--core/java/android/app/WallpaperManager.java3
-rw-r--r--core/java/android/app/admin/DevicePolicyManagerInternal.java12
-rw-r--r--core/java/android/content/pm/PackageManagerInternal.java13
-rw-r--r--core/java/android/hardware/camera2/impl/CameraDeviceImpl.java42
-rw-r--r--core/java/android/hardware/camera2/marshal/MarshalRegistry.java78
-rw-r--r--core/java/android/os/BatteryStats.java59
-rw-r--r--core/java/android/os/ParcelFileDescriptor.java28
-rw-r--r--core/java/android/os/RecoverySystem.java6
-rw-r--r--core/java/android/security/net/config/SystemCertificateSource.java7
-rw-r--r--core/java/android/security/net/config/UserCertificateSource.java6
-rw-r--r--core/java/android/view/SurfaceControl.java11
-rw-r--r--core/java/android/view/View.java12
-rw-r--r--core/java/android/view/ViewRootImpl.java4
-rw-r--r--core/java/android/view/accessibility/AccessibilityWindowInfo.java4
-rw-r--r--core/java/com/android/internal/os/BatteryStatsImpl.java50
-rw-r--r--core/java/com/android/internal/policy/DecorView.java29
-rw-r--r--core/java/com/android/internal/policy/PhoneWindow.java14
-rw-r--r--core/java/com/android/internal/widget/MessagingLinearLayout.java22
-rw-r--r--core/jni/android_view_SurfaceControl.cpp11
-rw-r--r--core/res/AndroidManifest.xml10
-rw-r--r--core/res/res/values-da/strings.xml4
-rw-r--r--core/res/res/values-de/strings.xml6
-rw-r--r--core/res/res/values-hy-rAM/strings.xml6
-rw-r--r--core/res/res/values-lt/strings.xml4
-rw-r--r--core/res/res/values-mn-rMN/strings.xml14
-rw-r--r--core/res/res/values-pt-rPT/strings.xml10
-rw-r--r--core/res/res/values/themes.xml1
-rw-r--r--docs/html/guide/practices/screens_support.jd8
-rw-r--r--docs/html/guide/topics/manifest/activity-element.jd2
-rw-r--r--docs/html/jd_extras_en.js7
-rw-r--r--docs/html/ndk/guides/graphics/getting-started.jd2
-rw-r--r--docs/html/ndk/guides/graphics/validation-layer.jd286
-rw-r--r--docs/html/preview/_book.yaml2
-rw-r--r--docs/html/preview/api-overview.jd65
-rw-r--r--docs/html/preview/features/key-attestation.jd845
-rw-r--r--docs/html/preview/features/multi-window.jd2
-rw-r--r--docs/html/preview/index.jd19
-rw-r--r--docs/html/preview/setup-sdk.jd8
-rwxr-xr-xdocs/html/topic/libraries/support-library/features.jd2
-rw-r--r--docs/html/topic/libraries/testing-support-library/index.jd2
-rw-r--r--docs/html/training/appbar/setting-up.jd2
-rw-r--r--docs/html/training/basics/supporting-devices/languages.jd2
-rw-r--r--docs/html/training/testing/performance.jd20
-rw-r--r--docs/html/training/wearables/data-layer/events.jd61
-rw-r--r--libs/hwui/Android.mk1
-rw-r--r--libs/hwui/BakedOpRenderer.cpp9
-rw-r--r--libs/hwui/FrameBuilder.cpp4
-rw-r--r--libs/hwui/RenderNode.cpp2
-rw-r--r--libs/hwui/RenderProperties.h4
-rw-r--r--libs/hwui/tests/unit/RenderPropertiesTests.cpp48
-rw-r--r--packages/CtsShim/Android.mk1
-rw-r--r--packages/CtsShim/build/Android.mk24
-rw-r--r--packages/CtsShim/build/README29
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/OpenExternalDirectoryActivity.java33
-rw-r--r--packages/PrintRecommendationService/res/values/strings.xml2
-rw-r--r--packages/PrintRecommendationService/res/xml/vendorconfigs.xml2
-rwxr-xr-xpackages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/xerox/MDnsUtils.java6
-rw-r--r--packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java3
-rw-r--r--packages/PrintSpooler/src/com/android/printspooler/util/MediaSizeUtils.java96
-rw-r--r--packages/Shell/AndroidManifest.xml2
-rw-r--r--packages/SystemUI/res/values-da/strings.xml6
-rw-r--r--packages/SystemUI/res/values-hy-rAM/strings.xml12
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSFooter.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskCardView.java17
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationMessagingTemplateViewWrapper.java73
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java18
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/DateView.java10
-rw-r--r--rs/java/android/renderscript/RenderScript.java14
-rw-r--r--rs/java/android/renderscript/Script.java31
-rw-r--r--rs/jni/android_renderscript_RenderScript.cpp70
-rw-r--r--services/backup/java/com/android/server/backup/BackupManagerService.java6
-rw-r--r--services/core/java/com/android/server/BluetoothManagerService.java2
-rw-r--r--services/core/java/com/android/server/ConnectivityService.java4
-rw-r--r--services/core/java/com/android/server/LocationManagerService.java7
-rw-r--r--services/core/java/com/android/server/MountService.java3
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java25
-rw-r--r--services/core/java/com/android/server/am/ActivityStack.java8
-rw-r--r--services/core/java/com/android/server/am/ActivityStackSupervisor.java16
-rw-r--r--services/core/java/com/android/server/am/ActivityStarter.java16
-rw-r--r--services/core/java/com/android/server/am/RecentTasks.java3
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java33
-rw-r--r--services/core/java/com/android/server/pm/ProtectedPackages.java89
-rw-r--r--services/core/java/com/android/server/pm/UserManagerService.java111
-rw-r--r--services/core/java/com/android/server/policy/PhoneWindowManager.java9
-rw-r--r--services/core/java/com/android/server/vr/VrManagerService.java152
-rw-r--r--services/core/java/com/android/server/wm/AccessibilityController.java3
-rw-r--r--services/core/java/com/android/server/wm/WindowStateAnimator.java68
-rw-r--r--services/core/java/com/android/server/wm/WindowSurfaceController.java157
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java23
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/Owners.java24
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java4
100 files changed, 2398 insertions, 860 deletions
diff --git a/core/java/android/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java
index 4edf249ce065..0c7ee2c8c2fe 100644
--- a/core/java/android/animation/ValueAnimator.java
+++ b/core/java/android/animation/ValueAnimator.java
@@ -602,7 +602,9 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio
long currentTime = AnimationUtils.currentAnimationTimeMillis();
mStartTime = currentTime - seekTime;
mStartTimeCommitted = true; // do not allow start time to be compensated for jank
- if (!mRunning) {
+ if (!isPulsingInternal()) {
+ // If the animation loop hasn't started, the startTime will be adjusted in the first
+ // frame based on seek fraction.
mSeekFraction = fraction;
}
mOverallFraction = fraction;
@@ -980,6 +982,10 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio
mStarted = true;
mPaused = false;
mRunning = false;
+ // Resets mLastFrameTime when start() is called, so that if the animation was running,
+ // calling start() would put the animation in the
+ // started-but-not-yet-reached-the-first-frame phase.
+ mLastFrameTime = 0;
AnimationHandler animationHandler = AnimationHandler.getInstance();
animationHandler.addAnimationFrameCallback(this, (long) (mStartDelay * sDurationScale));
@@ -1095,7 +1101,7 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio
*/
@Override
public void reverse() {
- if (mRunning) {
+ if (isPulsingInternal()) {
long currentTime = AnimationUtils.currentAnimationTimeMillis();
long currentPlayTime = currentTime - mStartTime;
long timeLeft = getScaledDuration() - currentPlayTime;
@@ -1103,6 +1109,7 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio
mStartTimeCommitted = true; // do not allow start time to be compensated for jank
mReversing = !mReversing;
} else if (mStarted) {
+ mReversing = !mReversing;
end();
} else {
start(true);
@@ -1177,6 +1184,15 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio
}
/**
+ * Internal only: This tracks whether the animation has gotten on the animation loop. Note
+ * this is different than {@link #isRunning()} in that the latter tracks the time after start()
+ * is called (or after start delay if any), which may be before the animation loop starts.
+ */
+ private boolean isPulsingInternal() {
+ return mLastFrameTime > 0;
+ }
+
+ /**
* Returns the name of this animator for debugging purposes.
*/
String getNameForTrace() {
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index a5fcec622956..13cf46d11519 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -57,6 +57,7 @@ import android.hardware.input.InputManager;
import android.media.AudioManager;
import android.media.session.MediaController;
import android.net.Uri;
+import android.os.BadParcelableException;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
@@ -5006,13 +5007,18 @@ public class Activity extends ContextThemeWrapper
@Nullable
public Uri getReferrer() {
Intent intent = getIntent();
- Uri referrer = intent.getParcelableExtra(Intent.EXTRA_REFERRER);
- if (referrer != null) {
- return referrer;
- }
- String referrerName = intent.getStringExtra(Intent.EXTRA_REFERRER_NAME);
- if (referrerName != null) {
- return Uri.parse(referrerName);
+ try {
+ Uri referrer = intent.getParcelableExtra(Intent.EXTRA_REFERRER);
+ if (referrer != null) {
+ return referrer;
+ }
+ String referrerName = intent.getStringExtra(Intent.EXTRA_REFERRER_NAME);
+ if (referrerName != null) {
+ return Uri.parse(referrerName);
+ }
+ } catch (BadParcelableException e) {
+ Log.w(TAG, "Cannot read referrer from intent;"
+ + " intent extras contain unknown custom Parcelable objects");
}
if (mReferrer != null) {
return new Uri.Builder().scheme("android-app").authority(mReferrer).build();
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 2c2f6c17370c..0728bdfc4016 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -16,6 +16,8 @@
package android.app;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.assist.AssistContent;
import android.app.assist.AssistStructure;
import android.app.backup.BackupAgent;
@@ -4578,20 +4580,37 @@ public final class ActivityThread {
}
/**
+ * Creates a new Configuration only if override would modify base. Otherwise returns base.
+ * @param base The base configuration.
+ * @param override The update to apply to the base configuration. Can be null.
+ * @return A Configuration representing base with override applied.
+ */
+ private static Configuration createNewConfigAndUpdateIfNotNull(@NonNull Configuration base,
+ @Nullable Configuration override) {
+ if (override == null) {
+ return base;
+ }
+ Configuration newConfig = new Configuration(base);
+ newConfig.updateFrom(override);
+ return newConfig;
+ }
+
+ /**
* Decides whether to update an Activity's configuration and whether to tell the
* Activity/Component about it.
* @param cb The component callback to notify of configuration change.
* @param activityToken The Activity binder token for which this configuration change happened.
* If the change is global, this is null.
* @param newConfig The new configuration.
- * @param overrideConfig The override config that differentiates the Activity's configuration
+ * @param amOverrideConfig The override config that differentiates the Activity's configuration
* from the base global configuration.
+ * This is supplied by ActivityManager.
* @param reportToActivity Notify the Activity of the change.
*/
private void performConfigurationChanged(ComponentCallbacks2 cb,
IBinder activityToken,
Configuration newConfig,
- Configuration overrideConfig,
+ Configuration amOverrideConfig,
boolean reportToActivity) {
// Only for Activity objects, check that they actually call up to their
// superclass implementation. ComponentCallbacks2 is an interface, so
@@ -4605,7 +4624,6 @@ public final class ActivityThread {
if ((activity == null) || (activity.mCurrentConfig == null)) {
shouldChangeConfig = true;
} else {
-
// If the new config is the same as the config this Activity
// is already running with then don't bother calling
// onConfigurationChanged
@@ -4615,34 +4633,36 @@ public final class ActivityThread {
}
}
- if (DEBUG_CONFIGURATION) {
- Slog.v(TAG, "Config callback " + cb + ": shouldChangeConfig=" + shouldChangeConfig);
- }
-
if (shouldChangeConfig) {
+ // Propagate the configuration change to the Activity and ResourcesManager.
+
+ // ContextThemeWrappers may override the configuration for that context.
+ // We must check and apply any overrides defined.
+ Configuration contextThemeWrapperOverrideConfig = null;
+ if (cb instanceof ContextThemeWrapper) {
+ final ContextThemeWrapper contextThemeWrapper = (ContextThemeWrapper) cb;
+ contextThemeWrapperOverrideConfig = contextThemeWrapper.getOverrideConfiguration();
+ }
+
+ // We only update an Activity's configuration if this is not a global
+ // configuration change. This must also be done before the callback,
+ // or else we violate the contract that the new resources are available
+ // in {@link ComponentCallbacks2#onConfigurationChanged(Configuration)}.
if (activityToken != null) {
- // We only update an Activity's configuration if this is not a global
- // configuration change. This must also be done before the callback,
- // or else we violate the contract that the new resources are available
- // in {@link ComponentCallbacks2#onConfigurationChanged(Configuration)}.
- mResourcesManager.updateResourcesForActivity(activityToken, overrideConfig);
+ // Apply the ContextThemeWrapper override if necessary.
+ // NOTE: Make sure the configurations are not modified, as they are treated
+ // as immutable in many places.
+ final Configuration finalOverrideConfig = createNewConfigAndUpdateIfNotNull(
+ amOverrideConfig, contextThemeWrapperOverrideConfig);
+ mResourcesManager.updateResourcesForActivity(activityToken, finalOverrideConfig);
}
if (reportToActivity) {
- Configuration configToReport = newConfig;
-
- if (cb instanceof ContextThemeWrapper) {
- // ContextThemeWrappers may override the configuration for that context.
- // We must check and apply any overrides defined.
- ContextThemeWrapper contextThemeWrapper = (ContextThemeWrapper) cb;
- final Configuration localOverrideConfig =
- contextThemeWrapper.getOverrideConfiguration();
- if (localOverrideConfig != null) {
- configToReport = new Configuration(newConfig);
- configToReport.updateFrom(localOverrideConfig);
- }
- }
-
+ // Apply the ContextThemeWrapper override if necessary.
+ // NOTE: Make sure the configurations are not modified, as they are treated
+ // as immutable in many places.
+ final Configuration configToReport = createNewConfigAndUpdateIfNotNull(
+ newConfig, contextThemeWrapperOverrideConfig);
cb.onConfigurationChanged(configToReport);
}
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index e526c17dde9d..1e4ffbeca33d 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -1340,9 +1340,14 @@ public class AppOpsManager {
/** @hide */
public void setUserRestriction(int code, boolean restricted, IBinder token,
String[] exceptionPackages) {
+ setUserRestrictionForUser(code, restricted, token, exceptionPackages, mContext.getUserId());
+ }
+
+ /** @hide */
+ public void setUserRestrictionForUser(int code, boolean restricted, IBinder token,
+ String[] exceptionPackages, int userId) {
try {
- mService.setUserRestriction(code, restricted, token, mContext.getUserId(),
- exceptionPackages);
+ mService.setUserRestriction(code, restricted, token, userId, exceptionPackages);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index 152f45e35287..0b62ed2b0917 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -1191,14 +1191,18 @@ public final class LoadedApk {
public void performReceive(Intent intent, int resultCode, String data,
Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
- if (ActivityThread.DEBUG_BROADCAST) {
- int seq = intent.getIntExtra("seq", -1);
- Slog.i(ActivityThread.TAG, "Enqueueing broadcast " + intent.getAction() + " seq=" + seq
- + " to " + mReceiver);
- }
- Args args = new Args(intent, resultCode, data, extras, ordered,
+ final Args args = new Args(intent, resultCode, data, extras, ordered,
sticky, sendingUser);
- if (!mActivityThread.post(args)) {
+ if (intent == null) {
+ Log.wtf(TAG, "Null intent received");
+ } else {
+ if (ActivityThread.DEBUG_BROADCAST) {
+ int seq = intent.getIntExtra("seq", -1);
+ Slog.i(ActivityThread.TAG, "Enqueueing broadcast " + intent.getAction()
+ + " seq=" + seq + " to " + mReceiver);
+ }
+ }
+ if (intent == null || !mActivityThread.post(args)) {
if (mRegistered && ordered) {
IActivityManager mgr = ActivityManagerNative.getDefault();
if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 83a20668b3b4..0fca78d5e8dc 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -4570,12 +4570,21 @@ public class Notification implements Parcelable
: mConversationTitle;
boolean hasTitle = !TextUtils.isEmpty(title);
- if (!hasTitle && mMessages.size() == 1) {
- CharSequence sender = mMessages.get(0).mSender;
- CharSequence text = mMessages.get(0).mText;
+ if (mMessages.size() == 1) {
+ // Special case for a single message: Use the big text style
+ // so the collapsed and expanded versions match nicely.
+ CharSequence bigTitle;
+ CharSequence text;
+ if (hasTitle) {
+ bigTitle = title;
+ text = makeMessageLine(mMessages.get(0));
+ } else {
+ bigTitle = mMessages.get(0).mSender;
+ text = mMessages.get(0).mText;
+ }
RemoteViews contentView = mBuilder.applyStandardTemplateWithActions(
mBuilder.getBigTextLayoutResource(),
- false /* progress */, sender, null /* text */);
+ false /* progress */, bigTitle, null /* text */);
BigTextStyle.applyBigTextContentView(mBuilder, contentView, text);
return contentView;
}
@@ -4601,6 +4610,8 @@ public class Notification implements Parcelable
contentView.setInt(R.id.notification_messaging, "setNumIndentLines",
mBuilder.mN.mLargeIcon == null ? 0 : (hasTitle ? 1 : 2));
+ int contractedChildId = View.NO_ID;
+ Message contractedMessage = findLatestIncomingMessage();
int firstMessage = Math.max(0, mMessages.size() - rowIds.length);
while (firstMessage + i < mMessages.size() && i < rowIds.length) {
Message m = mMessages.get(firstMessage + i);
@@ -4609,8 +4620,15 @@ public class Notification implements Parcelable
contentView.setViewVisibility(rowId, View.VISIBLE);
contentView.setTextViewText(rowId, makeMessageLine(m));
+ if (contractedMessage == m) {
+ contractedChildId = rowId;
+ }
+
i++;
}
+ // Record this here to allow transformation between the contracted and expanded views.
+ contentView.setInt(R.id.notification_messaging, "setContractedChildId",
+ contractedChildId);
return contentView;
}
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index 18f93cd4688a..7f467f0585c8 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -1576,8 +1576,11 @@ public class WallpaperManager {
final String whichProp;
final int defaultResId;
if (which == FLAG_LOCK) {
+ /* Factory-default lock wallpapers are not yet supported
whichProp = PROP_LOCK_WALLPAPER;
defaultResId = com.android.internal.R.drawable.default_lock_wallpaper;
+ */
+ return null;
} else {
whichProp = PROP_WALLPAPER;
defaultResId = com.android.internal.R.drawable.default_wallpaper;
diff --git a/core/java/android/app/admin/DevicePolicyManagerInternal.java b/core/java/android/app/admin/DevicePolicyManagerInternal.java
index 54a2f7aff7d6..e98bb7e7a9fd 100644
--- a/core/java/android/app/admin/DevicePolicyManagerInternal.java
+++ b/core/java/android/app/admin/DevicePolicyManagerInternal.java
@@ -17,7 +17,6 @@
package android.app.admin;
import android.content.Intent;
-import android.os.UserHandle;
import java.util.List;
@@ -74,17 +73,6 @@ public abstract class DevicePolicyManagerInternal {
public abstract boolean isActiveAdminWithPolicy(int uid, int reqPolicy);
/**
- * Checks if a given package has a device or a profile owner for the given user.
- * <p>
- * <em>Note: does <b>not</b> support negative userIds like {@link UserHandle#USER_ALL}</em>
- *
- * @param packageName The package to check
- * @param userId the userId to check for.
- * @return true if package has a device or profile owner, false otherwise.
- */
- public abstract boolean hasDeviceOwnerOrProfileOwner(String packageName, int userId);
-
- /**
* Creates an intent to show the admin support dialog to let the user know that the package is
* suspended by the admin. This assumes that {@param packageName} is suspended by the
* device/profile owner. The caller should check if the package is suspended or not.
diff --git a/core/java/android/content/pm/PackageManagerInternal.java b/core/java/android/content/pm/PackageManagerInternal.java
index 13ebb823bd78..14f7727e61a0 100644
--- a/core/java/android/content/pm/PackageManagerInternal.java
+++ b/core/java/android/content/pm/PackageManagerInternal.java
@@ -18,6 +18,7 @@ package android.content.pm;
import android.content.ComponentName;
import android.content.pm.PackageManager.NameNotFoundException;
+import android.util.SparseArray;
import java.util.List;
@@ -147,4 +148,16 @@ public abstract class PackageManagerInternal {
*/
public abstract ComponentName getHomeActivitiesAsUser(List<ResolveInfo> allHomeCandidates,
int userId);
+
+ /**
+ * Called by DeviceOwnerManagerService to set the package names of device owner and profile
+ * owners.
+ */
+ public abstract void setDeviceAndProfileOwnerPackages(
+ int deviceOwnerUserId, String deviceOwner, SparseArray<String> profileOwners);
+
+ /**
+ * Whether a package's data be cleared.
+ */
+ public abstract boolean canPackageBeWiped(int userId, String packageName);
}
diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
index 5743b4d42a37..0cee11445246 100644
--- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
@@ -1610,41 +1610,6 @@ public class CameraDeviceImpl extends CameraDevice
}
public class CameraDeviceCallbacks extends ICameraDeviceCallbacks.Stub {
- //
- // Constants below need to be kept up-to-date with
- // frameworks/av/include/camera/camera2/ICameraDeviceCallbacks.h
- //
-
- //
- // Error codes for onCameraError
- //
-
- /**
- * Camera has been disconnected
- */
- public static final int ERROR_CAMERA_DISCONNECTED = 0;
- /**
- * Camera has encountered a device-level error
- * Matches CameraDevice.StateCallback#ERROR_CAMERA_DEVICE
- */
- public static final int ERROR_CAMERA_DEVICE = 1;
- /**
- * Camera has encountered a service-level error
- * Matches CameraDevice.StateCallback#ERROR_CAMERA_SERVICE
- */
- public static final int ERROR_CAMERA_SERVICE = 2;
- /**
- * Camera has encountered an error processing a single request.
- */
- public static final int ERROR_CAMERA_REQUEST = 3;
- /**
- * Camera has encountered an error producing metadata for a single capture
- */
- public static final int ERROR_CAMERA_RESULT = 4;
- /**
- * Camera has encountered an error producing an image buffer for a single capture
- */
- public static final int ERROR_CAMERA_BUFFER = 5;
@Override
public IBinder asBinder() {
@@ -1675,11 +1640,14 @@ public class CameraDeviceImpl extends CameraDevice
case ERROR_CAMERA_DEVICE:
case ERROR_CAMERA_SERVICE:
mInError = true;
+ final int publicErrorCode = (errorCode == ERROR_CAMERA_DEVICE) ?
+ StateCallback.ERROR_CAMERA_DEVICE :
+ StateCallback.ERROR_CAMERA_SERVICE;
Runnable r = new Runnable() {
@Override
public void run() {
if (!CameraDeviceImpl.this.isClosed()) {
- mDeviceCallback.onError(CameraDeviceImpl.this, errorCode);
+ mDeviceCallback.onError(CameraDeviceImpl.this, publicErrorCode);
}
}
};
@@ -2050,7 +2018,7 @@ public class CameraDeviceImpl extends CameraDevice
public void run() {
if (!isClosed()) {
mDeviceCallback.onError(CameraDeviceImpl.this,
- CameraDeviceCallbacks.ERROR_CAMERA_SERVICE);
+ StateCallback.ERROR_CAMERA_SERVICE);
}
}
};
diff --git a/core/java/android/hardware/camera2/marshal/MarshalRegistry.java b/core/java/android/hardware/camera2/marshal/MarshalRegistry.java
index ba821e4770a4..15650879942a 100644
--- a/core/java/android/hardware/camera2/marshal/MarshalRegistry.java
+++ b/core/java/android/hardware/camera2/marshal/MarshalRegistry.java
@@ -37,7 +37,9 @@ public class MarshalRegistry {
* @param queryable a non-{@code null} marshal queryable that supports marshaling {@code T}
*/
public static <T> void registerMarshalQueryable(MarshalQueryable<T> queryable) {
- sRegisteredMarshalQueryables.add(queryable);
+ synchronized(sMarshalLock) {
+ sRegisteredMarshalQueryables.add(queryable);
+ }
}
/**
@@ -54,47 +56,50 @@ public class MarshalRegistry {
*/
@SuppressWarnings("unchecked")
public static <T> Marshaler<T> getMarshaler(TypeReference<T> typeToken, int nativeType) {
- // TODO: can avoid making a new token each time by code-genning
- // the list of type tokens and native types from the keys (at the call sites)
- MarshalToken<T> marshalToken = new MarshalToken<T>(typeToken, nativeType);
-
- /*
- * Marshalers are instantiated lazily once they are looked up; successive lookups
- * will not instantiate new marshalers.
- */
- Marshaler<T> marshaler =
- (Marshaler<T>) sMarshalerMap.get(marshalToken);
-
- if (sRegisteredMarshalQueryables.size() == 0) {
- throw new AssertionError("No available query marshalers registered");
- }
+ synchronized(sMarshalLock) {
+ // TODO: can avoid making a new token each time by code-genning
+ // the list of type tokens and native types from the keys (at the call sites)
+ MarshalToken<T> marshalToken = new MarshalToken<T>(typeToken, nativeType);
+
+ /*
+ * Marshalers are instantiated lazily once they are looked up; successive lookups
+ * will not instantiate new marshalers.
+ */
+ Marshaler<T> marshaler =
+ (Marshaler<T>) sMarshalerMap.get(marshalToken);
+
+ if (marshaler == null) {
+
+ if (sRegisteredMarshalQueryables.size() == 0) {
+ throw new AssertionError("No available query marshalers registered");
+ }
- if (marshaler == null) {
- // Query each marshaler to see if they support the native/managed type combination
- for (MarshalQueryable<?> potentialMarshaler : sRegisteredMarshalQueryables) {
+ // Query each marshaler to see if they support the native/managed type combination
+ for (MarshalQueryable<?> potentialMarshaler : sRegisteredMarshalQueryables) {
- MarshalQueryable<T> castedPotential =
- (MarshalQueryable<T>)potentialMarshaler;
+ MarshalQueryable<T> castedPotential =
+ (MarshalQueryable<T>)potentialMarshaler;
- if (castedPotential.isTypeMappingSupported(typeToken, nativeType)) {
- marshaler = castedPotential.createMarshaler(typeToken, nativeType);
- break;
+ if (castedPotential.isTypeMappingSupported(typeToken, nativeType)) {
+ marshaler = castedPotential.createMarshaler(typeToken, nativeType);
+ break;
+ }
}
- }
- if (marshaler == null) {
- throw new UnsupportedOperationException(
+ if (marshaler == null) {
+ throw new UnsupportedOperationException(
"Could not find marshaler that matches the requested " +
- "combination of type reference " +
- typeToken + " and native type " +
- MarshalHelpers.toStringNativeType(nativeType));
+ "combination of type reference " +
+ typeToken + " and native type " +
+ MarshalHelpers.toStringNativeType(nativeType));
+ }
+
+ // Only put when no cached version exists to avoid +0.5ms lookup per call.
+ sMarshalerMap.put(marshalToken, marshaler);
}
- // Only put when no cached version exists to avoid +0.5ms lookup per call.
- sMarshalerMap.put(marshalToken, marshaler);
+ return marshaler;
}
-
- return marshaler;
}
private static class MarshalToken<T> {
@@ -125,9 +130,12 @@ public class MarshalRegistry {
}
}
- private static List<MarshalQueryable<?>> sRegisteredMarshalQueryables =
+ // Control access to the static data structures below
+ private static final Object sMarshalLock = new Object();
+
+ private static final List<MarshalQueryable<?>> sRegisteredMarshalQueryables =
new ArrayList<MarshalQueryable<?>>();
- private static HashMap<MarshalToken<?>, Marshaler<?>> sMarshalerMap =
+ private static final HashMap<MarshalToken<?>, Marshaler<?>> sMarshalerMap =
new HashMap<MarshalToken<?>, Marshaler<?>>();
private MarshalRegistry() {
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index ea5ae32e8244..f4bf3eab169e 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -176,7 +176,7 @@ public abstract class BatteryStats implements Parcelable {
/**
* Current version of checkin data format.
*/
- static final String CHECKIN_VERSION = "17";
+ static final String CHECKIN_VERSION = "18";
/**
* Old version, we hit 9 and ran out of room, need to remove.
@@ -2371,6 +2371,20 @@ public abstract class BatteryStats implements Parcelable {
};
/**
+ * Return the counter keeping track of the amount of battery discharge while the screen was off,
+ * measured in micro-Ampere-hours. This will be non-zero only if the device's battery has
+ * a coulomb counter.
+ */
+ public abstract LongCounter getDischargeScreenOffCoulombCounter();
+
+ /**
+ * Return the counter keeping track of the amount of battery discharge measured in
+ * micro-Ampere-hours. This will be non-zero only if the device's battery has
+ * a coulomb counter.
+ */
+ public abstract LongCounter getDischargeCoulombCounter();
+
+ /**
* Return the array of discharge step durations.
*/
public abstract LevelStepTracker getDischargeLevelStepTracker();
@@ -2805,6 +2819,9 @@ public abstract class BatteryStats implements Parcelable {
rawRealtime, which);
final int connChanges = getNumConnectivityChange(which);
final long phoneOnTime = getPhoneOnTime(rawRealtime, which);
+ final long dischargeCount = getDischargeCoulombCounter().getCountLocked(which);
+ final long dischargeScreenOffCount = getDischargeScreenOffCoulombCounter()
+ .getCountLocked(which);
final StringBuilder sb = new StringBuilder(128);
@@ -2820,6 +2837,7 @@ public abstract class BatteryStats implements Parcelable {
totalRealtime / 1000, totalUptime / 1000,
getStartClockTime(),
whichBatteryScreenOffRealtime / 1000, whichBatteryScreenOffUptime / 1000);
+
// Calculate wakelock times across all uids.
long fullWakeLockTimeTotal = 0;
@@ -2969,12 +2987,14 @@ public abstract class BatteryStats implements Parcelable {
dumpLine(pw, 0 /* uid */, category, BATTERY_DISCHARGE_DATA,
getDischargeStartLevel()-getDischargeCurrentLevel(),
getDischargeStartLevel()-getDischargeCurrentLevel(),
- getDischargeAmountScreenOn(), getDischargeAmountScreenOff());
+ getDischargeAmountScreenOn(), getDischargeAmountScreenOff(),
+ dischargeCount / 1000, dischargeScreenOffCount / 1000);
} else {
dumpLine(pw, 0 /* uid */, category, BATTERY_DISCHARGE_DATA,
getLowDischargeAmountSinceCharge(), getHighDischargeAmountSinceCharge(),
getDischargeAmountScreenOnSinceCharge(),
- getDischargeAmountScreenOffSinceCharge());
+ getDischargeAmountScreenOffSinceCharge(),
+ dischargeCount / 1000, dischargeScreenOffCount / 1000);
}
if (reqUid < 0) {
@@ -3371,6 +3391,39 @@ public abstract class BatteryStats implements Parcelable {
formatTimeMs(sb, chargeTimeRemaining / 1000);
pw.println(sb.toString());
}
+
+ final LongCounter dischargeCounter = getDischargeCoulombCounter();
+ final long dischargeCount = dischargeCounter.getCountLocked(which);
+ if (dischargeCount >= 0) {
+ sb.setLength(0);
+ sb.append(prefix);
+ sb.append(" Discharge: ");
+ sb.append(BatteryStatsHelper.makemAh(dischargeCount / 1000.0));
+ sb.append(" mAh");
+ pw.println(sb.toString());
+ }
+
+ final LongCounter dischargeScreenOffCounter = getDischargeScreenOffCoulombCounter();
+ final long dischargeScreenOffCount = dischargeScreenOffCounter.getCountLocked(which);
+ if (dischargeScreenOffCount >= 0) {
+ sb.setLength(0);
+ sb.append(prefix);
+ sb.append(" Screen off discharge: ");
+ sb.append(BatteryStatsHelper.makemAh(dischargeScreenOffCount / 1000.0));
+ sb.append(" mAh");
+ pw.println(sb.toString());
+ }
+
+ final long dischargeScreenOnCount = dischargeCount - dischargeScreenOffCount;
+ if (dischargeScreenOnCount >= 0) {
+ sb.setLength(0);
+ sb.append(prefix);
+ sb.append(" Screen on discharge: ");
+ sb.append(BatteryStatsHelper.makemAh(dischargeScreenOnCount / 1000.0));
+ sb.append(" mAh");
+ pw.println(sb.toString());
+ }
+
pw.print(" Start clock time: ");
pw.println(DateFormat.format("yyyy-MM-dd-HH-mm-ss", getStartClockTime()).toString());
diff --git a/core/java/android/os/ParcelFileDescriptor.java b/core/java/android/os/ParcelFileDescriptor.java
index d5491d3a808a..7702c174ba2f 100644
--- a/core/java/android/os/ParcelFileDescriptor.java
+++ b/core/java/android/os/ParcelFileDescriptor.java
@@ -864,6 +864,34 @@ public class ParcelFileDescriptor implements Parcelable, Closeable {
super.close();
}
}
+
+ @Override
+ public int read() throws IOException {
+ final int result = super.read();
+ if (result == -1 && mPfd.canDetectErrors()) {
+ // Check for errors only on EOF, to minimize overhead.
+ mPfd.checkError();
+ }
+ return result;
+ }
+
+ @Override
+ public int read(byte[] b) throws IOException {
+ final int result = super.read(b);
+ if (result == -1 && mPfd.canDetectErrors()) {
+ mPfd.checkError();
+ }
+ return result;
+ }
+
+ @Override
+ public int read(byte[] b, int off, int len) throws IOException {
+ final int result = super.read(b, off, len);
+ if (result == -1 && mPfd.canDetectErrors()) {
+ mPfd.checkError();
+ }
+ return result;
+ }
}
/**
diff --git a/core/java/android/os/RecoverySystem.java b/core/java/android/os/RecoverySystem.java
index 6c21398e280b..7ff01daa6892 100644
--- a/core/java/android/os/RecoverySystem.java
+++ b/core/java/android/os/RecoverySystem.java
@@ -695,6 +695,7 @@ public class RecoverySystem {
String line = null;
int bytesWrittenInMiB = -1, bytesStashedInMiB = -1;
int timeTotal = -1;
+ int sourceVersion = -1;
while ((line = in.readLine()) != null) {
// Here is an example of lines in last_install:
// ...
@@ -729,6 +730,8 @@ public class RecoverySystem {
if (line.startsWith("time")) {
timeTotal = scaled;
+ } else if (line.startsWith("source_version")) {
+ sourceVersion = scaled;
} else if (line.startsWith("bytes_written")) {
bytesWrittenInMiB = (bytesWrittenInMiB == -1) ? scaled :
bytesWrittenInMiB + scaled;
@@ -742,6 +745,9 @@ public class RecoverySystem {
if (timeTotal != -1) {
MetricsLogger.histogram(context, "ota_time_total", timeTotal);
}
+ if (sourceVersion != -1) {
+ MetricsLogger.histogram(context, "ota_source_version", sourceVersion);
+ }
if (bytesWrittenInMiB != -1) {
MetricsLogger.histogram(context, "ota_written_in_MiBs", bytesWrittenInMiB);
}
diff --git a/core/java/android/security/net/config/SystemCertificateSource.java b/core/java/android/security/net/config/SystemCertificateSource.java
index abef7b453c79..cfb195b9509c 100644
--- a/core/java/android/security/net/config/SystemCertificateSource.java
+++ b/core/java/android/security/net/config/SystemCertificateSource.java
@@ -25,7 +25,10 @@ import java.io.File;
* @hide
*/
public final class SystemCertificateSource extends DirectoryCertificateSource {
- private static final SystemCertificateSource INSTANCE = new SystemCertificateSource();
+ private static class NoPreloadHolder {
+ private static final SystemCertificateSource INSTANCE = new SystemCertificateSource();
+ }
+
private final File mUserRemovedCaDir;
private SystemCertificateSource() {
@@ -35,7 +38,7 @@ public final class SystemCertificateSource extends DirectoryCertificateSource {
}
public static SystemCertificateSource getInstance() {
- return INSTANCE;
+ return NoPreloadHolder.INSTANCE;
}
@Override
diff --git a/core/java/android/security/net/config/UserCertificateSource.java b/core/java/android/security/net/config/UserCertificateSource.java
index 1a7d92456a3d..d6e2b3a8ca1f 100644
--- a/core/java/android/security/net/config/UserCertificateSource.java
+++ b/core/java/android/security/net/config/UserCertificateSource.java
@@ -25,7 +25,9 @@ import java.io.File;
* @hide
*/
public final class UserCertificateSource extends DirectoryCertificateSource {
- private static final UserCertificateSource INSTANCE = new UserCertificateSource();
+ private static class NoPreloadHolder {
+ private static final UserCertificateSource INSTANCE = new UserCertificateSource();
+ }
private UserCertificateSource() {
super(new File(
@@ -33,7 +35,7 @@ public final class UserCertificateSource extends DirectoryCertificateSource {
}
public static UserCertificateSource getInstance() {
- return INSTANCE;
+ return NoPreloadHolder.INSTANCE;
}
@Override
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index b4131b44263a..415e70ca03fd 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -51,6 +51,7 @@ public class SurfaceControl {
private static native void nativeSetLayer(long nativeObject, int zorder);
private static native void nativeSetPosition(long nativeObject, float x, float y);
+ private static native void nativeSetPositionAppliesWithResize(long nativeObject);
private static native void nativeSetSize(long nativeObject, int w, int h);
private static native void nativeSetTransparentRegionHint(long nativeObject, Region region);
private static native void nativeSetAlpha(long nativeObject, float alpha);
@@ -407,6 +408,16 @@ public class SurfaceControl {
nativeSetPosition(mNativeObject, x, y);
}
+ /**
+ * If the size changes in this transaction, position updates specified
+ * in this transaction will not complete until a buffer of the new size
+ * arrives.
+ */
+ public void setPositionAppliesWithResize() {
+ checkNotReleased();
+ nativeSetPositionAppliesWithResize(mNativeObject);
+ }
+
public void setSize(int w, int h) {
checkNotReleased();
nativeSetSize(mNativeObject, w, h);
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 88605db0408a..5f6ee09bf2ac 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -20538,6 +20538,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
if (ViewDebug.DEBUG_DRAG) {
Log.d(VIEW_LOG_TAG, "startDragAndDrop: data=" + data + " flags=" + flags);
}
+ if (mAttachInfo == null) {
+ Log.w(VIEW_LOG_TAG, "startDragAndDrop called on a detached view.");
+ return false;
+ }
boolean okay = false;
Point shadowSize = new Point();
@@ -20614,6 +20618,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
if (ViewDebug.DEBUG_DRAG) {
Log.d(VIEW_LOG_TAG, "cancelDragAndDrop");
}
+ if (mAttachInfo == null) {
+ Log.w(VIEW_LOG_TAG, "cancelDragAndDrop called on a detached view.");
+ return;
+ }
if (mAttachInfo.mDragToken != null) {
try {
mAttachInfo.mSession.cancelDragAndDrop(mAttachInfo.mDragToken);
@@ -20636,6 +20644,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
if (ViewDebug.DEBUG_DRAG) {
Log.d(VIEW_LOG_TAG, "updateDragShadow");
}
+ if (mAttachInfo == null) {
+ Log.w(VIEW_LOG_TAG, "updateDragShadow called on a detached view.");
+ return;
+ }
if (mAttachInfo.mDragToken != null) {
try {
Canvas canvas = mAttachInfo.mDragSurface.lockCanvas(null);
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 4742818d4be0..19b1cf3c86ba 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -1938,7 +1938,7 @@ public final class ViewRootImpl implements ViewParent,
mSurfaceHolder.setSurfaceFrameSize(mWidth, mHeight);
mSurfaceHolder.mSurfaceLock.unlock();
if (mSurface.isValid()) {
- if (!hadSurface || surfaceGenerationId != mSurface.getGenerationId()) {
+ if (!hadSurface) {
mSurfaceHolder.ungetCallbacks();
mIsCreating = true;
@@ -1951,7 +1951,7 @@ public final class ViewRootImpl implements ViewParent,
}
surfaceChanged = true;
}
- if (surfaceChanged) {
+ if (surfaceChanged || surfaceGenerationId != mSurface.getGenerationId()) {
mSurfaceHolderCallback.surfaceChanged(mSurfaceHolder,
lp.format, mWidth, mHeight);
SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
diff --git a/core/java/android/view/accessibility/AccessibilityWindowInfo.java b/core/java/android/view/accessibility/AccessibilityWindowInfo.java
index d0d4507e7b62..52f35de7e189 100644
--- a/core/java/android/view/accessibility/AccessibilityWindowInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityWindowInfo.java
@@ -16,6 +16,7 @@
package android.view.accessibility;
+import android.annotation.Nullable;
import android.graphics.Rect;
import android.os.Parcel;
import android.os.Parcelable;
@@ -101,8 +102,9 @@ public final class AccessibilityWindowInfo implements Parcelable {
/**
* Gets the title of the window.
*
- * @return The title.
+ * @return The title of the window, or {@code null} if none is available.
*/
+ @Nullable
public CharSequence getTitle() {
return mTitle;
}
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 8b0235249436..07d38d71b347 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 = 144 + (USE_OLD_HISTORY ? 1000 : 0);
+ private static final int VERSION = 146 + (USE_OLD_HISTORY ? 1000 : 0);
// Maximum number of items we will record in the history.
private static final int MAX_HISTORY_ITEMS = 2000;
@@ -509,6 +509,9 @@ public class BatteryStatsImpl extends BatteryStats {
int mDischargeAmountScreenOff;
int mDischargeAmountScreenOffSinceCharge;
+ private LongSamplingCounter mDischargeScreenOffCounter;
+ private LongSamplingCounter mDischargeCounter;
+
static final int MAX_LEVEL_STEPS = 200;
int mInitStepMode = 0;
@@ -565,6 +568,16 @@ public class BatteryStatsImpl extends BatteryStats {
return mWakeupReasonStats;
}
+ @Override
+ public LongCounter getDischargeScreenOffCoulombCounter() {
+ return mDischargeScreenOffCounter;
+ }
+
+ @Override
+ public LongCounter getDischargeCoulombCounter() {
+ return mDischargeCounter;
+ }
+
public BatteryStatsImpl() {
this(new SystemClocks());
}
@@ -912,7 +925,6 @@ public class BatteryStatsImpl extends BatteryStats {
final TimeBase mTimeBase;
long mCount;
long mLoadedCount;
- long mLastCount;
long mUnpluggedCount;
long mPluggedCount;
@@ -921,7 +933,6 @@ public class BatteryStatsImpl extends BatteryStats {
mPluggedCount = in.readLong();
mCount = mPluggedCount;
mLoadedCount = in.readLong();
- mLastCount = 0;
mUnpluggedCount = in.readLong();
timeBase.add(this);
}
@@ -949,20 +960,19 @@ public class BatteryStatsImpl extends BatteryStats {
}
public long getCountLocked(int which) {
- long val = mCount;
+ long val = mTimeBase.isRunning() ? mCount : mPluggedCount;
if (which == STATS_SINCE_UNPLUGGED) {
val -= mUnpluggedCount;
} else if (which != STATS_SINCE_CHARGED) {
val -= mLoadedCount;
}
-
return val;
}
@Override
public void logState(Printer pw, String prefix) {
pw.println(prefix + "mCount=" + mCount
- + " mLoadedCount=" + mLoadedCount + " mLastCount=" + mLastCount
+ + " mLoadedCount=" + mLoadedCount
+ " mUnpluggedCount=" + mUnpluggedCount
+ " mPluggedCount=" + mPluggedCount);
}
@@ -976,7 +986,7 @@ public class BatteryStatsImpl extends BatteryStats {
*/
void reset(boolean detachIfReset) {
mCount = 0;
- mLoadedCount = mLastCount = mPluggedCount = mUnpluggedCount = 0;
+ mLoadedCount = mPluggedCount = mUnpluggedCount = 0;
if (detachIfReset) {
detach();
}
@@ -993,7 +1003,6 @@ public class BatteryStatsImpl extends BatteryStats {
void readSummaryFromParcelLocked(Parcel in) {
mLoadedCount = in.readLong();
mCount = mLoadedCount;
- mLastCount = 0;
mUnpluggedCount = mPluggedCount = mLoadedCount;
}
}
@@ -7566,6 +7575,8 @@ public class BatteryStatsImpl extends BatteryStats {
mFlashlightOnTimer = new StopwatchTimer(mClocks, null, -9, null, mOnBatteryTimeBase);
mCameraOnTimer = new StopwatchTimer(mClocks, null, -13, null, mOnBatteryTimeBase);
mBluetoothScanTimer = new StopwatchTimer(mClocks, null, -14, null, mOnBatteryTimeBase);
+ mDischargeScreenOffCounter = new LongSamplingCounter(mOnBatteryScreenOffTimeBase);
+ mDischargeCounter = new LongSamplingCounter(mOnBatteryTimeBase);
mOnBattery = mOnBatteryInternal = false;
long uptime = mClocks.uptimeMillis() * 1000;
long realtime = mClocks.elapsedRealtime() * 1000;
@@ -8123,6 +8134,8 @@ public class BatteryStatsImpl extends BatteryStats {
mDischargeAmountScreenOffSinceCharge = 0;
mDischargeStepTracker.init();
mChargeStepTracker.init();
+ mDischargeScreenOffCounter.reset(false);
+ mDischargeCounter.reset(false);
}
public void resetAllStatsCmdLocked() {
@@ -9327,6 +9340,7 @@ public class BatteryStatsImpl extends BatteryStats {
mHistoryCur.states2 |= HistoryItem.STATE2_CHARGING_FLAG;
mHistoryCur.batteryStatus = (byte)status;
mHistoryCur.batteryLevel = (byte)level;
+ mHistoryCur.batteryChargeUAh = chargeUAh;
mMaxChargeStepLevel = mMinDischargeStepLevel =
mLastChargeStepLevel = mLastDischargeStepLevel = level;
mLastChargingStateLevel = level;
@@ -9358,6 +9372,12 @@ public class BatteryStatsImpl extends BatteryStats {
mHistoryCur.batteryPlugType = (byte)plugType;
mHistoryCur.batteryTemperature = (short)temp;
mHistoryCur.batteryVoltage = (char)volt;
+ if (chargeUAh < mHistoryCur.batteryChargeUAh) {
+ // Only record discharges
+ final long chargeDiff = mHistoryCur.batteryChargeUAh - chargeUAh;
+ mDischargeCounter.addCountLocked(chargeDiff);
+ mDischargeScreenOffCounter.addCountLocked(chargeDiff);
+ }
mHistoryCur.batteryChargeUAh = chargeUAh;
setOnBatteryLocked(elapsedRealtime, uptime, onBattery, oldStatus, level);
} else {
@@ -9394,6 +9414,12 @@ public class BatteryStatsImpl extends BatteryStats {
}
if (chargeUAh >= (mHistoryCur.batteryChargeUAh+10)
|| chargeUAh <= (mHistoryCur.batteryChargeUAh-10)) {
+ if (chargeUAh < mHistoryCur.batteryChargeUAh) {
+ // Only record discharges
+ final long chargeDiff = mHistoryCur.batteryChargeUAh - chargeUAh;
+ mDischargeCounter.addCountLocked(chargeDiff);
+ mDischargeScreenOffCounter.addCountLocked(chargeDiff);
+ }
mHistoryCur.batteryChargeUAh = chargeUAh;
changed = true;
}
@@ -10075,6 +10101,8 @@ public class BatteryStatsImpl extends BatteryStats {
mChargeStepTracker.readFromParcel(in);
mDailyDischargeStepTracker.readFromParcel(in);
mDailyChargeStepTracker.readFromParcel(in);
+ mDischargeCounter.readSummaryFromParcelLocked(in);
+ mDischargeScreenOffCounter.readSummaryFromParcelLocked(in);
int NPKG = in.readInt();
if (NPKG > 0) {
mDailyPackageChanges = new ArrayList<>(NPKG);
@@ -10425,6 +10453,8 @@ public class BatteryStatsImpl extends BatteryStats {
mChargeStepTracker.writeToParcel(out);
mDailyDischargeStepTracker.writeToParcel(out);
mDailyChargeStepTracker.writeToParcel(out);
+ mDischargeCounter.writeSummaryFromParcelLocked(out);
+ mDischargeScreenOffCounter.writeSummaryFromParcelLocked(out);
if (mDailyPackageChanges != null) {
final int NPKG = mDailyPackageChanges.size();
out.writeInt(NPKG);
@@ -10880,6 +10910,8 @@ public class BatteryStatsImpl extends BatteryStats {
mDischargeAmountScreenOffSinceCharge = in.readInt();
mDischargeStepTracker.readFromParcel(in);
mChargeStepTracker.readFromParcel(in);
+ mDischargeCounter = new LongSamplingCounter(mOnBatteryTimeBase, in);
+ mDischargeScreenOffCounter = new LongSamplingCounter(mOnBatteryTimeBase, in);
mLastWriteTime = in.readLong();
mKernelWakelockStats.clear();
@@ -11028,6 +11060,8 @@ public class BatteryStatsImpl extends BatteryStats {
out.writeInt(mDischargeAmountScreenOffSinceCharge);
mDischargeStepTracker.writeToParcel(out);
mChargeStepTracker.writeToParcel(out);
+ mDischargeCounter.writeToParcel(out);
+ mDischargeScreenOffCounter.writeToParcel(out);
out.writeLong(mLastWriteTime);
if (inclUids) {
diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java
index 7e38d9bc742d..3cf7a4e6b9ec 100644
--- a/core/java/com/android/internal/policy/DecorView.java
+++ b/core/java/com/android/internal/policy/DecorView.java
@@ -1550,7 +1550,13 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
private ActionMode createStandaloneActionMode(ActionMode.Callback callback) {
endOnGoingFadeAnimation();
cleanupPrimaryActionMode();
- if (mPrimaryActionModeView == null) {
+ // We want to create new mPrimaryActionModeView in two cases: if there is no existing
+ // instance at all, or if there is one, but it is detached from window. The latter case
+ // might happen when app is resized in multi-window mode and decor view is preserved
+ // along with the main app window. Keeping mPrimaryActionModeView reference doesn't cause
+ // app memory leaks because killMode() is called when the dismiss animation ends and from
+ // cleanupPrimaryActionMode() invocation above.
+ if (mPrimaryActionModeView == null || !mPrimaryActionModeView.isAttachedToWindow()) {
if (mWindow.isFloating()) {
// Use the action bar theme.
final TypedValue outValue = new TypedValue();
@@ -1616,6 +1622,7 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
ViewStub stub = (ViewStub) findViewById(R.id.action_mode_bar_stub);
if (stub != null) {
mPrimaryActionModeView = (ActionBarContextView) stub.inflate();
+ mPrimaryActionModePopup = null;
}
}
}
@@ -2278,9 +2285,14 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
}
if (mPrimaryActionModeView != null) {
endOnGoingFadeAnimation();
+ // Store action mode view reference, so we can access it safely when animation
+ // ends. mPrimaryActionModePopup is set together with mPrimaryActionModeView,
+ // so no need to store reference to it in separate variable.
+ final ActionBarContextView lastActionModeView = mPrimaryActionModeView;
mFadeAnim = ObjectAnimator.ofFloat(mPrimaryActionModeView, View.ALPHA,
1f, 0f);
mFadeAnim.addListener(new Animator.AnimatorListener() {
+
@Override
public void onAnimationStart(Animator animation) {
@@ -2288,12 +2300,17 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
@Override
public void onAnimationEnd(Animator animation) {
- mPrimaryActionModeView.setVisibility(GONE);
- if (mPrimaryActionModePopup != null) {
- mPrimaryActionModePopup.dismiss();
+ // If mPrimaryActionModeView has changed - it means that we've
+ // cleared the content while preserving decor view. We don't
+ // want to change the state of new instances accidentally here.
+ if (lastActionModeView == mPrimaryActionModeView) {
+ lastActionModeView.setVisibility(GONE);
+ if (mPrimaryActionModePopup != null) {
+ mPrimaryActionModePopup.dismiss();
+ }
+ lastActionModeView.killMode();
+ mFadeAnim = null;
}
- mPrimaryActionModeView.removeAllViews();
- mFadeAnim = null;
}
@Override
diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java
index 18408aa72f5f..9ad750d3a599 100644
--- a/core/java/com/android/internal/policy/PhoneWindow.java
+++ b/core/java/com/android/internal/policy/PhoneWindow.java
@@ -528,16 +528,22 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
@Override
public void setTitle(CharSequence title) {
+ setTitle(title, true);
+ }
+
+ public void setTitle(CharSequence title, boolean updateAccessibilityTitle) {
if (mTitleView != null) {
mTitleView.setText(title);
} else if (mDecorContentParent != null) {
mDecorContentParent.setWindowTitle(title);
}
mTitle = title;
- WindowManager.LayoutParams params = getAttributes();
- if (!TextUtils.equals(title, params.accessibilityTitle)) {
- params.accessibilityTitle = TextUtils.stringOrSpannedString(title);
- dispatchWindowAttributesChanged(getAttributes());
+ if (updateAccessibilityTitle) {
+ WindowManager.LayoutParams params = getAttributes();
+ if (!TextUtils.equals(title, params.accessibilityTitle)) {
+ params.accessibilityTitle = TextUtils.stringOrSpannedString(title);
+ dispatchWindowAttributesChanged(getAttributes());
+ }
}
}
diff --git a/core/java/com/android/internal/widget/MessagingLinearLayout.java b/core/java/com/android/internal/widget/MessagingLinearLayout.java
index dc7b7f5b9646..d2a43b755f18 100644
--- a/core/java/com/android/internal/widget/MessagingLinearLayout.java
+++ b/core/java/com/android/internal/widget/MessagingLinearLayout.java
@@ -48,6 +48,11 @@ public class MessagingLinearLayout extends ViewGroup {
private int mIndentLines;
+ /**
+ * Id of the child that's also visible in the contracted layout.
+ */
+ private int mContractedChildId;
+
public MessagingLinearLayout(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
@@ -255,14 +260,29 @@ public class MessagingLinearLayout extends ViewGroup {
return copy;
}
- @RemotableViewMethod
/**
* Sets how many lines should be indented to avoid a floating image.
*/
+ @RemotableViewMethod
public void setNumIndentLines(int numberLines) {
mIndentLines = numberLines;
}
+ /**
+ * Set id of the child that's also visible in the contracted layout.
+ */
+ @RemotableViewMethod
+ public void setContractedChildId(int contractedChildId) {
+ mContractedChildId = contractedChildId;
+ }
+
+ /**
+ * Get id of the child that's also visible in the contracted layout.
+ */
+ public int getContractedChildId() {
+ return mContractedChildId;
+ }
+
public static class LayoutParams extends MarginLayoutParams {
boolean hide = false;
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index a9ed9dce590e..ff75677536c4 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -248,6 +248,15 @@ static void nativeSetPosition(JNIEnv* env, jclass clazz, jlong nativeObject, jfl
}
}
+static void nativeSetPositionAppliesWithResize(JNIEnv* env, jclass clazz,
+ jlong nativeObject) {
+ SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
+ status_t err = ctrl->setPositionAppliesWithResize();
+ if (err < 0 && err != NO_INIT) {
+ doThrowIAE(env);
+ }
+}
+
static void nativeSetSize(JNIEnv* env, jclass clazz, jlong nativeObject, jint w, jint h) {
SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
status_t err = ctrl->setSize(w, h);
@@ -658,6 +667,8 @@ static const JNINativeMethod sSurfaceControlMethods[] = {
(void*)nativeSetLayer },
{"nativeSetPosition", "(JFF)V",
(void*)nativeSetPosition },
+ {"nativeSetPositionAppliesWithResize", "(J)V",
+ (void*)nativeSetPositionAppliesWithResize },
{"nativeSetSize", "(JII)V",
(void*)nativeSetSize },
{"nativeSetTransparentRegionHint", "(JLandroid/graphics/Region;)V",
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index b03ba20709a4..e9a3409be6ab 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -360,6 +360,7 @@
<!-- Added in N -->
<protected-broadcast android:name="android.intent.action.ANR" />
<protected-broadcast android:name="android.intent.action.CALL" />
+ <protected-broadcast android:name="android.intent.action.CALL_PRIVILEGED" />
<protected-broadcast android:name="android.intent.action.DROPBOX_ENTRY_ADDED" />
<protected-broadcast android:name="android.intent.action.INPUT_METHOD_CHANGED" />
<protected-broadcast android:name="android.intent.action.internal_sim_state_changed" />
@@ -480,6 +481,7 @@
<protected-broadcast android:name="android.intent.action.MANAGED_PROFILE_AVAILABLE" />
<protected-broadcast android:name="android.intent.action.MANAGED_PROFILE_UNAVAILABLE" />
+ <protected-broadcast android:name="com.android.server.pm.DISABLE_QUIET_MODE_AFTER_UNLOCK" />
<!-- ====================================================================== -->
<!-- RUNTIME PERMISSIONS -->
@@ -1621,6 +1623,14 @@
<permission android:name="android.permission.MANAGE_USERS"
android:protectionLevel="signature|privileged" />
+ <!-- @hide Allows an application to create, remove users and get the list of
+ users on the device. Applications holding this permission can only create restricted,
+ guest, managed, and ephemeral users. For creating other kind of users,
+ {@link android.Manifest.permission#MANAGE_USERS} is needed.
+ This permission is not available to third party applications. -->
+ <permission android:name="android.permission.CREATE_USERS"
+ android:protectionLevel="signature" />
+
<!-- @hide Allows an application to set the profile owners and the device owner.
This permission is not available to third party applications.-->
<permission android:name="android.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS"
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 6cd8d9f25252..e737f557ffb5 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -800,8 +800,8 @@
<string name="permdesc_setAlarm" msgid="316392039157473848">"Tillader, at appen kan indstille en alarm i en installeret alarmapp. Nogle alarmapps har muligvis ikke denne funktion."</string>
<string name="permlab_addVoicemail" msgid="5525660026090959044">"tilføje telefonsvarer"</string>
<string name="permdesc_addVoicemail" msgid="6604508651428252437">"Tillader, at appen kan tilføje beskeder på din telefonsvarer."</string>
- <string name="permlab_writeGeolocationPermissions" msgid="5962224158955273932">"skifte tilladelser til geografisk placering i Browser"</string>
- <string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"Tillader, at appen kan ændre browserens tilladelser angående geografisk placering. Ondsindede apps kan benytte dette til at sende oplysninger om placering til vilkårlige websites."</string>
+ <string name="permlab_writeGeolocationPermissions" msgid="5962224158955273932">"skifte tilladelser til geoplacering i Browser"</string>
+ <string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"Tillader, at appen kan ændre browserens tilladelser angående geoplacering. Ondsindede apps kan benytte dette til at sende oplysninger om sted til vilkårlige websites."</string>
<string name="save_password_message" msgid="767344687139195790">"Ønsker du, at browseren skal huske denne adgangskode?"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"Ikke nu"</string>
<string name="save_password_remember" msgid="6491879678996749466">"Husk"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 616d2b8dd13a..9245749e1fc0 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -525,11 +525,11 @@
<string name="policylab_resetPassword" msgid="4934707632423915395">"Displaysperre ändern"</string>
<string name="policydesc_resetPassword" msgid="1278323891710619128">"Displaysperre ändern"</string>
<string name="policylab_forceLock" msgid="2274085384704248431">"Bildschirm sperren"</string>
- <string name="policydesc_forceLock" msgid="1141797588403827138">"Lege fest, wie und wann der Bildschirm gesperrt wird."</string>
+ <string name="policydesc_forceLock" msgid="1141797588403827138">"Festlegen, wie und wann der Bildschirm gesperrt wird"</string>
<string name="policylab_wipeData" msgid="3910545446758639713">"Alle Daten löschen"</string>
<string name="policydesc_wipeData" product="tablet" msgid="4306184096067756876">"Auf Werkseinstellungen zurücksetzen und Daten auf dem Tablet ohne Warnung löschen"</string>
<string name="policydesc_wipeData" product="tv" msgid="5816221315214527028">"Auf Werkseinstellungen zurücksetzen und Daten auf dem Fernseher ohne Warnung löschen"</string>
- <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"Setze das Telefon auf die Werkseinstellungen zurück. Dabei werden alle Daten ohne Warnung gelöscht."</string>
+ <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"Auf Werkseinstellungen zurücksetzen und damit Daten auf dem Telefon ohne Warnung löschen"</string>
<string name="policylab_wipeData_secondaryUser" msgid="8362863289455531813">"Nutzerdaten löschen"</string>
<string name="policydesc_wipeData_secondaryUser" product="tablet" msgid="6336255514635308054">"Daten dieses Nutzers auf diesem Tablet ohne vorherige Warnung löschen"</string>
<string name="policydesc_wipeData_secondaryUser" product="tv" msgid="2086473496848351810">"Daten dieses Nutzers auf diesem Fernseher ohne vorherige Warnung löschen"</string>
@@ -543,7 +543,7 @@
<string name="policylab_disableCamera" msgid="6395301023152297826">"Kameras deaktivieren"</string>
<string name="policydesc_disableCamera" msgid="2306349042834754597">"Nutzung sämtlicher Gerätekameras unterbinden"</string>
<string name="policylab_disableKeyguardFeatures" msgid="8552277871075367771">"Einige Funktionen der Displaysperre deaktivieren"</string>
- <string name="policydesc_disableKeyguardFeatures" msgid="2044755691354158439">"Verhindert die Verwendung einiger Funktionen der Displaysperre"</string>
+ <string name="policydesc_disableKeyguardFeatures" msgid="2044755691354158439">"Verwendung einiger Funktionen der Displaysperre verhindern"</string>
<string-array name="phoneTypes">
<item msgid="8901098336658710359">"Privat"</item>
<item msgid="869923650527136615">"Mobil"</item>
diff --git a/core/res/res/values-hy-rAM/strings.xml b/core/res/res/values-hy-rAM/strings.xml
index ee89493de25a..d2ff2831faa6 100644
--- a/core/res/res/values-hy-rAM/strings.xml
+++ b/core/res/res/values-hy-rAM/strings.xml
@@ -228,9 +228,9 @@
<string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Անձայն ռեժիմ"</string>
<string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"Ձայնը անջատված է"</string>
<string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"Ձայնը միացված է"</string>
- <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Ինքնաթիռային ռեժիմ"</string>
- <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Ինքնաթիռային ռեժիմը միացված է"</string>
- <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Ինքնաթիռային ռեժիմը անջատված է"</string>
+ <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Ինքնաթիռի ռեժիմ"</string>
+ <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Ինքնաթիռի ռեժիմը միացված է"</string>
+ <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Ինքնաթիռի ռեժիմը անջատված է"</string>
<string name="global_action_settings" msgid="1756531602592545966">"Կարգավորումներ"</string>
<string name="global_action_assist" msgid="3892832961594295030">"Օգնական"</string>
<string name="global_action_voice_assist" msgid="7751191495200504480">"Ձայնային օգնութ"</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 0b062d1a8e6d..adc071d428df 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -344,11 +344,11 @@
<string name="permdesc_writeContacts" product="default" msgid="589869224625163558">"Leidžiama programai keisti duomenis apie telefone saugomus kontaktus, įskaitant dažnį, kuriuo konkretiems asmenims skambinote, siuntėte el. laiškus ar bendravote kitais būdais. Šis leidimas suteikia teisę programoms ištrinti kontaktinius duomenis."</string>
<string name="permlab_readCallLog" msgid="3478133184624102739">"skaityti skambučių žurnalą"</string>
<string name="permdesc_readCallLog" product="tablet" msgid="3700645184870760285">"Leidžiama programai skaityti planšetinio kompiuterio skambučių žurnalą, įskaitant duomenis apie gaunamuosius ir siunčiamuosius skambučius. Šis leidimas suteikia teisę programai išsaugoti skambučių žurnalo duomenis, o kenkėjiškos programos gali bendrinti skambučių žurnalą be jūsų žinios."</string>
- <string name="permdesc_readCallLog" product="tv" msgid="5611770887047387926">"Programai leidžiama nuskaityti TV skambučių žurnalą, įskaitant duomenis apie gaunamus arba siunčiamus skambučius. Dėl šio leidimo programoms leidžiama išsaugoti skambučių žurnalo duomenis, o kenkėjiškos programos gali bendrinti šiuos duomenis be jūsų žinios."</string>
+ <string name="permdesc_readCallLog" product="tv" msgid="5611770887047387926">"Programai leidžiama nuskaityti TV skambučių žurnalą, įskaitant duomenis apie gaunamuosius arba siunčiamuosius skambučius. Dėl šio leidimo programoms leidžiama išsaugoti skambučių žurnalo duomenis, o kenkėjiškos programos gali bendrinti šiuos duomenis be jūsų žinios."</string>
<string name="permdesc_readCallLog" product="default" msgid="5777725796813217244">"Leidžiama programai skaityti telefono skambučių žurnalą, įskaitant duomenis apie gaunamuosius ir siunčiamuosius skambučius. Šis leidimas suteikia teisę programai išsaugoti skambučių žurnalo duomenis, o kenkėjiškos programos gali bendrinti skambučių žurnalą be jūsų žinios."</string>
<string name="permlab_writeCallLog" msgid="8552045664743499354">"rašyti skambučių žurnalą"</string>
<string name="permdesc_writeCallLog" product="tablet" msgid="6661806062274119245">"Programai leidžiama skaityti planšetinio kompiuterio skambučių žurnalą, įskaitant duomenis apie gaunamuosius ir siunčiamuosius skambučius. Kenkėjiškos programos tai gali naudoti, kad ištrintų ar keistų jūsų skambučių žurnalą."</string>
- <string name="permdesc_writeCallLog" product="tv" msgid="4225034892248398019">"Programai leidžiama keisti TV skambučių žurnalą, įskaitant duomenis apie gaunamus ir siunčiamus skambučius. Taip kenkėjiškos programos gali ištrinti arba pakeisti skambučių žurnalą."</string>
+ <string name="permdesc_writeCallLog" product="tv" msgid="4225034892248398019">"Programai leidžiama keisti TV skambučių žurnalą, įskaitant duomenis apie gaunamuosius ir siunčiamuosius skambučius. Taip kenkėjiškos programos gali ištrinti arba pakeisti skambučių žurnalą."</string>
<string name="permdesc_writeCallLog" product="default" msgid="683941736352787842">"Programai leidžiama skaityti telefono skambučių žurnalą, įskaitant duomenis apie gaunamuosius ir siunčiamuosius skambučius. Kenkėjiškos programos tai gali naudoti, kad ištrintų ar keistų jūsų skambučių žurnalą."</string>
<string name="permlab_bodySensors" msgid="4683341291818520277">"pas. k. jut. (pvz., pul. dažn. st. įr.)"</string>
<string name="permdesc_bodySensors" product="default" msgid="4380015021754180431">"Programai leidžiama pasiekti duomenis, gautus iš jutiklių, stebinčių fizinę būseną, pvz., širdies ritmą."</string>
diff --git a/core/res/res/values-mn-rMN/strings.xml b/core/res/res/values-mn-rMN/strings.xml
index baf95b1d4c33..4f10c45d2986 100644
--- a/core/res/res/values-mn-rMN/strings.xml
+++ b/core/res/res/values-mn-rMN/strings.xml
@@ -395,9 +395,9 @@
<string name="permdesc_setTimeZone" product="tv" msgid="888864653946175955">"Апп-д телевизийн цагийн бүсийг өөрчлөхийг зөвшөөрдөг."</string>
<string name="permdesc_setTimeZone" product="default" msgid="4499943488436633398">"Апп нь утасны цагийн бүсийг өөрчлөх боломжтой."</string>
<string name="permlab_getAccounts" msgid="1086795467760122114">"төхөөрөмж дээрх акаунтыг олох"</string>
- <string name="permdesc_getAccounts" product="tablet" msgid="2741496534769660027">"Апп нь таблетэд мэдэгдэж байгаа акаунтын жагсаалтыг авах боломжтой. Энд таны суулгасан аппликешнүүдийн үүсгэсэн бүх акаунтууд хамрагдана."</string>
+ <string name="permdesc_getAccounts" product="tablet" msgid="2741496534769660027">"Апп нь таблетэд мэдэгдэж байгаа бүртгэлийн жагсаалтыг авах боломжтой. Энд таны суулгасан аппликешнүүдийн үүсгэсэн бүх акаунтууд хамрагдана."</string>
<string name="permdesc_getAccounts" product="tv" msgid="4190633395633907543">"Телевизийн жагсаалтад байгаа акаунтуудын хаягийг апп-д авахыг зөвшөөрдөг. Энэ нь таны суулгасан бусад аппликэйшнүүдийн бий болгосон акаунтуудыг оруулж болно."</string>
- <string name="permdesc_getAccounts" product="default" msgid="3448316822451807382">"Апп нь утсанд мэдэгдэж байгаа акаунтын жагсаалтыг авах боломжтой. Энд таны суулгасан аппликешнүүдийн үүсгэсэн бүх акаунтууд хамрагдана."</string>
+ <string name="permdesc_getAccounts" product="default" msgid="3448316822451807382">"Апп нь утсанд мэдэгдэж байгаа бүртгэлийн жагсаалтыг авах боломжтой. Энд таны суулгасан аппликешнүүдийн үүсгэсэн бүх акаунтууд хамрагдана."</string>
<string name="permlab_accessNetworkState" msgid="4951027964348974773">"сүлжээний холболтыг үзэх"</string>
<string name="permdesc_accessNetworkState" msgid="8318964424675960975">"Апп нь сүлжээ байгаа болон холбогдсон эсэх зэрэг сүлжээний холболтын талаарх мэдээллийг харах боломжтой."</string>
<string name="permlab_createNetworkSockets" msgid="7934516631384168107">"сүлжээнд бүрэн нэвтрэх"</string>
@@ -454,11 +454,11 @@
</string-array>
<string name="fingerprint_icon_content_description" msgid="2340202869968465936">"Хурууны хээний дүрс"</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"синк тохиргоог унших"</string>
- <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Апп нь акаунтын синк тохиргоог унших боломжтой. Жишээ нь энэ нь Хүмүүс апп акаунттай синк хийгдсэн эсэхийг тодорхойлох боломжтой."</string>
+ <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Апп нь бүртгэлийн синк тохиргоог унших боломжтой. Жишээ нь энэ нь Хүмүүс апп бүртгэлтэй синк хийгдсэн эсэхийг тодорхойлох боломжтой."</string>
<string name="permlab_writeSyncSettings" msgid="5408694875793945314">"синкийг унтрааж асаах тохиргоо"</string>
- <string name="permdesc_writeSyncSettings" msgid="8956262591306369868">"Апп нь акаунтын синк тохиргоог өөрчлөх боломжтой. Жишээ нь энэ нь Хүмүүс апп акаунттай синк хийхийг идэвхжүүлэх боломжтой."</string>
+ <string name="permdesc_writeSyncSettings" msgid="8956262591306369868">"Апп нь бүртгэлийн синк тохиргоог өөрчлөх боломжтой. Жишээ нь энэ нь Хүмүүс апп бүртгэлтэй синк хийхийг идэвхжүүлэх боломжтой."</string>
<string name="permlab_readSyncStats" msgid="7396577451360202448">"синк статистикийг унших"</string>
- <string name="permdesc_readSyncStats" msgid="1510143761757606156">"Апп нь синк үйлдэлийн түүх болон хэр их дата синк хийгдсэн зэрэг акаунтын синк статусыг унших боломжтой."</string>
+ <string name="permdesc_readSyncStats" msgid="1510143761757606156">"Апп нь синк үйлдэлийн түүх болон хэр их дата синк хийгдсэн зэрэг бүртгэлийн синк статусыг унших боломжтой."</string>
<string name="permlab_sdcardRead" product="nosdcard" msgid="367275095159405468">"таны USB сангийн агуулгыг унших боломжтой"</string>
<string name="permlab_sdcardRead" product="default" msgid="2188156462934977940">"таны SD картны агуулгыг унших боломжтой"</string>
<string name="permdesc_sdcardRead" product="nosdcard" msgid="3446988712598386079">"Апп нь таны USB сангийн агуулгыг унших боломжтой."</string>
@@ -1261,7 +1261,7 @@
<string name="gpsVerifYes" msgid="2346566072867213563">"Тийм"</string>
<string name="gpsVerifNo" msgid="1146564937346454865">"Үгүй"</string>
<string name="sync_too_many_deletes" msgid="5296321850662746890">"Устгах хязгаар хэтрэв"</string>
- <string name="sync_too_many_deletes_desc" msgid="496551671008694245">"<xliff:g id="TYPE_OF_SYNC">%2$s</xliff:g>-р <xliff:g id="ACCOUNT_NAME">%3$s</xliff:g> акаунтын <xliff:g id="NUMBER_OF_DELETED_ITEMS">%1$d</xliff:g> зүйл устсан . Та юу хиймээр байна?"</string>
+ <string name="sync_too_many_deletes_desc" msgid="496551671008694245">"<xliff:g id="TYPE_OF_SYNC">%2$s</xliff:g>-р <xliff:g id="ACCOUNT_NAME">%3$s</xliff:g> бүртгэлийн <xliff:g id="NUMBER_OF_DELETED_ITEMS">%1$d</xliff:g> зүйл устсан . Та юу хиймээр байна?"</string>
<string name="sync_really_delete" msgid="2572600103122596243">"Устгах"</string>
<string name="sync_undo_deletes" msgid="2941317360600338602">"Устгасныг буцаах"</string>
<string name="sync_do_nothing" msgid="3743764740430821845">"Одоо юу ч хийхгүй"</string>
@@ -1412,7 +1412,7 @@
<string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Та утсыг тайлах гэж <xliff:g id="NUMBER">%d</xliff:g> удаа буруу оролдлоо. Утас одоо үйлдвэрийн үндсэн утгаараа тохируулагдах болно."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Та тайлах хээг <xliff:g id="NUMBER_0">%1$d</xliff:g> удаа буруу зурлаа. <xliff:g id="NUMBER_1">%2$d</xliff:g> удаа дахин буруу оруулбал, та таблетаа тайлахын тулд имэйл бүртгэл шаардлагатай болно.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> секундын дараа дахин оролдоно уу."</string>
<string name="kg_failed_attempts_almost_at_login" product="tv" msgid="4224651132862313471">"Та зурган түгжээг <xliff:g id="NUMBER_0">%1$d</xliff:g> удаа буруу оруулсан байна. <xliff:g id="NUMBER_1">%2$d</xliff:g> удаа буруу оруулсны дараагаар та телевизийнхээ түгжээг и-мэйл дансаа ашиглан тайлах хэрэгтэй болно.\n\n Та <xliff:g id="NUMBER_2">%3$d</xliff:g> секундийн дараа дахин оролдоно уу."</string>
- <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Та тайлах хээг <xliff:g id="NUMBER_0">%1$d</xliff:g> удаа буруу зурлаа. <xliff:g id="NUMBER_1">%2$d</xliff:g> удаа дахин буруу оруулбал, та утсаа тайлахын тулд имэйл акаунтаа ашиглах шаардлагатай болно.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> секундын дараа дахин оролдоно уу."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Та тайлах хээг <xliff:g id="NUMBER_0">%1$d</xliff:g> удаа буруу зурлаа. <xliff:g id="NUMBER_1">%2$d</xliff:g> удаа дахин буруу оруулбал, та утсаа тайлахын тулд имэйл бүртгэлээ ашиглах шаардлагатай болно.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> секундын дараа дахин оролдоно уу."</string>
<string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Устгах"</string>
<string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"Дууг санал болгосноос чанга болгож өсгөх үү?\n\nУрт хугацаанд чанга хөгжим сонсох нь таны сонсголыг муутгаж болно."</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index fe136c3cecc2..221d0550a55e 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -245,19 +245,19 @@
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Contactos"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"aceder aos contactos"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Localização"</string>
- <string name="permgroupdesc_location" msgid="1346617465127855033">"aceda à localização do seu dispositivo"</string>
+ <string name="permgroupdesc_location" msgid="1346617465127855033">"aceder à localização do seu dispositivo"</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"Calendário"</string>
- <string name="permgroupdesc_calendar" msgid="3889615280211184106">"aceda ao calendário"</string>
+ <string name="permgroupdesc_calendar" msgid="3889615280211184106">"aceder ao calendário"</string>
<string name="permgrouplab_sms" msgid="228308803364967808">"SMS"</string>
- <string name="permgroupdesc_sms" msgid="4656988620100940350">"envie e veja mensagens SMS"</string>
+ <string name="permgroupdesc_sms" msgid="4656988620100940350">"enviar e ver mensagens SMS"</string>
<string name="permgrouplab_storage" msgid="1971118770546336966">"Armazenamento"</string>
- <string name="permgroupdesc_storage" msgid="637758554581589203">"aceda a fotos, multimédia e ficheiros no dispositivo"</string>
+ <string name="permgroupdesc_storage" msgid="637758554581589203">"aceder a fotos, multimédia e ficheiros no dispositivo"</string>
<string name="permgrouplab_microphone" msgid="171539900250043464">"Microfone"</string>
<string name="permgroupdesc_microphone" msgid="4988812113943554584">"gravar áudio"</string>
<string name="permgrouplab_camera" msgid="4820372495894586615">"Câmara"</string>
<string name="permgroupdesc_camera" msgid="3250611594678347720">"tirar fotografias e gravar vídeos"</string>
<string name="permgrouplab_phone" msgid="5229115638567440675">"Telemóvel"</string>
- <string name="permgroupdesc_phone" msgid="6234224354060641055">"faça e gira chamadas"</string>
+ <string name="permgroupdesc_phone" msgid="6234224354060641055">"fazer e gerir chamadas"</string>
<string name="permgrouplab_sensors" msgid="416037179223226722">"Sensores de corpo"</string>
<string name="permgroupdesc_sensors" msgid="7147968539346634043">"aceder a dados do sensor acerca dos seus sinais vitais"</string>
<string name="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"Obter conteúdo da janela"</string>
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index aecda44a6583..998eea5ac9ab 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -174,6 +174,7 @@ please see themes_device_defaults.xml.
<!-- Window attributes -->
<item name="windowBackground">@drawable/screen_background_selector_dark</item>
+ <item name="windowBackgroundFallback">?attr/colorBackground</item>
<item name="windowClipToOutline">false</item>
<item name="windowFrame">@null</item>
<item name="windowNoTitle">false</item>
diff --git a/docs/html/guide/practices/screens_support.jd b/docs/html/guide/practices/screens_support.jd
index 1335790cc9a7..2223dbf3096d 100644
--- a/docs/html/guide/practices/screens_support.jd
+++ b/docs/html/guide/practices/screens_support.jd
@@ -677,7 +677,7 @@ a bitmap drawable that's 48x48 pixels for medium-density screens, all the differ
<li>48x48 (1.0x baseline) for medium-density</li>
<li>72x72 (1.5x) for high-density</li>
<li>96x96 (2.0x) for extra-high-density</li>
- <li>180x180 (3.0x) for extra-extra-high-density</li>
+ <li>144x144 (3.0x) for extra-extra-high-density</li>
<li>192x192 (4.0x) for extra-extra-extra-high-density (launcher icon only; see
<a href="#xxxhdpi-note">note</a> above)</li>
</ul>
@@ -988,7 +988,7 @@ configurations.</p>
on different screens:</p>
<ol>
- <li>Use {@code wrap_content}, {@code fill_parent}, or {@code dp} units when specifying
+ <li>Use {@code wrap_content}, {@code match_parent}, or {@code dp} units when specifying
dimensions in an XML layout file</li>
<li>Do not use hard coded pixel values in your application code</li>
<li>Do not use {@code AbsoluteLayout} (it's deprecated)</li>
@@ -998,7 +998,7 @@ dimensions in an XML layout file</li>
<p>The following sections provide more details.</p>
-<h3 id="use-relative">1. Use wrap_content, fill_parent, or the dp unit for layout dimensions</h3>
+<h3 id="use-relative">1. Use wrap_content, match_parent, or the dp unit for layout dimensions</h3>
<p>When defining the <a
href="{@docRoot}reference/android/view/ViewGroup.LayoutParams.html#attr_android:layout_width"
@@ -1006,7 +1006,7 @@ href="{@docRoot}reference/android/view/ViewGroup.LayoutParams.html#attr_android:
href="{@docRoot}reference/android/view/ViewGroup.LayoutParams.html#attr_android:layout_height"
>{@code android:layout_height}</a> for
views in an XML layout file, using <code>"wrap_content"</code>,
-<code>"fill_parent"</code> or <code>dp</code> units guarantees that the view is
+<code>"match_parent"</code> or <code>dp</code> units guarantees that the view is
given an appropriate size on the current device screen.</p>
<p>For instance, a view with a <code>layout_width="100dp"</code> measures 100 pixels wide on
diff --git a/docs/html/guide/topics/manifest/activity-element.jd b/docs/html/guide/topics/manifest/activity-element.jd
index e0f5e3d2fc25..f30263e8983c 100644
--- a/docs/html/guide/topics/manifest/activity-element.jd
+++ b/docs/html/guide/topics/manifest/activity-element.jd
@@ -714,7 +714,7 @@ For example:</p>
&lt;activity
android:name="com.example.app.ChildActivity"
android:label="@string/title_child_activity"
- android:parentActivityName="com.example.myfirstapp.MainActivity" >
+ android:parentActivityName="com.example.app.MainActivity" >
&lt;!-- Parent activity meta-data to support API level 4+ -->
&lt;meta-data
android:name="android.support.PARENT_ACTIVITY"
diff --git a/docs/html/jd_extras_en.js b/docs/html/jd_extras_en.js
index 6295e0efd00c..21379292bf36 100644
--- a/docs/html/jd_extras_en.js
+++ b/docs/html/jd_extras_en.js
@@ -5379,10 +5379,15 @@ METADATA['en'].collections = {
"preview/support.html"
]
},
+ "preview/landing/videos/first": {
+ "title": "",
+ "resources": [
+ "https://www.youtube.com/watch?v=CsulIu3UaUM"
+ ]
+ },
"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",
diff --git a/docs/html/ndk/guides/graphics/getting-started.jd b/docs/html/ndk/guides/graphics/getting-started.jd
index 145e534783b1..0c2d939f1182 100644
--- a/docs/html/ndk/guides/graphics/getting-started.jd
+++ b/docs/html/ndk/guides/graphics/getting-started.jd
@@ -137,7 +137,7 @@ alt="Project pane after importing samples into Android Studio" id="figure1" />
<ol style="1">
<li>Select your project in the Android Studio <em>Project</em> panel.</li>
-<li>From the <strong>Build</strong> menu, choose <strong>Make Module &lt;module-name&gt; </strong>.</li>
+<li>From the <strong>Build</strong> menu, choose <strong>Make Module &lt;module-name&gt; </strong>; or select <strong> Build APK </strong> to generate APK.</li>
<li>Resolve any dependency issues, and then compile. As Figure 2 shows, you can select individual projects to compile by choosing them from the configuration pulldown.</li>
<img src="../images/config-pulldown.png"
diff --git a/docs/html/ndk/guides/graphics/validation-layer.jd b/docs/html/ndk/guides/graphics/validation-layer.jd
index beac1c09bbc8..1a7d83246d01 100644
--- a/docs/html/ndk/guides/graphics/validation-layer.jd
+++ b/docs/html/ndk/guides/graphics/validation-layer.jd
@@ -6,19 +6,8 @@ page.title=Vulkan Validation Layers on Android
<h2>On this page</h2>
<ol>
+ <li><a href="#ilp">Add Validation Layers to Project</a></li>
<li><a href="#gls">Getting Layer Source</a></li>
- <li><a href="#ias">Android Studio Integration</a>
- <ol>
- <li><a href="#asbl">Building Layers</a></li>
- <li><a href="#asil">Installing Layers</a></li>
- </ol>
- </li>
- <li><a href="#cli">Integrating on the Command Line</a>
- <ol>
- <li><a href="#clibl">Building Layers</a></li>
- <li><a href="#cliil">Installing Layers</a></li>
- </ol>
- </li>
<li><a href="#verifying">Verifying Layer Build</a></li>
<li><a href="#enabling">Enabling Layers</a></li>
<li><a href="#debug">Enabling the Debug Callback</a></li>
@@ -52,272 +41,94 @@ during development.
<p>
This page explains how to:
<ul>
+ <li>Integrate NDK's Layer Binaries.</li>
<li>Get source code for validation layers.</li>
- <li>Build the layers.</li>
- <li>Incorporate the layers into your app.</li>
+ <li>Verifying Layer Build.</li>
+ <li>Enabling Layers in Vulkan Application.</li>
+
</ul>
</p>
-<h2 id="gls">Getting Layer Source</h2>
-<p>
-This section explains how to build layers from source.
-If you have precompiled layers, you can skip this section, and instead read about how to
-install your layers using <a href="#asil">Android Studio</a> or from the <a href="cliil">
-command line</a>.
-</p>
-<h3 id="ftn">From the NDK (Recommended)</h3>
+<h2 id="ilp">Add Validation Layers to Project</h2>
<p>
-<a href="{@docRoot}ndk/downloads/index.html">NDK Revision 12</a> and later contains source
-code for Android validation layers that is known-good, and ready to build. This code resides under
-the {@code &lt;ndk-root&gt;/sources/third_party/vulkan/src/build-android/generated/gradle-build}
-directory. This version of the layers should be sufficient for most needs. If so, your next task is
-to <a href="#building">build them</a>. Alternatively, you can pull source code from the
-Khronos Group repository.
-</pre>
+ NDK release 12 and higher includes pre-built validation layer binaries. At
+ instance and device creation time, when requested by your application, the
+ Vulkan loader finds them in the APK installed location and loads them.
</p>
-<h3 id="ftr">From the repository</h3>
-
<p>
-Although we recommend that you use the source code provided with the NDK, you can also pull more
-recent versions of the source code directly from the
-<a class="external-link" href="https://github.com/KhronosGroup/Vulkan-LoaderAndValidationLayers">
-GitHub repository</a> belonging to the Khronos Group. To do so, perform the following steps.
+ To use the pre-built validation layer binaries, either modify the gradle build
+ configuration of your project or manually add the binaries into the JNI
+ libraries directory of your project.
</p>
-<ol style="1">
-<li>
-Clone the Vulkan directory by entering the following command in your terminal window:
-
-<pre class="no-pretty-print">
-$ git clone git@github.com:KhronosGroup/Vulkan-LoaderAndValidationLayers.git
-</pre>
-
-<p class="note"><strong>Note: </strong>You must have a private SSH key associated with
-GitHub, or this command fails with a {@code Permission denied (publickey)} message.</p>
-</li>
-
-<li>
-Navigate to the directory containing the layer source code, and
-check out the repo's stable Android branch, called {@code android_layers}:
-
-<pre class="no-pretty-print">
-$ cd Vulkan-LoaderAndValidationLayers
-$ git checkout android_layers
-</pre>
-</li>
-
-<li>
-Begin preparation for building by entering the following commands on the command line:
-<ul>
- <li>For Linux or OS X:
- <ul>
- <li>
- <pre class="no-pretty-print">
-$ cd build-android
-$ ./android-generate</pre>
- </li>
- </ul>
- </li>
-
- <li>For Windows:
- <ul>
- <li>
-<pre class="no-pretty-print">
-&gt; cd build-android
-&gt; android-generate.bat</pre>
- </li>
- </ul>
- </li>
-</ul>
-</li>
-
-<li>
-Continue by following the build instructions for your platform.
-These instructions are in the {@code BUILD.md} file contained in the local instance of the
-repository you cloned.
-</li>
-</ul>
-</ol>
+<h3 id="vl-gradle">Adding validation layers with Gradle</h3>
-<h3 id="ias">Android Studio Integration</h3>
<p>
-Android Studio builds the validation layers when it builds the rest of the app.
-This flow makes it easier for you to trace through the layers at runtime. Each layer's
-source code corresponds to a single Gradle project, which you can specify directly in your Android
-Studio app. For example, there is a {@code build.gradle} project for threading, and another
-one for parameter validation.
+ You can add the validation layer your project using either Andorid Studio's
+ support for CMake and Ndk-build, or using Studio's experimental plugin for
+ Gradle. In general, you should use the CMake and Ndk-build configuration.
</p>
-<h4 id="asbl">Building layers</h4>
<p>
-To integrate layers directory into Android Studio application, perform these steps:
+ To add the libraries using Android Studio's support for CMake/Ndk-build,
+ add the following to your project's gradle configuration:
</p>
-<li>
-Add layers to your Android Studio application's project by specifying their corresponding
-Gradle projects in {@code settings.gradle}, which is normally a peer to app directory.
-The following example shows how to do this, based on the assumption that you're
-<a href="#ftn">using the {@code build.gradle} files from the NDK</a>.
-
-<pre>
-// configure your path to the source code generated on your machine
-def layerProjRoot = file('/path/to/ndk-root/.../build-android/generated/gradle-build')
-String[] layers = ['threading',
- 'parameter_validation',
- 'object_tracker',
- 'core_validation',
- 'device_limits',
- 'image',
- 'swapchain',
- 'unique_objects']
-for (layer in layers) {
- include ":"+ layer
- project(":" + layer.toString()).projectDir = new File("${layerProjRoot}/${layer}")
-}
-</pre>
-</li>
-
-Your next step is to provide the built layers to the app by installing them.
-
-<h4 id="asil">Installing layers</h4>
-
-<li>
-To install your layers, add the layer Gradle projects to your application's jniLibs dependencies
-in your {@code build.gradle} module. This module normally resides under the {@code app/} directory.
-The following example shows how to do this:
-<pre>
-android.sources {
- main {
- jni { ... }
- jniLibs {
- dependencies {
- project ":threading"
- project ":parameter_validation"
- project ":object_tracker"
- project ":core_validation"
- project ":device_limits"
- project ":image"
- project ":swapchain"
- project ":unique_objects"
- }
- }
+<pre class="no-pretty-print">
+sourceSets {
+ main {
+ jniLibs {
+ srcDir "${your-ndk-dir}/sources/third_party/vulkan/src/build-android/jniLibs"
}
-} // android.sources
-</pre>
-</li>
-<li>
-Develop, build, and debug as you usually would. When you build, Android Studio automatically
-builds the layers and copies them into your APK.
-</li>
-<li>
-Debug your application. Android Studio allows you to trace through the layer source code.
-</li>
-<li>
-For best performance, remove the layers before you do your release build.
-</li>
-</ol>
-
-
-<h3 id="cli">From the Command Line</h3>
-
-This section explains how to build and install your layers if your project does not use
-Android Studio.
-
-<h4 id="clibl">Building layers</h4>
+ }
+}</pre>
<p>
-To build validation layers on Linux or OS X, enter these commands on the command line:
+ To add the libraries using Android Studio's experimental plugin for Gradle,
+ add the following to your project's gradle configuration:
</p>
-<ul>
-<li>
-Using Gradle:
-<pre class="no-pretty-print">
-$ cd generated/gradle-build
-$ # configure SDK and NDK path in local.properties
-$ gradlew assembleAllDebug
-</pre>
-</li>
-<li>
-Using Android makefiles:
-<pre class="no-pretty-print">
-$ ndk-build</pre>
-</li>
-</ul>
-<p>
-To build validation layers on Windows, enter these commands on the command line:
-</p>
-<ul>
-<li>
-Using Gradle:
<pre class="no-pretty-print">
-&gt; cd generated\gradle-build
-&gt; REM configure SDK and NDK path in local.properties
-&gt; gradlew.bat assembleAllDebug
-</pre>
-</li>
-<li>
-Using Android makefiles:
-<pre class="no-pretty-print">
-&gt; ndk-build.cmd
-</pre>
-</li>
-</ul>
-
-
+sources {
+ main {
+ jniLibs {
+ source.srcDir "${your-ndk-dir}/sources/third_party/vulkan/src/build-android/jniLibs"
+ }
+ }
+}</pre>
-</p>
-</li>
-</ol>
-<h4 id="cliil">Installing layers</h4>
+<h3 id="vl-jni-lib">Adding validation layers to JNI libraries</h3>
<p>
-After building the layers, you must provide them to your app. To do so, you must first
-create a {@code jniLibs} folder in your app's project directory under
-{@code ./src/main/}, and copy the libs to it. The following example shows how to do this.
+ If configuring your project's gradle build file is not working, you can
+ manually add the validation layer binaries to your project's JNI libraries
+ directory by using the following command line options:
</p>
<pre class="no-pretty-print">
-$ mkdir ./src/main/jniLibs
+$ cd ${your-app-project-root}
+$ mkdir -p app/src/main
+$ cp -fr ${your-ndk-dir}/sources/third_party/vulkan/src/build-android/jniLibs app/src/main/
</pre>
-<p>
-The next step depends on whether you are using Gradle or Android makefiles. If you're using
-Gradle, each built layer resides in its own directory. Consolidate the layers into a single
-directory, as the following example shows:
-</p>
-<pre class="no-pretty-print">
-$ cp -r .../build-android/generated/gradle-build/threading/build/outputs/native/debug/all/lib/* ./src/main/jniLibs/
-$ cp -r .../build-android/generated/gradle-build/parameter_validation/build/outputs/native/debug/all/lib/* ./src/main/jniLibs/
-$ cp -r .../build-android/generated/gradle-build/object_tracker/build/outputs/native/debug/all/lib/* ./src/main/jniLibs/
-$ cp -r .../build-android/generated/gradle-build/core_validation/build/outputs/native/debug/all/lib/* ./src/main/jniLibs/
-$ cp -r .../build-android/generated/gradle-build/device_limits/build/outputs/native/debug/all/lib/* ./src/main/jniLibs/
-$ cp -r .../build-android/generated/gradle-build/image/build/outputs/native/debug/all/lib/* ./src/main/jniLibs/
-$ cp -r .../build-android/generated/gradle-build/swapchain/build/outputs/native/debug/all/lib/* ./src/main/jniLibs/
-$ cp -r .../build-android/generated/gradle-build/unique_objects/build/outputs/native/debug/all/lib/* ./src/main/jniLibs/
-</pre>
-
-If you're using Android makefiles, the built layers reside in {@code lib} folders,
-with one {@code lib} folder under each architecture’s root directory. Consolidate the
-makefiles under the {@code jniLibs} directory as this example shows:
+<h2 id="gls">Getting Layer Source</h2>
+<p>
+If your app needs the latest validation layer, you can pull the latest source from the Khronos Group
+<a class="external-link" href="https://github.com/KhronosGroup/Vulkan-LoaderAndValidationLayers">
+GitHub repository</a> and follow the build instructions there.
</p>
-<pre class="no-pretty-print">
-$ cp -r .../build-android/libs/* ./src/main/jniLibs/
-</pre>
-</li>
-</ol>
<h2 id="verifying">Verifying Layer Build</h2>
<p>
-Regardless of whether you build using Gradle or Android makefiles, the build process produces
-a file structure like the following:
+Regardless of whether you build with NDK's prebuilt layers or you build from the latest source code,
+the build process produces final file structure like the following:
</p>
<pre class="no-pretty-print">
@@ -571,6 +382,7 @@ if (vkDestroyDebugReportCallbackEXT) {
</pre>
+<p>
Once your app has registered and enabled the debug callback, the system routes debugging
messages to a callback that you register. An example of such a callback appears below:
</p>
diff --git a/docs/html/preview/_book.yaml b/docs/html/preview/_book.yaml
index 0d4b81b61cfb..ad6724968554 100644
--- a/docs/html/preview/_book.yaml
+++ b/docs/html/preview/_book.yaml
@@ -220,6 +220,8 @@ toc:
value: TV 录制
- name: zh-tw-lang
value: 電視錄製
+ - title: Key Attestation
+ path: /preview/features/key-attestation.html
- title: Network Security Configuration
path: /preview/features/security-config.html
path_attributes:
diff --git a/docs/html/preview/api-overview.jd b/docs/html/preview/api-overview.jd
index d457d5cb4877..606b38fdd691 100644
--- a/docs/html/preview/api-overview.jd
+++ b/docs/html/preview/api-overview.jd
@@ -701,48 +701,37 @@ before unlock. All other data is unavailable until the User confirms their lock
For more information, see <a href="{@docRoot}preview/features/direct-boot.html">Direct Boot</a>.</p>
</p>
-
<h2 id="key_attestation">Key Attestation</h2>
-<p>Hardware-backed keystores provide a much safer method to create, store,
-and use cryptographic keys on Android devices. They protect keys from the
-Linux kernel, potential Android vulnerabilities, and extraction
-from rooted devices.</p>
-
-<p>To make it easier and more secure to use hardware-backed keystores,
-Android N introduces Key Attestation. Apps and off-devices can use Key
-Attestation to strongly determine whether an RSA or EC key pair is
-hardware-backed, what the properties of the key pair are, and what
- constraints are applied to its usage and validity. </p>
-
-<p>Apps and off-device services can request information about a key pair
-through an X.509 attestation certificate which must be signed by a valid
-attestation key. The attestation key is an ECDSA signing key which is
-injected into the device’s hardware-backed keystore at the factory.
-Therefore, an attestation certificate signed by a valid attestation
-key confirms the existence of a hardware-backed keystore, along with
- details of key pairs in that keystore.</p>
-
-<p>To ensure that the device is using a secure, official Android factory
-image, Key Attestation requires that the device <a
-class="external-link"
-href="https://source.android.com/security/verifiedboot/verified-boot.html#bootloader_requirements">bootloader</a>
-provide the following information to the <a class="external-link"
-href="https://source.android.com/security/trusty/index.html">Trusted
-Execution Environment (TEE)</a>:</p>
-
-<ul>
-<li>The OS version and patch level installed on the device</li>
-<li>The <a href="https://source.android.com/security/verifiedboot/index.html"
-class="external-link" >Verified Boot</a> public key and lock status</li>
- </ul>
+<p>
+ Android N introduces <em>key attestation</em>, a new security tool that helps
+ you make sure that the key pairs stored within a device's <a class=
+ "external-link" href=
+ "https://source.android.com/security/keystore/"><em>hardware-backed
+ keystore</em></a> properly protect the sensitive information that your app
+ uses. By using this tool, you gain additional confidence that your app
+ interacts with keys that reside in secure hardware, even if the device
+ running your app is rooted. If you use keys from the hardware-backed keystore
+ in your apps, you should use this tool, particularly if you use the keys to
+ verify sensitive information within your app.
+</p>
-<p>For more information about the hardware-backed keystore feature,
-see the guide for <a href="https://source.android.com/security/keystore/"
-class="external-link">Hardware-backed Keystore</a>.</p>
+<p>
+ Key attestation allows you to verify that an RSA or EC key pair has been
+ created and stored in a device’s hardware-backed keystore within the device’s
+ trusted execution environment (TEE). The tool also allows you to use an
+ off-device service, such as your app's back-end server, to determine and
+ strongly verify the uses and validity of the key pair. These features provide
+ an additional level of security that protects the key pair, even if someone
+ roots the device or compromises the security of the Android platform running
+ on the device.
+</p>
-<p>In addition to Key Attestation, Android N also introduces
- fingerprint-bound keys that are not revoked on fingerprint enrollment.</p>
+<p>
+ For more information, see the
+ <a href="{@docRoot}preview/features/key-attestation.html">Key Attestation</a>
+ developer documentation.
+</p>
<h2 id="network_security_config">Network Security Config</h2>
diff --git a/docs/html/preview/features/key-attestation.jd b/docs/html/preview/features/key-attestation.jd
new file mode 100644
index 000000000000..98b8340496d2
--- /dev/null
+++ b/docs/html/preview/features/key-attestation.jd
@@ -0,0 +1,845 @@
+page.title=Key Attestation
+page.metaDescription=New support in Android N for verifying security properties of hardware-backed keys.
+page.keywords="android N", "security", "TEE", "hardware-backed", "keystore", "certificate", "key attestation"
+
+@jd:body
+
+<div id="qv-wrapper">
+ <div id="qv">
+ <h2>In this document</h2>
+ <ol>
+ <li><a href="#verifying">Retrieving and Verifying a Hardware-backed Key Pair</a></li>
+ <li><a href="#certificate_schema">Certificate Extension Data Schema</a></li>
+ </ol>
+ </div>
+</div>
+
+<p>
+ Key Attestation gives you more confidence that the keys you use in your app
+ are stored in a device's hardware-backed keystore. The following sections
+ describe how to verify the properties of hardware-backed keys and how to
+ interpret the schema of the attestation certificate's extension data.
+</p>
+
+<h2 id="verifying">
+ Retrieving and Verifying a Hardware-backed Key Pair
+</h2>
+
+<p>
+ During key attestation, you specify the alias of a key pair. The attestation
+ tool, in return, provides a certificate chain, which you can use to verify
+ the properties of that key pair.
+</p>
+
+<p>
+ The root certificate within this chain is signed using an attestation key,
+ which the device manufacturer injects into the device’s hardware-backed
+ keystore at the factory.
+</p>
+
+<p class="note">
+ <strong>Note:</strong> On devices that ship with Android N and Google Play
+ services, the root certificate is issued by Google. You should verify that
+ this root certificate appears within Google’s list of root certificates.
+</p>
+
+<p>
+ To implement key attestation, complete the following steps:
+</p>
+
+<ol>
+ <li>
+ Use a {@link java.security.KeyStore KeyStore} object's
+ {@link java.security.KeyStore#getCertificateChain getCertificateChain()}
+ method to get a reference to the chain of X.509 certificates associated with
+ the hardware-backed keystore.
+ </li>
+
+ <li>
+ <p>
+ Check each certificate’s validity using a
+ {@link java.security.cert.CRL CRL} object's
+ {@link java.security.cert.CRL#isRevoked isRevoked()} method.
+ </p>
+
+ <p class="caution">
+ <strong>Caution:</strong> Although you can complete this process within
+ your app directly, it’s safer to check the certificates’ revocation lists
+ on a separate server that you trust.
+ </p>
+ </li>
+
+ <li>
+ <p>
+ Create an <code>Attestation</code> object, passing in the first element of
+ the certificate chain as an argument:</p>
+
+<pre>
+// "certificates" contains the certificate chain associated with a specific key
+// pair in the device's hardware-backed keystore.
+X509Certificate attestationCert = (X509Certificate) certificates[0];
+Attestation hardwareKeyAttestation = new Attestation(attestationCert);
+</pre>
+
+ <p>
+ An attestation object extracts the extension data within this certificate
+ and stores this information in a more accessible format. For more details
+ about the schema of the extension data, see <a href=
+ "#certificate_schema">Certificate Extension Data Schema</a>.
+ </p>
+ </li>
+
+ <li>
+ <p>
+ Use the accessor methods within the <code>Attestation</code> class to
+ retrieve the extension data from the certificate. These methods use the
+ same names and structure hierarchy as in the certificate extension data
+ schema.
+ </p>
+
+ <p>
+ For example, to view the verified boot key for the device’s TEE, use the
+ following method sequence:
+ </p>
+
+<pre>
+// "hardwareKeyAttestation" contains the first element of the attestation
+// certificate chain.
+AuthorizationList teeAuthList = hardwareKeyAttestation.getTeeEnforced();
+RootOfTrust teeRootOfTrust = teeAuthList.getRootOfTrust();
+byte[] teeVerifiedBootKey = teeRootOfTrust.getVerifiedBootKey();
+</pre>
+
+ </li>
+
+ <li>
+ <p>
+ Compare the extension data from the <code>Attestation</code> object with
+ the set of values that you expect the hardware-backed key to contain.
+ </p>
+
+ <p class="caution">
+ <strong>Caution:</strong> Although you can complete this process within
+ your app directly, it’s safer to check the certificate’s extension data
+ on a separate server that you trust.
+ </p>
+ </li>
+</ol>
+
+<h2 id="certificate_schema">
+ Certificate Extension Data Schema
+</h2>
+
+<p>
+ Key attestation verifies the extension data that appears in the first
+ certificate within the chain in a device’s hardware-backed keystore. The
+ certificate stores the information according to the following ASN.1 schema:
+</p>
+
+<pre class="no-pretty-print">
+KeyDescription ::= SEQUENCE {
+ attestationVersion INTEGER,
+ attestationSecurityLevel SecurityLevel,
+ keymasterVersion INTEGER,
+ keymasterSecurityLevel SecurityLevel,
+ attestationChallenge OCTET_STRING,
+ <var>reserved OCTET_STRING</var>,
+ softwareEnforced AuthorizationList,
+ teeEnforced AuthorizationList,
+}
+
+SecurityLevel ::= ENUMERATED {
+ Software (0),
+ TrustedEnvironment (1),
+}
+
+AuthorizationList ::= SEQUENCE {
+ purpose [1] EXPLICIT SET OF INTEGER OPTIONAL,
+ algorithm [2] EXPLICIT INTEGER OPTIONAL,
+ keySize [3] EXPLICIT INTEGER OPTIONAL,
+ digest [5] EXPLICIT SET OF INTEGER OPTIONAL,
+ padding [6] EXPLICIT SET OF INTEGER OPTIONAL,
+ ecCurve [10] EXPLICIT INTEGER OPTIONAL,
+ rsaPublicExponent [200] EXPLICIT INTEGER OPTIONAL,
+ activeDateTime [400] EXPLICIT INTEGER OPTIONAL,
+ originationExpireDateTime [401] EXPLICIT INTEGER OPTIONAL,
+ usageExpireDateTime [402] EXPLICIT INTEGER OPTIONAL,
+ noAuthRequired [503] EXPLICIT NULL OPTIONAL,
+ userAuthType [504] EXPLICIT INTEGER OPTIONAL,
+ authTimeout [505] EXPLICIT INTEGER OPTIONAL,
+ allowWhileOnBody [506] EXPLICIT NULL OPTIONAL,
+ allApplications [600] EXPLICIT NULL OPTIONAL,
+ applicationId [601] EXPLICIT OCTET_STRING OPTIONAL,
+ creationDateTime [701] EXPLICIT INTEGER OPTIONAL,
+ origin [702] EXPLICIT INTEGER OPTIONAL,
+ rollbackResistant [703] EXPLICIT NULL OPTIONAL,
+ rootOfTrust [704] EXPLICIT RootOfTrust OPTIONAL,
+ osVersion [705] EXPLICIT INTEGER OPTIONAL,
+ osPatchLevel [706] EXPLICIT INTEGER OPTIONAL,
+ attestationChallenge [708] EXPLICIT INTEGER OPTIONAL,
+ attestationApplicationId [709] EXPLICIT OCTET_STRING OPTIONAL,
+}
+
+RootOfTrust ::= SEQUENCE {
+ verifiedBootKey OCTET_STRING,
+ deviceLocked BOOLEAN,
+ verifiedBootState VerifiedBootState,
+}
+
+VerifiedBootState ::= ENUMERATED {
+ Verified (0),
+ SelfSigned (1),
+ Unverified (2),
+ Failed (3),
+}
+</pre>
+
+<p>
+ The following list presents a description of each element within the schema:
+</p>
+
+<h3 id="certificate_schema_keydescription">
+ KeyDescription
+</h3>
+
+<p>
+ This sequence of values presents general information about the key pair being
+ verified through key attestation and provides easy access to additional
+ details.
+</p>
+
+<dl>
+ <dt>
+ <code>attestationVersion</code>
+ </dt>
+
+ <dd>
+ The version of the key attestation feature. Should be set to 1.
+ </dd>
+
+ <dt>
+ <code>attestationSecurity</code>
+ </dt>
+
+ <dd>
+ <p>
+ The <a href="#certificate_schema_securitylevel">security
+ level</a> of the attestation.
+ </p>
+
+ <p class="note">
+ <strong>Note:</strong> Although it is possible to attest keys that are
+ stored in the Android system&mdash;that is, if the
+ <code>attestationSecurity</code> value is set to Software&mdash;you
+ cannot trust these attestations if the Android system becomes compromised.
+ </p>
+ </dd>
+
+ <dt>
+ <code>keymasterVersion</code>
+ </dt>
+
+ <dd>
+ The version of the Keymaster hardware abstraction layer (HAL). Use 0 to
+ represent version 0.2 or 0.3, 1 to represent version 1.0, and 2 to represent
+ version 2.0.
+ </dd>
+
+ <dt>
+ <code>keymasterSecurity</code>
+ </dt>
+
+ <dd>
+ The <a href="#certificate_schema_securitylevel">security
+ level</a> of the Keymaster implementation.
+ </dd>
+
+ <dt>
+ <code>attestationChallenge</code>
+ </dt>
+
+ <dd>
+ The challenge string associated with a key pair that is verified using key
+ attestation.
+ </dd>
+
+ <dt>
+ <code><var>reserved</var></code>
+ </dt>
+
+ <dd>
+ Only system apps use this value. In all other apps, this value is empty.
+ </dd>
+
+ <dt>
+ <code>softwareEnforced</code>
+ </dt>
+
+ <dd>
+ Optional. The Keymaster <a href=
+ "#certificate_schema_authorizationlist">authorization
+ list</a> that is enforced by the Android system, not by the device’s TEE.
+ </dd>
+
+ <dt>
+ <code>teeEnforced</code>
+ </dt>
+
+ <dd>
+ Optional. The Keymaster <a href=
+ "#certificate_schema_authorizationlist">authorization
+ list</a> that is enforced by the device’s TEE.
+ </dd>
+</dl>
+
+<h3 id="certificate_schema_securitylevel">
+ SecurityLevel
+</h3>
+
+<p>
+ This data structure indicates the extent to which a software feature, such as
+ a key pair, is protected based on its location within the device.
+</p>
+
+<p>
+ Because the data structure is an enumeration, it takes on exactly one of the
+ following values:
+</p>
+
+<dl>
+ <dt>
+ Software
+ </dt>
+
+ <dd>
+ The logic for creating and managing the feature is implemented in the
+ Android system. For the purposes of creating and storing key pairs, this
+ location is less secure than the TEE but is more secure than your app's
+ process space.
+ </dd>
+
+ <dt>
+ TrustedEnvironment
+ </dt>
+
+ <dd>
+ The logic for creating and managing the feature is implemented in secure
+ hardware, such as a TEE. For the purposes of creating and storing key pairs,
+ this location is more secure because secure hardware is highly resistant to
+ remote compromise.
+ </dd>
+</dl>
+
+<h3 id="certificate_schema_authorizationlist">
+ AuthorizationList
+</h3>
+
+<p>
+ This data structure contains the key pair’s properties themselves, as defined
+ in the Keymaster hardware abstraction layer (HAL). You compare these values
+ to the device’s current state or to a set of expected values to verify that a
+ key pair is still valid for use in your app.
+</p>
+
+<p>
+ Each field name corresponds to a similarly-named Keymaster tag. For example,
+ the <code>keySize</code> field in an authorization list corresponds to the
+ <code>KM_TAG_KEY_SIZE</code> Keymaster tag.
+</p>
+
+<p>
+ Each field in the following list is optional:
+</p>
+
+<dl>
+ <dt>
+ <code>purpose</code>
+ </dt>
+
+ <dd>
+ Corresponds to the <code><a href=
+ "https://source.android.com/security/keystore/implementer-ref.html#km_tag_purpose">
+ KM_TAG_PURPOSE</a></code> Keymaster tag, which uses a tag ID value of 1.
+ </dd>
+
+ <dt>
+ <code>algorithm</code>
+ </dt>
+
+ <dd>
+ <p>
+ Corresponds to the <code><a href=
+ "https://source.android.com/security/keystore/implementer-ref.html#km_tag_algorithm">
+ KM_TAG_ALGORITHM</a></code> Keymaster tag, which uses a tag ID value of
+ 2.
+ </p>
+
+ <p>
+ When an <code>AuthorizationList</code> object is associated with key
+ attestation, this value is always <code>KM_ALGORITHM_RSA</code> or
+ <code>KM_ALGORITHM_EC</code>.
+ </p>
+ </dd>
+
+ <dt>
+ <code>keySize</code>
+ </dt>
+
+ <dd>
+ Corresponds to the <code><a href=
+ "https://source.android.com/security/keystore/implementer-ref.html#km_tag_key_size">
+ KM_TAG_KEY_SIZE</a></code> Keymaster tag, which uses a tag ID value of 3.
+ </dd>
+
+ <dt>
+ <code>digest</code>
+ </dt>
+
+ <dd>
+ Corresponds to the <code><a href=
+ "https://source.android.com/security/keystore/implementer-ref.html#km_tag_digest">
+ KM_TAG_DIGEST</a></code> Keymaster tag, which uses a tag ID value of 5.
+ </dd>
+
+ <dt>
+ <code>padding</code>
+ </dt>
+
+ <dd>
+ Corresponds to the <code><a href=
+ "https://source.android.com/security/keystore/implementer-ref.html#km_tag_padding">
+ KM_TAG_PADDING</a></code> Keymaster tag, which uses a tag ID value of 6.
+ </dd>
+
+ <dt>
+ <code>ecCurve</code>
+ </dt>
+
+ <dd>
+ <p>
+ Corresponds to the <code>KM_TAG_EC_CURVE</code> Keymaster tag, which uses
+ a tag ID value of 10.
+ </p>
+
+ <p>
+ The set of parameters used to generate an elliptic curve (EC) key pair,
+ which uses ECDSA for signing and verification, within the Android system
+ keystore.
+ </p>
+ </dd>
+
+ <dt>
+ <code>rsaPublicExponent</code>
+ </dt>
+
+ <dd>
+ Corresponds to the <code><a href=
+ "https://source.android.com/security/keystore/implementer-ref.html#km_tag_rsa_public_exponent">
+ KM_TAG_RSA_PUBLIC_EXPONENT</a></code> Keymaster tag, which uses a tag ID
+ value of 200.
+ </dd>
+
+ <dt>
+ <code>activeDateTime</code>
+ </dt>
+
+ <dd>
+ Corresponds to the <code><a href=
+ "https://source.android.com/security/keystore/implementer-ref.html#km_tag_active_datetime">
+ KM_TAG_ACTIVE_DATETIME</a></code> Keymaster tag, which uses a tag ID value
+ of 400.
+ </dd>
+
+ <dt>
+ <code>originationExpireDateTime</code>
+ </dt>
+
+ <dd>
+ Corresponds to the <code><a href=
+ "https://source.android.com/security/keystore/implementer-ref.html#km_tag_origination_expire_datetime">
+ KM_TAG_ORIGINATION_EXPIRE_DATETIME</a></code> Keymaster tag, which uses a
+ tag ID value of 401.
+ </dd>
+
+ <dt>
+ <code>usageExpireDateTime</code>
+ </dt>
+
+ <dd>
+ Corresponds to the <code><a href=
+ "https://source.android.com/security/keystore/implementer-ref.html#km_tag_usage_expire_datetime">
+ KM_TAG_USAGE_EXPIRE_DATETIME</a></code> Keymaster tag, which uses a tag ID
+ value of 402.
+ </dd>
+
+ <dt>
+ <code>noAuthRequired</code>
+ </dt>
+
+ <dd>
+ <p>
+ Corresponds to the <code><a href=
+ "https://source.android.com/security/keystore/implementer-ref.html#km_tag_no_auth_required">
+ KM_TAG_NO_AUTH_REQUIRED</a></code> Keymaster tag, which uses a tag ID
+ value of 503.
+ </p>
+
+ <p>
+ When an <code>AuthorizationList</code> object is associated with key
+ attestation, this value is always true.
+ </p>
+ </dd>
+
+ <dt>
+ <code>userAuthType</code>
+ </dt>
+
+ <dd>
+ Corresponds to the <code><a href=
+ "https://source.android.com/security/keystore/implementer-ref.html#km_tag_user_auth_type">
+ KM_TAG_USER_AUTH_TYPE</a></code> Keymaster tag, which uses a tag ID value
+ of 504.
+ </dd>
+
+ <dt>
+ <code>authTimeout</code>
+ </dt>
+
+ <dd>
+ Corresponds to the <code><a href=
+ "https://source.android.com/security/keystore/implementer-ref.html#km_tag_auth_timeout">
+ KM_TAG_AUTH_TIMEOUT</a></code> Keymaster tag, which uses a tag ID value of
+ 505.
+ </dd>
+
+ <dt>
+ <code>allowWhileOnBody</code>
+ </dt>
+
+ <dd>
+ <p>
+ Corresponds to the <code>KM_TAG_ALLOW_WHILE_ON_BODY</code> Keymaster tag,
+ which uses a tag ID value of 506.
+ </p>
+
+ <p>
+ Allows the key to be used after its authentication timeout period if the
+ user is still wearing the device on their body. Note that a secure
+ on-body sensor determines whether the device is being worn on the user’s
+ body.
+ </p>
+
+ <p>
+ When an <code>AuthorizationList</code> object is associated with key
+ attestation, this value is always true.
+ </p>
+ </dd>
+
+ <dt>
+ <code>allApplications</code>
+ </dt>
+
+ <dd>
+ <p>
+ Corresponds to the <code>KM_TAG_ALL_APPLICATIONS</code> Keymaster tag,
+ which uses a tag ID value of 600.
+ </p>
+
+ <p>
+ Indicates whether all apps on a device can access the key pair.
+ </p>
+
+ <p>
+ When an <code>AuthorizationList</code> object is associated with key
+ attestation, this value is always true.
+ </p>
+ </dd>
+
+ <dt>
+ <code>applicationId</code>
+ </dt>
+
+ <dd>
+ Corresponds to the <code><a href=
+ "https://source.android.com/security/keystore/implementer-ref.html#km_tag_application_id">
+ KM_TAG_APPLICATION_ID</a></code> Keymaster tag, which uses a tag ID value
+ of 601.
+ </dd>
+
+ <dt>
+ <code>creationDateTime</code>
+ </dt>
+
+ <dd>
+ Corresponds to the <code><a href=
+ "https://source.android.com/security/keystore/implementer-ref.html#km_tag_creation_datetime">
+ KM_TAG_CREATION_DATETIME</a></code> Keymaster tag, which uses a tag ID
+ value of 701.
+ </dd>
+
+ <dt>
+ <code>origin</code>
+ </dt>
+
+ <dd>
+ <p>
+ Corresponds to the <code><a href=
+ "https://source.android.com/security/keystore/implementer-ref.html#km_tag_origin">
+ KM_TAG_ORIGIN</a></code> Keymaster tag, which uses a tag ID value of 702.
+ </p>
+
+ <p>
+ When an <code>AuthorizationList</code> object is associated with key
+ attestation, this value is usually set to
+ <code>KM_ORIGIN_GENERATED</code>. If the attestation uses Keymaster
+ version 0.2 or 0.3, however, the origin may be set to
+ <code>KM_ORIGIN_UNKNOWN</code> instead.
+ </p>
+ </dd>
+
+ <dt>
+ <code>rollbackResistant</code>
+ </dt>
+
+ <dd>
+ Corresponds to the <code><a href=
+ "https://source.android.com/security/keystore/implementer-ref.html#km_tag_rollback_resistant">
+ KM_TAG_ROLLBACK_RESISTANT</a></code> Keymaster tag, which uses a tag ID
+ value of 703.
+ </dd>
+
+ <dt>
+ <code>rootOfTrust</code>
+ </dt>
+
+ <dd>
+ <p>
+ Corresponds to the <code><a href=
+ "https://source.android.com/security/keystore/implementer-ref.html#km_tag_root_of_trust">
+ KM_TAG_ROOT_OF_TRUST</a></code> Keymaster tag, which uses a tag ID value
+ of 704.
+ </p>
+
+ <p>
+ For more details, see the section describing the <code><a href=
+ "#certificate_schema_rootoftrust">RootOfTrust</a></code>
+ data structure.
+ </p>
+ </dd>
+
+ <dt>
+ <code>osVersion</code>
+ </dt>
+
+ <dd>
+ <p>
+ Corresponds to the <code>KM_TAG_OS_VERSION</code> Keymaster tag, which
+ uses a tag ID value of 705.
+ </p>
+
+ <p>
+ The version of the Android operating system associated with the
+ Keymaster, specified as a six-digit integer. For example, version 6.0.1
+ is represented as 060001.
+ </p>
+
+ <p>
+ Only Keymaster version 1.0 or higher includes this value in the
+ authorization list.
+ </p>
+ </dd>
+
+ <dt>
+ <code>osPatchLevel</code>
+ </dt>
+
+ <dd>
+ <p>
+ Corresponds to the <code>KM_TAG_PATCHLEVEL</code> Keymaster tag, which
+ uses a tag ID value of 706.
+ </p>
+
+ <p>
+ The month and year associated with the security patch that is being used
+ within the Keymaster, specified as a six-digit integer. For example, the
+ June 2016 patch is represented as 201606.
+ </p>
+
+ <p>
+ Only Keymaster version 1.0 or higher includes this value in the
+ authorization list.
+ </p>
+ </dd>
+
+ <dt>
+ <code>attestationChallenge</code>
+ </dt>
+
+ <dd>
+ <p>
+ Corresponds to the <code>KM_TAG_ATTESTATION_CHALLENGE</code> Keymaster
+ tag, which uses a tag ID value of 708.
+ </p>
+
+ <p>
+ The challenge string associated with the key pair that is defined in the
+ Keymaster.
+ </p>
+ </dd>
+
+ <dt>
+ <code>attestationApplicationId</code>
+ </dt>
+
+ <dd>
+ <p>
+ Corresponds to the <code>KM_TAG_ATTESTATION_APPLICATION_ID</code>
+ Keymaster tag, which uses a tag ID value of 709.
+ </p>
+
+ <p>
+ The unique ID of the attestation certificate that signed the key pair
+ that is in the Keymaster.
+ </p>
+ </dd>
+</dl>
+
+<h3 id="certificate_schema_rootoftrust">
+ RootOfTrust
+</h3>
+
+<p>
+ This collection of values defines key information about the device’s status.
+</p>
+
+<p>
+ Each field in the following list is required:
+</p>
+
+<dl>
+ <dt>
+ <code>verifiedBootKey</code>
+ </dt>
+
+ <dd>
+ <p>
+ A secure hash of the key that verifies the system image. It is recommended
+ that you use the SHA-256 algorithm for this hash.
+ </p>
+ </dd>
+
+ <dt>
+ <code>deviceLocked</code>
+ </dt>
+
+ <dd>
+ True if the device’s bootloader is locked, which enables Verified Boot
+ checking and prevents an unsigned device image from being flashed onto the
+ device. For more information about this feature, see the <a class=
+ "external-link" href=
+ "https://source.android.com/security/verifiedboot/verified-boot.html">Verifying
+ Boot</a> documentation.
+ </dd>
+
+ <dt>
+ <code>verifiedBootState</code>
+ </dt>
+
+ <dd>
+ The <a href="#certificate_schema_verifiedbootstate">boot
+ state</a> of the device, according to the Verified Boot feature.
+ </dd>
+
+ <dt>
+ <code>osVersion</code>
+ </dt>
+
+ <dd>
+ The current version of the Android operating system on the device,
+ specified as a six-digit integer. For example, version 6.0.1 is represented
+ as 060001.
+ </dd>
+
+ <dt>
+ <code>patchMonthYear</code>
+ </dt>
+
+ <dd>
+ The month and year associated with the security patch that is currently
+ installed on the device, specified as a six-digit integer. For example, the
+ June 2016 patch is represented as 201606.
+ </dd>
+</dl>
+
+<h3 id="certificate_schema_verifiedbootstate">
+ VerifiedBootState
+</h3>
+
+<p>
+ This data structure provides the device’s current boot state, which
+ represents the level of protection provided to the user and to apps after the
+ device finishes booting. For more information about this feature, see the
+ <a class="external-link" href=
+ "https://source.android.com/security/verifiedboot/verified-boot.html#boot_state">
+ Boot State</a> section within the Verifying Boot documentation.
+</p>
+
+<p>
+ This data structure is an enumeration, so it takes on exactly one of the
+ following values:
+</p>
+
+<dl>
+ <dt>
+ Verified
+ </dt>
+
+ <dd>
+ <p>
+ Indicates a full chain of trust, which includes the bootloader, the boot
+ partition, and all verified partitions.
+ </p>
+
+ <p>
+ When the device is in this boot state, the <code>verifiedBootKey</code> is
+ the hash of the device-embedded certificate, which the device manufacturer
+ adds to the device's ROM at the factory.
+ </p>
+ </dd>
+
+ <dt>
+ SelfSigned
+ </dt>
+
+ <dd>
+ <p>
+ Indicates that the device-embedded certificate has verified the device’s
+ boot partition and that the signature is valid.
+ </p>
+
+ <p>
+ When the device is in this boot state, the <code>verifiedBootKey</code> is
+ the hash of a user-installed certificate, which signs a boot partition
+ that the user adds to the device in place of the original,
+ manufacturer-provided boot partition.
+ </p>
+ </dd>
+
+ <dt>
+ Unverified
+ </dt>
+
+ <dd>
+ Indicates that the user can modify the device freely. Therefore, the user is
+ responsible for verifying the device’s integrity.
+ </dd>
+
+ <dt>
+ Failed
+ </dt>
+
+ <dd>
+ Indicates that the device has failed verification. The attestation
+ certificate should never use this value for <code>VerifiedBootState</code>.
+ </dd>
+</dl>
diff --git a/docs/html/preview/features/multi-window.jd b/docs/html/preview/features/multi-window.jd
index a4f389a0948b..ca5bd0da292e 100644
--- a/docs/html/preview/features/multi-window.jd
+++ b/docs/html/preview/features/multi-window.jd
@@ -471,7 +471,7 @@ android:supportsPictureInPicture=["true" | "false"]
</dd>
<dt>
- <code>Activity.requestDropPermissions()</code>
+ <code>Activity.requestDragAndDropPermissions()</code>
</dt>
<dd>
diff --git a/docs/html/preview/index.jd b/docs/html/preview/index.jd
index 918de48c41d3..0b21e68cd855 100644
--- a/docs/html/preview/index.jd
+++ b/docs/html/preview/index.jd
@@ -114,7 +114,24 @@ footer.hide=1
data-initial-results="3"></div>
</div></section>
-<section class="dac-section dac-gray"><div class="wrap">
+
+<section class="dac-section dac-gray" id="videos"><div class="wrap">
+ <h1 class="dac-section-title">Videos</h1>
+ <div class="dac-section-subtitle">
+ New Android capabilities and the right way to use them in your apps.
+ </div>
+
+ <div class="resource-widget resource-flow-layout col-16"
+ data-query="collection:preview/landing/videos/first,type:youtube+tag:androidn"
+ data-sortOrder="-timestamp"
+ data-cardSizes="6x6"
+ data-items-per-page="6"
+ data-maxResults="15"
+ data-initial-results="3"></div>
+</div></section>
+
+
+<section class="dac-section dac-light" id="resources"><div class="wrap">
<h1 class="dac-section-title">Resources</h1>
<div class="dac-section-subtitle">
Essential information to help you get your apps ready for Android N.
diff --git a/docs/html/preview/setup-sdk.jd b/docs/html/preview/setup-sdk.jd
index 3b479e25b675..58ca1d0b174a 100644
--- a/docs/html/preview/setup-sdk.jd
+++ b/docs/html/preview/setup-sdk.jd
@@ -76,6 +76,12 @@ Android N Preview SDK in Android Studio as follows:</p>
<h3 id="docs-dl">Get the N Preview reference documentation</h3>
+<p class="note">
+ <strong>Note:</strong> The N Preview (API level 24) reference documentation
+ is now available online at <a href=
+ "{@docRoot}reference/">developer.android.com/reference/</a>.
+</p>
+
<p>
Detailed information about the Android N APIs is available in the N Preview
reference documentation, which you can download from the following table.
@@ -95,7 +101,7 @@ Android N Preview SDK in Android Studio as follows:</p>
>n-preview-3-docs.zip</a></td>
<td width="100%">
MD5: 19bcfd057a1f9dd01ffbb3d8ff7b8d81<br>
- SHA-1: 9224bd4445cd7f653c4c294d362ccb195a2101e7
+ SHA-1: 9224bd4445cd7f653c4c294d362ccb195a2101e7
</td>
</tr>
</table>
diff --git a/docs/html/topic/libraries/support-library/features.jd b/docs/html/topic/libraries/support-library/features.jd
index d9616d951c5c..584bef8a7981 100755
--- a/docs/html/topic/libraries/support-library/features.jd
+++ b/docs/html/topic/libraries/support-library/features.jd
@@ -619,7 +619,7 @@ package provides APIs to support adding and managing custom tabs in your apps. <
<a href="{@docRoot}reference/android/support/customtabs/CustomTabsService.html">Custom Tabs
Service</a>
and
-<a href="{@docRoot}reference/android/support/customtabs/CustomTabsSCallback.html">Custom Tabs
+<a href="{@docRoot}reference/android/support/customtabs/CustomTabsCallback.html">Custom Tabs
Callback</a>. </p>
diff --git a/docs/html/topic/libraries/testing-support-library/index.jd b/docs/html/topic/libraries/testing-support-library/index.jd
index 8b23f73e0ca6..941f5c3024d0 100644
--- a/docs/html/topic/libraries/testing-support-library/index.jd
+++ b/docs/html/topic/libraries/testing-support-library/index.jd
@@ -523,7 +523,7 @@ onView(withId(R.id.changeTextBt)).perform(click());</pre>
mDevice = UiDevice.getInstance(getInstrumentation());
// Perform a short press on the HOME button
-mDevice().pressHome();
+mDevice.pressHome();
// Bring up the default launcher by searching for
// a UI component that matches the content-description for the launcher button
diff --git a/docs/html/training/appbar/setting-up.jd b/docs/html/training/appbar/setting-up.jd
index cc963c6df398..cf564d0ffc27 100644
--- a/docs/html/training/appbar/setting-up.jd
+++ b/docs/html/training/appbar/setting-up.jd
@@ -68,7 +68,7 @@ These steps describe how to set up a {@link android.support.v7.widget.Toolbar}
as your activity's app bar:
<ol>
- <li>Add the the
+ <li>Add the
<a href="{@docRoot}tools/support-library/features.html#v7-appcompat">v7
appcompat</a> support library to your project, as described in <a href=
"{@docRoot}tools/support-library/setup.html">Support Library Setup</a>.
diff --git a/docs/html/training/basics/supporting-devices/languages.jd b/docs/html/training/basics/supporting-devices/languages.jd
index 7d4d4743a50c..ba7c0160fe51 100644
--- a/docs/html/training/basics/supporting-devices/languages.jd
+++ b/docs/html/training/basics/supporting-devices/languages.jd
@@ -41,7 +41,7 @@ your string values.</p>
<p>To add support for more languages, create additional <code>values</code> directories inside
<code>res/</code> that include a hyphen and the ISO language code at the end of the
directory name. For example, <code>values-es/</code> is the directory containing simple
-resourcess for the Locales with the language code "es". Android loads the appropriate resources
+resources for the Locales with the language code "es". Android loads the appropriate resources
according to the locale settings of the device at run time. For more information, see
<a href="{@docRoot}guide/topics/resources/providing-resources.html#AlternativeResources">Providing Alternative Resources</a>.</p>
diff --git a/docs/html/training/testing/performance.jd b/docs/html/training/testing/performance.jd
index 8592c0f85120..0c0ab7f696e4 100644
--- a/docs/html/training/testing/performance.jd
+++ b/docs/html/training/testing/performance.jd
@@ -437,15 +437,25 @@ Number Slow draw: 23342
</p>
<ul>
- <li>Rendering Performance 101
+ <li>
+ <a class="external-link" href="https://www.youtube.com/watch?v=HXQhu6qfTVU">
+ Rendering Performance 101</a>
</li>
- <li>Why 60fps?
+ <li>
+ <a class="external-link" href="https://www.youtube.com/watch?v=CaMTIgxCSqU">
+ Why 60fps?</a>
</li>
- <li>Android UI and the GPU
+ <li>
+ <a class="external-link" href="https://www.youtube.com/watch?v=WH9AFhgwmDw">
+ Android, UI, and the GPU</a>
</li>
- <li>Invalidations Layouts and performance
+ <li>
+ <a class="external-link" href="https://www.youtube.com/watch?v=we6poP0kw6E">
+ Invalidations, Layouts, and Performance</a>
</li>
- <li>Analyzing UI Performance with Systrace
+ <li>
+ <a href="{@docRoot}studio/profile/systrace.html">
+ Analyzing UI Performance with Systrace</a>
</li>
</ul>
diff --git a/docs/html/training/wearables/data-layer/events.jd b/docs/html/training/wearables/data-layer/events.jd
index 9bed9d548aad..20f219d69188 100644
--- a/docs/html/training/wearables/data-layer/events.jd
+++ b/docs/html/training/wearables/data-layer/events.jd
@@ -22,21 +22,21 @@ the call ends up making with listeners.
<h2 id="Wait">Wait for the Status of Data Layer Calls</h2>
<p>You'll notice that calls to the Data Layer API sometimes return a
-<a href="{@docRoot}reference/com/google/android/gms/common/api/PendingResult.html"><code>PendingResult</code></a>,
+<a href="https://developers.google.com/android/reference/com/google/android/gms/common/api/PendingResult.html"><code>PendingResult</code></a>,
such as
-<a href="{@docRoot}reference/com/google/android/gms/wearable/DataApi.html#putDataItem(com.google.android.gms.common.api.GoogleApiClient, com.google.android.gms.wearable.PutDataRequest)"><code>putDataItem()</code></a>.
-As soon as the <a href="{@docRoot}reference/com/google/android/gms/common/api/PendingResult.html"><code>PendingResult</code></a> is created,
+<a href="https://developers.google.com/android/reference/com/google/android/gms/wearable/DataApi.html#putDataItem(com.google.android.gms.common.api.GoogleApiClient, com.google.android.gms.wearable.PutDataRequest)"><code>putDataItem()</code></a>.
+As soon as the <a href="https://developers.google.com/android/reference/com/google/android/gms/common/api/PendingResult.html"><code>PendingResult</code></a> is created,
the operation is queued in the background. If you do nothing else after this, the operation
eventually completes silently. However, you'll usually want to do something with the result
after the operation completes, so the
-<a href="{@docRoot}reference/com/google/android/gms/common/api/PendingResult.html"><code>PendingResult</code></a>
+<a href="https://developers.google.com/android/reference/com/google/android/gms/common/api/PendingResult.html"><code>PendingResult</code></a>
lets you wait for the result status, either synchronously or asynchronously.
</p>
<h3 id="async-waiting">Asynchronous calls</h3>
<p>If your code is running on the main UI thread, do not make blocking calls
to the Data Layer API. You can run the calls asynchronously by adding a callback method
-to the <a href="{@docRoot}reference/com/google/android/gms/common/api/PendingResult.html"><code>PendingResult</code></a> object,
+to the <a href="https://developers.google.com/android/reference/com/google/android/gms/common/api/PendingResult.html"><code>PendingResult</code></a> object,
which fires when the operation is completed:</p>
<pre>
pendingResult.setResultCallback(new ResultCallback&lt;DataItemResult&gt;() {
@@ -51,12 +51,12 @@ pendingResult.setResultCallback(new ResultCallback&lt;DataItemResult&gt;() {
<h3 id="sync-waiting">Synchronous calls</h3>
<p>If your code is running on a separate handler thread in a background service (which is the case
-in a <a href="{@docRoot}reference/com/google/android/gms/wearable/WearableListenerService.html"><code>WearableListenerService</code></a>),
+in a <a href="https://developers.google.com/android/reference/com/google/android/gms/wearable/WearableListenerService.html"><code>WearableListenerService</code></a>),
it's fine for the calls to block. In this case, you can call
-<a href="{@docRoot}reference/com/google/android/gms/common/api/PendingResult.html#await()"><code>await()</code></a>
-on the <a href="{@docRoot}reference/com/google/android/gms/common/api/PendingResult.html"><code>PendingResult</code></a>
+<a href="https://developers.google.com/android/reference/com/google/android/gms/common/api/PendingResult.html#await()"><code>await()</code></a>
+on the <a href="https://developers.google.com/android/reference/com/google/android/gms/common/api/PendingResult.html"><code>PendingResult</code></a>
object, which blocks until the request completes and returns a
-<a href="{@docRoot}reference/com/google/android/gms/common/api/Result.html"><code>Result</code></a>
+<a href="https://developers.google.com/android/reference/com/google/android/gms/common/api/Result.html"><code>Result</code></a>
object:
</p>
@@ -79,7 +79,7 @@ To listen for data layer events, you have two options:
</p>
<ul>
<li>Create a service that extends <a href
-="https://developer.android.com/reference/com/google/android/gms/wearable/WearableListenerService.html">
+="https://developers.google.com/android/reference/com/google/android/gms/wearable/WearableListenerService.html">
{@code WearableListenerService}</a>.</li>
<li>Create an activity that implements <a
href="https://developer.android.com/reference/com/google/android/gms/wearable/DataApi.DataListener.html">
@@ -215,7 +215,7 @@ The next section explains how to use an intent filter with this listener.
<p>
An intent filter for the
-<a href="{@docRoot}reference/com/google/android/gms/wearable/WearableListenerService.html">
+<a href="https://developers.google.com/android/reference/com/google/android/gms/wearable/WearableListenerService.html">
{@code WearableListenerService}</a> example shown in the previous section might look like this:
<pre>
@@ -250,14 +250,14 @@ You can also match a literal path or path prefix. If you are matching by path
or path prefix, you must specify a wildcard or specific host.
If you do not do so, the system ignores the path you specified.
</p>
+
<p>
For more information on the filter types that Wear supports, see the
API reference documentation for <a
href="https://developers.google.com/android/reference/com/google/android/gms/wearable/WearableListenerService">
{@code WearableListenerService}</a>.
-
-
</p>
+
<p>
For more information on data filters and matching rules, see the API reference
documentation for the <a
@@ -265,7 +265,6 @@ href="{@docRoot}guide/topics/manifest/data-element.html">{@code data}</a>
manifest element.
</p>
-
<p>When matching intent filters, there are two important rules to remember:</p>
<ul>
<li>If a scheme is not specified for the intent filter, the system ignores
@@ -282,10 +281,10 @@ change. In such a case, you can listen for events in an activity by
implementing one or more of the following interfaces:
</p>
<ul>
- <li><a href="{@docRoot}reference/com/google/android/gms/wearable/DataApi.DataListener.html"><code>
+ <li><a href="https://developers.google.com/android/reference/com/google/android/gms/wearable/DataApi.DataListener.html"><code>
DataApi.DataListener</code></a></li>
- <li><a href="{@docRoot}reference/com/google/android/gms/wearable/MessageApi.MessageListener.html">
+ <li><a href="https://developers.google.com/android/reference/com/google/android/gms/wearable/MessageApi.MessageListener.html">
<code>MessageApi.MessageListener</code></a></li>
<li><a href="https://developers.google.com/android/reference/com/google/android/gms/wearable/CapabilityApi.CapabilityListener.html">{@code CapabilityApi.CapabilityListener}</a></li>
@@ -295,21 +294,21 @@ implementing one or more of the following interfaces:
<ol>
<li>Implement the desired interfaces.</li>
<li>In {@link android.app.Activity#onCreate onCreate()}, create an instance of
-<a href="{@docRoot}reference/com/google/android/gms/common/api/GoogleApiClient.html"><code>GoogleApiClient</code>
+<a href="https://developers.google.com/android/reference/com/google/android/gms/common/api/GoogleApiClient.html"><code>GoogleApiClient</code>
</a>to work with the Data Layer API.</li>
<li>
-In {@link android.app.Activity#onStart onStart()}, call <a href="{@docRoot}reference/com/google/android/gms/common/api/GoogleApiClient.html#connect()">
+In {@link android.app.Activity#onStart onStart()}, call <a href="https://developers.google.com/android/reference/com/google/android/gms/common/api/GoogleApiClient.html#connect()">
<code>connect()</code></a> to connect the client to Google Play services.
</li>
<li>When the connection to Google Play services is established, the system calls
-<a href="{@docRoot}reference/com/google/android/gms/common/api/GoogleApiClient.ConnectionCallbacks.html#onConnected(android.os.Bundle)"><code>onConnected()</code></a>. This is where you call
+<a href="https://developers.google.com/android/reference/com/google/android/gms/common/api/GoogleApiClient.ConnectionCallbacks.html#onConnected(android.os.Bundle)"><code>onConnected()</code></a>. This is where you call
-<a href="{@docRoot}reference/com/google/android/gms/wearable/DataApi.html#addListener(com.google.android.gms.common.api.GoogleApiClient, com.google.android.gms.wearable.DataApi.DataListener)">
+<a href="https://developers.google.com/android/reference/com/google/android/gms/wearable/DataApi.html#addListener(com.google.android.gms.common.api.GoogleApiClient, com.google.android.gms.wearable.DataApi.DataListener)">
<code>DataApi.addListener()</code></a>,
-<a href="{@docRoot}android/reference/com/google/android/gms/wearable/CapabilityApi.CapabilityListener">
+<a href="https://developers.google.com/android/reference/com/google/android/gms/wearable/MessageApi.html#addListener(com.google.android.gms.common.api.GoogleApiClient, com.google.android.gms.wearable.MessageApi.MessageListener, android.net.Uri, int)">
<code>MessageApi.addListener()</code></a>, or
<a href="https://developers.google.com/android/reference/com/google/android/gms/wearable/CapabilityApi.html#addListener(com.google.android.gms.common.api.GoogleApiClient,%20com.google.android.gms.wearable.CapabilityApi.CapabilityListener,%20android.net.Uri,%20int)">
@@ -317,14 +316,16 @@ In {@link android.app.Activity#onStart onStart()}, call <a href="{@docRoot}refer
interested in listening for data layer events.</li>
<li>In {@link android.app.Activity#onStop onStop()}, unregister any listeners with
-<a href="{@docRoot}reference/com/google/android/gms/wearable/DataApi.html#removeListener(com.google.android.gms.common.api.GoogleApiClient, com.google.android.gms.wearable.DataApi.DataListener)"><code>DataApi.removeListener()</code></a>,
-<a href="{@docRoot}reference/com/google/android/gms/wearable/MessageApi.html#removeListener(com.google.android.gms.common.api.GoogleApiClient, com.google.android.gms.wearable.MessageApi.MessageListener)"><code>MessageApi.removeListener()</code></a>, or
-<a href="http://developer.android.com/reference/com/google/android/gms/wearable/MessageApi.html#removeListener(com.google.android.gms.common.api.GoogleApiClient,%20com.google.android.gms.wearable.MessageApi.MessageListener)">
+<a href="https://developers.google.com/android/reference/com/google/android/gms/wearable/DataApi.html#removeListener(com.google.android.gms.common.api.GoogleApiClient, com.google.android.gms.wearable.DataApi.DataListener)"><code>DataApi.removeListener()</code></a>,
+
+<a href="https://developers.google.com/android/reference/com/google/android/gms/wearable/MessageApi.html#removeListener(com.google.android.gms.common.api.GoogleApiClient, com.google.android.gms.wearable.MessageApi.MessageListener)"><code>MessageApi.removeListener()</code></a>, or
+
+<a href="https://developers.google.com/android/reference/com/google/android/gms/wearable/CapabilityApi.html#removeListener(com.google.android.gms.common.api.GoogleApiClient, com.google.android.gms.wearable.CapabilityApi.CapabilityListener)">
{@code CapabilityApi.removeListener()}</a>.</li>
<p>An alternative to adding listeners in
-<a href="{@docRoot}reference/com/google/android/gms/common/api/GoogleApiClient.ConnectionCallbacks.html#onConnected(android.os.Bundle)"><code>onConnected()</code></a>
+<a href="https://developers.google.com/android/reference/com/google/android/gms/common/api/GoogleApiClient.ConnectionCallbacks.html#onConnected(android.os.Bundle)"><code>onConnected()</code></a>
and removing them in
{@link android.app.Activity#onStop onStop()} is to add a filtered listener in an activity’s {@link android.app.Activity#onResume onResume()} and
remove it in {@link android.app.Activity#onPause onPause()}, so as to only receive data that is relevant to the
@@ -332,18 +333,18 @@ current application state.</p>
<li>Implement
-<a href="{@docRoot}reference/com/google/android/gms/wearable/DataApi.DataListener.html#onDataChanged(com.google.android.gms.wearable.DataEventBuffer)">
+<a href="https://developers.google.com/android/reference/com/google/android/gms/wearable/DataApi.DataListener.html#onDataChanged(com.google.android.gms.wearable.DataEventBuffer)">
<code>onDataChanged()</code></a>,
<a href="https://developers.google.com/android/reference/com/google/android/gms/wearable/MessageApi.MessageListener.html#onMessageReceived(com.google.android.gms.wearable.MessageEvent)">
<code>onMessageReceived()</code></a>,
<a href="https://developers.google.com/android/reference/com/google/android/gms/wearable/WearableListenerService.html#onCapabilityChanged(com.google.android.gms.wearable.CapabilityInfo)">
{@code onCapabilityChanged()}</a>,
-or methods from <a href="http://developer.android.com/reference/com/google/android/gms/wearable/ChannelApi.ChannelListener.html">
+or methods from <a href="https://developers.google.com/android/reference/com/google/android/gms/wearable/ChannelApi.ChannelListener.html">
Channel API listener methods</a>, depending on the interfaces that you implemented.</li>
</ol>
<p>Here's an example that implements
-<a href="{@docRoot}reference/com/google/android/gms/wearable/DataApi.DataListener.html"><code>DataApi.DataListener</code></a>:</p>
+<a href="https://developers.google.com/android/reference/com/google/android/gms/wearable/DataApi.DataListener.html"><code>DataApi.DataListener</code></a>:</p>
<pre>
public class MainActivity extends Activity implements
@@ -403,7 +404,7 @@ public class MainActivity extends Activity implements
<h3>Using Filters with Listener Activities</h3>
<p>
Just as you can specify intent filters for manifest-based
-<a href="{@docRoot}reference/com/google/android/gms/wearable/WearableListenerService.html">
+<a href="https://developers.google.com/android/reference/com/google/android/gms/wearable/WearableListenerService.html">
<code>WearableListenerService</code></a> objects, you can also use intent filters when registering a
listener through the Wearable API. The same rules are applicable to both
API-based listeners manifest-based listeners.
@@ -411,7 +412,7 @@ API-based listeners manifest-based listeners.
<p>
A common pattern is to register a listener with a specific path or path prefix
-in an activity’s{@link android.app.Activity#onResume onResume()} method, and to
+in an activity’s {@link android.app.Activity#onResume onResume()} method, and to
remove the listener in the activity’s {@link android.app.Activity#onPause onPause()} method.
Implementing listeners in this fashion allows your application to more selectively receive events,
improving its design and efficiency.
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index faf6a52bca85..c9d4af69c0df 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -256,6 +256,7 @@ LOCAL_SRC_FILES += \
tests/unit/MatrixTests.cpp \
tests/unit/OffscreenBufferPoolTests.cpp \
tests/unit/RenderNodeTests.cpp \
+ tests/unit/RenderPropertiesTests.cpp \
tests/unit/SkiaBehaviorTests.cpp \
tests/unit/SnapshotTests.cpp \
tests/unit/StringUtilsTests.cpp \
diff --git a/libs/hwui/BakedOpRenderer.cpp b/libs/hwui/BakedOpRenderer.cpp
index ea2e15b54b2f..6db345ac0006 100644
--- a/libs/hwui/BakedOpRenderer.cpp
+++ b/libs/hwui/BakedOpRenderer.cpp
@@ -66,8 +66,13 @@ void BakedOpRenderer::startRepaintLayer(OffscreenBuffer* offscreenBuffer, const
offscreenBuffer->texture.id(), 0);
GL_CHECKPOINT(LOW);
- LOG_ALWAYS_FATAL_IF(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE,
- "framebuffer incomplete!");
+ int status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+ LOG_ALWAYS_FATAL_IF(status != GL_FRAMEBUFFER_COMPLETE,
+ "framebuffer incomplete, status %d, textureId %d, size %dx%d",
+ status,
+ offscreenBuffer->texture.id(),
+ offscreenBuffer->texture.width(),
+ offscreenBuffer->texture.height());
// Change the viewport & ortho projection
setViewport(offscreenBuffer->viewportWidth, offscreenBuffer->viewportHeight);
diff --git a/libs/hwui/FrameBuilder.cpp b/libs/hwui/FrameBuilder.cpp
index cb8e55fbb21c..b8a5ce6686b4 100644
--- a/libs/hwui/FrameBuilder.cpp
+++ b/libs/hwui/FrameBuilder.cpp
@@ -86,7 +86,9 @@ void FrameBuilder::deferLayers(const LayerUpdateQueue& layers) {
ATRACE_FORMAT("Optimize HW Layer DisplayList %s %ux%u",
layerNode->getName(), layerNode->getWidth(), layerNode->getHeight());
- const Rect& layerDamage = layers.entries()[i].damage;
+ Rect layerDamage = layers.entries()[i].damage;
+ // TODO: ensure layer damage can't be larger than layer
+ layerDamage.doIntersect(0, 0, layer->viewportWidth, layer->viewportHeight);
layerNode->computeOrdering();
// map current light center into RenderNode's coordinate space
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index 6e848fddf48f..be2dab98e911 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -319,6 +319,8 @@ void RenderNode::pushLayerUpdate(TreeInfo& info) {
transformUpdateNeeded = true;
} else if (!layerMatchesWidthAndHeight(mLayer, getWidth(), getHeight())) {
#if HWUI_NEW_OPS
+ // TODO: remove now irrelevant, currently enqueued damage (respecting damage ordering)
+ // Or, ideally, maintain damage between frames on node/layer so ordering is always correct
RenderState& renderState = mLayer->renderState;
if (properties().fitsOnLayer()) {
mLayer = renderState.layerPool().resize(mLayer, getWidth(), getHeight());
diff --git a/libs/hwui/RenderProperties.h b/libs/hwui/RenderProperties.h
index 395279806adb..696cc29de3a4 100644
--- a/libs/hwui/RenderProperties.h
+++ b/libs/hwui/RenderProperties.h
@@ -611,7 +611,9 @@ public:
bool fitsOnLayer() const {
const DeviceInfo* deviceInfo = DeviceInfo::get();
return mPrimitiveFields.mWidth <= deviceInfo->maxTextureSize()
- && mPrimitiveFields.mHeight <= deviceInfo->maxTextureSize();
+ && mPrimitiveFields.mHeight <= deviceInfo->maxTextureSize()
+ && mPrimitiveFields.mWidth > 0
+ && mPrimitiveFields.mHeight > 0;
}
bool promotedToLayer() const {
diff --git a/libs/hwui/tests/unit/RenderPropertiesTests.cpp b/libs/hwui/tests/unit/RenderPropertiesTests.cpp
new file mode 100644
index 000000000000..90010983f154
--- /dev/null
+++ b/libs/hwui/tests/unit/RenderPropertiesTests.cpp
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ */
+
+#include <gtest/gtest.h>
+
+#include <RenderProperties.h>
+
+using namespace android;
+using namespace android::uirenderer;
+
+TEST(RenderProperties, layerValidity) {
+ DeviceInfo::initialize();
+
+ const int maxTextureSize = DeviceInfo::get()->maxTextureSize();
+ ASSERT_LE(2048, maxTextureSize);
+ ASSERT_GT(100000, maxTextureSize);
+
+ RenderProperties props;
+
+ // simple cases that all should fit on layers
+ props.setLeftTopRightBottom(0, 0, 100, 100);
+ ASSERT_TRUE(props.fitsOnLayer());
+ props.setLeftTopRightBottom(100, 2000, 300, 4000);
+ ASSERT_TRUE(props.fitsOnLayer());
+ props.setLeftTopRightBottom(-10, -10, 510, 512);
+ ASSERT_TRUE(props.fitsOnLayer());
+
+ // Too big - can't have layer bigger than max texture size
+ props.setLeftTopRightBottom(0, 0, maxTextureSize + 1, maxTextureSize + 1);
+ ASSERT_FALSE(props.fitsOnLayer());
+
+ // Too small - can't have 0 dimen layer
+ props.setLeftTopRightBottom(0, 0, 100, 0);
+ ASSERT_FALSE(props.fitsOnLayer());
+}
diff --git a/packages/CtsShim/Android.mk b/packages/CtsShim/Android.mk
index cd5b288617d8..fa6423ecb8c7 100644
--- a/packages/CtsShim/Android.mk
+++ b/packages/CtsShim/Android.mk
@@ -53,3 +53,4 @@ LOCAL_SRC_FILES := CtsShim.apk
include $(BUILD_PREBUILT)
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/packages/CtsShim/build/Android.mk b/packages/CtsShim/build/Android.mk
index b550c1c253f3..bf6ae4151dae 100644
--- a/packages/CtsShim/build/Android.mk
+++ b/packages/CtsShim/build/Android.mk
@@ -17,7 +17,7 @@
LOCAL_PATH := $(my-dir)
###########################################################
-# Variant: Privileged app
+# Variant: Privileged app upgrade
include $(CLEAR_VARS)
# this needs to be a privileged application
@@ -28,15 +28,15 @@ LOCAL_SDK_VERSION := current
LOCAL_PROGUARD_ENABLED := disabled
LOCAL_DEX_PREOPT := false
-LOCAL_PACKAGE_NAME := CtsShimPriv
+LOCAL_PACKAGE_NAME := CtsShimPrivUpgrade
-LOCAL_MANIFEST_FILE := shim_priv/AndroidManifest.xml
+LOCAL_MANIFEST_FILE := shim_priv_upgrade/AndroidManifest.xml
include $(BUILD_PACKAGE)
-
+my_shim_priv_upgrade_apk := $(LOCAL_BUILT_MODULE)
###########################################################
-# Variant: Privileged app upgrade
+# Variant: Privileged app
include $(CLEAR_VARS)
# this needs to be a privileged application
@@ -47,12 +47,20 @@ LOCAL_SDK_VERSION := current
LOCAL_PROGUARD_ENABLED := disabled
LOCAL_DEX_PREOPT := false
-LOCAL_PACKAGE_NAME := CtsShimPrivUpgrade
+LOCAL_PACKAGE_NAME := CtsShimPriv
-LOCAL_MANIFEST_FILE := shim_priv_upgrade/AndroidManifest.xml
+# Generate the upgrade key by taking the hash of the built CtsShimPrivUpgrade apk
+gen := $(call intermediates-dir-for,APPS,$(LOCAL_PACKAGE_NAME),,true)/AndroidManifest.xml
+$(gen): PRIVATE_CUSTOM_TOOL = sed -e "s/__HASH__/`sha512sum $(PRIVATE_INPUT_APK) | cut -d' ' -f1`/" $< >$@
+$(gen): PRIVATE_INPUT_APK := $(my_shim_priv_upgrade_apk)
+$(gen): $(LOCAL_PATH)/shim_priv/AndroidManifest.xml $(my_shim_priv_upgrade_apk)
+ $(transform-generated-source)
-include $(BUILD_PACKAGE)
+my_shim_priv_upgrade_apk :=
+
+LOCAL_FULL_MANIFEST_FILE := $(gen)
+include $(BUILD_PACKAGE)
###########################################################
# Variant: System app
diff --git a/packages/CtsShim/build/README b/packages/CtsShim/build/README
index 1f154e1d70b0..333b87c8cb9d 100644
--- a/packages/CtsShim/build/README
+++ b/packages/CtsShim/build/README
@@ -6,31 +6,18 @@ must specify the singular APK that can be used to upgrade it.
NOTE: The need to include a binary on the system image may be deprecated if a
solution involving a temporarily writable /system partition is implemented.
-MAKING THE PREBUILTS
-In order to generate the upgrade key, the shim directory needs to be built multiple
-times. First to generate the upgrade APK [so its hash can be obtained] and again
-once the hash has been included as part of the pre-installed APK.
-
build:
- $ mmm frameworks/base/packages/CtsShim/build
-
-update the manifest:
- $ sed -i -e "s/__HASH__/`sha512sum out/target/product/shamu/system/priv-app/CtsShimPrivUpgrade/CtsShimPrivUpgrade.apk | cut -d' ' -f1`/" \
- frameworks/base/packages/CtsShim/build/shim_priv/AndroidManifest.xml
+ $ tapas CtsShim CtsShimPriv CtsShimPrivUpgrade
+ $ m
-build:
- $ mmm frameworks/base/packages/CtsShim/build
-
-update prebuilts:
- $ cp out/target/product/shamu/system/priv-app/CtsShimPrivUpgrade/CtsShimPrivUpgrade.apk \
+local testing:
+ $ cp $OUT/system/priv-app/CtsShimPrivUpgrade/CtsShimPrivUpgrade.apk \
cts/hostsidetests/appsecurity/test-apps/PrivilegedUpdateApp
- $ cp out/target/product/shamu/system/priv-app/CtsShimPriv/CtsShimPriv.apk \
+ $ cp $OUT/system/priv-app/CtsShimPriv/CtsShimPriv.apk \
frameworks/base/packages/CtsShim
- $ cp out/target/product/shamu/system/app/CtsShim/CtsShim.apk \
+ $ cp $OUT/system/app/CtsShim/CtsShim.apk \
frameworks/base/packages/CtsShim
-revert manifest:
- $ pushd frameworks/base && git checkout -- packages/CtsShim/build/shim_priv/AndroidManifest.xml && popd
-
-Finally, upload and submit both the cts/ and frameworks/base/ repos.
+For final submission, the APKs should be downloaded from the build server, then
+submitted to the cts/ and frameworks/base/ repos.
diff --git a/packages/DocumentsUI/src/com/android/documentsui/OpenExternalDirectoryActivity.java b/packages/DocumentsUI/src/com/android/documentsui/OpenExternalDirectoryActivity.java
index b0e5e4e531e1..6588ee1c91c6 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/OpenExternalDirectoryActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/OpenExternalDirectoryActivity.java
@@ -20,6 +20,7 @@ import static android.os.Environment.isStandardDirectory;
import static android.os.Environment.STANDARD_DIRECTORIES;
import static android.os.storage.StorageVolume.EXTRA_DIRECTORY_NAME;
import static android.os.storage.StorageVolume.EXTRA_STORAGE_VOLUME;
+
import static com.android.documentsui.LocalPreferences.getScopedAccessPermissionStatus;
import static com.android.documentsui.LocalPreferences.PERMISSION_ASK;
import static com.android.documentsui.LocalPreferences.PERMISSION_ASK_AGAIN;
@@ -201,14 +202,23 @@ public class OpenExternalDirectoryActivity extends Activity {
final List<VolumeInfo> volumes = sm.getVolumes();
if (DEBUG) Log.d(TAG, "Number of volumes: " + volumes.size());
File internalRoot = null;
+ boolean found = true;
for (VolumeInfo volume : volumes) {
if (isRightVolume(volume, root, userId)) {
+ found = true;
internalRoot = volume.getInternalPathForUser(userId);
// Must convert path before calling getDocIdForFileCreateNewDir()
if (DEBUG) Log.d(TAG, "Converting " + root + " to " + internalRoot);
file = isRoot ? internalRoot : new File(internalRoot, directory);
+ volumeUuid = storageVolume.getUuid();
volumeLabel = sm.getBestVolumeDescription(volume);
- volumeUuid = volume.getFsUuid();
+ if (TextUtils.isEmpty(volumeLabel)) {
+ volumeLabel = storageVolume.getDescription(activity);
+ }
+ if (TextUtils.isEmpty(volumeLabel)) {
+ volumeLabel = activity.getString(android.R.string.unknownName);
+ Log.w(TAG, "No volume description for " + volume + "; using " + volumeLabel);
+ }
break;
}
}
@@ -229,7 +239,7 @@ public class OpenExternalDirectoryActivity extends Activity {
return true;
}
- if (volumeLabel == null) {
+ if (!found) {
Log.e(TAG, "Could not get volume for " + file);
logInvalidScopedAccessRequest(activity, SCOPED_DIRECTORY_ACCESS_ERROR);
return false;
@@ -277,15 +287,16 @@ public class OpenExternalDirectoryActivity extends Activity {
private static boolean isRightVolume(VolumeInfo volume, String root, int userId) {
final File userPath = volume.getPathForUser(userId);
final String path = userPath == null ? null : volume.getPathForUser(userId).getPath();
- final boolean isVisible = volume.isVisibleForWrite(userId);
+ final boolean isMounted = volume.isMountedReadable();
if (DEBUG)
- Log.d(TAG, "Volume: " + volume + " userId: " + userId + " root: " + root
- + " volumePath: " + volume.getPath().getPath()
- + " pathForUser: " + path
- + " internalPathForUser: " + volume.getInternalPath()
- + " isVisible: " + isVisible);
-
- return volume.isVisibleForWrite(userId) && root.equals(path);
+ Log.d(TAG, "Volume: " + volume
+ + "\n\tuserId: " + userId
+ + "\n\tuserPath: " + userPath
+ + "\n\troot: " + root
+ + "\n\tpath: " + path
+ + "\n\tisMounted: " + isMounted);
+
+ return isMounted && root.equals(path);
}
private static Uri getGrantedUriPermission(Context context, ContentProviderClient provider,
@@ -455,7 +466,7 @@ public class OpenExternalDirectoryActivity extends Activity {
message = TextUtils.expandTemplate(
getText(mIsPrimary ? R.string.open_external_dialog_request_primary_volume
: R.string.open_external_dialog_request),
- mAppLabel, directory, mVolumeLabel);
+ mAppLabel, directory, mVolumeLabel);
}
final TextView messageField = (TextView) view.findViewById(R.id.message);
messageField.setText(message);
diff --git a/packages/PrintRecommendationService/res/values/strings.xml b/packages/PrintRecommendationService/res/values/strings.xml
index 348fcace90c5..b6c45b7a23c8 100644
--- a/packages/PrintRecommendationService/res/values/strings.xml
+++ b/packages/PrintRecommendationService/res/values/strings.xml
@@ -26,6 +26,6 @@
<string name="plugin_vendor_samsung">Samsung</string>
<string name="plugin_vendor_epson">Epson</string>
<string name="plugin_vendor_konica_minolta">Konica Minolta</string>
- <string name="plugin_vendor_fuji">Fuji</string>
+ <string name="plugin_vendor_fuji_xerox">Fuji Xerox</string>
<string name="plugin_vendor_morpia">Mopria</string>
</resources>
diff --git a/packages/PrintRecommendationService/res/xml/vendorconfigs.xml b/packages/PrintRecommendationService/res/xml/vendorconfigs.xml
index 52889ce186a4..703cf6f45ddf 100644
--- a/packages/PrintRecommendationService/res/xml/vendorconfigs.xml
+++ b/packages/PrintRecommendationService/res/xml/vendorconfigs.xml
@@ -60,7 +60,7 @@
</vendor>
<vendor>
- <name>@string/plugin_vendor_fuji</name>
+ <name>@string/plugin_vendor_fuji_xerox</name>
<package>jp.co.fujixerox.prt.PrintUtil.PCL</package>
<mdns-names>
<mdns-name>FUJI XEROX</mdns-name>
diff --git a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/xerox/MDnsUtils.java b/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/xerox/MDnsUtils.java
index 7a2d0d8957ea..b0da08bf3003 100755
--- a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/xerox/MDnsUtils.java
+++ b/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/xerox/MDnsUtils.java
@@ -39,8 +39,10 @@ class MDnsUtils {
String usbMfg = getString(attributes.get(ATTRIBUTE__USB_MFG));
String usbMdl = getString(attributes.get(ATTRIBUTE__USB_MDL));
String mfg = getString(attributes.get(ATTRIBUTE__MFG));
- return containsVendor(product, vendorValues) || containsVendor(ty, vendorValues) || containsVendor(usbMfg, vendorValues) || containsVendor(mfg, vendorValues) && !(containsString(ty, EXCLUDE_FUJI) || containsString(product, EXCLUDE_FUJI) || containsString(usbMdl, EXCLUDE_FUJI));
-
+ return (containsVendor(product, vendorValues) || containsVendor(ty, vendorValues) ||
+ containsVendor(usbMfg, vendorValues) || containsVendor(mfg, vendorValues)) &&
+ !(containsString(ty, EXCLUDE_FUJI) || containsString(product, EXCLUDE_FUJI) ||
+ containsString(usbMdl, EXCLUDE_FUJI));
}
public static String getVendor(NsdServiceInfo networkDevice) {
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
index be3df54e12ae..c318275aafd0 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
@@ -614,6 +614,9 @@ public class PrintActivity extends Activity implements RemotePrintDocument.Updat
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
+
+ mMediaSizeComparator.onConfigurationChanged(newConfig);
+
if (mPrintPreviewController != null) {
mPrintPreviewController.onOrientationChanged();
}
diff --git a/packages/PrintSpooler/src/com/android/printspooler/util/MediaSizeUtils.java b/packages/PrintSpooler/src/com/android/printspooler/util/MediaSizeUtils.java
index 912ee1d09454..72893012ba19 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/util/MediaSizeUtils.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/util/MediaSizeUtils.java
@@ -16,13 +16,16 @@
package com.android.printspooler.util;
+import android.annotation.NonNull;
import android.content.Context;
+import android.content.pm.ActivityInfo;
+import android.content.res.Configuration;
import android.print.PrintAttributes.MediaSize;
-import android.util.ArrayMap;
import com.android.printspooler.R;
import java.util.Comparator;
+import java.util.HashMap;
import java.util.Map;
/**
@@ -30,7 +33,10 @@ import java.util.Map;
*/
public final class MediaSizeUtils {
- private static Map<MediaSize, String> sMediaSizeToStandardMap;
+ private static Map<MediaSize, Integer> sMediaSizeToStandardMap;
+
+ /** The media size standard for all media sizes no standard is defined for */
+ private static int sMediaSizeStandardIso;
private MediaSizeUtils() {
/* do nothing - hide constructor */
@@ -47,22 +53,32 @@ public final class MediaSizeUtils {
return MediaSize.getStandardMediaSizeById(mediaSizeId);
}
- private static String getStandardForMediaSize(Context context, MediaSize mediaSize) {
+ /**
+ * Get the standard the {@link MediaSize} belongs to.
+ *
+ * @param context The context of the caller
+ * @param mediaSize The {@link MediaSize} to be resolved
+ *
+ * @return The standard the {@link MediaSize} belongs to
+ */
+ private static int getStandardForMediaSize(Context context, MediaSize mediaSize) {
if (sMediaSizeToStandardMap == null) {
- sMediaSizeToStandardMap = new ArrayMap<MediaSize, String>();
+ sMediaSizeStandardIso = Integer.parseInt(context.getString(
+ R.string.mediasize_standard_iso));
+
+ sMediaSizeToStandardMap = new HashMap<>();
String[] mediaSizeToStandardMapValues = context.getResources()
.getStringArray(R.array.mediasize_to_standard_map);
final int mediaSizeToStandardCount = mediaSizeToStandardMapValues.length;
for (int i = 0; i < mediaSizeToStandardCount; i += 2) {
String mediaSizeId = mediaSizeToStandardMapValues[i];
MediaSize key = MediaSize.getStandardMediaSizeById(mediaSizeId);
- String value = mediaSizeToStandardMapValues[i + 1];
+ int value = Integer.parseInt(mediaSizeToStandardMapValues[i + 1]);
sMediaSizeToStandardMap.put(key, value);
}
}
- String standard = sMediaSizeToStandardMap.get(mediaSize);
- return (standard != null) ? standard : context.getString(
- R.string.mediasize_standard_iso);
+ Integer standard = sMediaSizeToStandardMap.get(mediaSize);
+ return (standard != null) ? standard : sMediaSizeStandardIso;
}
/**
@@ -73,32 +89,76 @@ public final class MediaSizeUtils {
public static final class MediaSizeComparator implements Comparator<MediaSize> {
private final Context mContext;
+ /** Current configuration */
+ private Configuration mCurrentConfig;
+
+ /** The standard to use for the current locale */
+ private int mCurrentStandard;
+
+ /** Mapping from media size to label */
+ private final @NonNull Map<MediaSize, String> mMediaSizeToLabel;
+
public MediaSizeComparator(Context context) {
mContext = context;
+ mMediaSizeToLabel = new HashMap<>();
+ mCurrentStandard = Integer.parseInt(mContext.getString(R.string.mediasize_standard));
+ }
+
+ /**
+ * Handle a configuration change by reloading all resources.
+ *
+ * @param newConfig The new configuration that will be applied.
+ */
+ public void onConfigurationChanged(@NonNull Configuration newConfig) {
+ if (mCurrentConfig == null ||
+ (newConfig.diff(mCurrentConfig) & ActivityInfo.CONFIG_LOCALE) != 0) {
+ mCurrentStandard = Integer
+ .parseInt(mContext.getString(R.string.mediasize_standard));
+ mMediaSizeToLabel.clear();
+
+ mCurrentConfig = newConfig;
+ }
+ }
+
+ /**
+ * Get the label for a {@link MediaSize}.
+ *
+ * @param context The context the label should be loaded for
+ * @param mediaSize The {@link MediaSize} to resolve
+ *
+ * @return The label for the media size
+ */
+ public @NonNull String getLabel(@NonNull Context context, @NonNull MediaSize mediaSize) {
+ String label = mMediaSizeToLabel.get(mediaSize);
+
+ if (label == null) {
+ label = mediaSize.getLabel(context.getPackageManager());
+ mMediaSizeToLabel.put(mediaSize, label);
+ }
+
+ return label;
}
@Override
public int compare(MediaSize lhs, MediaSize rhs) {
- String currentStandard = mContext.getString(R.string.mediasize_standard);
- String lhsStandard = getStandardForMediaSize(mContext, lhs);
- String rhsStandard = getStandardForMediaSize(mContext, rhs);
+ int lhsStandard = getStandardForMediaSize(mContext, lhs);
+ int rhsStandard = getStandardForMediaSize(mContext, rhs);
// The current standard always wins.
- if (lhsStandard.equals(currentStandard)) {
- if (!rhsStandard.equals(currentStandard)) {
+ if (lhsStandard == mCurrentStandard) {
+ if (rhsStandard != mCurrentStandard) {
return -1;
}
- } else if (rhsStandard.equals(currentStandard)) {
+ } else if (rhsStandard == mCurrentStandard) {
return 1;
}
- if (!lhsStandard.equals(rhsStandard)) {
+ if (lhsStandard != rhsStandard) {
// Different standards - use the standard ordering.
- return lhsStandard.compareTo(rhsStandard);
+ return Integer.valueOf(lhsStandard).compareTo(rhsStandard);
} else {
// Same standard - sort alphabetically by label.
- return lhs.getLabel(mContext.getPackageManager()).
- compareTo(rhs.getLabel(mContext.getPackageManager()));
+ return getLabel(mContext, lhs).compareTo(getLabel(mContext, rhs));
}
}
}
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 9c0aa35da9a4..2efefb3bc1aa 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -90,7 +90,7 @@
<uses-permission android:name="android.permission.WRITE_MEDIA_STORAGE" />
<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
- <uses-permission android:name="android.permission.MANAGE_USERS" />
+ <uses-permission android:name="android.permission.CREATE_USERS" />
<uses-permission android:name="android.permission.MANAGE_DEVICE_ADMINS" />
<uses-permission android:name="android.permission.BLUETOOTH_STACK" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 19d612daeb65..603d1e05b4e3 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -402,16 +402,16 @@
<string name="monitoring_title" msgid="169206259253048106">"Overvågning af netværk"</string>
<string name="disable_vpn" msgid="4435534311510272506">"Deaktiver VPN"</string>
<string name="disconnect_vpn" msgid="1324915059568548655">"Afbryd VPN-forbindelse"</string>
- <string name="monitoring_description_device_owned" msgid="5780988291898461883">"Din enhed administreres af <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nDin administrator kan overvåge og administrere indstillinger, virksomhedsadgang, apps, data, der er knyttet til din enhed, og din enheds placeringsoplysninger. Kontakt din administrator, hvis du vil have flere oplysninger."</string>
+ <string name="monitoring_description_device_owned" msgid="5780988291898461883">"Din enhed administreres af <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nDin administrator kan overvåge og administrere indstillinger, virksomhedsadgang, apps, data, der er knyttet til din enhed, og din enheds stedoplysninger. Kontakt din administrator, hvis du vil have flere oplysninger."</string>
<string name="monitoring_description_vpn" msgid="4445150119515393526">"Du gav en app tilladelse til at konfigurere en VPN-forbindelse.\n\nDenne app kan overvåge din enhed og netværksaktivitet, bl.a. e-mails, apps og websites."</string>
- <string name="monitoring_description_vpn_device_owned" msgid="3090670777499161246">"Din enhed administreres af <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nDin administrator kan overvåge og administrere indstillinger, virksomhedsadgang, apps, data, der er knyttet til din enhed, og din enheds placeringsoplysninger.\n\nDu har forbindelse til et VPN, som kan overvåge din netværksaktivitet, herunder e-mails, apps og websites.\n\nKontakt din administrator, hvis du vil have flere oplysninger."</string>
+ <string name="monitoring_description_vpn_device_owned" msgid="3090670777499161246">"Din enhed administreres af <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nDin administrator kan overvåge og administrere indstillinger, virksomhedsadgang, apps, data, der er knyttet til din enhed, og din enheds stedoplysninger.\n\nDu har forbindelse til et VPN, som kan overvåge din netværksaktivitet, herunder e-mails, apps og websites.\n\nKontakt din administrator, hvis du vil have flere oplysninger."</string>
<string name="monitoring_description_vpn_profile_owned" msgid="2054949132145039290">"Din arbejdsprofil administreres af <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nDin administrator kan overvåge din netværksaktivitet, bl.a. e-mails, apps og websites.\n\nKontakt din administrator for at få flere oplysninger.\n\nDu er også forbundet til en VPN-forbindelse, som kan overvåge din netværksaktivitet."</string>
<string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
<string name="monitoring_description_app" msgid="6259179342284742878">"Du har forbindelse til <xliff:g id="APPLICATION">%1$s</xliff:g>, som kan overvåge din netværksaktivitet, bl.a. e-mails, apps og websites."</string>
<string name="monitoring_description_app_personal" msgid="484599052118316268">"Du har forbindelse til <xliff:g id="APPLICATION">%1$s</xliff:g>, som kan overvåge din private netværksaktivitet, bl.a. e-mails, apps og websites."</string>
<string name="monitoring_description_app_work" msgid="1754325860918060897">"Din arbejdsprofil administreres af <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Den er forbundet til <xliff:g id="APPLICATION">%2$s</xliff:g>, som kan overvåge din arbejdsrelaterede netværksaktivitet, bl.a. e-mails, apps og websites.\n\nKontakt din administrator for at få flere oplysninger."</string>
<string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Din arbejdsprofil administreres af <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Den er forbundet til <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, som kan overvåge din arbejdsrelaterede netværksaktivitet, bl.a. e-mails, apps og websites.\n\nDu er også forbundet til <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, som kan overvåge din private netværksaktivitet."</string>
- <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Din enhed administreres af <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nDin administrator kan overvåge og administrere indstillinger, virksomhedens adgang, data tilknyttet din enhed og enhedens placeringsoplysninger.\n\nDu er forbundet til <xliff:g id="APPLICATION">%2$s</xliff:g>, som kan overvåge din netværksaktivitet, bl.a. e-mails, apps og websites.\n\nKontakt din administrator for at få flere oplysninger."</string>
+ <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Din enhed administreres af <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nDin administrator kan overvåge og administrere indstillinger, virksomhedens adgang, data tilknyttet din enhed og enhedens stedoplysninger.\n\nDu er forbundet til <xliff:g id="APPLICATION">%2$s</xliff:g>, som kan overvåge din netværksaktivitet, bl.a. e-mails, apps og websites.\n\nKontakt din administrator for at få flere oplysninger."</string>
<string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Enheden vil forblive låst, indtil du manuelt låser den op"</string>
<string name="hidden_notifications_title" msgid="7139628534207443290">"Modtag underretninger hurtigere"</string>
<string name="hidden_notifications_text" msgid="2326409389088668981">"Se dem, før du låser op"</string>
diff --git a/packages/SystemUI/res/values-hy-rAM/strings.xml b/packages/SystemUI/res/values-hy-rAM/strings.xml
index 01dcee2ad61f..5d01d15adce8 100644
--- a/packages/SystemUI/res/values-hy-rAM/strings.xml
+++ b/packages/SystemUI/res/values-hy-rAM/strings.xml
@@ -153,7 +153,7 @@
<string name="accessibility_cell_data_on" msgid="4310018593519761767">"Բջջային տվյալներն ակտիվ են"</string>
<string name="accessibility_cell_data_off" msgid="8000803571751407635">"Բջջային ցանցով տվյալների փոխանցումն անջատված է"</string>
<string name="accessibility_bluetooth_tether" msgid="4102784498140271969">"Bluetooth-ը կապվում է:"</string>
- <string name="accessibility_airplane_mode" msgid="834748999790763092">"Ինքնաթիռային ռեժիմ"</string>
+ <string name="accessibility_airplane_mode" msgid="834748999790763092">"Ինքնաթիռի ռեժիմ"</string>
<string name="accessibility_no_sims" msgid="3957997018324995781">"SIM քարտ չկա:"</string>
<string name="accessibility_carrier_network_change_mode" msgid="4017301580441304305">"Օպերատորի ցանցի փոփոխում:"</string>
<string name="accessibility_battery_details" msgid="7645516654955025422">"Բացել մարտկոցի տվյալները"</string>
@@ -189,10 +189,10 @@
<string name="accessibility_quick_settings_wifi_changed_on" msgid="6440117170789528622">"Wifi-ը միացավ:"</string>
<string name="accessibility_quick_settings_mobile" msgid="4876806564086241341">"Շարժական <xliff:g id="SIGNAL">%1$s</xliff:g>: <xliff:g id="TYPE">%2$s</xliff:g>: <xliff:g id="NETWORK">%3$s</xliff:g>:"</string>
<string name="accessibility_quick_settings_battery" msgid="1480931583381408972">"Մարտկոցը <xliff:g id="STATE">%s</xliff:g> է:"</string>
- <string name="accessibility_quick_settings_airplane_off" msgid="7786329360056634412">"Ինքնաթիռային ռեժիմն անջատված է:"</string>
- <string name="accessibility_quick_settings_airplane_on" msgid="6406141469157599296">"Ինքնաթիռային ռեժիմը միացված է:"</string>
- <string name="accessibility_quick_settings_airplane_changed_off" msgid="66846307818850664">"Ինքնաթիռային ռեժիմն անջատվեց:"</string>
- <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Ինքնաթիռային ռեժիմը միացավ:"</string>
+ <string name="accessibility_quick_settings_airplane_off" msgid="7786329360056634412">"Ինքնաթիռի ռեժիմն անջատված է:"</string>
+ <string name="accessibility_quick_settings_airplane_on" msgid="6406141469157599296">"Ինքնաթիռի ռեժիմը միացված է:"</string>
+ <string name="accessibility_quick_settings_airplane_changed_off" msgid="66846307818850664">"Ինքնաթիռի ռեժիմն անջատվեց:"</string>
+ <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Ինքնաթիռի ռեժիմը միացավ:"</string>
<string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"Չխանգարելու ընտրանքը միացված է: Ընդհատել միայն կարևոր ծանուցումների դեպքում:"</string>
<string name="accessibility_quick_settings_dnd_none_on" msgid="6882582132662613537">"Չանհանգստացնել՝ ընդհանուր լուռ վիճակը:"</string>
<string name="accessibility_quick_settings_dnd_alarms_on" msgid="9152834845587554157">"Չանհանգստացնել՝ միայն զարթուցիչ"</string>
@@ -451,7 +451,7 @@
<string name="status_bar_ethernet" msgid="5044290963549500128">"Ethernet"</string>
<string name="status_bar_alarm" msgid="8536256753575881818">"Զարթուցիչ"</string>
<string name="status_bar_work" msgid="6022553324802866373">"Android for Work-ի պրոֆիլ"</string>
- <string name="status_bar_airplane" msgid="7057575501472249002">"Ինքնաթիռային ռեժիմ"</string>
+ <string name="status_bar_airplane" msgid="7057575501472249002">"Ինքնաթիռի ռեժիմ"</string>
<string name="add_tile" msgid="2995389510240786221">"Սալիկի ավելացում"</string>
<string name="broadcast_tile" msgid="3894036511763289383">"Սալիկի հեռարձակում"</string>
<string name="zen_alarm_warning_indef" msgid="3482966345578319605">"Ժամը <xliff:g id="WHEN">%1$s</xliff:g>-ի զարթուցիչը չի զանգի, եթե մինչ այդ չանջատեք այս կարգավորումը"</string>
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java
index 51efbf06739f..932b4f56bf26 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java
@@ -127,7 +127,7 @@ public class QSFooter implements OnClickListener, DialogInterface.OnClickListene
public void onClick(DialogInterface dialog, int which) {
if (which == DialogInterface.BUTTON_NEGATIVE) {
final Intent settingsIntent = new Intent(ACTION_VPN_SETTINGS);
- mContext.startActivityAsUser(settingsIntent, UserHandle.CURRENT);
+ mHost.startActivityDismissingKeyguard(settingsIntent);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
index 8ec6a2f66e1a..777ed6a41c63 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
@@ -28,6 +28,8 @@ import android.os.AsyncTask;
import android.os.Handler;
import android.os.Looper;
import android.service.quicksettings.TileService;
+import android.widget.Button;
+
import com.android.systemui.R;
import com.android.systemui.qs.QSTile;
import com.android.systemui.qs.QSTile.DrawableIcon;
@@ -110,6 +112,8 @@ public class TileQueryHelper {
}
TileInfo info = new TileInfo();
info.state = state;
+ info.state.minimalAccessibilityClassName = info.state.expandedAccessibilityClassName =
+ Button.class.getName();
info.spec = spec;
info.appLabel = appLabel;
info.isSystem = isSystem;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskCardView.java b/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskCardView.java
index 72a589fe3c1a..e7575608b819 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskCardView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskCardView.java
@@ -56,6 +56,7 @@ public class TaskCardView extends LinearLayout {
private ImageView mBadgeView;
private Task mTask;
private boolean mDismissState;
+ private boolean mTouchExplorationEnabled;
private int mCornerRadius;
private ViewFocusAnimator mViewFocusAnimator;
@@ -90,7 +91,8 @@ public class TaskCardView extends LinearLayout {
R.dimen.recents_task_view_rounded_corners_radius);
mRecentsRowFocusAnimationHolder = new RecentsRowFocusAnimationHolder(this, mInfoFieldView);
SystemServicesProxy ssp = Recents.getSystemServices();
- if (!ssp.isTouchExplorationEnabled()) {
+ mTouchExplorationEnabled = ssp.isTouchExplorationEnabled();
+ if (!mTouchExplorationEnabled) {
mDismissIconView.setVisibility(VISIBLE);
} else {
mDismissIconView.setVisibility(GONE);
@@ -237,10 +239,15 @@ public class TaskCardView extends LinearLayout {
private void setDismissState(boolean dismissState) {
if (mDismissState != dismissState) {
mDismissState = dismissState;
- if (dismissState) {
- mDismissAnimationsHolder.startEnterAnimation();
- } else {
- mDismissAnimationsHolder.startExitAnimation();
+ // Check for touch exploration to ensure dismiss icon/text do not
+ // get animated. This should be removed based on decision from
+ // b/29208918
+ if (!mTouchExplorationEnabled) {
+ if (dismissState) {
+ mDismissAnimationsHolder.startEnterAnimation();
+ } else {
+ mDismissAnimationsHolder.startExitAnimation();
+ }
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java
index 41869dd5f417..e503c56437a4 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java
@@ -209,7 +209,9 @@ public class RecentsTransitionHelper {
EventBus.getDefault().send(new LaunchTaskSucceededEvent(taskIndexFromFront));
} else {
// Dismiss the task if we fail to launch it
- taskView.dismissTask();
+ if (taskView != null) {
+ taskView.dismissTask();
+ }
// Keep track of failed launches
EventBus.getDefault().send(new LaunchTaskFailedEvent());
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationMessagingTemplateViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationMessagingTemplateViewWrapper.java
new file mode 100644
index 000000000000..ff2febfa38f8
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationMessagingTemplateViewWrapper.java
@@ -0,0 +1,73 @@
+/*
+ * 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.systemui.statusbar.notification;
+
+import com.android.internal.widget.MessagingLinearLayout;
+import com.android.systemui.statusbar.ExpandableNotificationRow;
+import com.android.systemui.statusbar.TransformableView;
+
+import android.content.Context;
+import android.service.notification.StatusBarNotification;
+import android.view.View;
+
+/**
+ * Wraps a notification containing a messaging template
+ */
+public class NotificationMessagingTemplateViewWrapper extends NotificationTemplateViewWrapper {
+
+ private View mContractedMessage;
+
+ protected NotificationMessagingTemplateViewWrapper(Context ctx, View view,
+ ExpandableNotificationRow row) {
+ super(ctx, view, row);
+ }
+
+ private void resolveViews() {
+ mContractedMessage = null;
+
+ View container = mView.findViewById(com.android.internal.R.id.notification_messaging);
+ if (container instanceof MessagingLinearLayout
+ && ((MessagingLinearLayout) container).getChildCount() > 0) {
+ MessagingLinearLayout messagingContainer = (MessagingLinearLayout) container;
+
+ // Only consider the first child - transforming to a position other than the first
+ // looks bad because we have to move across other messages that are fading in.
+ View child = messagingContainer.getChildAt(0);
+ if (child.getId() == messagingContainer.getContractedChildId()) {
+ mContractedMessage = child;
+ }
+ }
+ }
+
+ @Override
+ public void notifyContentUpdated(StatusBarNotification notification) {
+ // Reinspect the notification. Before the super call, because the super call also updates
+ // the transformation types and we need to have our values set by then.
+ resolveViews();
+ super.notifyContentUpdated(notification);
+ }
+
+ @Override
+ protected void updateTransformedTypes() {
+ // This also clears the existing types
+ super.updateTransformedTypes();
+ if (mContractedMessage != null) {
+ mTransformationHelper.addTransformedView(TransformableView.TRANSFORMING_VIEW_TEXT,
+ mContractedMessage);
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java
index 22519e6e4de3..16348dfe5818 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java
@@ -50,6 +50,8 @@ public abstract class NotificationViewWrapper implements TransformableView {
return new NotificationBigTextTemplateViewWrapper(ctx, v, row);
} else if ("media".equals(v.getTag()) || "bigMediaNarrow".equals(v.getTag())) {
return new NotificationMediaTemplateViewWrapper(ctx, v, row);
+ } else if ("messaging".equals(v.getTag())) {
+ return new NotificationMessagingTemplateViewWrapper(ctx, v, row);
}
return new NotificationTemplateViewWrapper(ctx, v, row);
} else if (v instanceof NotificationHeaderView) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
index 6d0fbb15ca64..58fbd4c954d2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
@@ -80,14 +80,16 @@ public class AutoTileManager {
new NightModeController.Listener() {
@Override
public void onNightModeChanged() {
- mHost.addTile("night");
- Prefs.putBoolean(mContext, Key.QS_NIGHT_ADDED, true);
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- mHost.getNightModeController().removeListener(mNightModeListener);
- }
- });
+ if (mHost.getNightModeController().isEnabled()) {
+ mHost.addTile("night");
+ Prefs.putBoolean(mContext, Key.QS_NIGHT_ADDED, true);
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mHost.getNightModeController().removeListener(mNightModeListener);
+ }
+ });
+ }
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DateView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DateView.java
index 186005cc2162..a92422a66a22 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DateView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DateView.java
@@ -21,7 +21,8 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.TypedArray;
-import android.text.format.DateFormat;
+import android.icu.text.DateFormat;
+import android.icu.text.DisplayContext;
import android.util.AttributeSet;
import android.widget.TextView;
@@ -36,7 +37,7 @@ public class DateView extends TextView {
private final Date mCurrentTime = new Date();
- private SimpleDateFormat mDateFormat;
+ private DateFormat mDateFormat;
private String mLastText;
private String mDatePattern;
@@ -100,8 +101,9 @@ public class DateView extends TextView {
protected void updateClock() {
if (mDateFormat == null) {
final Locale l = Locale.getDefault();
- final String fmt = DateFormat.getBestDateTimePattern(l, mDatePattern);
- mDateFormat = new SimpleDateFormat(fmt, l);
+ DateFormat format = DateFormat.getInstanceForSkeleton(mDatePattern, l);
+ format.setContext(DisplayContext.CAPITALIZATION_FOR_STANDALONE);
+ mDateFormat = format;
}
mCurrentTime.setTime(System.currentTimeMillis());
diff --git a/rs/java/android/renderscript/RenderScript.java b/rs/java/android/renderscript/RenderScript.java
index 3d1370a52ae3..3333aa863cbc 100644
--- a/rs/java/android/renderscript/RenderScript.java
+++ b/rs/java/android/renderscript/RenderScript.java
@@ -752,20 +752,12 @@ public class RenderScript {
rsnScriptForEach(mContext, id, slot, ains, aout, params, limits);
}
- native void rsnScriptReduce(long con, long id, int slot, long ain,
+ native void rsnScriptReduce(long con, long id, int slot, long[] ains,
long aout, int[] limits);
- synchronized void nScriptReduce(long id, int slot, long ain, long aout,
+ synchronized void nScriptReduce(long id, int slot, long ains[], long aout,
int[] limits) {
validate();
- rsnScriptReduce(mContext, id, slot, ain, aout, limits);
- }
-
- native void rsnScriptReduceNew(long con, long id, int slot, long[] ains,
- long aout, int[] limits);
- synchronized void nScriptReduceNew(long id, int slot, long ains[], long aout,
- int[] limits) {
- validate();
- rsnScriptReduceNew(mContext, id, slot, ains, aout, limits);
+ rsnScriptReduce(mContext, id, slot, ains, aout, limits);
}
native void rsnScriptInvokeV(long con, long id, int slot, byte[] params);
diff --git a/rs/java/android/renderscript/Script.java b/rs/java/android/renderscript/Script.java
index fc3280be3ac7..13d5fcd57446 100644
--- a/rs/java/android/renderscript/Script.java
+++ b/rs/java/android/renderscript/Script.java
@@ -286,35 +286,6 @@ public class Script extends BaseObj {
}
/**
- * Only intended for use by generated reflected code. (Simple reduction)
- *
- * @hide
- */
- protected void reduce(int slot, Allocation ain, Allocation aout, LaunchOptions sc) {
- mRS.validate();
- mRS.validateObject(ain);
- mRS.validateObject(aout);
-
- if (ain == null || aout == null) {
- throw new RSIllegalArgumentException(
- "Both ain and aout are required to be non-null.");
- }
-
- long in_id = ain.getID(mRS);
- long out_id = aout.getID(mRS);
-
- int[] limits = null;
- if (sc != null) {
- limits = new int[2];
-
- limits[0] = sc.xstart;
- limits[1] = sc.xend;
- }
-
- mRS.nScriptReduce(getID(mRS), slot, in_id, out_id, limits);
- }
-
- /**
* Only intended for use by generated reflected code. (General reduction)
*
*/
@@ -350,7 +321,7 @@ public class Script extends BaseObj {
limits[5] = sc.zend;
}
- mRS.nScriptReduceNew(getID(mRS), slot, in_ids, out_id, limits);
+ mRS.nScriptReduce(getID(mRS), slot, in_ids, out_id, limits);
}
long[] mInIdsBuffer;
diff --git a/rs/jni/android_renderscript_RenderScript.cpp b/rs/jni/android_renderscript_RenderScript.cpp
index e0f5934cab74..aa2a607dc702 100644
--- a/rs/jni/android_renderscript_RenderScript.cpp
+++ b/rs/jni/android_renderscript_RenderScript.cpp
@@ -2094,67 +2094,10 @@ nScriptForEach(JNIEnv *_env, jobject _this, jlong con, jlong script, jint slot,
static void
nScriptReduce(JNIEnv *_env, jobject _this, jlong con, jlong script, jint slot,
- jlong ain, jlong aout, jintArray limits)
+ jlongArray ains, jlong aout, jintArray limits)
{
if (kLogApi) {
- ALOGD("nScriptReduce, con(%p), s(%p), slot(%i) ain(%" PRId64 ") aout(%" PRId64 ")", (RsContext)con, (void *)script, slot, ain, aout);
- }
-
- RsScriptCall sc, *sca = nullptr;
- uint32_t sc_size = 0;
-
- jint limit_len = 0;
- jint *limit_ptr = nullptr;
-
- // If the caller passed limits, reflect them in the RsScriptCall.
- if (limits != nullptr) {
- limit_len = _env->GetArrayLength(limits);
- limit_ptr = _env->GetIntArrayElements(limits, nullptr);
- if (limit_ptr == nullptr) {
- ALOGE("Failed to get Java array elements");
- return;
- }
-
- // We expect to be passed an array [x1, x2] which specifies
- // the sub-range for a 1-dimensional reduction.
- assert(limit_len == 2);
- UNUSED(limit_len); // As the assert might not be compiled.
-
- sc.xStart = limit_ptr[0];
- sc.xEnd = limit_ptr[1];
- sc.yStart = 0;
- sc.yEnd = 0;
- sc.zStart = 0;
- sc.zEnd = 0;
- sc.strategy = RS_FOR_EACH_STRATEGY_DONT_CARE;
- sc.arrayStart = 0;
- sc.arrayEnd = 0;
- sc.array2Start = 0;
- sc.array2End = 0;
- sc.array3Start = 0;
- sc.array3End = 0;
- sc.array4Start = 0;
- sc.array4End = 0;
-
- sca = &sc;
- sc_size = sizeof(sc);
- }
-
- rsScriptReduce((RsContext)con, (RsScript)script, slot,
- (RsAllocation)ain, (RsAllocation)aout,
- sca, sc_size);
-
- if (limits != nullptr) {
- _env->ReleaseIntArrayElements(limits, limit_ptr, JNI_ABORT);
- }
-}
-
-static void
-nScriptReduceNew(JNIEnv *_env, jobject _this, jlong con, jlong script, jint slot,
- jlongArray ains, jlong aout, jintArray limits)
-{
- if (kLogApi) {
- ALOGD("nScriptReduceNew, con(%p), s(%p), slot(%i) ains(%p) aout(%" PRId64 ")", (RsContext)con, (void *)script, slot, ains, aout);
+ ALOGD("nScriptReduce, con(%p), s(%p), slot(%i) ains(%p) aout(%" PRId64 ")", (RsContext)con, (void *)script, slot, ains, aout);
}
if (ains == nullptr) {
@@ -2233,9 +2176,9 @@ nScriptReduceNew(JNIEnv *_env, jobject _this, jlong con, jlong script, jint slot
sc_size = sizeof(sc);
}
- rsScriptReduceNew((RsContext)con, (RsScript)script, slot,
- in_allocs, in_len, (RsAllocation)aout,
- sca, sc_size);
+ rsScriptReduce((RsContext)con, (RsScript)script, slot,
+ in_allocs, in_len, (RsAllocation)aout,
+ sca, sc_size);
_env->ReleaseLongArrayElements(ains, in_ptr, JNI_ABORT);
@@ -2951,8 +2894,7 @@ static const JNINativeMethod methods[] = {
{"rsnScriptInvokeV", "(JJI[B)V", (void*)nScriptInvokeV },
{"rsnScriptForEach", "(JJI[JJ[B[I)V", (void*)nScriptForEach },
-{"rsnScriptReduce", "(JJIJJ[I)V", (void*)nScriptReduce },
-{"rsnScriptReduceNew", "(JJI[JJ[I)V", (void*)nScriptReduceNew },
+{"rsnScriptReduce", "(JJI[JJ[I)V", (void*)nScriptReduce },
{"rsnScriptSetVarI", "(JJII)V", (void*)nScriptSetVarI },
{"rsnScriptGetVarI", "(JJI)I", (void*)nScriptGetVarI },
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index acc2ec30d67f..334b228a4ab7 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -9849,7 +9849,11 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF
synchronized(this) {
if (mActiveRestoreSession != null) {
- Slog.d(TAG, "Restore session requested but one already active");
+ Slog.i(TAG, "Restore session requested but one already active");
+ return null;
+ }
+ if (mBackupRunning) {
+ Slog.i(TAG, "Restore session requested but currently running backups");
return null;
}
mActiveRestoreSession = new ActiveRestoreSession(packageName, transport);
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index 3eadb5ca7316..9154b8eced4a 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -222,7 +222,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
} catch (RemoteException e) {
Slog.e(TAG,"Unable to call onBrEdrDown", e);
} finally {
- mBluetoothLock.readLock().lock();
+ mBluetoothLock.readLock().unlock();
}
} else if (st == BluetoothAdapter.STATE_ON){
// disable without persisting the setting
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index acf8009e34a6..41d8b4fffb1c 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -3552,14 +3552,14 @@ public class ConnectivityService extends IConnectivityManager.Stub
.build();
try {
- notificationManager.notify(NOTIFICATION_ID, id, notification);
+ notificationManager.notifyAsUser(NOTIFICATION_ID, id, notification, UserHandle.ALL);
} catch (NullPointerException npe) {
loge("setNotificationVisible: visible notificationManager npe=" + npe);
npe.printStackTrace();
}
} else {
try {
- notificationManager.cancel(NOTIFICATION_ID, id);
+ notificationManager.cancelAsUser(NOTIFICATION_ID, id, UserHandle.ALL);
} catch (NullPointerException npe) {
loge("setNotificationVisible: cancel notificationManager npe=" + npe);
npe.printStackTrace();
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index e0b49603ac4f..36ec2eb9a192 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -1431,6 +1431,13 @@ public class LocationManagerService extends ILocationManager.Stub {
for (UpdateRecord record : records) {
if (isCurrentProfile(UserHandle.getUserId(record.mReceiver.mUid))) {
LocationRequest locationRequest = record.mRequest;
+
+ // Don't assign battery blame for update records whose
+ // client has no permission to receive location data.
+ if (!providerRequest.locationRequests.contains(locationRequest)) {
+ continue;
+ }
+
if (locationRequest.getInterval() <= thresholdInterval) {
if (record.mReceiver.mWorkSource != null
&& record.mReceiver.mWorkSource.size() > 0
diff --git a/services/core/java/com/android/server/MountService.java b/services/core/java/com/android/server/MountService.java
index c89b6ea4f18d..9c75a009d7af 100644
--- a/services/core/java/com/android/server/MountService.java
+++ b/services/core/java/com/android/server/MountService.java
@@ -3031,7 +3031,8 @@ class MountService extends IMountService.Stub
if (forWrite) {
match = vol.isVisibleForWrite(userId);
} else {
- match = vol.isVisibleForRead(userId) || includeInvisible;
+ match = vol.isVisibleForRead(userId)
+ || (includeInvisible && vol.getPath() != null);
}
if (!match) continue;
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 2d6b5ef8b607..897aa203a548 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -5375,17 +5375,18 @@ public final class ActivityManagerService extends ActivityManagerNative
userId = mUserController.handleIncomingUser(pid, uid, userId, false,
ALLOW_FULL_ONLY, "clearApplicationUserData", null);
- final DevicePolicyManagerInternal dpmi = LocalServices
- .getService(DevicePolicyManagerInternal.class);
- if (dpmi != null && dpmi.hasDeviceOwnerOrProfileOwner(packageName, userId)) {
- throw new SecurityException("Cannot clear data for a device owner or a profile owner");
- }
long callingId = Binder.clearCallingIdentity();
try {
IPackageManager pm = AppGlobals.getPackageManager();
int pkgUid = -1;
synchronized(this) {
+ if (getPackageManagerInternalLocked().canPackageBeWiped(
+ userId, packageName)) {
+ throw new SecurityException(
+ "Cannot clear data for a device owner or a profile owner");
+ }
+
try {
pkgUid = pm.getPackageUid(packageName, MATCH_UNINSTALLED_PACKAGES, userId);
} catch (RemoteException e) {
@@ -6036,7 +6037,7 @@ public final class ActivityManagerService extends ActivityManagerNative
if (appId < 0 && packageName != null) {
try {
appId = UserHandle.getAppId(AppGlobals.getPackageManager()
- .getPackageUid(packageName, MATCH_DEBUG_TRIAGED_MISSING, userId));
+ .getPackageUid(packageName, MATCH_DEBUG_TRIAGED_MISSING, 0));
} catch (RemoteException e) {
}
}
@@ -13881,7 +13882,12 @@ public final class ActivityManagerService extends ActivityManagerNative
args.length - opti);
}
synchronized (this) {
- dumpBroadcastStatsLocked(fd, pw, args, opti, true, dumpPackage);
+ if (dumpCheckinFormat) {
+ dumpBroadcastStatsCheckinLocked(fd, pw, args, opti, dumpCheckin,
+ dumpPackage);
+ } else {
+ dumpBroadcastStatsLocked(fd, pw, args, opti, true, dumpPackage);
+ }
}
} else if ("intents".equals(cmd) || "i".equals(cmd)) {
String[] newArgs;
@@ -17778,6 +17784,11 @@ public final class ActivityManagerService extends ActivityManagerNative
getPackageManagerInternalLocked().getApplicationInfo(
ssp,
userId);
+ if (aInfo == null) {
+ Slog.w(TAG, "Dropping ACTION_PACKAGE_REPLACED for non-existent pkg:"
+ + " ssp=" + ssp + " data=" + data);
+ return ActivityManager.BROADCAST_SUCCESS;
+ }
mStackSupervisor.updateActivityApplicationInfoLocked(aInfo);
sendPackageBroadcastLocked(IApplicationThread.PACKAGE_REPLACED,
new String[] {ssp}, userId);
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index d83a750ccbb3..df85cfa939e3 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -2581,11 +2581,14 @@ final class ActivityStack {
}
private void insertTaskAtTop(TaskRecord task, ActivityRecord newActivity) {
+ boolean isLastTaskOverHome = false;
// If the moving task is over home stack, transfer its return type to next task
if (task.isOverHomeStack()) {
final TaskRecord nextTask = getNextTask(task);
if (nextTask != null) {
nextTask.setTaskToReturnTo(task.getTaskToReturnTo());
+ } else {
+ isLastTaskOverHome = true;
}
}
@@ -2595,7 +2598,10 @@ final class ActivityStack {
ActivityStack lastStack = mStackSupervisor.getLastStack();
final boolean fromHome = lastStack.isHomeStack();
if (!isHomeStack() && (fromHome || topTask() != task)) {
- int returnToType = APPLICATION_ACTIVITY_TYPE;
+ // If it's a last task over home - we default to keep its return to type not to
+ // make underlying task focused when this one will be finished.
+ int returnToType = isLastTaskOverHome
+ ? task.getTaskToReturnTo() : APPLICATION_ACTIVITY_TYPE;
if (fromHome && StackId.allowTopTaskToReturnHome(mStackId)) {
returnToType = lastStack.topTask() == null
? HOME_ACTIVITY_TYPE : lastStack.topTask().taskType;
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 0e4c9a4d9773..52c002d4cc5a 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -1097,21 +1097,7 @@ public final class ActivityStackSupervisor implements DisplayListener {
// Don't debug things in the system process
if (!aInfo.processName.equals("system")) {
if ((startFlags & ActivityManager.START_FLAG_DEBUG) != 0) {
- final ProcessRecord app = mService.getProcessRecordLocked(
- aInfo.processName, aInfo.applicationInfo.uid, true);
- // If the process already started, we can't wait for debugger and shouldn't
- // modify the debug settings.
- // For non-persistent debug, normally we set the debug app here, and restores
- // to the original at attachApplication time. However, if the app process
- // already exists, we won't get another attachApplication, and the debug setting
- // never gets restored. Furthermore, if we get two such calls back-to-back,
- // both mOrigDebugApp and mDebugApp will become the same app, and it won't be
- // cleared even if we get attachApplication after the app process is killed.
- if (app == null || app.thread == null) {
- mService.setDebugApp(aInfo.processName, true, false);
- } else {
- Slog.w(TAG, "Ignoring waitForDebugger because process already exists");
- }
+ mService.setDebugApp(aInfo.processName, true, false);
}
if ((startFlags & ActivityManager.START_FLAG_NATIVE_DEBUGGING) != 0) {
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index 61b131761b15..522e42bda94b 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -166,8 +166,9 @@ class ActivityStarter {
private Intent mNewTaskIntent;
private ActivityStack mSourceStack;
private ActivityStack mTargetStack;
- // TODO: Is the mMoveHome flag really needed?
- private boolean mMovedHome;
+ // Indicates that we moved other task and are going to put something on top soon, so
+ // we don't want to show it redundantly or accidentally change what's shown below.
+ private boolean mMovedOtherTask;
private boolean mMovedToFront;
private boolean mNoAnimation;
private boolean mKeepCurTransition;
@@ -204,7 +205,7 @@ class ActivityStarter {
mSourceStack = null;
mTargetStack = null;
- mMovedHome = false;
+ mMovedOtherTask = false;
mMovedToFront = false;
mNoAnimation = false;
mKeepCurTransition = false;
@@ -1013,7 +1014,6 @@ class ActivityStarter {
resumeTargetStackIfNeeded();
return START_RETURN_INTENT_TO_CALLER;
}
-
setTaskFromIntentActivity(mReusedActivity);
if (!mAddingToTask && mReuseTask == null) {
@@ -1082,7 +1082,7 @@ class ActivityStarter {
Slog.e(TAG, "Attempted Lock Task Mode violation mStartActivity=" + mStartActivity);
return START_RETURN_LOCK_TASK_MODE_VIOLATION;
}
- if (!mMovedHome) {
+ if (!mMovedOtherTask) {
updateTaskReturnToType(mStartActivity.task, mLaunchFlags, topStack);
}
} else if (mSourceRecord != null) {
@@ -1443,7 +1443,7 @@ class ActivityStarter {
if (mLaunchTaskBehind && mSourceRecord != null) {
intentActivity.setTaskToAffiliateWith(mSourceRecord.task);
}
- mMovedHome = true;
+ mMovedOtherTask = true;
// If the launch flags carry both NEW_TASK and CLEAR_TASK, the task's activities
// will be cleared soon by ActivityStarter in setTaskFromIntentActivity().
@@ -1521,6 +1521,10 @@ class ActivityStarter {
mReuseTask = intentActivity.task;
mReuseTask.performClearTaskLocked();
mReuseTask.setIntent(mStartActivity);
+ // When we clear the task - focus will be adjusted, which will bring another task
+ // to top before we launch the activity we need. This will temporary swap their
+ // mTaskToReturnTo values and we don't want to overwrite them accidentally.
+ mMovedOtherTask = true;
} else if ((mLaunchFlags & FLAG_ACTIVITY_CLEAR_TOP) != 0
|| mLaunchSingleInstance || mLaunchSingleTask) {
ActivityRecord top = intentActivity.task.performClearTaskLocked(mStartActivity,
diff --git a/services/core/java/com/android/server/am/RecentTasks.java b/services/core/java/com/android/server/am/RecentTasks.java
index cea76f236fc9..ab5d4b650748 100644
--- a/services/core/java/com/android/server/am/RecentTasks.java
+++ b/services/core/java/com/android/server/am/RecentTasks.java
@@ -621,6 +621,9 @@ class RecentTasks extends ArrayList<TaskRecord> {
for (int i = 0; i < recentsCount; i++) {
final TaskRecord tr = get(i);
if (task != tr) {
+ if (task.stack != tr.stack) {
+ continue;
+ }
if (task.userId != tr.userId) {
continue;
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 87141b4cfced..f2fde0f91e40 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -102,11 +102,11 @@ import static com.android.server.pm.PermissionsState.PERMISSION_OPERATION_SUCCES
import android.Manifest;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.UserIdInt;
import android.app.ActivityManager;
import android.app.ActivityManagerNative;
import android.app.IActivityManager;
import android.app.ResourcesManager;
-import android.app.admin.DevicePolicyManagerInternal;
import android.app.admin.IDevicePolicyManager;
import android.app.admin.SecurityLog;
import android.app.backup.IBackupManager;
@@ -622,6 +622,8 @@ public class PackageManagerService extends IPackageManager.Stub {
@GuardedBy("mPackages")
final ArraySet<String> mFrozenPackages = new ArraySet<>();
+ final ProtectedPackages mProtectedPackages = new ProtectedPackages();
+
boolean mRestoredSettings;
// System configuration read by SystemConfig.
@@ -16338,8 +16340,9 @@ public class PackageManagerService extends IPackageManager.Stub {
for (int curUser : users) {
long timeout = SystemClock.uptimeMillis() + 5000;
synchronized (conn) {
- long now = SystemClock.uptimeMillis();
- while (conn.mContainerService == null && now < timeout) {
+ long now;
+ while (conn.mContainerService == null &&
+ (now = SystemClock.uptimeMillis()) < timeout) {
try {
conn.wait(timeout - now);
} catch (InterruptedException e) {
@@ -16393,9 +16396,7 @@ public class PackageManagerService extends IPackageManager.Stub {
enforceCrossUserPermission(Binder.getCallingUid(), userId,
true /* requireFullPermission */, false /* checkShell */, "clear application data");
- final DevicePolicyManagerInternal dpmi = LocalServices
- .getService(DevicePolicyManagerInternal.class);
- if (dpmi != null && dpmi.hasDeviceOwnerOrProfileOwner(packageName, userId)) {
+ if (mProtectedPackages.canPackageBeWiped(userId, packageName)) {
throw new SecurityException("Cannot clear data for a device owner or a profile owner");
}
// Queue up an async operation since the package deletion may take a little while.
@@ -17722,10 +17723,8 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
+ Binder.getCallingPid()
+ ", uid=" + uid + ", package uid=" + pkgSetting.appId);
}
- // Don't allow changing profile and device owners. Calling into DPMS, so no locking.
- final DevicePolicyManagerInternal dpmi = LocalServices
- .getService(DevicePolicyManagerInternal.class);
- if (dpmi != null && dpmi.hasDeviceOwnerOrProfileOwner(packageName, userId)) {
+ // Don't allow changing profile and device owners.
+ if (mProtectedPackages.canPackageStateBeChanged(userId, packageName)) {
throw new SecurityException("Cannot disable a device owner or a profile owner");
}
}
@@ -20822,6 +20821,20 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
int userId) {
return PackageManagerService.this.getHomeActivitiesAsUser(allHomeCandidates, userId);
}
+
+ @Override
+ public void setDeviceAndProfileOwnerPackages(
+ int deviceOwnerUserId, String deviceOwnerPackage,
+ SparseArray<String> profileOwnerPackages) {
+ mProtectedPackages.setDeviceAndProfileOwnerPackages(
+ deviceOwnerUserId, deviceOwnerPackage, profileOwnerPackages);
+ }
+
+ @Override
+ public boolean canPackageBeWiped(int userId, String packageName) {
+ return mProtectedPackages.canPackageBeWiped(userId,
+ packageName);
+ }
}
@Override
diff --git a/services/core/java/com/android/server/pm/ProtectedPackages.java b/services/core/java/com/android/server/pm/ProtectedPackages.java
new file mode 100644
index 000000000000..7bdea181473e
--- /dev/null
+++ b/services/core/java/com/android/server/pm/ProtectedPackages.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.server.pm;
+
+import android.annotation.UserIdInt;
+import android.os.UserHandle;
+import android.util.SparseArray;
+
+/**
+ * Manages package names that need special protection.
+ *
+ * TODO: This class should persist the information by itself, and also keeps track of device admin
+ * packages for all users. Then PMS.isPackageDeviceAdmin() should use it instead of talking
+ * to DPMS.
+ */
+public class ProtectedPackages {
+ @UserIdInt
+ private int mDeviceOwnerUserId;
+
+ private String mDeviceOwnerPackage;
+
+ private SparseArray<String> mProfileOwnerPackages;
+
+ private final Object mLock = new Object();
+
+ /**
+ * Sets the device/profile owner information.
+ */
+ public void setDeviceAndProfileOwnerPackages(
+ int deviceOwnerUserId, String deviceOwnerPackage,
+ SparseArray<String> profileOwnerPackages) {
+ synchronized (mLock) {
+ mDeviceOwnerUserId = deviceOwnerUserId;
+ mDeviceOwnerPackage =
+ (deviceOwnerUserId == UserHandle.USER_NULL) ? null : deviceOwnerPackage;
+ mProfileOwnerPackages = (profileOwnerPackages == null) ? null
+ : profileOwnerPackages.clone();
+ }
+ }
+
+ private boolean hasDeviceOwnerOrProfileOwner(int userId, String packageName) {
+ if (packageName == null) {
+ return false;
+ }
+ synchronized (mLock) {
+ if (mDeviceOwnerPackage != null) {
+ if ((mDeviceOwnerUserId == userId)
+ && (packageName.equals(mDeviceOwnerPackage))) {
+ return true;
+ }
+ }
+ if (mProfileOwnerPackages != null) {
+ if (packageName.equals(mProfileOwnerPackages.get(userId))) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Whether a package or the components in a package's enabled state can be changed
+ * by other callers than itself.
+ */
+ public boolean canPackageStateBeChanged(@UserIdInt int userId, String packageName) {
+ return hasDeviceOwnerOrProfileOwner(userId, packageName);
+ }
+
+ /**
+ * Whether a package's data be cleared.
+ */
+ public boolean canPackageBeWiped(@UserIdInt int userId, String packageName) {
+ return hasDeviceOwnerOrProfileOwner(userId, packageName);
+ }
+}
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index b9167905612d..dd34ebcf690e 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -30,6 +30,7 @@ import android.app.ActivityManagerNative;
import android.app.IActivityManager;
import android.app.IStopUserCallback;
import android.app.KeyguardManager;
+import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -167,6 +168,12 @@ public class UserManagerService extends IUserManager.Stub {
private static final String RESTRICTIONS_FILE_PREFIX = "res_";
private static final String XML_SUFFIX = ".xml";
+ private static final int ALLOWED_FLAGS_FOR_CREATE_USERS_PERMISSION =
+ UserInfo.FLAG_MANAGED_PROFILE
+ | UserInfo.FLAG_EPHEMERAL
+ | UserInfo.FLAG_RESTRICTED
+ | UserInfo.FLAG_GUEST;
+
private static final int MIN_USER_ID = 10;
// We need to keep process uid within Integer.MAX_VALUE.
private static final int MAX_USER_ID = Integer.MAX_VALUE / UserHandle.PER_USER_RANGE;
@@ -322,6 +329,27 @@ public class UserManagerService extends IUserManager.Stub {
private final LockPatternUtils mLockPatternUtils;
+ private final String ACTION_DISABLE_QUIET_MODE_AFTER_UNLOCK =
+ "com.android.server.pm.DISABLE_QUIET_MODE_AFTER_UNLOCK";
+
+ private final BroadcastReceiver mDisableQuietModeCallback = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (ACTION_DISABLE_QUIET_MODE_AFTER_UNLOCK.equals(intent.getAction())) {
+ final IntentSender target = intent.getParcelableExtra(Intent.EXTRA_INTENT);
+ final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_ID, 0);
+ setQuietModeEnabled(userHandle, false);
+ if (target != null) {
+ try {
+ mContext.startIntentSender(target, null, 0, 0, 0);
+ } catch (IntentSender.SendIntentException e) {
+ /* ignore */
+ }
+ }
+ }
+ }
+ };
+
/**
* Whether all users should be created ephemeral.
*/
@@ -414,6 +442,9 @@ public class UserManagerService extends IUserManager.Stub {
// user restriction was not a default guest restriction.
setUserRestriction(UserManager.DISALLOW_CONFIG_WIFI, true, currentGuestUser.id);
}
+ mContext.registerReceiver(mDisableQuietModeCallback,
+ new IntentFilter(ACTION_DISABLE_QUIET_MODE_AFTER_UNLOCK),
+ null, mHandler);
}
@Override
@@ -465,7 +496,7 @@ public class UserManagerService extends IUserManager.Stub {
@Override
public @NonNull List<UserInfo> getUsers(boolean excludeDying) {
- checkManageUsersPermission("query users");
+ checkManageOrCreateUsersPermission("query users");
synchronized (mUsersLock) {
ArrayList<UserInfo> users = new ArrayList<UserInfo>(mUsers.size());
final int userSize = mUsers.size();
@@ -703,6 +734,7 @@ public class UserManagerService extends IUserManager.Stub {
@Override
public boolean trySetQuietModeDisabled(int userHandle, IntentSender target) {
+ checkManageUsersPermission("silence profile");
if (StorageManager.isUserKeyUnlocked(userHandle)
|| !mLockPatternUtils.isSecure(userHandle)) {
// if the user is already unlocked, no need to show a profile challenge
@@ -723,9 +755,24 @@ public class UserManagerService extends IUserManager.Stub {
if (unlockIntent == null) {
return false;
}
+ final Intent callBackIntent = new Intent(
+ ACTION_DISABLE_QUIET_MODE_AFTER_UNLOCK);
if (target != null) {
- unlockIntent.putExtra(Intent.EXTRA_INTENT, target);
- }
+ callBackIntent.putExtra(Intent.EXTRA_INTENT, target);
+ }
+ callBackIntent.putExtra(Intent.EXTRA_USER_ID, userHandle);
+ callBackIntent.setPackage(mContext.getPackageName());
+ callBackIntent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+ final PendingIntent pendingIntent = PendingIntent.getBroadcast(
+ mContext,
+ 0,
+ callBackIntent,
+ PendingIntent.FLAG_CANCEL_CURRENT |
+ PendingIntent.FLAG_ONE_SHOT |
+ PendingIntent.FLAG_IMMUTABLE);
+ // After unlocking the challenge, it will disable quiet mode and run the original
+ // intentSender
+ unlockIntent.putExtra(Intent.EXTRA_INTENT, pendingIntent.getIntentSender());
unlockIntent.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
mContext.startActivity(unlockIntent);
} finally {
@@ -1407,6 +1454,41 @@ public class UserManagerService extends IUserManager.Stub {
}
/**
+ * Enforces that only the system UID or root's UID or apps that have the
+ * {@link android.Manifest.permission#MANAGE_USERS MANAGE_USERS} or
+ * {@link android.Manifest.permission#CREATE_USERS CREATE_USERS}
+ * can make certain calls to the UserManager.
+ *
+ * @param message used as message if SecurityException is thrown
+ * @throws SecurityException if the caller is not system or root
+ * @see #hasManageOrCreateUsersPermission()
+ */
+ private static final void checkManageOrCreateUsersPermission(String message) {
+ if (!hasManageOrCreateUsersPermission()) {
+ throw new SecurityException(
+ "You either need MANAGE_USERS or CREATE_USERS permission to: " + message);
+ }
+ }
+
+ /**
+ * Similar to {@link #checkManageOrCreateUsersPermission(String)} but when the caller is tries
+ * to create user/profiles other than what is allowed for
+ * {@link android.Manifest.permission#CREATE_USERS CREATE_USERS} permission, then it will only
+ * allow callers with {@link android.Manifest.permission#MANAGE_USERS MANAGE_USERS} permission.
+ */
+ private static final void checkManageOrCreateUsersPermission(int creationFlags) {
+ if ((creationFlags & ~ALLOWED_FLAGS_FOR_CREATE_USERS_PERMISSION) == 0) {
+ if (!hasManageOrCreateUsersPermission()) {
+ throw new SecurityException("You either need MANAGE_USERS or CREATE_USERS "
+ + "permission to create an user with flags: " + creationFlags);
+ }
+ } else if (!hasManageUsersPermission()) {
+ throw new SecurityException("You need MANAGE_USERS permission to create an user "
+ + " with flags: " + creationFlags);
+ }
+ }
+
+ /**
* @return whether the calling UID is system UID or root's UID or the calling app has the
* {@link android.Manifest.permission#MANAGE_USERS MANAGE_USERS}.
*/
@@ -1420,6 +1502,23 @@ public class UserManagerService extends IUserManager.Stub {
}
/**
+ * @return whether the calling UID is system UID or root's UID or the calling app has the
+ * {@link android.Manifest.permission#MANAGE_USERS MANAGE_USERS} or
+ * {@link android.Manifest.permission#CREATE_USERS CREATE_USERS}.
+ */
+ private static final boolean hasManageOrCreateUsersPermission() {
+ final int callingUid = Binder.getCallingUid();
+ return UserHandle.isSameApp(callingUid, Process.SYSTEM_UID)
+ || callingUid == Process.ROOT_UID
+ || ActivityManager.checkComponentPermission(
+ android.Manifest.permission.MANAGE_USERS,
+ callingUid, -1, true) == PackageManager.PERMISSION_GRANTED
+ || ActivityManager.checkComponentPermission(
+ android.Manifest.permission.CREATE_USERS,
+ callingUid, -1, true) == PackageManager.PERMISSION_GRANTED;
+ }
+
+ /**
* Enforces that only the system UID or root's UID (on any user) can make certain calls to the
* UserManager.
*
@@ -2005,13 +2104,13 @@ public class UserManagerService extends IUserManager.Stub {
@Override
public UserInfo createProfileForUser(String name, int flags, int userId) {
- checkManageUsersPermission("Only the system can create users");
+ checkManageOrCreateUsersPermission(flags);
return createUserInternal(name, flags, userId);
}
@Override
public UserInfo createUser(String name, int flags) {
- checkManageUsersPermission("Only the system can create users");
+ checkManageOrCreateUsersPermission(flags);
return createUserInternal(name, flags, UserHandle.USER_NULL);
}
@@ -2255,7 +2354,7 @@ public class UserManagerService extends IUserManager.Stub {
*/
@Override
public boolean removeUser(int userHandle) {
- checkManageUsersPermission("Only the system can remove users");
+ checkManageOrCreateUsersPermission("Only the system can remove users");
if (getUserRestrictions(UserHandle.getCallingUserId()).getBoolean(
UserManager.DISALLOW_REMOVE_USER, false)) {
Log.w(LOG_TAG, "Cannot remove user. DISALLOW_REMOVE_USER is enabled.");
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 698774441cca..568f94c9684f 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -2589,8 +2589,13 @@ public class PhoneWindowManager implements WindowManagerPolicy {
final PhoneWindow win = new PhoneWindow(context);
win.setIsStartingWindow(true);
- final Resources r = context.getResources();
- win.setTitle(r.getText(labelRes, nonLocalizedLabel));
+ CharSequence label = context.getResources().getText(labelRes, null);
+ // Only change the accessibility title if the label is localized
+ if (label != null) {
+ win.setTitle(label, true);
+ } else {
+ win.setTitle(nonLocalizedLabel, false);
+ }
win.setType(
WindowManager.LayoutParams.TYPE_APPLICATION_STARTING);
diff --git a/services/core/java/com/android/server/vr/VrManagerService.java b/services/core/java/com/android/server/vr/VrManagerService.java
index 3700c71e1da7..b4c4bd8daa76 100644
--- a/services/core/java/com/android/server/vr/VrManagerService.java
+++ b/services/core/java/com/android/server/vr/VrManagerService.java
@@ -46,11 +46,12 @@ import android.service.vr.IVrListener;
import android.service.vr.IVrManager;
import android.service.vr.IVrStateCallbacks;
import android.service.vr.VrListenerService;
+import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Slog;
import android.util.SparseArray;
-
import com.android.internal.R;
+import com.android.server.LocalServices;
import com.android.server.SystemConfig;
import com.android.server.SystemService;
import com.android.server.utils.ManagedApplicationService.PendingEvent;
@@ -67,6 +68,7 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;
+import java.util.Map;
import java.util.Objects;
/**
@@ -197,29 +199,44 @@ public class VrManagerService extends SystemService implements EnabledComponentC
private final class NotificationAccessManager {
private final SparseArray<ArraySet<String>> mAllowedPackages = new SparseArray<>();
+ private final ArrayMap<String, Integer> mNotificationAccessPackageToUserId =
+ new ArrayMap<>();
public void update(Collection<String> packageNames) {
int currentUserId = ActivityManager.getCurrentUser();
- UserHandle currentUserHandle = new UserHandle(currentUserId);
-
ArraySet<String> allowed = mAllowedPackages.get(currentUserId);
if (allowed == null) {
allowed = new ArraySet<>();
}
+ // Make sure we revoke notification access for listeners in other users
+ final int listenerCount = mNotificationAccessPackageToUserId.size();
+ for (int i = listenerCount - 1; i >= 0; i--) {
+ final int grantUserId = mNotificationAccessPackageToUserId.valueAt(i);
+ if (grantUserId != currentUserId) {
+ String packageName = mNotificationAccessPackageToUserId.keyAt(i);
+ revokeNotificationListenerAccess(packageName, grantUserId);
+ revokeNotificationPolicyAccess(packageName);
+ revokeCoarseLocationPermissionIfNeeded(packageName, grantUserId);
+ mNotificationAccessPackageToUserId.removeAt(i);
+ }
+ }
+
for (String pkg : allowed) {
if (!packageNames.contains(pkg)) {
- revokeNotificationListenerAccess(pkg);
+ revokeNotificationListenerAccess(pkg, currentUserId);
revokeNotificationPolicyAccess(pkg);
- revokeCoarseLocationAccess(pkg, currentUserHandle);
+ revokeCoarseLocationPermissionIfNeeded(pkg, currentUserId);
+ mNotificationAccessPackageToUserId.remove(pkg);
}
}
for (String pkg : packageNames) {
if (!allowed.contains(pkg)) {
grantNotificationPolicyAccess(pkg);
- grantNotificationListenerAccess(pkg, currentUserHandle);
- grantCoarseLocationAccess(pkg, currentUserHandle);
+ grantNotificationListenerAccess(pkg, currentUserId);
+ grantCoarseLocationPermissionIfNeeded(pkg, currentUserId);
+ mNotificationAccessPackageToUserId.put(pkg, currentUserId);
}
}
@@ -229,7 +246,6 @@ public class VrManagerService extends SystemService implements EnabledComponentC
}
}
-
/**
* Called when a user, package, or setting changes that could affect whether or not the
* currently bound VrListenerService is changed.
@@ -535,17 +551,33 @@ public class VrManagerService extends SystemService implements EnabledComponentC
}
}
- private void updateOverlayStateLocked(ComponentName exemptedComponent) {
+ private void updateOverlayStateLocked(String exemptedPackage, int newUserId, int oldUserId) {
+ AppOpsManager appOpsManager = getContext().getSystemService(AppOpsManager.class);
+
+ // If user changed drop restrictions for the old user.
+ if (oldUserId != newUserId) {
+ appOpsManager.setUserRestrictionForUser(AppOpsManager.OP_SYSTEM_ALERT_WINDOW,
+ false, mOverlayToken, null, oldUserId);
+ }
+
+ // Apply the restrictions for the current user based on vr state
+ String[] exemptions = (exemptedPackage == null) ? new String[0] :
+ new String[] { exemptedPackage };
+
+ appOpsManager.setUserRestrictionForUser(AppOpsManager.OP_SYSTEM_ALERT_WINDOW,
+ mVrModeEnabled, mOverlayToken, exemptions, newUserId);
+ }
+
+ private void updateDependentAppOpsLocked(String newVrServicePackage, int newUserId,
+ String oldVrServicePackage, int oldUserId) {
+ // If VR state changed and we also have a VR service change.
+ if (Objects.equals(newVrServicePackage, oldVrServicePackage)) {
+ return;
+ }
final long identity = Binder.clearCallingIdentity();
try {
- AppOpsManager appOpsManager = getContext().getSystemService(AppOpsManager.class);
- if (appOpsManager != null) {
- String[] exemptions = (exemptedComponent == null) ? new String[0] :
- new String[] { exemptedComponent.getPackageName() };
-
- appOpsManager.setUserRestriction(AppOpsManager.OP_SYSTEM_ALERT_WINDOW,
- mVrModeEnabled, mOverlayToken, exemptions);
- }
+ // Set overlay exception state based on VR enabled and current service
+ updateOverlayStateLocked(newVrServicePackage, newUserId, oldUserId);
} finally {
Binder.restoreCallingIdentity(identity);
}
@@ -578,8 +610,12 @@ public class VrManagerService extends SystemService implements EnabledComponentC
return validUserComponent; // Disabled -> Disabled transition does nothing.
}
+ String oldVrServicePackage = mCurrentVrService != null
+ ? mCurrentVrService.getComponent().getPackageName() : null;
+ final int oldUserId = mCurrentVrModeUser;
+
// Always send mode change events.
- changeVrModeLocked(enabled, (enabled && validUserComponent) ? component : null);
+ changeVrModeLocked(enabled);
if (!enabled || !validUserComponent) {
// Unbind whatever is running
@@ -606,12 +642,25 @@ public class VrManagerService extends SystemService implements EnabledComponentC
}
}
- if (calling != null && !Objects.equals(calling, mCurrentVrModeComponent)) {
+ if (calling != null && !Objects.equals(calling, mCurrentVrModeComponent)) {
mCurrentVrModeComponent = calling;
+ sendUpdatedCaller = true;
+ }
+
+ if (mCurrentVrModeUser != userId) {
mCurrentVrModeUser = userId;
sendUpdatedCaller = true;
}
+ String newVrServicePackage = mCurrentVrService != null
+ ? mCurrentVrService.getComponent().getPackageName() : null;
+ final int newUserId = mCurrentVrModeUser;
+
+ // Update AppOps settings that change state when entering/exiting VR mode, or changing
+ // the current VrListenerService.
+ updateDependentAppOpsLocked(newVrServicePackage, newUserId,
+ oldVrServicePackage, oldUserId);
+
if (mCurrentVrService != null && sendUpdatedCaller) {
final ComponentName c = mCurrentVrModeComponent;
mCurrentVrService.sendEvent(new PendingEvent() {
@@ -645,18 +694,6 @@ public class VrManagerService extends SystemService implements EnabledComponentC
return true;
}
- private void grantCoarseLocationAccess(String pkg, UserHandle userId) {
- PackageManager pm = mContext.getPackageManager();
- pm.grantRuntimePermission(pkg, android.Manifest.permission.ACCESS_COARSE_LOCATION,
- userId);
- }
-
- private void revokeCoarseLocationAccess(String pkg, UserHandle userId) {
- PackageManager pm = mContext.getPackageManager();
- pm.revokeRuntimePermission(pkg,
- android.Manifest.permission.ACCESS_COARSE_LOCATION, userId);
- }
-
private void grantNotificationPolicyAccess(String pkg) {
NotificationManager nm = mContext.getSystemService(NotificationManager.class);
nm.setNotificationPolicyAccessGranted(pkg, true);
@@ -670,14 +707,14 @@ public class VrManagerService extends SystemService implements EnabledComponentC
nm.setNotificationPolicyAccessGranted(pkg, false);
}
- private void grantNotificationListenerAccess(String pkg, UserHandle userId) {
+ private void grantNotificationListenerAccess(String pkg, int userId) {
PackageManager pm = mContext.getPackageManager();
ArraySet<ComponentName> possibleServices = EnabledComponentsObserver.loadComponentNames(pm,
- userId.getIdentifier(), NotificationListenerService.SERVICE_INTERFACE,
+ userId, NotificationListenerService.SERVICE_INTERFACE,
android.Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE);
ContentResolver resolver = mContext.getContentResolver();
- ArraySet<String> current = getCurrentNotifListeners(resolver);
+ ArraySet<String> current = getNotificationListeners(resolver, userId);
for (ComponentName c : possibleServices) {
String flatName = c.flattenToString();
@@ -689,14 +726,16 @@ public class VrManagerService extends SystemService implements EnabledComponentC
if (current.size() > 0) {
String flatSettings = formatSettings(current);
- Settings.Secure.putString(resolver, Settings.Secure.ENABLED_NOTIFICATION_LISTENERS,
- flatSettings);
+ Settings.Secure.putStringForUser(resolver,
+ Settings.Secure.ENABLED_NOTIFICATION_LISTENERS,
+ flatSettings, userId);
}
}
- private void revokeNotificationListenerAccess(String pkg) {
+ private void revokeNotificationListenerAccess(String pkg, int userId) {
ContentResolver resolver = mContext.getContentResolver();
- ArraySet<String> current = getCurrentNotifListeners(resolver);
+
+ ArraySet<String> current = getNotificationListeners(resolver, userId);
ArrayList<String> toRemove = new ArrayList<>();
@@ -710,14 +749,37 @@ public class VrManagerService extends SystemService implements EnabledComponentC
current.removeAll(toRemove);
String flatSettings = formatSettings(current);
- Settings.Secure.putString(resolver, Settings.Secure.ENABLED_NOTIFICATION_LISTENERS,
- flatSettings);
+ Settings.Secure.putStringForUser(resolver,
+ Settings.Secure.ENABLED_NOTIFICATION_LISTENERS,
+ flatSettings, userId);
+ }
+
+ private void grantCoarseLocationPermissionIfNeeded(String pkg, int userId) {
+ // Don't clobber the user if permission set in current state explicitly
+ if (!isPermissionUserUpdated(Manifest.permission.ACCESS_COARSE_LOCATION, pkg, userId)) {
+ mContext.getPackageManager().grantRuntimePermission(pkg,
+ Manifest.permission.ACCESS_COARSE_LOCATION, new UserHandle(userId));
+ }
+ }
+
+ private void revokeCoarseLocationPermissionIfNeeded(String pkg, int userId) {
+ // Don't clobber the user if permission set in current state explicitly
+ if (!isPermissionUserUpdated(Manifest.permission.ACCESS_COARSE_LOCATION, pkg, userId)) {
+ mContext.getPackageManager().revokeRuntimePermission(pkg,
+ Manifest.permission.ACCESS_COARSE_LOCATION, new UserHandle(userId));
+ }
+ }
+ private boolean isPermissionUserUpdated(String permission, String pkg, int userId) {
+ final int flags = mContext.getPackageManager().getPermissionFlags(
+ permission, pkg, new UserHandle(userId));
+ return (flags & (PackageManager.FLAG_PERMISSION_USER_SET
+ | PackageManager.FLAG_PERMISSION_USER_FIXED)) != 0;
}
- private ArraySet<String> getCurrentNotifListeners(ContentResolver resolver) {
- String flat = Settings.Secure.getString(resolver,
- Settings.Secure.ENABLED_NOTIFICATION_LISTENERS);
+ private ArraySet<String> getNotificationListeners(ContentResolver resolver, int userId) {
+ String flat = Settings.Secure.getStringForUser(resolver,
+ Settings.Secure.ENABLED_NOTIFICATION_LISTENERS, userId);
ArraySet<String> current = new ArraySet<>();
if (flat != null) {
@@ -763,9 +825,8 @@ public class VrManagerService extends SystemService implements EnabledComponentC
* Note: Must be called while holding {@code mLock}.
*
* @param enabled new state of the VR mode.
- * @param exemptedComponent a component to exempt from AppOps restrictions for overlays.
*/
- private void changeVrModeLocked(boolean enabled, ComponentName exemptedComponent) {
+ private void changeVrModeLocked(boolean enabled) {
if (mVrModeEnabled != enabled) {
mVrModeEnabled = enabled;
@@ -773,7 +834,6 @@ public class VrManagerService extends SystemService implements EnabledComponentC
Slog.i(TAG, "VR mode " + ((mVrModeEnabled) ? "enabled" : "disabled"));
setVrModeNative(mVrModeEnabled);
- updateOverlayStateLocked(exemptedComponent);
onVrModeChangedLocked();
}
}
diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java
index 101f56f49241..8be5dfb3c7fd 100644
--- a/services/core/java/com/android/server/wm/AccessibilityController.java
+++ b/services/core/java/com/android/server/wm/AccessibilityController.java
@@ -1203,9 +1203,6 @@ final class AccessibilityController {
window.layer = windowState.mLayer;
window.token = windowState.mClient.asBinder();
window.title = windowState.mAttrs.accessibilityTitle;
- if (window.title == null) {
- window.title = windowState.mAttrs.getTitle();
- }
window.accessibilityIdOfAnchor = windowState.mAttrs.accessibilityIdOfAnchor;
WindowState attachedWindow = windowState.mAttachedWindow;
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index e46ed8d2ac1f..36d96979d36e 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -824,22 +824,11 @@ class WindowStateAnimator {
mTmpSize.bottom = mTmpSize.top + 1;
}
- final int displayId = w.getDisplayId();
- float scale = 1.0f;
- // Magnification is supported only for the default display.
- if (mService.mAccessibilityController != null && displayId == DEFAULT_DISPLAY) {
- final MagnificationSpec spec =
- mService.mAccessibilityController.getMagnificationSpecForWindowLocked(w);
- if (spec != null && !spec.isNop()) {
- scale = spec.scale;
- }
- }
-
// Adjust for surface insets.
- mTmpSize.left -= scale * attrs.surfaceInsets.left;
- mTmpSize.top -= scale * attrs.surfaceInsets.top;
- mTmpSize.right += scale * attrs.surfaceInsets.right;
- mTmpSize.bottom += scale * attrs.surfaceInsets.bottom;
+ mTmpSize.left -= attrs.surfaceInsets.left;
+ mTmpSize.top -= attrs.surfaceInsets.top;
+ mTmpSize.right += attrs.surfaceInsets.right;
+ mTmpSize.bottom += attrs.surfaceInsets.bottom;
}
boolean hasSurface() {
@@ -1300,9 +1289,13 @@ class WindowStateAnimator {
void updateSurfaceWindowCrop(Rect clipRect, Rect finalClipRect, boolean recoveringMemory) {
if (DEBUG_WINDOW_CROP) Slog.d(TAG, "updateSurfaceWindowCrop: win=" + mWin
+ " clipRect=" + clipRect + " finalClipRect=" + finalClipRect);
- if (!clipRect.equals(mLastClipRect)) {
- mLastClipRect.set(clipRect);
- mSurfaceController.setCropInTransaction(clipRect, recoveringMemory);
+ if (clipRect != null) {
+ if (!clipRect.equals(mLastClipRect)) {
+ mLastClipRect.set(clipRect);
+ mSurfaceController.setCropInTransaction(clipRect, recoveringMemory);
+ }
+ } else {
+ mSurfaceController.clearCropInTransaction(recoveringMemory);
}
if (!finalClipRect.equals(mLastFinalClipRect)) {
mLastFinalClipRect.set(finalClipRect);
@@ -1314,7 +1307,6 @@ class WindowStateAnimator {
}
private int resolveStackClip() {
-
// App animation overrides window animation stack clip mode.
if (mAppAnimator != null && mAppAnimator.animation != null) {
return mAppAnimator.getStackClip();
@@ -1420,6 +1412,9 @@ class WindowStateAnimator {
// aren't observing known issues here outside of PiP resizing. (Typically
// the other windows that use -1 are PopupWindows which aren't likely
// to be rendering while we resize).
+
+ boolean wasForceScaled = mForceScaleUntilResize;
+
if (!w.inPinnedWorkspace() || (!w.mRelayoutCalled || w.mInRelayout)) {
mSurfaceResized = mSurfaceController.setSizeInTransaction(
mTmpSize.width(), mTmpSize.height(), recoveringMemory);
@@ -1428,13 +1423,17 @@ class WindowStateAnimator {
}
mForceScaleUntilResize = mForceScaleUntilResize && !mSurfaceResized;
-
calculateSurfaceWindowCrop(mTmpClipRect, mTmpFinalClipRect);
+
+ float surfaceWidth = mSurfaceController.getWidth();
+ float surfaceHeight = mSurfaceController.getHeight();
+
if ((task != null && task.mStack.getForceScaleToCrop()) || mForceScaleUntilResize) {
int hInsets = w.getAttrs().surfaceInsets.left + w.getAttrs().surfaceInsets.right;
int vInsets = w.getAttrs().surfaceInsets.top + w.getAttrs().surfaceInsets.bottom;
- float surfaceWidth = mSurfaceController.getWidth();
- float surfaceHeight = mSurfaceController.getHeight();
+ if (!mForceScaleUntilResize) {
+ mSurfaceController.forceScaleableInTransaction(true);
+ }
// We want to calculate the scaling based on the content area, not based on
// the entire surface, so that we scale in sync with windows that don't have insets.
mExtraHScale = (mTmpClipRect.width() - hInsets) / (float)(surfaceWidth - hInsets);
@@ -1455,7 +1454,8 @@ class WindowStateAnimator {
posX += w.getAttrs().surfaceInsets.left * (1 - mExtraHScale);
posY += w.getAttrs().surfaceInsets.top * (1 - mExtraVScale);
- mSurfaceController.setPositionInTransaction(posX, posY, recoveringMemory);
+ mSurfaceController.setPositionInTransaction((float)Math.floor(posX),
+ (float)Math.floor(posY), recoveringMemory);
// Since we are scaled to fit in our previously desired crop, we can now
// expose the whole window in buffer space, and not risk extending
@@ -1467,7 +1467,7 @@ class WindowStateAnimator {
// We need to ensure for each surface, that we disable transformation matrix
// scaling in the same transaction which we resize the surface in.
// As we are in SCALING_MODE_SCALE_TO_WINDOW, SurfaceFlinger will
- // then take over the scaling until the new buffer arrives, and things
+ // then take over the scaling until the new buffer arrives, and things
// will be seamless.
mForceScaleUntilResize = true;
} else {
@@ -1475,7 +1475,25 @@ class WindowStateAnimator {
recoveringMemory);
}
- updateSurfaceWindowCrop(mTmpClipRect, mTmpFinalClipRect, recoveringMemory);
+ // If we are ending the scaling mode. We switch to SCALING_MODE_FREEZE
+ // to prevent further updates until buffer latch. Normally position
+ // would continue to apply immediately. But we need a different position
+ // before and after resize (since we have scaled the shadows, as discussed
+ // above).
+ if (wasForceScaled && !mForceScaleUntilResize) {
+ mSurfaceController.setPositionAppliesWithResizeInTransaction(true);
+ mSurfaceController.forceScaleableInTransaction(false);
+ }
+
+ Rect clipRect = mTmpClipRect;
+ if (w.inPinnedWorkspace()) {
+ clipRect = null;
+ task.mStack.getDimBounds(mTmpFinalClipRect);
+ mTmpFinalClipRect.inset(-w.mAttrs.surfaceInsets.left, -w.mAttrs.surfaceInsets.top,
+ -w.mAttrs.surfaceInsets.right, -w.mAttrs.surfaceInsets.bottom);
+ }
+
+ updateSurfaceWindowCrop(clipRect, mTmpFinalClipRect, recoveringMemory);
mSurfaceController.setMatrixInTransaction(mDsDx * w.mHScale * mExtraHScale,
mDtDx * w.mVScale * mExtraVScale,
diff --git a/services/core/java/com/android/server/wm/WindowSurfaceController.java b/services/core/java/com/android/server/wm/WindowSurfaceController.java
index 9646a49b8a88..fd0bb9905ce0 100644
--- a/services/core/java/com/android/server/wm/WindowSurfaceController.java
+++ b/services/core/java/com/android/server/wm/WindowSurfaceController.java
@@ -26,6 +26,7 @@ import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import static android.view.Surface.SCALING_MODE_FREEZE;
import static android.view.Surface.SCALING_MODE_SCALE_TO_WINDOW;
+import android.graphics.PixelFormat;
import android.graphics.Point;
import android.graphics.PointF;
import android.graphics.Rect;
@@ -78,7 +79,15 @@ class WindowSurfaceController {
title = name;
- if (DEBUG_SURFACE_TRACE) {
+ // For opaque child windows placed under parent windows,
+ // we use a special SurfaceControl which mirrors commands
+ // to a black-out layer placed one Z-layer below the surface.
+ // This prevents holes to whatever app/wallpaper is underneath.
+ if (animator.mWin.isChildWindow() &&
+ animator.mWin.mSubLayer < 0) {
+ mSurfaceControl = new SurfaceControlWithBackground(s,
+ name, w, h, format, flags);
+ } else if (DEBUG_SURFACE_TRACE) {
mSurfaceControl = new SurfaceTrace(
s, name, w, h, format, flags);
} else {
@@ -194,6 +203,20 @@ class WindowSurfaceController {
}
}
+ void clearCropInTransaction(boolean recoveringMemory) {
+ if (SHOW_TRANSACTIONS) logSurface(
+ "CLEAR CROP", null);
+ try {
+ Rect clipRect = new Rect(0, 0, -1, -1);
+ mSurfaceControl.setWindowCrop(clipRect);
+ } catch (RuntimeException e) {
+ Slog.w(TAG, "Error setting clearing crop of " + this, e);
+ if (!recoveringMemory) {
+ mAnimator.reclaimSomeSurfaceMemory("crop", true);
+ }
+ }
+ }
+
void setFinalCropInTransaction(Rect clipRect) {
if (SHOW_TRANSACTIONS) logSurface(
"FINAL CROP " + clipRect.toShortString(), null);
@@ -236,6 +259,10 @@ class WindowSurfaceController {
}
}
+ void setPositionAppliesWithResizeInTransaction(boolean recoveringMemory) {
+ mSurfaceControl.setPositionAppliesWithResize();
+ }
+
void setMatrixInTransaction(float dsdx, float dtdx, float dsdy, float dtdy,
boolean recoveringMemory) {
try {
@@ -554,6 +581,13 @@ class WindowSurfaceController {
}
@Override
+ public void setPositionAppliesWithResize() {
+ if (LOG_SURFACE_TRACE) Slog.v(SURFACE_TAG, "setPositionAppliesWithResize(): OLD: "
+ + this + ". Called by" + Debug.getCallers(9));
+ super.setPositionAppliesWithResize();
+ }
+
+ @Override
public void setSize(int w, int h) {
if (w != mSize.x || h != mSize.y) {
if (LOG_SURFACE_TRACE) Slog.v(SURFACE_TAG, "setSize(" + w + "," + h + "): OLD:"
@@ -719,4 +753,125 @@ class WindowSurfaceController {
+ " (" + mDsdx + "," + mDtdx + "," + mDsdy + "," + mDtdy + ")";
}
}
+
+ private static class SurfaceControlWithBackground extends SurfaceControl {
+ private SurfaceControl mBackgroundControl;
+ private boolean mOpaque = true;
+ private boolean mVisible = false;
+
+ public SurfaceControlWithBackground(SurfaceSession s,
+ String name, int w, int h, int format, int flags)
+ throws OutOfResourcesException {
+ super(s, name, w, h, format, flags);
+ mBackgroundControl = new SurfaceControl(s, name, w, h,
+ PixelFormat.OPAQUE, flags | SurfaceControl.FX_SURFACE_DIM);
+ mOpaque = (flags & SurfaceControl.OPAQUE) != 0;
+ }
+
+ @Override
+ public void setAlpha(float alpha) {
+ super.setAlpha(alpha);
+ mBackgroundControl.setAlpha(alpha);
+ }
+
+ @Override
+ public void setLayer(int zorder) {
+ super.setLayer(zorder);
+ mBackgroundControl.setLayer(zorder - 1);
+ }
+
+ @Override
+ public void setPosition(float x, float y) {
+ super.setPosition(x, y);
+ mBackgroundControl.setPosition(x, y);
+ }
+
+ @Override
+ public void setSize(int w, int h) {
+ super.setSize(w, h);
+ mBackgroundControl.setSize(w, h);
+ }
+
+ @Override
+ public void setWindowCrop(Rect crop) {
+ super.setWindowCrop(crop);
+ mBackgroundControl.setWindowCrop(crop);
+ }
+
+ @Override
+ public void setFinalCrop(Rect crop) {
+ super.setFinalCrop(crop);
+ mBackgroundControl.setFinalCrop(crop);
+ }
+
+ @Override
+ public void setLayerStack(int layerStack) {
+ super.setLayerStack(layerStack);
+ mBackgroundControl.setLayerStack(layerStack);
+ }
+
+ @Override
+ public void setOpaque(boolean isOpaque) {
+ super.setOpaque(isOpaque);
+ mOpaque = isOpaque;
+ updateBackgroundVisibility();
+ }
+
+ @Override
+ public void setSecure(boolean isSecure) {
+ super.setSecure(isSecure);
+ }
+
+ @Override
+ public void setMatrix(float dsdx, float dtdx, float dsdy, float dtdy) {
+ super.setMatrix(dsdx, dtdx, dsdy, dtdy);
+ mBackgroundControl.setMatrix(dsdx, dtdx, dsdy, dtdy);
+ }
+
+ @Override
+ public void hide() {
+ mVisible = false;
+ super.hide();
+ updateBackgroundVisibility();
+ }
+
+ @Override
+ public void show() {
+ mVisible = true;
+ super.show();
+ updateBackgroundVisibility();
+ }
+
+ @Override
+ public void destroy() {
+ super.destroy();
+ mBackgroundControl.destroy();
+ }
+
+ @Override
+ public void release() {
+ super.release();
+ mBackgroundControl.release();
+ }
+
+ @Override
+ public void setTransparentRegionHint(Region region) {
+ super.setTransparentRegionHint(region);
+ mBackgroundControl.setTransparentRegionHint(region);
+ }
+
+ @Override
+ public void deferTransactionUntil(IBinder handle, long frame) {
+ super.deferTransactionUntil(handle, frame);
+ mBackgroundControl.deferTransactionUntil(handle, frame);
+ }
+
+ private void updateBackgroundVisibility() {
+ if (mOpaque && mVisible) {
+ mBackgroundControl.show();
+ } else {
+ mBackgroundControl.hide();
+ }
+ }
+ }
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 9a7e64b3a923..4692a57406d1 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -1338,7 +1338,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
Owners newOwners() {
- return new Owners(mContext, getUserManager(), getUserManagerInternal());
+ return new Owners(getUserManager(), getUserManagerInternal(),
+ getPackageManagerInternal());
}
UserManager getUserManager() {
@@ -8134,26 +8135,6 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
@Override
- public boolean hasDeviceOwnerOrProfileOwner(String packageName, int userId) {
- if (!mHasFeature || packageName == null) {
- return false;
- }
- if (userId < 0) {
- throw new UnsupportedOperationException("userId should be >= 0");
- }
- synchronized (DevicePolicyManagerService.this) {
- if (packageName.equals(mOwners.getProfileOwnerPackage(userId))) {
- return true;
- }
- if (userId == mOwners.getDeviceOwnerUserId()
- && packageName.equals(mOwners.getDeviceOwnerPackageName())) {
- return true;
- }
- }
- return false;
- }
-
- @Override
public Intent createPackageSuspendedDialogIntent(String packageName, int userId) {
Intent intent = new Intent(Settings.ACTION_SHOW_ADMIN_SUPPORT_DETAILS);
intent.putExtra(Intent.EXTRA_USER_ID, userId);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
index b316cbd96453..cb39ebd0e3b0 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
@@ -19,6 +19,7 @@ package com.android.server.devicepolicy;
import android.app.admin.SystemUpdatePolicy;
import android.content.ComponentName;
import android.content.Context;
+import android.content.pm.PackageManagerInternal;
import android.content.pm.UserInfo;
import android.os.Environment;
import android.os.UserHandle;
@@ -28,6 +29,7 @@ import android.util.ArrayMap;
import android.util.AtomicFile;
import android.util.Log;
import android.util.Slog;
+import android.util.SparseArray;
import android.util.Xml;
import com.android.internal.util.FastXmlSerializer;
@@ -86,6 +88,7 @@ class Owners {
private final UserManager mUserManager;
private final UserManagerInternal mUserManagerInternal;
+ private final PackageManagerInternal mPackageManagerInternal;
// Internal state for the device owner package.
private OwnerInfo mDeviceOwner;
@@ -98,10 +101,12 @@ class Owners {
// Local system update policy controllable by device owner.
private SystemUpdatePolicy mSystemUpdatePolicy;
- public Owners(Context context, UserManager userManager,
- UserManagerInternal userManagerInternal) {
+ public Owners(UserManager userManager,
+ UserManagerInternal userManagerInternal,
+ PackageManagerInternal packageManagerInternal) {
mUserManager = userManager;
mUserManagerInternal = userManagerInternal;
+ mPackageManagerInternal = packageManagerInternal;
}
/**
@@ -145,6 +150,17 @@ class Owners {
Slog.w(TAG, String.format("User %d has both DO and PO, which is not supported",
getDeviceOwnerUserId()));
}
+ pushToPackageManager();
+ }
+
+ private void pushToPackageManager() {
+ final SparseArray<String> po = new SparseArray<>();
+ for (int i = mProfileOwners.size() - 1; i >= 0; i--) {
+ po.put(mProfileOwners.keyAt(i), mProfileOwners.valueAt(i).packageName);
+ }
+ mPackageManagerInternal.setDeviceAndProfileOwnerPackages(
+ mDeviceOwnerUserId, (mDeviceOwner != null ? mDeviceOwner.packageName : null),
+ po);
}
String getDeviceOwnerPackageName() {
@@ -190,6 +206,7 @@ class Owners {
mDeviceOwnerUserId = userId;
mUserManagerInternal.setDeviceManaged(true);
+ pushToPackageManager();
}
void clearDeviceOwner() {
@@ -197,6 +214,7 @@ class Owners {
mDeviceOwnerUserId = UserHandle.USER_NULL;
mUserManagerInternal.setDeviceManaged(false);
+ pushToPackageManager();
}
void setProfileOwner(ComponentName admin, String ownerName, int userId) {
@@ -205,11 +223,13 @@ class Owners {
/* userRestrictionsMigrated =*/ true, /* remoteBugreportUri =*/ null,
/* remoteBugreportHash =*/ null));
mUserManagerInternal.setUserManaged(userId, true);
+ pushToPackageManager();
}
void removeProfileOwner(int userId) {
mProfileOwners.remove(userId);
mUserManagerInternal.setUserManaged(userId, false);
+ pushToPackageManager();
}
ComponentName getProfileOwnerComponent(int userId) {
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
index 744443f1d7e7..6cb4a8238727 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
@@ -28,10 +28,8 @@ import android.os.PowerManagerInternal;
import android.os.UserHandle;
import android.os.UserManager;
import android.os.UserManagerInternal;
-import android.os.storage.StorageManager;
import android.telephony.TelephonyManager;
import android.util.ArrayMap;
-import android.util.Log;
import android.util.Pair;
import android.view.IWindowManager;
@@ -57,7 +55,7 @@ public class DevicePolicyManagerServiceTestable extends DevicePolicyManagerServi
private final File mProfileOwnerBase;
public OwnersTestable(DpmMockContext context) {
- super(context, context.userManager, context.userManagerInternal);
+ super(context.userManager, context.userManagerInternal, context.packageManagerInternal);
mLegacyFile = new File(context.dataDir, LEGACY_FILE);
mDeviceOwnerFile = new File(context.dataDir, DEVICE_OWNER_FILE);
mProfileOwnerBase = new File(context.dataDir, PROFILE_OWNER_FILE_BASE);