summaryrefslogtreecommitdiffstats
path: root/services/core/java
diff options
context:
space:
mode:
Diffstat (limited to 'services/core/java')
-rw-r--r--services/core/java/com/android/server/AppOpsService.java30
-rw-r--r--services/core/java/com/android/server/ConnectivityService.java3
-rw-r--r--services/core/java/com/android/server/MountService.java108
-rw-r--r--services/core/java/com/android/server/TelephonyRegistry.java51
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java9
-rw-r--r--services/core/java/com/android/server/am/ActivityStack.java10
-rw-r--r--services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java31
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java159
-rw-r--r--services/core/java/com/android/server/pm/PackageSettingBase.java23
-rw-r--r--services/core/java/com/android/server/pm/Settings.java39
-rw-r--r--services/core/java/com/android/server/policy/PhoneWindowManager.java47
11 files changed, 387 insertions, 123 deletions
diff --git a/services/core/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java
index f0fc399..417f18d 100644
--- a/services/core/java/com/android/server/AppOpsService.java
+++ b/services/core/java/com/android/server/AppOpsService.java
@@ -48,6 +48,7 @@ import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
+import android.os.storage.MountServiceInternal;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.AtomicFile;
@@ -60,6 +61,7 @@ import android.util.Xml;
import com.android.internal.app.IAppOpsService;
import com.android.internal.app.IAppOpsCallback;
+import com.android.internal.os.Zygote;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.XmlUtils;
@@ -245,6 +247,34 @@ public class AppOpsService extends IAppOpsService.Stub {
scheduleFastWriteLocked();
}
}
+
+ MountServiceInternal mountServiceInternal = LocalServices.getService(
+ MountServiceInternal.class);
+ mountServiceInternal.addExternalStoragePolicy(
+ new MountServiceInternal.ExternalStorageMountPolicy() {
+ @Override
+ public int getMountMode(int uid, String packageName) {
+ if (Process.isIsolated(uid)) {
+ return Zygote.MOUNT_EXTERNAL_NONE;
+ }
+ if (noteOperation(AppOpsManager.OP_READ_EXTERNAL_STORAGE, uid,
+ packageName) != AppOpsManager.MODE_ALLOWED) {
+ return Zygote.MOUNT_EXTERNAL_NONE;
+ }
+ if (noteOperation(AppOpsManager.OP_WRITE_EXTERNAL_STORAGE, uid,
+ packageName) != AppOpsManager.MODE_ALLOWED) {
+ return Zygote.MOUNT_EXTERNAL_READ;
+ }
+ return Zygote.MOUNT_EXTERNAL_WRITE;
+ }
+
+ @Override
+ public boolean hasExternalStorage(int uid, String packageName) {
+ final int mountMode = getMountMode(uid, packageName);
+ return mountMode == Zygote.MOUNT_EXTERNAL_READ
+ || mountMode == Zygote.MOUNT_EXTERNAL_WRITE;
+ }
+ });
}
public void packageRemoved(int uid, String packageName) {
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 9b1e26a..eb74ab0 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -563,8 +563,9 @@ public class ConnectivityService extends IConnectivityManager.Stub
final DetailedState state = nai.networkInfo.getDetailedState();
for (int type = 0; type < mTypeLists.length; type++) {
final ArrayList<NetworkAgentInfo> list = mTypeLists[type];
+ final boolean contains = (list != null && list.contains(nai));
final boolean isFirst = (list != null && list.size() > 0 && nai == list.get(0));
- if (isFirst || isDefault) {
+ if (isFirst || (contains && isDefault)) {
maybeLogBroadcast(nai, state, type, isDefault);
sendLegacyNetworkBroadcast(nai, state, type);
}
diff --git a/services/core/java/com/android/server/MountService.java b/services/core/java/com/android/server/MountService.java
index da552dd..bc61c3d 100644
--- a/services/core/java/com/android/server/MountService.java
+++ b/services/core/java/com/android/server/MountService.java
@@ -68,6 +68,8 @@ import android.os.storage.IMountService;
import android.os.storage.IMountServiceListener;
import android.os.storage.IMountShutdownObserver;
import android.os.storage.IObbActionListener;
+import android.os.storage.MountServiceInternal;
+import android.os.storage.MountServiceInternal.ExternalStorageMountPolicy;
import android.os.storage.OnObbStateChangeListener;
import android.os.storage.StorageManager;
import android.os.storage.StorageResultCode;
@@ -127,6 +129,7 @@ import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
+import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
@@ -307,16 +310,6 @@ class MountService extends IMountService.Stub
@GuardedBy("mLock")
private String mMoveTargetUuid;
- private DiskInfo findDiskById(String id) {
- synchronized (mLock) {
- final DiskInfo disk = mDisks.get(id);
- if (disk != null) {
- return disk;
- }
- }
- throw new IllegalArgumentException("No disk found for ID " + id);
- }
-
private VolumeInfo findVolumeByIdOrThrow(String id) {
synchronized (mLock) {
final VolumeInfo vol = mVolumes.get(id);
@@ -456,6 +449,9 @@ class MountService extends IMountService.Stub
/** Map from raw paths to {@link ObbState}. */
final private Map<String, ObbState> mObbPathToStateMap = new HashMap<String, ObbState>();
+ // Not guarded by a lock.
+ private final MountServiceInternalImpl mMountServiceInternal = new MountServiceInternalImpl();
+
class ObbState implements IBinder.DeathRecipient {
public ObbState(String rawPath, String canonicalPath, int callingUid,
IObbActionListener token, int nonce) {
@@ -807,7 +803,7 @@ class MountService extends IMountService.Stub
for (int i = 0; i < mVolumes.size(); i++) {
final VolumeInfo vol = mVolumes.valueAt(i);
if (vol.isVisibleToUser(userId) && vol.isMountedReadable()) {
- final StorageVolume userVol = vol.buildStorageVolume(mContext, userId);
+ final StorageVolume userVol = vol.buildStorageVolume(mContext, userId, false);
mHandler.obtainMessage(H_VOLUME_BROADCAST, userVol).sendToTarget();
final String envState = VolumeInfo.getEnvironmentForState(vol.getState());
@@ -1250,7 +1246,7 @@ class MountService extends IMountService.Stub
// user-specific broadcasts.
for (int userId : mStartedUsers) {
if (vol.isVisibleToUser(userId)) {
- final StorageVolume userVol = vol.buildStorageVolume(mContext, userId);
+ final StorageVolume userVol = vol.buildStorageVolume(mContext, userId, false);
mHandler.obtainMessage(H_VOLUME_BROADCAST, userVol).sendToTarget();
mCallbacks.notifyStorageStateChanged(userVol.getPath(), oldStateEnv,
@@ -1370,6 +1366,8 @@ class MountService extends IMountService.Stub
readSettingsLocked();
}
+ LocalServices.addService(MountServiceInternal.class, mMountServiceInternal);
+
/*
* Create the connection to vold with a maximum queue of twice the
* amount of containers we'd ever expect to have. This keeps an
@@ -1787,27 +1785,28 @@ class MountService extends IMountService.Stub
}
}
- @Override
- public void remountUid(int uid) {
- enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
+ private void remountUidExternalStorage(int uid, int mode) {
waitForReady();
- final int mountExternal = mPms.getMountExternalMode(uid);
- final String mode;
- if (mountExternal == Zygote.MOUNT_EXTERNAL_DEFAULT) {
- mode = "default";
- } else if (mountExternal == Zygote.MOUNT_EXTERNAL_READ) {
- mode = "read";
- } else if (mountExternal == Zygote.MOUNT_EXTERNAL_WRITE) {
- mode = "write";
- } else {
- mode = "none";
+ String modeName = "none";
+ switch (mode) {
+ case Zygote.MOUNT_EXTERNAL_DEFAULT: {
+ modeName = "default";
+ } break;
+
+ case Zygote.MOUNT_EXTERNAL_READ: {
+ modeName = "read";
+ } break;
+
+ case Zygote.MOUNT_EXTERNAL_WRITE: {
+ modeName = "write";
+ } break;
}
try {
- mConnector.execute("volume", "remount_uid", uid, mode);
+ mConnector.execute("volume", "remount_uid", uid, modeName);
} catch (NativeDaemonConnectorException e) {
- Slog.w(TAG, "Failed to remount UID " + uid + " as " + mode + ": " + e);
+ Slog.w(TAG, "Failed to remount UID " + uid + " as " + modeName + ": " + e);
}
}
@@ -2598,15 +2597,20 @@ class MountService extends IMountService.Stub
}
@Override
- public StorageVolume[] getVolumeList(int userId) {
+ public StorageVolume[] getVolumeList(int uid, String packageName) {
final ArrayList<StorageVolume> res = new ArrayList<>();
boolean foundPrimary = false;
+ final int userId = UserHandle.getUserId(uid);
+ final boolean reportUnmounted = !mMountServiceInternal.hasExternalStorage(
+ uid, packageName);
+
synchronized (mLock) {
for (int i = 0; i < mVolumes.size(); i++) {
final VolumeInfo vol = mVolumes.valueAt(i);
if (vol.isVisibleToUser(userId)) {
- final StorageVolume userVol = vol.buildStorageVolume(mContext, userId);
+ final StorageVolume userVol = vol.buildStorageVolume(mContext, userId,
+ reportUnmounted);
if (vol.isPrimary()) {
res.add(0, userVol);
foundPrimary = true;
@@ -3379,4 +3383,50 @@ class MountService extends IMountService.Stub
mCryptConnector.monitor();
}
}
+
+ private final class MountServiceInternalImpl extends MountServiceInternal {
+ // Not guarded by a lock.
+ private final CopyOnWriteArrayList<ExternalStorageMountPolicy> mPolicies =
+ new CopyOnWriteArrayList<>();
+
+ @Override
+ public void addExternalStoragePolicy(ExternalStorageMountPolicy policy) {
+ // No locking - CopyOnWriteArrayList
+ mPolicies.add(policy);
+ }
+
+ @Override
+ public void onExternalStoragePolicyChanged(int uid, String packageName) {
+ final int mountMode = getExternalStorageMountMode(uid, packageName);
+ remountUidExternalStorage(uid, mountMode);
+ }
+
+ @Override
+ public int getExternalStorageMountMode(int uid, String packageName) {
+ // No locking - CopyOnWriteArrayList
+ int mountMode = Integer.MAX_VALUE;
+ for (ExternalStorageMountPolicy policy : mPolicies) {
+ final int policyMode = policy.getMountMode(uid, packageName);
+ if (policyMode == Zygote.MOUNT_EXTERNAL_NONE) {
+ return Zygote.MOUNT_EXTERNAL_NONE;
+ }
+ mountMode = Math.min(mountMode, policyMode);
+ }
+ if (mountMode == Integer.MAX_VALUE) {
+ return Zygote.MOUNT_EXTERNAL_NONE;
+ }
+ return mountMode;
+ }
+
+ public boolean hasExternalStorage(int uid, String packageName) {
+ // No locking - CopyOnWriteArrayList
+ for (ExternalStorageMountPolicy policy : mPolicies) {
+ final boolean policyHasStorage = policy.hasExternalStorage(uid, packageName);
+ if (!policyHasStorage) {
+ return false;
+ }
+ }
+ return true;
+ }
+ }
}
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 36d64aa..a06bb30 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -16,6 +16,7 @@
package com.android.server;
+import android.Manifest;
import android.app.ActivityManager;
import android.app.AppOpsManager;
import android.content.BroadcastReceiver;
@@ -360,12 +361,20 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
+ " callback.asBinder=" + callback.asBinder());
}
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.READ_PHONE_STATE, null);
+ try {
+ mContext.enforceCallingPermission(
+ android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
+ "addOnSubscriptionsChangedListener");
+ // SKIP checking for run-time permission since obtained PRIVILEGED
+ } catch (SecurityException e) {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.READ_PHONE_STATE,
+ "addOnSubscriptionsChangedListener");
- if (mAppOps.noteOp(AppOpsManager.OP_READ_PHONE_STATE, Binder.getCallingUid(),
- callingPackage) != AppOpsManager.MODE_ALLOWED) {
- return;
+ if (mAppOps.noteOp(AppOpsManager.OP_READ_PHONE_STATE, Binder.getCallingUid(),
+ callingPackage) != AppOpsManager.MODE_ALLOWED) {
+ return;
+ }
}
Record r;
@@ -471,9 +480,15 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
checkListenerPermission(events);
if ((events & ENFORCE_PHONE_STATE_PERMISSION_MASK) != 0) {
- if (mAppOps.noteOp(AppOpsManager.OP_READ_PHONE_STATE, Binder.getCallingUid(),
- callingPackage) != AppOpsManager.MODE_ALLOWED) {
- return;
+ try {
+ mContext.enforceCallingPermission(
+ android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, null);
+ // SKIP checking for run-time permission since obtained PRIVILEGED
+ } catch (SecurityException e) {
+ if (mAppOps.noteOp(AppOpsManager.OP_READ_PHONE_STATE, Binder.getCallingUid(),
+ callingPackage) != AppOpsManager.MODE_ALLOWED) {
+ return;
+ }
}
}
@@ -646,6 +661,12 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
}
private boolean canReadPhoneState(String callingPackage) {
+ if (mContext.checkCallingPermission(
+ android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) ==
+ PackageManager.PERMISSION_GRANTED) {
+ // SKIP checking for run-time permission since obtained PRIVILEGED
+ return true;
+ }
boolean canReadPhoneState = mContext.checkCallingOrSelfPermission(
android.Manifest.permission.READ_PHONE_STATE) == PackageManager.PERMISSION_GRANTED;
if (canReadPhoneState &&
@@ -1432,6 +1453,10 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId);
}
+ // Send broadcast twice, once for apps that have PRIVILEGED permission and once for those
+ // that have the runtime one
+ mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
+ android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE);
mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
android.Manifest.permission.READ_PHONE_STATE,
AppOpsManager.OP_READ_PHONE_STATE);
@@ -1563,8 +1588,14 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
}
if ((events & ENFORCE_PHONE_STATE_PERMISSION_MASK) != 0) {
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.READ_PHONE_STATE, null);
+ try {
+ mContext.enforceCallingPermission(
+ android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, null);
+ // SKIP checking for run-time permission since obtained PRIVILEGED
+ } catch (SecurityException e) {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.READ_PHONE_STATE, null);
+ }
}
if ((events & PRECISE_PHONE_STATE_PERMISSION_MASK) != 0) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 6e94647..5bfca10 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -18,7 +18,10 @@ package com.android.server.am;
import static android.Manifest.permission.INTERACT_ACROSS_USERS;
import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
+import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
import static android.Manifest.permission.START_TASKS_FROM_RECENTS;
+import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE;
+import static android.Manifest.permission.WRITE_MEDIA_STORAGE;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static com.android.internal.util.XmlUtils.readBooleanAttribute;
import static com.android.internal.util.XmlUtils.readIntAttribute;
@@ -62,6 +65,7 @@ import android.os.Trace;
import android.os.TransactionTooLargeException;
import android.os.WorkSource;
import android.os.storage.IMountService;
+import android.os.storage.MountServiceInternal;
import android.os.storage.StorageManager;
import android.service.voice.IVoiceInteractionSession;
import android.util.ArrayMap;
@@ -3219,7 +3223,10 @@ public final class ActivityManagerService extends ActivityManagerNative
checkTime(startTime, "startProcess: getting gids from package manager");
final IPackageManager pm = AppGlobals.getPackageManager();
permGids = pm.getPackageGids(app.info.packageName, app.userId);
- mountExternal = pm.getMountExternalMode(uid);
+ MountServiceInternal mountServiceInternal = LocalServices.getService(
+ MountServiceInternal.class);
+ mountExternal = mountServiceInternal.getExternalStorageMountMode(uid,
+ app.info.packageName);
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 8c3a950..470bbb0 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -2669,8 +2669,13 @@ final class ActivityStack {
if (!r.finishing) {
if (!mService.isSleeping()) {
if (DEBUG_STATES) Slog.d(TAG_STATES, "no-history finish of " + r);
- requestFinishActivityLocked(r.appToken, Activity.RESULT_CANCELED, null,
- "stop-no-history", false);
+ if (requestFinishActivityLocked(r.appToken, Activity.RESULT_CANCELED, null,
+ "stop-no-history", false)) {
+ // Activity was finished, no need to continue trying to schedule stop.
+ adjustFocusedActivityLocked(r, "stopActivityFinished");
+ r.resumeKeyDispatchingLocked();
+ return;
+ }
} else {
if (DEBUG_STATES) Slog.d(TAG_STATES, "Not finishing noHistory " + r
+ " on stop because we're just sleeping");
@@ -2963,6 +2968,7 @@ final class ActivityStack {
r.state = ActivityState.FINISHING;
if (mode == FINISH_IMMEDIATELY
+ || (mode == FINISH_AFTER_PAUSE && prevState == ActivityState.PAUSED)
|| prevState == ActivityState.STOPPED
|| prevState == ActivityState.INITIALIZING) {
// If this activity is already stopped, we can just finish
diff --git a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
index 7a74729..e3c6037 100644
--- a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
@@ -29,6 +29,7 @@ import android.content.pm.ProviderInfo;
import android.content.pm.ResolveInfo;
import android.net.Uri;
import android.os.Build;
+import android.os.Debug;
import android.os.UserHandle;
import android.provider.CalendarContract;
import android.provider.ContactsContract;
@@ -174,7 +175,7 @@ final class DefaultPermissionGrantPolicy {
synchronized (mService.mPackages) {
for (PackageParser.Package pkg : mService.mPackages.values()) {
- if (!isSysComponentOrPersistentPrivApp(pkg)
+ if (!isSysComponentOrPersistentPlatformSignedPrivApp(pkg)
|| !doesPackageSupportRuntimePermissions(pkg)) {
continue;
}
@@ -344,7 +345,6 @@ final class DefaultPermissionGrantPolicy {
Intent cbrIntent = new Intent(Intents.SMS_CB_RECEIVED_ACTION);
PackageParser.Package cbrPackage =
getDefaultSystemHandlerActivityPackageLPr(cbrIntent, userId);
-
if (cbrPackage != null && doesPackageSupportRuntimePermissions(cbrPackage)) {
grantRuntimePermissionsLPw(cbrPackage, SMS_PERMISSIONS, false, userId);
}
@@ -625,8 +625,9 @@ final class DefaultPermissionGrantPolicy {
private PackageParser.Package getDefaultSystemHandlerActivityPackageLPr(
Intent intent, int userId) {
- List<ResolveInfo> handlers = mService.queryIntentActivities(intent,
- intent.resolveType(mService.mContext.getContentResolver()), 0, userId);
+ List<ResolveInfo> handlers = mService.mActivities.queryIntent(intent,
+ intent.resolveType(mService.mContext.getContentResolver()),
+ PackageManager.GET_DISABLED_COMPONENTS, userId);
final int handlerCount = handlers.size();
for (int i = 0; i < handlerCount; i++) {
ResolveInfo handler = handlers.get(i);
@@ -650,8 +651,9 @@ final class DefaultPermissionGrantPolicy {
for (String syncAdapterPackageName : syncAdapterPackageNames) {
homeIntent.setPackage(syncAdapterPackageName);
- List<ResolveInfo> homeActivities = mService.queryIntentActivities(homeIntent,
- homeIntent.resolveType(mService.mContext.getContentResolver()), 0, userId);
+ List<ResolveInfo> homeActivities = mService.mActivities.queryIntent(homeIntent,
+ homeIntent.resolveType(mService.mContext.getContentResolver()),
+ PackageManager.GET_DISABLED_COMPONENTS, userId);
if (!homeActivities.isEmpty()) {
continue;
}
@@ -681,7 +683,7 @@ final class DefaultPermissionGrantPolicy {
private PackageParser.Package getSystemPackageLPr(String packageName) {
PackageParser.Package pkg = getPackageLPr(packageName);
if (pkg != null && pkg.isSystemApp()) {
- return !isSysComponentOrPersistentPrivApp(pkg) ? pkg : null;
+ return !isSysComponentOrPersistentPlatformSignedPrivApp(pkg) ? pkg : null;
}
return null;
}
@@ -730,11 +732,16 @@ final class DefaultPermissionGrantPolicy {
}
}
- private static boolean isSysComponentOrPersistentPrivApp(PackageParser.Package pkg) {
- return UserHandle.getAppId(pkg.applicationInfo.uid) < FIRST_APPLICATION_UID
- || ((pkg.applicationInfo.privateFlags
- & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0
- && (pkg.applicationInfo.flags & ApplicationInfo.FLAG_PERSISTENT) != 0);
+ private boolean isSysComponentOrPersistentPlatformSignedPrivApp(PackageParser.Package pkg) {
+ if (UserHandle.getAppId(pkg.applicationInfo.uid) < FIRST_APPLICATION_UID) {
+ return true;
+ }
+ if ((pkg.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) == 0
+ || (pkg.applicationInfo.flags & ApplicationInfo.FLAG_PERSISTENT) == 0) {
+ return false;
+ }
+ return PackageManagerService.compareSignatures(mService.mPlatformPackage.mSignatures,
+ pkg.mSignatures) == PackageManager.SIGNATURE_MATCH;
}
private static boolean doesPackageSupportRuntimePermissions(PackageParser.Package pkg) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index bfb803d..ef9bc8b 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -62,6 +62,7 @@ import static android.content.pm.PackageManager.MOVE_FAILED_DOESNT_EXIST;
import static android.content.pm.PackageManager.MOVE_FAILED_INTERNAL_ERROR;
import static android.content.pm.PackageManager.MOVE_FAILED_OPERATION_PENDING;
import static android.content.pm.PackageManager.MOVE_FAILED_SYSTEM_PACKAGE;
+import static android.content.pm.PackageManager.PERMISSION_DENIED;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.content.pm.PackageParser.isApkFile;
import static android.os.Process.PACKAGE_INFO_GID;
@@ -143,10 +144,10 @@ import android.content.pm.VerifierInfo;
import android.content.res.Resources;
import android.hardware.display.DisplayManager;
import android.net.Uri;
+import android.os.Debug;
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
-import android.os.Debug;
import android.os.Environment;
import android.os.Environment.UserEnvironment;
import android.os.FileUtils;
@@ -166,6 +167,7 @@ import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
import android.os.storage.IMountService;
+import android.os.storage.MountServiceInternal;
import android.os.storage.StorageEventListener;
import android.os.storage.StorageManager;
import android.os.storage.VolumeInfo;
@@ -284,7 +286,7 @@ public class PackageManagerService extends IPackageManager.Stub {
static final boolean DEBUG_PREFERRED = false;
static final boolean DEBUG_UPGRADE = false;
static final boolean DEBUG_DOMAIN_VERIFICATION = false;
- private static final boolean DEBUG_BACKUP = true;
+ private static final boolean DEBUG_BACKUP = false;
private static final boolean DEBUG_INSTALL = false;
private static final boolean DEBUG_REMOVE = false;
private static final boolean DEBUG_BROADCASTS = false;
@@ -2727,23 +2729,6 @@ public class PackageManagerService extends IPackageManager.Stub {
return null;
}
- @Override
- public int getMountExternalMode(int uid) {
- if (Process.isIsolated(uid)) {
- return Zygote.MOUNT_EXTERNAL_NONE;
- } else {
- if (checkUidPermission(WRITE_MEDIA_STORAGE, uid) == PERMISSION_GRANTED) {
- return Zygote.MOUNT_EXTERNAL_DEFAULT;
- } else if (checkUidPermission(WRITE_EXTERNAL_STORAGE, uid) == PERMISSION_GRANTED) {
- return Zygote.MOUNT_EXTERNAL_WRITE;
- } else if (checkUidPermission(READ_EXTERNAL_STORAGE, uid) == PERMISSION_GRANTED) {
- return Zygote.MOUNT_EXTERNAL_READ;
- } else {
- return Zygote.MOUNT_EXTERNAL_DEFAULT;
- }
- }
- }
-
static PermissionInfo generatePermissionInfo(
BasePermission bp, int flags) {
if (bp.perm != null) {
@@ -3461,13 +3446,15 @@ public class PackageManagerService extends IPackageManager.Stub {
// Only need to do this if user is initialized. Otherwise it's a new user
// and there are no processes running as the user yet and there's no need
// to make an expensive call to remount processes for the changed permissions.
- if ((READ_EXTERNAL_STORAGE.equals(name)
- || WRITE_EXTERNAL_STORAGE.equals(name))
- && sUserManager.isInitialized(userId)) {
+ if (READ_EXTERNAL_STORAGE.equals(name)
+ || WRITE_EXTERNAL_STORAGE.equals(name)) {
final long token = Binder.clearCallingIdentity();
try {
- final StorageManager storage = mContext.getSystemService(StorageManager.class);
- storage.remountUid(uid);
+ if (sUserManager.isInitialized(userId)) {
+ MountServiceInternal mountServiceInternal = LocalServices.getService(
+ MountServiceInternal.class);
+ mountServiceInternal.onExternalStoragePolicyChanged(uid, packageName);
+ }
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -4431,8 +4418,11 @@ public class PackageManagerService extends IPackageManager.Stub {
// cross-profile app linking works only towards the parent.
final UserInfo parent = getProfileParent(sourceUserId);
synchronized(mPackages) {
- return getCrossProfileDomainPreferredLpr(intent, resolvedType, 0, sourceUserId,
- parent.id) != null;
+ CrossProfileDomainInfo xpDomainInfo = getCrossProfileDomainPreferredLpr(
+ intent, resolvedType, 0, sourceUserId, parent.id);
+ return xpDomainInfo != null
+ && xpDomainInfo.bestDomainVerificationStatus !=
+ INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER;
}
}
return false;
@@ -4527,8 +4517,8 @@ public class PackageManagerService extends IPackageManager.Stub {
} else if (result.size() <= 1) {
return result;
}
- result = filterCandidatesWithDomainPreferredActivitiesLPr(flags, result,
- xpDomainInfo);
+ result = filterCandidatesWithDomainPreferredActivitiesLPr(intent, flags, result,
+ xpDomainInfo, userId);
Collections.sort(result, mResolvePrioritySorter);
}
return result;
@@ -4577,7 +4567,8 @@ public class PackageManagerService extends IPackageManager.Stub {
if (ps == null) {
continue;
}
- int status = getDomainVerificationStatusLPr(ps, parentUserId);
+ long verificationState = getDomainVerificationStatusLPr(ps, parentUserId);
+ int status = (int)(verificationState >> 32);
if (result == null) {
result = new CrossProfileDomainInfo();
result.resolveInfo =
@@ -4644,14 +4635,16 @@ public class PackageManagerService extends IPackageManager.Stub {
return scheme.equals(IntentFilter.SCHEME_HTTP) || scheme.equals(IntentFilter.SCHEME_HTTPS);
}
- private List<ResolveInfo> filterCandidatesWithDomainPreferredActivitiesLPr(
- int flags, List<ResolveInfo> candidates, CrossProfileDomainInfo xpDomainInfo) {
+ private List<ResolveInfo> filterCandidatesWithDomainPreferredActivitiesLPr(Intent intent,
+ int matchFlags, List<ResolveInfo> candidates, CrossProfileDomainInfo xpDomainInfo,
+ int userId) {
+ final boolean debug = (intent.getFlags() & Intent.FLAG_DEBUG_LOG_RESOLUTION) != 0;
+
if (DEBUG_PREFERRED || DEBUG_DOMAIN_VERIFICATION) {
- Slog.v("TAG", "Filtering results with preferred activities. Candidates count: " +
+ Slog.v(TAG, "Filtering results with preferred activities. Candidates count: " +
candidates.size());
}
- final int userId = UserHandle.getCallingUserId();
ArrayList<ResolveInfo> result = new ArrayList<ResolveInfo>();
ArrayList<ResolveInfo> alwaysList = new ArrayList<ResolveInfo>();
ArrayList<ResolveInfo> undefinedList = new ArrayList<ResolveInfo>();
@@ -4674,11 +4667,17 @@ public class PackageManagerService extends IPackageManager.Stub {
continue;
}
// Try to get the status from User settings first
- int status = getDomainVerificationStatusLPr(ps, userId);
+ long packedStatus = getDomainVerificationStatusLPr(ps, userId);
+ int status = (int)(packedStatus >> 32);
+ int linkGeneration = (int)(packedStatus & 0xFFFFFFFF);
if (status == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS) {
if (DEBUG_DOMAIN_VERIFICATION) {
- Slog.i(TAG, " + always: " + info.activityInfo.packageName);
+ Slog.i(TAG, " + always: " + info.activityInfo.packageName
+ + " : linkgen=" + linkGeneration);
}
+ // Use link-enabled generation as preferredOrder, i.e.
+ // prefer newly-enabled over earlier-enabled.
+ info.preferredOrder = linkGeneration;
alwaysList.add(info);
} else if (status == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER) {
if (DEBUG_DOMAIN_VERIFICATION) {
@@ -4694,7 +4693,7 @@ public class PackageManagerService extends IPackageManager.Stub {
}
}
}
- // First try to add the "always" resolution for the current user if there is any
+ // First try to add the "always" resolution(s) for the current user, if any
if (alwaysList.size() > 0) {
result.addAll(alwaysList);
// if there is an "always" for the parent user, add it.
@@ -4712,26 +4711,41 @@ public class PackageManagerService extends IPackageManager.Stub {
result.add(xpDomainInfo.resolveInfo);
}
// Also add Browsers (all of them or only the default one)
- if ((flags & MATCH_ALL) != 0) {
+ if ((matchFlags & MATCH_ALL) != 0) {
result.addAll(matchAllList);
} else {
- // Try to add the Default Browser if we can
+ // Browser/generic handling case. If there's a default browser, go straight
+ // to that (but only if there is no other higher-priority match).
final String defaultBrowserPackageName = getDefaultBrowserPackageName(
UserHandle.myUserId());
- if (!TextUtils.isEmpty(defaultBrowserPackageName)) {
- boolean defaultBrowserFound = false;
- final int browserCount = matchAllList.size();
- for (int n=0; n<browserCount; n++) {
- ResolveInfo browser = matchAllList.get(n);
- if (browser.activityInfo.packageName.equals(defaultBrowserPackageName)) {
- result.add(browser);
- defaultBrowserFound = true;
- break;
+ int maxMatchPrio = 0;
+ ResolveInfo defaultBrowserMatch = null;
+ final int numCandidates = matchAllList.size();
+ for (int n = 0; n < numCandidates; n++) {
+ ResolveInfo info = matchAllList.get(n);
+ // track the highest overall match priority...
+ if (info.priority > maxMatchPrio) {
+ maxMatchPrio = info.priority;
+ }
+ // ...and the highest-priority default browser match
+ if (info.activityInfo.packageName.equals(defaultBrowserPackageName)) {
+ if (defaultBrowserMatch == null
+ || (defaultBrowserMatch.priority < info.priority)) {
+ if (debug) {
+ Slog.v(TAG, "Considering default browser match " + info);
+ }
+ defaultBrowserMatch = info;
}
}
- if (!defaultBrowserFound) {
- result.addAll(matchAllList);
+ }
+ if (defaultBrowserMatch != null
+ && defaultBrowserMatch.priority >= maxMatchPrio
+ && !TextUtils.isEmpty(defaultBrowserPackageName))
+ {
+ if (debug) {
+ Slog.v(TAG, "Default browser match " + defaultBrowserMatch);
}
+ result.add(defaultBrowserMatch);
} else {
result.addAll(matchAllList);
}
@@ -4755,15 +4769,19 @@ public class PackageManagerService extends IPackageManager.Stub {
return result;
}
- private int getDomainVerificationStatusLPr(PackageSetting ps, int userId) {
- int status = ps.getDomainVerificationStatusForUser(userId);
+ // Returns a packed value as a long:
+ //
+ // high 'int'-sized word: link status: undefined/ask/never/always.
+ // low 'int'-sized word: relative priority among 'always' results.
+ private long getDomainVerificationStatusLPr(PackageSetting ps, int userId) {
+ long result = ps.getDomainVerificationStatusForUser(userId);
// if none available, get the master status
- if (status == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED) {
+ if (result >> 32 == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED) {
if (ps.getIntentFilterVerificationInfo() != null) {
- status = ps.getIntentFilterVerificationInfo().getStatus();
+ result = ((long)ps.getIntentFilterVerificationInfo().getStatus()) << 32;
}
}
- return status;
+ return result;
}
private ResolveInfo querySkipCurrentProfileIntents(
@@ -12959,7 +12977,7 @@ public class PackageManagerService extends IPackageManager.Stub {
false, //hidden
null, null, null,
false, // blockUninstall
- INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED);
+ INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED, 0);
if (!isSystemApp(ps)) {
if (ps.isAnyInstalled(sUserManager.getUserIds())) {
// Other user still have this package installed, so all
@@ -14435,6 +14453,33 @@ public class PackageManagerService extends IPackageManager.Stub {
mInstallerService.systemReady();
mPackageDexOptimizer.systemReady();
+
+ MountServiceInternal mountServiceInternal = LocalServices.getService(
+ MountServiceInternal.class);
+ mountServiceInternal.addExternalStoragePolicy(
+ new MountServiceInternal.ExternalStorageMountPolicy() {
+ @Override
+ public int getMountMode(int uid, String packageName) {
+ if (Process.isIsolated(uid)) {
+ return Zygote.MOUNT_EXTERNAL_NONE;
+ }
+ if (checkUidPermission(WRITE_MEDIA_STORAGE, uid) == PERMISSION_GRANTED) {
+ return Zygote.MOUNT_EXTERNAL_DEFAULT;
+ }
+ if (checkUidPermission(READ_EXTERNAL_STORAGE, uid) == PERMISSION_DENIED) {
+ return Zygote.MOUNT_EXTERNAL_DEFAULT;
+ }
+ if (checkUidPermission(WRITE_EXTERNAL_STORAGE, uid) == PERMISSION_DENIED) {
+ return Zygote.MOUNT_EXTERNAL_READ;
+ }
+ return Zygote.MOUNT_EXTERNAL_WRITE;
+ }
+
+ @Override
+ public boolean hasExternalStorage(int uid, String packageName) {
+ return true;
+ }
+ });
}
@Override
@@ -14882,8 +14927,8 @@ public class PackageManagerService extends IPackageManager.Stub {
pw.println();
count = 0;
for (PackageSetting ps : allPackageSettings) {
- final int status = ps.getDomainVerificationStatusForUser(userId);
- if (status == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED) {
+ final long status = ps.getDomainVerificationStatusForUser(userId);
+ if (status >> 32 == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED) {
continue;
}
pw.println(prefix + "Package: " + ps.name);
diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java
index 6f46f69..4faf75a 100644
--- a/services/core/java/com/android/server/pm/PackageSettingBase.java
+++ b/services/core/java/com/android/server/pm/PackageSettingBase.java
@@ -341,7 +341,8 @@ abstract class PackageSettingBase extends SettingBase {
void setUserState(int userId, int enabled, boolean installed, boolean stopped,
boolean notLaunched, boolean hidden,
String lastDisableAppCaller, ArraySet<String> enabledComponents,
- ArraySet<String> disabledComponents, boolean blockUninstall, int domainVerifState) {
+ ArraySet<String> disabledComponents, boolean blockUninstall, int domainVerifState,
+ int linkGeneration) {
PackageUserState state = modifyUserState(userId);
state.enabled = enabled;
state.installed = installed;
@@ -353,6 +354,7 @@ abstract class PackageSettingBase extends SettingBase {
state.disabledComponents = disabledComponents;
state.blockUninstall = blockUninstall;
state.domainVerificationStatus = domainVerifState;
+ state.appLinkGeneration = linkGeneration;
}
ArraySet<String> getEnabledComponents(int userId) {
@@ -449,12 +451,23 @@ abstract class PackageSettingBase extends SettingBase {
verificationInfo = info;
}
- int getDomainVerificationStatusForUser(int userId) {
- return readUserState(userId).domainVerificationStatus;
+ // Returns a packed value as a long:
+ //
+ // high 'int'-sized word: link status: undefined/ask/never/always.
+ // low 'int'-sized word: relative priority among 'always' results.
+ long getDomainVerificationStatusForUser(int userId) {
+ PackageUserState state = readUserState(userId);
+ long result = (long) state.appLinkGeneration;
+ result |= ((long) state.domainVerificationStatus) << 32;
+ return result;
}
- void setDomainVerificationStatusForUser(int status, int userId) {
- modifyUserState(userId).domainVerificationStatus = status;
+ void setDomainVerificationStatusForUser(final int status, int generation, int userId) {
+ PackageUserState state = modifyUserState(userId);
+ state.domainVerificationStatus = status;
+ if (status == PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS) {
+ state.appLinkGeneration = generation;
+ }
}
void clearDomainVerificationStatusForUser(int userId) {
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index bdcd714..312b7b3 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -87,6 +87,7 @@ import android.util.ArraySet;
import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
+import android.util.SparseIntArray;
import android.util.Xml;
import java.io.BufferedOutputStream;
@@ -196,6 +197,7 @@ final class Settings {
private static final String ATTR_DOMAIN_VERIFICATON_STATE = "domainVerificationStatus";
private static final String ATTR_PACKAGE_NAME= "packageName";
private static final String ATTR_FINGERPRINT = "fingerprint";
+ private static final String ATTR_APP_LINK_GENERATION = "app-link-generation";
private final Object mLock;
@@ -294,6 +296,9 @@ final class Settings {
// For every user, it is used to find the package name of the default Browser App.
final SparseArray<String> mDefaultBrowserApp = new SparseArray<String>();
+ // App-link priority tracking, per-user
+ final SparseIntArray mNextAppLinkGeneration = new SparseIntArray();
+
final StringBuilder mReadMessages = new StringBuilder();
/**
@@ -624,7 +629,7 @@ final class Settings {
false, // hidden
null, null, null,
false, // blockUninstall
- INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED);
+ INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED, 0);
writePackageRestrictionsLPr(user.id);
}
}
@@ -1051,7 +1056,7 @@ final class Settings {
}
return INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED;
}
- int status = ps.getDomainVerificationStatusForUser(userId);
+ int status = (int)(ps.getDomainVerificationStatusForUser(userId) >> 32);
if (status == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED) {
if (ps.getIntentFilterVerificationInfo() != null) {
status = ps.getIntentFilterVerificationInfo().getStatus();
@@ -1060,7 +1065,7 @@ final class Settings {
return status;
}
- boolean updateIntentFilterVerificationStatusLPw(String packageName, int status, int userId) {
+ boolean updateIntentFilterVerificationStatusLPw(String packageName, final int status, int userId) {
// Update the status for the current package
PackageSetting current = mPackages.get(packageName);
if (current == null) {
@@ -1070,7 +1075,15 @@ final class Settings {
return false;
}
- current.setDomainVerificationStatusForUser(status, userId);
+ final int alwaysGeneration;
+ if (status == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS) {
+ alwaysGeneration = mNextAppLinkGeneration.get(userId) + 1;
+ mNextAppLinkGeneration.put(userId, alwaysGeneration);
+ } else {
+ alwaysGeneration = 0;
+ }
+
+ current.setDomainVerificationStatusForUser(status, alwaysGeneration, userId);
return true;
}
@@ -1382,7 +1395,7 @@ final class Settings {
false, // hidden
null, null, null,
false, // blockUninstall
- INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED);
+ INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED, 0);
}
return;
}
@@ -1404,6 +1417,8 @@ final class Settings {
return;
}
+ int maxAppLinkGeneration = 0;
+
int outerDepth = parser.getDepth();
PackageSetting ps = null;
while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
@@ -1457,6 +1472,12 @@ final class Settings {
PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED :
Integer.parseInt(verifStateStr);
+ final String linkGenStr = parser.getAttributeValue(null, ATTR_APP_LINK_GENERATION);
+ final int linkGeneration = linkGenStr == null ? 0 : Integer.parseInt(linkGenStr);
+ if (linkGeneration > maxAppLinkGeneration) {
+ maxAppLinkGeneration = linkGeneration;
+ }
+
ArraySet<String> enabledComponents = null;
ArraySet<String> disabledComponents = null;
@@ -1478,7 +1499,7 @@ final class Settings {
ps.setUserState(userId, enabled, installed, stopped, notLaunched, hidden,
enabledCaller, enabledComponents, disabledComponents, blockUninstall,
- verifState);
+ verifState, linkGeneration);
} else if (tagName.equals("preferred-activities")) {
readPreferredActivitiesLPw(parser, userId);
} else if (tagName.equals(TAG_PERSISTENT_PREFERRED_ACTIVITIES)) {
@@ -1496,6 +1517,8 @@ final class Settings {
str.close();
+ mNextAppLinkGeneration.put(userId, maxAppLinkGeneration + 1);
+
} catch (XmlPullParserException e) {
mReadMessages.append("Error reading: " + e.toString());
PackageManagerService.reportSettingsProblem(Log.ERROR,
@@ -1749,6 +1772,10 @@ final class Settings {
serializer.attribute(null, ATTR_DOMAIN_VERIFICATON_STATE,
Integer.toString(ustate.domainVerificationStatus));
}
+ if (ustate.appLinkGeneration != 0) {
+ serializer.attribute(null, ATTR_APP_LINK_GENERATION,
+ Integer.toString(ustate.appLinkGeneration));
+ }
if (ustate.enabledComponents != null
&& ustate.enabledComponents.size() > 0) {
serializer.startTag(null, TAG_ENABLED_COMPONENTS);
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 87efb8d..9e41f70 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -44,6 +44,9 @@ import android.content.res.TypedArray;
import android.database.ContentObserver;
import android.graphics.PixelFormat;
import android.graphics.Rect;
+import android.hardware.hdmi.HdmiControlManager;
+import android.hardware.hdmi.HdmiPlaybackClient;
+import android.hardware.hdmi.HdmiPlaybackClient.OneTouchPlayCallback;
import android.media.AudioAttributes;
import android.media.AudioManager;
import android.media.AudioSystem;
@@ -356,6 +359,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
boolean mSystemReady;
boolean mSystemBooted;
boolean mHdmiPlugged;
+ HdmiControl mHdmiControl;
IUiModeManager mUiModeManager;
int mUiMode;
int mDockMode = Intent.EXTRA_DOCK_STATE_UNDOCKED;
@@ -1212,6 +1216,9 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
private void handleShortPressOnHome() {
+ // Turn on the connected TV and switch HDMI input if we're a HDMI playback device.
+ getHdmiControl().turnOnTv();
+
// If there's a dream running then use home to escape the dream
// but don't actually go home.
if (mDreamManagerInternal != null && mDreamManagerInternal.isDreaming()) {
@@ -1223,6 +1230,46 @@ public class PhoneWindowManager implements WindowManagerPolicy {
launchHomeFromHotKey();
}
+ /**
+ * Creates an accessor to HDMI control service that performs the operation of
+ * turning on TV (optional) and switching input to us. If HDMI control service
+ * is not available or we're not a HDMI playback device, the operation is no-op.
+ */
+ private HdmiControl getHdmiControl() {
+ if (null == mHdmiControl) {
+ HdmiControlManager manager = (HdmiControlManager) mContext.getSystemService(
+ Context.HDMI_CONTROL_SERVICE);
+ HdmiPlaybackClient client = null;
+ if (manager != null) {
+ client = manager.getPlaybackClient();
+ }
+ mHdmiControl = new HdmiControl(client);
+ }
+ return mHdmiControl;
+ }
+
+ private static class HdmiControl {
+ private final HdmiPlaybackClient mClient;
+
+ private HdmiControl(HdmiPlaybackClient client) {
+ mClient = client;
+ }
+
+ public void turnOnTv() {
+ if (mClient == null) {
+ return;
+ }
+ mClient.oneTouchPlay(new OneTouchPlayCallback() {
+ @Override
+ public void onComplete(int result) {
+ if (result != HdmiControlManager.RESULT_SUCCESS) {
+ Log.w(TAG, "One touch play failed: " + result);
+ }
+ }
+ });
+ }
+ }
+
private void handleLongPressOnHome(int deviceId) {
if (mLongPressOnHomeBehavior != LONG_PRESS_HOME_NOTHING) {
mHomeConsumed = true;