diff options
Diffstat (limited to 'services/java/com/android')
18 files changed, 901 insertions, 672 deletions
diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java index ec58e43..f06bf8e 100644 --- a/services/java/com/android/server/InputMethodManagerService.java +++ b/services/java/com/android/server/InputMethodManagerService.java @@ -900,14 +900,28 @@ public class InputMethodManagerService extends IInputMethodManager.Stub Slog.d(TAG, "--- calledFromForegroundUserOrSystemProcess ? " + "calling uid = " + uid + " system uid = " + Process.SYSTEM_UID + " calling userId = " + userId + ", foreground user id = " - + mSettings.getCurrentUserId()); + + mSettings.getCurrentUserId() + ", calling uid = " + Binder.getCallingPid()); } if (uid == Process.SYSTEM_UID || userId == mSettings.getCurrentUserId()) { return true; - } else { - Slog.w(TAG, "--- IPC called from background users. Ignore. \n" + getStackTrace()); - return false; } + + // Caveat: A process which has INTERACT_ACROSS_USERS_FULL gets results for the + // foreground user, not for the user of that process. Accordingly InputMethodManagerService + // must not manage background users' states in any functions. + // Note that privacy-sensitive IPCs, such as setInputMethod, are still securely guarded + // by a token. + if (mContext.checkCallingOrSelfPermission( + android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) + == PackageManager.PERMISSION_GRANTED) { + if (DEBUG) { + Slog.d(TAG, "--- Access granted because the calling process has " + + "the INTERACT_ACROSS_USERS_FULL permission"); + } + return true; + } + Slog.w(TAG, "--- IPC called from background users. Ignore. \n" + getStackTrace()); + return false; } private boolean bindCurrentInputMethodService( @@ -1475,9 +1489,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub final CharSequence title = mRes.getText( com.android.internal.R.string.select_input_method); final CharSequence imiLabel = imi.loadLabel(pm); - if (DEBUG) { - Slog.d(TAG, "--- imiLabel = " + imiLabel); - } final CharSequence summary = mCurrentSubtype != null ? TextUtils.concat(mCurrentSubtype.getDisplayName(mContext, imi.getPackageName(), imi.getServiceInfo().applicationInfo), @@ -1488,15 +1499,22 @@ public class InputMethodManagerService extends IInputMethodManager.Stub mImeSwitcherNotification.setLatestEventInfo( mContext, title, summary, mImeSwitchPendingIntent); if (mNotificationManager != null) { - mNotificationManager.notify( + if (DEBUG) { + Slog.d(TAG, "--- show notification: label = " + imiLabel + + ", summary = " + summary); + } + mNotificationManager.notifyAsUser(null, com.android.internal.R.string.select_input_method, - mImeSwitcherNotification); + mImeSwitcherNotification, UserHandle.ALL); mNotificationShown = true; } } else { if (mNotificationShown && mNotificationManager != null) { - mNotificationManager.cancel( - com.android.internal.R.string.select_input_method); + if (DEBUG) { + Slog.d(TAG, "--- hide notification"); + } + mNotificationManager.cancelAsUser(null, + com.android.internal.R.string.select_input_method, UserHandle.ALL); mNotificationShown = false; } } diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java index d982d0d..2197e31 100644 --- a/services/java/com/android/server/LocationManagerService.java +++ b/services/java/com/android/server/LocationManagerService.java @@ -247,6 +247,12 @@ public class LocationManagerService extends ILocationManager.Stub implements Run } private void loadProvidersLocked() { + // create a passive location provider, which is always enabled + PassiveProvider passiveProvider = new PassiveProvider(this); + addProviderLocked(passiveProvider); + mEnabledProviders.add(passiveProvider.getName()); + mPassiveProvider = passiveProvider; + if (GpsLocationProvider.isSupported()) { // Create a gps location provider GpsLocationProvider gpsProvider = new GpsLocationProvider(mContext, this); @@ -256,12 +262,6 @@ public class LocationManagerService extends ILocationManager.Stub implements Run mRealProviders.put(LocationManager.GPS_PROVIDER, gpsProvider); } - // create a passive location provider, which is always enabled - PassiveProvider passiveProvider = new PassiveProvider(this); - addProviderLocked(passiveProvider); - mEnabledProviders.add(passiveProvider.getName()); - mPassiveProvider = passiveProvider; - /* Load package name(s) containing location provider support. These packages can contain services implementing location providers: diff --git a/services/java/com/android/server/MountService.java b/services/java/com/android/server/MountService.java index 0312705..c512bc1 100644 --- a/services/java/com/android/server/MountService.java +++ b/services/java/com/android/server/MountService.java @@ -1577,9 +1577,16 @@ class MountService extends IMountService.Stub private void warnOnNotMounted() { final StorageVolume primary = getPrimaryPhysicalVolume(); - if (primary != null - && Environment.MEDIA_MOUNTED.equals(getVolumeState(primary.getPath()))) { - Slog.w(TAG, "getSecureContainerList() called when storage not mounted"); + if (primary != null) { + boolean mounted = false; + try { + mounted = Environment.MEDIA_MOUNTED.equals(getVolumeState(primary.getPath())); + } catch (IllegalStateException e) { + } + + if (!mounted) { + Slog.w(TAG, "getSecureContainerList() called when storage not mounted"); + } } } diff --git a/services/java/com/android/server/StatusBarManagerService.java b/services/java/com/android/server/StatusBarManagerService.java index 87b0eb3..5d9441b 100644 --- a/services/java/com/android/server/StatusBarManagerService.java +++ b/services/java/com/android/server/StatusBarManagerService.java @@ -64,7 +64,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub = new HashMap<IBinder,StatusBarNotification>(); // for disabling the status bar - ArrayList<DisableRecord> mDisableRecords = new ArrayList<DisableRecord>(); + final ArrayList<DisableRecord> mDisableRecords = new ArrayList<DisableRecord>(); IBinder mSysUiVisToken = new Binder(); int mDisabled = 0; @@ -75,15 +75,17 @@ public class StatusBarManagerService extends IStatusBarService.Stub int mImeWindowVis = 0; int mImeBackDisposition; IBinder mImeToken = null; + int mCurrentUserId; private class DisableRecord implements IBinder.DeathRecipient { + int userId; String pkg; int what; IBinder token; public void binderDied() { Slog.i(TAG, "binder died for pkg=" + pkg); - disable(0, token, pkg); + disableInternal(userId, 0, token, pkg); token.unlinkToDeath(this, 0); } } @@ -151,20 +153,24 @@ public class StatusBarManagerService extends IStatusBarService.Stub } public void disable(int what, IBinder token, String pkg) { + disableInternal(mCurrentUserId, what, token, pkg); + } + + private void disableInternal(int userId, int what, IBinder token, String pkg) { enforceStatusBar(); synchronized (mLock) { - disableLocked(what, token, pkg); + disableLocked(userId, what, token, pkg); } } - private void disableLocked(int what, IBinder token, String pkg) { + private void disableLocked(int userId, int what, IBinder token, String pkg) { // It's important that the the callback and the call to mBar get done // in the same order when multiple threads are calling this function // so they are paired correctly. The messages on the handler will be // handled in the order they were enqueued, but will be outside the lock. - manageDisableListLocked(what, token, pkg); - final int net = gatherDisableActionsLocked(); + manageDisableListLocked(userId, what, token, pkg); + final int net = gatherDisableActionsLocked(userId); if (net != mDisabled) { mDisabled = net; mHandler.post(new Runnable() { @@ -312,7 +318,10 @@ public class StatusBarManagerService extends IStatusBarService.Stub synchronized (mLock) { updateUiVisibilityLocked(vis, mask); - disableLocked(vis & StatusBarManager.DISABLE_MASK, mSysUiVisToken, + disableLocked( + mCurrentUserId, + vis & StatusBarManager.DISABLE_MASK, + mSysUiVisToken, "WindowManager.LayoutParams"); } } @@ -382,6 +391,12 @@ public class StatusBarManagerService extends IStatusBarService.Stub } } + @Override + public void setCurrentUser(int newUserId) { + if (SPEW) Slog.d(TAG, "Setting current user to user " + newUserId); + mCurrentUserId = newUserId; + } + private void enforceStatusBar() { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR, "StatusBarManagerService"); @@ -417,7 +432,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub } } synchronized (mLock) { - switches[0] = gatherDisableActionsLocked(); + switches[0] = gatherDisableActionsLocked(mCurrentUserId); switches[1] = mSystemUiVisibility; switches[2] = mMenuVisible ? 1 : 0; switches[3] = mImeWindowVis; @@ -518,9 +533,10 @@ public class StatusBarManagerService extends IStatusBarService.Stub // ================================================================================ // lock on mDisableRecords - void manageDisableListLocked(int what, IBinder token, String pkg) { + void manageDisableListLocked(int userId, int what, IBinder token, String pkg) { if (SPEW) { - Slog.d(TAG, "manageDisableList what=0x" + Integer.toHexString(what) + " pkg=" + pkg); + Slog.d(TAG, "manageDisableList userId=" + userId + + " what=0x" + Integer.toHexString(what) + " pkg=" + pkg); } // update the list final int N = mDisableRecords.size(); @@ -541,6 +557,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub } else { if (tok == null) { tok = new DisableRecord(); + tok.userId = userId; try { token.linkToDeath(tok, 0); } @@ -556,12 +573,15 @@ public class StatusBarManagerService extends IStatusBarService.Stub } // lock on mDisableRecords - int gatherDisableActionsLocked() { + int gatherDisableActionsLocked(int userId) { final int N = mDisableRecords.size(); // gather the new net flags int net = 0; for (int i=0; i<N; i++) { - net |= mDisableRecords.get(i).what; + final DisableRecord rec = mDisableRecords.get(i); + if (rec.userId == userId) { + net |= rec.what; + } } return net; } @@ -593,13 +613,15 @@ public class StatusBarManagerService extends IStatusBarService.Stub } synchronized (mLock) { + pw.println(" mDisabled=0x" + Integer.toHexString(mDisabled)); final int N = mDisableRecords.size(); - pw.println(" mDisableRecords.size=" + N - + " mDisabled=0x" + Integer.toHexString(mDisabled)); + pw.println(" mDisableRecords.size=" + N); for (int i=0; i<N; i++) { DisableRecord tok = mDisableRecords.get(i); - pw.println(" [" + i + "] what=0x" + Integer.toHexString(tok.what) - + " pkg=" + tok.pkg + " token=" + tok.token); + pw.println(" [" + i + "] userId=" + tok.userId + + " what=0x" + Integer.toHexString(tok.what) + + " pkg=" + tok.pkg + + " token=" + tok.token); } } } diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index b684c90..eaaf33f 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -631,11 +631,12 @@ class ServerThread extends Thread { } try { - Slog.i(TAG, "Wired Accessory Observer"); + Slog.i(TAG, "Wired Accessory Manager"); // Listen for wired headset changes - new WiredAccessoryObserver(context); + inputManager.setWiredAccessoryCallbacks( + new WiredAccessoryManager(context, inputManager)); } catch (Throwable e) { - reportWtf("starting WiredAccessoryObserver", e); + reportWtf("starting WiredAccessoryManager", e); } try { diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java index adb63f9..98794c9 100644 --- a/services/java/com/android/server/WifiService.java +++ b/services/java/com/android/server/WifiService.java @@ -21,6 +21,7 @@ import android.app.AlarmManager; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; +import android.app.TaskStackBuilder; import android.bluetooth.BluetoothAdapter; import android.content.BroadcastReceiver; import android.content.ContentResolver; @@ -1766,9 +1767,10 @@ public class WifiService extends IWifiManager.Stub { mNotification.when = 0; mNotification.icon = ICON_NETWORKS_AVAILABLE; mNotification.flags = Notification.FLAG_AUTO_CANCEL; - mNotification.contentIntent = PendingIntent.getActivityAsUser(mContext, 0, - new Intent(WifiManager.ACTION_PICK_WIFI_NETWORK), 0, - null, UserHandle.CURRENT); + mNotification.contentIntent = TaskStackBuilder.create(mContext) + .addNextIntentWithParentStack( + new Intent(WifiManager.ACTION_PICK_WIFI_NETWORK)) + .getPendingIntent(0, 0, null, UserHandle.CURRENT); } CharSequence title = mContext.getResources().getQuantityText( diff --git a/services/java/com/android/server/WiredAccessoryManager.java b/services/java/com/android/server/WiredAccessoryManager.java new file mode 100644 index 0000000..63e8895 --- /dev/null +++ b/services/java/com/android/server/WiredAccessoryManager.java @@ -0,0 +1,432 @@ +/* + * Copyright (C) 2008 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.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; +import android.os.PowerManager; +import android.os.PowerManager.WakeLock; +import android.os.UEventObserver; +import android.util.Slog; +import android.media.AudioManager; +import android.util.Log; +import android.view.InputDevice; + +import com.android.internal.R; +import com.android.server.input.InputManagerService; +import com.android.server.input.InputManagerService.WiredAccessoryCallbacks; +import static com.android.server.input.InputManagerService.SW_HEADPHONE_INSERT; +import static com.android.server.input.InputManagerService.SW_MICROPHONE_INSERT; +import static com.android.server.input.InputManagerService.SW_HEADPHONE_INSERT_BIT; +import static com.android.server.input.InputManagerService.SW_MICROPHONE_INSERT_BIT; + +import java.io.File; +import java.io.FileReader; +import java.io.FileNotFoundException; +import java.util.ArrayList; +import java.util.List; + +/** + * <p>WiredAccessoryManager monitors for a wired headset on the main board or dock using + * both the InputManagerService notifyWiredAccessoryChanged interface and the UEventObserver + * subsystem. + */ +final class WiredAccessoryManager implements WiredAccessoryCallbacks { + private static final String TAG = WiredAccessoryManager.class.getSimpleName(); + private static final boolean LOG = true; + + private static final int BIT_HEADSET = (1 << 0); + private static final int BIT_HEADSET_NO_MIC = (1 << 1); + private static final int BIT_USB_HEADSET_ANLG = (1 << 2); + private static final int BIT_USB_HEADSET_DGTL = (1 << 3); + private static final int BIT_HDMI_AUDIO = (1 << 4); + private static final int SUPPORTED_HEADSETS = (BIT_HEADSET|BIT_HEADSET_NO_MIC| + BIT_USB_HEADSET_ANLG|BIT_USB_HEADSET_DGTL| + BIT_HDMI_AUDIO); + + private static final String NAME_H2W = "h2w"; + private static final String NAME_USB_AUDIO = "usb_audio"; + private static final String NAME_HDMI_AUDIO = "hdmi_audio"; + private static final String NAME_HDMI = "hdmi"; + + private static final int MSG_NEW_DEVICE_STATE = 1; + + private final Object mLock = new Object(); + + private final WakeLock mWakeLock; // held while there is a pending route change + private final AudioManager mAudioManager; + + private int mHeadsetState; + + private int mSwitchValues; + + private final WiredAccessoryObserver mObserver; + private final InputManagerService mInputManager; + + private final boolean mUseDevInputEventForAudioJack; + + public WiredAccessoryManager(Context context, InputManagerService inputManager) { + PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE); + mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "WiredAccessoryManager"); + mWakeLock.setReferenceCounted(false); + mAudioManager = (AudioManager)context.getSystemService(Context.AUDIO_SERVICE); + mInputManager = inputManager; + + mUseDevInputEventForAudioJack = + context.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack); + + mObserver = new WiredAccessoryObserver(); + + context.registerReceiver(new BroadcastReceiver() { + @Override + public void onReceive(Context ctx, Intent intent) { + bootCompleted(); + } + }, + new IntentFilter(Intent.ACTION_BOOT_COMPLETED), null, null); + } + + private void bootCompleted() { + if (mUseDevInputEventForAudioJack) { + int switchValues = 0; + if (mInputManager.getSwitchState(-1, InputDevice.SOURCE_ANY, SW_HEADPHONE_INSERT) == 1) { + switchValues |= SW_HEADPHONE_INSERT_BIT; + } + if (mInputManager.getSwitchState(-1, InputDevice.SOURCE_ANY, SW_MICROPHONE_INSERT) == 1) { + switchValues |= SW_MICROPHONE_INSERT_BIT; + } + notifyWiredAccessoryChanged(0, switchValues, + SW_HEADPHONE_INSERT_BIT | SW_MICROPHONE_INSERT_BIT); + } + + mObserver.init(); + } + + @Override + public void notifyWiredAccessoryChanged(long whenNanos, int switchValues, int switchMask) { + if (LOG) Slog.v(TAG, "notifyWiredAccessoryChanged: when=" + whenNanos + + " bits=" + switchCodeToString(switchValues, switchMask) + + " mask=" + Integer.toHexString(switchMask)); + + synchronized (mLock) { + int headset; + mSwitchValues = (mSwitchValues & ~switchMask) | switchValues; + switch (mSwitchValues & (SW_HEADPHONE_INSERT_BIT | SW_MICROPHONE_INSERT_BIT)) { + case 0: + headset = 0; + break; + + case SW_HEADPHONE_INSERT_BIT: + headset = BIT_HEADSET_NO_MIC; + break; + + case SW_HEADPHONE_INSERT_BIT | SW_MICROPHONE_INSERT_BIT: + headset = BIT_HEADSET; + break; + + case SW_MICROPHONE_INSERT_BIT: + headset = BIT_HEADSET; + break; + + default: + headset = 0; + break; + } + + updateLocked(NAME_H2W, headset); + } + } + + /** + * Compare the existing headset state with the new state and pass along accordingly. Note + * that this only supports a single headset at a time. Inserting both a usb and jacked headset + * results in support for the last one plugged in. Similarly, unplugging either is seen as + * unplugging all. + * + * @param newName One of the NAME_xxx variables defined above. + * @param newState 0 or one of the BIT_xxx variables defined above. + */ + private void updateLocked(String newName, int newState) { + // Retain only relevant bits + int headsetState = newState & SUPPORTED_HEADSETS; + int usb_headset_anlg = headsetState & BIT_USB_HEADSET_ANLG; + int usb_headset_dgtl = headsetState & BIT_USB_HEADSET_DGTL; + int h2w_headset = headsetState & (BIT_HEADSET | BIT_HEADSET_NO_MIC); + boolean h2wStateChange = true; + boolean usbStateChange = true; + if (LOG) Slog.v(TAG, "newName=" + newName + + " newState=" + newState + + " headsetState=" + headsetState + + " prev headsetState=" + mHeadsetState); + + if (mHeadsetState == headsetState) { + Log.e(TAG, "No state change."); + return; + } + + // reject all suspect transitions: only accept state changes from: + // - a: 0 headset to 1 headset + // - b: 1 headset to 0 headset + if (h2w_headset == (BIT_HEADSET | BIT_HEADSET_NO_MIC)) { + Log.e(TAG, "Invalid combination, unsetting h2w flag"); + h2wStateChange = false; + } + // - c: 0 usb headset to 1 usb headset + // - d: 1 usb headset to 0 usb headset + if (usb_headset_anlg == BIT_USB_HEADSET_ANLG && usb_headset_dgtl == BIT_USB_HEADSET_DGTL) { + Log.e(TAG, "Invalid combination, unsetting usb flag"); + usbStateChange = false; + } + if (!h2wStateChange && !usbStateChange) { + Log.e(TAG, "invalid transition, returning ..."); + return; + } + + mWakeLock.acquire(); + + Message msg = mHandler.obtainMessage(MSG_NEW_DEVICE_STATE, headsetState, + mHeadsetState, newName); + mHandler.sendMessage(msg); + + mHeadsetState = headsetState; + } + + private final Handler mHandler = new Handler(Looper.myLooper(), null, true) { + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case MSG_NEW_DEVICE_STATE: + setDevicesState(msg.arg1, msg.arg2, (String)msg.obj); + mWakeLock.release(); + } + } + }; + + private void setDevicesState( + int headsetState, int prevHeadsetState, String headsetName) { + synchronized (mLock) { + int allHeadsets = SUPPORTED_HEADSETS; + for (int curHeadset = 1; allHeadsets != 0; curHeadset <<= 1) { + if ((curHeadset & allHeadsets) != 0) { + setDeviceStateLocked(curHeadset, headsetState, prevHeadsetState, headsetName); + allHeadsets &= ~curHeadset; + } + } + } + } + + private void setDeviceStateLocked(int headset, + int headsetState, int prevHeadsetState, String headsetName) { + if ((headsetState & headset) != (prevHeadsetState & headset)) { + int device; + int state; + + if ((headsetState & headset) != 0) { + state = 1; + } else { + state = 0; + } + + if (headset == BIT_HEADSET) { + device = AudioManager.DEVICE_OUT_WIRED_HEADSET; + } else if (headset == BIT_HEADSET_NO_MIC){ + device = AudioManager.DEVICE_OUT_WIRED_HEADPHONE; + } else if (headset == BIT_USB_HEADSET_ANLG) { + device = AudioManager.DEVICE_OUT_ANLG_DOCK_HEADSET; + } else if (headset == BIT_USB_HEADSET_DGTL) { + device = AudioManager.DEVICE_OUT_DGTL_DOCK_HEADSET; + } else if (headset == BIT_HDMI_AUDIO) { + device = AudioManager.DEVICE_OUT_AUX_DIGITAL; + } else { + Slog.e(TAG, "setDeviceState() invalid headset type: "+headset); + return; + } + + if (LOG) + Slog.v(TAG, "device "+headsetName+((state == 1) ? " connected" : " disconnected")); + + mAudioManager.setWiredDeviceConnectionState(device, state, headsetName); + } + } + + private String switchCodeToString(int switchValues, int switchMask) { + StringBuffer sb = new StringBuffer(); + if ((switchMask & SW_HEADPHONE_INSERT_BIT) != 0 && + (switchValues & SW_HEADPHONE_INSERT_BIT) != 0) { + sb.append("SW_HEADPHONE_INSERT "); + } + if ((switchMask & SW_MICROPHONE_INSERT_BIT) != 0 && + (switchValues & SW_MICROPHONE_INSERT_BIT) != 0) { + sb.append("SW_MICROPHONE_INSERT"); + } + return sb.toString(); + } + + class WiredAccessoryObserver extends UEventObserver { + private final List<UEventInfo> mUEventInfo; + + public WiredAccessoryObserver() { + mUEventInfo = makeObservedUEventList(); + } + + void init() { + synchronized (mLock) { + if (LOG) Slog.v(TAG, "init()"); + char[] buffer = new char[1024]; + + for (int i = 0; i < mUEventInfo.size(); ++i) { + UEventInfo uei = mUEventInfo.get(i); + try { + int curState; + FileReader file = new FileReader(uei.getSwitchStatePath()); + int len = file.read(buffer, 0, 1024); + file.close(); + curState = Integer.valueOf((new String(buffer, 0, len)).trim()); + + if (curState > 0) { + updateStateLocked(uei.getDevPath(), uei.getDevName(), curState); + } + } catch (FileNotFoundException e) { + Slog.w(TAG, uei.getSwitchStatePath() + + " not found while attempting to determine initial switch state"); + } catch (Exception e) { + Slog.e(TAG, "" , e); + } + } + } + + // At any given time accessories could be inserted + // one on the board, one on the dock and one on HDMI: + // observe three UEVENTs + for (int i = 0; i < mUEventInfo.size(); ++i) { + UEventInfo uei = mUEventInfo.get(i); + startObserving("DEVPATH="+uei.getDevPath()); + } + } + + private List<UEventInfo> makeObservedUEventList() { + List<UEventInfo> retVal = new ArrayList<UEventInfo>(); + UEventInfo uei; + + // Monitor h2w + if (!mUseDevInputEventForAudioJack) { + uei = new UEventInfo(NAME_H2W, BIT_HEADSET, BIT_HEADSET_NO_MIC); + if (uei.checkSwitchExists()) { + retVal.add(uei); + } else { + Slog.w(TAG, "This kernel does not have wired headset support"); + } + } + + // Monitor USB + uei = new UEventInfo(NAME_USB_AUDIO, BIT_USB_HEADSET_ANLG, BIT_USB_HEADSET_DGTL); + if (uei.checkSwitchExists()) { + retVal.add(uei); + } else { + Slog.w(TAG, "This kernel does not have usb audio support"); + } + + // Monitor HDMI + // + // If the kernel has support for the "hdmi_audio" switch, use that. It will be + // signalled only when the HDMI driver has a video mode configured, and the downstream + // sink indicates support for audio in its EDID. + // + // If the kernel does not have an "hdmi_audio" switch, just fall back on the older + // "hdmi" switch instead. + uei = new UEventInfo(NAME_HDMI_AUDIO, BIT_HDMI_AUDIO, 0); + if (uei.checkSwitchExists()) { + retVal.add(uei); + } else { + uei = new UEventInfo(NAME_HDMI, BIT_HDMI_AUDIO, 0); + if (uei.checkSwitchExists()) { + retVal.add(uei); + } else { + Slog.w(TAG, "This kernel does not have HDMI audio support"); + } + } + + return retVal; + } + + @Override + public void onUEvent(UEventObserver.UEvent event) { + if (LOG) Slog.v(TAG, "Headset UEVENT: " + event.toString()); + + try { + String devPath = event.get("DEVPATH"); + String name = event.get("SWITCH_NAME"); + int state = Integer.parseInt(event.get("SWITCH_STATE")); + synchronized (mLock) { + updateStateLocked(devPath, name, state); + } + } catch (NumberFormatException e) { + Slog.e(TAG, "Could not parse switch state from event " + event); + } + } + + private void updateStateLocked(String devPath, String name, int state) { + for (int i = 0; i < mUEventInfo.size(); ++i) { + UEventInfo uei = mUEventInfo.get(i); + if (devPath.equals(uei.getDevPath())) { + updateLocked(name, uei.computeNewHeadsetState(mHeadsetState, state)); + return; + } + } + } + + private final class UEventInfo { + private final String mDevName; + private final int mState1Bits; + private final int mState2Bits; + + public UEventInfo(String devName, int state1Bits, int state2Bits) { + mDevName = devName; + mState1Bits = state1Bits; + mState2Bits = state2Bits; + } + + public String getDevName() { return mDevName; } + + public String getDevPath() { + return String.format("/devices/virtual/switch/%s", mDevName); + } + + public String getSwitchStatePath() { + return String.format("/sys/class/switch/%s/state", mDevName); + } + + public boolean checkSwitchExists() { + File f = new File(getSwitchStatePath()); + return f.exists(); + } + + public int computeNewHeadsetState(int headsetState, int switchState) { + int preserveMask = ~(mState1Bits | mState2Bits); + int setBits = ((switchState == 1) ? mState1Bits : + ((switchState == 2) ? mState2Bits : 0)); + + return ((headsetState & preserveMask) | setBits); + } + } + } +} diff --git a/services/java/com/android/server/WiredAccessoryObserver.java b/services/java/com/android/server/WiredAccessoryObserver.java deleted file mode 100644 index 56c0fdf..0000000 --- a/services/java/com/android/server/WiredAccessoryObserver.java +++ /dev/null @@ -1,319 +0,0 @@ -/* - * Copyright (C) 2008 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.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.os.Handler; -import android.os.Looper; -import android.os.Message; -import android.os.PowerManager; -import android.os.PowerManager.WakeLock; -import android.os.UEventObserver; -import android.util.Slog; -import android.media.AudioManager; -import android.util.Log; - -import java.io.File; -import java.io.FileReader; -import java.io.FileNotFoundException; -import java.util.ArrayList; -import java.util.List; - -/** - * <p>WiredAccessoryObserver monitors for a wired headset on the main board or dock. - */ -final class WiredAccessoryObserver extends UEventObserver { - private static final String TAG = WiredAccessoryObserver.class.getSimpleName(); - private static final boolean LOG = true; - private static final int BIT_HEADSET = (1 << 0); - private static final int BIT_HEADSET_NO_MIC = (1 << 1); - private static final int BIT_USB_HEADSET_ANLG = (1 << 2); - private static final int BIT_USB_HEADSET_DGTL = (1 << 3); - private static final int BIT_HDMI_AUDIO = (1 << 4); - private static final int SUPPORTED_HEADSETS = (BIT_HEADSET|BIT_HEADSET_NO_MIC| - BIT_USB_HEADSET_ANLG|BIT_USB_HEADSET_DGTL| - BIT_HDMI_AUDIO); - - private final Object mLock = new Object(); - - private final Context mContext; - private final WakeLock mWakeLock; // held while there is a pending route change - private final AudioManager mAudioManager; - private final List<UEventInfo> mUEventInfo; - - private int mHeadsetState; - private int mPrevHeadsetState; - private String mHeadsetName; - - public WiredAccessoryObserver(Context context) { - mContext = context; - - PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE); - mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "WiredAccessoryObserver"); - mWakeLock.setReferenceCounted(false); - mAudioManager = (AudioManager)context.getSystemService(Context.AUDIO_SERVICE); - - mUEventInfo = makeObservedUEventList(); - - context.registerReceiver(new BootCompletedReceiver(), - new IntentFilter(Intent.ACTION_BOOT_COMPLETED), null, null); - } - - @Override - public void onUEvent(UEventObserver.UEvent event) { - if (LOG) Slog.v(TAG, "Headset UEVENT: " + event.toString()); - - try { - String devPath = event.get("DEVPATH"); - String name = event.get("SWITCH_NAME"); - int state = Integer.parseInt(event.get("SWITCH_STATE")); - synchronized (mLock) { - updateStateLocked(devPath, name, state); - } - } catch (NumberFormatException e) { - Slog.e(TAG, "Could not parse switch state from event " + event); - } - } - - private void bootCompleted() { - synchronized (mLock) { - char[] buffer = new char[1024]; - mPrevHeadsetState = mHeadsetState; - - if (LOG) Slog.v(TAG, "init()"); - - for (int i = 0; i < mUEventInfo.size(); ++i) { - UEventInfo uei = mUEventInfo.get(i); - try { - int curState; - FileReader file = new FileReader(uei.getSwitchStatePath()); - int len = file.read(buffer, 0, 1024); - file.close(); - curState = Integer.valueOf((new String(buffer, 0, len)).trim()); - - if (curState > 0) { - updateStateLocked(uei.getDevPath(), uei.getDevName(), curState); - } - } catch (FileNotFoundException e) { - Slog.w(TAG, uei.getSwitchStatePath() + - " not found while attempting to determine initial switch state"); - } catch (Exception e) { - Slog.e(TAG, "" , e); - } - } - } - - // At any given time accessories could be inserted - // one on the board, one on the dock and one on HDMI: - // observe three UEVENTs - for (int i = 0; i < mUEventInfo.size(); ++i) { - UEventInfo uei = mUEventInfo.get(i); - startObserving("DEVPATH="+uei.getDevPath()); - } - } - - private void updateStateLocked(String devPath, String name, int state) { - for (int i = 0; i < mUEventInfo.size(); ++i) { - UEventInfo uei = mUEventInfo.get(i); - if (devPath.equals(uei.getDevPath())) { - updateLocked(name, uei.computeNewHeadsetState(mHeadsetState, state)); - return; - } - } - } - - private void updateLocked(String newName, int newState) { - // Retain only relevant bits - int headsetState = newState & SUPPORTED_HEADSETS; - int usb_headset_anlg = headsetState & BIT_USB_HEADSET_ANLG; - int usb_headset_dgtl = headsetState & BIT_USB_HEADSET_DGTL; - int h2w_headset = headsetState & (BIT_HEADSET | BIT_HEADSET_NO_MIC); - boolean h2wStateChange = true; - boolean usbStateChange = true; - // reject all suspect transitions: only accept state changes from: - // - a: 0 heaset to 1 headset - // - b: 1 headset to 0 headset - if (LOG) Slog.v(TAG, "newState = "+newState+", headsetState = "+headsetState+"," - + "mHeadsetState = "+mHeadsetState); - if (mHeadsetState == headsetState || ((h2w_headset & (h2w_headset - 1)) != 0)) { - Log.e(TAG, "unsetting h2w flag"); - h2wStateChange = false; - } - // - c: 0 usb headset to 1 usb headset - // - d: 1 usb headset to 0 usb headset - if ((usb_headset_anlg >> 2) == 1 && (usb_headset_dgtl >> 3) == 1) { - Log.e(TAG, "unsetting usb flag"); - usbStateChange = false; - } - if (!h2wStateChange && !usbStateChange) { - Log.e(TAG, "invalid transition, returning ..."); - return; - } - - mHeadsetName = newName; - mPrevHeadsetState = mHeadsetState; - mHeadsetState = headsetState; - - mWakeLock.acquire(); - - Message msg = mHandler.obtainMessage(0, mHeadsetState, mPrevHeadsetState, mHeadsetName); - mHandler.sendMessage(msg); - } - - private void setDevicesState( - int headsetState, int prevHeadsetState, String headsetName) { - synchronized (mLock) { - int allHeadsets = SUPPORTED_HEADSETS; - for (int curHeadset = 1; allHeadsets != 0; curHeadset <<= 1) { - if ((curHeadset & allHeadsets) != 0) { - setDeviceStateLocked(curHeadset, headsetState, prevHeadsetState, headsetName); - allHeadsets &= ~curHeadset; - } - } - } - } - - private void setDeviceStateLocked(int headset, - int headsetState, int prevHeadsetState, String headsetName) { - if ((headsetState & headset) != (prevHeadsetState & headset)) { - int device; - int state; - - if ((headsetState & headset) != 0) { - state = 1; - } else { - state = 0; - } - - if (headset == BIT_HEADSET) { - device = AudioManager.DEVICE_OUT_WIRED_HEADSET; - } else if (headset == BIT_HEADSET_NO_MIC){ - device = AudioManager.DEVICE_OUT_WIRED_HEADPHONE; - } else if (headset == BIT_USB_HEADSET_ANLG) { - device = AudioManager.DEVICE_OUT_ANLG_DOCK_HEADSET; - } else if (headset == BIT_USB_HEADSET_DGTL) { - device = AudioManager.DEVICE_OUT_DGTL_DOCK_HEADSET; - } else if (headset == BIT_HDMI_AUDIO) { - device = AudioManager.DEVICE_OUT_AUX_DIGITAL; - } else { - Slog.e(TAG, "setDeviceState() invalid headset type: "+headset); - return; - } - - if (LOG) - Slog.v(TAG, "device "+headsetName+((state == 1) ? " connected" : " disconnected")); - - mAudioManager.setWiredDeviceConnectionState(device, state, headsetName); - } - } - - private static List<UEventInfo> makeObservedUEventList() { - List<UEventInfo> retVal = new ArrayList<UEventInfo>(); - UEventInfo uei; - - // Monitor h2w - uei = new UEventInfo("h2w", BIT_HEADSET, BIT_HEADSET_NO_MIC); - if (uei.checkSwitchExists()) { - retVal.add(uei); - } else { - Slog.w(TAG, "This kernel does not have wired headset support"); - } - - // Monitor USB - uei = new UEventInfo("usb_audio", BIT_USB_HEADSET_ANLG, BIT_USB_HEADSET_DGTL); - if (uei.checkSwitchExists()) { - retVal.add(uei); - } else { - Slog.w(TAG, "This kernel does not have usb audio support"); - } - - // Monitor HDMI - // - // If the kernel has support for the "hdmi_audio" switch, use that. It will be signalled - // only when the HDMI driver has a video mode configured, and the downstream sink indicates - // support for audio in its EDID. - // - // If the kernel does not have an "hdmi_audio" switch, just fall back on the older "hdmi" - // switch instead. - uei = new UEventInfo("hdmi_audio", BIT_HDMI_AUDIO, 0); - if (uei.checkSwitchExists()) { - retVal.add(uei); - } else { - uei = new UEventInfo("hdmi", BIT_HDMI_AUDIO, 0); - if (uei.checkSwitchExists()) { - retVal.add(uei); - } else { - Slog.w(TAG, "This kernel does not have HDMI audio support"); - } - } - - return retVal; - } - - private final Handler mHandler = new Handler(Looper.myLooper(), null, true) { - @Override - public void handleMessage(Message msg) { - setDevicesState(msg.arg1, msg.arg2, (String)msg.obj); - mWakeLock.release(); - } - }; - - private static final class UEventInfo { - private final String mDevName; - private final int mState1Bits; - private final int mState2Bits; - - public UEventInfo(String devName, int state1Bits, int state2Bits) { - mDevName = devName; - mState1Bits = state1Bits; - mState2Bits = state2Bits; - } - - public String getDevName() { return mDevName; } - - public String getDevPath() { - return String.format("/devices/virtual/switch/%s", mDevName); - } - - public String getSwitchStatePath() { - return String.format("/sys/class/switch/%s/state", mDevName); - } - - public boolean checkSwitchExists() { - File f = new File(getSwitchStatePath()); - return ((null != f) && f.exists()); - } - - public int computeNewHeadsetState(int headsetState, int switchState) { - int preserveMask = ~(mState1Bits | mState2Bits); - int setBits = ((switchState == 1) ? mState1Bits : - ((switchState == 2) ? mState2Bits : 0)); - - return ((headsetState & preserveMask) | setBits); - } - } - - private final class BootCompletedReceiver extends BroadcastReceiver { - @Override - public void onReceive(Context context, Intent intent) { - bootCompleted(); - } - } -} diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index 3428326..e90eef9 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -181,6 +181,7 @@ public final class ActivityManagerService extends ActivityManagerNative static final boolean DEBUG_VISBILITY = localLOGV || false; static final boolean DEBUG_PROCESSES = localLOGV || false; static final boolean DEBUG_PROCESS_OBSERVERS = localLOGV || false; + static final boolean DEBUG_CLEANUP = localLOGV || false; static final boolean DEBUG_PROVIDER = localLOGV || false; static final boolean DEBUG_URI_PERMISSION = localLOGV || false; static final boolean DEBUG_USER_LEAVING = localLOGV || false; @@ -1968,7 +1969,7 @@ public final class ActivityManagerService extends ActivityManagerNative } else { // An application record is attached to a previous process, // clean it up now. - if (DEBUG_PROCESSES) Slog.v(TAG, "App died: " + app); + if (DEBUG_PROCESSES || DEBUG_CLEANUP) Slog.v(TAG, "App died: " + app); handleAppDiedLocked(app, true, true); } } @@ -2925,7 +2926,8 @@ public final class ActivityManagerService extends ActivityManagerNative // Just in case... if (mMainStack.mPausingActivity != null && mMainStack.mPausingActivity.app == app) { - if (DEBUG_PAUSE) Slog.v(TAG, "App died while pausing: " +mMainStack.mPausingActivity); + if (DEBUG_PAUSE || DEBUG_CLEANUP) Slog.v(TAG, + "App died while pausing: " + mMainStack.mPausingActivity); mMainStack.mPausingActivity = null; } if (mMainStack.mLastPausedActivity != null && mMainStack.mLastPausedActivity.app == app) { @@ -2933,61 +2935,7 @@ public final class ActivityManagerService extends ActivityManagerNative } // Remove this application's activities from active lists. - mMainStack.removeHistoryRecordsForAppLocked(app); - - boolean atTop = true; - boolean hasVisibleActivities = false; - - // Clean out the history list. - int i = mMainStack.mHistory.size(); - if (localLOGV) Slog.v( - TAG, "Removing app " + app + " from history with " + i + " entries"); - while (i > 0) { - i--; - ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(i); - if (localLOGV) Slog.v( - TAG, "Record #" + i + " " + r + ": app=" + r.app); - if (r.app == app) { - if ((!r.haveState && !r.stateNotNeeded) || r.finishing) { - if (ActivityStack.DEBUG_ADD_REMOVE) { - RuntimeException here = new RuntimeException("here"); - here.fillInStackTrace(); - Slog.i(TAG, "Removing activity " + r + " from stack at " + i - + ": haveState=" + r.haveState - + " stateNotNeeded=" + r.stateNotNeeded - + " finishing=" + r.finishing - + " state=" + r.state, here); - } - if (!r.finishing) { - Slog.w(TAG, "Force removing " + r + ": app died, no saved state"); - EventLog.writeEvent(EventLogTags.AM_FINISH_ACTIVITY, - r.userId, System.identityHashCode(r), - r.task.taskId, r.shortComponentName, - "proc died without state saved"); - } - mMainStack.removeActivityFromHistoryLocked(r); - - } else { - // We have the current state for this activity, so - // it can be restarted later when needed. - if (localLOGV) Slog.v( - TAG, "Keeping entry, setting app to null"); - if (r.visible) { - hasVisibleActivities = true; - } - r.app = null; - r.nowVisible = false; - if (!r.haveState) { - if (ActivityStack.DEBUG_SAVED_STATE) Slog.i(TAG, - "App died, clearing saved state of " + r); - r.icicle = null; - } - } - - r.stack.cleanUpActivityLocked(r, true, true); - } - atTop = false; - } + boolean hasVisibleActivities = mMainStack.removeHistoryRecordsForAppLocked(app); app.activities.clear(); @@ -3053,7 +3001,7 @@ public final class ActivityManagerService extends ActivityManagerNative + ") has died."); } EventLog.writeEvent(EventLogTags.AM_PROC_DIED, app.userId, app.pid, app.processName); - if (localLOGV) Slog.v( + if (DEBUG_CLEANUP) Slog.v( TAG, "Dying app: " + app + ", pid: " + pid + ", thread: " + thread.asBinder()); boolean doLowMem = app.instrumentationClass == null; @@ -10757,7 +10705,8 @@ public final class ActivityManagerService extends ActivityManagerNative // If the app is undergoing backup, tell the backup manager about it if (mBackupTarget != null && app.pid == mBackupTarget.app.pid) { - if (DEBUG_BACKUP) Slog.d(TAG, "App " + mBackupTarget.appInfo + " died during backup"); + if (DEBUG_BACKUP || DEBUG_CLEANUP) Slog.d(TAG, "App " + + mBackupTarget.appInfo + " died during backup"); try { IBackupManager bm = IBackupManager.Stub.asInterface( ServiceManager.getService(Context.BACKUP_SERVICE)); @@ -10783,7 +10732,7 @@ public final class ActivityManagerService extends ActivityManagerNative } if (!app.persistent || app.isolated) { - if (DEBUG_PROCESSES) Slog.v(TAG, + if (DEBUG_PROCESSES || DEBUG_CLEANUP) Slog.v(TAG, "Removing non-persistent process during cleanup: " + app); mProcessNames.remove(app.processName, app.uid); mIsolatedProcesses.remove(app.uid); @@ -10801,7 +10750,7 @@ public final class ActivityManagerService extends ActivityManagerNative restart = true; } } - if (DEBUG_PROCESSES && mProcessesOnHold.contains(app)) Slog.v(TAG, + if ((DEBUG_PROCESSES || DEBUG_CLEANUP) && mProcessesOnHold.contains(app)) Slog.v(TAG, "Clean-up removing on hold: " + app); mProcessesOnHold.remove(app); @@ -11745,7 +11694,7 @@ public final class ActivityManagerService extends ActivityManagerNative users = mStartedUserArray; } else { // Caller wants broadcast to go to one specific user. - users = mCurrentUserArray; + users = new int[] {userId}; } // Figure out who all will receive this broadcast. diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java index 2d445274..90a7abc 100755 --- a/services/java/com/android/server/am/ActivityStack.java +++ b/services/java/com/android/server/am/ActivityStack.java @@ -81,6 +81,7 @@ final class ActivityStack { static final boolean DEBUG_RESULTS = ActivityManagerService.DEBUG_RESULTS; static final boolean DEBUG_CONFIGURATION = ActivityManagerService.DEBUG_CONFIGURATION; static final boolean DEBUG_TASKS = ActivityManagerService.DEBUG_TASKS; + static final boolean DEBUG_CLEANUP = ActivityManagerService.DEBUG_CLEANUP; static final boolean DEBUG_STATES = false; static final boolean DEBUG_ADD_REMOVE = false; @@ -1142,9 +1143,13 @@ final class ActivityStack { resumeTopActivityLocked(prev); } else { checkReadyForSleepLocked(); - if (topRunningActivityLocked(null) == null) { - // If there are no more activities available to run, then - // do resume anyway to start something. + ActivityRecord top = topRunningActivityLocked(null); + if (top == null || (prev != null && top != prev)) { + // If there are no more activities available to run, + // do resume anyway to start something. Also if the top + // activity on the stack is not the just paused activity, + // we need to go ahead and resume it to ensure we complete + // an in-flight app switch. resumeTopActivityLocked(null); } } @@ -1461,7 +1466,8 @@ final class ActivityStack { // If we are currently pausing an activity, then don't do anything // until that is done. if (mPausingActivity != null) { - if (DEBUG_SWITCH) Slog.v(TAG, "Skip resume: pausing=" + mPausingActivity); + if (DEBUG_SWITCH || DEBUG_PAUSE) Slog.v(TAG, + "Skip resume: pausing=" + mPausingActivity); return false; } @@ -3862,6 +3868,7 @@ final class ActivityStack { if (setState) { if (DEBUG_STATES) Slog.v(TAG, "Moving to DESTROYED: " + r + " (cleaning up)"); r.state = ActivityState.DESTROYED; + r.app = null; } // Make sure this record is no longer in the pending finishes list. @@ -3905,26 +3912,26 @@ final class ActivityStack { } final void removeActivityFromHistoryLocked(ActivityRecord r) { - if (r.state != ActivityState.DESTROYED) { - finishActivityResultsLocked(r, Activity.RESULT_CANCELED, null); - r.makeFinishing(); - if (DEBUG_ADD_REMOVE) { - RuntimeException here = new RuntimeException("here"); - here.fillInStackTrace(); - Slog.i(TAG, "Removing activity " + r + " from stack"); - } - mHistory.remove(r); - r.takeFromHistory(); - if (DEBUG_STATES) Slog.v(TAG, "Moving to DESTROYED: " + r - + " (removed from history)"); - r.state = ActivityState.DESTROYED; - mService.mWindowManager.removeAppToken(r.appToken); - if (VALIDATE_TOKENS) { - validateAppTokensLocked(); - } - cleanUpActivityServicesLocked(r); - r.removeUriPermissionsLocked(); + finishActivityResultsLocked(r, Activity.RESULT_CANCELED, null); + r.makeFinishing(); + if (DEBUG_ADD_REMOVE) { + RuntimeException here = new RuntimeException("here"); + here.fillInStackTrace(); + Slog.i(TAG, "Removing activity " + r + " from stack"); + } + mHistory.remove(r); + r.takeFromHistory(); + removeTimeoutsForActivityLocked(r); + if (DEBUG_STATES) Slog.v(TAG, "Moving to DESTROYED: " + r + + " (removed from history)"); + r.state = ActivityState.DESTROYED; + r.app = null; + mService.mWindowManager.removeAppToken(r.appToken); + if (VALIDATE_TOKENS) { + validateAppTokensLocked(); } + cleanUpActivityServicesLocked(r); + r.removeUriPermissionsLocked(); } /** @@ -3992,7 +3999,7 @@ final class ActivityStack { */ final boolean destroyActivityLocked(ActivityRecord r, boolean removeFromApp, boolean oomAdj, String reason) { - if (DEBUG_SWITCH) Slog.v( + if (DEBUG_SWITCH || DEBUG_CLEANUP) Slog.v( TAG, "Removing activity from " + reason + ": token=" + r + ", app=" + (r.app != null ? r.app.processName : "(null)")); EventLog.writeEvent(EventLogTags.AM_DESTROY_ACTIVITY, @@ -4000,11 +4007,11 @@ final class ActivityStack { r.task.taskId, r.shortComponentName, reason); boolean removedFromHistory = false; - + cleanUpActivityLocked(r, false, false); final boolean hadApp = r.app != null; - + if (hadApp) { if (removeFromApp) { int idx = r.app.activities.indexOf(r); @@ -4040,7 +4047,6 @@ final class ActivityStack { } } - r.app = null; r.nowVisible = false; // If the activity is finishing, we need to wait on removing it @@ -4061,6 +4067,7 @@ final class ActivityStack { if (DEBUG_STATES) Slog.v(TAG, "Moving to DESTROYED: " + r + " (destroy skipped)"); r.state = ActivityState.DESTROYED; + r.app = null; } } else { // remove this record from the history. @@ -4071,6 +4078,7 @@ final class ActivityStack { if (DEBUG_STATES) Slog.v(TAG, "Moving to DESTROYED: " + r + " (no app)"); r.state = ActivityState.DESTROYED; + r.app = null; } } @@ -4106,30 +4114,85 @@ final class ActivityStack { } } - private void removeHistoryRecordsForAppLocked(ArrayList list, ProcessRecord app) { + private void removeHistoryRecordsForAppLocked(ArrayList list, ProcessRecord app, + String listName) { int i = list.size(); - if (localLOGV) Slog.v( - TAG, "Removing app " + app + " from list " + list + if (DEBUG_CLEANUP) Slog.v( + TAG, "Removing app " + app + " from list " + listName + " with " + i + " entries"); while (i > 0) { i--; ActivityRecord r = (ActivityRecord)list.get(i); - if (localLOGV) Slog.v( - TAG, "Record #" + i + " " + r + ": app=" + r.app); + if (DEBUG_CLEANUP) Slog.v(TAG, "Record #" + i + " " + r); if (r.app == app) { - if (localLOGV) Slog.v(TAG, "Removing this entry!"); + if (DEBUG_CLEANUP) Slog.v(TAG, "---> REMOVING this entry!"); list.remove(i); removeTimeoutsForActivityLocked(r); } } } - void removeHistoryRecordsForAppLocked(ProcessRecord app) { - removeHistoryRecordsForAppLocked(mLRUActivities, app); - removeHistoryRecordsForAppLocked(mStoppingActivities, app); - removeHistoryRecordsForAppLocked(mGoingToSleepActivities, app); - removeHistoryRecordsForAppLocked(mWaitingVisibleActivities, app); - removeHistoryRecordsForAppLocked(mFinishingActivities, app); + boolean removeHistoryRecordsForAppLocked(ProcessRecord app) { + removeHistoryRecordsForAppLocked(mLRUActivities, app, "mLRUActivities"); + removeHistoryRecordsForAppLocked(mStoppingActivities, app, "mStoppingActivities"); + removeHistoryRecordsForAppLocked(mGoingToSleepActivities, app, "mGoingToSleepActivities"); + removeHistoryRecordsForAppLocked(mWaitingVisibleActivities, app, + "mWaitingVisibleActivities"); + removeHistoryRecordsForAppLocked(mFinishingActivities, app, "mFinishingActivities"); + + boolean hasVisibleActivities = false; + + // Clean out the history list. + int i = mHistory.size(); + if (DEBUG_CLEANUP) Slog.v( + TAG, "Removing app " + app + " from history with " + i + " entries"); + while (i > 0) { + i--; + ActivityRecord r = (ActivityRecord)mHistory.get(i); + if (DEBUG_CLEANUP) Slog.v( + TAG, "Record #" + i + " " + r + ": app=" + r.app); + if (r.app == app) { + if ((!r.haveState && !r.stateNotNeeded) || r.finishing) { + if (ActivityStack.DEBUG_ADD_REMOVE || DEBUG_CLEANUP) { + RuntimeException here = new RuntimeException("here"); + here.fillInStackTrace(); + Slog.i(TAG, "Removing activity " + r + " from stack at " + i + + ": haveState=" + r.haveState + + " stateNotNeeded=" + r.stateNotNeeded + + " finishing=" + r.finishing + + " state=" + r.state, here); + } + if (!r.finishing) { + Slog.w(TAG, "Force removing " + r + ": app died, no saved state"); + EventLog.writeEvent(EventLogTags.AM_FINISH_ACTIVITY, + r.userId, System.identityHashCode(r), + r.task.taskId, r.shortComponentName, + "proc died without state saved"); + } + removeActivityFromHistoryLocked(r); + + } else { + // We have the current state for this activity, so + // it can be restarted later when needed. + if (localLOGV) Slog.v( + TAG, "Keeping entry, setting app to null"); + if (r.visible) { + hasVisibleActivities = true; + } + r.app = null; + r.nowVisible = false; + if (!r.haveState) { + if (ActivityStack.DEBUG_SAVED_STATE) Slog.i(TAG, + "App died, clearing saved state of " + r); + r.icicle = null; + } + } + + r.stack.cleanUpActivityLocked(r, true, true); + } + } + + return hasVisibleActivities; } /** @@ -4375,7 +4438,7 @@ final class ActivityStack { return null; } - // Remove all of this task's activies starting at the sub task. + // Remove all of this task's activities starting at the sub task. TaskAccessInfo.SubTask subtask = info.subtasks.get(subTaskIndex); performClearTaskAtIndexLocked(taskId, subtask.index); return subtask.activity; diff --git a/services/java/com/android/server/display/DisplayManagerService.java b/services/java/com/android/server/display/DisplayManagerService.java index f348cb6..b8c6cd5 100644 --- a/services/java/com/android/server/display/DisplayManagerService.java +++ b/services/java/com/android/server/display/DisplayManagerService.java @@ -209,7 +209,7 @@ public final class DisplayManagerService extends IDisplayManager.Stub { public void setWindowManager(WindowManagerFuncs windowManagerFuncs) { synchronized (mSyncRoot) { mWindowManagerFuncs = windowManagerFuncs; - scheduleTraversalLocked(); + scheduleTraversalLocked(false); } } @@ -220,7 +220,7 @@ public final class DisplayManagerService extends IDisplayManager.Stub { public void setInputManager(InputManagerFuncs inputManagerFuncs) { synchronized (mSyncRoot) { mInputManagerFuncs = inputManagerFuncs; - scheduleTraversalLocked(); + scheduleTraversalLocked(false); } } @@ -264,7 +264,7 @@ public final class DisplayManagerService extends IDisplayManager.Stub { display.setDisplayInfoOverrideFromWindowManagerLocked(info); if (!mTempDisplayInfo.equals(display.getDisplayInfoLocked())) { sendDisplayEventLocked(displayId, DisplayManagerGlobal.EVENT_DISPLAY_CHANGED); - scheduleTraversalLocked(); + scheduleTraversalLocked(false); } } } @@ -527,7 +527,7 @@ public final class DisplayManagerService extends IDisplayManager.Stub { mDisplayDevices.add(device); addLogicalDisplayLocked(device); - scheduleTraversalLocked(); + scheduleTraversalLocked(false); } } @@ -543,7 +543,7 @@ public final class DisplayManagerService extends IDisplayManager.Stub { device.applyPendingDisplayDeviceInfoChangesLocked(); if (updateLogicalDisplaysLocked()) { - scheduleTraversalLocked(); + scheduleTraversalLocked(false); } } } @@ -560,7 +560,7 @@ public final class DisplayManagerService extends IDisplayManager.Stub { mRemovedDisplayDevices.add(device); updateLogicalDisplaysLocked(); - scheduleTraversalLocked(); + scheduleTraversalLocked(false); } } @@ -668,13 +668,15 @@ public final class DisplayManagerService extends IDisplayManager.Stub { * * @param displayId The logical display id to update. * @param hasContent True if the logical display has content. + * @param inTraversal True if called from WindowManagerService during a window traversal prior + * to call to performTraversalInTransactionFromWindowManager. */ - public void setDisplayHasContent(int displayId, boolean hasContent) { + public void setDisplayHasContent(int displayId, boolean hasContent, boolean inTraversal) { synchronized (mSyncRoot) { LogicalDisplay display = mLogicalDisplays.get(displayId); if (display != null && display.hasContentLocked() != hasContent) { display.setHasContentLocked(hasContent); - scheduleTraversalLocked(); + scheduleTraversalLocked(inTraversal); } } } @@ -741,10 +743,12 @@ public final class DisplayManagerService extends IDisplayManager.Stub { // Requests that performTraversalsInTransactionFromWindowManager be called at a // later time to apply changes to surfaces and displays. - private void scheduleTraversalLocked() { + private void scheduleTraversalLocked(boolean inTraversal) { if (!mPendingTraversal && mWindowManagerFuncs != null) { mPendingTraversal = true; - mHandler.sendEmptyMessage(MSG_REQUEST_TRAVERSAL); + if (!inTraversal) { + mHandler.sendEmptyMessage(MSG_REQUEST_TRAVERSAL); + } } } @@ -911,7 +915,7 @@ public final class DisplayManagerService extends IDisplayManager.Stub { @Override public void onTraversalRequested() { synchronized (mSyncRoot) { - scheduleTraversalLocked(); + scheduleTraversalLocked(false); } } } diff --git a/services/java/com/android/server/input/InputManagerService.java b/services/java/com/android/server/input/InputManagerService.java index 7b0c452..5e4907e 100644 --- a/services/java/com/android/server/input/InputManagerService.java +++ b/services/java/com/android/server/input/InputManagerService.java @@ -113,6 +113,7 @@ public class InputManagerService extends IInputManager.Stub private final InputManagerHandler mHandler; private WindowManagerCallbacks mWindowManagerCallbacks; + private WiredAccessoryCallbacks mWiredAccessoryCallbacks; private boolean mSystemReady; private NotificationManager mNotificationManager; @@ -197,7 +198,7 @@ public class InputManagerService extends IInputManager.Stub // Key states (may be returned by queries about the current state of a // particular key code, scan code or switch). - + /** The key state is unknown or the requested key itself is not supported. */ public static final int KEY_STATE_UNKNOWN = -1; @@ -213,17 +214,41 @@ public class InputManagerService extends IInputManager.Stub /** Scan code: Mouse / trackball button. */ public static final int BTN_MOUSE = 0x110; + // Switch code values must match bionic/libc/kernel/common/linux/input.h /** Switch code: Lid switch. When set, lid is shut. */ public static final int SW_LID = 0x00; /** Switch code: Keypad slide. When set, keyboard is exposed. */ public static final int SW_KEYPAD_SLIDE = 0x0a; + /** Switch code: Headphone. When set, headphone is inserted. */ + public static final int SW_HEADPHONE_INSERT = 0x02; + + /** Switch code: Microphone. When set, microphone is inserted. */ + public static final int SW_MICROPHONE_INSERT = 0x04; + + /** Switch code: Headphone/Microphone Jack. When set, something is inserted. */ + public static final int SW_JACK_PHYSICAL_INSERT = 0x07; + + public static final int SW_LID_BIT = 1 << SW_LID; + public static final int SW_KEYPAD_SLIDE_BIT = 1 << SW_KEYPAD_SLIDE; + public static final int SW_HEADPHONE_INSERT_BIT = 1 << SW_HEADPHONE_INSERT; + public static final int SW_MICROPHONE_INSERT_BIT = 1 << SW_MICROPHONE_INSERT; + public static final int SW_JACK_PHYSICAL_INSERT_BIT = 1 << SW_JACK_PHYSICAL_INSERT; + public static final int SW_JACK_BITS = + SW_HEADPHONE_INSERT_BIT | SW_MICROPHONE_INSERT_BIT | SW_JACK_PHYSICAL_INSERT_BIT; + + /** Whether to use the dev/input/event or uevent subsystem for the audio jack. */ + final boolean mUseDevInputEventForAudioJack; + public InputManagerService(Context context, Handler handler) { this.mContext = context; this.mHandler = new InputManagerHandler(handler.getLooper()); - Slog.i(TAG, "Initializing input manager"); + mUseDevInputEventForAudioJack = + context.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack); + Slog.i(TAG, "Initializing input manager, mUseDevInputEventForAudioJack=" + + mUseDevInputEventForAudioJack); mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue()); } @@ -231,6 +256,10 @@ public class InputManagerService extends IInputManager.Stub mWindowManagerCallbacks = callbacks; } + public void setWiredAccessoryCallbacks(WiredAccessoryCallbacks callbacks) { + mWiredAccessoryCallbacks = callbacks; + } + public void start() { Slog.i(TAG, "Starting input manager"); nativeStart(mPtr); @@ -335,7 +364,7 @@ public class InputManagerService extends IInputManager.Stub public int getKeyCodeState(int deviceId, int sourceMask, int keyCode) { return nativeGetKeyCodeState(mPtr, deviceId, sourceMask, keyCode); } - + /** * Gets the current state of a key or button by scan code. * @param deviceId The input device id, or -1 to consult all devices. @@ -513,7 +542,7 @@ public class InputManagerService extends IInputManager.Stub /** * Gets information about the input device with the specified id. - * @param id The device id. + * @param deviceId The device id. * @return The input device or null if not found. */ @Override // Binder call @@ -976,8 +1005,8 @@ public class InputManagerService extends IInputManager.Stub // Must be called on handler. private void handleSwitchKeyboardLayout(int deviceId, int direction) { final InputDevice device = getInputDevice(deviceId); - final String inputDeviceDescriptor = device.getDescriptor(); if (device != null) { + final String inputDeviceDescriptor = device.getDescriptor(); final boolean changed; final String keyboardLayoutDescriptor; synchronized (mDataStore) { @@ -1214,6 +1243,7 @@ public class InputManagerService extends IInputManager.Stub } // Called by the heartbeat to ensure locks are not held indefinitely (for deadlock detection). + @Override public void monitor() { synchronized (mInputFilterLock) { } nativeMonitor(mPtr); @@ -1244,10 +1274,15 @@ public class InputManagerService extends IInputManager.Stub + ", mask=" + Integer.toHexString(switchMask)); } - if ((switchMask & (1 << SW_LID)) != 0) { - final boolean lidOpen = ((switchValues & (1 << SW_LID)) == 0); + if ((switchMask & SW_LID_BIT) != 0) { + final boolean lidOpen = ((switchValues & SW_LID_BIT) == 0); mWindowManagerCallbacks.notifyLidSwitchChanged(whenNanos, lidOpen); } + + if (mUseDevInputEventForAudioJack && (switchMask & SW_JACK_BITS) != 0) { + mWiredAccessoryCallbacks.notifyWiredAccessoryChanged(whenNanos, switchValues, + switchMask); + } } // Native callback. @@ -1431,7 +1466,6 @@ public class InputManagerService extends IInputManager.Stub return null; } - /** * Callback interface implemented by the Window Manager. */ @@ -1459,6 +1493,13 @@ public class InputManagerService extends IInputManager.Stub } /** + * Callback interface implemented by WiredAccessoryObserver. + */ + public interface WiredAccessoryCallbacks { + public void notifyWiredAccessoryChanged(long whenNanos, int switchValues, int switchMask); + } + + /** * Private handler for the input manager. */ private final class InputManagerHandler extends Handler { @@ -1498,6 +1539,7 @@ public class InputManagerService extends IInputManager.Stub mDisconnected = true; } + @Override public void sendInputEvent(InputEvent event, int policyFlags) { if (event == null) { throw new IllegalArgumentException("event must not be null"); diff --git a/services/java/com/android/server/location/GpsLocationProvider.java b/services/java/com/android/server/location/GpsLocationProvider.java index 84adb83..a254d74 100755 --- a/services/java/com/android/server/location/GpsLocationProvider.java +++ b/services/java/com/android/server/location/GpsLocationProvider.java @@ -40,10 +40,8 @@ import android.os.Binder; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; -import android.os.Looper; import android.os.Message; import android.os.PowerManager; -import android.os.Process; import android.os.RemoteException; import android.os.ServiceManager; import android.os.SystemClock; @@ -75,7 +73,6 @@ import java.util.ArrayList; import java.util.Date; import java.util.Map.Entry; import java.util.Properties; -import java.util.concurrent.CountDownLatch; /** * A GPS implementation of LocationProvider used by LocationManager. @@ -287,12 +284,8 @@ public class GpsLocationProvider implements LocationProviderInterface { private Bundle mLocationExtras = new Bundle(); private ArrayList<Listener> mListeners = new ArrayList<Listener>(); - // GpsLocationProvider's handler thread - private final Thread mThread; - // Handler for processing events in mThread. + // Handler for processing events private Handler mHandler; - // Used to signal when our main thread has initialized everything - private final CountDownLatch mInitializedLatch = new CountDownLatch(1); private String mAGpsApn; private int mAGpsDataConnectionState; @@ -437,21 +430,6 @@ public class GpsLocationProvider implements LocationProviderInterface { mWakeupIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(ALARM_WAKEUP), 0); mTimeoutIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(ALARM_TIMEOUT), 0); - IntentFilter intentFilter = new IntentFilter(); - intentFilter.addAction(Intents.DATA_SMS_RECEIVED_ACTION); - intentFilter.addDataScheme("sms"); - intentFilter.addDataAuthority("localhost","7275"); - context.registerReceiver(mBroadcastReciever, intentFilter); - - intentFilter = new IntentFilter(); - intentFilter.addAction(Intents.WAP_PUSH_RECEIVED_ACTION); - try { - intentFilter.addDataType("application/vnd.omaloc-supl-init"); - } catch (IntentFilter.MalformedMimeTypeException e) { - Log.w(TAG, "Malformed SUPL init mime type"); - } - context.registerReceiver(mBroadcastReciever, intentFilter); - mConnMgr = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE); // Battery statistics service to be notified when GPS turns on or off @@ -487,26 +465,43 @@ public class GpsLocationProvider implements LocationProviderInterface { Log.w(TAG, "Could not open GPS configuration file " + PROPERTIES_FILE); } - // wait until we are fully initialized before returning - mThread = new GpsLocationProviderThread(); - mThread.start(); - while (true) { - try { - mInitializedLatch.await(); - break; - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); + // construct handler, listen for events + mHandler = new ProviderHandler(); + listenForBroadcasts(); + + // also listen for PASSIVE_PROVIDER updates + mHandler.post(new Runnable() { + @Override + public void run() { + LocationManager locManager = + (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE); + locManager.requestLocationUpdates(LocationManager.PASSIVE_PROVIDER, + 0, 0, new NetworkLocationListener(), mHandler.getLooper()); } - } + }); } - private void initialize() { - // register our receiver on our thread rather than the main thread + private void listenForBroadcasts() { IntentFilter intentFilter = new IntentFilter(); + intentFilter.addAction(Intents.DATA_SMS_RECEIVED_ACTION); + intentFilter.addDataScheme("sms"); + intentFilter.addDataAuthority("localhost","7275"); + mContext.registerReceiver(mBroadcastReciever, intentFilter, null, mHandler); + + intentFilter = new IntentFilter(); + intentFilter.addAction(Intents.WAP_PUSH_RECEIVED_ACTION); + try { + intentFilter.addDataType("application/vnd.omaloc-supl-init"); + } catch (IntentFilter.MalformedMimeTypeException e) { + Log.w(TAG, "Malformed SUPL init mime type"); + } + mContext.registerReceiver(mBroadcastReciever, intentFilter, null, mHandler); + + intentFilter = new IntentFilter(); intentFilter.addAction(ALARM_WAKEUP); intentFilter.addAction(ALARM_TIMEOUT); intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); - mContext.registerReceiver(mBroadcastReciever, intentFilter); + mContext.registerReceiver(mBroadcastReciever, intentFilter, null, mHandler); } /** @@ -1536,29 +1531,6 @@ public class GpsLocationProvider implements LocationProviderInterface { } }; - private final class GpsLocationProviderThread extends Thread { - - public GpsLocationProviderThread() { - super("GpsLocationProvider"); - } - - @Override - public void run() { - Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); - initialize(); - Looper.prepare(); - - LocationManager locManager = - (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE); - mHandler = new ProviderHandler(); - // signal when we are initialized and ready to go - mInitializedLatch.countDown(); - locManager.requestLocationUpdates(LocationManager.PASSIVE_PROVIDER, - 0, 0, new NetworkLocationListener(), Looper.myLooper()); - Looper.loop(); - } - } - private final class NetworkLocationListener implements LocationListener { @Override public void onLocationChanged(Location location) { diff --git a/services/java/com/android/server/pm/Installer.java b/services/java/com/android/server/pm/Installer.java index ad85c0d..8b1e80f 100644 --- a/services/java/com/android/server/pm/Installer.java +++ b/services/java/com/android/server/pm/Installer.java @@ -254,10 +254,12 @@ public final class Installer { return execute(builder.toString()); } - public int deleteCacheFiles(String name) { + public int deleteCacheFiles(String name, int userId) { StringBuilder builder = new StringBuilder("rmcache"); builder.append(' '); builder.append(name); + builder.append(' '); + builder.append(userId); return execute(builder.toString()); } diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java index 1eafd9c..75bc265 100644 --- a/services/java/com/android/server/pm/PackageManagerService.java +++ b/services/java/com/android/server/pm/PackageManagerService.java @@ -45,6 +45,7 @@ import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlSerializer; +import android.app.ActivityManager; import android.app.ActivityManagerNative; import android.app.IActivityManager; import android.app.admin.IDevicePolicyManager; @@ -5890,6 +5891,10 @@ public class PackageManagerService extends IPackageManager.Stub { // Check if installing from ADB if ((flags & PackageManager.INSTALL_FROM_ADB) != 0) { + // Do not run verification in a test harness environment + if (ActivityManager.isRunningInTestHarness()) { + return false; + } // Check if the developer does not want package verification for ADB installs if (android.provider.Settings.Global.getInt(mContext.getContentResolver(), android.provider.Settings.Global.PACKAGE_VERIFIER_INCLUDE_ADB, 1) == 0) { @@ -8535,11 +8540,10 @@ public class PackageManagerService extends IPackageManager.Stub { Slog.w(TAG, "Package " + packageName + " has no applicationInfo."); return false; } - // TODO: Pass userId to deleteCacheFiles - int retCode = mInstaller.deleteCacheFiles(packageName); + int retCode = mInstaller.deleteCacheFiles(packageName, userId); if (retCode < 0) { Slog.w(TAG, "Couldn't remove cache files for package: " - + packageName); + + packageName + " u" + userId); return false; } return true; diff --git a/services/java/com/android/server/power/DisplayPowerController.java b/services/java/com/android/server/power/DisplayPowerController.java index 5f4a786..4f8cdde 100644 --- a/services/java/com/android/server/power/DisplayPowerController.java +++ b/services/java/com/android/server/power/DisplayPowerController.java @@ -44,7 +44,6 @@ import android.util.TimeUtils; import android.view.Display; import java.io.PrintWriter; -import java.io.StringWriter; import java.util.concurrent.Executor; /** @@ -95,7 +94,8 @@ final class DisplayPowerController { // when it is especially dark outside. The light sensor tends to perform // poorly at low light levels so we compensate for it by making an // assumption about the environment. - private static final boolean USE_TWILIGHT_ADJUSTMENT = true; + private static final boolean USE_TWILIGHT_ADJUSTMENT = + PowerManager.useTwilightAdjustmentFeature(); // Specifies the maximum magnitude of the time of day adjustment. private static final float TWILIGHT_ADJUSTMENT_MAX_GAMMA = 1.5f; diff --git a/services/java/com/android/server/power/PowerManagerService.java b/services/java/com/android/server/power/PowerManagerService.java index c2d47e5..664125a 100644 --- a/services/java/com/android/server/power/PowerManagerService.java +++ b/services/java/com/android/server/power/PowerManagerService.java @@ -266,6 +266,11 @@ public final class PowerManagerService extends IPowerManager.Stub // Use -1 to disable. private int mScreenBrightnessOverrideFromWindowManager = -1; + // The user activity timeout override from the window manager + // to allow the current foreground activity to override the user activity timeout. + // Use -1 to disable. + private long mUserActivityTimeoutOverrideFromWindowManager = -1; + // The screen brightness setting override from the settings application // to temporarily adjust the brightness until next updated, // Use -1 to disable. @@ -277,6 +282,9 @@ public final class PowerManagerService extends IPowerManager.Stub // Use NaN to disable. private float mTemporaryScreenAutoBrightnessAdjustmentSettingOverride = Float.NaN; + // Time when we last logged a warning about calling userActivity() without permission. + private long mLastWarningAboutUserActivityPermission = Long.MIN_VALUE; + private native void nativeInit(); private static native void nativeShutdown(); private static native void nativeReboot(String reason) throws IOException; @@ -683,12 +691,29 @@ public final class PowerManagerService extends IPowerManager.Stub @Override // Binder call public void userActivity(long eventTime, int event, int flags) { + final long now = SystemClock.uptimeMillis(); + if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER) + != PackageManager.PERMISSION_GRANTED) { + // Once upon a time applications could call userActivity(). + // Now we require the DEVICE_POWER permission. Log a warning and ignore the + // request instead of throwing a SecurityException so we don't break old apps. + synchronized (mLock) { + if (now >= mLastWarningAboutUserActivityPermission + (5 * 60 * 1000)) { + mLastWarningAboutUserActivityPermission = now; + Slog.w(TAG, "Ignoring call to PowerManager.userActivity() because the " + + "caller does not have DEVICE_POWER permission. " + + "Please fix your app! " + + " pid=" + Binder.getCallingPid() + + " uid=" + Binder.getCallingUid()); + } + } + return; + } + if (eventTime > SystemClock.uptimeMillis()) { throw new IllegalArgumentException("event time must not be in the future"); } - mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null); - final int uid = Binder.getCallingUid(); final long ident = Binder.clearCallingIdentity(); try { @@ -1156,6 +1181,9 @@ public final class PowerManagerService extends IPowerManager.Stub if (isMaximumScreenOffTimeoutFromDeviceAdminEnforcedLocked()) { timeout = Math.min(timeout, mMaximumScreenOffTimeoutFromDeviceAdmin); } + if (mUserActivityTimeoutOverrideFromWindowManager >= 0) { + timeout = (int)Math.min(timeout, mUserActivityTimeoutOverrideFromWindowManager); + } return Math.max(timeout, MINIMUM_SCREEN_OFF_TIMEOUT); } @@ -1573,18 +1601,6 @@ public final class PowerManagerService extends IPowerManager.Stub } } - @Override // Binder call - public void clearUserActivityTimeout(long now, long timeout) { - // TODO Auto-generated method stub - // Only used by phone app, delete this - } - - @Override // Binder call - public void setPokeLock(int pokey, IBinder lock, String tag) { - // TODO Auto-generated method stub - // Only used by phone app, delete this - } - /** * Set the setting that determines whether the device stays on when plugged in. * The argument is a bit string, with each bit specifying a power source that, @@ -1727,6 +1743,36 @@ public final class PowerManagerService extends IPowerManager.Stub } /** + * Used by the window manager to override the user activity timeout based on the + * current foreground activity. It can only be used to make the timeout shorter + * than usual, not longer. + * + * This method must only be called by the window manager. + * + * @param timeoutMillis The overridden timeout, or -1 to disable the override. + */ + public void setUserActivityTimeoutOverrideFromWindowManager(long timeoutMillis) { + mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null); + + final long ident = Binder.clearCallingIdentity(); + try { + setUserActivityTimeoutOverrideFromWindowManagerInternal(timeoutMillis); + } finally { + Binder.restoreCallingIdentity(ident); + } + } + + private void setUserActivityTimeoutOverrideFromWindowManagerInternal(long timeoutMillis) { + synchronized (mLock) { + if (mUserActivityTimeoutOverrideFromWindowManager != timeoutMillis) { + mUserActivityTimeoutOverrideFromWindowManager = timeoutMillis; + mDirty |= DIRTY_SETTINGS; + updatePowerStateLocked(); + } + } + } + + /** * Used by the settings application and brightness control widgets to * temporarily override the current screen brightness setting so that the * user can observe the effect of an intended settings change without applying @@ -1875,6 +1921,8 @@ public final class PowerManagerService extends IPowerManager.Stub pw.println(" mScreenBrightnessModeSetting=" + mScreenBrightnessModeSetting); pw.println(" mScreenBrightnessOverrideFromWindowManager=" + mScreenBrightnessOverrideFromWindowManager); + pw.println(" mUserActivityTimeoutOverrideFromWindowManager=" + + mUserActivityTimeoutOverrideFromWindowManager); pw.println(" mTemporaryScreenBrightnessSettingOverride=" + mTemporaryScreenBrightnessSettingOverride); pw.println(" mTemporaryScreenAutoBrightnessAdjustmentSettingOverride=" diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java index 23ce52e..3f7b67b 100755 --- a/services/java/com/android/server/wm/WindowManagerService.java +++ b/services/java/com/android/server/wm/WindowManagerService.java @@ -18,19 +18,24 @@ package com.android.server.wm; import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW; import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW; +import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM; import static android.view.WindowManager.LayoutParams.FLAG_COMPATIBLE_WINDOW; import static android.view.WindowManager.LayoutParams.FLAG_DIM_BEHIND; import static android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON; import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; -import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM; import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER; import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW; import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW; +import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING; import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION; +import static android.view.WindowManager.LayoutParams.TYPE_BOOT_PROGRESS; import static android.view.WindowManager.LayoutParams.TYPE_DREAM; import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD; import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG; +import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD; +import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG; +import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ERROR; import static android.view.WindowManager.LayoutParams.TYPE_UNIVERSE_BACKGROUND; import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER; @@ -593,7 +598,13 @@ public class WindowManagerService extends IWindowManager.Stub private boolean mSyswin = false; private float mScreenBrightness = -1; private float mButtonBrightness = -1; + private long mUserActivityTimeout = -1; private boolean mUpdateRotation = false; + + private static final int DISPLAY_CONTENT_UNKNOWN = 0; + private static final int DISPLAY_CONTENT_MIRROR = 1; + private static final int DISPLAY_CONTENT_UNIQUE = 2; + private int mDisplayHasContent = DISPLAY_CONTENT_UNKNOWN; } final LayoutFields mInnerFields = new LayoutFields(); @@ -1118,10 +1129,6 @@ public class WindowManagerService extends IWindowManager.Stub if (win.mAppToken != null && addToToken) { win.mAppToken.allAppWindows.add(win); } - - if (windows.size() == 1) { - mDisplayManagerService.setDisplayHasContent(win.getDisplayId(), true); - } } /** TODO(cmautner): Is this the same as {@link WindowState#canReceiveKeys()} */ @@ -1129,7 +1136,7 @@ public class WindowManagerService extends IWindowManager.Stub final int fl = w.mAttrs.flags & (FLAG_NOT_FOCUSABLE|FLAG_ALT_FOCUSABLE_IM); if (fl == 0 || fl == (FLAG_NOT_FOCUSABLE|FLAG_ALT_FOCUSABLE_IM) - || w.mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_STARTING) { + || w.mAttrs.type == TYPE_APPLICATION_STARTING) { if (DEBUG_INPUT_METHOD) { Slog.i(TAG, "isVisibleOrAdding " + w + ": " + w.isVisibleOrAdding()); if (!w.isVisibleOrAdding()) { @@ -1177,7 +1184,7 @@ public class WindowManagerService extends IWindowManager.Stub // is not actually looking to move the IME, look down below // for a real window to target... if (!willMove - && w.mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_STARTING + && w.mAttrs.type == TYPE_APPLICATION_STARTING && i > 0) { WindowState wb = windows.get(i-1); if (wb.mAppToken == w.mAppToken && canBeImeTarget(wb)) { @@ -1576,7 +1583,7 @@ public class WindowManagerService extends IWindowManager.Stub while (i > 0) { i--; w = windows.get(i); - if ((w.mAttrs.type == WindowManager.LayoutParams.TYPE_WALLPAPER)) { + if ((w.mAttrs.type == TYPE_WALLPAPER)) { if (topCurW == null) { topCurW = w; topCurI = i; @@ -2411,9 +2418,6 @@ public class WindowManagerService extends IWindowManager.Stub final WindowList windows = win.getWindowList(); windows.remove(win); - if (windows.isEmpty()) { - mDisplayManagerService.setDisplayHasContent(win.getDisplayId(), false); - } mPendingRemove.remove(win); mWindowsChanged = true; if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG, "Final remove of window: " + win); @@ -2748,7 +2752,10 @@ public class WindowManagerService extends IWindowManager.Stub } } - if (DEBUG_LAYOUT) Slog.v(TAG, "Relayout " + win + ": viewVisibility=" + viewVisibility + if (DEBUG_LAYOUT + // TODO: Remove once b/7094175 is fixed + || ((String)win.mAttrs.getTitle()).contains("Keyguard") + ) Slog.v(TAG, "Relayout " + win + ": viewVisibility=" + viewVisibility + " " + requestedWidth + "x" + requestedHeight + " " + win.mAttrs); win.mEnforceSizeCompat = (win.mAttrs.flags & FLAG_COMPATIBLE_WINDOW) != 0; @@ -2771,13 +2778,11 @@ public class WindowManagerService extends IWindowManager.Stub win.mHScale = win.mVScale = 1; } - boolean imMayMove = (flagChanges&( - WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM | - WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE)) != 0; + boolean imMayMove = (flagChanges & (FLAG_ALT_FOCUSABLE_IM | FLAG_NOT_FOCUSABLE)) != 0; final boolean isDefaultDisplay = win.isDefaultDisplay(); boolean focusMayChange = isDefaultDisplay && (win.mViewVisibility != viewVisibility - || ((flagChanges&WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE) != 0) + || ((flagChanges & FLAG_NOT_FOCUSABLE) != 0) || (!win.mRelayoutCalled)); boolean wallpaperMayMove = win.mViewVisibility != viewVisibility @@ -3091,8 +3096,7 @@ public class WindowManagerService extends IWindowManager.Stub final int windowCount = windows.size(); for (int i = 0; i < windowCount; i++) { WindowState window = windows.get(i); - if (window.isVisibleLw() || - window.mAttrs.type == WindowManager.LayoutParams.TYPE_UNIVERSE_BACKGROUND) { + if (window.isVisibleLw() || window.mAttrs.type == TYPE_UNIVERSE_BACKGROUND) { WindowInfo info = getWindowInfoForWindowStateLocked(window); outInfos.add(info); } @@ -3146,8 +3150,7 @@ public class WindowManagerService extends IWindowManager.Stub info.type = window.mAttrs.type; info.displayId = window.getDisplayId(); info.compatibilityScale = window.mGlobalScale; - info.visible = window.isVisibleLw() - || info.type == WindowManager.LayoutParams.TYPE_UNIVERSE_BACKGROUND; + info.visible = window.isVisibleLw() || info.type == TYPE_UNIVERSE_BACKGROUND; info.layer = window.mLayer; window.getTouchableRegion(mTempRegion); mTempRegion.getBounds(info.touchableRegion); @@ -4372,7 +4375,7 @@ public class WindowManagerService extends IWindowManager.Stub // an opaque window and our starting window transition animation // can still work. We just need to make sure the starting window // is also showing the wallpaper. - windowFlags |= WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER; + windowFlags |= FLAG_SHOW_WALLPAPER; } else { return; } @@ -5494,7 +5497,7 @@ public class WindowManagerService extends IWindowManager.Stub final int N = windows.size(); for (int i=0; i<N; i++) { WindowState w = windows.get(i); - if (w.mAttrs.type == WindowManager.LayoutParams.TYPE_KEYGUARD) { + if (w.mAttrs.type == TYPE_KEYGUARD) { // Only if there is a keyguard attached to the window manager // will we consider ourselves as having a keyguard. If it // isn't attached, we don't know if it wants to be shown or @@ -5510,13 +5513,13 @@ public class WindowManagerService extends IWindowManager.Stub return; } if (w.isDrawnLw()) { - if (w.mAttrs.type == WindowManager.LayoutParams.TYPE_BOOT_PROGRESS) { + if (w.mAttrs.type == TYPE_BOOT_PROGRESS) { haveBootMsg = true; - } else if (w.mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION) { + } else if (w.mAttrs.type == TYPE_APPLICATION) { haveApp = true; - } else if (w.mAttrs.type == WindowManager.LayoutParams.TYPE_WALLPAPER) { + } else if (w.mAttrs.type == TYPE_WALLPAPER) { haveWallpaper = true; - } else if (w.mAttrs.type == WindowManager.LayoutParams.TYPE_KEYGUARD) { + } else if (w.mAttrs.type == TYPE_KEYGUARD) { haveKeyguard = true; } } @@ -5712,9 +5715,8 @@ public class WindowManagerService extends IWindowManager.Stub dw = displayInfo.logicalWidth; dh = displayInfo.logicalHeight; - int aboveAppLayer = mPolicy.windowTypeToLayerLw( - WindowManager.LayoutParams.TYPE_APPLICATION) * TYPE_LAYER_MULTIPLIER - + TYPE_LAYER_OFFSET; + int aboveAppLayer = mPolicy.windowTypeToLayerLw(TYPE_APPLICATION) + * TYPE_LAYER_MULTIPLIER + TYPE_LAYER_OFFSET; aboveAppLayer += TYPE_LAYER_MULTIPLIER; boolean isImeTarget = mInputMethodTarget != null @@ -6673,9 +6675,6 @@ public class WindowManagerService extends IWindowManager.Stub int h = mPolicy.getNonDecorDisplayHeight(dw, dh, rotation); // Compute the screen layout size class for this rotation. - int screenLayoutSize; - boolean screenLayoutLong; - boolean screenLayoutCompatNeeded; int longSize = w; int shortSize = h; if (longSize < shortSize) { @@ -6685,64 +6684,7 @@ public class WindowManagerService extends IWindowManager.Stub } longSize = (int)(longSize/density); shortSize = (int)(shortSize/density); - - // These semi-magic numbers define our compatibility modes for - // applications with different screens. These are guarantees to - // app developers about the space they can expect for a particular - // configuration. DO NOT CHANGE! - if (longSize < 470) { - // This is shorter than an HVGA normal density screen (which - // is 480 pixels on its long side). - screenLayoutSize = Configuration.SCREENLAYOUT_SIZE_SMALL; - screenLayoutLong = false; - screenLayoutCompatNeeded = false; - } else { - // What size is this screen screen? - if (longSize >= 960 && shortSize >= 720) { - // 1.5xVGA or larger screens at medium density are the point - // at which we consider it to be an extra large screen. - screenLayoutSize = Configuration.SCREENLAYOUT_SIZE_XLARGE; - } else if (longSize >= 640 && shortSize >= 480) { - // VGA or larger screens at medium density are the point - // at which we consider it to be a large screen. - screenLayoutSize = Configuration.SCREENLAYOUT_SIZE_LARGE; - } else { - screenLayoutSize = Configuration.SCREENLAYOUT_SIZE_NORMAL; - } - - // If this screen is wider than normal HVGA, or taller - // than FWVGA, then for old apps we want to run in size - // compatibility mode. - if (shortSize > 321 || longSize > 570) { - screenLayoutCompatNeeded = true; - } else { - screenLayoutCompatNeeded = false; - } - - // Is this a long screen? - if (((longSize*3)/5) >= (shortSize-1)) { - // Anything wider than WVGA (5:3) is considering to be long. - screenLayoutLong = true; - } else { - screenLayoutLong = false; - } - } - - // Now reduce the last screenLayout to not be better than what we - // have found. - if (!screenLayoutLong) { - curLayout = (curLayout&~Configuration.SCREENLAYOUT_LONG_MASK) - | Configuration.SCREENLAYOUT_LONG_NO; - } - if (screenLayoutCompatNeeded) { - curLayout |= Configuration.SCREENLAYOUT_COMPAT_NEEDED; - } - int curSize = curLayout&Configuration.SCREENLAYOUT_SIZE_MASK; - if (screenLayoutSize < curSize) { - curLayout = (curLayout&~Configuration.SCREENLAYOUT_SIZE_MASK) - | screenLayoutSize; - } - return curLayout; + return Configuration.reduceScreenLayout(curLayout, longSize, shortSize); } private void computeSizeRangesAndScreenLayout(DisplayInfo displayInfo, boolean rotated, @@ -6769,15 +6711,13 @@ public class WindowManagerService extends IWindowManager.Stub adjustDisplaySizeRanges(displayInfo, Surface.ROTATION_90, unrotDh, unrotDw); adjustDisplaySizeRanges(displayInfo, Surface.ROTATION_180, unrotDw, unrotDh); adjustDisplaySizeRanges(displayInfo, Surface.ROTATION_270, unrotDh, unrotDw); - int sl = Configuration.SCREENLAYOUT_SIZE_XLARGE - | Configuration.SCREENLAYOUT_LONG_YES; + int sl = Configuration.resetScreenLayout(outConfig.screenLayout); sl = reduceConfigLayout(sl, Surface.ROTATION_0, density, unrotDw, unrotDh); sl = reduceConfigLayout(sl, Surface.ROTATION_90, density, unrotDh, unrotDw); sl = reduceConfigLayout(sl, Surface.ROTATION_180, density, unrotDw, unrotDh); sl = reduceConfigLayout(sl, Surface.ROTATION_270, density, unrotDh, unrotDw); outConfig.smallestScreenWidthDp = (int)(displayInfo.smallestNominalAppWidth / density); - outConfig.screenLayout = - sl|(outConfig.screenLayout&Configuration.SCREENLAYOUT_LAYOUTDIR_MASK); + outConfig.screenLayout = sl; } private int reduceCompatConfigWidthSize(int curSize, int rotation, DisplayMetrics dm, @@ -8053,8 +7993,7 @@ public class WindowManagerService extends IWindowManager.Stub numRemoved++; continue; } else if (lastBelow == i-1) { - if (w.mAttrs.type == WindowManager.LayoutParams.TYPE_WALLPAPER - || w.mAttrs.type == WindowManager.LayoutParams.TYPE_UNIVERSE_BACKGROUND) { + if (w.mAttrs.type == TYPE_WALLPAPER || w.mAttrs.type == TYPE_UNIVERSE_BACKGROUND) { lastBelow = i; } } @@ -8837,12 +8776,27 @@ public class WindowManagerService extends IWindowManager.Stub && mInnerFields.mButtonBrightness < 0) { mInnerFields.mButtonBrightness = w.mAttrs.buttonBrightness; } + if (!mInnerFields.mSyswin && w.mAttrs.userActivityTimeout >= 0 + && mInnerFields.mUserActivityTimeout < 0) { + mInnerFields.mUserActivityTimeout = w.mAttrs.userActivityTimeout; + } + + final int type = attrs.type; if (canBeSeen - && (attrs.type == WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG - || attrs.type == WindowManager.LayoutParams.TYPE_KEYGUARD - || attrs.type == WindowManager.LayoutParams.TYPE_SYSTEM_ERROR)) { + && (type == TYPE_SYSTEM_DIALOG + || type == TYPE_KEYGUARD + || type == TYPE_SYSTEM_ERROR)) { mInnerFields.mSyswin = true; } + + if (canBeSeen) { + if (type == TYPE_DREAM || type == TYPE_KEYGUARD) { + mInnerFields.mDisplayHasContent = LayoutFields.DISPLAY_CONTENT_MIRROR; + } else if (mInnerFields.mDisplayHasContent + == LayoutFields.DISPLAY_CONTENT_UNKNOWN) { + mInnerFields.mDisplayHasContent = LayoutFields.DISPLAY_CONTENT_UNIQUE; + } + } } boolean opaqueDrawn = canBeSeen && w.isOpaqueDrawn(); @@ -8861,7 +8815,7 @@ public class WindowManagerService extends IWindowManager.Stub final WindowStateAnimator winAnimator = w.mWinAnimator; if (!mAnimator.isDimmingLocked(winAnimator)) { final int width, height; - if (attrs.type == WindowManager.LayoutParams.TYPE_BOOT_PROGRESS) { + if (attrs.type == TYPE_BOOT_PROGRESS) { final DisplayInfo displayInfo = w.mDisplayContent.getDisplayInfo(); width = displayInfo.logicalWidth; height = displayInfo.logicalHeight; @@ -8926,6 +8880,9 @@ public class WindowManagerService extends IWindowManager.Stub mInnerFields.mHoldScreen = null; mInnerFields.mScreenBrightness = -1; mInnerFields.mButtonBrightness = -1; + mInnerFields.mUserActivityTimeout = -1; + mInnerFields.mDisplayHasContent = LayoutFields.DISPLAY_CONTENT_UNKNOWN; + mTransactionSequence++; final DisplayContent defaultDisplay = getDefaultDisplayContentLocked(); @@ -8945,10 +8902,6 @@ public class WindowManagerService extends IWindowManager.Stub mStrictModeFlash.positionSurface(defaultDw, defaultDh); } - // Give the display manager a chance to adjust properties - // like display rotation if it needs to. - mDisplayManagerService.performTraversalInTransactionFromWindowManager(); - boolean focusDisplayed = false; boolean updateAllDrawn = false; @@ -8964,6 +8917,11 @@ public class WindowManagerService extends IWindowManager.Stub final int innerDh = displayInfo.appHeight; final boolean isDefaultDisplay = (displayId == Display.DEFAULT_DISPLAY); + // Reset for each display unless we are forcing mirroring. + if (mInnerFields.mDisplayHasContent != LayoutFields.DISPLAY_CONTENT_MIRROR) { + mInnerFields.mDisplayHasContent = LayoutFields.DISPLAY_CONTENT_UNKNOWN; + } + int repeats = 0; do { repeats++; @@ -9083,9 +9041,8 @@ public class WindowManagerService extends IWindowManager.Stub final boolean committed = winAnimator.commitFinishDrawingLocked(currentTime); if (isDefaultDisplay && committed) { - if ((w.mAttrs.flags - & WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER) != 0) { - if (WindowManagerService.DEBUG_WALLPAPER) Slog.v(TAG, + if ((w.mAttrs.flags & FLAG_SHOW_WALLPAPER) != 0) { + if (DEBUG_WALLPAPER) Slog.v(TAG, "First draw done in potential wallpaper target " + w); mInnerFields.mWallpaperMayChange = true; displayContent.pendingLayoutChanges |= @@ -9101,7 +9058,8 @@ public class WindowManagerService extends IWindowManager.Stub winAnimator.setSurfaceBoundariesLocked(recoveringMemory); final AppWindowToken atoken = w.mAppToken; - if (DEBUG_STARTING_WINDOW && atoken != null && w == atoken.startingWindow) { + if (DEBUG_STARTING_WINDOW && atoken != null + && w == atoken.startingWindow) { Slog.d(TAG, "updateWindows: starting " + w + " isOnScreen=" + w.isOnScreen() + " allDrawn=" + atoken.allDrawn + " freezingScreen=" + atoken.mAppAnimator.freezingScreen); @@ -9113,8 +9071,7 @@ public class WindowManagerService extends IWindowManager.Stub atoken.numInterestingWindows = atoken.numDrawnWindows = 0; atoken.startingDisplayed = false; } - if ((w.isOnScreen() || winAnimator.mAttrType - == WindowManager.LayoutParams.TYPE_BASE_APPLICATION) + if ((w.isOnScreen() || winAnimator.mAttrType == TYPE_BASE_APPLICATION) && !w.mExiting && !w.mDestroying) { if (WindowManagerService.DEBUG_VISIBILITY || WindowManagerService.DEBUG_ORIENTATION) { @@ -9157,6 +9114,22 @@ public class WindowManagerService extends IWindowManager.Stub updateResizingWindows(w); } + final boolean hasUniqueContent; + switch (mInnerFields.mDisplayHasContent) { + case LayoutFields.DISPLAY_CONTENT_MIRROR: + hasUniqueContent = isDefaultDisplay; + break; + case LayoutFields.DISPLAY_CONTENT_UNIQUE: + hasUniqueContent = true; + break; + case LayoutFields.DISPLAY_CONTENT_UNKNOWN: + default: + hasUniqueContent = false; + break; + } + mDisplayManagerService.setDisplayHasContent(displayId, hasUniqueContent, + true /* inTraversal, must call performTraversalInTrans... below */); + if (!mInnerFields.mDimming && mAnimator.isDimmingLocked(displayId)) { stopDimmingLocked(displayId); } @@ -9169,6 +9142,11 @@ public class WindowManagerService extends IWindowManager.Stub if (focusDisplayed) { mH.sendEmptyMessage(H.REPORT_LOSING_FOCUS); } + + // Give the display manager a chance to adjust properties + // like display rotation if it needs to. + mDisplayManagerService.performTraversalInTransactionFromWindowManager(); + } catch (RuntimeException e) { Log.wtf(TAG, "Unhandled exception in Window Manager", e); } finally { @@ -9255,7 +9233,9 @@ public class WindowManagerService extends IWindowManager.Stub "Reporting new frame to " + win + ": " + win.mCompatFrame); int diff = 0; boolean configChanged = win.isConfigChanged(); - if ((DEBUG_RESIZE || DEBUG_ORIENTATION || DEBUG_CONFIGURATION) + if ((DEBUG_RESIZE || DEBUG_ORIENTATION || DEBUG_CONFIGURATION + // TODO: Remove once b/7094175 is fixed + || ((String)win.mAttrs.getTitle()).contains("Keyguard")) && configChanged) { Slog.i(TAG, "Sending new config to window " + win + ": " + winAnimator.mSurfaceW + "x" + winAnimator.mSurfaceH @@ -9377,6 +9357,8 @@ public class WindowManagerService extends IWindowManager.Stub mPowerManager.setButtonBrightnessOverrideFromWindowManager( toBrightnessOverride(mInnerFields.mButtonBrightness)); } + mPowerManager.setUserActivityTimeoutOverrideFromWindowManager( + mInnerFields.mUserActivityTimeout); } if (mTurnOnScreen) { |
