Merge "Make sure we're locked" into nyc-dev
diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java
index a4688d1..f56a6ad 100644
--- a/core/java/android/app/ResourcesManager.java
+++ b/core/java/android/app/ResourcesManager.java
@@ -274,7 +274,7 @@
if (libDir.endsWith(".apk")) {
// Avoid opening files we know do not have resources,
// like code-only .jar files.
- if (assets.addAssetPath(libDir) == 0) {
+ if (assets.addAssetPathAsSharedLibrary(libDir) == 0) {
Log.w(TAG, "Asset path '" + libDir +
"' does not exist or contains no resources.");
}
@@ -330,6 +330,22 @@
}
/**
+ * Finds a cached ResourcesImpl object that matches the given ResourcesKey, or
+ * creates a new one and caches it for future use.
+ * @param key The key to match.
+ * @return a ResourcesImpl object matching the key.
+ */
+ private @NonNull ResourcesImpl findOrCreateResourcesImplForKeyLocked(
+ @NonNull ResourcesKey key) {
+ ResourcesImpl impl = findResourcesImplForKeyLocked(key);
+ if (impl == null) {
+ impl = createResourcesImpl(key);
+ mResourceImpls.put(key, new WeakReference<>(impl));
+ }
+ return impl;
+ }
+
+ /**
* Find the ResourcesKey that this ResourcesImpl object is associated with.
* @return the ResourcesKey or null if none was found.
*/
@@ -811,4 +827,75 @@
Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
}
}
+
+ /**
+ * Appends the library asset path to any ResourcesImpl object that contains the main
+ * assetPath.
+ * @param assetPath The main asset path for which to add the library asset path.
+ * @param libAsset The library asset path to add.
+ */
+ public void appendLibAssetForMainAssetPath(String assetPath, String libAsset) {
+ synchronized (this) {
+ // Record which ResourcesImpl need updating
+ // (and what ResourcesKey they should update to).
+ final ArrayMap<ResourcesImpl, ResourcesKey> updatedResourceKeys = new ArrayMap<>();
+
+ final int implCount = mResourceImpls.size();
+ for (int i = 0; i < implCount; i++) {
+ final ResourcesImpl impl = mResourceImpls.valueAt(i).get();
+ final ResourcesKey key = mResourceImpls.keyAt(i);
+ if (impl != null && key.mResDir.equals(assetPath)) {
+ if (!ArrayUtils.contains(key.mLibDirs, libAsset)) {
+ final int newLibAssetCount = 1 +
+ (key.mLibDirs != null ? key.mLibDirs.length : 0);
+ final String[] newLibAssets = new String[newLibAssetCount];
+ if (key.mLibDirs != null) {
+ System.arraycopy(key.mLibDirs, 0, newLibAssets, 0, key.mLibDirs.length);
+ }
+ newLibAssets[newLibAssetCount - 1] = libAsset;
+
+ updatedResourceKeys.put(impl, new ResourcesKey(
+ key.mResDir,
+ key.mSplitResDirs,
+ key.mOverlayDirs,
+ newLibAssets,
+ key.mDisplayId,
+ key.mOverrideConfiguration,
+ key.mCompatInfo));
+ }
+ }
+ }
+
+ // Bail early if there is no work to do.
+ if (updatedResourceKeys.isEmpty()) {
+ return;
+ }
+
+ // Update any references to ResourcesImpl that require reloading.
+ final int resourcesCount = mResourceReferences.size();
+ for (int i = 0; i < resourcesCount; i++) {
+ final Resources r = mResourceReferences.get(i).get();
+ if (r != null) {
+ final ResourcesKey key = updatedResourceKeys.get(r.getImpl());
+ if (key != null) {
+ r.setImpl(findOrCreateResourcesImplForKeyLocked(key));
+ }
+ }
+ }
+
+ // Update any references to ResourcesImpl that require reloading for each Activity.
+ for (ActivityResources activityResources : mActivityResourceReferences.values()) {
+ final int resCount = activityResources.activityResources.size();
+ for (int i = 0; i < resCount; i++) {
+ final Resources r = activityResources.activityResources.get(i).get();
+ if (r != null) {
+ final ResourcesKey key = updatedResourceKeys.get(r.getImpl());
+ if (key != null) {
+ r.setImpl(findOrCreateResourcesImplForKeyLocked(key));
+ }
+ }
+ }
+ }
+ }
+ }
}
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 108350a..0881c9c 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -3646,6 +3646,12 @@
public static final String SYSTEM_HEALTH_SERVICE = "systemhealth";
/**
+ * Gatekeeper Service.
+ * @hide
+ */
+ public static final String GATEKEEPER_SERVICE = "android.service.gatekeeper.IGateKeeperService";
+
+ /**
* Determine whether the given permission is allowed for a particular
* process and user ID running in the system.
*
diff --git a/core/java/android/hardware/location/ContextHubService.java b/core/java/android/hardware/location/ContextHubService.java
index 8176189..43e596f 100644
--- a/core/java/android/hardware/location/ContextHubService.java
+++ b/core/java/android/hardware/location/ContextHubService.java
@@ -21,12 +21,15 @@
import android.content.pm.PackageManager;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.service.vr.IVrManager;
+import android.service.vr.IVrStateCallbacks;
import android.util.Log;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
-import java.util.HashMap;
+import java.util.concurrent.ConcurrentHashMap;
/**
* @hide
@@ -57,8 +60,11 @@
private static final int OS_APP_INSTANCE = -1;
+ private static final long APP_ID_ACTIVITY_RECOGNITION = 0x476f6f676c001000L;
+
private final Context mContext;
- private final HashMap<Integer, NanoAppInstanceInfo> mNanoAppHash = new HashMap<>();
+ private final ConcurrentHashMap<Integer, NanoAppInstanceInfo> mNanoAppHash =
+ new ConcurrentHashMap<>();
private final ContextHubInfo[] mContextHubInfo;
private final RemoteCallbackList<IContextHubCallback> mCallbacksList =
new RemoteCallbackList<>();
@@ -66,6 +72,18 @@
private native int nativeSendMessage(int[] header, byte[] data);
private native ContextHubInfo[] nativeInitialize();
+ private final IVrStateCallbacks mVrStateCallbacks = new IVrStateCallbacks.Stub() {
+ @Override
+ public void onVrStateChanged(boolean enabled) {
+ for (NanoAppInstanceInfo app : mNanoAppHash.values()) {
+ if (app.getAppId() == APP_ID_ACTIVITY_RECOGNITION) {
+ sendVrStateChangeMessageToApp(app, enabled);
+ break;
+ }
+ }
+ }
+ };
+
public ContextHubService(Context context) {
mContext = context;
mContextHubInfo = nativeInitialize();
@@ -74,6 +92,18 @@
Log.d(TAG, "ContextHub[" + i + "] id: " + mContextHubInfo[i].getId()
+ ", name: " + mContextHubInfo[i].getName());
}
+
+ if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_VR_MODE)) {
+ IVrManager vrManager =
+ IVrManager.Stub.asInterface(ServiceManager.getService("vrmanager"));
+ if (vrManager != null) {
+ try {
+ vrManager.registerListener(mVrStateCallbacks);
+ } catch (RemoteException e) {
+ Log.e(TAG, "VR state listener registration failed", e);
+ }
+ }
+ }
}
@Override
@@ -277,4 +307,19 @@
return 0;
}
+
+ private void sendVrStateChangeMessageToApp(NanoAppInstanceInfo app, boolean vrModeEnabled) {
+ int[] msgHeader = new int[MSG_HEADER_SIZE];
+ msgHeader[MSG_FIELD_TYPE] = 0;
+ msgHeader[MSG_FIELD_VERSION] = 0;
+ msgHeader[MSG_FIELD_HUB_HANDLE] = ANY_HUB;
+ msgHeader[MSG_FIELD_APP_INSTANCE] = app.getHandle();
+
+ byte[] data = new byte[1];
+ data[0] = (byte) ((vrModeEnabled) ? 1 : 0);
+ int ret = nativeSendMessage(msgHeader, data);
+ if (ret != 0) {
+ Log.e(TAG, "Couldn't send VR state change notification (" + ret + ")!");
+ }
+ }
}
diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java
index f6e8940..d8be2b6 100644
--- a/core/java/android/os/Environment.java
+++ b/core/java/android/os/Environment.java
@@ -240,6 +240,22 @@
return new File(getDataDirectory(), "system");
}
+ /**
+ * Returns the base directory for per-user system directory, device encrypted.
+ * {@hide}
+ */
+ public static File getDataSystemDeDirectory() {
+ return buildPath(getDataDirectory(), "system_de");
+ }
+
+ /**
+ * Returns the base directory for per-user system directory, credential encrypted.
+ * {@hide}
+ */
+ public static File getDataSystemCeDirectory() {
+ return buildPath(getDataDirectory(), "system_ce");
+ }
+
/** {@hide} */
public static File getDataSystemCeDirectory(int userId) {
return buildPath(getDataDirectory(), "system_ce", String.valueOf(userId));
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 7146448..bcc8d46 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -1496,7 +1496,9 @@
}
/**
- * Returns information for all users on this device.
+ * Returns information for all users on this device, including ones marked for deletion.
+ * To retrieve only users that are alive, use {@link #getUsers(boolean)}.
+ * <p>
* Requires {@link android.Manifest.permission#MANAGE_USERS} permission.
* @return the list of users that exist on the device.
* @hide
diff --git a/core/java/android/view/NotificationHeaderView.java b/core/java/android/view/NotificationHeaderView.java
index 3069e5a..c46acae 100644
--- a/core/java/android/view/NotificationHeaderView.java
+++ b/core/java/android/view/NotificationHeaderView.java
@@ -22,6 +22,7 @@
import android.graphics.Outline;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
+import android.os.Bundle;
import android.util.AttributeSet;
import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.ImageView;
@@ -63,6 +64,33 @@
}
}
};
+ final AccessibilityDelegate mExpandDelegate = new AccessibilityDelegate() {
+
+ @Override
+ public boolean performAccessibilityAction(View host, int action, Bundle args) {
+ if (super.performAccessibilityAction(host, action, args)) {
+ return true;
+ }
+ if (action == AccessibilityNodeInfo.ACTION_COLLAPSE
+ || action == AccessibilityNodeInfo.ACTION_EXPAND) {
+ mExpandClickListener.onClick(mExpandButton);
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
+ super.onInitializeAccessibilityNodeInfo(host, info);
+ // Avoid that the button description is also spoken
+ info.setClassName(getClass().getName());
+ if (mExpanded) {
+ info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_COLLAPSE);
+ } else {
+ info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_EXPAND);
+ }
+ }
+ };
public NotificationHeaderView(Context context) {
this(context, null);
@@ -92,6 +120,9 @@
mAppName = findViewById(com.android.internal.R.id.app_name_text);
mHeaderText = findViewById(com.android.internal.R.id.header_text);
mExpandButton = (ImageView) findViewById(com.android.internal.R.id.expand_button);
+ if (mExpandButton != null) {
+ mExpandButton.setAccessibilityDelegate(mExpandDelegate);
+ }
mIcon = findViewById(com.android.internal.R.id.icon);
mProfileBadge = findViewById(com.android.internal.R.id.profile_badge);
}
@@ -230,7 +261,7 @@
public void setOnClickListener(@Nullable OnClickListener l) {
mExpandClickListener = l;
setOnTouchListener(mExpandClickListener != null ? mTouchListener : null);
- setFocusable(l != null);
+ mExpandButton.setOnClickListener(mExpandClickListener);
updateTouchListener();
}
@@ -380,19 +411,6 @@
return this;
}
- @Override
- public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
- super.onInitializeAccessibilityNodeInfo(info);
- if (mExpandClickListener != null) {
- AccessibilityNodeInfo.AccessibilityAction expand
- = new AccessibilityNodeInfo.AccessibilityAction(
- AccessibilityNodeInfo.ACTION_CLICK,
- getContext().getString(
- com.android.internal.R.string.expand_action_accessibility));
- info.addAction(expand);
- }
- }
-
public ImageView getExpandButton() {
return mExpandButton;
}
diff --git a/core/java/android/webkit/WebViewDelegate.java b/core/java/android/webkit/WebViewDelegate.java
index 9e73af2..2cdff79 100644
--- a/core/java/android/webkit/WebViewDelegate.java
+++ b/core/java/android/webkit/WebViewDelegate.java
@@ -21,7 +21,9 @@
import android.annotation.SystemApi;
import android.app.ActivityThread;
import android.app.Application;
+import android.app.ResourcesManager;
import android.content.Context;
+import android.content.pm.ApplicationInfo;
import android.content.res.Resources;
import android.graphics.Canvas;
import android.os.SystemProperties;
@@ -31,6 +33,8 @@
import android.view.View;
import android.view.ViewRootImpl;
+import com.android.internal.util.ArrayUtils;
+
/**
* Delegate used by the WebView provider implementation to access
* the required framework functionality needed to implement a {@link WebView}.
@@ -177,7 +181,29 @@
* Adds the WebView asset path to {@link android.content.res.AssetManager}.
*/
public void addWebViewAssetPath(Context context) {
- context.getAssets().addAssetPathAsSharedLibrary(
- WebViewFactory.getLoadedPackageInfo().applicationInfo.sourceDir);
+ final String newAssetPath = WebViewFactory.getLoadedPackageInfo().applicationInfo.sourceDir;
+
+ final ApplicationInfo appInfo = context.getApplicationInfo();
+ final String[] libs = appInfo.sharedLibraryFiles;
+ if (!ArrayUtils.contains(libs, newAssetPath)) {
+ // Build the new library asset path list.
+ final int newLibAssetsCount = 1 + (libs != null ? libs.length : 0);
+ final String[] newLibAssets = new String[newLibAssetsCount];
+ if (libs != null) {
+ System.arraycopy(libs, 0, newLibAssets, 0, libs.length);
+ }
+ newLibAssets[newLibAssetsCount - 1] = newAssetPath;
+
+ // Update the ApplicationInfo object with the new list.
+ // We know this will persist and future Resources created via ResourcesManager
+ // will include the shared library because this ApplicationInfo comes from the
+ // underlying LoadedApk in ContextImpl, which does not change during the life of the
+ // application.
+ appInfo.sharedLibraryFiles = newLibAssets;
+
+ // Update existing Resources with the WebView library.
+ ResourcesManager.getInstance().appendLibAssetForMainAssetPath(
+ appInfo.getBaseResourcePath(), newAssetPath);
+ }
}
}
diff --git a/core/java/com/android/internal/app/LocalePickerWithRegion.java b/core/java/com/android/internal/app/LocalePickerWithRegion.java
index 04929a7..d0719ee 100644
--- a/core/java/com/android/internal/app/LocalePickerWithRegion.java
+++ b/core/java/com/android/internal/app/LocalePickerWithRegion.java
@@ -45,6 +45,7 @@
* default locale.</p>
*/
public class LocalePickerWithRegion extends ListFragment implements SearchView.OnQueryTextListener {
+ private static final String PARENT_FRAGMENT_NAME = "localeListEditor";
private SuggestedLocaleAdapter mAdapter;
private LocaleSelectedListener mListener;
@@ -130,11 +131,24 @@
return true;
}
+ private void returnToParentFrame() {
+ getFragmentManager().popBackStack(PARENT_FRAGMENT_NAME,
+ FragmentManager.POP_BACK_STACK_INCLUSIVE);
+ }
+
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
+ if (mLocaleList == null) {
+ // The fragment was killed and restored by the FragmentManager.
+ // At this point we have no data, no listener. Just return, to prevend a NPE.
+ // Fixes b/28748150. Created b/29400003 for a cleaner solution.
+ returnToParentFrame();
+ return;
+ }
+
final boolean countryMode = mParentLocale != null;
final Locale sortingLocale = countryMode ? mParentLocale.getLocale() : Locale.getDefault();
mAdapter = new SuggestedLocaleAdapter(mLocaleList, countryMode);
@@ -197,8 +211,7 @@
if (mListener != null) {
mListener.onLocaleSelected(locale);
}
- getFragmentManager().popBackStack("localeListEditor",
- FragmentManager.POP_BACK_STACK_INCLUSIVE);
+ returnToParentFrame();
} else {
LocalePickerWithRegion selector = LocalePickerWithRegion.createCountryPicker(
getContext(), mListener, locale, mTranslatedOnly /* translate only */);
@@ -208,8 +221,7 @@
.replace(getId(), selector).addToBackStack(null)
.commit();
} else {
- getFragmentManager().popBackStack("localeListEditor",
- FragmentManager.POP_BACK_STACK_INCLUSIVE);
+ returnToParentFrame();
}
}
}
diff --git a/core/java/com/android/internal/widget/NotificationExpandButton.java b/core/java/com/android/internal/widget/NotificationExpandButton.java
new file mode 100644
index 0000000..f4f49b1
--- /dev/null
+++ b/core/java/com/android/internal/widget/NotificationExpandButton.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.internal.widget;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.graphics.Rect;
+import android.util.AttributeSet;
+import android.widget.ImageView;
+import android.widget.RemoteViews;
+
+/**
+ * An expand button in a notification
+ */
+@RemoteViews.RemoteView
+public class NotificationExpandButton extends ImageView {
+ public NotificationExpandButton(Context context) {
+ super(context);
+ }
+
+ public NotificationExpandButton(Context context, @Nullable AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public NotificationExpandButton(Context context, @Nullable AttributeSet attrs,
+ int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ }
+
+ public NotificationExpandButton(Context context, @Nullable AttributeSet attrs, int defStyleAttr,
+ int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ }
+
+ @Override
+ public void getBoundsOnScreen(Rect outRect, boolean clipToParent) {
+ super.getBoundsOnScreen(outRect, clipToParent);
+ extendRectToMinTouchSize(outRect);
+ }
+
+ private void extendRectToMinTouchSize(Rect rect) {
+ int touchTargetSize = (int) (getResources().getDisplayMetrics().density * 48);
+ rect.left = rect.centerX() - touchTargetSize / 2;
+ rect.right = rect.left + touchTargetSize;
+ rect.top = rect.centerY() - touchTargetSize / 2;
+ rect.bottom = rect.top + touchTargetSize;
+ }
+}
diff --git a/core/res/res/layout/notification_template_header.xml b/core/res/res/layout/notification_template_header.xml
index 38ea92a..38f671c2 100644
--- a/core/res/res/layout/notification_template_header.xml
+++ b/core/res/res/layout/notification_template_header.xml
@@ -89,7 +89,7 @@
android:layout="@layout/notification_template_part_chronometer"
android:visibility="gone"
/>
- <ImageView
+ <com.android.internal.widget.NotificationExpandButton
android:id="@+id/expand_button"
android:background="@null"
android:layout_width="wrap_content"
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 9245749..6bc3e4c 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -245,7 +245,7 @@
<string name="permgrouplab_contacts" msgid="3657758145679177612">"Kontakte"</string>
<string name="permgroupdesc_contacts" msgid="6951499528303668046">"auf deine Kontakte zugreifen"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"Standort"</string>
- <string name="permgroupdesc_location" msgid="1346617465127855033">"auf den Standort deines Geräts zugreifen"</string>
+ <string name="permgroupdesc_location" msgid="1346617465127855033">"auf den Standort deines Geräts zuzugreifen"</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"Kalender"</string>
<string name="permgroupdesc_calendar" msgid="3889615280211184106">"auf deinen Kalender zugreifen"</string>
<string name="permgrouplab_sms" msgid="228308803364967808">"SMS"</string>
diff --git a/docs/html/preview/behavior-changes.jd b/docs/html/preview/behavior-changes.jd
index b38f1b8..3a37295 100644
--- a/docs/html/preview/behavior-changes.jd
+++ b/docs/html/preview/behavior-changes.jd
@@ -737,7 +737,17 @@
<li>The Work Mode setting controls access to work apps. When work mode is off the
system launcher indicates work apps are unavailable by greying them out. Enabling
- work mode again restores normal behavior.
+ work mode again restores normal behavior.</li>
+
+ <li>When installing a PKCS #12 file containing a client certificate chain and
+ the corresponding private key from Settings UI, the CA certificate in the
+ chain is no longer installed to the trusted credentials storage. This does
+ not affect the result of {@link android.security.KeyChain#getCertificateChain
+ KeyChain.getCertificateChain()} when apps attempt to retrieve the client
+ certificate chain later. If required, the CA certificate should be installed
+ to the trusted credentials storage via Settings UI separately, with a
+ DER-encoded format under a .crt or .cer file extension.
+ </li>
</ul>
<p>
diff --git a/docs/html/training/wearables/watch-faces/service.jd b/docs/html/training/wearables/watch-faces/service.jd
index 20eb0c77..b54f51a 100755
--- a/docs/html/training/wearables/watch-faces/service.jd
+++ b/docs/html/training/wearables/watch-faces/service.jd
@@ -93,24 +93,20 @@
<h3 id="Permissions">Declare Permissions</h3>
-<p>Watch faces require the <code>PROVIDE_BACKGROUND</code> and <code>WAKE_LOCK</code> permissions.
-Add the following permissions to the manifest files of both the wearable app and the mobile
-app under the <code>manifest</code> element:</p>
+<p>A watch face requires the <code>WAKE_LOCK</code> permission.
+Add the following permission to the manifest files of both the wearable app
+and the mobile app under the <code>manifest</code> element:</p>
<pre>
<manifest ...>
<uses-permission
- android:name="com.google.android.permission.PROVIDE_BACKGROUND" />
- <uses-permission
android:name="android.permission.WAKE_LOCK" />
...
</manifest>
</pre>
-<p class="caution"><strong>Caution:</strong> The handheld app must include all the permissions
-declared in the wearable app.</p>
-
-
+<p class="caution"><strong>Caution:</strong> The handheld app must include all
+of the permissions declared in the wearable app.</p>
<h2 id="CallbackMethods">Implement the Service and Callback Methods</h2>
diff --git a/keystore/java/android/security/GateKeeper.java b/keystore/java/android/security/GateKeeper.java
index c1df28c..7a2cbd0 100644
--- a/keystore/java/android/security/GateKeeper.java
+++ b/keystore/java/android/security/GateKeeper.java
@@ -16,6 +16,7 @@
package android.security;
+import android.content.Context;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
@@ -32,7 +33,7 @@
public static IGateKeeperService getService() {
IGateKeeperService service = IGateKeeperService.Stub.asInterface(
- ServiceManager.getService("android.service.gatekeeper.IGateKeeperService"));
+ ServiceManager.getService(Context.GATEKEEPER_SERVICE));
if (service == null) {
throw new IllegalStateException("Gatekeeper service not available");
}
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index d447a38..ceeb12b 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -6174,7 +6174,7 @@
if (id >= 256) {
LOG_ALWAYS_FATAL("Package id out of range");
return NO_ERROR;
- } else if (id == 0 || appAsLib || isSystemAsset) {
+ } else if (id == 0 || (id == 0x7f && appAsLib) || isSystemAsset) {
// This is a library or a system asset, so assign an ID
id = mNextPackageId++;
}
diff --git a/packages/SettingsLib/res/values-uz-rUZ/strings.xml b/packages/SettingsLib/res/values-uz-rUZ/strings.xml
index 13fdb05..bd0cc8c 100644
--- a/packages/SettingsLib/res/values-uz-rUZ/strings.xml
+++ b/packages/SettingsLib/res/values-uz-rUZ/strings.xml
@@ -85,7 +85,7 @@
<string name="accessibility_wifi_signal_full" msgid="7061045677694702">"Wi-Fi: signal to‘liq"</string>
<string name="process_kernel_label" msgid="3916858646836739323">"Android OS"</string>
<string name="data_usage_uninstalled_apps" msgid="614263770923231598">"O‘chirilgan ilovalar"</string>
- <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"O‘chirib yuborilgan ilovalar va foydalanuvchilar"</string>
+ <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"O‘chirib tashlangan ilova va foydalanuvchilar"</string>
<string name="tether_settings_title_usb" msgid="6688416425801386511">"USB modem"</string>
<string name="tether_settings_title_wifi" msgid="3277144155960302049">"Ixcham hotspot"</string>
<string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Bluetooth modem"</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java b/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java
index ce916cb..37e3c53 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java
@@ -308,6 +308,13 @@
}
@Override
+ protected void onPreExecute() {
+ if (sConfigTracker == null || sTileCache == null) {
+ getDashboardCategories();
+ }
+ }
+
+ @Override
protected void onPostExecute(List<DashboardCategory> dashboardCategories) {
for (int i = 0; i < dashboardCategories.size(); i++) {
DashboardCategory category = dashboardCategories.get(i);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsSystemUser.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsSystemUser.java
index 913da18..3921a20 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsSystemUser.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsSystemUser.java
@@ -30,6 +30,7 @@
import com.android.systemui.recents.events.activity.DockedTopTaskEvent;
import com.android.systemui.recents.events.activity.RecentsActivityStartingEvent;
import com.android.systemui.recents.events.ui.RecentsDrawnEvent;
+import com.android.systemui.recents.misc.ForegroundThread;
/**
* An implementation of the system user's Recents interface to be called remotely by secondary
@@ -78,12 +79,16 @@
@Override
public void updateRecentsVisibility(boolean visible) {
- mImpl.onVisibilityChanged(mContext, visible);
+ ForegroundThread.getHandler().post(() -> {
+ mImpl.onVisibilityChanged(mContext, visible);
+ });
}
@Override
public void startScreenPinning(int taskId) {
- mImpl.onStartScreenPinning(mContext, taskId);
+ ForegroundThread.getHandler().post(() -> {
+ mImpl.onStartScreenPinning(mContext, taskId);
+ });
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java b/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java
index 992b13f..b961055 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java
@@ -72,7 +72,12 @@
}
public void showPrompt(int taskId, boolean allowCancel) {
- clearPrompt();
+ try {
+ clearPrompt();
+ } catch (IllegalArgumentException e) {
+ // If the call to show the prompt fails due to the request window not already being
+ // attached, then just ignore the error since we will be re-adding it below.
+ }
this.taskId = taskId;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index 28a6851..e1d4c8a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -27,6 +27,7 @@
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.os.Build;
+import android.os.Bundle;
import android.service.notification.StatusBarNotification;
import android.util.AttributeSet;
import android.util.FloatProperty;
@@ -37,11 +38,11 @@
import android.view.View;
import android.view.ViewStub;
import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.Chronometer;
import android.widget.ImageView;
import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto;
import com.android.internal.logging.MetricsProto.MetricsEvent;
import com.android.internal.util.NotificationColorUtil;
import com.android.systemui.R;
@@ -50,6 +51,7 @@
import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.statusbar.stack.NotificationChildrenContainer;
+import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
import com.android.systemui.statusbar.stack.StackScrollState;
import com.android.systemui.statusbar.stack.StackStateAnimator;
import com.android.systemui.statusbar.stack.StackViewState;
@@ -140,15 +142,17 @@
@Override
public void onClick(View v) {
if (!mShowingPublic && mGroupManager.isSummaryOfGroup(mStatusBarNotification)) {
+ mGroupExpansionChanging = true;
final boolean wasExpanded = mGroupManager.isGroupExpanded(mStatusBarNotification);
boolean nowExpanded = mGroupManager.toggleGroupExpansion(mStatusBarNotification);
mOnExpandClickListener.onExpandClicked(mEntry, nowExpanded);
- mGroupExpansionChanging = true;
- updateBackgroundForGroupState();
MetricsLogger.action(mContext, MetricsEvent.ACTION_NOTIFICATION_GROUP_EXPANDER,
nowExpanded);
logExpansionEvent(true /* userAction */, wasExpanded);
} else {
+ if (v.isAccessibilityFocused()) {
+ mPrivateLayout.setFocusOnVisibilityChange();
+ }
boolean nowExpanded;
if (isPinned()) {
nowExpanded = !mExpandedWhenPinned;
@@ -181,6 +185,9 @@
}
};
private OnClickListener mOnClickListener;
+ private View mChildAfterViewWhenDismissed;
+ private View mGroupParentWhenDismissed;
+ private boolean mRefocusOnDismiss;
public boolean isGroupExpansionChanging() {
if (isChildInGroup()) {
@@ -717,8 +724,19 @@
}
}
- public void setDismissed(boolean dismissed) {
+ public void setDismissed(boolean dismissed, boolean fromAccessibility) {
mDismissed = dismissed;
+ mGroupParentWhenDismissed = mNotificationParent;
+ mRefocusOnDismiss = fromAccessibility;
+ mChildAfterViewWhenDismissed = null;
+ if (isChildInGroup()) {
+ List<ExpandableNotificationRow> notificationChildren =
+ mNotificationParent.getNotificationChildren();
+ int i = notificationChildren.indexOf(this);
+ if (i != -1 && i < notificationChildren.size() - 1) {
+ mChildAfterViewWhenDismissed = notificationChildren.get(i + 1);
+ }
+ }
}
public boolean isDismissed() {
@@ -750,6 +768,14 @@
return mChildrenContainer;
}
+ public View getChildAfterViewWhenDismissed() {
+ return mChildAfterViewWhenDismissed;
+ }
+
+ public View getGroupParentWhenDismissed() {
+ return mGroupParentWhenDismissed;
+ }
+
public interface ExpansionLogger {
public void logNotificationExpansion(String key, boolean userAction, boolean expanded);
}
@@ -1326,8 +1352,11 @@
private void updateClearability() {
// public versions cannot be dismissed
- mVetoButton.setVisibility(isClearable() && (!mShowingPublic
- || !mSensitiveHiddenInGeneral) ? View.VISIBLE : View.GONE);
+ mVetoButton.setVisibility(canViewBeDismissed() ? View.VISIBLE : View.GONE);
+ }
+
+ private boolean canViewBeDismissed() {
+ return isClearable() && (!mShowingPublic || !mSensitiveHiddenInGeneral);
}
public void makeActionsVisibile() {
@@ -1343,6 +1372,7 @@
if (mChildrenContainer != null) {
mChildrenContainer.setChildrenExpanded(expanded);
}
+ updateBackgroundForGroupState();
updateClickAndFocus();
}
@@ -1568,6 +1598,32 @@
}
}
+ @Override
+ public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
+ super.onInitializeAccessibilityNodeInfoInternal(info);
+ if (canViewBeDismissed()) {
+ info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_DISMISS);
+ }
+ }
+
+ @Override
+ public boolean performAccessibilityActionInternal(int action, Bundle arguments) {
+ if (super.performAccessibilityActionInternal(action, arguments)) {
+ return true;
+ }
+ switch (action) {
+ case AccessibilityNodeInfo.ACTION_DISMISS:
+ NotificationStackScrollLayout.performDismiss(this, mGroupManager,
+ true /* fromAccessibility */);
+ return true;
+ }
+ return false;
+ }
+
+ public boolean shouldRefocusOnDismiss() {
+ return mRefocusOnDismiss || isAccessibilityFocused();
+ }
+
public interface OnExpandClickListener {
void onExpandClicked(NotificationData.Entry clickedEntry, boolean nowExpanded);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
index a11263a..30ac9ca 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
@@ -29,6 +29,7 @@
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.widget.FrameLayout;
+import android.widget.ImageView;
import com.android.internal.util.NotificationColorUtil;
import com.android.systemui.R;
@@ -117,6 +118,7 @@
private PendingIntent mPreviousHeadsUpRemoteInputIntent;
private int mContentHeightAtAnimationStart = UNDEFINED;
+ private boolean mFocusOnVisibilityChange;
public NotificationContentView(Context context, AttributeSet attrs) {
@@ -395,6 +397,19 @@
}
}
+ private void focusExpandButtonIfNecessary() {
+ if (mFocusOnVisibilityChange) {
+ NotificationHeaderView header = getVisibleNotificationHeader();
+ if (header != null) {
+ ImageView expandButton = header.getExpandButton();
+ if (expandButton != null) {
+ expandButton.requestAccessibilityFocus();
+ }
+ }
+ mFocusOnVisibilityChange = false;
+ }
+ }
+
public void setContentHeight(int contentHeight) {
mContentHeight = Math.max(Math.min(contentHeight, getHeight()), getMinHeight());
selectLayout(mAnimate /* animate */, false /* force */);
@@ -584,7 +599,8 @@
updateContentTransformation();
} else {
int visibleType = calculateVisibleType();
- if (visibleType != mVisibleType || force) {
+ boolean changedType = visibleType != mVisibleType;
+ if (changedType || force) {
View visibleView = getViewForVisibleType(visibleType);
if (visibleView != null) {
visibleView.setVisibility(VISIBLE);
@@ -604,6 +620,9 @@
updateViewVisibilities(visibleType);
}
mVisibleType = visibleType;
+ if (changedType) {
+ focusExpandButtonIfNecessary();
+ }
updateBackgroundColor(animate);
}
}
@@ -1133,4 +1152,8 @@
mContentHeightAtAnimationStart = UNDEFINED;
}
}
+
+ public void setFocusOnVisibilityChange() {
+ mFocusOnVisibilityChange = true;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index 7c391fb..43f847c2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -769,7 +769,7 @@
mHeadsUpManager.addSwipedOutNotification(row.getStatusBarNotification().getKey());
}
}
- performDismiss(v);
+ performDismiss(v, mGroupManager, false /* fromAccessibility */);
mFalsingManager.onNotificationDismissed();
if (mFalsingManager.shouldEnforceBouncer()) {
@@ -778,17 +778,18 @@
}
}
- private void performDismiss(View v) {
+ public static void performDismiss(View v, NotificationGroupManager groupManager,
+ boolean fromAccessibility) {
if (v instanceof ExpandableNotificationRow) {
ExpandableNotificationRow row = (ExpandableNotificationRow) v;
- if (mGroupManager.isOnlyChildInSuppressedGroup(row.getStatusBarNotification())) {
+ if (groupManager.isOnlyChildInGroup(row.getStatusBarNotification())) {
ExpandableNotificationRow groupSummary =
- mGroupManager.getLogicalGroupSummary(row.getStatusBarNotification());
+ groupManager.getLogicalGroupSummary(row.getStatusBarNotification());
if (groupSummary.isClearable()) {
- performDismiss(groupSummary);
+ performDismiss(groupSummary, groupManager, fromAccessibility);
}
}
- row.setDismissed(true);
+ row.setDismissed(true, fromAccessibility);
}
final View veto = v.findViewById(R.id.veto);
if (veto != null && veto.getVisibility() != View.GONE) {
@@ -2265,6 +2266,27 @@
// Make sure the clipRect we might have set is removed
expandableView.setClipTopAmount(0);
+
+ focusNextViewIfFocused(child);
+ }
+
+ private void focusNextViewIfFocused(View view) {
+ if (view instanceof ExpandableNotificationRow) {
+ ExpandableNotificationRow row = (ExpandableNotificationRow) view;
+ if (row.shouldRefocusOnDismiss()) {
+ View nextView = row.getChildAfterViewWhenDismissed();
+ if (nextView == null) {
+ View groupParentWhenDismissed = row.getGroupParentWhenDismissed();
+ nextView = getFirstChildBelowTranlsationY(groupParentWhenDismissed != null
+ ? groupParentWhenDismissed.getTranslationY()
+ : view.getTranslationY());
+ }
+ if (nextView != null) {
+ nextView.requestAccessibilityFocus();
+ }
+ }
+ }
+
}
private boolean isChildInGroup(View child) {
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 41d8b4f..130fb7c 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -3417,10 +3417,6 @@
Slog.w(TAG, "User " + userId + " has no Vpn configuration");
return false;
}
- // If the current VPN package is the same as the new one, this is a no-op
- if (TextUtils.equals(packageName, vpn.getAlwaysOnPackage())) {
- return true;
- }
if (!vpn.setAlwaysOnPackage(packageName, lockdown)) {
return false;
}
diff --git a/services/core/java/com/android/server/LockSettingsService.java b/services/core/java/com/android/server/LockSettingsService.java
index eeb20bf..ef7b787 100644
--- a/services/core/java/com/android/server/LockSettingsService.java
+++ b/services/core/java/com/android/server/LockSettingsService.java
@@ -617,6 +617,7 @@
@Override
public boolean getSeparateProfileChallengeEnabled(int userId) throws RemoteException {
+ checkReadPermission(SEPARATE_PROFILE_CHALLENGE_KEY, userId);
synchronized (mSeparateChallengeLock) {
return getBoolean(SEPARATE_PROFILE_CHALLENGE_KEY, false, userId);
}
@@ -625,6 +626,7 @@
@Override
public void setSeparateProfileChallengeEnabled(int userId, boolean enabled,
String managedUserPassword) throws RemoteException {
+ checkWritePermission(userId);
synchronized (mSeparateChallengeLock) {
setBoolean(SEPARATE_PROFILE_CHALLENGE_KEY, enabled, userId);
if (enabled) {
@@ -672,7 +674,6 @@
@Override
public long getLong(String key, long defaultValue, int userId) throws RemoteException {
checkReadPermission(key, userId);
-
String value = getStringUnchecked(key, null, userId);
return TextUtils.isEmpty(value) ? defaultValue : Long.parseLong(value);
}
@@ -680,7 +681,6 @@
@Override
public String getString(String key, String defaultValue, int userId) throws RemoteException {
checkReadPermission(key, userId);
-
return getStringUnchecked(key, defaultValue, userId);
}
@@ -899,7 +899,7 @@
}
}
- public void setLockPatternInternal(String pattern, String savedCredential, int userId)
+ private void setLockPatternInternal(String pattern, String savedCredential, int userId)
throws RemoteException {
byte[] currentHandle = getCurrentHandle(userId);
@@ -962,7 +962,7 @@
}
}
- public void setLockPasswordInternal(String password, String savedCredential, int userId)
+ private void setLockPasswordInternal(String password, String savedCredential, int userId)
throws RemoteException {
byte[] currentHandle = getCurrentHandle(userId);
if (password == null) {
@@ -1156,6 +1156,7 @@
@Override
public void resetKeyStore(int userId) throws RemoteException {
+ checkWritePermission(userId);
if (DEBUG) Slog.v(TAG, "Reset keystore for user: " + userId);
int managedUserId = -1;
String managedUserDecryptedPassword = null;
@@ -1558,6 +1559,7 @@
LockPatternUtils.LOCK_PASSWORD_SALT_KEY,
LockPatternUtils.PASSWORD_HISTORY_KEY,
LockPatternUtils.PASSWORD_TYPE_KEY,
+ SEPARATE_PROFILE_CHALLENGE_KEY
};
private static final String[] SETTINGS_TO_BACKUP = new String[] {
@@ -1588,7 +1590,7 @@
}
final IBinder service =
- ServiceManager.getService("android.service.gatekeeper.IGateKeeperService");
+ ServiceManager.getService(Context.GATEKEEPER_SERVICE);
if (service != null) {
service.linkToDeath(new GateKeeperDiedRecipient(), 0);
mGateKeeperService = IGateKeeperService.Stub.asInterface(service);
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index 4084542..0cf5172 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -3425,7 +3425,7 @@
/** {@hide} */
@NonNull
public AccountAndUser[] getAllAccounts() {
- final List<UserInfo> users = getUserManager().getUsers();
+ final List<UserInfo> users = getUserManager().getUsers(true);
final int[] userIds = new int[users.size()];
for (int i = 0; i < userIds.length; i++) {
userIds[i] = users.get(i).id;
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 897aa20..09f24ed 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -2292,11 +2292,8 @@
final ActivityRecord r = (ActivityRecord) msg.obj;
final boolean needsVrMode = r != null && r.requestedVrComponent != null;
if (needsVrMode) {
- VrManagerInternal vrService =
- LocalServices.getService(VrManagerInternal.class);
- boolean enable = msg.arg1 == 1;
- vrService.setVrMode(enable, r.requestedVrComponent, r.userId,
- r.info.getComponentName());
+ applyVrMode(msg.arg1 == 1, r.requestedVrComponent, r.userId,
+ r.info.getComponentName(), false);
}
} break;
}
@@ -3084,6 +3081,17 @@
mHandler.obtainMessage(VR_MODE_APPLY_IF_NEEDED_MSG, enable ? 1 : 0, 0, r));
}
+ private void applyVrMode(boolean enabled, ComponentName packageName, int userId,
+ ComponentName callingPackage, boolean immediate) {
+ VrManagerInternal vrService =
+ LocalServices.getService(VrManagerInternal.class);
+ if (immediate) {
+ vrService.setVrModeImmediate(enabled, packageName, userId, callingPackage);
+ } else {
+ vrService.setVrMode(enabled, packageName, userId, callingPackage);
+ }
+ }
+
final void showAskCompatModeDialogLocked(ActivityRecord r) {
Message msg = Message.obtain();
msg.what = SHOW_COMPAT_MODE_DIALOG_UI_MSG;
@@ -21413,11 +21421,25 @@
public SleepToken acquireSleepToken(String tag) {
Preconditions.checkNotNull(tag);
+ ComponentName requestedVrService = null;
+ ComponentName callingVrActivity = null;
+ int userId = -1;
+ synchronized (ActivityManagerService.this) {
+ if (mFocusedActivity != null) {
+ requestedVrService = mFocusedActivity.requestedVrComponent;
+ callingVrActivity = mFocusedActivity.info.getComponentName();
+ userId = mFocusedActivity.userId;
+ }
+ }
+
+ if (requestedVrService != null) {
+ applyVrMode(false, requestedVrService, userId, callingVrActivity, true);
+ }
+
synchronized (ActivityManagerService.this) {
SleepTokenImpl token = new SleepTokenImpl(tag);
mSleepTokens.add(token);
updateSleepIfNeededLocked();
- applyVrModeIfNeededLocked(mFocusedActivity, false);
return token;
}
}
diff --git a/services/core/java/com/android/server/am/ActivityStartInterceptor.java b/services/core/java/com/android/server/am/ActivityStartInterceptor.java
index a2c2040..f26e47e 100644
--- a/services/core/java/com/android/server/am/ActivityStartInterceptor.java
+++ b/services/core/java/com/android/server/am/ActivityStartInterceptor.java
@@ -186,9 +186,13 @@
if (mActivityOptions == null) {
mActivityOptions = ActivityOptions.makeBasic();
}
- // Showing credential confirmation activity in home task to avoid stopping multi-windowed
- // mode after showing the full-screen credential confirmation activity.
- mActivityOptions.setLaunchTaskId(mSupervisor.getHomeActivity().task.taskId);
+
+ ActivityRecord homeActivityRecord = mSupervisor.getHomeActivity();
+ if (homeActivityRecord != null && homeActivityRecord.task != null) {
+ // Showing credential confirmation activity in home task to avoid stopping multi-windowed
+ // mode after showing the full-screen credential confirmation activity.
+ mActivityOptions.setLaunchTaskId(homeActivityRecord.task.taskId);
+ }
final UserInfo parent = mUserManager.getProfileParent(mUserId);
mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, parent.id);
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index ebacc71..ede3bda 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -259,28 +259,39 @@
*
* @param packageName the package to designate as always-on VPN supplier.
* @param lockdown whether to prevent traffic outside of a VPN, for example while connecting.
+ * @return {@code true} if the package has been set as always-on, {@code false} otherwise.
*/
public synchronized boolean setAlwaysOnPackage(String packageName, boolean lockdown) {
enforceControlPermissionOrInternalCaller();
+ if (VpnConfig.LEGACY_VPN.equals(packageName)) {
+ Log.w(TAG, "Not setting legacy VPN \"" + packageName + "\" as always-on.");
+ return false;
+ }
- // Disconnect current VPN.
- prepareInternal(VpnConfig.LEGACY_VPN);
-
- // Pre-authorize new always-on VPN package.
if (packageName != null) {
+ // Pre-authorize new always-on VPN package.
if (!setPackageAuthorization(packageName, true)) {
return false;
}
- prepareInternal(packageName);
+ mAlwaysOn = true;
+ } else {
+ packageName = VpnConfig.LEGACY_VPN;
+ mAlwaysOn = false;
}
- mAlwaysOn = (packageName != null);
mLockdown = (mAlwaysOn && lockdown);
+ if (!isCurrentPreparedPackage(packageName)) {
+ prepareInternal(packageName);
+ }
maybeRegisterPackageChangeReceiverLocked(packageName);
setVpnForcedLocked(mLockdown);
return true;
}
+ private static boolean isNullOrLegacyVpn(String packageName) {
+ return packageName == null || VpnConfig.LEGACY_VPN.equals(packageName);
+ }
+
private void unregisterPackageChangeReceiverLocked() {
// register previous intent filter
if (mIsPackageIntentReceiverRegistered) {
@@ -293,7 +304,7 @@
// Unregister IntentFilter listening for previous always-on package change
unregisterPackageChangeReceiverLocked();
- if (packageName != null) {
+ if (!isNullOrLegacyVpn(packageName)) {
mIsPackageIntentReceiverRegistered = true;
IntentFilter intentFilter = new IntentFilter();
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index f8ef3b2..ada0a6b 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -19352,10 +19352,18 @@
if ((flags & StorageManager.FLAG_STORAGE_DE) != 0 && !mOnlyCore) {
UserManagerService.enforceSerialNumber(
Environment.getDataUserDeDirectory(volumeUuid, userId), userSerial);
+ if (Objects.equals(volumeUuid, StorageManager.UUID_PRIVATE_INTERNAL)) {
+ UserManagerService.enforceSerialNumber(
+ Environment.getDataSystemDeDirectory(userId), userSerial);
+ }
}
if ((flags & StorageManager.FLAG_STORAGE_CE) != 0 && !mOnlyCore) {
UserManagerService.enforceSerialNumber(
Environment.getDataUserCeDirectory(volumeUuid, userId), userSerial);
+ if (Objects.equals(volumeUuid, StorageManager.UUID_PRIVATE_INTERNAL)) {
+ UserManagerService.enforceSerialNumber(
+ Environment.getDataSystemCeDirectory(userId), userSerial);
+ }
}
synchronized (mInstallLock) {
@@ -19424,6 +19432,10 @@
.listFilesOrEmpty(Environment.getDataUserDeDirectory(volumeUuid)));
Collections.addAll(files, FileUtils
.listFilesOrEmpty(Environment.getDataUserCeDirectory(volumeUuid)));
+ Collections.addAll(files, FileUtils
+ .listFilesOrEmpty(Environment.getDataSystemDeDirectory()));
+ Collections.addAll(files, FileUtils
+ .listFilesOrEmpty(Environment.getDataSystemCeDirectory()));
for (File file : files) {
if (!file.isDirectory()) continue;
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index a8cf110..a85064b 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -65,6 +65,8 @@
import android.os.UserManagerInternal;
import android.os.UserManagerInternal.UserRestrictionsListener;
import android.os.storage.StorageManager;
+import android.security.GateKeeper;
+import android.service.gatekeeper.IGateKeeperService;
import android.system.ErrnoException;
import android.system.Os;
import android.system.OsConstants;
@@ -87,6 +89,7 @@
import com.android.internal.util.XmlUtils;
import com.android.internal.widget.LockPatternUtils;
import com.android.server.LocalServices;
+import com.android.server.SystemService;
import com.android.server.am.UserState;
import libcore.io.IoUtils;
@@ -119,6 +122,7 @@
* </ul>
*/
public class UserManagerService extends IUserManager.Stub {
+
private static final String LOG_TAG = "UserManagerService";
static final boolean DBG = false; // DO NOT SUBMIT WITH TRUE
private static final boolean DBG_WITH_STACKTRACE = false; // DO NOT SUBMIT WITH TRUE
@@ -367,6 +371,31 @@
}
}
+ public static class LifeCycle extends SystemService {
+
+ private UserManagerService mUms;
+
+ /**
+ * @param context
+ */
+ public LifeCycle(Context context) {
+ super(context);
+ }
+
+ @Override
+ public void onStart() {
+ mUms = UserManagerService.getInstance();
+ publishBinderService(Context.USER_SERVICE, mUms);
+ }
+
+ @Override
+ public void onBootPhase(int phase) {
+ if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
+ mUms.cleanupPartialUsers();
+ }
+ }
+ }
+
@VisibleForTesting
UserManagerService(File dataDir) {
this(null, null, new Object(), dataDir);
@@ -408,25 +437,6 @@
}
void systemReady() {
- // Prune out any partially created, partially removed and ephemeral users.
- ArrayList<UserInfo> partials = new ArrayList<>();
- synchronized (mUsersLock) {
- final int userSize = mUsers.size();
- for (int i = 0; i < userSize; i++) {
- UserInfo ui = mUsers.valueAt(i).info;
- if ((ui.partial || ui.guestToRemove || ui.isEphemeral()) && i != 0) {
- partials.add(ui);
- }
- }
- }
- final int partialsSize = partials.size();
- for (int i = 0; i < partialsSize; i++) {
- UserInfo ui = partials.get(i);
- Slog.w(LOG_TAG, "Removing partially created user " + ui.id
- + " (name=" + ui.name + ")");
- removeUserState(ui.id);
- }
-
mAppOpsService = IAppOpsService.Stub.asInterface(
ServiceManager.getService(Context.APP_OPS_SERVICE));
@@ -447,6 +457,27 @@
null, mHandler);
}
+ void cleanupPartialUsers() {
+ // Prune out any partially created, partially removed and ephemeral users.
+ ArrayList<UserInfo> partials = new ArrayList<>();
+ synchronized (mUsersLock) {
+ final int userSize = mUsers.size();
+ for (int i = 0; i < userSize; i++) {
+ UserInfo ui = mUsers.valueAt(i).info;
+ if ((ui.partial || ui.guestToRemove || ui.isEphemeral()) && i != 0) {
+ partials.add(ui);
+ }
+ }
+ }
+ final int partialsSize = partials.size();
+ for (int i = 0; i < partialsSize; i++) {
+ UserInfo ui = partials.get(i);
+ Slog.w(LOG_TAG, "Removing partially created user " + ui.id
+ + " (name=" + ui.name + ")");
+ removeUserState(ui.id);
+ }
+ }
+
@Override
public String getUserAccount(int userId) {
checkManageUserAndAcrossUsersFullPermission("get user account");
@@ -2472,8 +2503,23 @@
"Destroying key for user " + userHandle + " failed, continuing anyway", e);
}
+ // Cleanup gatekeeper secure user id
+ try {
+ final IGateKeeperService gk = GateKeeper.getService();
+ if (gk != null) {
+ gk.clearSecureUserId(userHandle);
+ }
+ } catch (Exception ex) {
+ Slog.w(LOG_TAG, "unable to clear GK secure user id");
+ }
+
// Cleanup package manager settings
mPm.cleanUpUser(this, userHandle);
+
+ // Clean up all data before removing metadata
+ mPm.destroyUserData(userHandle,
+ StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE);
+
// Remove this user from the list
synchronized (mUsersLock) {
mUsers.remove(userHandle);
@@ -2496,12 +2542,6 @@
AtomicFile userFile = new AtomicFile(new File(mUsersDir, userHandle + XML_SUFFIX));
userFile.delete();
updateUserIds();
-
- // Now that we've purged all the metadata above, destroy the actual data
- // on disk; if we battery pull in here we'll finish cleaning up when
- // reconciling after reboot.
- mPm.destroyUserData(userHandle,
- StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE);
}
private void sendProfileRemovedBroadcast(int parentUserId, int removedUserId) {
diff --git a/services/core/java/com/android/server/vr/VrManagerInternal.java b/services/core/java/com/android/server/vr/VrManagerInternal.java
index 1bbb9f5..ad87a88 100644
--- a/services/core/java/com/android/server/vr/VrManagerInternal.java
+++ b/services/core/java/com/android/server/vr/VrManagerInternal.java
@@ -43,6 +43,9 @@
/**
* Set the current VR mode state.
+ * <p/>
+ * This may delay the mode change slightly during application transitions to avoid frequently
+ * tearing down VrListenerServices unless necessary.
*
* @param enabled {@code true} to enable VR mode.
* @param packageName The package name of the requested VrListenerService to bind.
@@ -52,6 +55,18 @@
public abstract void setVrMode(boolean enabled, @NonNull ComponentName packageName,
int userId, @NonNull ComponentName calling);
+ /**
+ * Set the current VR mode state immediately.
+ *
+ * @param enabled {@code true} to enable VR mode.
+ * @param packageName The package name of the requested VrListenerService to bind.
+ * @param userId the user requesting the VrListenerService component.
+ * @param calling the component currently using VR mode, or null to leave unchanged.
+ */
+ public abstract void setVrModeImmediate(boolean enabled, @NonNull ComponentName packageName,
+ int userId, @NonNull ComponentName calling);
+
+
/**
* Return NO_ERROR if the given package is installed on the device and enabled as a
* VrListenerService for the given current user, or a negative error code indicating a failure.
diff --git a/services/core/java/com/android/server/vr/VrManagerService.java b/services/core/java/com/android/server/vr/VrManagerService.java
index b4c4bd8..5fefd4c 100644
--- a/services/core/java/com/android/server/vr/VrManagerService.java
+++ b/services/core/java/com/android/server/vr/VrManagerService.java
@@ -218,7 +218,6 @@
String packageName = mNotificationAccessPackageToUserId.keyAt(i);
revokeNotificationListenerAccess(packageName, grantUserId);
revokeNotificationPolicyAccess(packageName);
- revokeCoarseLocationPermissionIfNeeded(packageName, grantUserId);
mNotificationAccessPackageToUserId.removeAt(i);
}
}
@@ -227,7 +226,6 @@
if (!packageNames.contains(pkg)) {
revokeNotificationListenerAccess(pkg, currentUserId);
revokeNotificationPolicyAccess(pkg);
- revokeCoarseLocationPermissionIfNeeded(pkg, currentUserId);
mNotificationAccessPackageToUserId.remove(pkg);
}
}
@@ -235,7 +233,6 @@
if (!allowed.contains(pkg)) {
grantNotificationPolicyAccess(pkg);
grantNotificationListenerAccess(pkg, currentUserId);
- grantCoarseLocationPermissionIfNeeded(pkg, currentUserId);
mNotificationAccessPackageToUserId.put(pkg, currentUserId);
}
}
@@ -373,7 +370,13 @@
@Override
public void setVrMode(boolean enabled, ComponentName packageName, int userId,
ComponentName callingPackage) {
- VrManagerService.this.setVrMode(enabled, packageName, userId, callingPackage);
+ VrManagerService.this.setVrMode(enabled, packageName, userId, callingPackage, false);
+ }
+
+ @Override
+ public void setVrModeImmediate(boolean enabled, ComponentName packageName, int userId,
+ ComponentName callingPackage) {
+ VrManagerService.this.setVrMode(enabled, packageName, userId, callingPackage, true);
}
@Override
@@ -754,22 +757,6 @@
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));
@@ -916,11 +903,11 @@
*/
private void setVrMode(boolean enabled, @NonNull ComponentName targetPackageName,
- int userId, @NonNull ComponentName callingPackage) {
+ int userId, @NonNull ComponentName callingPackage, boolean immediate) {
synchronized (mLock) {
- if (!enabled && mCurrentVrService != null) {
+ if (!enabled && mCurrentVrService != null && !immediate) {
// If we're transitioning out of VR mode, delay briefly to avoid expensive HAL calls
// and service bind/unbind in case we are immediately switching to another VR app.
if (mPendingState == null) {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
index 1ae1a77..b53933e 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
@@ -120,7 +120,7 @@
// First, try to read from the legacy file.
final File legacy = getLegacyConfigFileWithTestOverride();
- final List<UserInfo> users = mUserManager.getUsers();
+ final List<UserInfo> users = mUserManager.getUsers(true);
if (readLegacyOwnerFileLocked(legacy)) {
if (DEBUG) {
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 476a559..f59b2ff 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -470,7 +470,7 @@
}
traceBeginAndSlog("StartUserManagerService");
- ServiceManager.addService(Context.USER_SERVICE, UserManagerService.getInstance());
+ mSystemServiceManager.startService(UserManagerService.LifeCycle.class);
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
// Initialize attribute cache used to cache resources from packages.
diff --git a/telecomm/java/android/telecom/Conference.java b/telecomm/java/android/telecom/Conference.java
index 9fcbfe3..0227d27 100644
--- a/telecomm/java/android/telecom/Conference.java
+++ b/telecomm/java/android/telecom/Conference.java
@@ -82,6 +82,7 @@
private StatusHints mStatusHints;
private Bundle mExtras;
private Set<String> mPreviousExtraKeys;
+ private final Object mExtrasLock = new Object();
private final Connection.Listener mConnectionDeathListener = new Connection.Listener() {
@Override
@@ -686,32 +687,35 @@
* @param extras The extras associated with this {@code Conference}.
*/
public final void setExtras(@Nullable Bundle extras) {
- // Add/replace any new or changed extras values.
- putExtras(extras);
+ // Keeping putExtras and removeExtras in the same lock so that this operation happens as a
+ // block instead of letting other threads put/remove while this method is running.
+ synchronized (mExtrasLock) {
+ // Add/replace any new or changed extras values.
+ putExtras(extras);
+ // If we have used "setExtras" in the past, compare the key set from the last invocation
+ // to the current one and remove any keys that went away.
+ if (mPreviousExtraKeys != null) {
+ List<String> toRemove = new ArrayList<String>();
+ for (String oldKey : mPreviousExtraKeys) {
+ if (extras == null || !extras.containsKey(oldKey)) {
+ toRemove.add(oldKey);
+ }
+ }
- // If we have used "setExtras" in the past, compare the key set from the last invocation to
- // the current one and remove any keys that went away.
- if (mPreviousExtraKeys != null) {
- List<String> toRemove = new ArrayList<String>();
- for (String oldKey : mPreviousExtraKeys) {
- if (extras == null || !extras.containsKey(oldKey)) {
- toRemove.add(oldKey);
+ if (!toRemove.isEmpty()) {
+ removeExtras(toRemove);
}
}
- if (!toRemove.isEmpty()) {
- removeExtras(toRemove);
+ // Track the keys the last time set called setExtras. This way, the next time setExtras
+ // is called we can see if the caller has removed any extras values.
+ if (mPreviousExtraKeys == null) {
+ mPreviousExtraKeys = new ArraySet<String>();
}
- }
-
- // Track the keys the last time set called setExtras. This way, the next time setExtras is
- // called we can see if the caller has removed any extras values.
- if (mPreviousExtraKeys == null) {
- mPreviousExtraKeys = new ArraySet<String>();
- }
- mPreviousExtraKeys.clear();
- if (extras != null) {
- mPreviousExtraKeys.addAll(extras.keySet());
+ mPreviousExtraKeys.clear();
+ if (extras != null) {
+ mPreviousExtraKeys.addAll(extras.keySet());
+ }
}
}
@@ -730,13 +734,19 @@
return;
}
- if (mExtras == null) {
- mExtras = new Bundle();
+ // Creating a Bundle clone so we don't have to synchronize on mExtrasLock while calling
+ // onExtrasChanged.
+ Bundle listenersBundle;
+ synchronized (mExtrasLock) {
+ if (mExtras == null) {
+ mExtras = new Bundle();
+ }
+ mExtras.putAll(extras);
+ listenersBundle = new Bundle(mExtras);
}
- mExtras.putAll(extras);
for (Listener l : mListeners) {
- l.onExtrasChanged(this, extras);
+ l.onExtrasChanged(this, new Bundle(listenersBundle));
}
}
@@ -790,17 +800,17 @@
return;
}
- if (mExtras != null) {
- for (String key : keys) {
- mExtras.remove(key);
- }
- if (mExtras.size() == 0) {
- mExtras = null;
+ synchronized (mExtrasLock) {
+ if (mExtras != null) {
+ for (String key : keys) {
+ mExtras.remove(key);
+ }
}
}
+ List<String> unmodifiableKeys = Collections.unmodifiableList(keys);
for (Listener l : mListeners) {
- l.onExtrasRemoved(this, keys);
+ l.onExtrasRemoved(this, unmodifiableKeys);
}
}
@@ -833,7 +843,13 @@
* @hide
*/
final void handleExtrasChanged(Bundle extras) {
- mExtras = extras;
- onExtrasChanged(mExtras);
+ Bundle b = null;
+ synchronized (mExtrasLock) {
+ mExtras = extras;
+ if (mExtras != null) {
+ b = new Bundle(mExtras);
+ }
+ }
+ onExtrasChanged(b);
}
}
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index ef314f3..ff220f3 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -1239,6 +1239,7 @@
private Conference mConference;
private ConnectionService mConnectionService;
private Bundle mExtras;
+ private final Object mExtrasLock = new Object();
/**
* Tracks the key set for the extras bundle provided on the last invocation of
@@ -1388,7 +1389,13 @@
* @return The extras associated with this connection.
*/
public final Bundle getExtras() {
- return mExtras;
+ Bundle extras = null;
+ synchronized (mExtrasLock) {
+ if (mExtras != null) {
+ extras = new Bundle(mExtras);
+ }
+ }
+ return extras;
}
/**
@@ -1924,14 +1931,20 @@
if (extras == null) {
return;
}
-
- if (mExtras == null) {
- mExtras = new Bundle();
+ // Creating a duplicate bundle so we don't have to synchronize on mExtrasLock while calling
+ // the listeners.
+ Bundle listenerExtras;
+ synchronized (mExtrasLock) {
+ if (mExtras == null) {
+ mExtras = new Bundle();
+ }
+ mExtras.putAll(extras);
+ listenerExtras = new Bundle(mExtras);
}
- mExtras.putAll(extras);
-
for (Listener l : mListeners) {
- l.onExtrasChanged(this, extras);
+ // Create a new clone of the extras for each listener so that they don't clobber
+ // each other
+ l.onExtrasChanged(this, new Bundle(listenerExtras));
}
}
@@ -1981,18 +1994,16 @@
* @hide
*/
public final void removeExtras(List<String> keys) {
- if (mExtras != null) {
- for (String key : keys) {
- mExtras.remove(key);
- }
-
- if (mExtras.size() == 0) {
- mExtras = null;
+ synchronized (mExtrasLock) {
+ if (mExtras != null) {
+ for (String key : keys) {
+ mExtras.remove(key);
+ }
}
}
-
+ List<String> unmodifiableKeys = Collections.unmodifiableList(keys);
for (Listener l : mListeners) {
- l.onExtrasRemoved(this, keys);
+ l.onExtrasRemoved(this, unmodifiableKeys);
}
}
@@ -2274,8 +2285,14 @@
* @hide
*/
final void handleExtrasChanged(Bundle extras) {
- mExtras = extras;
- onExtrasChanged(mExtras);
+ Bundle b = null;
+ synchronized (mExtrasLock) {
+ mExtras = extras;
+ if (mExtras != null) {
+ b = new Bundle(mExtras);
+ }
+ }
+ onExtrasChanged(b);
}
/**