summaryrefslogtreecommitdiffstats
path: root/services/java
diff options
context:
space:
mode:
Diffstat (limited to 'services/java')
-rw-r--r--services/java/com/android/server/ConnectivityService.java12
-rw-r--r--services/java/com/android/server/DreamController.java217
-rw-r--r--services/java/com/android/server/DreamManagerService.java387
-rw-r--r--services/java/com/android/server/SystemServer.java13
-rw-r--r--services/java/com/android/server/TelephonyRegistry.java100
-rw-r--r--services/java/com/android/server/WallpaperManagerService.java45
-rw-r--r--services/java/com/android/server/am/ActivityManagerService.java66
-rw-r--r--services/java/com/android/server/am/ActivityRecord.java18
-rwxr-xr-xservices/java/com/android/server/am/ActivityStack.java46
-rw-r--r--services/java/com/android/server/am/TaskAccessInfo.java3
-rw-r--r--services/java/com/android/server/am/UsageStatsService.java2
-rw-r--r--services/java/com/android/server/display/DisplayManagerService.java69
-rw-r--r--services/java/com/android/server/display/PersistentDataStore.java292
-rw-r--r--services/java/com/android/server/display/WifiDisplayAdapter.java90
-rw-r--r--services/java/com/android/server/display/WifiDisplayController.java290
-rw-r--r--services/java/com/android/server/net/LockdownVpnTracker.java8
-rw-r--r--services/java/com/android/server/net/NetworkStatsCollection.java5
-rw-r--r--services/java/com/android/server/net/NetworkStatsRecorder.java27
-rw-r--r--services/java/com/android/server/net/NetworkStatsService.java71
-rw-r--r--services/java/com/android/server/pm/PackageManagerService.java19
-rw-r--r--services/java/com/android/server/power/PowerManagerService.java35
-rw-r--r--services/java/com/android/server/updates/ConfigUpdateInstallReceiver.java9
-rwxr-xr-xservices/java/com/android/server/wm/WindowManagerService.java46
-rw-r--r--services/java/com/android/server/wm/WindowState.java4
-rw-r--r--services/java/com/android/server/wm/WindowStateAnimator.java4
25 files changed, 1610 insertions, 268 deletions
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index 5c7a3ed..9676eb9 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -32,6 +32,7 @@ import static android.net.ConnectivityManager.isNetworkTypeValid;
import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL;
import static android.net.NetworkPolicyManager.RULE_REJECT_METERED;
+import android.app.Activity;
import android.bluetooth.BluetoothTetheringDataTracker;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
@@ -548,6 +549,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
mSettingsObserver = new SettingsObserver(mHandler, EVENT_APPLY_GLOBAL_HTTP_PROXY);
mSettingsObserver.observe(mContext);
+ mCaptivePortalTracker = CaptivePortalTracker.makeCaptivePortalTracker(mContext, this);
loadGlobalProxy();
}
@@ -1694,7 +1696,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
}
Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION);
- intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info);
+ intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, new NetworkInfo(info));
intent.putExtra(ConnectivityManager.EXTRA_NETWORK_TYPE, info.getType());
if (info.isFailover()) {
intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true);
@@ -1825,7 +1827,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
}
Intent intent = new Intent(bcastType);
- intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info);
+ intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, new NetworkInfo(info));
intent.putExtra(ConnectivityManager.EXTRA_NETWORK_TYPE, info.getType());
if (info.isFailover()) {
intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true);
@@ -1882,7 +1884,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
loge("Attempt to connect to " + info.getTypeName() + " failed" + reasonText);
Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION);
- intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info);
+ intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, new NetworkInfo(info));
intent.putExtra(ConnectivityManager.EXTRA_NETWORK_TYPE, info.getType());
if (getActiveNetworkInfo() == null) {
intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true);
@@ -2075,8 +2077,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
if (mActiveDefaultNetwork != -1 && mActiveDefaultNetwork != type) {
if (isNewNetTypePreferredOverCurrentNetType(type)) {
if (DBG) log("Captive check on " + info.getTypeName());
- mCaptivePortalTracker = CaptivePortalTracker.detect(mContext, info,
- ConnectivityService.this);
+ mCaptivePortalTracker.detectCaptivePortal(new NetworkInfo(info));
return;
} else {
if (DBG) log("Tear down low priority net " + info.getTypeName());
@@ -2092,7 +2093,6 @@ public class ConnectivityService extends IConnectivityManager.Stub {
/** @hide */
public void captivePortalCheckComplete(NetworkInfo info) {
mNetTrackers[info.getType()].captivePortalCheckComplete();
- mCaptivePortalTracker = null;
}
/**
diff --git a/services/java/com/android/server/DreamController.java b/services/java/com/android/server/DreamController.java
new file mode 100644
index 0000000..498e581
--- /dev/null
+++ b/services/java/com/android/server/DreamController.java
@@ -0,0 +1,217 @@
+/*
+ * Copyright (C) 2012 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;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.IBinder.DeathRecipient;
+import android.service.dreams.IDreamService;
+import android.util.Slog;
+import android.view.IWindowManager;
+import android.view.WindowManager;
+import android.view.WindowManagerGlobal;
+
+import com.android.internal.util.DumpUtils;
+
+import java.io.PrintWriter;
+import java.util.NoSuchElementException;
+
+/**
+ * Internal controller for starting and stopping the current dream and managing related state.
+ *
+ * Assumes all operations (except {@link #dump}) are called from a single thread.
+ */
+final class DreamController {
+ private static final boolean DEBUG = true;
+ private static final String TAG = DreamController.class.getSimpleName();
+
+ public interface Listener {
+ void onDreamStopped(boolean wasTest);
+ }
+
+ private final Context mContext;
+ private final IWindowManager mIWindowManager;
+ private final DeathRecipient mDeathRecipient;
+ private final ServiceConnection mServiceConnection;
+ private final Listener mListener;
+
+ private Handler mHandler;
+
+ private ComponentName mCurrentDreamComponent;
+ private IDreamService mCurrentDream;
+ private Binder mCurrentDreamToken;
+ private boolean mCurrentDreamIsTest;
+
+ public DreamController(Context context, DeathRecipient deathRecipient,
+ ServiceConnection serviceConnection, Listener listener) {
+ mContext = context;
+ mDeathRecipient = deathRecipient;
+ mServiceConnection = serviceConnection;
+ mListener = listener;
+ mIWindowManager = WindowManagerGlobal.getWindowManagerService();
+ }
+
+ public void setHandler(Handler handler) {
+ mHandler = handler;
+ }
+
+ public void dump(PrintWriter pw) {
+ if (mHandler== null || pw == null) {
+ return;
+ }
+ DumpUtils.dumpAsync(mHandler, new DumpUtils.Dump() {
+ @Override
+ public void dump(PrintWriter pw) {
+ pw.print(" component="); pw.println(mCurrentDreamComponent);
+ pw.print(" token="); pw.println(mCurrentDreamToken);
+ pw.print(" dream="); pw.println(mCurrentDream);
+ }
+ }, pw, 200);
+ }
+
+ public void start(ComponentName dream, boolean isTest) {
+ if (DEBUG) Slog.v(TAG, String.format("start(%s,%s)", dream, isTest));
+
+ if (mCurrentDreamComponent != null ) {
+ if (dream.equals(mCurrentDreamComponent) && isTest == mCurrentDreamIsTest) {
+ if (DEBUG) Slog.v(TAG, "Dream is already started: " + dream);
+ return;
+ }
+ // stop the current dream before starting a new one
+ stop();
+ }
+
+ mCurrentDreamComponent = dream;
+ mCurrentDreamIsTest = isTest;
+ mCurrentDreamToken = new Binder();
+
+ try {
+ if (DEBUG) Slog.v(TAG, "Adding window token: " + mCurrentDreamToken
+ + " for window type: " + WindowManager.LayoutParams.TYPE_DREAM);
+ mIWindowManager.addWindowToken(mCurrentDreamToken,
+ WindowManager.LayoutParams.TYPE_DREAM);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Unable to add window token.");
+ stop();
+ return;
+ }
+
+ Intent intent = new Intent(Intent.ACTION_MAIN)
+ .setComponent(mCurrentDreamComponent)
+ .addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS)
+ .putExtra("android.dreams.TEST", mCurrentDreamIsTest);
+
+ if (!mContext.bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE)) {
+ Slog.w(TAG, "Unable to bind service");
+ stop();
+ return;
+ }
+ if (DEBUG) Slog.v(TAG, "Bound service");
+ }
+
+ public void attach(ComponentName name, IBinder dream) {
+ if (DEBUG) Slog.v(TAG, String.format("attach(%s,%s)", name, dream));
+ mCurrentDream = IDreamService.Stub.asInterface(dream);
+
+ boolean linked = linkDeathRecipient(dream);
+ if (!linked) {
+ stop();
+ return;
+ }
+
+ try {
+ if (DEBUG) Slog.v(TAG, "Attaching with token:" + mCurrentDreamToken);
+ mCurrentDream.attach(mCurrentDreamToken);
+ } catch (Throwable ex) {
+ Slog.w(TAG, "Unable to send window token to dream:" + ex);
+ stop();
+ }
+ }
+
+ public void stop() {
+ if (DEBUG) Slog.v(TAG, "stop()");
+
+ if (mCurrentDream != null) {
+ unlinkDeathRecipient(mCurrentDream.asBinder());
+
+ if (DEBUG) Slog.v(TAG, "Unbinding: " + mCurrentDreamComponent + " service: " + mCurrentDream);
+ mContext.unbindService(mServiceConnection);
+ }
+ if (mCurrentDreamToken != null) {
+ removeWindowToken(mCurrentDreamToken);
+ }
+
+ final boolean wasTest = mCurrentDreamIsTest;
+ mCurrentDream = null;
+ mCurrentDreamToken = null;
+ mCurrentDreamComponent = null;
+ mCurrentDreamIsTest = false;
+
+ if (mListener != null && mHandler != null) {
+ mHandler.post(new Runnable(){
+ @Override
+ public void run() {
+ mListener.onDreamStopped(wasTest);
+ }});
+ }
+ }
+
+ public void stopSelf(IBinder token) {
+ if (DEBUG) Slog.v(TAG, String.format("stopSelf(%s)", token));
+ if (token == null || token != mCurrentDreamToken) {
+ Slog.w(TAG, "Stop requested for non-current dream token: " + token);
+ } else {
+ stop();
+ }
+ }
+
+ private void removeWindowToken(IBinder token) {
+ if (DEBUG) Slog.v(TAG, "Removing window token: " + token);
+ try {
+ mIWindowManager.removeWindowToken(token);
+ } catch (Throwable e) {
+ Slog.w(TAG, "Error removing window token", e);
+ }
+ }
+
+ private boolean linkDeathRecipient(IBinder dream) {
+ if (DEBUG) Slog.v(TAG, "Linking death recipient");
+ try {
+ dream.linkToDeath(mDeathRecipient, 0);
+ return true;
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Unable to link death recipient", e);
+ return false;
+ }
+ }
+
+ private void unlinkDeathRecipient(IBinder dream) {
+ if (DEBUG) Slog.v(TAG, "Unlinking death recipient");
+ try {
+ dream.unlinkToDeath(mDeathRecipient, 0);
+ } catch (NoSuchElementException e) {
+ // we tried
+ }
+ }
+
+} \ No newline at end of file
diff --git a/services/java/com/android/server/DreamManagerService.java b/services/java/com/android/server/DreamManagerService.java
new file mode 100644
index 0000000..b02ea7f
--- /dev/null
+++ b/services/java/com/android/server/DreamManagerService.java
@@ -0,0 +1,387 @@
+/*
+ * Copyright (C) 2012 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;
+
+import static android.provider.Settings.Secure.SCREENSAVER_COMPONENTS;
+import static android.provider.Settings.Secure.SCREENSAVER_DEFAULT_COMPONENT;
+
+import android.app.ActivityManagerNative;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.ServiceConnection;
+import android.content.pm.PackageManager;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.service.dreams.Dream;
+import android.service.dreams.IDreamManager;
+import android.util.Slog;
+import android.util.SparseArray;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
+/**
+ * Service api for managing dreams.
+ *
+ * @hide
+ */
+public final class DreamManagerService
+ extends IDreamManager.Stub
+ implements ServiceConnection {
+ private static final boolean DEBUG = true;
+ private static final String TAG = DreamManagerService.class.getSimpleName();
+
+ private static final Intent mDreamingStartedIntent = new Intent(Dream.ACTION_DREAMING_STARTED)
+ .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+ private static final Intent mDreamingStoppedIntent = new Intent(Dream.ACTION_DREAMING_STOPPED)
+ .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+
+ private final Object mLock = new Object();
+ private final DreamController mController;
+ private final DreamControllerHandler mHandler;
+ private final Context mContext;
+
+ private final CurrentUserManager mCurrentUserManager = new CurrentUserManager();
+
+ private final DeathRecipient mAwakenOnBinderDeath = new DeathRecipient() {
+ @Override
+ public void binderDied() {
+ if (DEBUG) Slog.v(TAG, "binderDied()");
+ awaken();
+ }
+ };
+
+ private final DreamController.Listener mControllerListener = new DreamController.Listener() {
+ @Override
+ public void onDreamStopped(boolean wasTest) {
+ synchronized(mLock) {
+ setDreamingLocked(false, wasTest);
+ }
+ }};
+
+ private boolean mIsDreaming;
+
+ public DreamManagerService(Context context) {
+ if (DEBUG) Slog.v(TAG, "DreamManagerService startup");
+ mContext = context;
+ mController = new DreamController(context, mAwakenOnBinderDeath, this, mControllerListener);
+ mHandler = new DreamControllerHandler(mController);
+ mController.setHandler(mHandler);
+ }
+
+ public void systemReady() {
+ mCurrentUserManager.init(mContext);
+
+ if (DEBUG) Slog.v(TAG, "Ready to dream!");
+ }
+
+ @Override
+ protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
+
+ pw.println("Dreamland:");
+ mController.dump(pw);
+ mCurrentUserManager.dump(pw);
+ }
+
+ // begin IDreamManager api
+ @Override
+ public ComponentName[] getDreamComponents() {
+ checkPermission(android.Manifest.permission.READ_DREAM_STATE);
+ int userId = UserHandle.getCallingUserId();
+
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ return getDreamComponentsForUser(userId);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ @Override
+ public void setDreamComponents(ComponentName[] componentNames) {
+ checkPermission(android.Manifest.permission.WRITE_DREAM_STATE);
+ int userId = UserHandle.getCallingUserId();
+
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ Settings.Secure.putStringForUser(mContext.getContentResolver(),
+ SCREENSAVER_COMPONENTS,
+ componentsToString(componentNames),
+ userId);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ @Override
+ public ComponentName getDefaultDreamComponent() {
+ checkPermission(android.Manifest.permission.READ_DREAM_STATE);
+ int userId = UserHandle.getCallingUserId();
+
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ String name = Settings.Secure.getStringForUser(mContext.getContentResolver(),
+ SCREENSAVER_DEFAULT_COMPONENT,
+ userId);
+ return name == null ? null : ComponentName.unflattenFromString(name);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+
+ }
+
+ @Override
+ public boolean isDreaming() {
+ checkPermission(android.Manifest.permission.READ_DREAM_STATE);
+
+ return mIsDreaming;
+ }
+
+ @Override
+ public void dream() {
+ checkPermission(android.Manifest.permission.WRITE_DREAM_STATE);
+
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ if (DEBUG) Slog.v(TAG, "Dream now");
+ ComponentName[] dreams = getDreamComponentsForUser(mCurrentUserManager.getCurrentUserId());
+ ComponentName firstDream = dreams != null && dreams.length > 0 ? dreams[0] : null;
+ if (firstDream != null) {
+ mHandler.requestStart(firstDream, false /*isTest*/);
+ synchronized (mLock) {
+ setDreamingLocked(true, false /*isTest*/);
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ @Override
+ public void testDream(ComponentName dream) {
+ checkPermission(android.Manifest.permission.WRITE_DREAM_STATE);
+
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ if (DEBUG) Slog.v(TAG, "Test dream name=" + dream);
+ if (dream != null) {
+ mHandler.requestStart(dream, true /*isTest*/);
+ synchronized (mLock) {
+ setDreamingLocked(true, true /*isTest*/);
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+
+ }
+
+ @Override
+ public void awaken() {
+ checkPermission(android.Manifest.permission.WRITE_DREAM_STATE);
+
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ if (DEBUG) Slog.v(TAG, "Wake up");
+ mHandler.requestStop();
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ @Override
+ public void awakenSelf(IBinder token) {
+ // requires no permission, called by Dream from an arbitrary process
+
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ if (DEBUG) Slog.v(TAG, "Wake up from dream: " + token);
+ if (token != null) {
+ mHandler.requestStopSelf(token);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+ // end IDreamManager api
+
+ // begin ServiceConnection
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder dream) {
+ if (DEBUG) Slog.v(TAG, "Service connected: " + name + " binder=" +
+ dream + " thread=" + Thread.currentThread().getId());
+ mHandler.requestAttach(name, dream);
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ if (DEBUG) Slog.v(TAG, "Service disconnected: " + name);
+ // Only happens in exceptional circumstances, awaken just to be safe
+ awaken();
+ }
+ // end ServiceConnection
+
+ private void checkPermission(String permission) {
+ if (PackageManager.PERMISSION_GRANTED != mContext.checkCallingOrSelfPermission(permission)) {
+ throw new SecurityException("Access denied to process: " + Binder.getCallingPid()
+ + ", must have permission " + permission);
+ }
+ }
+
+ private void setDreamingLocked(boolean isDreaming, boolean isTest) {
+ boolean wasDreaming = mIsDreaming;
+ if (!isTest) {
+ if (!wasDreaming && isDreaming) {
+ if (DEBUG) Slog.v(TAG, "Firing ACTION_DREAMING_STARTED");
+ mContext.sendBroadcast(mDreamingStartedIntent);
+ } else if (wasDreaming && !isDreaming) {
+ if (DEBUG) Slog.v(TAG, "Firing ACTION_DREAMING_STOPPED");
+ mContext.sendBroadcast(mDreamingStoppedIntent);
+ }
+ }
+ mIsDreaming = isDreaming;
+ }
+
+ private ComponentName[] getDreamComponentsForUser(int userId) {
+ String names = Settings.Secure.getStringForUser(mContext.getContentResolver(),
+ SCREENSAVER_COMPONENTS,
+ userId);
+ return names == null ? null : componentsFromString(names);
+ }
+
+ private static String componentsToString(ComponentName[] componentNames) {
+ StringBuilder names = new StringBuilder();
+ if (componentNames != null) {
+ for (ComponentName componentName : componentNames) {
+ if (names.length() > 0) {
+ names.append(',');
+ }
+ names.append(componentName.flattenToString());
+ }
+ }
+ return names.toString();
+ }
+
+ private static ComponentName[] componentsFromString(String names) {
+ String[] namesArray = names.split(",");
+ ComponentName[] componentNames = new ComponentName[namesArray.length];
+ for (int i = 0; i < namesArray.length; i++) {
+ componentNames[i] = ComponentName.unflattenFromString(namesArray[i]);
+ }
+ return componentNames;
+ }
+
+ /**
+ * Keeps track of the current user, since dream() uses the current user's configuration.
+ */
+ private static class CurrentUserManager {
+ private final Object mLock = new Object();
+ private int mCurrentUserId;
+
+ public void init(Context context) {
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(Intent.ACTION_USER_SWITCHED);
+ context.registerReceiver(new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ if (Intent.ACTION_USER_SWITCHED.equals(action)) {
+ synchronized(mLock) {
+ mCurrentUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
+ if (DEBUG) Slog.v(TAG, "userId " + mCurrentUserId + " is in the house");
+ }
+ }
+ }}, filter);
+ try {
+ synchronized (mLock) {
+ mCurrentUserId = ActivityManagerNative.getDefault().getCurrentUser().id;
+ }
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Couldn't get current user ID; guessing it's 0", e);
+ }
+ }
+
+ public void dump(PrintWriter pw) {
+ pw.print(" user="); pw.println(getCurrentUserId());
+ }
+
+ public int getCurrentUserId() {
+ synchronized(mLock) {
+ return mCurrentUserId;
+ }
+ }
+ }
+
+ /**
+ * Handler for asynchronous operations performed by the dream manager.
+ *
+ * Ensures operations to {@link DreamController} are single-threaded.
+ */
+ private static final class DreamControllerHandler extends Handler {
+ private final DreamController mController;
+ private final Runnable mStopRunnable = new Runnable() {
+ @Override
+ public void run() {
+ mController.stop();
+ }};
+
+ public DreamControllerHandler(DreamController controller) {
+ super(true /*async*/);
+ mController = controller;
+ }
+
+ public void requestStart(final ComponentName name, final boolean isTest) {
+ post(new Runnable(){
+ @Override
+ public void run() {
+ mController.start(name, isTest);
+ }});
+ }
+
+ public void requestAttach(final ComponentName name, final IBinder dream) {
+ post(new Runnable(){
+ @Override
+ public void run() {
+ mController.attach(name, dream);
+ }});
+ }
+
+ public void requestStopSelf(final IBinder token) {
+ post(new Runnable(){
+ @Override
+ public void run() {
+ mController.stopSelf(token);
+ }});
+ }
+
+ public void requestStop() {
+ post(mStopRunnable);
+ }
+
+ }
+
+}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 90783b7..6c5a4e2 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -38,7 +38,6 @@ import android.os.StrictMode;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.server.search.SearchManagerService;
-import android.service.dreams.DreamManagerService;
import android.util.DisplayMetrics;
import android.util.EventLog;
import android.util.Log;
@@ -149,6 +148,7 @@ class ServerThread extends Thread {
NetworkTimeUpdateService networkTimeUpdater = null;
CommonTimeManagementService commonTimeMgmtService = null;
InputManagerService inputManager = null;
+ TelephonyRegistry telephonyRegistry = null;
// Create a shared handler thread for UI within the system server.
// This thread is used by at least the following components:
@@ -189,7 +189,7 @@ class ServerThread extends Thread {
// For debug builds, log event loop stalls to dropbox for analysis.
if (StrictMode.conditionallyEnableDebugLogging()) {
- Slog.i(TAG, "Enabled StrictMode logging for UI Looper");
+ Slog.i(TAG, "Enabled StrictMode logging for WM Looper");
}
}
});
@@ -219,7 +219,8 @@ class ServerThread extends Thread {
ServiceManager.addService(Context.DISPLAY_SERVICE, display, true);
Slog.i(TAG, "Telephony Registry");
- ServiceManager.addService("telephony.registry", new TelephonyRegistry(context));
+ telephonyRegistry = new TelephonyRegistry(context);
+ ServiceManager.addService("telephony.registry", telephonyRegistry);
Slog.i(TAG, "Scheduling Policy");
ServiceManager.addService(Context.SCHEDULING_POLICY_SERVICE,
@@ -845,6 +846,7 @@ class ServerThread extends Thread {
final StatusBarManagerService statusBarF = statusBar;
final DreamManagerService dreamyF = dreamy;
final InputManagerService inputManagerF = inputManager;
+ final TelephonyRegistry telephonyRegistryF = telephonyRegistry;
// We now tell the activity manager it is okay to run third party
// code. It will call back into us once it has gotten to the state
@@ -972,6 +974,11 @@ class ServerThread extends Thread {
} catch (Throwable e) {
reportWtf("making InputManagerService ready", e);
}
+ try {
+ if (telephonyRegistryF != null) telephonyRegistryF.systemReady();
+ } catch (Throwable e) {
+ reportWtf("making TelephonyRegistry ready", e);
+ }
}
});
diff --git a/services/java/com/android/server/TelephonyRegistry.java b/services/java/com/android/server/TelephonyRegistry.java
index 8361477..26684de 100644
--- a/services/java/com/android/server/TelephonyRegistry.java
+++ b/services/java/com/android/server/TelephonyRegistry.java
@@ -16,14 +16,19 @@
package com.android.server;
+import android.app.ActivityManager;
+import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
+import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.net.LinkCapabilities;
import android.net.LinkProperties;
import android.os.Binder;
import android.os.Bundle;
+import android.os.Handler;
import android.os.IBinder;
+import android.os.Message;
import android.os.RemoteException;
import android.os.UserHandle;
import android.telephony.CellLocation;
@@ -39,13 +44,11 @@ import java.util.ArrayList;
import java.util.List;
import java.io.FileDescriptor;
import java.io.PrintWriter;
-import java.net.NetworkInterface;
import com.android.internal.app.IBatteryStats;
import com.android.internal.telephony.ITelephonyRegistry;
import com.android.internal.telephony.IPhoneStateListener;
import com.android.internal.telephony.DefaultPhoneNotifier;
-import com.android.internal.telephony.Phone;
import com.android.internal.telephony.PhoneConstants;
import com.android.internal.telephony.ServiceStateTracker;
import com.android.internal.telephony.TelephonyIntents;
@@ -58,6 +61,7 @@ import com.android.server.am.BatteryStatsService;
class TelephonyRegistry extends ITelephonyRegistry.Stub {
private static final String TAG = "TelephonyRegistry";
private static final boolean DBG = false;
+ private static final boolean DBG_LOC = false;
private static class Record {
String pkgForDebug;
@@ -66,7 +70,15 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
IPhoneStateListener callback;
+ int callerUid;
+
int events;
+
+ @Override
+ public String toString() {
+ return "{pkgForDebug=" + pkgForDebug + " callerUid=" + callerUid +
+ " events=" + Integer.toHexString(events) + "}";
+ }
}
private final Context mContext;
@@ -120,6 +132,32 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
PhoneStateListener.LISTEN_DATA_CONNECTION_STATE |
PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR;
+ private static final int MSG_USER_SWITCHED = 1;
+
+ private final Handler mHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_USER_SWITCHED: {
+ Slog.d(TAG, "MSG_USER_SWITCHED userId=" + msg.arg1);
+ TelephonyRegistry.this.notifyCellLocation(mCellLocation);
+ break;
+ }
+ }
+ }
+ };
+
+ private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ if (Intent.ACTION_USER_SWITCHED.equals(action)) {
+ mHandler.sendMessage(mHandler.obtainMessage(MSG_USER_SWITCHED,
+ intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0), 0));
+ }
+ }
+ };
+
// we keep a copy of all of the state so we can send it out when folks
// register for it
//
@@ -140,10 +178,24 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
mConnectedApns = new ArrayList<String>();
}
+ public void systemReady() {
+ // Watch for interesting updates
+ final IntentFilter filter = new IntentFilter();
+ filter.addAction(Intent.ACTION_USER_SWITCHED);
+ filter.addAction(Intent.ACTION_USER_REMOVED);
+ mContext.registerReceiver(mBroadcastReceiver, filter);
+ }
+
+ @Override
public void listen(String pkgForDebug, IPhoneStateListener callback, int events,
boolean notifyNow) {
- // Slog.d(TAG, "listen pkg=" + pkgForDebug + " events=0x" +
- // Integer.toHexString(events));
+ int callerUid = UserHandle.getCallingUserId();
+ int myUid = UserHandle.myUserId();
+ if (DBG) {
+ Slog.d(TAG, "listen: E pkg=" + pkgForDebug + " events=0x" + Integer.toHexString(events)
+ + " myUid=" + myUid
+ + " callerUid=" + callerUid);
+ }
if (events != 0) {
/* Checks permission and throws Security exception */
checkListenerPermission(events);
@@ -164,7 +216,9 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
r.binder = b;
r.callback = callback;
r.pkgForDebug = pkgForDebug;
+ r.callerUid = callerUid;
mRecords.add(r);
+ if (DBG) Slog.i(TAG, "listen: add new record=" + r);
}
int send = events & (events ^ r.events);
r.events = events;
@@ -199,8 +253,9 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
remove(r.binder);
}
}
- if ((events & PhoneStateListener.LISTEN_CELL_LOCATION) != 0) {
+ if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_LOCATION)) {
try {
+ if (DBG_LOC) Slog.d(TAG, "listen: mCellLocation=" + mCellLocation);
r.callback.onCellLocationChanged(new Bundle(mCellLocation));
} catch (RemoteException ex) {
remove(r.binder);
@@ -242,8 +297,9 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
remove(r.binder);
}
}
- if ((events & PhoneStateListener.LISTEN_CELL_INFO) != 0) {
+ if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_INFO)) {
try {
+ if (DBG_LOC) Slog.d(TAG, "listen: mCellInfo=" + mCellInfo);
r.callback.onCellInfoChanged(mCellInfo);
} catch (RemoteException ex) {
remove(r.binder);
@@ -346,8 +402,11 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
synchronized (mRecords) {
mCellInfo = cellInfo;
for (Record r : mRecords) {
- if ((r.events & PhoneStateListener.LISTEN_CELL_INFO) != 0) {
+ if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_INFO)) {
try {
+ if (DBG_LOC) {
+ Slog.d(TAG, "notifyCellInfo: mCellInfo=" + mCellInfo + " r=" + r);
+ }
r.callback.onCellInfoChanged(cellInfo);
} catch (RemoteException ex) {
mRemoveList.add(r.binder);
@@ -424,7 +483,8 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
if (DBG) {
Slog.i(TAG, "notifyDataConnection: state=" + state + " isDataConnectivityPossible="
+ isDataConnectivityPossible + " reason='" + reason
- + "' apn='" + apn + "' apnType=" + apnType + " networkType=" + networkType);
+ + "' apn='" + apn + "' apnType=" + apnType + " networkType=" + networkType
+ + " mRecords.size()=" + mRecords.size() + " mRecords=" + mRecords);
}
synchronized (mRecords) {
boolean modified = false;
@@ -506,8 +566,12 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
synchronized (mRecords) {
mCellLocation = cellLocation;
for (Record r : mRecords) {
- if ((r.events & PhoneStateListener.LISTEN_CELL_LOCATION) != 0) {
+ if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_LOCATION)) {
try {
+ if (DBG_LOC) {
+ Slog.d(TAG, "notifyCellLocation: mCellLocation=" + mCellLocation
+ + " r=" + r);
+ }
r.callback.onCellLocationChanged(new Bundle(cellLocation));
} catch (RemoteException ex) {
mRemoveList.add(r.binder);
@@ -712,4 +776,22 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
mRemoveList.clear();
}
}
+
+ private boolean validateEventsAndUserLocked(Record r, int events) {
+ int foregroundUser;
+ long callingIdentity = Binder.clearCallingIdentity();
+ boolean valid = false;
+ try {
+ foregroundUser = ActivityManager.getCurrentUser();
+ valid = r.callerUid == foregroundUser && (r.events & events) != 0;
+ if (DBG | DBG_LOC) {
+ Slog.d(TAG, "validateEventsAndUserLocked: valid=" + valid
+ + " r.callerUid=" + r.callerUid + " foregroundUser=" + foregroundUser
+ + " r.events=" + r.events + " events=" + events);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(callingIdentity);
+ }
+ return valid;
+ }
}
diff --git a/services/java/com/android/server/WallpaperManagerService.java b/services/java/com/android/server/WallpaperManagerService.java
index b027c1f..4225913 100644
--- a/services/java/com/android/server/WallpaperManagerService.java
+++ b/services/java/com/android/server/WallpaperManagerService.java
@@ -293,17 +293,18 @@ class WallpaperManagerService extends IWallpaperManager.Stub {
@Override
public void onPackageUpdateFinished(String packageName, int uid) {
synchronized (mLock) {
- for (int i = 0; i < mWallpaperMap.size(); i++) {
- WallpaperData wallpaper = mWallpaperMap.valueAt(i);
+ if (mCurrentUserId != getChangingUserId()) {
+ return;
+ }
+ WallpaperData wallpaper = mWallpaperMap.get(mCurrentUserId);
+ if (wallpaper != null) {
if (wallpaper.wallpaperComponent != null
&& wallpaper.wallpaperComponent.getPackageName().equals(packageName)) {
wallpaper.wallpaperUpdating = false;
ComponentName comp = wallpaper.wallpaperComponent;
clearWallpaperComponentLocked(wallpaper);
- // Do this only for the current user's wallpaper
- if (wallpaper.userId == mCurrentUserId
- && !bindWallpaperComponentLocked(comp, false, false,
- wallpaper, null)) {
+ if (!bindWallpaperComponentLocked(comp, false, false,
+ wallpaper, null)) {
Slog.w(TAG, "Wallpaper no longer available; reverting to default");
clearWallpaperLocked(false, wallpaper.userId, null);
}
@@ -315,11 +316,14 @@ class WallpaperManagerService extends IWallpaperManager.Stub {
@Override
public void onPackageModified(String packageName) {
synchronized (mLock) {
- for (int i = 0; i < mWallpaperMap.size(); i++) {
- WallpaperData wallpaper = mWallpaperMap.valueAt(i);
+ if (mCurrentUserId != getChangingUserId()) {
+ return;
+ }
+ WallpaperData wallpaper = mWallpaperMap.get(mCurrentUserId);
+ if (wallpaper != null) {
if (wallpaper.wallpaperComponent == null
|| !wallpaper.wallpaperComponent.getPackageName().equals(packageName)) {
- continue;
+ return;
}
doPackagesChangedLocked(true, wallpaper);
}
@@ -329,8 +333,11 @@ class WallpaperManagerService extends IWallpaperManager.Stub {
@Override
public void onPackageUpdateStarted(String packageName, int uid) {
synchronized (mLock) {
- for (int i = 0; i < mWallpaperMap.size(); i++) {
- WallpaperData wallpaper = mWallpaperMap.valueAt(i);
+ if (mCurrentUserId != getChangingUserId()) {
+ return;
+ }
+ WallpaperData wallpaper = mWallpaperMap.get(mCurrentUserId);
+ if (wallpaper != null) {
if (wallpaper.wallpaperComponent != null
&& wallpaper.wallpaperComponent.getPackageName().equals(packageName)) {
wallpaper.wallpaperUpdating = true;
@@ -343,8 +350,11 @@ class WallpaperManagerService extends IWallpaperManager.Stub {
public boolean onHandleForceStop(Intent intent, String[] packages, int uid, boolean doit) {
synchronized (mLock) {
boolean changed = false;
- for (int i = 0; i < mWallpaperMap.size(); i++) {
- WallpaperData wallpaper = mWallpaperMap.valueAt(i);
+ if (mCurrentUserId != getChangingUserId()) {
+ return false;
+ }
+ WallpaperData wallpaper = mWallpaperMap.get(mCurrentUserId);
+ if (wallpaper != null) {
boolean res = doPackagesChangedLocked(doit, wallpaper);
changed |= res;
}
@@ -355,8 +365,11 @@ class WallpaperManagerService extends IWallpaperManager.Stub {
@Override
public void onSomePackagesChanged() {
synchronized (mLock) {
- for (int i = 0; i < mWallpaperMap.size(); i++) {
- WallpaperData wallpaper = mWallpaperMap.valueAt(i);
+ if (mCurrentUserId != getChangingUserId()) {
+ return;
+ }
+ WallpaperData wallpaper = mWallpaperMap.get(mCurrentUserId);
+ if (wallpaper != null) {
doPackagesChangedLocked(true, wallpaper);
}
}
@@ -416,7 +429,7 @@ class WallpaperManagerService extends IWallpaperManager.Stub {
ServiceManager.getService(Context.WINDOW_SERVICE));
mIPackageManager = AppGlobals.getPackageManager();
mMonitor = new MyPackageMonitor();
- mMonitor.register(context, null, true);
+ mMonitor.register(context, null, UserHandle.ALL, true);
getWallpaperDir(UserHandle.USER_OWNER).mkdirs();
loadSettingsLocked(UserHandle.USER_OWNER);
}
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 66b60ec..cd3aeff 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -147,6 +147,7 @@ import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
@@ -168,6 +169,7 @@ public final class ActivityManagerService extends ActivityManagerNative
static final boolean localLOGV = DEBUG;
static final boolean DEBUG_SWITCH = localLOGV || false;
static final boolean DEBUG_TASKS = localLOGV || false;
+ static final boolean DEBUG_THUMBNAILS = localLOGV || false;
static final boolean DEBUG_PAUSE = localLOGV || false;
static final boolean DEBUG_OOM_ADJ = localLOGV || false;
static final boolean DEBUG_TRANSITION = localLOGV || false;
@@ -447,6 +449,11 @@ public final class ActivityManagerService extends ActivityManagerNative
final ArrayList<Integer> mUserLru = new ArrayList<Integer>();
/**
+ * Constant array of the users that are currently started.
+ */
+ int[] mStartedUserArray = new int[] { 0 };
+
+ /**
* Registered observers of the user switching mechanics.
*/
final RemoteCallbackList<IUserSwitchObserver> mUserSwitchObservers
@@ -831,7 +838,8 @@ public final class ActivityManagerService extends ActivityManagerNative
static ActivityManagerService mSelf;
static ActivityThread mSystemThread;
- private int mCurrentUserId;
+ private int mCurrentUserId = 0;
+ private int[] mCurrentUserArray = new int[] { 0 };
private UserManagerService mUserManager;
private final class AppDeathRecipient implements IBinder.DeathRecipient {
@@ -1567,6 +1575,7 @@ public final class ActivityManagerService extends ActivityManagerNative
// User 0 is the first and only user that runs at boot.
mStartedUsers.put(0, new UserStartedState(new UserHandle(0), true));
mUserLru.add(Integer.valueOf(0));
+ updateStartedUserArrayLocked();
GL_ES_VERSION = SystemProperties.getInt("ro.opengles.version",
ConfigurationInfo.GL_ES_VERSION_UNDEFINED);
@@ -3749,6 +3758,7 @@ public final class ActivityManagerService extends ActivityManagerNative
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
}
intent.putExtra(Intent.EXTRA_UID, uid);
+ intent.putExtra(Intent.EXTRA_USER_HANDLE, UserHandle.getUserId(uid));
broadcastIntentLocked(null, null, intent,
null, null, 0, null, null, null,
false, false,
@@ -5849,6 +5859,18 @@ public final class ActivityManagerService extends ActivityManagerNative
return null;
}
+ public Bitmap getTaskTopThumbnail(int id) {
+ synchronized (this) {
+ enforceCallingPermission(android.Manifest.permission.READ_FRAME_BUFFER,
+ "getTaskTopThumbnail()");
+ TaskRecord tr = taskForIdLocked(id);
+ if (tr != null) {
+ return mMainStack.getTaskTopThumbnailLocked(tr);
+ }
+ }
+ return null;
+ }
+
public boolean removeSubTask(int taskId, int subTaskIndex) {
synchronized (this) {
enforceCallingPermission(android.Manifest.permission.REMOVE_TASKS,
@@ -9298,6 +9320,9 @@ public final class ActivityManagerService extends ActivityManagerNative
pw.print(mUserLru.get(i));
}
pw.println("]");
+ if (dumpAll) {
+ pw.print(" mStartedUserArray: "); pw.println(Arrays.toString(mStartedUserArray));
+ }
pw.println(" mHomeProcess: " + mHomeProcess);
pw.println(" mPreviousProcess: " + mPreviousProcess);
if (dumpAll) {
@@ -11485,7 +11510,7 @@ public final class ActivityManagerService extends ActivityManagerNative
userId = handleIncomingUserLocked(callingPid, callingUid, userId,
true, false, "broadcast", callerPackage);
- // Make sure that the user who is receiving this broadcast is started
+ // Make sure that the user who is receiving this broadcast is started.
// If not, we will just skip it.
if (userId != UserHandle.USER_ALL && mStartedUsers.get(userId) == null) {
if (callingUid != Process.SYSTEM_UID || (intent.getFlags()
@@ -11680,13 +11705,10 @@ public final class ActivityManagerService extends ActivityManagerNative
int[] users;
if (userId == UserHandle.USER_ALL) {
// Caller wants broadcast to go to all started users.
- users = new int[mStartedUsers.size()];
- for (int i=0; i<mStartedUsers.size(); i++) {
- users[i] = mStartedUsers.keyAt(i);
- }
+ users = mStartedUserArray;
} else {
// Caller wants broadcast to go to one specific user.
- users = new int[] {userId};
+ users = mCurrentUserArray;
}
// Figure out who all will receive this broadcast.
@@ -13962,13 +13984,17 @@ public final class ActivityManagerService extends ActivityManagerNative
// we need to start it now.
if (mStartedUsers.get(userId) == null) {
mStartedUsers.put(userId, new UserStartedState(new UserHandle(userId), false));
+ updateStartedUserArrayLocked();
}
mCurrentUserId = userId;
+ mCurrentUserArray = new int[] { userId };
final Integer userIdInt = Integer.valueOf(userId);
mUserLru.remove(userIdInt);
mUserLru.add(userIdInt);
+ mWindowManager.setCurrentUser(userId);
+
final UserStartedState uss = mStartedUsers.get(userId);
mHandler.removeMessages(REPORT_USER_SWITCH_MSG);
@@ -14007,7 +14033,7 @@ public final class ActivityManagerService extends ActivityManagerNative
if (!haveActivities) {
startHomeActivityLocked(userId);
}
-
+
sendUserSwitchBroadcastsLocked(oldUserId, userId);
}
} finally {
@@ -14241,6 +14267,7 @@ public final class ActivityManagerService extends ActivityManagerNative
// User can no longer run.
mStartedUsers.remove(userId);
mUserLru.remove(Integer.valueOf(userId));
+ updateStartedUserArrayLocked();
// Clean up all state and processes associated with the user.
// Kill all the processes for the user.
@@ -14297,6 +14324,29 @@ public final class ActivityManagerService extends ActivityManagerNative
}
@Override
+ public int[] getRunningUserIds() {
+ if (checkCallingPermission(android.Manifest.permission.INTERACT_ACROSS_USERS)
+ != PackageManager.PERMISSION_GRANTED) {
+ String msg = "Permission Denial: isUserRunning() from pid="
+ + Binder.getCallingPid()
+ + ", uid=" + Binder.getCallingUid()
+ + " requires " + android.Manifest.permission.INTERACT_ACROSS_USERS;
+ Slog.w(TAG, msg);
+ throw new SecurityException(msg);
+ }
+ synchronized (this) {
+ return mStartedUserArray;
+ }
+ }
+
+ private void updateStartedUserArrayLocked() {
+ mStartedUserArray = new int[mStartedUsers.size()];
+ for (int i=0; i<mStartedUsers.size(); i++) {
+ mStartedUserArray[i] = mStartedUsers.keyAt(i);
+ }
+ }
+
+ @Override
public void registerUserSwitchObserver(IUserSwitchObserver observer) {
if (checkCallingPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
!= PackageManager.PERMISSION_GRANTED) {
diff --git a/services/java/com/android/server/am/ActivityRecord.java b/services/java/com/android/server/am/ActivityRecord.java
index 009fb5d..7ff5748 100644
--- a/services/java/com/android/server/am/ActivityRecord.java
+++ b/services/java/com/android/server/am/ActivityRecord.java
@@ -219,7 +219,13 @@ final class ActivityRecord {
pw.print(prefix); pw.print("frozenBeforeDestroy="); pw.print(frozenBeforeDestroy);
pw.print(" thumbnailNeeded="); pw.print(thumbnailNeeded);
pw.print(" forceNewConfig="); pw.println(forceNewConfig);
- pw.print(prefix); pw.print("thumbHolder="); pw.println(thumbHolder);
+ pw.print(prefix); pw.print("thumbHolder: ");
+ pw.print(Integer.toHexString(System.identityHashCode(thumbHolder)));
+ if (thumbHolder != null) {
+ pw.print(" bm="); pw.print(thumbHolder.lastThumbnail);
+ pw.print(" desc="); pw.print(thumbHolder.lastDescription);
+ }
+ pw.println();
if (launchTime != 0 || startTime != 0) {
pw.print(prefix); pw.print("launchTime=");
if (launchTime == 0) pw.print("0");
@@ -674,19 +680,15 @@ final class ActivityRecord {
}
if (thumbHolder != null) {
if (newThumbnail != null) {
+ if (ActivityManagerService.DEBUG_THUMBNAILS) Slog.i(ActivityManagerService.TAG,
+ "Setting thumbnail of " + this + " holder " + thumbHolder
+ + " to " + newThumbnail);
thumbHolder.lastThumbnail = newThumbnail;
}
thumbHolder.lastDescription = description;
}
}
- void clearThumbnail() {
- if (thumbHolder != null) {
- thumbHolder.lastThumbnail = null;
- thumbHolder.lastDescription = null;
- }
- }
-
void startLaunchTickingLocked() {
if (ActivityManagerService.IS_USER_BUILD) {
return;
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index 29ee0bc..df50d89 100755
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -1203,8 +1203,7 @@ final class ActivityStack {
if (mMainStack) {
mService.reportResumedActivityLocked(next);
}
-
- next.clearThumbnail();
+
if (mMainStack) {
mService.setFocusedActivityLocked(next);
}
@@ -4328,18 +4327,33 @@ final class ActivityStack {
finishTaskMoveLocked(task);
return true;
}
-
+
public ActivityManager.TaskThumbnails getTaskThumbnailsLocked(TaskRecord tr) {
TaskAccessInfo info = getTaskAccessInfoLocked(tr.taskId, true);
ActivityRecord resumed = mResumedActivity;
if (resumed != null && resumed.thumbHolder == tr) {
info.mainThumbnail = resumed.stack.screenshotActivities(resumed);
- } else {
- info.mainThumbnail = tr.lastThumbnail;
}
return info;
}
+ public Bitmap getTaskTopThumbnailLocked(TaskRecord tr) {
+ ActivityRecord resumed = mResumedActivity;
+ if (resumed != null && resumed.task == tr) {
+ // This task is the current resumed task, we just need to take
+ // a screenshot of it and return that.
+ return resumed.stack.screenshotActivities(resumed);
+ }
+ // Return the information about the task, to figure out the top
+ // thumbnail to return.
+ TaskAccessInfo info = getTaskAccessInfoLocked(tr.taskId, true);
+ if (info.numSubThumbbails <= 0) {
+ return info.mainThumbnail;
+ } else {
+ return info.subtasks.get(info.numSubThumbbails-1).holder.lastThumbnail;
+ }
+ }
+
public ActivityRecord removeTaskActivitiesLocked(int taskId, int subTaskIndex,
boolean taskRequired) {
TaskAccessInfo info = getTaskAccessInfoLocked(taskId, false);
@@ -4370,7 +4384,6 @@ final class ActivityStack {
}
public TaskAccessInfo getTaskAccessInfoLocked(int taskId, boolean inclThumbs) {
- ActivityRecord resumed = mResumedActivity;
final TaskAccessInfo thumbs = new TaskAccessInfo();
// How many different sub-thumbnails?
final int NA = mHistory.size();
@@ -4380,6 +4393,10 @@ final class ActivityStack {
ActivityRecord ar = mHistory.get(j);
if (!ar.finishing && ar.task.taskId == taskId) {
holder = ar.thumbHolder;
+ if (holder != null) {
+ thumbs.mainThumbnail = holder.lastThumbnail;
+ }
+ j++;
break;
}
j++;
@@ -4394,7 +4411,6 @@ final class ActivityStack {
ArrayList<TaskAccessInfo.SubTask> subtasks = new ArrayList<TaskAccessInfo.SubTask>();
thumbs.subtasks = subtasks;
- ActivityRecord lastActivity = null;
while (j < NA) {
ActivityRecord ar = mHistory.get(j);
j++;
@@ -4404,30 +4420,28 @@ final class ActivityStack {
if (ar.task.taskId != taskId) {
break;
}
- lastActivity = ar;
if (ar.thumbHolder != holder && holder != null) {
thumbs.numSubThumbbails++;
holder = ar.thumbHolder;
TaskAccessInfo.SubTask sub = new TaskAccessInfo.SubTask();
- sub.thumbnail = holder.lastThumbnail;
+ sub.holder = holder;
sub.activity = ar;
sub.index = j-1;
subtasks.add(sub);
}
}
- if (lastActivity != null && subtasks.size() > 0) {
- if (resumed == lastActivity) {
- TaskAccessInfo.SubTask sub = subtasks.get(subtasks.size()-1);
- sub.thumbnail = lastActivity.stack.screenshotActivities(lastActivity);
- }
- }
if (thumbs.numSubThumbbails > 0) {
thumbs.retriever = new IThumbnailRetriever.Stub() {
public Bitmap getThumbnail(int index) {
if (index < 0 || index >= thumbs.subtasks.size()) {
return null;
}
- return thumbs.subtasks.get(index).thumbnail;
+ TaskAccessInfo.SubTask sub = thumbs.subtasks.get(index);
+ ActivityRecord resumed = mResumedActivity;
+ if (resumed != null && resumed.thumbHolder == sub.holder) {
+ return resumed.stack.screenshotActivities(resumed);
+ }
+ return sub.holder.lastThumbnail;
}
};
}
diff --git a/services/java/com/android/server/am/TaskAccessInfo.java b/services/java/com/android/server/am/TaskAccessInfo.java
index 5618c1a..50aeec1 100644
--- a/services/java/com/android/server/am/TaskAccessInfo.java
+++ b/services/java/com/android/server/am/TaskAccessInfo.java
@@ -19,11 +19,10 @@ package com.android.server.am;
import java.util.ArrayList;
import android.app.ActivityManager.TaskThumbnails;
-import android.graphics.Bitmap;
final class TaskAccessInfo extends TaskThumbnails {
final static class SubTask {
- Bitmap thumbnail;
+ ThumbnailHolder holder;
ActivityRecord activity;
int index;
}
diff --git a/services/java/com/android/server/am/UsageStatsService.java b/services/java/com/android/server/am/UsageStatsService.java
index 7059674..6dae4aa 100644
--- a/services/java/com/android/server/am/UsageStatsService.java
+++ b/services/java/com/android/server/am/UsageStatsService.java
@@ -650,7 +650,7 @@ public final class UsageStatsService extends IUsageStats.Stub {
public void monitorPackages() {
mPackageMonitor = new PackageMonitor() {
@Override
- public void onPackageRemoved(String packageName, int uid) {
+ public void onPackageRemovedAllUsers(String packageName, int uid) {
synchronized (mStatsLock) {
mLastResumeTimes.remove(packageName);
}
diff --git a/services/java/com/android/server/display/DisplayManagerService.java b/services/java/com/android/server/display/DisplayManagerService.java
index 39f2418..02fc6b1 100644
--- a/services/java/com/android/server/display/DisplayManagerService.java
+++ b/services/java/com/android/server/display/DisplayManagerService.java
@@ -148,6 +148,9 @@ public final class DisplayManagerService extends IDisplayManager.Stub {
private final DisplayViewport mDefaultViewport = new DisplayViewport();
private final DisplayViewport mExternalTouchViewport = new DisplayViewport();
+ // Persistent data store for all internal settings maintained by the display manager service.
+ private final PersistentDataStore mPersistentDataStore = new PersistentDataStore();
+
// Temporary callback list, used when sending display events to applications.
// May be used outside of the lock but only on the handler thread.
private final ArrayList<CallbackRecord> mTempCallbacks = new ArrayList<CallbackRecord>();
@@ -403,6 +406,50 @@ public final class DisplayManagerService extends IDisplayManager.Stub {
}
@Override // Binder call
+ public void renameWifiDisplay(String address, String alias) {
+ if (mContext.checkCallingPermission(android.Manifest.permission.CONFIGURE_WIFI_DISPLAY)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Requires CONFIGURE_WIFI_DISPLAY permission");
+ }
+ if (address == null) {
+ throw new IllegalArgumentException("address must not be null");
+ }
+
+ final long token = Binder.clearCallingIdentity();
+ try {
+ synchronized (mSyncRoot) {
+ if (mWifiDisplayAdapter != null) {
+ mWifiDisplayAdapter.requestRenameLocked(address, alias);
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @Override // Binder call
+ public void forgetWifiDisplay(String address) {
+ if (mContext.checkCallingPermission(android.Manifest.permission.CONFIGURE_WIFI_DISPLAY)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Requires CONFIGURE_WIFI_DISPLAY permission");
+ }
+ if (address == null) {
+ throw new IllegalArgumentException("address must not be null");
+ }
+
+ final long token = Binder.clearCallingIdentity();
+ try {
+ synchronized (mSyncRoot) {
+ if (mWifiDisplayAdapter != null) {
+ mWifiDisplayAdapter.requestForgetLocked(address);
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @Override // Binder call
public WifiDisplayStatus getWifiDisplayStatus() {
if (mContext.checkCallingPermission(android.Manifest.permission.CONFIGURE_WIFI_DISPLAY)
!= PackageManager.PERMISSION_GRANTED) {
@@ -439,15 +486,27 @@ public final class DisplayManagerService extends IDisplayManager.Stub {
private void registerAdditionalDisplayAdapters() {
synchronized (mSyncRoot) {
if (shouldRegisterNonEssentialDisplayAdaptersLocked()) {
- registerDisplayAdapterLocked(new OverlayDisplayAdapter(
- mSyncRoot, mContext, mHandler, mDisplayAdapterListener, mUiHandler));
- mWifiDisplayAdapter = new WifiDisplayAdapter(
- mSyncRoot, mContext, mHandler, mDisplayAdapterListener);
- registerDisplayAdapterLocked(mWifiDisplayAdapter);
+ registerOverlayDisplayAdapterLocked();
+ registerWifiDisplayAdapterLocked();
}
}
}
+ private void registerOverlayDisplayAdapterLocked() {
+ registerDisplayAdapterLocked(new OverlayDisplayAdapter(
+ mSyncRoot, mContext, mHandler, mDisplayAdapterListener, mUiHandler));
+ }
+
+ private void registerWifiDisplayAdapterLocked() {
+ if (mContext.getResources().getBoolean(
+ com.android.internal.R.bool.config_enableWifiDisplay)) {
+ mWifiDisplayAdapter = new WifiDisplayAdapter(
+ mSyncRoot, mContext, mHandler, mDisplayAdapterListener,
+ mPersistentDataStore);
+ registerDisplayAdapterLocked(mWifiDisplayAdapter);
+ }
+ }
+
private boolean shouldRegisterNonEssentialDisplayAdaptersLocked() {
// In safe mode, we disable non-essential display adapters to give the user
// an opportunity to fix broken settings or other problems that might affect
diff --git a/services/java/com/android/server/display/PersistentDataStore.java b/services/java/com/android/server/display/PersistentDataStore.java
new file mode 100644
index 0000000..3a6e1a6
--- /dev/null
+++ b/services/java/com/android/server/display/PersistentDataStore.java
@@ -0,0 +1,292 @@
+/*
+ * Copyright (C) 2012 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.display;
+
+import com.android.internal.util.FastXmlSerializer;
+import com.android.internal.util.XmlUtils;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import android.hardware.display.WifiDisplay;
+import android.util.AtomicFile;
+import android.util.Slog;
+import android.util.Xml;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+
+import libcore.io.IoUtils;
+import libcore.util.Objects;
+
+/**
+ * Manages persistent state recorded by the display manager service as an XML file.
+ * Caller must acquire lock on the data store before accessing it.
+ *
+ * File format:
+ * <code>
+ * &lt;display-manager-state>
+ * &lt;remembered-wifi-displays>
+ * &lt;wifi-display deviceAddress="00:00:00:00:00:00" deviceName="XXXX" deviceAlias="YYYY" />
+ * &gt;remembered-wifi-displays>
+ * &gt;/display-manager-state>
+ * </code>
+ *
+ * TODO: refactor this to extract common code shared with the input manager's data store
+ */
+final class PersistentDataStore {
+ static final String TAG = "DisplayManager";
+
+ // Remembered Wifi display devices.
+ private ArrayList<WifiDisplay> mRememberedWifiDisplays = new ArrayList<WifiDisplay>();
+
+ // The atomic file used to safely read or write the file.
+ private final AtomicFile mAtomicFile;
+
+ // True if the data has been loaded.
+ private boolean mLoaded;
+
+ // True if there are changes to be saved.
+ private boolean mDirty;
+
+ public PersistentDataStore() {
+ mAtomicFile = new AtomicFile(new File("/data/system/display-manager-state.xml"));
+ }
+
+ public void saveIfNeeded() {
+ if (mDirty) {
+ save();
+ mDirty = false;
+ }
+ }
+
+ public WifiDisplay[] getRememberedWifiDisplays() {
+ loadIfNeeded();
+ return mRememberedWifiDisplays.toArray(new WifiDisplay[mRememberedWifiDisplays.size()]);
+ }
+
+ public WifiDisplay applyWifiDisplayAlias(WifiDisplay display) {
+ if (display != null) {
+ loadIfNeeded();
+
+ String alias = null;
+ int index = findRememberedWifiDisplay(display.getDeviceAddress());
+ if (index >= 0) {
+ alias = mRememberedWifiDisplays.get(index).getDeviceAlias();
+ }
+ if (!Objects.equal(display.getDeviceAlias(), alias)) {
+ return new WifiDisplay(display.getDeviceAddress(), display.getDeviceName(), alias);
+ }
+ }
+ return display;
+ }
+
+ public WifiDisplay[] applyWifiDisplayAliases(WifiDisplay[] displays) {
+ WifiDisplay[] results = displays;
+ if (results != null) {
+ int count = displays.length;
+ for (int i = 0; i < count; i++) {
+ WifiDisplay result = applyWifiDisplayAlias(displays[i]);
+ if (result != displays[i]) {
+ if (results == displays) {
+ results = new WifiDisplay[count];
+ System.arraycopy(displays, 0, results, 0, count);
+ }
+ results[i] = result;
+ }
+ }
+ }
+ return results;
+ }
+
+ public boolean rememberWifiDisplay(WifiDisplay display) {
+ loadIfNeeded();
+
+ int index = findRememberedWifiDisplay(display.getDeviceAddress());
+ if (index >= 0) {
+ WifiDisplay other = mRememberedWifiDisplays.get(index);
+ if (other.equals(display)) {
+ return false; // already remembered without change
+ }
+ mRememberedWifiDisplays.set(index, display);
+ } else {
+ mRememberedWifiDisplays.add(display);
+ }
+ setDirty();
+ return true;
+ }
+
+ public boolean renameWifiDisplay(String deviceAddress, String alias) {
+ int index = findRememberedWifiDisplay(deviceAddress);
+ if (index >= 0) {
+ WifiDisplay display = mRememberedWifiDisplays.get(index);
+ if (Objects.equal(display.getDeviceAlias(), alias)) {
+ return false; // already has this alias
+ }
+ WifiDisplay renamedDisplay = new WifiDisplay(deviceAddress,
+ display.getDeviceName(), alias);
+ mRememberedWifiDisplays.set(index, renamedDisplay);
+ setDirty();
+ return true;
+ }
+ return false;
+ }
+
+ public boolean forgetWifiDisplay(String deviceAddress) {
+ int index = findRememberedWifiDisplay(deviceAddress);
+ if (index >= 0) {
+ mRememberedWifiDisplays.remove(index);
+ setDirty();
+ return true;
+ }
+ return false;
+ }
+
+ private int findRememberedWifiDisplay(String deviceAddress) {
+ int count = mRememberedWifiDisplays.size();
+ for (int i = 0; i < count; i++) {
+ if (mRememberedWifiDisplays.get(i).getDeviceAddress().equals(deviceAddress)) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ private void loadIfNeeded() {
+ if (!mLoaded) {
+ load();
+ mLoaded = true;
+ }
+ }
+
+ private void setDirty() {
+ mDirty = true;
+ }
+
+ private void clearState() {
+ mRememberedWifiDisplays.clear();
+ }
+
+ private void load() {
+ clearState();
+
+ final InputStream is;
+ try {
+ is = mAtomicFile.openRead();
+ } catch (FileNotFoundException ex) {
+ return;
+ }
+
+ XmlPullParser parser;
+ try {
+ parser = Xml.newPullParser();
+ parser.setInput(new BufferedInputStream(is), null);
+ loadFromXml(parser);
+ } catch (IOException ex) {
+ Slog.w(TAG, "Failed to load display manager persistent store data.", ex);
+ clearState();
+ } catch (XmlPullParserException ex) {
+ Slog.w(TAG, "Failed to load display manager persistent store data.", ex);
+ clearState();
+ } finally {
+ IoUtils.closeQuietly(is);
+ }
+ }
+
+ private void save() {
+ final FileOutputStream os;
+ try {
+ os = mAtomicFile.startWrite();
+ boolean success = false;
+ try {
+ XmlSerializer serializer = new FastXmlSerializer();
+ serializer.setOutput(new BufferedOutputStream(os), "utf-8");
+ saveToXml(serializer);
+ serializer.flush();
+ success = true;
+ } finally {
+ if (success) {
+ mAtomicFile.finishWrite(os);
+ } else {
+ mAtomicFile.failWrite(os);
+ }
+ }
+ } catch (IOException ex) {
+ Slog.w(TAG, "Failed to save display manager persistent store data.", ex);
+ }
+ }
+
+ private void loadFromXml(XmlPullParser parser)
+ throws IOException, XmlPullParserException {
+ XmlUtils.beginDocument(parser, "display-manager-state");
+ final int outerDepth = parser.getDepth();
+ while (XmlUtils.nextElementWithin(parser, outerDepth)) {
+ if (parser.getName().equals("remembered-wifi-displays")) {
+ loadRememberedWifiDisplaysFromXml(parser);
+ }
+ }
+ }
+
+ private void loadRememberedWifiDisplaysFromXml(XmlPullParser parser)
+ throws IOException, XmlPullParserException {
+ final int outerDepth = parser.getDepth();
+ while (XmlUtils.nextElementWithin(parser, outerDepth)) {
+ if (parser.getName().equals("wifi-display")) {
+ String deviceAddress = parser.getAttributeValue(null, "deviceAddress");
+ String deviceName = parser.getAttributeValue(null, "deviceName");
+ String deviceAlias = parser.getAttributeValue(null, "deviceAlias");
+ if (deviceAddress == null || deviceName == null) {
+ throw new XmlPullParserException(
+ "Missing deviceAddress or deviceName attribute on wifi-display.");
+ }
+ if (findRememberedWifiDisplay(deviceAddress) >= 0) {
+ throw new XmlPullParserException(
+ "Found duplicate wifi display device address.");
+ }
+
+ mRememberedWifiDisplays.add(
+ new WifiDisplay(deviceAddress, deviceName, deviceAlias));
+ }
+ }
+ }
+
+ private void saveToXml(XmlSerializer serializer) throws IOException {
+ serializer.startDocument(null, true);
+ serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
+ serializer.startTag(null, "display-manager-state");
+ serializer.startTag(null, "remembered-wifi-displays");
+ for (WifiDisplay display : mRememberedWifiDisplays) {
+ serializer.startTag(null, "wifi-display");
+ serializer.attribute(null, "deviceAddress", display.getDeviceAddress());
+ serializer.attribute(null, "deviceName", display.getDeviceName());
+ if (display.getDeviceAlias() != null) {
+ serializer.attribute(null, "deviceAlias", display.getDeviceAlias());
+ }
+ serializer.endTag(null, "wifi-display");
+ }
+ serializer.endTag(null, "remembered-wifi-displays");
+ serializer.endTag(null, "display-manager-state");
+ serializer.endDocument();
+ }
+} \ No newline at end of file
diff --git a/services/java/com/android/server/display/WifiDisplayAdapter.java b/services/java/com/android/server/display/WifiDisplayAdapter.java
index b57d3dc..1d50ded 100644
--- a/services/java/com/android/server/display/WifiDisplayAdapter.java
+++ b/services/java/com/android/server/display/WifiDisplayAdapter.java
@@ -49,21 +49,26 @@ import java.util.Arrays;
final class WifiDisplayAdapter extends DisplayAdapter {
private static final String TAG = "WifiDisplayAdapter";
+ private PersistentDataStore mPersistentDataStore;
+
private WifiDisplayController mDisplayController;
private WifiDisplayDevice mDisplayDevice;
private WifiDisplayStatus mCurrentStatus;
- private boolean mEnabled;
+ private int mFeatureState;
private int mScanState;
private int mActiveDisplayState;
private WifiDisplay mActiveDisplay;
- private WifiDisplay[] mKnownDisplays = WifiDisplay.EMPTY_ARRAY;
+ private WifiDisplay[] mAvailableDisplays = WifiDisplay.EMPTY_ARRAY;
+ private WifiDisplay[] mRememberedDisplays = WifiDisplay.EMPTY_ARRAY;
private boolean mPendingStatusChangeBroadcast;
public WifiDisplayAdapter(DisplayManagerService.SyncRoot syncRoot,
- Context context, Handler handler, Listener listener) {
+ Context context, Handler handler, Listener listener,
+ PersistentDataStore persistentDataStore) {
super(syncRoot, context, handler, listener, TAG);
+ mPersistentDataStore = persistentDataStore;
}
@Override
@@ -71,11 +76,12 @@ final class WifiDisplayAdapter extends DisplayAdapter {
super.dumpLocked(pw);
pw.println("mCurrentStatus=" + getWifiDisplayStatusLocked());
- pw.println("mEnabled=" + mEnabled);
+ pw.println("mFeatureState=" + mFeatureState);
pw.println("mScanState=" + mScanState);
pw.println("mActiveDisplayState=" + mActiveDisplayState);
pw.println("mActiveDisplay=" + mActiveDisplay);
- pw.println("mKnownDisplays=" + Arrays.toString(mKnownDisplays));
+ pw.println("mAvailableDisplays=" + Arrays.toString(mAvailableDisplays));
+ pw.println("mRememberedDisplays=" + Arrays.toString(mRememberedDisplays));
pw.println("mPendingStatusChangeBroadcast=" + mPendingStatusChangeBroadcast);
// Try to dump the controller state.
@@ -93,6 +99,8 @@ final class WifiDisplayAdapter extends DisplayAdapter {
public void registerLocked() {
super.registerLocked();
+ updateRememberedDisplaysLocked();
+
getHandler().post(new Runnable() {
@Override
public void run() {
@@ -135,18 +143,58 @@ final class WifiDisplayAdapter extends DisplayAdapter {
});
}
+ public void requestRenameLocked(String address, String alias) {
+ if (alias != null) {
+ alias = alias.trim();
+ if (alias.isEmpty()) {
+ alias = null;
+ }
+ }
+
+ if (mPersistentDataStore.renameWifiDisplay(address, alias)) {
+ mPersistentDataStore.saveIfNeeded();
+ updateRememberedDisplaysLocked();
+ scheduleStatusChangedBroadcastLocked();
+ }
+ }
+
+ public void requestForgetLocked(String address) {
+ if (mPersistentDataStore.forgetWifiDisplay(address)) {
+ mPersistentDataStore.saveIfNeeded();
+ updateRememberedDisplaysLocked();
+ scheduleStatusChangedBroadcastLocked();
+ }
+
+ if (mActiveDisplay != null && mActiveDisplay.getDeviceAddress().equals(address)) {
+ requestDisconnectLocked();
+ }
+ }
+
public WifiDisplayStatus getWifiDisplayStatusLocked() {
if (mCurrentStatus == null) {
- mCurrentStatus = new WifiDisplayStatus(mEnabled, mScanState, mActiveDisplayState,
- mActiveDisplay, mKnownDisplays);
+ mCurrentStatus = new WifiDisplayStatus(
+ mFeatureState, mScanState, mActiveDisplayState,
+ mActiveDisplay, mAvailableDisplays, mRememberedDisplays);
}
return mCurrentStatus;
}
+ private void updateRememberedDisplaysLocked() {
+ mRememberedDisplays = mPersistentDataStore.getRememberedWifiDisplays();
+ mActiveDisplay = mPersistentDataStore.applyWifiDisplayAlias(mActiveDisplay);
+ mAvailableDisplays = mPersistentDataStore.applyWifiDisplayAliases(mAvailableDisplays);
+ }
+
private void handleConnectLocked(WifiDisplay display,
Surface surface, int width, int height, int flags) {
handleDisconnectLocked();
+ if (mPersistentDataStore.rememberWifiDisplay(display)) {
+ mPersistentDataStore.saveIfNeeded();
+ updateRememberedDisplaysLocked();
+ scheduleStatusChangedBroadcastLocked();
+ }
+
int deviceFlags = 0;
if ((flags & RemoteDisplay.DISPLAY_FLAG_SECURE) != 0) {
deviceFlags |= DisplayDeviceInfo.FLAG_SUPPORTS_SECURE_VIDEO_OUTPUT;
@@ -154,7 +202,7 @@ final class WifiDisplayAdapter extends DisplayAdapter {
float refreshRate = 60.0f; // TODO: get this for real
- String name = display.getDeviceName();
+ String name = display.getFriendlyDisplayName();
IBinder displayToken = Surface.createDisplay(name);
mDisplayDevice = new WifiDisplayDevice(displayToken, name, width, height,
refreshRate, deviceFlags, surface);
@@ -170,6 +218,7 @@ final class WifiDisplayAdapter extends DisplayAdapter {
}
private void scheduleStatusChangedBroadcastLocked() {
+ mCurrentStatus = null;
if (!mPendingStatusChangeBroadcast) {
mPendingStatusChangeBroadcast = true;
getHandler().post(mStatusChangeBroadcast);
@@ -202,11 +251,10 @@ final class WifiDisplayAdapter extends DisplayAdapter {
private final WifiDisplayController.Listener mWifiDisplayListener =
new WifiDisplayController.Listener() {
@Override
- public void onEnablementChanged(boolean enabled) {
+ public void onFeatureStateChanged(int featureState) {
synchronized (getSyncRoot()) {
- if (mEnabled != enabled) {
- mCurrentStatus = null;
- mEnabled = enabled;
+ if (mFeatureState != featureState) {
+ mFeatureState = featureState;
scheduleStatusChangedBroadcastLocked();
}
}
@@ -216,20 +264,21 @@ final class WifiDisplayAdapter extends DisplayAdapter {
public void onScanStarted() {
synchronized (getSyncRoot()) {
if (mScanState != WifiDisplayStatus.SCAN_STATE_SCANNING) {
- mCurrentStatus = null;
mScanState = WifiDisplayStatus.SCAN_STATE_SCANNING;
scheduleStatusChangedBroadcastLocked();
}
}
}
- public void onScanFinished(WifiDisplay[] knownDisplays) {
+ public void onScanFinished(WifiDisplay[] availableDisplays) {
synchronized (getSyncRoot()) {
+ availableDisplays = mPersistentDataStore.applyWifiDisplayAliases(
+ availableDisplays);
+
if (mScanState != WifiDisplayStatus.SCAN_STATE_NOT_SCANNING
- || !Arrays.equals(mKnownDisplays, knownDisplays)) {
- mCurrentStatus = null;
+ || !Arrays.equals(mAvailableDisplays, availableDisplays)) {
mScanState = WifiDisplayStatus.SCAN_STATE_NOT_SCANNING;
- mKnownDisplays = knownDisplays;
+ mAvailableDisplays = availableDisplays;
scheduleStatusChangedBroadcastLocked();
}
}
@@ -238,10 +287,11 @@ final class WifiDisplayAdapter extends DisplayAdapter {
@Override
public void onDisplayConnecting(WifiDisplay display) {
synchronized (getSyncRoot()) {
+ display = mPersistentDataStore.applyWifiDisplayAlias(display);
+
if (mActiveDisplayState != WifiDisplayStatus.DISPLAY_STATE_CONNECTING
|| mActiveDisplay == null
|| !mActiveDisplay.equals(display)) {
- mCurrentStatus = null;
mActiveDisplayState = WifiDisplayStatus.DISPLAY_STATE_CONNECTING;
mActiveDisplay = display;
scheduleStatusChangedBroadcastLocked();
@@ -254,7 +304,6 @@ final class WifiDisplayAdapter extends DisplayAdapter {
synchronized (getSyncRoot()) {
if (mActiveDisplayState != WifiDisplayStatus.DISPLAY_STATE_NOT_CONNECTED
|| mActiveDisplay != null) {
- mCurrentStatus = null;
mActiveDisplayState = WifiDisplayStatus.DISPLAY_STATE_NOT_CONNECTED;
mActiveDisplay = null;
scheduleStatusChangedBroadcastLocked();
@@ -266,12 +315,12 @@ final class WifiDisplayAdapter extends DisplayAdapter {
public void onDisplayConnected(WifiDisplay display, Surface surface,
int width, int height, int flags) {
synchronized (getSyncRoot()) {
+ display = mPersistentDataStore.applyWifiDisplayAlias(display);
handleConnectLocked(display, surface, width, height, flags);
if (mActiveDisplayState != WifiDisplayStatus.DISPLAY_STATE_CONNECTED
|| mActiveDisplay == null
|| !mActiveDisplay.equals(display)) {
- mCurrentStatus = null;
mActiveDisplayState = WifiDisplayStatus.DISPLAY_STATE_CONNECTED;
mActiveDisplay = display;
scheduleStatusChangedBroadcastLocked();
@@ -287,7 +336,6 @@ final class WifiDisplayAdapter extends DisplayAdapter {
if (mActiveDisplayState != WifiDisplayStatus.DISPLAY_STATE_NOT_CONNECTED
|| mActiveDisplay != null) {
- mCurrentStatus = null;
mActiveDisplayState = WifiDisplayStatus.DISPLAY_STATE_NOT_CONNECTED;
mActiveDisplay = null;
scheduleStatusChangedBroadcastLocked();
diff --git a/services/java/com/android/server/display/WifiDisplayController.java b/services/java/com/android/server/display/WifiDisplayController.java
index 328f687..84f4e83 100644
--- a/services/java/com/android/server/display/WifiDisplayController.java
+++ b/services/java/com/android/server/display/WifiDisplayController.java
@@ -19,13 +19,17 @@ package com.android.server.display;
import com.android.internal.util.DumpUtils;
import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.database.ContentObserver;
import android.hardware.display.WifiDisplay;
+import android.hardware.display.WifiDisplayStatus;
import android.media.AudioManager;
import android.media.RemoteDisplay;
import android.net.NetworkInfo;
+import android.net.Uri;
import android.net.wifi.p2p.WifiP2pConfig;
import android.net.wifi.p2p.WifiP2pDevice;
import android.net.wifi.p2p.WifiP2pDeviceList;
@@ -37,6 +41,7 @@ import android.net.wifi.p2p.WifiP2pManager.Channel;
import android.net.wifi.p2p.WifiP2pManager.GroupInfoListener;
import android.net.wifi.p2p.WifiP2pManager.PeerListListener;
import android.os.Handler;
+import android.provider.Settings;
import android.util.Slog;
import android.view.Surface;
@@ -48,6 +53,8 @@ import java.net.SocketException;
import java.util.ArrayList;
import java.util.Enumeration;
+import libcore.util.Objects;
+
/**
* Manages all of the various asynchronous interactions with the {@link WifiP2pManager}
* on behalf of {@link WifiDisplayAdapter}.
@@ -94,9 +101,12 @@ final class WifiDisplayController implements DumpUtils.Dump {
private boolean mWfdEnabling;
private NetworkInfo mNetworkInfo;
- private final ArrayList<WifiP2pDevice> mKnownWifiDisplayPeers =
+ private final ArrayList<WifiP2pDevice> mAvailableWifiDisplayPeers =
new ArrayList<WifiP2pDevice>();
+ // True if Wifi display is enabled by the user.
+ private boolean mWifiDisplayOnSetting;
+
// True if there is a call to discoverPeers in progress.
private boolean mDiscoverPeersInProgress;
@@ -132,6 +142,13 @@ final class WifiDisplayController implements DumpUtils.Dump {
// True if the remote submix is enabled.
private boolean mRemoteSubmixOn;
+ // The information we have most recently told WifiDisplayAdapter about.
+ private WifiDisplay mAdvertisedDisplay;
+ private Surface mAdvertisedDisplaySurface;
+ private int mAdvertisedDisplayWidth;
+ private int mAdvertisedDisplayHeight;
+ private int mAdvertisedDisplayFlags;
+
public WifiDisplayController(Context context, Handler handler, Listener listener) {
mContext = context;
mHandler = handler;
@@ -146,10 +163,31 @@ final class WifiDisplayController implements DumpUtils.Dump {
intentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION);
intentFilter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION);
intentFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
- context.registerReceiver(mWifiP2pReceiver, intentFilter);
+ context.registerReceiver(mWifiP2pReceiver, intentFilter, null, mHandler);
+
+ ContentObserver settingsObserver = new ContentObserver(mHandler) {
+ @Override
+ public void onChange(boolean selfChange, Uri uri) {
+ updateSettings();
+ }
+ };
+
+ final ContentResolver resolver = mContext.getContentResolver();
+ resolver.registerContentObserver(Settings.Global.getUriFor(
+ Settings.Global.WIFI_DISPLAY_ON), false, settingsObserver);
+ updateSettings();
+ }
+
+ private void updateSettings() {
+ final ContentResolver resolver = mContext.getContentResolver();
+ mWifiDisplayOnSetting = Settings.Global.getInt(resolver,
+ Settings.Global.WIFI_DISPLAY_ON, 0) != 0;
+
+ updateWfdEnableState();
}
public void dump(PrintWriter pw) {
+ pw.println("mWifiDisplayOnSetting=" + mWifiDisplayOnSetting);
pw.println("mWifiP2pEnabled=" + mWifiP2pEnabled);
pw.println("mWfdEnabled=" + mWfdEnabled);
pw.println("mWfdEnabling=" + mWfdEnabling);
@@ -164,9 +202,14 @@ final class WifiDisplayController implements DumpUtils.Dump {
pw.println("mRemoteDisplayInterface=" + mRemoteDisplayInterface);
pw.println("mRemoteDisplayConnected=" + mRemoteDisplayConnected);
pw.println("mRemoteSubmixOn=" + mRemoteSubmixOn);
-
- pw.println("mKnownWifiDisplayPeers: size=" + mKnownWifiDisplayPeers.size());
- for (WifiP2pDevice device : mKnownWifiDisplayPeers) {
+ pw.println("mAdvertisedDisplay=" + mAdvertisedDisplay);
+ pw.println("mAdvertisedDisplaySurface=" + mAdvertisedDisplaySurface);
+ pw.println("mAdvertisedDisplayWidth=" + mAdvertisedDisplayWidth);
+ pw.println("mAdvertisedDisplayHeight=" + mAdvertisedDisplayHeight);
+ pw.println("mAdvertisedDisplayFlags=" + mAdvertisedDisplayFlags);
+
+ pw.println("mAvailableWifiDisplayPeers: size=" + mAvailableWifiDisplayPeers.size());
+ for (WifiP2pDevice device : mAvailableWifiDisplayPeers) {
pw.println(" " + describeWifiP2pDevice(device));
}
}
@@ -176,7 +219,7 @@ final class WifiDisplayController implements DumpUtils.Dump {
}
public void requestConnect(String address) {
- for (WifiP2pDevice device : mKnownWifiDisplayPeers) {
+ for (WifiP2pDevice device : mAvailableWifiDisplayPeers) {
if (device.deviceAddress.equals(address)) {
connect(device);
}
@@ -187,49 +230,65 @@ final class WifiDisplayController implements DumpUtils.Dump {
disconnect();
}
- private void enableWfd() {
- if (!mWfdEnabled && !mWfdEnabling) {
- mWfdEnabling = true;
-
- WifiP2pWfdInfo wfdInfo = new WifiP2pWfdInfo();
- wfdInfo.setWfdEnabled(true);
- wfdInfo.setDeviceType(WifiP2pWfdInfo.WFD_SOURCE);
- wfdInfo.setSessionAvailable(true);
- wfdInfo.setControlPort(DEFAULT_CONTROL_PORT);
- wfdInfo.setMaxThroughput(MAX_THROUGHPUT);
- mWifiP2pManager.setWFDInfo(mWifiP2pChannel, wfdInfo, new ActionListener() {
- @Override
- public void onSuccess() {
- if (DEBUG) {
- Slog.d(TAG, "Successfully set WFD info.");
- }
- if (mWfdEnabling) {
- mWfdEnabling = false;
- setWfdEnabled(true);
+ private void updateWfdEnableState() {
+ if (mWifiDisplayOnSetting && mWifiP2pEnabled) {
+ // WFD should be enabled.
+ if (!mWfdEnabled && !mWfdEnabling) {
+ mWfdEnabling = true;
+
+ WifiP2pWfdInfo wfdInfo = new WifiP2pWfdInfo();
+ wfdInfo.setWfdEnabled(true);
+ wfdInfo.setDeviceType(WifiP2pWfdInfo.WFD_SOURCE);
+ wfdInfo.setSessionAvailable(true);
+ wfdInfo.setControlPort(DEFAULT_CONTROL_PORT);
+ wfdInfo.setMaxThroughput(MAX_THROUGHPUT);
+ mWifiP2pManager.setWFDInfo(mWifiP2pChannel, wfdInfo, new ActionListener() {
+ @Override
+ public void onSuccess() {
+ if (DEBUG) {
+ Slog.d(TAG, "Successfully set WFD info.");
+ }
+ if (mWfdEnabling) {
+ mWfdEnabling = false;
+ mWfdEnabled = true;
+ reportFeatureState();
+ }
}
- }
- @Override
- public void onFailure(int reason) {
- if (DEBUG) {
- Slog.d(TAG, "Failed to set WFD info with reason " + reason + ".");
+ @Override
+ public void onFailure(int reason) {
+ if (DEBUG) {
+ Slog.d(TAG, "Failed to set WFD info with reason " + reason + ".");
+ }
+ mWfdEnabling = false;
}
- mWfdEnabling = false;
- }
- });
+ });
+ }
+ } else {
+ // WFD should be disabled.
+ mWfdEnabling = false;
+ mWfdEnabled = false;
+ reportFeatureState();
+ disconnect();
}
}
- private void setWfdEnabled(final boolean enabled) {
- if (mWfdEnabled != enabled) {
- mWfdEnabled = enabled;
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- mListener.onEnablementChanged(enabled);
- }
- });
+ private void reportFeatureState() {
+ final int featureState = computeFeatureState();
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mListener.onFeatureStateChanged(featureState);
+ }
+ });
+ }
+
+ private int computeFeatureState() {
+ if (!mWifiP2pEnabled) {
+ return WifiDisplayStatus.FEATURE_STATE_DISABLED;
}
+ return mWifiDisplayOnSetting ? WifiDisplayStatus.FEATURE_STATE_ON :
+ WifiDisplayStatus.FEATURE_STATE_OFF;
}
private void discoverPeers() {
@@ -296,14 +355,14 @@ final class WifiDisplayController implements DumpUtils.Dump {
Slog.d(TAG, "Received list of peers.");
}
- mKnownWifiDisplayPeers.clear();
+ mAvailableWifiDisplayPeers.clear();
for (WifiP2pDevice device : peers.getDeviceList()) {
if (DEBUG) {
Slog.d(TAG, " " + describeWifiP2pDevice(device));
}
if (isWifiDisplay(device)) {
- mKnownWifiDisplayPeers.add(device);
+ mAvailableWifiDisplayPeers.add(device);
}
}
@@ -322,10 +381,10 @@ final class WifiDisplayController implements DumpUtils.Dump {
}
private void handleScanFinished() {
- final int count = mKnownWifiDisplayPeers.size();
+ final int count = mAvailableWifiDisplayPeers.size();
final WifiDisplay[] displays = WifiDisplay.CREATOR.newArray(count);
for (int i = 0; i < count; i++) {
- displays[i] = createWifiDisplay(mKnownWifiDisplayPeers.get(i));
+ displays[i] = createWifiDisplay(mAvailableWifiDisplayPeers.get(i));
}
mHandler.post(new Runnable() {
@@ -368,18 +427,11 @@ final class WifiDisplayController implements DumpUtils.Dump {
}
private void retryConnection() {
- if (mDesiredDevice != null && mConnectedDevice != mDesiredDevice
- && mConnectionRetriesLeft > 0) {
- mConnectionRetriesLeft -= 1;
- Slog.i(TAG, "Retrying Wifi display connection. Retries left: "
- + mConnectionRetriesLeft);
-
- // Cheap hack. Make a new instance of the device object so that we
- // can distinguish it from the previous connection attempt.
- // This will cause us to tear everything down before we try again.
- mDesiredDevice = new WifiP2pDevice(mDesiredDevice);
- updateConnection();
- }
+ // Cheap hack. Make a new instance of the device object so that we
+ // can distinguish it from the previous connection attempt.
+ // This will cause us to tear everything down before we try again.
+ mDesiredDevice = new WifiP2pDevice(mDesiredDevice);
+ updateConnection();
}
/**
@@ -401,13 +453,7 @@ final class WifiDisplayController implements DumpUtils.Dump {
mHandler.removeCallbacks(mRtspTimeout);
setRemoteSubmixOn(false);
-
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- mListener.onDisplayDisconnected();
- }
- });
+ unadvertiseDisplay();
// continue to next step
}
@@ -416,6 +462,8 @@ final class WifiDisplayController implements DumpUtils.Dump {
if (mConnectedDevice != null && mConnectedDevice != mDesiredDevice) {
Slog.i(TAG, "Disconnecting from Wifi display: " + mConnectedDevice.deviceName);
+ unadvertiseDisplay();
+
final WifiP2pDevice oldDevice = mConnectedDevice;
mWifiP2pManager.removeGroup(mWifiP2pChannel, new ActionListener() {
@Override
@@ -446,6 +494,7 @@ final class WifiDisplayController implements DumpUtils.Dump {
if (mConnectingDevice != null && mConnectingDevice != mDesiredDevice) {
Slog.i(TAG, "Canceling connection to Wifi display: " + mConnectingDevice.deviceName);
+ unadvertiseDisplay();
mHandler.removeCallbacks(mConnectionTimeout);
final WifiP2pDevice oldDevice = mConnectingDevice;
@@ -475,6 +524,7 @@ final class WifiDisplayController implements DumpUtils.Dump {
// Step 4. If we wanted to disconnect, then mission accomplished.
if (mDesiredDevice == null) {
+ unadvertiseDisplay();
return; // done
}
@@ -488,13 +538,8 @@ final class WifiDisplayController implements DumpUtils.Dump {
// Helps with STA & P2P concurrency
config.groupOwnerIntent = WifiP2pConfig.MAX_GROUP_OWNER_INTENT;
- final WifiDisplay display = createWifiDisplay(mConnectingDevice);
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- mListener.onDisplayConnecting(display);
- }
- });
+ WifiDisplay display = createWifiDisplay(mConnectingDevice);
+ advertiseDisplay(display, null, 0, 0, 0);
final WifiP2pDevice newDevice = mDesiredDevice;
mWifiP2pManager.connect(mWifiP2pChannel, config, new ActionListener() {
@@ -543,8 +588,8 @@ final class WifiDisplayController implements DumpUtils.Dump {
mRemoteDisplay = RemoteDisplay.listen(iface, new RemoteDisplay.Listener() {
@Override
- public void onDisplayConnected(final Surface surface,
- final int width, final int height, final int flags) {
+ public void onDisplayConnected(Surface surface,
+ int width, int height, int flags) {
if (mConnectedDevice == oldDevice && !mRemoteDisplayConnected) {
Slog.i(TAG, "Opened RTSP connection with Wifi display: "
+ mConnectedDevice.deviceName);
@@ -552,13 +597,7 @@ final class WifiDisplayController implements DumpUtils.Dump {
mHandler.removeCallbacks(mRtspTimeout);
final WifiDisplay display = createWifiDisplay(mConnectedDevice);
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- mListener.onDisplayConnected(display,
- surface, width, height, flags);
- }
- });
+ advertiseDisplay(display, surface, width, height, flags);
}
}
@@ -595,26 +634,13 @@ final class WifiDisplayController implements DumpUtils.Dump {
}
private void handleStateChanged(boolean enabled) {
- if (mWifiP2pEnabled != enabled) {
- mWifiP2pEnabled = enabled;
- if (enabled) {
- if (!mWfdEnabled) {
- enableWfd();
- }
- } else {
- setWfdEnabled(false);
- disconnect();
- }
- }
+ mWifiP2pEnabled = enabled;
+ updateWfdEnableState();
}
private void handlePeersChanged() {
- if (mWifiP2pEnabled) {
- if (mWfdEnabled) {
- requestPeers();
- } else {
- enableWfd();
- }
+ if (mWfdEnabled) {
+ requestPeers();
}
}
@@ -632,7 +658,8 @@ final class WifiDisplayController implements DumpUtils.Dump {
if (mConnectingDevice != null && !info.contains(mConnectingDevice)) {
Slog.i(TAG, "Aborting connection to Wifi display because "
+ "the current P2P group does not contain the device "
- + "we expected to find: " + mConnectingDevice.deviceName);
+ + "we expected to find: " + mConnectingDevice.deviceName
+ + ", group info was: " + describeWifiP2pGroup(info));
handleConnectionFailure(false);
return;
}
@@ -695,19 +722,18 @@ final class WifiDisplayController implements DumpUtils.Dump {
private void handleConnectionFailure(boolean timeoutOccurred) {
Slog.i(TAG, "Wifi display connection failed!");
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- mListener.onDisplayConnectionFailed();
- }
- });
-
if (mDesiredDevice != null) {
if (mConnectionRetriesLeft > 0) {
+ final WifiP2pDevice oldDevice = mDesiredDevice;
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
- retryConnection();
+ if (mDesiredDevice == oldDevice && mConnectionRetriesLeft > 0) {
+ mConnectionRetriesLeft -= 1;
+ Slog.i(TAG, "Retrying Wifi display connection. Retries left: "
+ + mConnectionRetriesLeft);
+ retryConnection();
+ }
}
}, timeoutOccurred ? 0 : CONNECT_RETRY_DELAY_MILLIS);
} else {
@@ -716,6 +742,48 @@ final class WifiDisplayController implements DumpUtils.Dump {
}
}
+ private void advertiseDisplay(final WifiDisplay display,
+ final Surface surface, final int width, final int height, final int flags) {
+ if (!Objects.equal(mAdvertisedDisplay, display)
+ || mAdvertisedDisplaySurface != surface
+ || mAdvertisedDisplayWidth != width
+ || mAdvertisedDisplayHeight != height
+ || mAdvertisedDisplayFlags != flags) {
+ final WifiDisplay oldDisplay = mAdvertisedDisplay;
+ final Surface oldSurface = mAdvertisedDisplaySurface;
+
+ mAdvertisedDisplay = display;
+ mAdvertisedDisplaySurface = surface;
+ mAdvertisedDisplayWidth = width;
+ mAdvertisedDisplayHeight = height;
+ mAdvertisedDisplayFlags = flags;
+
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ if (oldSurface != null && surface != oldSurface) {
+ mListener.onDisplayDisconnected();
+ } else if (oldDisplay != null && !Objects.equal(display, oldDisplay)) {
+ mListener.onDisplayConnectionFailed();
+ }
+
+ if (display != null) {
+ if (!Objects.equal(display, oldDisplay)) {
+ mListener.onDisplayConnecting(display);
+ }
+ if (surface != null && surface != oldSurface) {
+ mListener.onDisplayConnected(display, surface, width, height, flags);
+ }
+ }
+ }
+ });
+ }
+ }
+
+ private void unadvertiseDisplay() {
+ advertiseDisplay(null, null, 0, 0, 0);
+ }
+
private static Inet4Address getInterfaceAddress(WifiP2pGroup info) {
NetworkInterface iface;
try {
@@ -768,7 +836,7 @@ final class WifiDisplayController implements DumpUtils.Dump {
}
private static WifiDisplay createWifiDisplay(WifiP2pDevice device) {
- return new WifiDisplay(device.deviceAddress, device.deviceName);
+ return new WifiDisplay(device.deviceAddress, device.deviceName, null);
}
private final BroadcastReceiver mWifiP2pReceiver = new BroadcastReceiver() {
@@ -776,6 +844,8 @@ final class WifiDisplayController implements DumpUtils.Dump {
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if (action.equals(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION)) {
+ // This broadcast is sticky so we'll always get the initial Wifi P2P state
+ // on startup.
boolean enabled = (intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE,
WifiP2pManager.WIFI_P2P_STATE_DISABLED)) ==
WifiP2pManager.WIFI_P2P_STATE_ENABLED;
@@ -808,10 +878,10 @@ final class WifiDisplayController implements DumpUtils.Dump {
* Called on the handler thread when displays are connected or disconnected.
*/
public interface Listener {
- void onEnablementChanged(boolean enabled);
+ void onFeatureStateChanged(int featureState);
void onScanStarted();
- void onScanFinished(WifiDisplay[] knownDisplays);
+ void onScanFinished(WifiDisplay[] availableDisplays);
void onDisplayConnecting(WifiDisplay display);
void onDisplayConnectionFailed();
diff --git a/services/java/com/android/server/net/LockdownVpnTracker.java b/services/java/com/android/server/net/LockdownVpnTracker.java
index f2d6745..f32dd09 100644
--- a/services/java/com/android/server/net/LockdownVpnTracker.java
+++ b/services/java/com/android/server/net/LockdownVpnTracker.java
@@ -268,9 +268,11 @@ public class LockdownVpnTracker {
}
public NetworkInfo augmentNetworkInfo(NetworkInfo info) {
- final NetworkInfo vpnInfo = mVpn.getNetworkInfo();
- info = new NetworkInfo(info);
- info.setDetailedState(vpnInfo.getDetailedState(), vpnInfo.getReason(), null);
+ if (info.isConnected()) {
+ final NetworkInfo vpnInfo = mVpn.getNetworkInfo();
+ info = new NetworkInfo(info);
+ info.setDetailedState(vpnInfo.getDetailedState(), vpnInfo.getReason(), null);
+ }
return info;
}
diff --git a/services/java/com/android/server/net/NetworkStatsCollection.java b/services/java/com/android/server/net/NetworkStatsCollection.java
index 60666b4..3169035 100644
--- a/services/java/com/android/server/net/NetworkStatsCollection.java
+++ b/services/java/com/android/server/net/NetworkStatsCollection.java
@@ -31,6 +31,7 @@ import android.net.TrafficStats;
import android.text.format.DateUtils;
import android.util.AtomicFile;
+import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FileRotator;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.Objects;
@@ -431,13 +432,13 @@ public class NetworkStatsCollection implements FileRotator.Reader {
* moving any {@link NetworkStats#TAG_NONE} series to
* {@link TrafficStats#UID_REMOVED}.
*/
- public void removeUid(int uid) {
+ public void removeUids(int[] uids) {
final ArrayList<Key> knownKeys = Lists.newArrayList();
knownKeys.addAll(mStats.keySet());
// migrate all UID stats into special "removed" bucket
for (Key key : knownKeys) {
- if (key.uid == uid) {
+ if (ArrayUtils.contains(uids, key.uid)) {
// only migrate combined TAG_NONE history
if (key.tag == TAG_NONE) {
final NetworkStatsHistory uidHistory = mStats.get(key);
diff --git a/services/java/com/android/server/net/NetworkStatsRecorder.java b/services/java/com/android/server/net/NetworkStatsRecorder.java
index c3ecf54..2b32b41 100644
--- a/services/java/com/android/server/net/NetworkStatsRecorder.java
+++ b/services/java/com/android/server/net/NetworkStatsRecorder.java
@@ -42,6 +42,7 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.ref.WeakReference;
+import java.util.Arrays;
import java.util.HashSet;
import java.util.Map;
@@ -233,23 +234,27 @@ public class NetworkStatsRecorder {
* Remove the given UID from all {@link FileRotator} history, migrating it
* to {@link TrafficStats#UID_REMOVED}.
*/
- public void removeUidLocked(int uid) {
+ public void removeUidsLocked(int[] uids) {
try {
- // process all existing data to migrate uid
- mRotator.rewriteAll(new RemoveUidRewriter(mBucketDuration, uid));
+ // Rewrite all persisted data to migrate UID stats
+ mRotator.rewriteAll(new RemoveUidRewriter(mBucketDuration, uids));
} catch (IOException e) {
- Log.wtf(TAG, "problem removing UID " + uid, e);
+ Log.wtf(TAG, "problem removing UIDs " + Arrays.toString(uids), e);
recoverFromWtf();
}
- // clear UID from current stats snapshot
+ // Remove any pending stats
+ mPending.removeUids(uids);
+ mSinceBoot.removeUids(uids);
+
+ // Clear UID from current stats snapshot
if (mLastSnapshot != null) {
- mLastSnapshot = mLastSnapshot.withoutUid(uid);
+ mLastSnapshot = mLastSnapshot.withoutUids(uids);
}
final NetworkStatsCollection complete = mComplete != null ? mComplete.get() : null;
if (complete != null) {
- complete.removeUid(uid);
+ complete.removeUids(uids);
}
}
@@ -293,11 +298,11 @@ public class NetworkStatsRecorder {
*/
public static class RemoveUidRewriter implements FileRotator.Rewriter {
private final NetworkStatsCollection mTemp;
- private final int mUid;
+ private final int[] mUids;
- public RemoveUidRewriter(long bucketDuration, int uid) {
+ public RemoveUidRewriter(long bucketDuration, int[] uids) {
mTemp = new NetworkStatsCollection(bucketDuration);
- mUid = uid;
+ mUids = uids;
}
@Override
@@ -309,7 +314,7 @@ public class NetworkStatsRecorder {
public void read(InputStream in) throws IOException {
mTemp.read(in);
mTemp.clearDirty();
- mTemp.removeUid(mUid);
+ mTemp.removeUids(mUids);
}
@Override
diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java
index 3a593e4..f2748a3 100644
--- a/services/java/com/android/server/net/NetworkStatsService.java
+++ b/services/java/com/android/server/net/NetworkStatsService.java
@@ -23,6 +23,7 @@ import static android.Manifest.permission.MODIFY_NETWORK_ACCOUNTING;
import static android.Manifest.permission.READ_NETWORK_USAGE_HISTORY;
import static android.content.Intent.ACTION_SHUTDOWN;
import static android.content.Intent.ACTION_UID_REMOVED;
+import static android.content.Intent.ACTION_USER_REMOVED;
import static android.content.Intent.EXTRA_UID;
import static android.net.ConnectivityManager.ACTION_TETHER_STATE_CHANGED;
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION_IMMEDIATE;
@@ -76,6 +77,8 @@ import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
import android.net.IConnectivityManager;
import android.net.INetworkManagementEventObserver;
import android.net.INetworkStatsService;
@@ -112,6 +115,7 @@ import android.util.Slog;
import android.util.SparseIntArray;
import android.util.TrustedTime;
+import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FileRotator;
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.EventLogTags;
@@ -122,8 +126,10 @@ import java.io.File;
import java.io.FileDescriptor;
import java.io.IOException;
import java.io.PrintWriter;
+import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.List;
/**
* Collect and persist detailed network statistics, and provide this data to
@@ -322,6 +328,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
final IntentFilter removedFilter = new IntentFilter(ACTION_UID_REMOVED);
mContext.registerReceiver(mRemovedReceiver, removedFilter, null, mHandler);
+ // listen for user changes to clean stats
+ final IntentFilter userFilter = new IntentFilter(ACTION_USER_REMOVED);
+ mContext.registerReceiver(mUserReceiver, userFilter, null, mHandler);
+
// persist stats during clean shutdown
final IntentFilter shutdownFilter = new IntentFilter(ACTION_SHUTDOWN);
mContext.registerReceiver(mShutdownReceiver, shutdownFilter);
@@ -739,11 +749,34 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
public void onReceive(Context context, Intent intent) {
// on background handler thread, and UID_REMOVED is protected
// broadcast.
- final int uid = intent.getIntExtra(EXTRA_UID, 0);
+
+ final int uid = intent.getIntExtra(EXTRA_UID, -1);
+ if (uid == -1) return;
+
+ synchronized (mStatsLock) {
+ mWakeLock.acquire();
+ try {
+ removeUidsLocked(uid);
+ } finally {
+ mWakeLock.release();
+ }
+ }
+ }
+ };
+
+ private BroadcastReceiver mUserReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ // On background handler thread, and USER_REMOVED is protected
+ // broadcast.
+
+ final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
+ if (userId == -1) return;
+
synchronized (mStatsLock) {
mWakeLock.acquire();
try {
- removeUidLocked(uid);
+ removeUserLocked(userId);
} finally {
mWakeLock.release();
}
@@ -1034,15 +1067,37 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
/**
* Clean up {@link #mUidRecorder} after UID is removed.
*/
- private void removeUidLocked(int uid) {
- // perform one last poll before removing
+ private void removeUidsLocked(int... uids) {
+ if (LOGV) Slog.v(TAG, "removeUidsLocked() for UIDs " + Arrays.toString(uids));
+
+ // Perform one last poll before removing
performPollLocked(FLAG_PERSIST_ALL);
- mUidRecorder.removeUidLocked(uid);
- mUidTagRecorder.removeUidLocked(uid);
+ mUidRecorder.removeUidsLocked(uids);
+ mUidTagRecorder.removeUidsLocked(uids);
+
+ // Clear kernel stats associated with UID
+ for (int uid : uids) {
+ resetKernelUidStats(uid);
+ }
+ }
+
+ /**
+ * Clean up {@link #mUidRecorder} after user is removed.
+ */
+ private void removeUserLocked(int userId) {
+ if (LOGV) Slog.v(TAG, "removeUserLocked() for userId=" + userId);
+
+ // Build list of UIDs that we should clean up
+ int[] uids = new int[0];
+ final List<ApplicationInfo> apps = mContext.getPackageManager().getInstalledApplications(
+ PackageManager.GET_UNINSTALLED_PACKAGES | PackageManager.GET_DISABLED_COMPONENTS);
+ for (ApplicationInfo app : apps) {
+ final int uid = UserHandle.getUid(userId, app.uid);
+ uids = ArrayUtils.appendInt(uids, uid);
+ }
- // clear kernel stats associated with UID
- resetKernelUidStats(uid);
+ removeUidsLocked(uids);
}
@Override
diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
index f0cc083..f3de8a4 100644
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -719,7 +719,7 @@ public class PackageManagerService extends IPackageManager.Stub {
PackageInstalledInfo res = data.res;
if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
- res.removedInfo.sendBroadcast(false, true);
+ res.removedInfo.sendBroadcast(false, true, false);
Bundle extras = new Bundle(1);
extras.putInt(Intent.EXTRA_UID, res.uid);
// Determine the set of users who are adding this
@@ -5386,7 +5386,7 @@ public class PackageManagerService extends IPackageManager.Stub {
if (am != null) {
try {
if (userIds == null) {
- userIds = sUserManager.getUserIds();
+ userIds = am.getRunningUserIds();
}
for (int id : userIds) {
final Intent intent = new Intent(action,
@@ -5403,6 +5403,7 @@ public class PackageManagerService extends IPackageManager.Stub {
uid = UserHandle.getUid(id, UserHandle.getAppId(uid));
intent.putExtra(Intent.EXTRA_UID, uid);
}
+ intent.putExtra(Intent.EXTRA_USER_HANDLE, id);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
if (DEBUG_BROADCASTS) {
RuntimeException here = new RuntimeException("here");
@@ -8051,18 +8052,23 @@ public class PackageManagerService extends IPackageManager.Stub {
} catch (RemoteException e) {
}
+ boolean removedForAllUsers = false;
+ boolean systemUpdate = false;
synchronized (mInstallLock) {
res = deletePackageLI(packageName,
(flags & PackageManager.DELETE_ALL_USERS) != 0
? UserHandle.ALL : new UserHandle(UserHandle.getUserId(uid)),
true, flags | REMOVE_CHATTY, info, true);
+ systemUpdate = info.isRemovedPackageSystemUpdate;
+ if (res && !systemUpdate && mPackages.get(packageName) == null) {
+ removedForAllUsers = true;
+ }
}
if (res) {
- boolean systemUpdate = info.isRemovedPackageSystemUpdate;
- info.sendBroadcast(true, systemUpdate);
+ info.sendBroadcast(true, systemUpdate, removedForAllUsers);
- // If the removed package was a system update, the old system packaged
+ // If the removed package was a system update, the old system package
// was re-enabled; we need to broadcast this information
if (systemUpdate) {
Bundle extras = new Bundle(1);
@@ -8100,13 +8106,14 @@ public class PackageManagerService extends IPackageManager.Stub {
// Clean up resources deleted packages.
InstallArgs args = null;
- void sendBroadcast(boolean fullRemove, boolean replacing) {
+ void sendBroadcast(boolean fullRemove, boolean replacing, boolean removedForAllUsers) {
Bundle extras = new Bundle(1);
extras.putInt(Intent.EXTRA_UID, removedAppId >= 0 ? removedAppId : uid);
extras.putBoolean(Intent.EXTRA_DATA_REMOVED, fullRemove);
if (replacing) {
extras.putBoolean(Intent.EXTRA_REPLACING, true);
}
+ extras.putBoolean(Intent.EXTRA_REMOVED_FOR_ALL_USERS, removedForAllUsers);
if (removedPackage != null) {
sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED, removedPackage,
extras, null, null, removedUsers);
diff --git a/services/java/com/android/server/power/PowerManagerService.java b/services/java/com/android/server/power/PowerManagerService.java
index fda619c..7052ed5 100644
--- a/services/java/com/android/server/power/PowerManagerService.java
+++ b/services/java/com/android/server/power/PowerManagerService.java
@@ -50,6 +50,7 @@ import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.WorkSource;
import android.provider.Settings;
+import android.service.dreams.Dream;
import android.service.dreams.IDreamManager;
import android.util.EventLog;
import android.util.Log;
@@ -98,6 +99,8 @@ public final class PowerManagerService extends IPowerManager.Stub
private static final int DIRTY_STAY_ON = 1 << 7;
// Dirty bit: battery state changed
private static final int DIRTY_BATTERY_STATE = 1 << 8;
+ // Dirty bit: dream ended
+ private static final int DIRTY_DREAM_ENDED = 1 << 9;
// Wakefulness: The device is asleep and can only be awoken by a call to wakeUp().
// The screen should be off or in the process of being turned off by the display controller.
@@ -364,6 +367,10 @@ public final class PowerManagerService extends IPowerManager.Stub
filter.addAction(Intent.ACTION_DOCK_EVENT);
mContext.registerReceiver(new DockReceiver(), filter);
+ filter = new IntentFilter();
+ filter.addAction(Dream.ACTION_DREAMING_STOPPED);
+ mContext.registerReceiver(new DreamReceiver(), filter);
+
// Register for settings changes.
final ContentResolver resolver = mContext.getContentResolver();
resolver.registerContentObserver(Settings.Secure.getUriFor(
@@ -1146,8 +1153,12 @@ public final class PowerManagerService extends IPowerManager.Stub
* Determines whether to post a message to the sandman to update the dream state.
*/
private void updateDreamLocked(int dirty) {
- if ((dirty & (DIRTY_WAKEFULNESS | DIRTY_SETTINGS
- | DIRTY_IS_POWERED | DIRTY_STAY_ON | DIRTY_BATTERY_STATE)) != 0) {
+ if ((dirty & (DIRTY_WAKEFULNESS
+ | DIRTY_SETTINGS
+ | DIRTY_IS_POWERED
+ | DIRTY_STAY_ON
+ | DIRTY_BATTERY_STATE
+ | DIRTY_DREAM_ENDED)) != 0) {
scheduleSandmanLocked();
}
}
@@ -1230,15 +1241,15 @@ public final class PowerManagerService extends IPowerManager.Stub
handleDreamFinishedLocked();
}
- // Allow the sandman to detect when the dream has ended.
- // FIXME: The DreamManagerService should tell us explicitly.
+ // In addition to listening for the intent, poll the sandman periodically to detect
+ // when the dream has ended (as a watchdog only, ensuring our state is always correct).
if (mWakefulness == WAKEFULNESS_DREAMING
|| mWakefulness == WAKEFULNESS_NAPPING) {
if (!mSandmanScheduled) {
mSandmanScheduled = true;
Message msg = mHandler.obtainMessage(MSG_SANDMAN);
msg.setAsynchronous(true);
- mHandler.sendMessageDelayed(msg, 1000);
+ mHandler.sendMessageDelayed(msg, 5000);
}
}
}
@@ -1472,6 +1483,11 @@ public final class PowerManagerService extends IPowerManager.Stub
// TODO
}
+ private void handleDreamEndedLocked() {
+ mDirty |= DIRTY_DREAM_ENDED;
+ updatePowerStateLocked();
+ }
+
/**
* Reboot the device immediately, passing 'reason' (may be null)
* to the underlying __reboot system call. Should not return.
@@ -1937,6 +1953,15 @@ public final class PowerManagerService extends IPowerManager.Stub
}
}
+ private final class DreamReceiver extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ synchronized (mLock) {
+ handleDreamEndedLocked();
+ }
+ }
+ }
+
private final class SettingsObserver extends ContentObserver {
public SettingsObserver(Handler handler) {
super(handler);
diff --git a/services/java/com/android/server/updates/ConfigUpdateInstallReceiver.java b/services/java/com/android/server/updates/ConfigUpdateInstallReceiver.java
index a74a648..e07230d 100644
--- a/services/java/com/android/server/updates/ConfigUpdateInstallReceiver.java
+++ b/services/java/com/android/server/updates/ConfigUpdateInstallReceiver.java
@@ -89,8 +89,7 @@ public class ConfigUpdateInstallReceiver extends BroadcastReceiver {
// get the hash of the currently used value
String currentHash = getCurrentHash(getCurrentContent());
if (!verifyVersion(currentVersion, altVersion)) {
- EventLog.writeEvent(EventLogTags.CONFIG_INSTALL_FAILED,
- "New version is not greater than current version");
+ Slog.i(TAG, "Not installing, new version is <= current version");
} else if (!verifyPreviousHash(currentHash, altRequiredHash)) {
EventLog.writeEvent(EventLogTags.CONFIG_INSTALL_FAILED,
"Current hash did not match required value");
@@ -224,7 +223,7 @@ public class ConfigUpdateInstallReceiver extends BroadcastReceiver {
return signer.verify(Base64.decode(signature.getBytes(), Base64.DEFAULT));
}
- private void writeUpdate(File dir, File file, String content) {
+ private void writeUpdate(File dir, File file, String content) throws IOException {
FileOutputStream out = null;
File tmp = null;
try {
@@ -248,8 +247,6 @@ public class ConfigUpdateInstallReceiver extends BroadcastReceiver {
if (!tmp.renameTo(file)) {
throw new IOException("Failed to atomically rename " + file.getCanonicalPath());
}
- } catch (IOException e) {
- Slog.e(TAG, "Failed to write update", e);
} finally {
if (tmp != null) {
tmp.delete();
@@ -258,7 +255,7 @@ public class ConfigUpdateInstallReceiver extends BroadcastReceiver {
}
}
- private void install(String content, int version) {
+ private void install(String content, int version) throws IOException {
writeUpdate(updateDir, updateContent, content);
writeUpdate(updateDir, updateVersion, Long.toString(version));
}
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index 55a7c46..73cc7ed 100755
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -292,9 +292,6 @@ public class WindowManagerService extends IWindowManager.Stub
if (DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED.equals(action)) {
mKeyguardDisableHandler.sendEmptyMessage(
KeyguardDisableHandler.KEYGUARD_POLICY_CHANGED);
- } else if (Intent.ACTION_USER_SWITCHED.equals(action)) {
- final int newUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
- mCurrentUserId = newUserId;
}
}
};
@@ -811,8 +808,6 @@ public class WindowManagerService extends IWindowManager.Stub
// Track changes to DevicePolicyManager state so we can enable/disable keyguard.
IntentFilter filter = new IntentFilter();
filter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
- // Track user switching.
- filter.addAction(Intent.ACTION_USER_SWITCHED);
mContext.registerReceiver(mBroadcastReceiver, filter);
mHoldingScreenWakeLock = pmc.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK
@@ -1648,7 +1643,8 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
- if (mWallpaperTarget != foundW) {
+ if (mWallpaperTarget != foundW
+ && (mLowerWallpaperTarget == null || mLowerWallpaperTarget != foundW)) {
if (DEBUG_WALLPAPER) {
Slog.v(TAG, "New wallpaper target: " + foundW
+ " oldTarget: " + mWallpaperTarget);
@@ -3391,7 +3387,7 @@ public class WindowManagerService extends IWindowManager.Stub
// Exiting app
if (scaleUp) {
// noop animation
- a = new AlphaAnimation(1, 1);
+ a = new AlphaAnimation(1, 0);
a.setDuration(duration);
} else {
float scaleW = thumbWidth / displayInfo.appWidth;
@@ -3440,7 +3436,7 @@ public class WindowManagerService extends IWindowManager.Stub
"applyAnimation: atoken=" + atoken
+ " anim=" + a + " nextAppTransition=ANIM_CUSTOM"
+ " transit=" + transit + " isEntrance=" + enter
- + " Callers " + Debug.getCallers(3));
+ + " Callers=" + Debug.getCallers(3));
} else if (mNextAppTransitionType == ActivityOptions.ANIM_SCALE_UP) {
a = createScaleUpAnimationLocked(transit, enter);
initialized = true;
@@ -3448,7 +3444,7 @@ public class WindowManagerService extends IWindowManager.Stub
"applyAnimation: atoken=" + atoken
+ " anim=" + a + " nextAppTransition=ANIM_SCALE_UP"
+ " transit=" + transit + " isEntrance=" + enter
- + " Callers " + Debug.getCallers(3));
+ + " Callers=" + Debug.getCallers(3));
} else if (mNextAppTransitionType == ActivityOptions.ANIM_THUMBNAIL_SCALE_UP ||
mNextAppTransitionType == ActivityOptions.ANIM_THUMBNAIL_SCALE_DOWN) {
boolean scaleUp = (mNextAppTransitionType == ActivityOptions.ANIM_THUMBNAIL_SCALE_UP);
@@ -3459,7 +3455,7 @@ public class WindowManagerService extends IWindowManager.Stub
Slog.v(TAG, "applyAnimation: atoken=" + atoken
+ " anim=" + a + " nextAppTransition=" + animName
+ " transit=" + transit + " isEntrance=" + enter
- + " Callers " + Debug.getCallers(3));
+ + " Callers=" + Debug.getCallers(3));
}
} else {
int animAttr = 0;
@@ -3521,7 +3517,7 @@ public class WindowManagerService extends IWindowManager.Stub
+ " anim=" + a
+ " animAttr=0x" + Integer.toHexString(animAttr)
+ " transit=" + transit + " isEntrance=" + enter
- + " Callers " + Debug.getCallers(3));
+ + " Callers=" + Debug.getCallers(3));
}
if (a != null) {
if (DEBUG_ANIM) {
@@ -4193,7 +4189,7 @@ public class WindowManagerService extends IWindowManager.Stub
synchronized(mWindowMap) {
if (DEBUG_STARTING_WINDOW) Slog.v(
- TAG, "setAppStartingIcon: token=" + token + " pkg=" + pkg
+ TAG, "setAppStartingWindow: token=" + token + " pkg=" + pkg
+ " transferFrom=" + transferFrom);
AppWindowToken wtoken = findAppWindowToken(token);
@@ -4225,7 +4221,7 @@ public class WindowManagerService extends IWindowManager.Stub
mSkipAppTransitionAnimation = true;
}
if (DEBUG_STARTING_WINDOW) Slog.v(TAG,
- "Moving existing starting from " + ttoken
+ "Moving existing starting " + startingWindow + " from " + ttoken
+ " to " + wtoken);
final long origId = Binder.clearCallingIdentity();
@@ -4234,6 +4230,7 @@ public class WindowManagerService extends IWindowManager.Stub
wtoken.startingData = ttoken.startingData;
wtoken.startingView = ttoken.startingView;
wtoken.startingDisplayed = ttoken.startingDisplayed;
+ ttoken.startingDisplayed = false;
wtoken.startingWindow = startingWindow;
wtoken.reportedVisible = ttoken.reportedVisible;
ttoken.startingData = null;
@@ -4243,6 +4240,8 @@ public class WindowManagerService extends IWindowManager.Stub
startingWindow.mToken = wtoken;
startingWindow.mRootToken = wtoken;
startingWindow.mAppToken = wtoken;
+ startingWindow.mWinAnimator.mAppAnimator = wtoken.mAppAnimator;
+
if (DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE || DEBUG_STARTING_WINDOW) {
Slog.v(TAG, "Removing starting window: " + startingWindow);
}
@@ -4550,9 +4549,9 @@ public class WindowManagerService extends IWindowManager.Stub
}
wtoken.hiddenRequested = !visible;
- if (DEBUG_APP_TRANSITIONS) Slog.v(
- TAG, "Setting dummy animation on: " + wtoken);
if (!wtoken.startingDisplayed) {
+ if (DEBUG_APP_TRANSITIONS) Slog.v(
+ TAG, "Setting dummy animation on: " + wtoken);
wtoken.mAppAnimator.setDummyAnimation();
}
mOpeningApps.remove(wtoken);
@@ -5396,6 +5395,13 @@ public class WindowManagerService extends IWindowManager.Stub
mInputManager.setInputFilter(filter);
}
+ public void setCurrentUser(final int newUserId) {
+ synchronized (mWindowMap) {
+ mCurrentUserId = newUserId;
+ mPolicy.setCurrentUserLw(newUserId);
+ }
+ }
+
public void enableScreenAfterBoot() {
synchronized(mWindowMap) {
if (DEBUG_BOOT) {
@@ -8147,7 +8153,11 @@ public class WindowManagerService extends IWindowManager.Stub
updateLayoutToAnimationLocked();
}
if (DEBUG_LAYERS) Slog.v(TAG, "Assign layer " + w + ": "
- + winAnimator.mAnimLayer);
+ + "mBase=" + w.mBaseLayer
+ + " mLayer=" + w.mLayer
+ + (w.mAppToken == null ?
+ "" : " mAppLayer=" + w.mAppToken.mAppAnimator.animLayerAdjustment)
+ + " =mAnimLayer=" + winAnimator.mAnimLayer);
//System.out.println(
// "Assigned layer " + curLayer + " to " + w.mClient.asBinder());
}
@@ -8539,7 +8549,7 @@ public class WindowManagerService extends IWindowManager.Stub
transit = WindowManagerPolicy.TRANSIT_WALLPAPER_CLOSE;
if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
"New transit away from wallpaper: " + transit);
- } else if (mWallpaperTarget != null) {
+ } else if (mWallpaperTarget != null && mWallpaperTarget.isVisibleLw()) {
// We are transitioning from an activity without
// a wallpaper to now showing the wallpaper
transit = WindowManagerPolicy.TRANSIT_WALLPAPER_OPEN;
@@ -8596,7 +8606,7 @@ public class WindowManagerService extends IWindowManager.Stub
for (i=0; i<NN; i++) {
AppWindowToken wtoken = mClosingApps.get(i);
if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
- "Now closing app" + wtoken);
+ "Now closing app " + wtoken);
wtoken.mAppAnimator.clearThumbnail();
wtoken.inPendingTransaction = false;
wtoken.mAppAnimator.animation = null;
diff --git a/services/java/com/android/server/wm/WindowState.java b/services/java/com/android/server/wm/WindowState.java
index b62028e..ac958b8 100644
--- a/services/java/com/android/server/wm/WindowState.java
+++ b/services/java/com/android/server/wm/WindowState.java
@@ -518,11 +518,11 @@ final class WindowState implements WindowManagerPolicy.WindowState {
MagnificationSpec spec = mDisplayContent.mMagnificationSpec;
if (spec != null && !spec.isNop()) {
if (mAttachedWindow != null) {
- if (!mPolicy.canMagnifyWindow(mAttachedWindow.mAttrs)) {
+ if (!mPolicy.canMagnifyWindowLw(mAttachedWindow.mAttrs)) {
return null;
}
}
- if (!mPolicy.canMagnifyWindow(mAttrs)) {
+ if (!mPolicy.canMagnifyWindowLw(mAttrs)) {
return null;
}
}
diff --git a/services/java/com/android/server/wm/WindowStateAnimator.java b/services/java/com/android/server/wm/WindowStateAnimator.java
index 000a191..5f40709 100644
--- a/services/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/java/com/android/server/wm/WindowStateAnimator.java
@@ -62,7 +62,7 @@ class WindowStateAnimator {
final WindowState mWin;
final WindowStateAnimator mAttachedWinAnimator;
final WindowAnimator mAnimator;
- final AppWindowAnimator mAppAnimator;
+ AppWindowAnimator mAppAnimator;
final Session mSession;
final WindowManagerPolicy mPolicy;
final Context mContext;
@@ -1520,7 +1520,7 @@ class WindowStateAnimator {
"applyAnimation: win=" + this
+ " anim=" + anim + " attr=0x" + Integer.toHexString(attr)
+ " a=" + a
- + " mAnimation=" + mAnimation
+ + " transit=" + transit
+ " isEntrance=" + isEntrance + " Callers " + Debug.getCallers(3));
if (a != null) {
if (WindowManagerService.DEBUG_ANIM) {