Merge "Fix realCallingUid/Pid for startActivities()" into nyc-mr1-dev
diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java
index b8b7c55..8f908fb 100644
--- a/core/java/android/widget/ListView.java
+++ b/core/java/android/widget/ListView.java
@@ -2050,6 +2050,8 @@
p.recycledHeaderFooter = true;
}
addViewInLayout(child, flowDown ? -1 : 0, p, true);
+ // add view in layout will reset the RTL properties. We have to re-resolve them
+ child.resolveRtlPropertiesIfNeeded();
}
if (needToMeasure) {
diff --git a/docs/html/guide/topics/media/camera.jd b/docs/html/guide/topics/media/camera.jd
index 8b79b23..c806c88 100644
--- a/docs/html/guide/topics/media/camera.jd
+++ b/docs/html/guide/topics/media/camera.jd
@@ -1243,7 +1243,7 @@
camera application that checks to see if device hardware supports those features and fails
gracefully if a feature is not available.</p>
-<p>You can check the availabilty of camera features by getting an instance of a camera’s parameters
+<p>You can check the availabilty of camera features by getting an instance of a camera's parameters
object, and checking the relevant methods. The following code sample shows you how to obtain a
{@link android.hardware.Camera.Parameters} object and check if the camera supports the autofocus
feature:</p>
@@ -1290,7 +1290,7 @@
<p>This technique works for nearly all camera features, and most parameters can be changed at any
time after you have obtained an instance of the {@link android.hardware.Camera} object. Changes to
-parameters are typically visible to the user immediately in the application’s camera preview.
+parameters are typically visible to the user immediately in the application's camera preview.
On the software side, parameter changes may take several frames to actually take effect as the
camera hardware processes the new instructions and then sends updated image data.</p>
@@ -1341,7 +1341,7 @@
</pre>
<p>The {@link android.hardware.Camera.Area} object contains two data parameters: A {@link
-android.graphics.Rect} object for specifying an area within the camera’s field of view and a weight
+android.graphics.Rect} object for specifying an area within the camera's field of view and a weight
value, which tells the camera what level of importance this area should be given in light metering
or focus calculations.</p>
@@ -1405,7 +1405,7 @@
}
</pre>
-<p>After creating this class, you then set it into your application’s
+<p>After creating this class, you then set it into your application's
{@link android.hardware.Camera} object, as shown in the example code below:</p>
<pre>
@@ -1480,7 +1480,7 @@
<p class="note"><strong>Note:</strong> Remember to call this method <em>after</em> calling
{@link android.hardware.Camera#startPreview startPreview()}. Do not attempt to start face detection
-in the {@link android.app.Activity#onCreate onCreate()} method of your camera app’s main activity,
+in the {@link android.app.Activity#onCreate onCreate()} method of your camera app's main activity,
as the preview is not available by this point in your application's the execution.</p>
diff --git a/docs/html/guide/topics/ui/accessibility/apps.jd b/docs/html/guide/topics/ui/accessibility/apps.jd
index 26fb3cc..ab8c792 100644
--- a/docs/html/guide/topics/ui/accessibility/apps.jd
+++ b/docs/html/guide/topics/ui/accessibility/apps.jd
@@ -160,7 +160,7 @@
{@code android:focusable}</a> attribute is set to {@code true}. This setting allows users to focus
on the element using the directional controls and then interact with it. The user interface controls
provided by the Android framework are focusable by default and visually indicate focus by changing
-the control’s appearance.</p>
+the control's appearance.</p>
<p>Android provides several APIs that let you control whether a user interface control is focusable
and even request that a control be given focus:</p>
@@ -436,7 +436,7 @@
<h3 id="populate-events">Populating accessibility events</h3>
<p>Each {@link android.view.accessibility.AccessibilityEvent} has a set of required properties that
-describe the current state of the view. These properties include things such as the view’s class
+describe the current state of the view. These properties include things such as the view's class
name, content description and checked state. The specific properties required for each event type
are described in the {@link android.view.accessibility.AccessibilityEvent} reference documentation.
The {@link android.view.View} implementation provides default values for these properties. Many of
diff --git a/docs/html/guide/topics/ui/accessibility/services.jd b/docs/html/guide/topics/ui/accessibility/services.jd
index f91a979..c6db855 100644
--- a/docs/html/guide/topics/ui/accessibility/services.jd
+++ b/docs/html/guide/topics/ui/accessibility/services.jd
@@ -124,7 +124,7 @@
</service>
</pre>
-<p>This meta-data element refers to an XML file that you create in your application’s resource
+<p>This meta-data element refers to an XML file that you create in your application's resource
directory ({@code <project_dir>/res/xml/accessibility_service_config.xml}). The following code
shows example contents for the service configuration file:</p>
@@ -267,7 +267,7 @@
accessibility services to provide more useful feedback to users.</p>
<p>An accessibility service gets information about an user interface event through an {@link
-android.view.accessibility.AccessibilityEvent} passed by the system to the service’s
+android.view.accessibility.AccessibilityEvent} passed by the system to the service's
{@link android.accessibilityservice.AccessibilityService#onAccessibilityEvent
onAccessibilityEvent()} callback method. This object provides details about the event, including the
type of object being acted upon, its descriptive text and other details. Starting in Android 4.0
@@ -335,7 +335,7 @@
of a user. This feature, added in Android 4.1 (API Level 16), and requires that your
accessibility service request activation of the Explore by Touch feature. Your service can
request this activation by setting the
- {@link android.accessibilityservice.AccessibilityServiceInfo#flags flags} member of the service’s
+ {@link android.accessibilityservice.AccessibilityServiceInfo#flags flags} member of the service's
{@link android.accessibilityservice.AccessibilityServiceInfo} instance to
{@link android.accessibilityservice.AccessibilityServiceInfo#FLAG_REQUEST_TOUCH_EXPLORATION_MODE},
as shown in the following example.
diff --git a/docs/html/guide/topics/ui/index.jd b/docs/html/guide/topics/ui/index.jd
index ccdf200..7dbc015 100644
--- a/docs/html/guide/topics/ui/index.jd
+++ b/docs/html/guide/topics/ui/index.jd
@@ -13,7 +13,7 @@
<a href="http://android-developers.blogspot.com/2012/01/say-goodbye-to-menu-button.html">
<h4>Say Goodbye to the Menu Button</h4>
- <p>As Ice Cream Sandwich rolls out to more devices, it’s important that you begin to migrate
+ <p>As Ice Cream Sandwich rolls out to more devices, it's important that you begin to migrate
your designs to the action bar in order to promote a consistent Android user experience.</p> </a>
<a href="http://android-developers.blogspot.com/2011/11/new-layout-widgets-space-and-gridlayout.html">
@@ -29,7 +29,7 @@
<a href="http://android-developers.blogspot.com/2011/08/horizontal-view-swiping-with-viewpager.html">
<h4>Horizontal View Swiping with ViewPager</h4>
<p>Whether you have just started out in Android app development or are a veteran of the craft,
-it probably won’t be too long before you’ll need to implement horizontally scrolling sets of views.
+it probably won't be too long before you'll need to implement horizontally scrolling sets of views.
</p> </a>
</div>
diff --git a/docs/html/guide/topics/ui/settings.jd b/docs/html/guide/topics/ui/settings.jd
index 9e304a3..619fd26 100644
--- a/docs/html/guide/topics/ui/settings.jd
+++ b/docs/html/guide/topics/ui/settings.jd
@@ -943,8 +943,8 @@
<p>The Android framework includes a variety of {@link android.preference.Preference} subclasses that
allow you to build a UI for several different types of settings.
-However, you might discover a setting you need for which there’s no built-in solution, such as a
-number picker or date picker. In such a case, you’ll need to create a custom preference by extending
+However, you might discover a setting you need for which there's no built-in solution, such as a
+number picker or date picker. In such a case, you'll need to create a custom preference by extending
the {@link android.preference.Preference} class or one of the other subclasses.</p>
<p>When you extend the {@link android.preference.Preference} class, there are a few important
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index b907be0..54c36e1 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -12302,6 +12302,9 @@
public void run() {
for (int i = 0; i < mRunningInstalls.size(); i++) {
final PostInstallData data = mRunningInstalls.valueAt(i);
+ if (data.res.returnCode != PackageManager.INSTALL_SUCCEEDED) {
+ continue;
+ }
if (pkgName.equals(data.res.pkg.applicationInfo.packageName)) {
// right package; but is it for the right user?
for (int uIndex = 0; uIndex < data.res.newUsers.length; uIndex++) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 5787bdb..e5ddfd0 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -1236,7 +1236,7 @@
PackageInstaller.STATUS_FAILURE);
if (status == PackageInstaller.STATUS_SUCCESS) {
if (logSuccess) {
- System.out.println("Success");
+ pw.println("Success");
}
} else {
pw.println("Failure ["
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index 185a6a2..93693ce 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -131,12 +131,8 @@
* - getIconMaxWidth()/getIconMaxHeight() should use xdpi and ydpi.
* -> But TypedValue.applyDimension() doesn't differentiate x and y..?
*
- * - Default launcher check does take a few ms. Worth caching.
- *
* - Detect when already registered instances are passed to APIs again, which might break
* internal bitmap handling.
- *
- * - Add more call stats.
*/
public class ShortcutService extends IShortcutService.Stub {
static final String TAG = "ShortcutService";
@@ -1354,16 +1350,21 @@
}
private void enforceSystemOrShell() {
- Preconditions.checkState(isCallerSystem() || isCallerShell(),
- "Caller must be system or shell");
+ if (!(isCallerSystem() || isCallerShell())) {
+ throw new SecurityException("Caller must be system or shell");
+ }
}
private void enforceShell() {
- Preconditions.checkState(isCallerShell(), "Caller must be shell");
+ if (!isCallerShell()) {
+ throw new SecurityException("Caller must be shell");
+ }
}
private void enforceSystem() {
- Preconditions.checkState(isCallerSystem(), "Caller must be system");
+ if (!isCallerSystem()) {
+ throw new SecurityException("Caller must be system");
+ }
}
private void enforceResetThrottlingPermission() {
@@ -3177,9 +3178,13 @@
enforceShell();
- final int status = (new MyShellCommand()).exec(this, in, out, err, args, resultReceiver);
-
- resultReceiver.send(status, null);
+ final long token = injectClearCallingIdentity();
+ try {
+ final int status = (new MyShellCommand()).exec(this, in, out, err, args, resultReceiver);
+ resultReceiver.send(status, null);
+ } finally {
+ injectRestoreCallingIdentity(token);
+ }
}
static class CommandException extends Exception {
@@ -3224,9 +3229,6 @@
final PrintWriter pw = getOutPrintWriter();
try {
switch (cmd) {
- case "reset-package-throttling":
- handleResetPackageThrottling();
- break;
case "reset-throttling":
handleResetThrottling();
break;
@@ -3245,9 +3247,6 @@
case "get-default-launcher":
handleGetDefaultLauncher();
break;
- case "refresh-default-launcher":
- handleRefreshDefaultLauncher();
- break;
case "unload-user":
handleUnloadUser();
break;
@@ -3273,9 +3272,6 @@
final PrintWriter pw = getOutPrintWriter();
pw.println("Usage: cmd shortcut COMMAND [options ...]");
pw.println();
- pw.println("cmd shortcut reset-package-throttling [--user USER_ID] PACKAGE");
- pw.println(" Reset throttling for a package");
- pw.println();
pw.println("cmd shortcut reset-throttling [--user USER_ID]");
pw.println(" Reset throttling for all packages and users");
pw.println();
@@ -3292,10 +3288,7 @@
pw.println(" Clear the cached default launcher");
pw.println();
pw.println("cmd shortcut get-default-launcher [--user USER_ID]");
- pw.println(" Show the cached default launcher");
- pw.println();
- pw.println("cmd shortcut refresh-default-launcher [--user USER_ID]");
- pw.println(" Refresh the cached default launcher");
+ pw.println(" Show the default launcher");
pw.println();
pw.println("cmd shortcut unload-user [--user USER_ID]");
pw.println(" Unload a user from the memory");
@@ -3309,7 +3302,7 @@
private void handleResetThrottling() throws CommandException {
parseOptions(/* takeUser =*/ true);
- Slog.i(TAG, "cmd: handleResetThrottling");
+ Slog.i(TAG, "cmd: handleResetThrottling: user=" + mUserId);
resetThrottlingInner(mUserId);
}
@@ -3320,16 +3313,6 @@
resetAllThrottlingInner();
}
- private void handleResetPackageThrottling() throws CommandException {
- parseOptions(/* takeUser =*/ true);
-
- final String packageName = getNextArgRequired();
-
- Slog.i(TAG, "cmd: handleResetPackageThrottling: " + packageName);
-
- resetPackageThrottling(packageName, mUserId);
- }
-
private void handleOverrideConfig() throws CommandException {
final String config = getNextArgRequired();
@@ -3375,12 +3358,6 @@
private void handleGetDefaultLauncher() throws CommandException {
parseOptions(/* takeUser =*/ true);
- showLauncher();
- }
-
- private void handleRefreshDefaultLauncher() throws CommandException {
- parseOptions(/* takeUser =*/ true);
-
clearLauncher();
showLauncher();
}
@@ -3388,7 +3365,7 @@
private void handleUnloadUser() throws CommandException {
parseOptions(/* takeUser =*/ true);
- Slog.i(TAG, "cmd: handleUnloadUser: " + mUserId);
+ Slog.i(TAG, "cmd: handleUnloadUser: user=" + mUserId);
ShortcutService.this.handleCleanupUser(mUserId);
}
@@ -3397,7 +3374,7 @@
parseOptions(/* takeUser =*/ true);
final String packageName = getNextArgRequired();
- Slog.i(TAG, "cmd: handleClearShortcuts: " + mUserId + ", " + packageName);
+ Slog.i(TAG, "cmd: handleClearShortcuts: user" + mUserId + ", " + packageName);
ShortcutService.this.cleanUpPackageForAllLoadedUsers(packageName, mUserId,
/* appStillExists = */ true);
diff --git a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
index ff1c3b6..ecebbc4 100644
--- a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
@@ -614,6 +614,14 @@
protected final Map<Integer, Boolean> mRunningUsers = new HashMap<>();
protected final Map<Integer, Boolean> mUnlockedUsers = new HashMap<>();
+ protected static final String PACKAGE_SYSTEM_LAUNCHER = "com.android.systemlauncher";
+ protected static final String PACKAGE_SYSTEM_LAUNCHER_NAME = "systemlauncher_name";
+ protected static final int PACKAGE_SYSTEM_LAUNCHER_PRIORITY = 0;
+
+ protected static final String PACKAGE_FALLBACK_LAUNCHER = "com.android.settings";
+ protected static final String PACKAGE_FALLBACK_LAUNCHER_NAME = "fallback";
+ protected static final int PACKAGE_FALLBACK_LAUNCHER_PRIORITY = -999;
+
static {
QUERY_ALL.setQueryFlags(
ShortcutQuery.FLAG_GET_ALL_KINDS);
@@ -1866,4 +1874,40 @@
}
return sb.toString();
}
+
+ protected void prepareGetHomeActivitiesAsUser(ComponentName preferred,
+ List<ResolveInfo> candidates, int userId) {
+ doAnswer(inv -> {
+ ((List) inv.getArguments()[0]).addAll(candidates);
+ return preferred;
+ }).when(mMockPackageManagerInternal).getHomeActivitiesAsUser(any(List.class), eq(userId));
+ }
+
+ protected static ComponentName cn(String packageName, String name) {
+ return new ComponentName(packageName, name);
+ }
+
+ protected static ResolveInfo ri(String packageName, String name, boolean isSystem, int priority) {
+ final ResolveInfo ri = new ResolveInfo();
+ ri.activityInfo = new ActivityInfo();
+ ri.activityInfo.applicationInfo = new ApplicationInfo();
+
+ ri.activityInfo.packageName = packageName;
+ ri.activityInfo.name = name;
+ if (isSystem) {
+ ri.activityInfo.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
+ }
+ ri.priority = priority;
+ return ri;
+ }
+
+ protected static ResolveInfo getSystemLauncher() {
+ return ri(PACKAGE_SYSTEM_LAUNCHER, PACKAGE_SYSTEM_LAUNCHER_NAME, true,
+ PACKAGE_SYSTEM_LAUNCHER_PRIORITY);
+ }
+
+ protected static ResolveInfo getFallbackLauncher() {
+ return ri(PACKAGE_FALLBACK_LAUNCHER, PACKAGE_FALLBACK_LAUNCHER_NAME, true,
+ PACKAGE_FALLBACK_LAUNCHER_PRIORITY);
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
index 5206507..82ccd36 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
@@ -107,15 +107,6 @@
-r -g ${ANDROID_PRODUCT_OUT}/data/app/FrameworksServicesTests/FrameworksServicesTests.apk &&
adb shell am instrument -e class com.android.server.pm.ShortcutManagerTest1 \
-w com.android.frameworks.servicestests/android.support.test.runner.AndroidJUnitRunner
-
-
- * TODO More tests for pinning + manifest shortcuts
- * TODO Manifest shortcuts + app upgrade -> launcher callback.
- * Also locale change should trigger launcehr callbacks too, when they use strign resoucres.
- * (not implemented yet.)
- * TODO: Add checks with assertAllNotHaveIcon()
- * TODO: Detailed test for hasShortcutPermissionInner().
- * TODO: Add tests for the command line functions too.
*/
@SmallTest
public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
@@ -4068,7 +4059,7 @@
});
// Clear data
- mService.mPackageMonitor.onReceive(getTestContext(),
+ mService.mPackageMonitor.onReceive(getTestContext(),
genPackageDataClear(CALLING_PACKAGE_1, USER_10));
// Only manifest shortcuts will remain, and are no longer pinned.
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest6.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest6.java
index ffb2953..5f24637 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest6.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest6.java
@@ -18,7 +18,6 @@
import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.list;
import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.doAnswer;
@@ -36,51 +35,6 @@
*/
@SmallTest
public class ShortcutManagerTest6 extends BaseShortcutManagerTest {
-
- private static final String PACKAGE_SYSTEM_LAUNCHER = "com.android.systemlauncher";
- private static final String PACKAGE_SYSTEM_LAUNCHER_NAME = "systemlauncher_name";
- private static final int PACKAGE_SYSTEM_LAUNCHER_PRIORITY = 0;
-
- private static final String PACKAGE_FALLBACK_LAUNCHER = "com.android.settings";
- private static final String PACKAGE_FALLBACK_LAUNCHER_NAME = "fallback";
- private static final int PACKAGE_FALLBACK_LAUNCHER_PRIORITY = -999;
-
- private void prepareGetHomeActivitiesAsUser(ComponentName preferred,
- List<ResolveInfo> candidates, int userId) {
- doAnswer(inv -> {
- ((List) inv.getArguments()[0]).addAll(candidates);
- return preferred;
- }).when(mMockPackageManagerInternal).getHomeActivitiesAsUser(any(List.class), eq(userId));
- }
-
- private static ComponentName cn(String packageName, String name) {
- return new ComponentName(packageName, name);
- }
-
- private static ResolveInfo ri(String packageName, String name, boolean isSystem, int priority) {
- final ResolveInfo ri = new ResolveInfo();
- ri.activityInfo = new ActivityInfo();
- ri.activityInfo.applicationInfo = new ApplicationInfo();
-
- ri.activityInfo.packageName = packageName;
- ri.activityInfo.name = name;
- if (isSystem) {
- ri.activityInfo.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
- }
- ri.priority = priority;
- return ri;
- }
-
- private static ResolveInfo getSystemLauncher() {
- return ri(PACKAGE_SYSTEM_LAUNCHER, PACKAGE_SYSTEM_LAUNCHER_NAME, true,
- PACKAGE_SYSTEM_LAUNCHER_PRIORITY);
- }
-
- private static ResolveInfo getFallbackLauncher() {
- return ri(PACKAGE_FALLBACK_LAUNCHER, PACKAGE_FALLBACK_LAUNCHER_NAME, true,
- PACKAGE_FALLBACK_LAUNCHER_PRIORITY);
- }
-
public void testHasShortcutHostPermissionInner_systemLauncherOnly() {
// Preferred isn't set, use the system launcher.
prepareGetHomeActivitiesAsUser(
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest7.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest7.java
new file mode 100644
index 0000000..f9ff514
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest7.java
@@ -0,0 +1,335 @@
+/*
+ * 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 static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertContains;
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertExpectException;
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertSuccess;
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertWith;
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.list;
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.readAll;
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.resultContains;
+
+import android.content.ComponentName;
+import android.os.Bundle;
+import android.os.ParcelFileDescriptor;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.ResultReceiver;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import com.android.frameworks.servicestests.R;
+import com.android.server.pm.ShortcutService.ConfigConstants;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * Unit test for "cmd shortcut"
+ *
+ * Launcher related commands are tested in
+ */
+@SmallTest
+public class ShortcutManagerTest7 extends BaseShortcutManagerTest {
+ private List<String> callShellCommand(String... args) throws IOException, RemoteException {
+
+ // For reset to work, the current time needs to be incrementing.
+ mInjectedCurrentTimeMillis++;
+
+ final AtomicInteger resultCode = new AtomicInteger(Integer.MIN_VALUE);
+
+ final ResultReceiver rr = new ResultReceiver(mHandler) {
+ @Override
+ public void send(int resultCode_, Bundle resultData) {
+ resultCode.set(resultCode_);
+ }
+ };
+ final File out = File.createTempFile("shellout-", ".tmp",
+ getTestContext().getCacheDir());
+ try {
+ try (final ParcelFileDescriptor fd = ParcelFileDescriptor.open(out,
+ ParcelFileDescriptor.MODE_READ_WRITE)) {
+ mService.onShellCommand(
+ /* fdin*/ null,
+ /* fdout*/ fd.getFileDescriptor(),
+ /* fderr*/ fd.getFileDescriptor(),
+ args, rr);
+ }
+ return readAll(out);
+ } finally {
+ out.delete();
+ }
+ }
+
+ public void testNonShell() throws Exception {
+ mService.mMaxUpdatesPerInterval = 99;
+
+ mInjectedCallingUid = 12345;
+ assertExpectException(SecurityException.class, "must be shell",
+ () -> callShellCommand("reset-config"));
+
+ mInjectedCallingUid = Process.SYSTEM_UID;
+ assertExpectException(SecurityException.class, "must be shell",
+ () -> callShellCommand("reset-config"));
+
+ assertEquals(99, mService.mMaxUpdatesPerInterval);
+ }
+
+ public void testRoot() throws Exception {
+ mService.mMaxUpdatesPerInterval = 99;
+
+ mInjectedCallingUid = Process.ROOT_UID;
+ assertSuccess(callShellCommand("reset-config"));
+
+ assertEquals(3, mService.mMaxUpdatesPerInterval);
+ }
+
+ public void testRestConfig() throws Exception {
+ mService.mMaxUpdatesPerInterval = 99;
+
+ mInjectedCallingUid = Process.SHELL_UID;
+ assertSuccess(callShellCommand("reset-config"));
+
+ assertEquals(3, mService.mMaxUpdatesPerInterval);
+ }
+
+ public void testOverrideConfig() throws Exception {
+ mService.mMaxUpdatesPerInterval = 99;
+
+ mInjectedCallingUid = Process.SHELL_UID;
+ assertSuccess(callShellCommand("override-config",
+ ConfigConstants.KEY_MAX_UPDATES_PER_INTERVAL + "=1"));
+
+ assertEquals(1, mService.mMaxUpdatesPerInterval);
+ }
+
+ public void testResetThrottling() throws Exception {
+ prepareCrossProfileDataSet();
+
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ assertTrue(mManager.getRemainingCallCount() < 3);
+ });
+ runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
+ assertTrue(mManager.getRemainingCallCount() < 3);
+ });
+
+ mInjectedCallingUid = Process.SHELL_UID;
+ assertSuccess(callShellCommand("reset-throttling"));
+
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ assertEquals(3, mManager.getRemainingCallCount());
+ });
+ runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
+ assertTrue(mManager.getRemainingCallCount() < 3);
+ });
+ }
+
+ public void testResetThrottling_user_not_running() throws Exception {
+ prepareCrossProfileDataSet();
+
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ assertTrue(mManager.getRemainingCallCount() < 3);
+ });
+ runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
+ assertTrue(mManager.getRemainingCallCount() < 3);
+ });
+
+ mInjectedCallingUid = Process.SHELL_UID;
+
+ assertTrue(resultContains(
+ callShellCommand("reset-throttling", "--user", "10"),
+ "User 10 is not running or locked"));
+
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ assertTrue(mManager.getRemainingCallCount() < 3);
+ });
+ runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
+ assertTrue(mManager.getRemainingCallCount() < 3);
+ });
+ }
+
+ public void testResetThrottling_user_running() throws Exception {
+ prepareCrossProfileDataSet();
+
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ assertTrue(mManager.getRemainingCallCount() < 3);
+ });
+ runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
+ assertTrue(mManager.getRemainingCallCount() < 3);
+ });
+
+ mRunningUsers.put(USER_10, true);
+ mUnlockedUsers.put(USER_10, true);
+
+ mInjectedCallingUid = Process.SHELL_UID;
+ assertSuccess(callShellCommand("reset-throttling", "--user", "10"));
+
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ assertTrue(mManager.getRemainingCallCount() < 3);
+ });
+ runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
+ assertEquals(3, mManager.getRemainingCallCount());
+ });
+ }
+
+ public void testResetAllThrottling() throws Exception {
+ prepareCrossProfileDataSet();
+
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ assertTrue(mManager.getRemainingCallCount() < 3);
+ });
+ runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
+ assertTrue(mManager.getRemainingCallCount() < 3);
+ });
+
+ mInjectedCallingUid = Process.SHELL_UID;
+ assertSuccess(callShellCommand("reset-all-throttling"));
+
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ assertEquals(3, mManager.getRemainingCallCount());
+ });
+ runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
+ assertEquals(3, mManager.getRemainingCallCount());
+ });
+ }
+
+ public void testLauncherCommands() throws Exception {
+ prepareGetHomeActivitiesAsUser(
+ /* preferred */ null,
+ list(getSystemLauncher(), getFallbackLauncher()),
+ USER_0);
+
+ prepareGetHomeActivitiesAsUser(
+ /* preferred */ cn(CALLING_PACKAGE_2, "name"),
+ list(getSystemLauncher(), getFallbackLauncher(),
+ ri(CALLING_PACKAGE_1, "name", false, 0),
+ ri(CALLING_PACKAGE_2, "name", false, 0)
+ ),
+ USER_10);
+
+ assertTrue(mService.hasShortcutHostPermissionInner(PACKAGE_SYSTEM_LAUNCHER, USER_0));
+
+ // First, test "get".
+
+ mRunningUsers.put(USER_10, true);
+ mUnlockedUsers.put(USER_10, true);
+ mInjectedCallingUid = Process.SHELL_UID;
+ assertContains(
+ assertSuccess(callShellCommand("get-default-launcher")),
+ "Launcher: ComponentInfo{com.android.systemlauncher/systemlauncher_name}");
+
+ assertContains(
+ assertSuccess(callShellCommand("get-default-launcher", "--user", "10")),
+ "Launcher: ComponentInfo{com.android.test.2/name}");
+
+ // Next, test "clear".
+ assertSuccess(callShellCommand("clear-default-launcher", "--user", "10"));
+
+ // User-10's launcher should be cleared.
+ assertEquals(null, mService.getUserShortcutsLocked(USER_10).getLastKnownLauncher());
+ assertEquals(null, mService.getUserShortcutsLocked(USER_10).getCachedLauncher());
+
+ // but user'0's shouldn't.
+ assertEquals(cn(PACKAGE_SYSTEM_LAUNCHER, PACKAGE_SYSTEM_LAUNCHER_NAME),
+ mService.getUserShortcutsLocked(USER_0).getCachedLauncher());
+
+ // Change user-0's launcher.
+ prepareGetHomeActivitiesAsUser(
+ /* preferred */ cn(CALLING_PACKAGE_1, "name"),
+ list(
+ ri(CALLING_PACKAGE_1, "name", false, 0)
+ ),
+ USER_0);
+ assertContains(
+ assertSuccess(callShellCommand("get-default-launcher")),
+ "Launcher: ComponentInfo{com.android.test.1/name}");
+ }
+
+ public void testUnloadUser() throws Exception {
+ prepareCrossProfileDataSet();
+
+ assertNotNull(mService.getShortcutsForTest().get(USER_10));
+
+ mRunningUsers.put(USER_10, true);
+ mUnlockedUsers.put(USER_10, true);
+
+ mInjectedCallingUid = Process.SHELL_UID;
+ assertSuccess(callShellCommand("unload-user", "--user", "10"));
+
+ assertNull(mService.getShortcutsForTest().get(USER_10));
+ }
+
+ public void testClearShortcuts() throws Exception {
+
+ mRunningUsers.put(USER_10, true);
+
+ // Add two manifests and two dynamics.
+ addManifestShortcutResource(
+ new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
+ R.xml.shortcut_2);
+ updatePackageVersion(CALLING_PACKAGE_1, 1);
+ mService.mPackageMonitor.onReceive(getTestContext(),
+ genPackageAddIntent(CALLING_PACKAGE_1, USER_10));
+
+ runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
+ assertTrue(mManager.addDynamicShortcuts(list(
+ makeShortcut("s1"), makeShortcut("s2"))));
+ });
+ runWithCaller(LAUNCHER_1, USER_10, () -> {
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("ms2", "s2"), HANDLE_USER_10);
+ });
+
+ runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
+ assertWith(getCallerShortcuts())
+ .haveIds("ms1", "ms2", "s1", "s2")
+ .areAllEnabled()
+
+ .selectPinned()
+ .haveIds("ms2", "s2");
+ });
+
+ // First, call for a different package.
+
+ mRunningUsers.put(USER_10, true);
+ mUnlockedUsers.put(USER_10, true);
+
+ mInjectedCallingUid = Process.SHELL_UID;
+ assertSuccess(callShellCommand("clear-shortcuts", "--user", "10", CALLING_PACKAGE_2));
+
+ // Shouldn't be cleared yet.
+ runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
+ assertWith(getCallerShortcuts())
+ .haveIds("ms1", "ms2", "s1", "s2")
+ .areAllEnabled()
+
+ .selectPinned()
+ .haveIds("ms2", "s2");
+ });
+
+ mInjectedCallingUid = Process.SHELL_UID;
+ assertSuccess(callShellCommand("clear-shortcuts", "--user", "10", CALLING_PACKAGE_1));
+
+ // Only manifest shortcuts will remain, and are no longer pinned.
+ runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
+ assertWith(getCallerShortcuts())
+ .haveIds("ms1", "ms2")
+ .areAllEnabled()
+ .areAllNotPinned();
+ });
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserRestrictionsUtilsTest.java b/services/tests/servicestests/src/com/android/server/pm/UserRestrictionsUtilsTest.java
index e2dce853..11f9ebb 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserRestrictionsUtilsTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserRestrictionsUtilsTest.java
@@ -16,15 +16,14 @@
package com.android.server.pm;
-import android.os.UserHandle;
-import com.android.server.devicepolicy.DpmTestUtils;
-
import android.os.Bundle;
+import android.os.UserHandle;
import android.os.UserManager;
import android.test.AndroidTestCase;
-import android.test.MoreAsserts;
import android.test.suitebuilder.annotation.SmallTest;
+import com.android.server.devicepolicy.DpmTestUtils;
+
/**
* Tests for {@link com.android.server.pm.UserRestrictionsUtils}.
*
diff --git a/services/tests/shortcutmanagerutils/src/com/android/server/pm/shortcutmanagertest/ShortcutManagerTestUtils.java b/services/tests/shortcutmanagerutils/src/com/android/server/pm/shortcutmanagertest/ShortcutManagerTestUtils.java
index ce7adfa..5d29363 100644
--- a/services/tests/shortcutmanagerutils/src/com/android/server/pm/shortcutmanagertest/ShortcutManagerTestUtils.java
+++ b/services/tests/shortcutmanagerutils/src/com/android/server/pm/shortcutmanagertest/ShortcutManagerTestUtils.java
@@ -59,6 +59,8 @@
import org.mockito.Mockito;
import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
@@ -93,7 +95,12 @@
private ShortcutManagerTestUtils() {
}
- private static List<String> readAll(ParcelFileDescriptor pfd) {
+ public static List<String> readAll(File file) throws FileNotFoundException {
+ return readAll(ParcelFileDescriptor.open(
+ file.getAbsoluteFile(), ParcelFileDescriptor.MODE_READ_ONLY));
+ }
+
+ public static List<String> readAll(ParcelFileDescriptor pfd) {
try {
try {
final ArrayList<String> ret = new ArrayList<>();
@@ -114,7 +121,7 @@
}
}
- private static String concatResult(List<String> result) {
+ public static String concatResult(List<String> result) {
final StringBuilder sb = new StringBuilder();
for (String s : result) {
sb.append(s);
@@ -123,6 +130,30 @@
return sb.toString();
}
+ public static boolean resultContains(List<String> result, String expected) {
+ for (String line : result) {
+ if (line.contains(expected)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public static List<String> assertSuccess(List<String> result) {
+ if (!resultContains(result, "Success")) {
+ fail("Command failed. Result was:\n" + concatResult(result));
+ }
+ return result;
+ }
+
+ public static List<String> assertContains(List<String> result, String expected) {
+ if (!resultContains(result, expected)) {
+ fail("Didn't contain expected string=" + expected
+ + "\nActual:\n" + concatResult(result));
+ }
+ return result;
+ }
+
private static List<String> runCommand(Instrumentation instrumentation, String command) {
return runCommand(instrumentation, command, null);
}
@@ -321,24 +352,29 @@
return filter(list, si -> si.getLastChangedTimestamp() >= time);
}
+ @FunctionalInterface
+ public interface ExceptionRunnable {
+ void run() throws Exception;
+ }
+
public static void assertExpectException(Class<? extends Throwable> expectedExceptionType,
- String expectedExceptionMessageRegex, Runnable r) {
+ String expectedExceptionMessageRegex, ExceptionRunnable r) {
assertExpectException("", expectedExceptionType, expectedExceptionMessageRegex, r);
}
public static void assertCannotUpdateImmutable(Runnable r) {
assertExpectException(
- IllegalArgumentException.class, "may not be manipulated via APIs", r);
+ IllegalArgumentException.class, "may not be manipulated via APIs", r::run);
}
public static void assertDynamicShortcutCountExceeded(Runnable r) {
assertExpectException(IllegalArgumentException.class,
- "Max number of dynamic shortcuts exceeded", r);
+ "Max number of dynamic shortcuts exceeded", r::run);
}
public static void assertExpectException(String message,
Class<? extends Throwable> expectedExceptionType,
- String expectedExceptionMessageRegex, Runnable r) {
+ String expectedExceptionMessageRegex, ExceptionRunnable r) {
try {
r.run();
} catch (Throwable e) {