summaryrefslogtreecommitdiffstats
path: root/services
diff options
context:
space:
mode:
authorThe Android Open Source Project <initial-contribution@android.com>2008-12-17 18:05:43 -0800
committerThe Android Open Source Project <initial-contribution@android.com>2008-12-17 18:05:43 -0800
commitf013e1afd1e68af5e3b868c26a653bbfb39538f8 (patch)
tree7ad6c8fd9c7b55f4b4017171dec1cb760bbd26bf /services
parente70cfafe580c6f2994c4827cd8a534aabf3eb05c (diff)
downloadframeworks_base-f013e1afd1e68af5e3b868c26a653bbfb39538f8.zip
frameworks_base-f013e1afd1e68af5e3b868c26a653bbfb39538f8.tar.gz
frameworks_base-f013e1afd1e68af5e3b868c26a653bbfb39538f8.tar.bz2
Code drop from //branches/cupcake/...@124589
Diffstat (limited to 'services')
-rw-r--r--services/java/com/android/server/AlarmManagerService.java107
-rw-r--r--services/java/com/android/server/BatteryService.java29
-rw-r--r--services/java/com/android/server/ConnectivityService.java99
-rw-r--r--services/java/com/android/server/DeviceStorageMonitorService.java294
-rw-r--r--services/java/com/android/server/HeadsetObserver.java2
-rw-r--r--services/java/com/android/server/InputDevice.java29
-rw-r--r--services/java/com/android/server/InputMethodManagerService.java1305
-rw-r--r--services/java/com/android/server/KeyInputQueue.java3
-rw-r--r--services/java/com/android/server/LocationManagerService.java401
-rw-r--r--services/java/com/android/server/MountService.java28
-rw-r--r--services/java/com/android/server/NotificationManagerService.java2
-rw-r--r--services/java/com/android/server/PackageManagerService.java1294
-rw-r--r--services/java/com/android/server/PowerManagerService.java78
-rw-r--r--services/java/com/android/server/SensorService.java125
-rw-r--r--services/java/com/android/server/SystemServer.java104
-rw-r--r--services/java/com/android/server/TelephonyRegistry.java28
-rw-r--r--services/java/com/android/server/Watchdog.java10
-rw-r--r--services/java/com/android/server/WifiService.java220
-rw-r--r--services/java/com/android/server/WifiWatchdogService.java121
-rw-r--r--services/java/com/android/server/WindowManagerService.java1285
-rw-r--r--services/java/com/android/server/am/ActivityManagerService.java224
-rw-r--r--services/java/com/android/server/am/AppErrorDialog.java2
-rw-r--r--services/java/com/android/server/am/AppNotRespondingDialog.java2
-rw-r--r--services/java/com/android/server/am/BatteryStats.java1146
-rw-r--r--services/java/com/android/server/am/BatteryStatsService.java130
-rw-r--r--services/java/com/android/server/am/ProcessRecord.java41
-rw-r--r--services/java/com/android/server/am/ServiceRecord.java6
-rw-r--r--services/java/com/android/server/status/DateView.java2
-rw-r--r--services/java/com/android/server/status/StatusBarIcon.java4
-rw-r--r--services/java/com/android/server/status/StatusBarPolicy.java54
-rw-r--r--services/java/com/android/server/status/StatusBarService.java93
31 files changed, 4943 insertions, 2325 deletions
diff --git a/services/java/com/android/server/AlarmManagerService.java b/services/java/com/android/server/AlarmManagerService.java
index 968467b..1625853 100644
--- a/services/java/com/android/server/AlarmManagerService.java
+++ b/services/java/com/android/server/AlarmManagerService.java
@@ -73,6 +73,17 @@ class AlarmManagerService extends IAlarmManager.Stub {
private final ArrayList<Alarm> mElapsedRealtimeWakeupAlarms = new ArrayList<Alarm>();
private final ArrayList<Alarm> mElapsedRealtimeAlarms = new ArrayList<Alarm>();
+ // slots corresponding with the inexact-repeat interval buckets,
+ // ordered from shortest to longest
+ private static final long sInexactSlotIntervals[] = {
+ AlarmManager.INTERVAL_FIFTEEN_MINUTES,
+ AlarmManager.INTERVAL_HALF_HOUR,
+ AlarmManager.INTERVAL_HOUR,
+ AlarmManager.INTERVAL_HALF_DAY,
+ AlarmManager.INTERVAL_DAY
+ };
+ private long mInexactDeliveryTimes[] = { 0, 0, 0, 0, 0};
+
private int mDescriptor;
private int mBroadcastRefCount = 0;
private PowerManager.WakeLock mWakeLock;
@@ -162,6 +173,67 @@ class AlarmManagerService extends IAlarmManager.Stub {
}
}
+ public void setInexactRepeating(int type, long triggerAtTime, long interval,
+ PendingIntent operation) {
+ if (operation == null) {
+ Log.w(TAG, "setInexactRepeating ignored because there is no intent");
+ return;
+ }
+
+ // find the slot in the delivery-times array that we will use
+ int intervalSlot;
+ for (intervalSlot = 0; intervalSlot < sInexactSlotIntervals.length; intervalSlot++) {
+ if (sInexactSlotIntervals[intervalSlot] == interval) {
+ break;
+ }
+ }
+
+ // Non-bucket intervals just fall back to the less-efficient
+ // unbucketed recurring alarm implementation
+ if (intervalSlot >= sInexactSlotIntervals.length) {
+ setRepeating(type, triggerAtTime, interval, operation);
+ return;
+ }
+
+ // Align bucketed alarm deliveries by trying to match
+ // the shortest-interval bucket already scheduled
+ long bucketTime = 0;
+ for (int slot = 0; slot < mInexactDeliveryTimes.length; slot++) {
+ if (mInexactDeliveryTimes[slot] > 0) {
+ bucketTime = mInexactDeliveryTimes[slot];
+ break;
+ }
+ }
+
+ if (bucketTime == 0) {
+ // If nothing is scheduled yet, just start at the requested time
+ bucketTime = triggerAtTime;
+ } else {
+ // Align the new alarm with the existing bucketed sequence. To achieve
+ // alignment, we slide the start time around by min{interval, slot interval}
+ long adjustment = (interval <= sInexactSlotIntervals[intervalSlot])
+ ? interval : sInexactSlotIntervals[intervalSlot];
+
+ // The bucket may have started in the past; adjust
+ while (bucketTime < triggerAtTime) {
+ bucketTime += adjustment;
+ }
+
+ // Or the bucket may be set to start more than an interval beyond
+ // our requested trigger time; pull it back to meet our needs
+ while (bucketTime > triggerAtTime + adjustment) {
+ bucketTime -= adjustment;
+ }
+ }
+
+ // Remember where this bucket started (reducing the amount of later
+ // fixup required) and set the alarm with the new, bucketed start time.
+ if (localLOGV) Log.v(TAG, "setInexactRepeating: interval=" + interval
+ + " bucketTime=" + bucketTime);
+ mInexactDeliveryTimes[intervalSlot] = bucketTime;
+ setRepeating(type, bucketTime, interval, operation);
+ }
+
public void setTimeZone(String tz) {
mContext.enforceCallingOrSelfPermission(
"android.permission.SET_TIME_ZONE",
@@ -171,15 +243,28 @@ class AlarmManagerService extends IAlarmManager.Stub {
TimeZone zone = TimeZone.getTimeZone(tz);
// Prevent reentrant calls from stepping on each other when writing
// the time zone property
+ boolean timeZoneWasChanged = false;
synchronized (this) {
- SystemProperties.set(TIMEZONE_PROPERTY, zone.getID());
+ String current = SystemProperties.get(TIMEZONE_PROPERTY);
+ if (current == null || !current.equals(zone.getID())) {
+ if (localLOGV) Log.v(TAG, "timezone changed: " + current + ", new=" + zone.getID());
+ timeZoneWasChanged = true;
+ SystemProperties.set(TIMEZONE_PROPERTY, zone.getID());
+
+ // Update the kernel timezone information
+ // Kernel tracks time offsets as 'minutes west of GMT'
+ int gmtOffset = (zone.getRawOffset() + zone.getDSTSavings()) / 60000;
+ setKernelTimezone(mDescriptor, -(gmtOffset));
+ }
}
-
+
TimeZone.setDefault(null);
- Intent intent = new Intent(Intent.ACTION_TIMEZONE_CHANGED);
- intent.putExtra("time-zone", zone.getID());
- mContext.sendBroadcast(intent);
+ if (timeZoneWasChanged) {
+ Intent intent = new Intent(Intent.ACTION_TIMEZONE_CHANGED);
+ intent.putExtra("time-zone", zone.getID());
+ mContext.sendBroadcast(intent);
+ }
}
public void remove(PendingIntent operation) {
@@ -359,7 +444,8 @@ class AlarmManagerService extends IAlarmManager.Stub {
private native void close(int fd);
private native void set(int fd, int type, long nanoseconds);
private native int waitForAlarm(int fd);
-
+ private native int setKernelTimezone(int fd, int minuteswest);
+
private void triggerAlarmsLocked(ArrayList<Alarm> alarmList,
ArrayList<Alarm> triggerList,
long now)
@@ -581,6 +667,7 @@ class AlarmManagerService extends IAlarmManager.Stub {
public ClockReceiver() {
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_TIME_TICK);
+ filter.addAction(Intent.ACTION_DATE_CHANGED);
mContext.registerReceiver(this, filter);
}
@@ -589,6 +676,14 @@ class AlarmManagerService extends IAlarmManager.Stub {
if (intent.getAction().equals(Intent.ACTION_TIME_TICK)) {
scheduleTimeTickEvent();
} else if (intent.getAction().equals(Intent.ACTION_DATE_CHANGED)) {
+ // Since the kernel does not keep track of DST, we need to
+ // reset the TZ information at the beginning of each day
+ // based off of the current Zone gmt offset + userspace tracked
+ // daylight savings information.
+ TimeZone zone = TimeZone.getTimeZone(SystemProperties.get(TIMEZONE_PROPERTY));
+ int gmtOffset = (zone.getRawOffset() + zone.getDSTSavings()) / 60000;
+
+ setKernelTimezone(mDescriptor, -(gmtOffset));
scheduleDateChangedEvent();
}
}
diff --git a/services/java/com/android/server/BatteryService.java b/services/java/com/android/server/BatteryService.java
index 608299c..dba8fca 100644
--- a/services/java/com/android/server/BatteryService.java
+++ b/services/java/com/android/server/BatteryService.java
@@ -17,7 +17,7 @@
package com.android.server;
import com.android.internal.app.IBatteryStats;
-import com.android.server.am.BatteryStats;
+import com.android.server.am.BatteryStatsService;
import android.app.ActivityManagerNative;
import android.content.Context;
@@ -27,7 +27,6 @@ import android.os.BatteryManager;
import android.os.Binder;
import android.os.RemoteException;
import android.os.UEventObserver;
-import android.util.Config;
import android.util.EventLog;
import android.util.Log;
@@ -90,9 +89,9 @@ class BatteryService extends Binder {
public BatteryService(Context context) {
mContext = context;
- mBatteryStats = BatteryStats.getService();
+ mBatteryStats = BatteryStatsService.getService();
- mUEventObserver.startObserving("DEVPATH=/class/power_supply");
+ mUEventObserver.startObserving("SUBSYSTEM=power_supply");
// set initial status
update();
@@ -103,6 +102,28 @@ class BatteryService extends Binder {
return (mAcOnline || mUsbOnline || mBatteryStatus == BatteryManager.BATTERY_STATUS_UNKNOWN);
}
+ final boolean isPowered(int plugTypeSet) {
+ // assume we are powered if battery state is unknown so
+ // the "stay on while plugged in" option will work.
+ if (mBatteryStatus == BatteryManager.BATTERY_STATUS_UNKNOWN) {
+ return true;
+ }
+ if (plugTypeSet == 0) {
+ return false;
+ }
+ int plugTypeBit = 0;
+ if (mAcOnline) {
+ plugTypeBit = BatteryManager.BATTERY_PLUGGED_AC;
+ } else if (mUsbOnline) {
+ plugTypeBit = BatteryManager.BATTERY_PLUGGED_USB;
+ }
+ return (plugTypeSet & plugTypeBit) != 0;
+ }
+
+ final int getPlugType() {
+ return mPlugType;
+ }
+
private UEventObserver mUEventObserver = new UEventObserver() {
@Override
public void onUEvent(UEventObserver.UEvent event) {
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index 11f34cc..65e3650 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -35,7 +35,6 @@ import android.os.Message;
import android.os.ServiceManager;
import android.os.SystemProperties;
import android.provider.Settings;
-import android.telephony.TelephonyManager;
import android.util.EventLog;
import android.util.Log;
@@ -43,7 +42,7 @@ import java.io.FileDescriptor;
import java.io.PrintWriter;
/**
- * {@hide}
+ * @hide
*/
public class ConnectivityService extends IConnectivityManager.Stub {
@@ -59,7 +58,6 @@ public class ConnectivityService extends IConnectivityManager.Stub {
* abstractly.
*/
private NetworkStateTracker mNetTrackers[];
- private boolean mTeardownRequested[];
private WifiStateTracker mWifiStateTracker;
private MobileDataStateTracker mMobileDataStateTracker;
private WifiWatchdogService mWifiWatchdogService;
@@ -69,11 +67,11 @@ public class ConnectivityService extends IConnectivityManager.Stub {
private NetworkStateTracker mActiveNetwork;
private int mNumDnsEntries;
- private static int mDnsChangeCounter;
+ private static int sDnsChangeCounter;
private boolean mTestMode;
private static ConnectivityService sServiceInstance;
-
+
private static class ConnectivityThread extends Thread {
private Context mContext;
@@ -101,7 +99,9 @@ public class ConnectivityService extends IConnectivityManager.Stub {
try {
// Wait until sServiceInstance has been initialized.
thread.wait();
- } catch (InterruptedException e) {
+ } catch (InterruptedException ignore) {
+ Log.e(TAG,
+ "Unexpected InterruptedException while waiting for ConnectivityService thread");
}
}
}
@@ -118,7 +118,6 @@ public class ConnectivityService extends IConnectivityManager.Stub {
if (DBG) Log.v(TAG, "ConnectivityService starting up");
mContext = context;
mNetTrackers = new NetworkStateTracker[2];
- mTeardownRequested = new boolean[2];
Handler handler = new MyHandler();
mNetworkPreference = getPersistedNetworkPreference();
@@ -134,7 +133,6 @@ public class ConnectivityService extends IConnectivityManager.Stub {
mWifiStateTracker = new WifiStateTracker(context, handler);
WifiService wifiService = new WifiService(context, mWifiStateTracker);
ServiceManager.addService(Context.WIFI_SERVICE, wifiService);
- // The WifiStateTracker should appear first in the list
mNetTrackers[ConnectivityManager.TYPE_WIFI] = mWifiStateTracker;
mMobileDataStateTracker = new MobileDataStateTracker(context, handler);
@@ -160,10 +158,11 @@ public class ConnectivityService extends IConnectivityManager.Stub {
public synchronized void setNetworkPreference(int preference) {
enforceChangePermission();
if (ConnectivityManager.isNetworkTypeValid(preference)) {
- int oldPreference = mNetworkPreference;
- persistNetworkPreference(preference);
- if (mNetworkPreference != oldPreference)
+ if (mNetworkPreference != preference) {
+ persistNetworkPreference(preference);
+ mNetworkPreference = preference;
enforcePreference();
+ }
}
}
@@ -174,14 +173,14 @@ public class ConnectivityService extends IConnectivityManager.Stub {
private void persistNetworkPreference(int networkPreference) {
final ContentResolver cr = mContext.getContentResolver();
- Settings.System.putInt(cr, Settings.System.NETWORK_PREFERENCE, networkPreference);
+ Settings.Secure.putInt(cr, Settings.Secure.NETWORK_PREFERENCE, networkPreference);
}
private int getPersistedNetworkPreference() {
final ContentResolver cr = mContext.getContentResolver();
- final int networkPrefSetting = Settings.System
- .getInt(cr, Settings.System.NETWORK_PREFERENCE, -1);
+ final int networkPrefSetting = Settings.Secure
+ .getInt(cr, Settings.Secure.NETWORK_PREFERENCE, -1);
if (networkPrefSetting != -1) {
return networkPrefSetting;
}
@@ -219,7 +218,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
private boolean teardown(NetworkStateTracker netTracker) {
if (netTracker.teardown()) {
- mTeardownRequested[netTracker.getNetworkInfo().getType()] = true;
+ netTracker.setTeardownRequested(true);
return true;
} else {
return false;
@@ -227,9 +226,9 @@ public class ConnectivityService extends IConnectivityManager.Stub {
}
/**
- * Return NetworkInfo for the active network interface. It is assumed that at most
- * one network is active at a time. If more than one is active, it is indeterminate
- * which will be returned.
+ * Return NetworkInfo for the active (i.e., connected) network interface.
+ * It is assumed that at most one network is active at a time. If more
+ * than one is active, it is indeterminate which will be returned.
* @return the info for the active network, or {@code null} if none is active
*/
public NetworkInfo getActiveNetworkInfo() {
@@ -291,7 +290,6 @@ public class ConnectivityService extends IConnectivityManager.Stub {
return tracker.startUsingNetworkFeature(feature, getCallingPid(), getCallingUid());
}
return -1;
-
}
public int stopUsingNetworkFeature(int networkType, String feature) {
@@ -339,8 +337,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
int numConnectedNets = 0;
for (NetworkStateTracker nt : mNetTrackers) {
- if (nt.getNetworkInfo().isConnected()
- && !mTeardownRequested[nt.getNetworkInfo().getType()]) {
+ if (nt.getNetworkInfo().isConnected() && !nt.isTeardownRequested()) {
++numConnectedNets;
}
}
@@ -369,13 +366,13 @@ public class ConnectivityService extends IConnectivityManager.Stub {
if (DBG) Log.v(TAG, "Handle DISCONNECT for " + info.getTypeName());
+ mNetTrackers[info.getType()].setTeardownRequested(false);
/*
* If the disconnected network is not the active one, then don't report
* this as a loss of connectivity. What probably happened is that we're
* getting the disconnect for a network that we explicitly disabled
* in accordance with network preference policies.
*/
- mTeardownRequested[info.getType()] = false;
if (mActiveNetwork == null || info.getType() != mActiveNetwork.getNetworkInfo().getType())
return;
@@ -386,13 +383,23 @@ public class ConnectivityService extends IConnectivityManager.Stub {
newNet = mMobileDataStateTracker;
}
+ /**
+ * See if the other network is available to fail over to.
+ * If is not available, we enable it anyway, so that it
+ * will be able to connect when it does become available,
+ * but we report a total loss of connectivity rather than
+ * report that we are attempting to fail over.
+ */
NetworkInfo switchTo = null;
if (newNet.isAvailable()) {
mActiveNetwork = newNet;
switchTo = newNet.getNetworkInfo();
switchTo.setFailover(true);
- if (!switchTo.isConnectedOrConnecting())
+ if (!switchTo.isConnectedOrConnecting()) {
newNet.reconnect();
+ }
+ } else {
+ newNet.reconnect();
}
boolean otherNetworkConnected = false;
@@ -449,8 +456,12 @@ public class ConnectivityService extends IConnectivityManager.Stub {
mContext.sendStickyBroadcast(intent);
}
+ /**
+ * Called when an attempt to fail over to another network has failed.
+ * @param info the {@link NetworkInfo} for the failed network
+ */
private void handleConnectionFailure(NetworkInfo info) {
- mTeardownRequested[info.getType()] = false;
+ mNetTrackers[info.getType()].setTeardownRequested(false);
if (getActiveNetworkInfo() == null) {
String reason = info.getReason();
String extraInfo = info.getExtraInfo();
@@ -496,10 +507,9 @@ public class ConnectivityService extends IConnectivityManager.Stub {
otherNet = mMobileDataStateTracker;
}
/*
- * Check policy to see whether we are now connected to a network that
- * takes precedence over the other one. If so, we need to tear down
- * the other one.
- */
+ * Check policy to see whether we are connected to a non-preferred
+ * network that now needs to be torn down.
+ */
NetworkInfo wifiInfo = mWifiStateTracker.getNetworkInfo();
NetworkInfo mobileInfo = mMobileDataStateTracker.getNetworkInfo();
if (wifiInfo.isConnected() && mobileInfo.isConnected()) {
@@ -510,7 +520,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
}
boolean toredown = false;
- mTeardownRequested[info.getType()] = false;
+ thisNet.setTeardownRequested(false);
if (!mTestMode && deadnet != null) {
if (DBG) Log.v(TAG, "Policy requires " +
deadnet.getNetworkInfo().getTypeName() + " teardown");
@@ -520,6 +530,10 @@ public class ConnectivityService extends IConnectivityManager.Stub {
}
}
+ /*
+ * Note that if toredown is true, deadnet cannot be null, so there is
+ * no danger of a null pointer exception here..
+ */
if (!toredown || deadnet.getNetworkInfo().getType() != info.getType()) {
mActiveNetwork = thisNet;
if (DBG) Log.v(TAG, "Sending CONNECT bcast for " + info.getTypeName());
@@ -592,10 +606,9 @@ public class ConnectivityService extends IConnectivityManager.Stub {
int incrValue = ConnectivityManager.TYPE_MOBILE - ConnectivityManager.TYPE_WIFI;
int stopValue = ConnectivityManager.TYPE_MOBILE + incrValue;
- for (int net = ConnectivityManager.TYPE_WIFI; net != stopValue; net += incrValue) {
- NetworkStateTracker nt = mNetTrackers[net];
- if (nt.getNetworkInfo().isConnected()
- && !mTeardownRequested[nt.getNetworkInfo().getType()]) {
+ for (int netType = ConnectivityManager.TYPE_WIFI; netType != stopValue; netType += incrValue) {
+ NetworkStateTracker nt = mNetTrackers[netType];
+ if (nt.getNetworkInfo().isConnected() && !nt.isTeardownRequested()) {
++numConnectedNets;
String[] dnsList = nt.getNameServers();
for (int i = 0; i < dnsList.length && dnsList[i] != null; i++) {
@@ -613,7 +626,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
}
mNumDnsEntries = index - 1;
// Notify the name resolver library of the change
- SystemProperties.set("net.dnschange", String.valueOf(mDnsChangeCounter++));
+ SystemProperties.set("net.dnschange", String.valueOf(sDnsChangeCounter++));
return numConnectedNets;
}
@@ -650,13 +663,13 @@ public class ConnectivityService extends IConnectivityManager.Stub {
info.getState() + "/" + info.getDetailedState());
// Connectivity state changed:
- // [31-11] Reserved for future use
- // [10-9] Mobile network connection type (as defined by the TelephonyManager)
- // [8-3] Detailed state ordinal (as defined by NetworkInfo.DetailedState)
+ // [31-13] Reserved for future use
+ // [12-9] Network subtype (for mobile network, as defined by TelephonyManager)
+ // [8-3] Detailed state ordinal (as defined by NetworkInfo.DetailedState)
// [2-0] Network type (as defined by ConnectivityManager)
int eventLogParam = (info.getType() & 0x7) |
- ((info.getDetailedState().ordinal() & 0x3f) << 3) |
- (TelephonyManager.getDefault().getNetworkType() << 9);
+ ((info.getDetailedState().ordinal() & 0x3f) << 3) |
+ (info.getSubtype() << 9);
EventLog.writeEvent(EVENTLOG_CONNECTIVITY_STATE_CHANGED, eventLogParam);
if (info.getDetailedState() == NetworkInfo.DetailedState.FAILED) {
@@ -687,6 +700,14 @@ public class ConnectivityService extends IConnectivityManager.Stub {
case NetworkStateTracker.EVENT_CONFIGURATION_CHANGED:
handleConfigurationChange();
break;
+
+ case NetworkStateTracker.EVENT_ROAMING_CHANGED:
+ // fill me in
+ break;
+
+ case NetworkStateTracker.EVENT_NETWORK_SUBTYPE_CHANGED:
+ // fill me in
+ break;
}
}
}
diff --git a/services/java/com/android/server/DeviceStorageMonitorService.java b/services/java/com/android/server/DeviceStorageMonitorService.java
new file mode 100644
index 0000000..04b1900
--- /dev/null
+++ b/services/java/com/android/server/DeviceStorageMonitorService.java
@@ -0,0 +1,294 @@
+/*
+ * Copyright (C) 2007-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 com.android.server.am.ActivityManagerService;
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.IPackageDataObserver;
+import android.content.pm.IPackageManager;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.Message;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.StatFs;
+import android.os.SystemClock;
+import android.os.SystemProperties;
+import android.provider.Settings.Gservices;
+import android.util.Config;
+import android.util.EventLog;
+import android.util.Log;
+import android.provider.Settings;
+
+/**
+ * This class implements a service to monitor the amount of disk storage space
+ * on the device. If the free storage on device is less than a tunable threshold value
+ * (default is 10%. this value is a gservices parameter) a low memory notification is
+ * displayed to alert the user. If the user clicks on the low memory notification the
+ * Application Manager application gets launched to let the user free storage space.
+ * Event log events:
+ * A low memory event with the free storage on device in bytes is logged to the event log
+ * when the device goes low on storage space.
+ * The amount of free storage on the device is periodically logged to the event log. The log
+ * interval is a gservices parameter with a default value of 12 hours
+ * When the free storage differential goes below a threshold(again a gservices parameter with
+ * a default value of 2MB), the free memory is logged to the event log
+ */
+class DeviceStorageMonitorService extends Binder {
+ private static final String TAG = "DeviceStorageMonitorService";
+ private static final boolean DEBUG = false;
+ private static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV;
+ private static final int DEVICE_MEMORY_WHAT = 1;
+ private static final int MONITOR_INTERVAL = 1; //in minutes
+ private static final int LOW_MEMORY_NOTIFICATION_ID = 1;
+ private static final int DEFAULT_THRESHOLD_PERCENTAGE = 10;
+ private static final int DEFAULT_FREE_STORAGE_LOG_INTERVAL_IN_MINUTES = 12*60; //in minutes
+ private static final int EVENT_LOG_STORAGE_BELOW_THRESHOLD = 2744;
+ private static final int EVENT_LOG_LOW_STORAGE_NOTIFICATION = 2745;
+ private static final int EVENT_LOG_FREE_STORAGE_LEFT = 2746;
+ private static final long DEFAULT_DISK_FREE_CHANGE_REPORTING_THRESHOLD = 2 * 1024 * 1024; // 2MB
+ private long mFreeMem;
+ private long mLastReportedFreeMem;
+ private long mLastReportedFreeMemTime;
+ private boolean mLowMemFlag=false;
+ private Context mContext;
+ private ContentResolver mContentResolver;
+ int mBlkSize;
+ long mTotalMemory;
+ StatFs mFileStats;
+ private static final String DATA_PATH="/data";
+ long mThreadStartTime = -1;
+ boolean mClearSucceeded = false;
+ boolean mClearingCache;
+ private Intent mStorageLowIntent;
+ private Intent mStorageOkIntent;
+
+ /**
+ * This string is used for ServiceManager access to this class.
+ */
+ static final String SERVICE = "devicestoragemonitor";
+
+ /**
+ * Handler that checks the amount of disk space on the device and sends a
+ * notification if the device runs low on disk space
+ */
+ Handler mHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ //dont handle an invalid message
+ if (msg.what != DEVICE_MEMORY_WHAT) {
+ Log.e(TAG, "Will not process invalid message");
+ return;
+ }
+ checkMemory();
+ }
+ };
+
+ class CachePackageDataObserver extends IPackageDataObserver.Stub {
+ public void onRemoveCompleted(String packageName, boolean succeeded) {
+ mClearSucceeded = succeeded;
+ mClearingCache = false;
+ if(localLOGV) Log.i(TAG, " Clear succeeded:"+mClearSucceeded
+ +", mClearingCache:"+mClearingCache);
+ }
+ }
+
+ private final void restatDataDir() {
+ mFileStats.restat(DATA_PATH);
+ mFreeMem = mFileStats.getAvailableBlocks()*mBlkSize;
+ // Allow freemem to be overridden by debug.freemem for testing
+ String debugFreeMem = SystemProperties.get("debug.freemem");
+ if (!"".equals(debugFreeMem)) {
+ mFreeMem = Long.parseLong(debugFreeMem);
+ }
+ // Read the log interval from Gservices
+ long freeMemLogInterval = Gservices.getLong(mContentResolver,
+ Gservices.SYS_FREE_STORAGE_LOG_INTERVAL,
+ DEFAULT_FREE_STORAGE_LOG_INTERVAL_IN_MINUTES)*60*1000;
+ //log the amount of free memory in event log
+ long currTime = SystemClock.elapsedRealtime();
+ if((mLastReportedFreeMemTime == 0) ||
+ (currTime-mLastReportedFreeMemTime) >= freeMemLogInterval) {
+ mLastReportedFreeMemTime = currTime;
+ EventLog.writeEvent(EVENT_LOG_FREE_STORAGE_LEFT, mFreeMem);
+ }
+ // Read the reporting threshold from Gservices
+ long threshold = Gservices.getLong(mContentResolver,
+ Gservices.DISK_FREE_CHANGE_REPORTING_THRESHOLD,
+ DEFAULT_DISK_FREE_CHANGE_REPORTING_THRESHOLD);
+ // If mFree changed significantly log the new value
+ long delta = mFreeMem - mLastReportedFreeMem;
+ if (delta > threshold || delta < -threshold) {
+ mLastReportedFreeMem = mFreeMem;
+ EventLog.writeEvent(EVENT_LOG_STORAGE_BELOW_THRESHOLD, mFreeMem);
+ }
+ }
+
+ private final void clearCache() {
+ CachePackageDataObserver observer = new CachePackageDataObserver();
+ mClearingCache = true;
+ try {
+ IPackageManager.Stub.asInterface(ServiceManager.getService("package")).
+ freeApplicationCache(getMemThreshold(), observer);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed to get handle for PackageManger Exception: "+e);
+ mClearingCache = false;
+ mClearSucceeded = false;
+ }
+ }
+
+ private final void checkMemory() {
+ //if the thread that was started to clear cache is still running do nothing till its
+ //finished clearing cache. Ideally this flag could be modified by clearCache
+ // and should be accessed via a lock but even if it does this test will fail now and
+ //hopefully the next time this flag will be set to the correct value.
+ if(mClearingCache) {
+ if(localLOGV) Log.i(TAG, "Thread already running just skip");
+ //make sure the thread is not hung for too long
+ long diffTime = System.currentTimeMillis() - mThreadStartTime;
+ if(diffTime > (10*60*1000)) {
+ Log.w(TAG, "Thread that clears cache file seems to run for ever");
+ }
+ } else {
+ restatDataDir();
+ if (localLOGV) Log.v(TAG, "freeMemory="+mFreeMem);
+ //post intent to NotificationManager to display icon if necessary
+ long memThreshold = getMemThreshold();
+ if (mFreeMem < memThreshold) {
+ if (!mLowMemFlag) {
+ //see if clearing cache helps
+ mThreadStartTime = System.currentTimeMillis();
+ clearCache();
+ Log.i(TAG, "Running low on memory. Sending notification");
+ sendNotification();
+ mLowMemFlag = true;
+ } else {
+ if (localLOGV) Log.v(TAG, "Running low on memory " +
+ "notification already sent. do nothing");
+ }
+ } else {
+ if (mLowMemFlag) {
+ Log.i(TAG, "Memory available. Cancelling notification");
+ cancelNotification();
+ mLowMemFlag = false;
+ }
+ }
+ }
+ if(localLOGV) Log.i(TAG, "Posting Message again");
+ //keep posting messages to itself periodically
+ mHandler.sendMessageDelayed(mHandler.obtainMessage(DEVICE_MEMORY_WHAT),
+ MONITOR_INTERVAL*60*1000);
+ }
+
+ /*
+ * just query settings to retrieve the memory threshold.
+ * Preferred this over using a ContentObserver since Settings.Gservices caches the value
+ * any way
+ */
+ private long getMemThreshold() {
+ int value = Settings.Gservices.getInt(
+ mContentResolver,
+ Settings.Gservices.SYS_STORAGE_THRESHOLD_PERCENTAGE,
+ DEFAULT_THRESHOLD_PERCENTAGE);
+ if(localLOGV) Log.v(TAG, "Threshold Percentage="+value);
+ //evaluate threshold value
+ return mTotalMemory*value;
+ }
+
+ /**
+ * Constructor to run service. initializes the disk space threshold value
+ * and posts an empty message to kickstart the process.
+ */
+ public DeviceStorageMonitorService(Context context) {
+ mLastReportedFreeMemTime = 0;
+ mContext = context;
+ mContentResolver = mContext.getContentResolver();
+ //create StatFs object
+ mFileStats = new StatFs(DATA_PATH);
+ //initialize block size
+ mBlkSize = mFileStats.getBlockSize();
+ //initialize total storage on device
+ mTotalMemory = (mFileStats.getBlockCount()*mBlkSize)/100;
+ mStorageLowIntent = new Intent(Intent.ACTION_DEVICE_STORAGE_LOW);
+ mStorageOkIntent = new Intent(Intent.ACTION_DEVICE_STORAGE_OK);
+ checkMemory();
+ }
+
+
+ /**
+ * This method sends a notification to NotificationManager to display
+ * an error dialog indicating low disk space and launch the Installer
+ * application
+ */
+ private final void sendNotification() {
+ if(localLOGV) Log.i(TAG, "Sending low memory notification");
+ //log the event to event log with the amount of free storage(in bytes) left on the device
+ EventLog.writeEvent(EVENT_LOG_LOW_STORAGE_NOTIFICATION, mFreeMem);
+ // Pack up the values and broadcast them to everyone
+ Intent lowMemIntent = new Intent(Intent.ACTION_MANAGE_PACKAGE_STORAGE);
+ lowMemIntent.putExtra("memory", mFreeMem);
+ lowMemIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ NotificationManager mNotificationMgr =
+ (NotificationManager)mContext.getSystemService(
+ Context.NOTIFICATION_SERVICE);
+ CharSequence title = mContext.getText(
+ com.android.internal.R.string.low_internal_storage_view_title);
+ CharSequence details = mContext.getText(
+ com.android.internal.R.string.low_internal_storage_view_text);
+ PendingIntent intent = PendingIntent.getActivity(mContext, 0, lowMemIntent, 0);
+ Notification notification = new Notification();
+ notification.icon = com.android.internal.R.drawable.stat_notify_disk_full;
+ notification.tickerText = title;
+ notification.flags |= Notification.FLAG_NO_CLEAR;
+ notification.setLatestEventInfo(mContext, title, details, intent);
+ mNotificationMgr.notify(LOW_MEMORY_NOTIFICATION_ID, notification);
+ mContext.sendStickyBroadcast(mStorageLowIntent);
+ }
+
+ /**
+ * Cancels low storage notification and sends OK intent.
+ */
+ private final void cancelNotification() {
+ if(localLOGV) Log.i(TAG, "Canceling low memory notification");
+ NotificationManager mNotificationMgr =
+ (NotificationManager)mContext.getSystemService(
+ Context.NOTIFICATION_SERVICE);
+ //cancel notification since memory has been freed
+ mNotificationMgr.cancel(LOW_MEMORY_NOTIFICATION_ID);
+
+ mContext.removeStickyBroadcast(mStorageLowIntent);
+ mContext.sendBroadcast(mStorageOkIntent);
+ }
+
+ public void updateMemory() {
+ ActivityManagerService ams = (ActivityManagerService)ServiceManager.getService("activity");
+ int callingUid = getCallingUid();
+ if(callingUid != Process.SYSTEM_UID) {
+ return;
+ }
+ //remove queued messages
+ mHandler.removeMessages(DEVICE_MEMORY_WHAT);
+ //force an early check
+ checkMemory();
+ }
+}
diff --git a/services/java/com/android/server/HeadsetObserver.java b/services/java/com/android/server/HeadsetObserver.java
index 9f7701d..cb681e0 100644
--- a/services/java/com/android/server/HeadsetObserver.java
+++ b/services/java/com/android/server/HeadsetObserver.java
@@ -32,7 +32,7 @@ import java.io.FileNotFoundException;
class HeadsetObserver extends UEventObserver {
private static final String TAG = HeadsetObserver.class.getSimpleName();
- private static final String HEADSET_UEVENT_MATCH = "DEVPATH=/class/switch/h2w";
+ private static final String HEADSET_UEVENT_MATCH = "DEVPATH=/devices/virtual/switch/h2w";
private static final String HEADSET_STATE_PATH = "/sys/class/switch/h2w/state";
private static final String HEADSET_NAME_PATH = "/sys/class/switch/h2w/name";
diff --git a/services/java/com/android/server/InputDevice.java b/services/java/com/android/server/InputDevice.java
index 70bf38e..7b8a2a4 100644
--- a/services/java/com/android/server/InputDevice.java
+++ b/services/java/com/android/server/InputDevice.java
@@ -75,6 +75,7 @@ public class InputDevice {
float temp;
float scaledPressure = 1.0f;
float scaledSize = 0;
+ int edgeFlags = 0;
if (isAbs) {
int w = display.getWidth()-1;
int h = display.getHeight()-1;
@@ -118,6 +119,19 @@ public class InputDevice {
scaledY = temp;
break;
}
+
+ if (scaledX == 0) {
+ edgeFlags += MotionEvent.EDGE_LEFT;
+ } else if (scaledX == display.getWidth() - 1.0f) {
+ edgeFlags += MotionEvent.EDGE_RIGHT;
+ }
+
+ if (scaledY == 0) {
+ edgeFlags += MotionEvent.EDGE_TOP;
+ } else if (scaledY == display.getHeight() - 1.0f) {
+ edgeFlags += MotionEvent.EDGE_BOTTOM;
+ }
+
} else {
scaledX *= xMoveScale;
scaledY *= yMoveScale;
@@ -138,19 +152,6 @@ public class InputDevice {
break;
}
}
-
- int edgeFlags = 0;
- if (scaledX == 0) {
- edgeFlags += MotionEvent.EDGE_LEFT;
- } else if (scaledX == display.getWidth() - 1.0f) {
- edgeFlags += MotionEvent.EDGE_RIGHT;
- }
-
- if (scaledY == 0) {
- edgeFlags += MotionEvent.EDGE_TOP;
- } else if (scaledY == display.getHeight() - 1.0f) {
- edgeFlags += MotionEvent.EDGE_BOTTOM;
- }
changed = false;
if (down != lastDown) {
@@ -171,6 +172,8 @@ public class InputDevice {
xPrecision, yPrecision, device.id, edgeFlags);
} else {
if (currentMove != null) {
+ if (false) Log.i("InputDevice", "Adding batch x=" + scaledX
+ + " y=" + scaledY + " to " + currentMove);
currentMove.addBatch(curTime, scaledX, scaledY,
scaledPressure, scaledSize, metaState);
if (WindowManagerPolicy.WATCH_POINTER) {
diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java
new file mode 100644
index 0000000..c701ca1
--- /dev/null
+++ b/services/java/com/android/server/InputMethodManagerService.java
@@ -0,0 +1,1305 @@
+/*
+ * Copyright (C) 2006-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 com.android.internal.os.HandlerCaller;
+import com.android.internal.view.IInputContext;
+import com.android.internal.view.IInputMethod;
+import com.android.internal.view.IInputMethodCallback;
+import com.android.internal.view.IInputMethodClient;
+import com.android.internal.view.IInputMethodManager;
+import com.android.internal.view.IInputMethodSession;
+import com.android.internal.view.InputBindResult;
+
+import com.android.server.status.IconData;
+import com.android.server.status.StatusBarService;
+
+import org.xmlpull.v1.XmlPullParserException;
+
+import android.app.AlertDialog;
+import android.content.ComponentName;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.IntentFilter;
+import android.content.DialogInterface.OnCancelListener;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.IInterface;
+import android.os.Message;
+import android.os.Parcel;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.provider.Settings;
+import android.text.TextUtils;
+import android.util.Log;
+import android.util.PrintWriterPrinter;
+import android.util.Printer;
+import android.view.IWindowManager;
+import android.view.WindowManager;
+import android.view.inputmethod.DefaultInputMethod;
+import android.view.inputmethod.InputBinding;
+import android.view.inputmethod.InputMethod;
+import android.view.inputmethod.InputMethodInfo;
+import android.view.inputmethod.InputMethodManager;
+import android.view.inputmethod.EditorInfo;
+
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * This class provides a system service that manages input methods.
+ */
+public class InputMethodManagerService extends IInputMethodManager.Stub
+ implements ServiceConnection, Handler.Callback {
+ static final boolean DEBUG = false;
+ static final String TAG = "InputManagerService";
+
+ static final int MSG_SHOW_IM_PICKER = 1;
+
+ static final int MSG_UNBIND_INPUT = 1000;
+ static final int MSG_BIND_INPUT = 1010;
+ static final int MSG_SHOW_SOFT_INPUT = 1020;
+ static final int MSG_HIDE_SOFT_INPUT = 1030;
+ static final int MSG_ATTACH_TOKEN = 1040;
+ static final int MSG_CREATE_SESSION = 1050;
+
+ static final int MSG_START_INPUT = 2000;
+ static final int MSG_RESTART_INPUT = 2010;
+
+ static final int MSG_UNBIND_METHOD = 3000;
+ static final int MSG_BIND_METHOD = 3010;
+
+ final Context mContext;
+ final Handler mHandler;
+ final SettingsObserver mSettingsObserver;
+ final StatusBarService mStatusBar;
+ final IBinder mInputMethodIcon;
+ final IconData mInputMethodData;
+ final IWindowManager mIWindowManager;
+ final HandlerCaller mCaller;
+
+ final InputBindResult mNoBinding = new InputBindResult(null, null, -1);
+
+ // All known input methods. mMethodMap also serves as the global
+ // lock for this class.
+ final ArrayList<InputMethodInfo> mMethodList
+ = new ArrayList<InputMethodInfo>();
+ final HashMap<String, InputMethodInfo> mMethodMap
+ = new HashMap<String, InputMethodInfo>();
+
+ final TextUtils.SimpleStringSplitter mStringColonSplitter
+ = new TextUtils.SimpleStringSplitter(':');
+
+ class SessionState {
+ final ClientState client;
+ final IInputMethod method;
+ final IInputMethodSession session;
+
+ @Override
+ public String toString() {
+ return "SessionState{uid " + client.uid + " pid " + client.pid
+ + " method " + Integer.toHexString(
+ System.identityHashCode(method))
+ + " session " + Integer.toHexString(
+ System.identityHashCode(session))
+ + "}";
+ }
+
+ SessionState(ClientState _client, IInputMethod _method,
+ IInputMethodSession _session) {
+ client = _client;
+ method = _method;
+ session = _session;
+ }
+ }
+
+ class ClientState {
+ final IInputMethodClient client;
+ final IInputContext inputContext;
+ final int uid;
+ final int pid;
+ final InputBinding binding;
+
+ boolean sessionRequested;
+ SessionState curSession;
+
+ @Override
+ public String toString() {
+ return "ClientState{" + Integer.toHexString(
+ System.identityHashCode(this)) + " uid " + uid
+ + " pid " + pid + "}";
+ }
+
+ ClientState(IInputMethodClient _client, IInputContext _inputContext,
+ int _uid, int _pid) {
+ client = _client;
+ inputContext = _inputContext;
+ uid = _uid;
+ pid = _pid;
+ binding = new InputBinding(null, inputContext.asBinder(), uid, pid);
+ }
+ }
+
+ final HashMap<IBinder, ClientState> mClients
+ = new HashMap<IBinder, ClientState>();
+
+ /**
+ * Id of the currently selected input method.
+ */
+ String mCurMethodId;
+
+ /**
+ * The current binding sequence number, incremented every time there is
+ * a new bind performed.
+ */
+ int mCurSeq;
+
+ /**
+ * The client that is currently bound to an input method.
+ */
+ ClientState mCurClient;
+
+ /**
+ * The attributes last provided by the current client.
+ */
+ EditorInfo mCurAttribute;
+
+ /**
+ * The input method ID of the input method service that we are currently
+ * connected to or in the process of connecting to.
+ */
+ String mCurId;
+
+ /**
+ * Set to true if our ServiceConnection is currently actively bound to
+ * a service (whether or not we have gotten its IBinder back yet).
+ */
+ boolean mHaveConnection;
+
+ /**
+ * Set if the client has asked for the input method to be shown.
+ */
+ boolean mShowRequested;
+
+ /**
+ * Set if we last told the input method to show itself.
+ */
+ boolean mInputShown;
+
+ /**
+ * The Intent used to connect to the current input method.
+ */
+ Intent mCurIntent;
+
+ /**
+ * The token we have made for the currently active input method, to
+ * identify it in the future.
+ */
+ IBinder mCurToken;
+
+ /**
+ * If non-null, this is the input method service we are currently connected
+ * to.
+ */
+ IInputMethod mCurMethod;
+
+ /**
+ * Have we called mCurMethod.bindInput()?
+ */
+ boolean mBoundToMethod;
+
+ /**
+ * Currently enabled session. Only touched by service thread, not
+ * protected by a lock.
+ */
+ SessionState mEnabledSession;
+
+ /**
+ * True if the screen is on. The value is true initially.
+ */
+ boolean mScreenOn = true;
+
+ AlertDialog.Builder mDialogBuilder;
+ AlertDialog mSwitchingDialog;
+ InputMethodInfo[] mIms;
+ CharSequence[] mItems;
+
+ class SettingsObserver extends ContentObserver {
+ SettingsObserver(Handler handler) {
+ super(handler);
+ ContentResolver resolver = mContext.getContentResolver();
+ resolver.registerContentObserver(Settings.Secure.getUriFor(
+ Settings.Secure.DEFAULT_INPUT_METHOD), false, this);
+ }
+
+ @Override public void onChange(boolean selfChange) {
+ synchronized (mMethodMap) {
+ updateFromSettingsLocked();
+ }
+ }
+ }
+
+ class ScreenOnOffReceiver extends android.content.BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
+ mScreenOn = true;
+ } else if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
+ mScreenOn = false;
+ } else {
+ Log.e(TAG, "Unexpected intent " + intent);
+ }
+
+ // Inform the current client of the change in active status
+ try {
+ if (mCurClient != null && mCurClient.client != null) {
+ mCurClient.client.setActive(mScreenOn);
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Got RemoteException sending 'screen on/off' notification", e);
+ }
+ }
+ }
+
+ class PackageReceiver extends android.content.BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ synchronized (mMethodMap) {
+ buildInputMethodListLocked(mMethodList, mMethodMap);
+
+ InputMethodInfo curIm = null;
+ String curInputMethodId = Settings.Secure.getString(context
+ .getContentResolver(), Settings.Secure.DEFAULT_INPUT_METHOD);
+ final int N = mMethodList.size();
+ if (curInputMethodId != null) {
+ for (int i=0; i<N; i++) {
+ if (mMethodList.get(i).getId().equals(curInputMethodId)) {
+ curIm = mMethodList.get(i);
+ }
+ }
+ }
+
+ boolean changed = false;
+
+ Uri uri = intent.getData();
+ String pkg = uri != null ? uri.getSchemeSpecificPart() : null;
+ if (curIm != null && curIm.getPackageName().equals(pkg)) {
+ ServiceInfo si = null;
+ try {
+ si = mContext.getPackageManager().getServiceInfo(
+ curIm.getComponent(), 0);
+ } catch (PackageManager.NameNotFoundException ex) {
+ }
+ if (si == null) {
+ // Uh oh, current input method is no longer around!
+ // Pick another one...
+ Log.i(TAG, "Current input method removed: " + curInputMethodId);
+ List<InputMethodInfo> enabled = getEnabledInputMethodListLocked();
+ if (enabled != null && enabled.size() > 0) {
+ changed = true;
+ curIm = enabled.get(0);
+ curInputMethodId = curIm.getId();
+ Log.i(TAG, "Switching to: " + curInputMethodId);
+ Settings.Secure.putString(mContext.getContentResolver(),
+ Settings.Secure.DEFAULT_INPUT_METHOD,
+ curInputMethodId);
+ } else if (curIm != null) {
+ changed = true;
+ curIm = null;
+ curInputMethodId = "";
+ Log.i(TAG, "Unsetting current input method");
+ Settings.Secure.putString(mContext.getContentResolver(),
+ Settings.Secure.DEFAULT_INPUT_METHOD,
+ curInputMethodId);
+ }
+ }
+
+ } else if (curIm == null) {
+ // We currently don't have a default input method... is
+ // one now available?
+ List<InputMethodInfo> enabled = getEnabledInputMethodListLocked();
+ if (enabled != null && enabled.size() > 0) {
+ changed = true;
+ curIm = enabled.get(0);
+ curInputMethodId = curIm.getId();
+ Log.i(TAG, "New default input method: " + curInputMethodId);
+ Settings.Secure.putString(mContext.getContentResolver(),
+ Settings.Secure.DEFAULT_INPUT_METHOD,
+ curInputMethodId);
+ }
+ }
+
+ if (changed) {
+ updateFromSettingsLocked();
+ }
+ }
+ }
+ }
+
+ class MethodCallback extends IInputMethodCallback.Stub {
+ final IInputMethod mMethod;
+
+ MethodCallback(IInputMethod method) {
+ mMethod = method;
+ }
+
+ public void finishedEvent(int seq, boolean handled) throws RemoteException {
+ }
+
+ public void sessionCreated(IInputMethodSession session) throws RemoteException {
+ onSessionCreated(mMethod, session);
+ }
+ }
+
+ public InputMethodManagerService(Context context, StatusBarService statusBar) {
+ mContext = context;
+ mHandler = new Handler(this);
+ mIWindowManager = IWindowManager.Stub.asInterface(
+ ServiceManager.getService(Context.WINDOW_SERVICE));
+ mCaller = new HandlerCaller(context, new HandlerCaller.Callback() {
+ public void executeMessage(Message msg) {
+ handleMessage(msg);
+ }
+ });
+
+ IntentFilter packageFilt = new IntentFilter();
+ packageFilt.addAction(Intent.ACTION_PACKAGE_ADDED);
+ packageFilt.addAction(Intent.ACTION_PACKAGE_CHANGED);
+ packageFilt.addAction(Intent.ACTION_PACKAGE_REMOVED);
+ packageFilt.addAction(Intent.ACTION_PACKAGE_RESTARTED);
+ packageFilt.addDataScheme("package");
+ mContext.registerReceiver(new PackageReceiver(), packageFilt);
+
+ IntentFilter screenOnOffFilt = new IntentFilter();
+ screenOnOffFilt.addAction(Intent.ACTION_SCREEN_ON);
+ screenOnOffFilt.addAction(Intent.ACTION_SCREEN_OFF);
+ mContext.registerReceiver(new ScreenOnOffReceiver(), screenOnOffFilt);
+
+ buildInputMethodListLocked(mMethodList, mMethodMap);
+
+ final String enabledStr = Settings.Secure.getString(
+ mContext.getContentResolver(),
+ Settings.Secure.ENABLED_INPUT_METHODS);
+ Log.i(TAG, "Enabled input methods: " + enabledStr);
+ if (enabledStr == null) {
+ Log.i(TAG, "Enabled input methods has not been set, enabling all");
+ InputMethodInfo defIm = null;
+ StringBuilder sb = new StringBuilder(256);
+ final int N = mMethodList.size();
+ for (int i=0; i<N; i++) {
+ InputMethodInfo imi = mMethodList.get(i);
+ Log.i(TAG, "Adding: " + imi.getId());
+ if (i > 0) sb.append(':');
+ sb.append(imi.getId());
+ if (defIm == null && imi.getIsDefaultResourceId() != 0) {
+ try {
+ Resources res = mContext.createPackageContext(
+ imi.getPackageName(), 0).getResources();
+ if (res.getBoolean(imi.getIsDefaultResourceId())) {
+ defIm = imi;
+ Log.i(TAG, "Selected default: " + imi.getId());
+ }
+ } catch (PackageManager.NameNotFoundException ex) {
+ } catch (Resources.NotFoundException ex) {
+ }
+ }
+ }
+ if (defIm == null && N > 0) {
+ defIm = mMethodList.get(0);
+ Log.i(TAG, "No default found, using " + defIm.getId());
+ }
+ Settings.Secure.putString(mContext.getContentResolver(),
+ Settings.Secure.ENABLED_INPUT_METHODS, sb.toString());
+ if (defIm != null) {
+ Settings.Secure.putString(mContext.getContentResolver(),
+ Settings.Secure.DEFAULT_INPUT_METHOD, defIm.getId());
+ }
+ }
+
+ mStatusBar = statusBar;
+ mInputMethodData = IconData.makeIcon("ime", null, 0, 0, 0);
+ mInputMethodIcon = statusBar.addIcon(mInputMethodData, null);
+ statusBar.setIconVisibility(mInputMethodIcon, false);
+
+ mSettingsObserver = new SettingsObserver(mHandler);
+ updateFromSettingsLocked();
+ }
+
+ @Override
+ public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
+ throws RemoteException {
+ try {
+ return super.onTransact(code, data, reply, flags);
+ } catch (RuntimeException e) {
+ // The input method manager only throws security exceptions, so let's
+ // log all others.
+ if (!(e instanceof SecurityException)) {
+ Log.e(TAG, "Input Method Manager Crash", e);
+ }
+ throw e;
+ }
+ }
+
+ public void systemReady() {
+
+ }
+
+ public List<InputMethodInfo> getInputMethodList() {
+ synchronized (mMethodMap) {
+ return new ArrayList<InputMethodInfo>(mMethodList);
+ }
+ }
+
+ public List<InputMethodInfo> getEnabledInputMethodList() {
+ synchronized (mMethodMap) {
+ return getEnabledInputMethodListLocked();
+ }
+ }
+
+ List<InputMethodInfo> getEnabledInputMethodListLocked() {
+ final ArrayList<InputMethodInfo> res = new ArrayList<InputMethodInfo>();
+
+ final String enabledStr = Settings.Secure.getString(
+ mContext.getContentResolver(),
+ Settings.Secure.ENABLED_INPUT_METHODS);
+ if (enabledStr != null) {
+ final TextUtils.SimpleStringSplitter splitter = mStringColonSplitter;
+ splitter.setString(enabledStr);
+
+ while (splitter.hasNext()) {
+ InputMethodInfo info = mMethodMap.get(splitter.next());
+ if (info != null) {
+ res.add(info);
+ }
+ }
+ }
+
+ return res;
+ }
+
+ public void addClient(IInputMethodClient client,
+ IInputContext inputContext, int uid, int pid) {
+ synchronized (mMethodMap) {
+ mClients.put(client.asBinder(), new ClientState(client,
+ inputContext, uid, pid));
+ }
+ }
+
+ public void removeClient(IInputMethodClient client) {
+ synchronized (mMethodMap) {
+ mClients.remove(client.asBinder());
+ }
+ }
+
+ void executeOrSendMessage(IInterface target, Message msg) {
+ if (target.asBinder() instanceof Binder) {
+ mCaller.sendMessage(msg);
+ } else {
+ handleMessage(msg);
+ msg.recycle();
+ }
+ }
+
+ void unbindCurrentInputLocked() {
+ if (mCurClient != null) {
+ if (DEBUG) Log.v(TAG, "unbindCurrentInputLocked: client = "
+ + mCurClient.client.asBinder());
+ if (mBoundToMethod) {
+ mBoundToMethod = false;
+ if (mCurMethod != null) {
+ executeOrSendMessage(mCurMethod, mCaller.obtainMessageO(
+ MSG_UNBIND_INPUT, mCurMethod));
+ }
+ }
+ executeOrSendMessage(mCurClient.client, mCaller.obtainMessageIO(
+ MSG_UNBIND_METHOD, mCurSeq, mCurClient.client));
+ mCurClient.sessionRequested = false;
+
+ // Call setActive(false) on the old client
+ try {
+ mCurClient.client.setActive(false);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Got RemoteException sending setActive(false) notification", e);
+ }
+ mCurClient = null;
+ }
+ }
+
+ InputBindResult attachNewInputLocked(boolean initial, boolean needResult) {
+ if (!mBoundToMethod) {
+ executeOrSendMessage(mCurMethod, mCaller.obtainMessageOO(
+ MSG_BIND_INPUT, mCurMethod, mCurClient.binding));
+ mBoundToMethod = true;
+ }
+ final SessionState session = mCurClient.curSession;
+ if (initial) {
+ executeOrSendMessage(session.method, mCaller.obtainMessageOO(
+ MSG_START_INPUT, session, mCurAttribute));
+ } else {
+ executeOrSendMessage(session.method, mCaller.obtainMessageOO(
+ MSG_RESTART_INPUT, session, mCurAttribute));
+ }
+ if (mShowRequested) {
+ showCurrentInputLocked();
+ }
+ return needResult
+ ? new InputBindResult(session.session, mCurId, mCurSeq)
+ : null;
+ }
+
+ InputBindResult startInputLocked(IInputMethodClient client,
+ EditorInfo attribute, boolean initial, boolean needResult) {
+ // If no method is currently selected, do nothing.
+ if (mCurMethodId == null) {
+ return mNoBinding;
+ }
+
+ ClientState cs = mClients.get(client.asBinder());
+ if (cs == null) {
+ throw new IllegalArgumentException("unknown client "
+ + client.asBinder());
+ }
+
+ try {
+ if (!mIWindowManager.inputMethodClientHasFocus(cs.client)) {
+ // Check with the window manager to make sure this client actually
+ // has a window with focus. If not, reject. This is thread safe
+ // because if the focus changes some time before or after, the
+ // next client receiving focus that has any interest in input will
+ // be calling through here after that change happens.
+ Log.w(TAG, "Starting input on non-focused client " + cs.client
+ + " (uid=" + cs.uid + " pid=" + cs.pid + ")");
+ return null;
+ }
+ } catch (RemoteException e) {
+ }
+
+ if (mCurClient != cs) {
+ // If the client is changing, we need to switch over to the new
+ // one.
+ unbindCurrentInputLocked();
+ if (DEBUG) Log.v(TAG, "switching to client: client = "
+ + cs.client.asBinder());
+
+ // If the screen is on, inform the new client it is active
+ if (mScreenOn) {
+ try {
+ cs.client.setActive(mScreenOn);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Got RemoteException sending setActive notification", e);
+ }
+ }
+ }
+
+ // Bump up the sequence for this client and attach it.
+ mCurSeq++;
+ if (mCurSeq <= 0) mCurSeq = 1;
+ mCurClient = cs;
+ mCurAttribute = attribute;
+
+ // Check if the input method is changing.
+ if (mCurId != null && mCurId.equals(mCurMethodId)) {
+ if (cs.curSession != null) {
+ // Fast case: if we are already connected to the input method,
+ // then just return it.
+ return attachNewInputLocked(initial, needResult);
+ }
+ if (mHaveConnection) {
+ if (mCurMethod != null && !cs.sessionRequested) {
+ cs.sessionRequested = true;
+ if (DEBUG) Log.v(TAG, "Creating new session for client " + cs);
+ executeOrSendMessage(mCurMethod, mCaller.obtainMessageOO(
+ MSG_CREATE_SESSION, mCurMethod,
+ new MethodCallback(mCurMethod)));
+ }
+ return new InputBindResult(null, mCurId, mCurSeq);
+ }
+ }
+
+ InputMethodInfo info = mMethodMap.get(mCurMethodId);
+ if (info == null) {
+ throw new IllegalArgumentException("Unknown id: " + mCurMethodId);
+ }
+
+ if (mCurToken != null) {
+ try {
+ mIWindowManager.removeWindowToken(mCurToken);
+ } catch (RemoteException e) {
+ }
+ mCurToken = null;
+ }
+
+ if (mHaveConnection) {
+ mContext.unbindService(this);
+ mHaveConnection = false;
+ }
+
+ clearCurMethod();
+
+ mCurIntent = new Intent(InputMethod.SERVICE_INTERFACE);
+ mCurIntent.setComponent(info.getComponent());
+ if (mContext.bindService(mCurIntent, this, Context.BIND_AUTO_CREATE)) {
+ mHaveConnection = true;
+ mCurId = info.getId();
+ mCurToken = new Binder();
+ try {
+ mIWindowManager.addWindowToken(mCurToken,
+ WindowManager.LayoutParams.TYPE_INPUT_METHOD);
+ } catch (RemoteException e) {
+ }
+ return new InputBindResult(null, mCurId, mCurSeq);
+ } else {
+ mCurIntent = null;
+ Log.e(TAG, "Failure connecting to input method service: "
+ + mCurIntent);
+ }
+ return null;
+ }
+
+ public InputBindResult startInput(IInputMethodClient client,
+ EditorInfo attribute, boolean initial, boolean needResult) {
+ synchronized (mMethodMap) {
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ return startInputLocked(client, attribute, initial, needResult);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+ }
+
+ public void finishInput(IInputMethodClient client) {
+ }
+
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ synchronized (mMethodMap) {
+ if (mCurIntent != null && name.equals(mCurIntent.getComponent())) {
+ mCurMethod = IInputMethod.Stub.asInterface(service);
+ if (mCurClient != null) {
+ executeOrSendMessage(mCurMethod, mCaller.obtainMessageOO(
+ MSG_ATTACH_TOKEN, mCurMethod, mCurToken));
+ if (mCurClient != null) {
+ if (DEBUG) Log.v(TAG, "Creating first session while with client "
+ + mCurClient);
+ executeOrSendMessage(mCurMethod, mCaller.obtainMessageOO(
+ MSG_CREATE_SESSION, mCurMethod,
+ new MethodCallback(mCurMethod)));
+ }
+ }
+ }
+ }
+ }
+
+ void onSessionCreated(IInputMethod method, IInputMethodSession session) {
+ synchronized (mMethodMap) {
+ if (mCurMethod == method) {
+ if (mCurClient != null) {
+ mCurClient.curSession = new SessionState(mCurClient,
+ method, session);
+ mCurClient.sessionRequested = false;
+ InputBindResult res = attachNewInputLocked(true, true);
+ if (res.method != null) {
+ executeOrSendMessage(mCurClient.client, mCaller.obtainMessageOO(
+ MSG_BIND_METHOD, mCurClient.client, res));
+ }
+ }
+ }
+ }
+ }
+
+ void clearCurMethod() {
+ if (mCurMethod != null) {
+ for (ClientState cs : mClients.values()) {
+ cs.sessionRequested = false;
+ cs.curSession = null;
+ }
+ mCurMethod = null;
+ }
+ }
+
+ public void onServiceDisconnected(ComponentName name) {
+ synchronized (mMethodMap) {
+ if (DEBUG) Log.v(TAG, "Service disconnected: " + name
+ + " mCurIntent=" + mCurIntent);
+ if (mCurMethod != null && mCurIntent != null
+ && name.equals(mCurIntent.getComponent())) {
+ clearCurMethod();
+ mShowRequested = mInputShown;
+ mInputShown = false;
+ if (mCurClient != null) {
+ executeOrSendMessage(mCurClient.client, mCaller.obtainMessageIO(
+ MSG_UNBIND_METHOD, mCurSeq, mCurClient.client));
+ }
+ }
+ }
+ }
+
+ public void updateStatusIcon(int iconId, String iconPackage) {
+ if (iconId == 0) {
+ Log.d(TAG, "hide the small icon for the input method");
+ mStatusBar.setIconVisibility(mInputMethodIcon, false);
+ } else {
+ Log.d(TAG, "show a small icon for the input method");
+
+ if (iconPackage != null
+ && iconPackage
+ .equals(InputMethodManager.BUILDIN_INPUTMETHOD_PACKAGE)) {
+ iconPackage = null;
+ }
+
+ mInputMethodData.iconId = iconId;
+ mInputMethodData.iconPackage = iconPackage;
+ mStatusBar.updateIcon(mInputMethodIcon, mInputMethodData, null);
+ mStatusBar.setIconVisibility(mInputMethodIcon, true);
+ }
+ }
+
+ void updateFromSettingsLocked() {
+ String id = Settings.Secure.getString(mContext.getContentResolver(),
+ Settings.Secure.DEFAULT_INPUT_METHOD);
+ if (id != null) {
+ try {
+ setInputMethodLocked(id);
+ } catch (IllegalArgumentException e) {
+ Log.w(TAG, "Unknown input method from prefs: " + id, e);
+ }
+ }
+ }
+
+ void setInputMethodLocked(String id) {
+ InputMethodInfo info = mMethodMap.get(id);
+ if (info == null) {
+ throw new IllegalArgumentException("Unknown id: " + mCurMethodId);
+ }
+
+ if (id.equals(mCurMethodId)) {
+ return;
+ }
+
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ mCurMethodId = id;
+ Settings.Secure.putString(mContext.getContentResolver(),
+ Settings.Secure.DEFAULT_INPUT_METHOD, id);
+
+ Intent intent = new Intent(Intent.ACTION_INPUT_METHOD_CHANGED);
+ intent.putExtra("input_method_id", id);
+ mContext.sendBroadcast(intent);
+ unbindCurrentInputLocked();
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ public void showSoftInput(IInputMethodClient client) {
+ synchronized (mMethodMap) {
+ if (mCurClient == null || client == null
+ || mCurClient.client.asBinder() != client.asBinder()) {
+ try {
+ // We need to check if this is the current client with
+ // focus in the window manager, to allow this call to
+ // be made before input is started in it.
+ if (!mIWindowManager.inputMethodClientHasFocus(client)) {
+ Log.w(TAG, "Ignoring showSoftInput of: " + client);
+ return;
+ }
+ } catch (RemoteException e) {
+ }
+ }
+
+ showCurrentInputLocked();
+ }
+ }
+
+ void showCurrentInputLocked() {
+ mShowRequested = true;
+ if (!mInputShown) {
+ if (mCurMethod != null) {
+ executeOrSendMessage(mCurMethod, mCaller.obtainMessageO(
+ MSG_SHOW_SOFT_INPUT, mCurMethod));
+ mInputShown = true;
+ }
+ }
+ }
+
+ public void hideSoftInput(IInputMethodClient client) {
+ synchronized (mMethodMap) {
+ if (mCurClient == null || client == null
+ || mCurClient.client.asBinder() != client.asBinder()) {
+ try {
+ // We need to check if this is the current client with
+ // focus in the window manager, to allow this call to
+ // be made before input is started in it.
+ if (!mIWindowManager.inputMethodClientHasFocus(client)) {
+ Log.w(TAG, "Ignoring hideSoftInput of: " + client);
+ return;
+ }
+ } catch (RemoteException e) {
+ }
+ }
+
+ hideCurrentInputLocked();
+ }
+ }
+
+ void hideCurrentInputLocked() {
+ if (mInputShown && mCurMethod != null) {
+ executeOrSendMessage(mCurMethod, mCaller.obtainMessageO(
+ MSG_HIDE_SOFT_INPUT, mCurMethod));
+ }
+ mInputShown = false;
+ mShowRequested = false;
+ }
+
+ public void windowGainedFocus(IInputMethodClient client,
+ boolean viewHasFocus, int softInputMode, boolean first,
+ int windowFlags) {
+ synchronized (mMethodMap) {
+ if (DEBUG) Log.v(TAG, "windowGainedFocus: " + client.asBinder()
+ + " viewHasFocus=" + viewHasFocus
+ + " softInputMode=#" + Integer.toHexString(softInputMode)
+ + " first=" + first + " flags=#"
+ + Integer.toHexString(windowFlags));
+
+ if (mCurClient == null || client == null
+ || mCurClient.client.asBinder() != client.asBinder()) {
+ try {
+ // We need to check if this is the current client with
+ // focus in the window manager, to allow this call to
+ // be made before input is started in it.
+ if (!mIWindowManager.inputMethodClientHasFocus(client)) {
+ Log.w(TAG, "Ignoring focus gain of: " + client);
+ return;
+ }
+ } catch (RemoteException e) {
+ }
+ }
+
+ switch (softInputMode&WindowManager.LayoutParams.SOFT_INPUT_MASK_STATE) {
+ case WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED:
+ if (!viewHasFocus || (softInputMode &
+ WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST)
+ != WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE) {
+ if ((windowFlags&WindowManager.LayoutParams
+ .FLAG_ALT_FOCUSABLE_IM) == 0) {
+ // There is no focus view, and this window will
+ // be behind any soft input window, then hide the
+ // soft input window if it is shown.
+ hideCurrentInputLocked();
+ }
+ }
+ break;
+ case WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED:
+ // Do nothing.
+ break;
+ case WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN:
+ hideCurrentInputLocked();
+ break;
+ case WindowManager.LayoutParams.SOFT_INPUT_STATE_FIRST_VISIBLE:
+ if (first && !viewHasFocus && (windowFlags
+ & WindowManager.LayoutParams.FLAG_RESTORED_STATE) == 0) {
+ showCurrentInputLocked();
+ }
+ break;
+ case WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE:
+ if (viewHasFocus) {
+ showCurrentInputLocked();
+ }
+ break;
+ }
+ }
+ }
+
+ public void showInputMethodPickerFromClient(IInputMethodClient client) {
+ synchronized (mMethodMap) {
+ if (mCurClient == null || client == null
+ || mCurClient.client.asBinder() != client.asBinder()) {
+ Log.w(TAG, "Ignoring showInputMethodDialogFromClient of: " + client);
+ }
+
+ mHandler.sendEmptyMessage(MSG_SHOW_IM_PICKER);
+ }
+ }
+
+ public void setInputMethod(IBinder token, String id) {
+ synchronized (mMethodMap) {
+ if (mCurToken == null || mCurToken != token) {
+ Log.w(TAG, "Ignoring setInputMethod of token: " + token);
+ }
+
+ setInputMethodLocked(id);
+ }
+ }
+
+ public void hideMySoftInput(IBinder token) {
+ synchronized (mMethodMap) {
+ if (mCurToken == null || mCurToken != token) {
+ Log.w(TAG, "Ignoring hideInputMethod of token: " + token);
+ }
+
+ if (mInputShown && mCurMethod != null) {
+ executeOrSendMessage(mCurMethod, mCaller.obtainMessageO(
+ MSG_HIDE_SOFT_INPUT, mCurMethod));
+ }
+ mInputShown = false;
+ mShowRequested = false;
+ }
+ }
+
+ void setEnabledSessionInMainThread(SessionState session) {
+ if (mEnabledSession != session) {
+ if (mEnabledSession != null) {
+ try {
+ if (DEBUG) Log.v(TAG, "Disabling: " + mEnabledSession);
+ mEnabledSession.method.setSessionEnabled(
+ mEnabledSession.session, false);
+ } catch (RemoteException e) {
+ }
+ }
+ mEnabledSession = session;
+ try {
+ if (DEBUG) Log.v(TAG, "Enabling: " + mEnabledSession);
+ session.method.setSessionEnabled(
+ session.session, true);
+ } catch (RemoteException e) {
+ }
+ }
+ }
+
+ public boolean handleMessage(Message msg) {
+ HandlerCaller.SomeArgs args;
+ switch (msg.what) {
+ case MSG_SHOW_IM_PICKER:
+ showInputMethodMenu();
+ return true;
+
+ // ---------------------------------------------------------
+
+ case MSG_UNBIND_INPUT:
+ try {
+ ((IInputMethod)msg.obj).unbindInput();
+ } catch (RemoteException e) {
+ // There is nothing interesting about the method dying.
+ }
+ return true;
+ case MSG_BIND_INPUT:
+ args = (HandlerCaller.SomeArgs)msg.obj;
+ try {
+ ((IInputMethod)args.arg1).bindInput((InputBinding)args.arg2);
+ } catch (RemoteException e) {
+ }
+ return true;
+ case MSG_SHOW_SOFT_INPUT:
+ try {
+ ((IInputMethod)msg.obj).showSoftInput();
+ } catch (RemoteException e) {
+ }
+ return true;
+ case MSG_HIDE_SOFT_INPUT:
+ try {
+ ((IInputMethod)msg.obj).hideSoftInput();
+ } catch (RemoteException e) {
+ }
+ return true;
+ case MSG_ATTACH_TOKEN:
+ args = (HandlerCaller.SomeArgs)msg.obj;
+ try {
+ ((IInputMethod)args.arg1).attachToken((IBinder)args.arg2);
+ } catch (RemoteException e) {
+ }
+ return true;
+ case MSG_CREATE_SESSION:
+ args = (HandlerCaller.SomeArgs)msg.obj;
+ try {
+ ((IInputMethod)args.arg1).createSession(
+ (IInputMethodCallback)args.arg2);
+ } catch (RemoteException e) {
+ }
+ return true;
+
+ // ---------------------------------------------------------
+
+ case MSG_START_INPUT:
+ args = (HandlerCaller.SomeArgs)msg.obj;
+ try {
+ SessionState session = (SessionState)args.arg1;
+ setEnabledSessionInMainThread(session);
+ session.method.startInput((EditorInfo)args.arg2);
+ } catch (RemoteException e) {
+ }
+ return true;
+ case MSG_RESTART_INPUT:
+ args = (HandlerCaller.SomeArgs)msg.obj;
+ try {
+ SessionState session = (SessionState)args.arg1;
+ setEnabledSessionInMainThread(session);
+ session.method.restartInput((EditorInfo)args.arg2);
+ } catch (RemoteException e) {
+ }
+ return true;
+
+ // ---------------------------------------------------------
+
+ case MSG_UNBIND_METHOD:
+ try {
+ ((IInputMethodClient)msg.obj).onUnbindMethod(msg.arg1);
+ } catch (RemoteException e) {
+ // There is nothing interesting about the last client dying.
+ }
+ return true;
+ case MSG_BIND_METHOD:
+ args = (HandlerCaller.SomeArgs)msg.obj;
+ try {
+ ((IInputMethodClient)args.arg1).onBindMethod(
+ (InputBindResult)args.arg2);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Client died receiving input method " + args.arg2);
+ }
+ return true;
+ }
+ return false;
+ }
+
+ void buildInputMethodListLocked(ArrayList<InputMethodInfo> list,
+ HashMap<String, InputMethodInfo> map) {
+ list.clear();
+ map.clear();
+
+ PackageManager pm = mContext.getPackageManager();
+
+ Object[][] buildin = {{
+ DefaultInputMethod.class.getName(),
+ DefaultInputMethod.getMetaInfo()}};
+
+ List<ResolveInfo> services = pm.queryIntentServices(
+ new Intent(InputMethod.SERVICE_INTERFACE),
+ PackageManager.GET_META_DATA);
+
+ for (int i = 0; i < services.size(); ++i) {
+ ResolveInfo ri = services.get(i);
+ ServiceInfo si = ri.serviceInfo;
+ ComponentName compName = new ComponentName(si.packageName, si.name);
+ if (!android.Manifest.permission.BIND_INPUT_METHOD.equals(
+ si.permission)) {
+ Log.w(TAG, "Skipping input method " + compName
+ + ": it does not require the permission "
+ + android.Manifest.permission.BIND_INPUT_METHOD);
+ continue;
+ }
+
+ if (DEBUG) Log.d(TAG, "Checking " + compName);
+
+ /* Built-in input methods are not currently supported... this will
+ * need to be reworked to bring them back (all input methods must
+ * now be published in a manifest).
+ */
+ /*
+ if (compName.getPackageName().equals(
+ InputMethodManager.BUILDIN_INPUTMETHOD_PACKAGE)) {
+ // System build-in input methods;
+ String inputMethodName = null;
+ int kbType = 0;
+ String skbName = null;
+
+ for (int j = 0; j < buildin.length; ++j) {
+ Object[] obj = buildin[j];
+ if (compName.getClassName().equals(obj[0])) {
+ InputMethodMetaInfo imp = (InputMethodMetaInfo) obj[1];
+ inputMethodName = imp.inputMethodName;
+ }
+ }
+
+ InputMethodMetaInfo p = new InputMethodMetaInfo(compName,
+ inputMethodName, "");
+
+ list.add(p);
+
+ if (DEBUG) {
+ Log.d(TAG, "Found a build-in input method " + p);
+ }
+
+ continue;
+ }
+ */
+
+ try {
+ InputMethodInfo p = new InputMethodInfo(mContext, ri);
+ list.add(p);
+ map.put(p.getId(), p);
+
+ if (DEBUG) {
+ Log.d(TAG, "Found a third-party input method " + p);
+ }
+
+ } catch (XmlPullParserException e) {
+ Log.w(TAG, "Unable to load input method " + compName, e);
+ } catch (IOException e) {
+ Log.w(TAG, "Unable to load input method " + compName, e);
+ }
+ }
+ }
+
+ // ----------------------------------------------------------------------
+
+ public void showInputMethodMenu() {
+ if (DEBUG) Log.v(TAG, "Show switching menu");
+
+ hideInputMethodMenu();
+
+ final Context context = mContext;
+
+ final PackageManager pm = context.getPackageManager();
+
+ String lastInputMethodId = Settings.Secure.getString(context
+ .getContentResolver(), Settings.Secure.DEFAULT_INPUT_METHOD);
+ if (DEBUG) Log.v(TAG, "Current IME: " + lastInputMethodId);
+
+ final List<InputMethodInfo> immis = getEnabledInputMethodList();
+
+ int N = (immis == null ? 0 : immis.size());
+
+ mItems = new CharSequence[N];
+ mIms = new InputMethodInfo[N];
+
+ for (int i = 0; i < N; ++i) {
+ InputMethodInfo property = immis.get(i);
+ mItems[i] = property.loadLabel(pm);
+ mIms[i] = property;
+ }
+
+ int checkedItem = 0;
+ for (int i = 0; i < N; ++i) {
+ if (mIms[i].getId().equals(lastInputMethodId)) {
+ checkedItem = i;
+ break;
+ }
+ }
+
+ AlertDialog.OnClickListener adocl = new AlertDialog.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ hideInputMethodMenu();
+ }
+ };
+
+ TypedArray a = context.obtainStyledAttributes(null,
+ com.android.internal.R.styleable.DialogPreference,
+ com.android.internal.R.attr.alertDialogStyle, 0);
+ mDialogBuilder = new AlertDialog.Builder(context)
+ .setTitle(com.android.internal.R.string.select_input_method)
+ .setOnCancelListener(new OnCancelListener() {
+ public void onCancel(DialogInterface dialog) {
+ hideInputMethodMenu();
+ }
+ })
+ .setIcon(a.getDrawable(
+ com.android.internal.R.styleable.DialogPreference_dialogTitle));
+ a.recycle();
+
+ mDialogBuilder.setSingleChoiceItems(mItems, checkedItem,
+ new AlertDialog.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ synchronized (mMethodMap) {
+ InputMethodInfo im = mIms[which];
+ hideInputMethodMenu();
+ setInputMethodLocked(im.getId());
+ }
+ }
+ });
+
+ synchronized (mMethodMap) {
+ mSwitchingDialog = mDialogBuilder.create();
+ mSwitchingDialog.getWindow().setType(
+ WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG);
+ mSwitchingDialog.show();
+ }
+ }
+
+ void hideInputMethodMenu() {
+ if (DEBUG) Log.v(TAG, "Hide switching menu");
+
+ synchronized (mMethodMap) {
+ if (mSwitchingDialog != null) {
+ mSwitchingDialog.dismiss();
+ mSwitchingDialog = null;
+ }
+
+ mDialogBuilder = null;
+ mItems = null;
+ mIms = null;
+ }
+ }
+
+ @Override
+ protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ if (mContext.checkCallingPermission("android.permission.DUMP")
+ != PackageManager.PERMISSION_GRANTED) {
+
+ pw.println("Permission Denial: can't dump InputMethodManager from from pid="
+ + Binder.getCallingPid()
+ + ", uid=" + Binder.getCallingUid());
+ return;
+ }
+
+ synchronized (mMethodMap) {
+ final Printer p = new PrintWriterPrinter(pw);
+ p.println("Current Input Method Manager state:");
+ int N = mMethodList.size();
+ p.println(" Input Methods:");
+ for (int i=0; i<N; i++) {
+ InputMethodInfo info = mMethodList.get(i);
+ p.println(" InputMethod #" + i + ":");
+ info.dump(p, " ");
+ }
+ p.println(" Clients:");
+ for (ClientState ci : mClients.values()) {
+ p.println(" Client " + ci + ":");
+ p.println(" client=" + ci.client);
+ p.println(" inputContext=" + ci.inputContext);
+ p.println(" sessionRequested=" + ci.sessionRequested);
+ p.println(" curSession=" + ci.curSession);
+ }
+ p.println(" mInputMethodIcon=" + mInputMethodIcon);
+ p.println(" mInputMethodData=" + mInputMethodData);
+ p.println(" mCurrentMethod=" + mCurMethodId);
+ p.println(" mCurSeq=" + mCurSeq + " mCurClient=" + mCurClient);
+ p.println(" mCurId=" + mCurId + " mHaveConnect=" + mHaveConnection
+ + " mBoundToMethod=" + mBoundToMethod);
+ p.println(" mCurToken=" + mCurToken);
+ p.println(" mCurIntent=" + mCurIntent);
+ p.println(" mCurMethod=" + mCurMethod);
+ p.println(" mEnabledSession=" + mEnabledSession);
+ p.println(" mShowRequested=" + mShowRequested
+ + " mInputShown=" + mInputShown);
+ p.println(" mScreenOn=" + mScreenOn);
+ }
+ }
+}
diff --git a/services/java/com/android/server/KeyInputQueue.java b/services/java/com/android/server/KeyInputQueue.java
index c67754b..77182f7 100644
--- a/services/java/com/android/server/KeyInputQueue.java
+++ b/services/java/com/android/server/KeyInputQueue.java
@@ -32,7 +32,7 @@ import android.view.WindowManagerPolicy;
public abstract class KeyInputQueue {
static final String TAG = "KeyInputQueue";
- SparseArray<InputDevice> mDevices = new SparseArray();
+ SparseArray<InputDevice> mDevices = new SparseArray<InputDevice>();
int mGlobalMetaState = 0;
boolean mHaveGlobalMetaState = false;
@@ -498,6 +498,7 @@ public abstract class KeyInputQueue {
ev.inputDevice.mAbs.currentMove = null;
}
if (ev.event == ev.inputDevice.mRel.currentMove) {
+ if (false) Log.i(TAG, "Detach rel " + ev.event);
ev.inputDevice.mRel.currentMove = null;
ev.inputDevice.mRel.x = 0;
ev.inputDevice.mRel.y = 0;
diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java
index 1bf60d4..831d1d2 100644
--- a/services/java/com/android/server/LocationManagerService.java
+++ b/services/java/com/android/server/LocationManagerService.java
@@ -57,9 +57,9 @@ import android.os.PowerManager;
import android.os.RemoteException;
import android.os.SystemClock;
import android.provider.Settings;
+import android.provider.Settings.SettingNotFoundException;
import android.telephony.CellLocation;
import android.telephony.PhoneStateListener;
-import android.telephony.ServiceState;
import android.telephony.TelephonyManager;
import android.util.Config;
import android.util.Log;
@@ -145,24 +145,25 @@ public class LocationManagerService extends ILocationManager.Stub {
private boolean mCellWakeLockAcquired = false;
/**
- * Mapping from listener IBinder to local Listener wrappers.
+ * Mapping from listener IBinder/PendingIntent to local Listener wrappers.
*/
- private final HashMap<IBinder,Listener> mListeners =
- new HashMap<IBinder,Listener>();
+ private final HashMap<Object,Receiver> mListeners =
+ new HashMap<Object,Receiver>();
/**
- * Mapping from listener IBinder to a map from provider name to UpdateRecord.
+ * Mapping from listener IBinder/PendingIntent to a map from provider name to UpdateRecord.
*/
- private final HashMap<IBinder,HashMap<String,UpdateRecord>> mLocationListeners =
- new HashMap<IBinder,HashMap<String,UpdateRecord>>();
+ private final HashMap<Object,HashMap<String,UpdateRecord>> mLocationListeners =
+ new HashMap<Object,HashMap<String,UpdateRecord>>();
/**
- * Mapping from listener IBinder to a map from provider name to last broadcast location.
+ * Mapping from listener IBinder/PendingIntent to a map from provider name to last broadcast
+ * location.
*/
- private final HashMap<IBinder,HashMap<String,Location>> mLastFixBroadcast =
- new HashMap<IBinder,HashMap<String,Location>>();
- private final HashMap<IBinder,HashMap<String,Long>> mLastStatusBroadcast =
- new HashMap<IBinder,HashMap<String,Long>>();
+ private final HashMap<Object,HashMap<String,Location>> mLastFixBroadcast =
+ new HashMap<Object,HashMap<String,Location>>();
+ private final HashMap<Object,HashMap<String,Long>> mLastStatusBroadcast =
+ new HashMap<Object,HashMap<String,Long>>();
/**
* Mapping from provider name to all its UpdateRecords
@@ -178,7 +179,7 @@ public class LocationManagerService extends ILocationManager.Stub {
new HashMap<String,Location>();
// Proximity listeners
- private ProximityListener mProximityListener = null;
+ private Receiver mProximityListener = null;
private HashMap<PendingIntent,ProximityAlert> mProximityAlerts =
new HashMap<PendingIntent,ProximityAlert>();
private HashSet<ProximityAlert> mProximitiesEntered =
@@ -195,7 +196,7 @@ public class LocationManagerService extends ILocationManager.Stub {
// Last known cell service state
private TelephonyManager mTelephonyManager;
- private ServiceState mServiceState = new ServiceState();
+ private int mSignalStrength = -1;
// Location collector
private LocationCollector mCollector;
@@ -206,11 +207,82 @@ public class LocationManagerService extends ILocationManager.Stub {
// Wifi Manager
private WifiManager mWifiManager;
- private final class Listener implements IBinder.DeathRecipient {
+ /**
+ * A wrapper class holding either an ILocationListener or a PendingIntent to receive
+ * location updates.
+ */
+ private final class Receiver implements IBinder.DeathRecipient {
final ILocationListener mListener;
+ final PendingIntent mPendingIntent;
- Listener(ILocationListener listener) {
+ Receiver(ILocationListener listener) {
mListener = listener;
+ mPendingIntent = null;
+ }
+
+ Receiver(PendingIntent intent) {
+ mPendingIntent = intent;
+ mListener = null;
+ }
+
+ public Object getKey() {
+ if (mListener != null) {
+ return mListener.asBinder();
+ } else {
+ return mPendingIntent;
+ }
+ }
+
+ public boolean isListener() {
+ return mListener != null;
+ }
+
+ public boolean isPendingIntent() {
+ return mPendingIntent != null;
+ }
+
+ public ILocationListener getListener() {
+ if (mListener != null) {
+ return mListener;
+ }
+ throw new IllegalStateException("Request for non-existent listener");
+ }
+
+ public PendingIntent getPendingIntent() {
+ if (mPendingIntent != null) {
+ return mPendingIntent;
+ }
+ throw new IllegalStateException("Request for non-existent intent");
+ }
+
+ public void onStatusChanged(String provider, int status, Bundle extras)
+ throws RemoteException {
+ if (mListener != null) {
+ mListener.onStatusChanged(provider, status, extras);
+ } else {
+ Intent statusChanged = new Intent();
+ statusChanged.putExtras(extras);
+ statusChanged.putExtra(LocationManager.KEY_STATUS_CHANGED, status);
+ try {
+ mPendingIntent.send(mContext, 0, statusChanged, null, null);
+ } catch (PendingIntent.CanceledException e) {
+ _removeUpdates(this);
+ }
+ }
+ }
+
+ public void onLocationChanged(Location location) throws RemoteException {
+ if (mListener != null) {
+ mListener.onLocationChanged(location);
+ } else {
+ Intent locationChanged = new Intent();
+ locationChanged.putExtra(LocationManager.KEY_LOCATION_CHANGED, location);
+ try {
+ mPendingIntent.send(mContext, 0, locationChanged, null, null);
+ } catch (PendingIntent.CanceledException e) {
+ _removeUpdates(this);
+ }
+ }
}
public void binderDied() {
@@ -218,7 +290,7 @@ public class LocationManagerService extends ILocationManager.Stub {
Log.d(TAG, "Location listener died");
}
synchronized (mLocationListeners) {
- _removeUpdates(mListener);
+ _removeUpdates(this);
}
}
}
@@ -228,7 +300,7 @@ public class LocationManagerService extends ILocationManager.Stub {
String s = null;
try {
File f = new File(LocationManager.SYSTEM_DIR + "/location."
- + provider);
+ + provider);
if (!f.exists()) {
return null;
}
@@ -443,13 +515,22 @@ public class LocationManagerService extends ILocationManager.Stub {
// Create location collector
mCollector = new LocationCollector(mMasfClient);
+ // Alarm manager, needs to be done before calling loadProviders() below
+ mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
+
+ // Create a wake lock, needs to be done before calling loadProviders() below
+ PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
+ mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY);
+
// Load providers
loadProviders();
// Listen for Radio changes
mTelephonyManager = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
mTelephonyManager.listen(mPhoneStateListener,
- PhoneStateListener.LISTEN_SERVICE_STATE | PhoneStateListener.LISTEN_CELL_LOCATION);
+ PhoneStateListener.LISTEN_CELL_LOCATION |
+ PhoneStateListener.LISTEN_SIGNAL_STRENGTH |
+ PhoneStateListener.LISTEN_DATA_CONNECTION_STATE);
// Register for Network (Wifi or Mobile) updates
NetworkStateBroadcastReceiver networkReceiver = new NetworkStateBroadcastReceiver();
@@ -460,9 +541,6 @@ public class LocationManagerService extends ILocationManager.Stub {
networkIntentFilter.addAction(GpsLocationProvider.GPS_ENABLED_CHANGE_ACTION);
context.registerReceiver(networkReceiver, networkIntentFilter);
- // Alarm manager
- mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
-
// Register for power updates
PowerStateBroadcastReceiver powerStateReceiver = new PowerStateBroadcastReceiver();
IntentFilter intentFilter = new IntentFilter();
@@ -472,10 +550,6 @@ public class LocationManagerService extends ILocationManager.Stub {
intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED);
context.registerReceiver(powerStateReceiver, intentFilter);
- // Create a wake lock
- PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
- mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY);
-
// Get the wifi manager
mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
@@ -510,8 +584,8 @@ public class LocationManagerService extends ILocationManager.Stub {
}
// Use system settings
ContentResolver resolver = mContext.getContentResolver();
- String allowedProviders = Settings.System.getString(resolver,
- Settings.System.LOCATION_PROVIDERS_ALLOWED);
+ String allowedProviders = Settings.Secure.getString(resolver,
+ Settings.Secure.LOCATION_PROVIDERS_ALLOWED);
return ((allowedProviders != null) && (allowedProviders.contains(provider)));
}
@@ -638,16 +712,28 @@ public class LocationManagerService extends ILocationManager.Stub {
}
synchronized (mRecordsByProvider) {
-
HashSet<UpdateRecord> records = mRecordsByProvider.get(provider);
if (records != null) {
for (UpdateRecord record : records) {
- // Sends a notification message to the listener
+ // Sends a notification message to the receiver
try {
- if (enabled) {
- record.mListener.mListener.onProviderEnabled(provider);
+ Receiver receiver = record.mReceiver;
+ if (receiver.isListener()) {
+ if (enabled) {
+ receiver.getListener().onProviderEnabled(provider);
+ } else {
+ receiver.getListener().onProviderDisabled(provider);
+ }
} else {
- record.mListener.mListener.onProviderDisabled(provider);
+ PendingIntent intent = receiver.getPendingIntent();
+ Intent providerIntent = new Intent();
+ providerIntent.putExtra(LocationManager.KEY_PROVIDER_ENABLED, enabled);
+ try {
+ receiver.getPendingIntent().send(mContext, 0,
+ providerIntent, null, null);
+ } catch (PendingIntent.CanceledException e) {
+ _removeUpdates(receiver);
+ }
}
} catch (RemoteException e) {
// The death link will clean this up.
@@ -694,15 +780,15 @@ public class LocationManagerService extends ILocationManager.Stub {
private class UpdateRecord {
String mProvider;
- Listener mListener;
+ Receiver mReceiver;
long mMinTime;
float mMinDistance;
String[] mPackages;
- UpdateRecord(String provider, long minTime, float minDistance, Listener listener,
- String[] packages) {
+ UpdateRecord(String provider, long minTime, float minDistance,
+ Receiver receiver, String[] packages) {
mProvider = provider;
- mListener = listener;
+ mReceiver = receiver;
mMinTime = minTime;
mMinDistance = minDistance;
mPackages = packages;
@@ -740,7 +826,20 @@ public class LocationManagerService extends ILocationManager.Stub {
long minTime, float minDistance, ILocationListener listener) {
try {
- _requestLocationUpdates(provider, minTime, minDistance, listener);
+ _requestLocationUpdates(provider, minTime, minDistance,
+ new Receiver(listener));
+ } catch (SecurityException se) {
+ throw se;
+ } catch (Exception e) {
+ Log.e(TAG, "requestUpdates got exception:", e);
+ }
+ }
+
+ public void requestLocationUpdatesPI(String provider,
+ long minTime, float minDistance, PendingIntent intent) {
+ try {
+ _requestLocationUpdates(provider, minTime, minDistance,
+ new Receiver(intent));
} catch (SecurityException se) {
throw se;
} catch (Exception e) {
@@ -749,9 +848,10 @@ public class LocationManagerService extends ILocationManager.Stub {
}
private void _requestLocationUpdates(String provider,
- long minTime, float minDistance, ILocationListener listener) {
+ long minTime, float minDistance, Receiver receiver) {
+ Object key = receiver.getKey();
if (Config.LOGD) {
- Log.d(TAG, "_requestLocationUpdates: listener = " + listener.asBinder());
+ Log.d(TAG, "_requestLocationUpdates: listener = " + key);
}
LocationProviderImpl impl = LocationProviderImpl.getProvider(provider);
@@ -766,24 +866,23 @@ public class LocationManagerService extends ILocationManager.Stub {
// so wakelock calls will succeed
long identity = Binder.clearCallingIdentity();
try {
- Listener myListener = new Listener(listener);
- UpdateRecord r = new UpdateRecord(provider, minTime, minDistance, myListener, packages);
-
+ UpdateRecord r = new UpdateRecord(provider, minTime, minDistance, receiver, packages);
synchronized (mLocationListeners) {
- IBinder binder = listener.asBinder();
- if (mListeners.get(binder) == null) {
+ if (mListeners.get(key) == null) {
try {
- binder.linkToDeath(myListener, 0);
- mListeners.put(binder, myListener);
+ if (receiver.isListener()) {
+ receiver.getListener().asBinder().linkToDeath(receiver, 0);
+ }
+ mListeners.put(key, receiver);
} catch (RemoteException e) {
return;
}
}
- HashMap<String,UpdateRecord> records = mLocationListeners.get(binder);
+ HashMap<String,UpdateRecord> records = mLocationListeners.get(key);
if (records == null) {
records = new HashMap<String,UpdateRecord>();
- mLocationListeners.put(binder, records);
+ mLocationListeners.put(key, records);
}
UpdateRecord oldRecord = records.put(provider, r);
if (oldRecord != null) {
@@ -809,9 +908,12 @@ public class LocationManagerService extends ILocationManager.Stub {
} else {
try {
// Notify the listener that updates are currently disabled
- listener.onProviderDisabled(provider);
+ if (receiver.isListener()) {
+ receiver.getListener().onProviderDisabled(provider);
+ }
} catch(RemoteException e) {
- Log.w(TAG, "RemoteException calling onProviderDisabled on " + listener);
+ Log.w(TAG, "RemoteException calling onProviderDisabled on " +
+ receiver.getListener());
}
}
}
@@ -822,7 +924,7 @@ public class LocationManagerService extends ILocationManager.Stub {
public void removeUpdates(ILocationListener listener) {
try {
- _removeUpdates(listener);
+ _removeUpdates(new Receiver(listener));
} catch (SecurityException se) {
throw se;
} catch (Exception e) {
@@ -830,24 +932,34 @@ public class LocationManagerService extends ILocationManager.Stub {
}
}
- private void _removeUpdates(ILocationListener listener) {
+ public void removeUpdatesPI(PendingIntent intent) {
+ try {
+ _removeUpdates(new Receiver(intent));
+ } catch (SecurityException se) {
+ throw se;
+ } catch (Exception e) {
+ Log.e(TAG, "removeUpdates got exception:", e);
+ }
+ }
+
+ private void _removeUpdates(Receiver receiver) {
+ Object key = receiver.getKey();
if (Config.LOGD) {
- Log.d(TAG, "_removeUpdates: listener = " + listener.asBinder());
+ Log.d(TAG, "_removeUpdates: listener = " + key);
}
// so wakelock calls will succeed
long identity = Binder.clearCallingIdentity();
try {
synchronized (mLocationListeners) {
- IBinder binder = listener.asBinder();
- Listener myListener = mListeners.remove(binder);
- if (myListener != null) {
- binder.unlinkToDeath(myListener, 0);
+ Receiver myReceiver = mListeners.remove(key);
+ if ((myReceiver != null) && (myReceiver.isListener())) {
+ myReceiver.getListener().asBinder().unlinkToDeath(myReceiver, 0);
}
// Record which providers were associated with this listener
HashSet<String> providers = new HashSet<String>();
- HashMap<String,UpdateRecord> oldRecords = mLocationListeners.get(binder);
+ HashMap<String,UpdateRecord> oldRecords = mLocationListeners.get(key);
if (oldRecords != null) {
// Call dispose() on the obsolete update records.
for (UpdateRecord record : oldRecords.values()) {
@@ -862,9 +974,9 @@ public class LocationManagerService extends ILocationManager.Stub {
providers.addAll(oldRecords.keySet());
}
- mLocationListeners.remove(binder);
- mLastFixBroadcast.remove(binder);
- mLastStatusBroadcast.remove(binder);
+ mLocationListeners.remove(key);
+ mLastFixBroadcast.remove(key);
+ mLastStatusBroadcast.remove(key);
// See if the providers associated with this listener have any
// other listeners; if one does, inform it of the new smallest minTime
@@ -894,7 +1006,7 @@ public class LocationManagerService extends ILocationManager.Stub {
}
}
- updateWakelockStatus(mScreenOn);
+ updateWakelockStatus(mScreenOn);
}
} finally {
Binder.restoreCallingIdentity(identity);
@@ -905,6 +1017,11 @@ public class LocationManagerService extends ILocationManager.Stub {
if (mGpsLocationProvider == null) {
return false;
}
+ if (mContext.checkCallingPermission(ACCESS_FINE_LOCATION) !=
+ PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Requires ACCESS_FINE_LOCATION permission");
+ }
+
try {
mGpsLocationProvider.addGpsStatusListener(listener);
} catch (RemoteException e) {
@@ -996,7 +1113,6 @@ public class LocationManagerService extends ILocationManager.Stub {
ArrayList<PendingIntent> intentsToRemove = null;
for (ProximityAlert alert : mProximityAlerts.values()) {
-
PendingIntent intent = alert.getIntent();
long expiration = alert.getExpiration();
@@ -1115,7 +1231,7 @@ public class LocationManagerService extends ILocationManager.Stub {
mProximityAlerts.put(intent, alert);
if (mProximityListener == null) {
- mProximityListener = new ProximityListener();
+ mProximityListener = new Receiver(new ProximityListener());
LocationProvider provider = LocationProviderImpl.getProvider(
LocationManager.GPS_PROVIDER);
@@ -1345,15 +1461,15 @@ public class LocationManagerService extends ILocationManager.Stub {
// Broadcast location or status to all listeners
for (UpdateRecord r : records) {
- ILocationListener listener = r.mListener.mListener;
- IBinder binder = listener.asBinder();
+ Receiver receiver = r.mReceiver;
+ Object key = receiver.getKey();
// Broadcast location only if it is valid
if (locationValid) {
- HashMap<String,Location> map = mLastFixBroadcast.get(binder);
+ HashMap<String,Location> map = mLastFixBroadcast.get(key);
if (map == null) {
map = new HashMap<String,Location>();
- mLastFixBroadcast.put(binder, map);
+ mLastFixBroadcast.put(key, map);
}
Location lastLoc = map.get(provider);
if ((lastLoc == null) || shouldBroadcast(loc, lastLoc, r)) {
@@ -1364,19 +1480,19 @@ public class LocationManagerService extends ILocationManager.Stub {
lastLoc.set(loc);
}
try {
- listener.onLocationChanged(loc);
+ receiver.onLocationChanged(loc);
} catch (RemoteException doe) {
- Log.w(TAG, "RemoteException calling onLocationChanged on " + listener);
- _removeUpdates(listener);
+ Log.w(TAG, "RemoteException calling onLocationChanged on " + receiver);
+ _removeUpdates(receiver);
}
}
}
// Broadcast status message
- HashMap<String,Long> statusMap = mLastStatusBroadcast.get(binder);
+ HashMap<String,Long> statusMap = mLastStatusBroadcast.get(key);
if (statusMap == null) {
statusMap = new HashMap<String,Long>();
- mLastStatusBroadcast.put(binder, statusMap);
+ mLastStatusBroadcast.put(key, statusMap);
}
long prevStatusUpdateTime =
(statusMap.get(provider) != null) ? statusMap.get(provider) : 0;
@@ -1386,10 +1502,10 @@ public class LocationManagerService extends ILocationManager.Stub {
statusMap.put(provider, newStatusUpdateTime);
try {
- listener.onStatusChanged(provider, status, extras);
+ receiver.onStatusChanged(provider, status, extras);
} catch (RemoteException doe) {
- Log.w(TAG, "RemoteException calling onStatusChanged on " + listener);
- _removeUpdates(listener);
+ Log.w(TAG, "RemoteException calling onStatusChanged on " + receiver);
+ _removeUpdates(receiver);
}
}
}
@@ -1423,7 +1539,8 @@ public class LocationManagerService extends ILocationManager.Stub {
}
if ((mWakeLockAcquireTime != 0) &&
- (SystemClock.elapsedRealtime() - mWakeLockAcquireTime > MAX_TIME_FOR_WAKE_LOCK)) {
+ (SystemClock.elapsedRealtime() - mWakeLockAcquireTime
+ > MAX_TIME_FOR_WAKE_LOCK)) {
removeMessages(MESSAGE_ACQUIRE_WAKE_LOCK);
removeMessages(MESSAGE_RELEASE_WAKE_LOCK);
@@ -1449,7 +1566,7 @@ public class LocationManagerService extends ILocationManager.Stub {
acquireWakeLock();
} else if (msg.what == MESSAGE_RELEASE_WAKE_LOCK) {
log("LocationWorkerHandler: Release");
-
+
// Update wakelock status so the next alarm is set before releasing wakelock
updateWakelockStatus(mScreenOn);
releaseWakeLock();
@@ -1462,22 +1579,24 @@ public class LocationManagerService extends ILocationManager.Stub {
}
PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
+
+ private CellState mLastCellState = null;
@Override
public void onCellLocationChanged(CellLocation cellLocation) {
try {
- ServiceState serviceState = mServiceState;
+ int asu = mSignalStrength;
// Gets cell state
- CellState cellState = new CellState(serviceState, cellLocation);
+ mLastCellState = new CellState(mTelephonyManager, cellLocation, asu);
// Notify collector
- mCollector.updateCellState(cellState);
+ mCollector.updateCellState(mLastCellState);
// Updates providers
List<LocationProviderImpl> providers = LocationProviderImpl.getProviders();
for (LocationProviderImpl provider : providers) {
if (provider.requiresCell()) {
- provider.updateCellState(cellState);
+ provider.updateCellState(mLastCellState);
}
}
} catch (Exception e) {
@@ -1486,8 +1605,19 @@ public class LocationManagerService extends ILocationManager.Stub {
}
@Override
- public void onServiceStateChanged(ServiceState serviceState) {
- mServiceState = serviceState;
+ public void onSignalStrengthChanged(int asu) {
+ mSignalStrength = asu;
+
+ if (mLastCellState != null) {
+ mLastCellState.updateSignalStrength(asu);
+ }
+ }
+
+ @Override
+ public void onDataConnectionStateChanged(int state) {
+ if (mLastCellState != null) {
+ mLastCellState.updateRadioType(mTelephonyManager);
+ }
}
};
@@ -1578,7 +1708,8 @@ public class LocationManagerService extends ILocationManager.Stub {
} else if (action.equals(GpsLocationProvider.GPS_ENABLED_CHANGE_ACTION)) {
- final boolean enabled = intent.getBooleanExtra(GpsLocationProvider.EXTRA_ENABLED, false);
+ final boolean enabled = intent.getBooleanExtra(GpsLocationProvider.EXTRA_ENABLED,
+ false);
if (!enabled) {
// When GPS is disabled, we are OK to release wake-lock
@@ -1608,7 +1739,7 @@ public class LocationManagerService extends ILocationManager.Stub {
if (screenOn) {
startGps();
} else if (mScreenOn && !screenOn) {
-
+
// We just turned the screen off so stop navigating
stopGps();
}
@@ -1641,13 +1772,23 @@ public class LocationManagerService extends ILocationManager.Stub {
}
private void acquireWakeLock() {
+ try {
+ acquireWakeLockX();
+ } catch (Exception e) {
+ // This is to catch a runtime exception thrown when we try to release an
+ // already released lock.
+ Log.e(TAG, "exception in acquireWakeLock()", e);
+ }
+ }
+
+ private void acquireWakeLockX() {
if (mWakeLock.isHeld()) {
log("Must release wakelock before acquiring");
mWakeLockAcquireTime = 0;
mWakeLock.release();
}
- boolean networkActive = (mNetworkLocationProvider != null)
+ boolean networkActive = (mNetworkLocationProvider != null)
&& mNetworkLocationProvider.isLocationTracking();
boolean gpsActive = (mGpsLocationProvider != null)
&& mGpsLocationProvider.isLocationTracking();
@@ -1668,7 +1809,7 @@ public class LocationManagerService extends ILocationManager.Stub {
// Start the gps provider
startGps();
-
+
// Acquire cell lock
if (mCellWakeLockAcquired) {
// Lock is already acquired
@@ -1700,7 +1841,7 @@ public class LocationManagerService extends ILocationManager.Stub {
}
private void startGps() {
- boolean gpsActive = (mGpsLocationProvider != null)
+ boolean gpsActive = (mGpsLocationProvider != null)
&& mGpsLocationProvider.isLocationTracking();
if (gpsActive) {
mGpsLocationProvider.startNavigating();
@@ -1708,7 +1849,7 @@ public class LocationManagerService extends ILocationManager.Stub {
}
private void stopGps() {
- boolean gpsActive = mGpsLocationProvider != null
+ boolean gpsActive = mGpsLocationProvider != null
&& mGpsLocationProvider.isLocationTracking();
if (gpsActive) {
mGpsLocationProvider.stopNavigating();
@@ -1716,6 +1857,16 @@ public class LocationManagerService extends ILocationManager.Stub {
}
private void releaseWakeLock() {
+ try {
+ releaseWakeLockX();
+ } catch (Exception e) {
+ // This is to catch a runtime exception thrown when we try to release an
+ // already released lock.
+ Log.e(TAG, "exception in releaseWakeLock()", e);
+ }
+ }
+
+ private void releaseWakeLockX() {
// Release wifi lock
WifiManager.WifiLock wifiLock = getWifiWakelock();
if (wifiLock != null) {
@@ -1726,22 +1877,22 @@ public class LocationManagerService extends ILocationManager.Stub {
}
if (!mScreenOn) {
-
+
// Stop the gps
stopGps();
}
-
+
// Release cell lock
if (mCellWakeLockAcquired) {
mTelephonyManager.disableLocationUpdates();
mCellWakeLockAcquired = false;
}
-
+
// Notify NetworkLocationProvider
if (mNetworkLocationProvider != null) {
mNetworkLocationProvider.updateCellLockStatus(mCellWakeLockAcquired);
}
-
+
// Release wake lock
mWakeLockAcquireTime = 0;
if (mWakeLock.isHeld()) {
@@ -1751,7 +1902,7 @@ public class LocationManagerService extends ILocationManager.Stub {
log("Can't release wakelock again!");
}
}
-
+
// Geocoder
public String getFromLocation(double latitude, double longitude, int maxResults,
@@ -1903,14 +2054,29 @@ public class LocationManagerService extends ILocationManager.Stub {
return mSupportsSpeed;
}
}
+
+ private void checkMockPermissions() {
+ boolean allowMocks = false;
+ try {
+ allowMocks = Settings.Secure.getInt(mContext.getContentResolver(),
+ Settings.Secure.ALLOW_MOCK_LOCATION) == 1;
+ } catch (SettingNotFoundException e) {
+ // Do nothing
+ }
+ if (!allowMocks) {
+ throw new SecurityException("Requires ACCESS_MOCK_LOCATION secure setting");
+ }
- public void addTestProvider(String name, boolean requiresNetwork, boolean requiresSatellite,
- boolean requiresCell, boolean hasMonetaryCost, boolean supportsAltitude,
- boolean supportsSpeed, boolean supportsBearing, int powerRequirement, int accuracy) {
if (mContext.checkCallingPermission(ACCESS_MOCK_LOCATION) !=
PackageManager.PERMISSION_GRANTED) {
throw new SecurityException("Requires ACCESS_MOCK_LOCATION permission");
- }
+ }
+ }
+
+ public void addTestProvider(String name, boolean requiresNetwork, boolean requiresSatellite,
+ boolean requiresCell, boolean hasMonetaryCost, boolean supportsAltitude,
+ boolean supportsSpeed, boolean supportsBearing, int powerRequirement, int accuracy) {
+ checkMockPermissions();
MockProvider provider = new MockProvider(name, requiresNetwork, requiresSatellite,
requiresCell, hasMonetaryCost, supportsAltitude,
@@ -1923,10 +2089,7 @@ public class LocationManagerService extends ILocationManager.Stub {
}
public void removeTestProvider(String provider) {
- if (mContext.checkCallingPermission(ACCESS_MOCK_LOCATION) !=
- PackageManager.PERMISSION_GRANTED) {
- throw new SecurityException("Requires ACCESS_MOCK_LOCATION permission");
- }
+ checkMockPermissions();
LocationProviderImpl p = LocationProviderImpl.getProvider(provider);
if (p == null) {
throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
@@ -1936,10 +2099,7 @@ public class LocationManagerService extends ILocationManager.Stub {
}
public void setTestProviderLocation(String provider, Location loc) {
- if (mContext.checkCallingPermission(ACCESS_MOCK_LOCATION) !=
- PackageManager.PERMISSION_GRANTED) {
- throw new SecurityException("Requires ACCESS_MOCK_LOCATION permission");
- }
+ checkMockPermissions();
if (LocationProviderImpl.getProvider(provider) == null) {
throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
}
@@ -1947,10 +2107,7 @@ public class LocationManagerService extends ILocationManager.Stub {
}
public void clearTestProviderLocation(String provider) {
- if (mContext.checkCallingPermission(ACCESS_MOCK_LOCATION) !=
- PackageManager.PERMISSION_GRANTED) {
- throw new SecurityException("Requires ACCESS_MOCK_LOCATION permission");
- }
+ checkMockPermissions();
if (LocationProviderImpl.getProvider(provider) == null) {
throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
}
@@ -1958,10 +2115,7 @@ public class LocationManagerService extends ILocationManager.Stub {
}
public void setTestProviderEnabled(String provider, boolean enabled) {
- if (mContext.checkCallingPermission(ACCESS_MOCK_LOCATION) !=
- PackageManager.PERMISSION_GRANTED) {
- throw new SecurityException("Requires ACCESS_MOCK_LOCATION permission");
- }
+ checkMockPermissions();
if (LocationProviderImpl.getProvider(provider) == null) {
throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
}
@@ -1976,10 +2130,7 @@ public class LocationManagerService extends ILocationManager.Stub {
}
public void clearTestProviderEnabled(String provider) {
- if (mContext.checkCallingPermission(ACCESS_MOCK_LOCATION) !=
- PackageManager.PERMISSION_GRANTED) {
- throw new SecurityException("Requires ACCESS_MOCK_LOCATION permission");
- }
+ checkMockPermissions();
if (LocationProviderImpl.getProvider(provider) == null) {
throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
}
@@ -1989,10 +2140,7 @@ public class LocationManagerService extends ILocationManager.Stub {
}
public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime) {
- if (mContext.checkCallingPermission(ACCESS_MOCK_LOCATION) !=
- PackageManager.PERMISSION_GRANTED) {
- throw new SecurityException("Requires ACCESS_MOCK_LOCATION permission");
- }
+ checkMockPermissions();
if (LocationProviderImpl.getProvider(provider) == null) {
throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
}
@@ -2002,10 +2150,7 @@ public class LocationManagerService extends ILocationManager.Stub {
}
public void clearTestProviderStatus(String provider) {
- if (mContext.checkCallingPermission(ACCESS_MOCK_LOCATION) !=
- PackageManager.PERMISSION_GRANTED) {
- throw new SecurityException("Requires ACCESS_MOCK_LOCATION permission");
- }
+ checkMockPermissions();
if (LocationProviderImpl.getProvider(provider) == null) {
throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
}
diff --git a/services/java/com/android/server/MountService.java b/services/java/com/android/server/MountService.java
index 6f29332..03480d1 100644
--- a/services/java/com/android/server/MountService.java
+++ b/services/java/com/android/server/MountService.java
@@ -22,6 +22,7 @@ import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
+import android.content.res.Resources;
import android.net.Uri;
import android.os.IMountService;
import android.os.Environment;
@@ -59,10 +60,11 @@ class MountService extends IMountService.Stub {
private Notification mUsbStorageNotification;
private class SdDoorListener extends UEventObserver {
- static final String SD_DOOR_UEVENT_MATCH = "DEVPATH=/class/switch/sd-door";
+ static final String SD_DOOR_UEVENT_MATCH = "DEVPATH=/devices/virtual/switch/sd-door";
+ static final String SD_DOOR_SWITCH_NAME = "sd-door";
public void onUEvent(UEvent event) {
- if ("sd-door".equals(event.get("SWITCH_NAME"))) {
+ if (SD_DOOR_SWITCH_NAME.equals(event.get("SWITCH_NAME"))) {
sdDoorStateChanged(event.get("SWITCH_STATE"));
}
}
@@ -127,9 +129,7 @@ class MountService extends IMountService.Stub {
throw new SecurityException("Requires MOUNT_UNMOUNT_FILESYSTEMS permission");
}
- // notify listeners that we are trying to eject
- notifyMediaEject(mountPath);
- // tell usbd to unmount the media
+ // tell mountd to unmount the media
mListener.ejectMedia(mountPath);
}
@@ -269,22 +269,24 @@ class MountService extends IMountService.Stub {
* @return A {@link Notification} that leads to the dialog to enable USB storage.
*/
private synchronized Notification getUsbStorageNotification() {
+ Resources r = Resources.getSystem();
+ CharSequence title =
+ r.getText(com.android.internal.R.string.usb_storage_notification_title);
+ CharSequence message =
+ r.getText(com.android.internal.R.string.usb_storage_notification_message);
+
if (mUsbStorageNotification == null) {
- CharSequence title =
- mContext.getString(com.android.internal.R.string.usb_storage_notification_title);
- CharSequence message =
- mContext.getString(com.android.internal.R.string.usb_storage_notification_message);
-
mUsbStorageNotification = new Notification();
mUsbStorageNotification.icon = com.android.internal.R.drawable.stat_sys_data_usb;
- mUsbStorageNotification.tickerText = title;
mUsbStorageNotification.when = 0;
mUsbStorageNotification.flags = Notification.FLAG_AUTO_CANCEL;
mUsbStorageNotification.defaults |= Notification.DEFAULT_SOUND;
- mUsbStorageNotification.setLatestEventInfo(mContext, title, message,
- getUsbStorageDialogIntent());
}
+ mUsbStorageNotification.tickerText = title;
+ mUsbStorageNotification.setLatestEventInfo(mContext, title, message,
+ getUsbStorageDialogIntent());
+
return mUsbStorageNotification;
}
diff --git a/services/java/com/android/server/NotificationManagerService.java b/services/java/com/android/server/NotificationManagerService.java
index 14ac1be..eb9ebe9 100644
--- a/services/java/com/android/server/NotificationManagerService.java
+++ b/services/java/com/android/server/NotificationManagerService.java
@@ -72,7 +72,7 @@ class NotificationManagerService extends INotificationManager.Stub
private static final long[] DEFAULT_VIBRATE_PATTERN = {0, 250, 250, 250};
- private static final int DEFAULT_STREAM_TYPE = AudioManager.STREAM_RING;
+ private static final int DEFAULT_STREAM_TYPE = AudioManager.STREAM_NOTIFICATION;
final Context mContext;
final IActivityManager mAm;
diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java
index c000d8a..e86ff02 100644
--- a/services/java/com/android/server/PackageManagerService.java
+++ b/services/java/com/android/server/PackageManagerService.java
@@ -55,6 +55,7 @@ import android.content.pm.ProviderInfo;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.content.pm.Signature;
+import android.content.pm.PackageParser.Package;
import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
@@ -177,7 +178,7 @@ class PackageManagerService extends IPackageManager.Stub {
// Lock for state used when installing and doing other long running
// operations. Methods that must be called with this lock held have
// the prefix "LI".
- Object mInstallLock = new Object();
+ final Object mInstallLock = new Object();
// These are the directories in the 3rd party applications installed dir
// that we have currently loaded packages from. Keys are the application's
@@ -674,7 +675,7 @@ class PackageManagerService extends IPackageManager.Stub {
}
}
- int[] appendInt(int[] cur, int val) {
+ static int[] appendInt(int[] cur, int val) {
if (cur == null) {
return new int[] { val };
}
@@ -690,7 +691,7 @@ class PackageManagerService extends IPackageManager.Stub {
return ret;
}
- int[] appendInts(int[] cur, int[] add) {
+ static int[] appendInts(int[] cur, int[] add) {
if (add == null) return cur;
if (cur == null) return add;
final int N = add.length;
@@ -718,6 +719,9 @@ class PackageManagerService extends IPackageManager.Stub {
if (p != null) {
return generatePackageInfo(p, flags);
}
+ if((flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0) {
+ return generatePackageInfoFromSettingsLP(packageName, flags);
+ }
}
return null;
}
@@ -725,6 +729,14 @@ class PackageManagerService extends IPackageManager.Stub {
public int getPackageUid(String packageName) {
synchronized (mPackages) {
PackageParser.Package p = mPackages.get(packageName);
+ if(p != null) {
+ return p.applicationInfo.uid;
+ }
+ PackageSetting ps = mSettings.mPackages.get(packageName);
+ if((ps == null) || (ps.pkg == null) || (ps.pkg.applicationInfo == null)) {
+ return -1;
+ }
+ p = ps.pkg;
return p != null ? p.applicationInfo.uid : -1;
}
}
@@ -796,12 +808,39 @@ class PackageManagerService extends IPackageManager.Stub {
}
}
+ private ApplicationInfo generateApplicationInfoFromSettingsLP(String packageName, int flags) {
+ PackageSetting ps = mSettings.mPackages.get(packageName);
+ if(ps != null) {
+ if(ps.pkg == null) {
+ PackageInfo pInfo = generatePackageInfoFromSettingsLP(packageName, flags);
+ if(pInfo != null) {
+ return pInfo.applicationInfo;
+ }
+ return null;
+ }
+ return PackageParser.generateApplicationInfo(ps.pkg, flags);
+ }
+ return null;
+ }
+
+ private PackageInfo generatePackageInfoFromSettingsLP(String packageName, int flags) {
+ PackageSetting ps = mSettings.mPackages.get(packageName);
+ if(ps != null) {
+ if(ps.pkg == null) {
+ ps.pkg = new PackageParser.Package(packageName);
+ ps.pkg.applicationInfo.packageName = packageName;
+ }
+ return generatePackageInfo(ps.pkg, flags);
+ }
+ return null;
+ }
+
public ApplicationInfo getApplicationInfo(String packageName, int flags) {
synchronized (mPackages) {
PackageParser.Package p = mPackages.get(packageName);
if (Config.LOGV) Log.v(
- TAG, "getApplicationInfo " + packageName
- + ": " + p);
+ TAG, "getApplicationInfo " + packageName
+ + ": " + p);
if (p != null) {
// Note: isEnabledLP() does not apply here - always return info
return PackageParser.generateApplicationInfo(p, flags);
@@ -809,10 +848,14 @@ class PackageManagerService extends IPackageManager.Stub {
if ("android".equals(packageName)||"system".equals(packageName)) {
return mAndroidApplication;
}
+ if((flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0) {
+ return generateApplicationInfoFromSettingsLP(packageName, flags);
+ }
}
return null;
}
+
public void freeApplicationCache(final long freeStorageSize, final IPackageDataObserver observer) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.CLEAR_APP_CACHE, null);
@@ -1063,6 +1106,19 @@ class PackageManagerService extends IPackageManager.Stub {
}
return null;
}
+
+ public int getUidForSharedUser(String sharedUserName) {
+ if(sharedUserName == null) {
+ return -1;
+ }
+ synchronized (mPackages) {
+ SharedUserSetting suid = mSettings.getSharedUserLP(sharedUserName, 0, false);
+ if(suid == null) {
+ return -1;
+ }
+ return suid.userId;
+ }
+ }
public ResolveInfo resolveIntent(Intent intent, String resolvedType,
int flags) {
@@ -1391,37 +1447,63 @@ class PackageManagerService extends IPackageManager.Stub {
queryIntent(null, intent, resolvedType, flags);
}
}
-
+
public List<PackageInfo> getInstalledPackages(int flags) {
ArrayList<PackageInfo> finalList = new ArrayList<PackageInfo>();
synchronized (mPackages) {
- Iterator<PackageParser.Package> i = mPackages.values().iterator();
- while (i.hasNext()) {
- final PackageParser.Package p = i.next();
- PackageInfo pi = generatePackageInfo(p, flags);
- if (pi != null) {
- finalList.add(pi);
+ if((flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0) {
+ Iterator<PackageSetting> i = mSettings.mPackages.values().iterator();
+ while (i.hasNext()) {
+ final PackageSetting ps = i.next();
+ PackageInfo psPkg = generatePackageInfoFromSettingsLP(ps.name, flags);
+ if(psPkg != null) {
+ finalList.add(psPkg);
+ }
+ }
+ }
+ else {
+ Iterator<PackageParser.Package> i = mPackages.values().iterator();
+ while (i.hasNext()) {
+ final PackageParser.Package p = i.next();
+ if (p.applicationInfo != null) {
+ PackageInfo pi = generatePackageInfo(p, flags);
+ if(pi != null) {
+ finalList.add(pi);
+ }
+ }
}
}
}
-
return finalList;
}
public List<ApplicationInfo> getInstalledApplications(int flags) {
ArrayList<ApplicationInfo> finalList = new ArrayList<ApplicationInfo>();
-
- synchronized (mPackages) {
- Iterator<PackageParser.Package> i = mPackages.values().iterator();
- while (i.hasNext()) {
- final PackageParser.Package p = i.next();
- if (p.applicationInfo != null) {
- finalList.add(p.applicationInfo);
+ synchronized(mPackages) {
+ if((flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0) {
+ Iterator<PackageSetting> i = mSettings.mPackages.values().iterator();
+ while (i.hasNext()) {
+ final PackageSetting ps = i.next();
+ ApplicationInfo ai = generateApplicationInfoFromSettingsLP(ps.name, flags);
+ if(ai != null) {
+ finalList.add(ai);
+ }
+ }
+ }
+ else {
+ Iterator<PackageParser.Package> i = mPackages.values().iterator();
+ while (i.hasNext()) {
+ final PackageParser.Package p = i.next();
+ if (p.applicationInfo != null) {
+ ApplicationInfo ai = PackageParser.generateApplicationInfo(p, flags);
+ if(ai != null) {
+ finalList.add(ai);
+ }
+ }
}
}
}
-
return finalList;
}
@@ -1569,7 +1651,7 @@ class PackageManagerService extends IPackageManager.Stub {
PackageParser.Package pkg, File srcFile, int parseFlags) {
if (GET_CERTIFICATES) {
if (ps == null || !ps.codePath.equals(srcFile)
- || ps.timeStamp != srcFile.lastModified()) {
+ || ps.getTimeStamp() != srcFile.lastModified()) {
Log.i(TAG, srcFile.toString() + " changed; collecting certs");
if (!pp.collectCertificates(pkg, parseFlags)) {
mLastScanError = pp.getParseError();
@@ -1580,6 +1662,10 @@ class PackageManagerService extends IPackageManager.Stub {
return true;
}
+ /*
+ * Scan a package and return the newly parsed package.
+ * Returns null in case of errors and the error code is stored in mLastScanError
+ */
private PackageParser.Package scanPackageLI(File scanFile,
File destCodeFile, File destResourceFile, int parseFlags,
int scanMode) {
@@ -1595,11 +1681,29 @@ class PackageManagerService extends IPackageManager.Stub {
return null;
}
PackageSetting ps;
+ PackageSetting updatedPkg;
synchronized (mPackages) {
ps = mSettings.peekPackageLP(pkg.packageName,
scanFile.toString());
+ updatedPkg = mSettings.mDisabledSysPackages.get(pkg.packageName);
+ }
+ if (updatedPkg != null) {
+ // An updated system app will not have the PARSE_IS_SYSTEM flag set initially
+ parseFlags |= PackageParser.PARSE_IS_SYSTEM;
+ }
+ if ((parseFlags&PackageParser.PARSE_IS_SYSTEM) != 0) {
+ // Check for updated system applications here
+ if ((updatedPkg != null) && (ps == null)) {
+ // The system package has been updated and the code path does not match
+ // Ignore entry. Just return
+ Log.w(TAG, "Package:" + pkg.packageName +
+ " has been updated. Ignoring the one from path:"+scanFile);
+ mLastScanError = PackageManager.INSTALL_FAILED_DUPLICATE_PACKAGE;
+ return null;
+ }
}
if (!collectCertificatesLI(pp, ps, pkg, scanFile, parseFlags)) {
+ Log.i(TAG, "Failed verifying certificates for package:" + pkg.packageName);
return null;
}
// The apk is forward locked (not public) if its code and resources
@@ -1607,6 +1711,7 @@ class PackageManagerService extends IPackageManager.Stub {
if (ps != null && !ps.codePath.equals(ps.resourcePath)) {
scanMode |= SCAN_FORWARD_LOCKED;
}
+ // Note that we invoke the following method only if we are about to unpack an application
return scanPackageLI(scanFile, destCodeFile, destResourceFile,
pkg, parseFlags, scanMode | SCAN_UPDATE_SIGNATURE);
}
@@ -1652,6 +1757,7 @@ class PackageManagerService extends IPackageManager.Stub {
mScanningPath = scanFile;
if (pkg == null) {
+ mLastScanError = PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME;
return null;
}
@@ -1681,7 +1787,7 @@ class PackageManagerService extends IPackageManager.Stub {
mResolveActivity.packageName = mAndroidApplication.packageName;
mResolveActivity.processName = mAndroidApplication.processName;
mResolveActivity.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
- mResolveActivity.flags = 0;
+ mResolveActivity.flags = ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS;
mResolveActivity.theme = com.android.internal.R.style.Theme_Dialog_Alert;
mResolveActivity.exported = true;
mResolveActivity.enabled = true;
@@ -1748,6 +1854,11 @@ class PackageManagerService extends IPackageManager.Stub {
mLastScanError = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
return null;
}
+ synchronized(mPackages) {
+ if(mSettings.mDisabledSysPackages.get(pkg.packageName) != null) {
+ pkg.applicationInfo.flags |= ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
+ }
+ }
pkg.applicationInfo.uid = pkgSetting.userId;
pkg.mExtras = pkgSetting;
@@ -1755,6 +1866,7 @@ class PackageManagerService extends IPackageManager.Stub {
if (!verifySignaturesLP(pkgSetting, pkg, parseFlags,
(scanMode&SCAN_UPDATE_SIGNATURE) != 0)) {
if ((parseFlags&PackageParser.PARSE_IS_SYSTEM) == 0) {
+ mLastScanError = PackageManager.INSTALL_FAILED_UPDATE_INCOMPATIBLE;
return null;
}
// The signature has changed, but this package is in the system
@@ -1768,6 +1880,7 @@ class PackageManagerService extends IPackageManager.Stub {
if (pkgSetting.sharedUser != null) {
if (!pkgSetting.sharedUser.signatures.mergeSignatures(
pkg.mSignatures, false)) {
+ mLastScanError = PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES;
return null;
}
}
@@ -1782,6 +1895,7 @@ class PackageManagerService extends IPackageManager.Stub {
String msg = "System package " + pkg.packageName
+ " could not have data directory erased after signature change.";
reportSettingsProblem(Log.WARN, msg);
+ mLastScanError = PackageManager.INSTALL_FAILED_REPLACE_COULDNT_DELETE;
return null;
}
}
@@ -1792,7 +1906,7 @@ class PackageManagerService extends IPackageManager.Stub {
long scanFileTime = scanFile.lastModified();
final boolean forceDex = (scanMode&SCAN_FORCE_DEX) != 0;
- final boolean scanFileNewer = forceDex || scanFileTime != pkgSetting.timeStamp;
+ final boolean scanFileNewer = forceDex || scanFileTime != pkgSetting.getTimeStamp();
// At this point we know it is okay to accept the package, though
// errors can still happen as we try to install...
@@ -3037,48 +3151,363 @@ class PackageManagerService extends IPackageManager.Stub {
PackageRemovedInfo removedInfo;
}
- PackageInstalledInfo installPackageLI(Uri packageURI, int flags) {
- int returnCode = PackageManager.INSTALL_SUCCEEDED;
- String installedPackageName = null;
- int installedPackageUid = -1;
- PackageParser.Package installedPackage = null;
+ /*
+ * Install a non-existing package.
+ */
+ private void installNewPackageLI(String pkgName, int parseFlags,
+ File tmpPackageFile,
+ String destFilePath, File destPackageFile, File destResourceFile,
+ PackageParser.Package pkg, boolean forwardLocked,
+ PackageInstalledInfo res) {
+ // Remember this for later, in case we need to rollback this install
+ boolean dataDirExists = (new File(mAppDataDir, pkgName)).exists();
+ res.name = pkgName;
+ synchronized(mPackages) {
+ if (mPackages.containsKey(pkgName) || mAppDirs.containsKey(destFilePath)) {
+ // Don't allow installation over an existing package with the same name.
+ Log.w(TAG, "Attempt to re-install " + pkgName
+ + " without first uninstalling.");
+ res.returnCode = PackageManager.INSTALL_FAILED_ALREADY_EXISTS;
+ return;
+ }
+ }
+ if (destPackageFile.exists()) {
+ // It's safe to do this because we know (from the above check) that the file
+ // isn't currently used for an installed package.
+ destPackageFile.delete();
+ }
+ mLastScanError = PackageManager.INSTALL_SUCCEEDED;
+ PackageParser.Package newPackage = scanPackageLI(tmpPackageFile, destPackageFile,
+ destResourceFile, pkg, parseFlags,
+ SCAN_MONITOR | SCAN_FORCE_DEX
+ | SCAN_UPDATE_SIGNATURE
+ | (forwardLocked ? SCAN_FORWARD_LOCKED : 0));
+ if (newPackage == null) {
+ Log.w(TAG, "Package couldn't be installed in " + destPackageFile);
+ if ((res.returnCode=mLastScanError) == PackageManager.INSTALL_SUCCEEDED) {
+ res.returnCode = PackageManager.INSTALL_FAILED_INVALID_APK;
+ }
+ } else {
+ updateSettingsLI(pkgName, tmpPackageFile,
+ destFilePath, destPackageFile,
+ destResourceFile, pkg,
+ newPackage,
+ true,
+ forwardLocked,
+ res);
+ // delete the partially installed application. the data directory will have to be
+ // restored if it was already existing
+ if (res.returnCode != PackageManager.INSTALL_SUCCEEDED) {
+ // remove package from internal structures. Note that we want deletePackageX to
+ // delete the package data and cache directories that it created in
+ // scanPackageLocked, unless those directories existed before we even tried to
+ // install.
+ deletePackageLI(
+ pkgName, true,
+ dataDirExists ? PackageManager.DONT_DELETE_DATA : 0,
+ res.removedInfo);
+ }
+ }
+ }
+
+ private void replacePackageLI(String pkgName, int parseFlags,
+ File tmpPackageFile,
+ String destFilePath, File destPackageFile, File destResourceFile,
+ PackageParser.Package pkg, boolean forwardLocked,
+ PackageInstalledInfo res) {
+ PackageParser.Package deletedPackage;
+ // First find the old package info and check signatures
+ synchronized(mPackages) {
+ deletedPackage = mPackages.get(pkgName);
+ if(checkSignaturesLP(pkg, deletedPackage) != PackageManager.SIGNATURE_MATCH) {
+ res.returnCode = PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES;
+ return;
+ }
+ }
+ boolean sysPkg = ((deletedPackage.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0);
+ if(sysPkg) {
+ replaceSystemPackageLI(deletedPackage,
+ parseFlags,
+ tmpPackageFile, destFilePath,
+ destPackageFile, destResourceFile, pkg, forwardLocked, res);
+ } else {
+ replaceNonSystemPackageLI(deletedPackage, parseFlags, tmpPackageFile, destFilePath,
+ destPackageFile, destResourceFile, pkg, forwardLocked, res);
+ }
+ }
+
+ private void replaceNonSystemPackageLI(PackageParser.Package deletedPackage, int parseFlags,
+ File tmpPackageFile,
+ String destFilePath, File destPackageFile, File destResourceFile,
+ PackageParser.Package pkg, boolean forwardLocked,
+ PackageInstalledInfo res) {
+ PackageParser.Package newPackage = null;
+ String pkgName = deletedPackage.packageName;
+ boolean deletedPkg = true;
+ boolean updatedSettings = false;
+ // First delete the existing package while retaining the data directory
+ if (!deletePackageLI(pkgName, false, PackageManager.DONT_DELETE_DATA,
+ res.removedInfo)) {
+ // If the existing package was'nt successfully deleted
+ res.returnCode = PackageManager.INSTALL_FAILED_REPLACE_COULDNT_DELETE;
+ deletedPkg = false;
+ } else {
+ // Successfully deleted the old package. Now proceed with re-installation
+ mLastScanError = PackageManager.INSTALL_SUCCEEDED;
+ newPackage = scanPackageLI(tmpPackageFile, destPackageFile,
+ destResourceFile, pkg, parseFlags,
+ SCAN_MONITOR | SCAN_FORCE_DEX
+ | SCAN_UPDATE_SIGNATURE
+ | (forwardLocked ? SCAN_FORWARD_LOCKED : 0));
+ if (newPackage == null) {
+ Log.w(TAG, "Package couldn't be installed in " + destPackageFile);
+ if ((res.returnCode=mLastScanError) == PackageManager.INSTALL_SUCCEEDED) {
+ res.returnCode = PackageManager.INSTALL_FAILED_INVALID_APK;
+ }
+ } else {
+ updateSettingsLI(pkgName, tmpPackageFile,
+ destFilePath, destPackageFile,
+ destResourceFile, pkg,
+ newPackage,
+ true,
+ forwardLocked,
+ res);
+ updatedSettings = true;
+ }
+ }
+
+ if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
+ // If we deleted an exisiting package, the old source and resource files that we
+ // were keeping around in case we needed them (see below) can now be deleted
+ final ApplicationInfo deletedPackageAppInfo = deletedPackage.applicationInfo;
+ final ApplicationInfo installedPackageAppInfo =
+ newPackage.applicationInfo;
+ if (!deletedPackageAppInfo.sourceDir
+ .equals(installedPackageAppInfo.sourceDir)) {
+ new File(deletedPackageAppInfo.sourceDir).delete();
+ }
+ if (!deletedPackageAppInfo.publicSourceDir
+ .equals(installedPackageAppInfo.publicSourceDir)) {
+ new File(deletedPackageAppInfo.publicSourceDir).delete();
+ }
+ //update signature on the new package setting
+ //this should always succeed, since we checked the
+ //signature earlier.
+ synchronized(mPackages) {
+ verifySignaturesLP(mSettings.mPackages.get(pkgName), pkg,
+ parseFlags, true);
+ }
+ } else {
+ // remove package from internal structures. Note that we want deletePackageX to
+ // delete the package data and cache directories that it created in
+ // scanPackageLocked, unless those directories existed before we even tried to
+ // install.
+ if(updatedSettings) {
+ deletePackageLI(
+ pkgName, true,
+ PackageManager.DONT_DELETE_DATA,
+ res.removedInfo);
+ }
+ // Since we failed to install the new package we need to restore the old
+ // package that we deleted.
+ if(deletedPkg) {
+ installPackageLI(
+ Uri.fromFile(new File(deletedPackage.mPath)),
+ isForwardLocked(deletedPackage)
+ ? PackageManager.FORWARD_LOCK_PACKAGE
+ : 0);
+ }
+ }
+ }
+
+ private void replaceSystemPackageLI(PackageParser.Package deletedPackage, int parseFlags,
+ File tmpPackageFile,
+ String destFilePath, File destPackageFile, File destResourceFile,
+ PackageParser.Package pkg, boolean forwardLocked,
+ PackageInstalledInfo res) {
+ PackageParser.Package newPackage = null;
+ boolean updatedSettings = false;
+ parseFlags |= PackageParser.PARSE_IS_SYSTEM;
+ String packageName = deletedPackage.packageName;
+ res.returnCode = PackageManager.INSTALL_FAILED_REPLACE_COULDNT_DELETE;
+ if (packageName == null) {
+ Log.w(TAG, "Attempt to delete null packageName.");
+ return;
+ }
+ PackageParser.Package oldPkg;
+ PackageSetting oldPkgSetting;
+ synchronized (mPackages) {
+ oldPkg = mPackages.get(packageName);
+ oldPkgSetting = mSettings.mPackages.get(packageName);
+ if((oldPkg == null) || (oldPkg.applicationInfo == null) ||
+ (oldPkgSetting == null)) {
+ Log.w(TAG, "Could'nt find package:"+packageName+" information");
+ return;
+ }
+ }
+ res.removedInfo.uid = oldPkg.applicationInfo.uid;
+ res.removedInfo.removedPackage = packageName;
+ // Remove existing system package
+ removePackageLI(oldPkg, true);
+ synchronized (mPackages) {
+ res.removedInfo.removedUid = mSettings.disableSystemPackageLP(packageName);
+ }
+
+ // Successfully disabled the old package. Now proceed with re-installation
+ mLastScanError = PackageManager.INSTALL_SUCCEEDED;
+ pkg.applicationInfo.flags |= ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
+ newPackage = scanPackageLI(tmpPackageFile, destPackageFile,
+ destResourceFile, pkg, parseFlags,
+ SCAN_MONITOR | SCAN_FORCE_DEX
+ | SCAN_UPDATE_SIGNATURE
+ | (forwardLocked ? SCAN_FORWARD_LOCKED : 0));
+ if (newPackage == null) {
+ Log.w(TAG, "Package couldn't be installed in " + destPackageFile);
+ if ((res.returnCode=mLastScanError) == PackageManager.INSTALL_SUCCEEDED) {
+ res.returnCode = PackageManager.INSTALL_FAILED_INVALID_APK;
+ }
+ } else {
+ updateSettingsLI(packageName, tmpPackageFile,
+ destFilePath, destPackageFile,
+ destResourceFile, pkg,
+ newPackage,
+ true,
+ forwardLocked,
+ res);
+ updatedSettings = true;
+ }
+
+ if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
+ //update signature on the new package setting
+ //this should always succeed, since we checked the
+ //signature earlier.
+ synchronized(mPackages) {
+ verifySignaturesLP(mSettings.mPackages.get(packageName), pkg,
+ parseFlags, true);
+ }
+ } else {
+ // Re installation failed. Restore old information
+ // Remove new pkg information
+ removePackageLI(newPackage, true);
+ // Add back the old system package
+ scanPackageLI(oldPkgSetting.codePath, oldPkgSetting.codePath,
+ oldPkgSetting.resourcePath,
+ oldPkg, parseFlags,
+ SCAN_MONITOR
+ | SCAN_UPDATE_SIGNATURE
+ | (forwardLocked ? SCAN_FORWARD_LOCKED : 0));
+ // Restore the old system information in Settings
+ synchronized(mPackages) {
+ if(updatedSettings) {
+ mSettings.enableSystemPackageLP(packageName);
+ }
+ mSettings.writeLP();
+ }
+ }
+ }
+
+ private void updateSettingsLI(String pkgName, File tmpPackageFile,
+ String destFilePath, File destPackageFile,
+ File destResourceFile,
+ PackageParser.Package pkg,
+ PackageParser.Package newPackage,
+ boolean replacingExistingPackage,
+ boolean forwardLocked,
+ PackageInstalledInfo res) {
+ synchronized (mPackages) {
+ //write settings. the installStatus will be incomplete at this stage.
+ //note that the new package setting would have already been
+ //added to mPackages. It hasn't been persisted yet.
+ mSettings.setInstallStatus(pkgName, PKG_INSTALL_INCOMPLETE);
+ mSettings.writeLP();
+ }
+
+ int retCode = 0;
+ if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_HAS_CODE) != 0) {
+ retCode = mInstaller.movedex(tmpPackageFile.toString(),
+ destPackageFile.toString());
+ if (retCode != 0) {
+ Log.e(TAG, "Couldn't rename dex file: " + destPackageFile);
+ res.returnCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
+ return;
+ }
+ }
+ // XXX There are probably some big issues here: upon doing
+ // the rename, we have reached the point of no return (the
+ // original .apk is gone!), so we can't fail. Yet... we can.
+ if (!tmpPackageFile.renameTo(destPackageFile)) {
+ Log.e(TAG, "Couldn't move package file to: " + destPackageFile);
+ res.returnCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
+ } else {
+ res.returnCode = setPermissionsLI(pkgName, newPackage, destFilePath,
+ destResourceFile,
+ forwardLocked);
+ if(res.returnCode != PackageManager.INSTALL_SUCCEEDED) {
+ return;
+ } else {
+ Log.d(TAG, "New package installed in " + destPackageFile);
+ }
+ }
+ if(res.returnCode != PackageManager.INSTALL_SUCCEEDED) {
+ if (mInstaller != null) {
+ mInstaller.rmdex(tmpPackageFile.getPath());
+ }
+ }
+
+ synchronized (mPackages) {
+ grantPermissionsLP(newPackage, true);
+ res.name = pkgName;
+ res.uid = newPackage.applicationInfo.uid;
+ res.pkg = newPackage;
+ mSettings.setInstallStatus(pkgName, PKG_INSTALL_COMPLETE);
+ res.returnCode = PackageManager.INSTALL_SUCCEEDED;
+ //to update install status
+ mSettings.writeLP();
+ }
+ }
+
+ private PackageInstalledInfo installPackageLI(Uri pPackageURI, int pFlags) {
File tmpPackageFile = null;
- boolean wroteSettings = false;
String pkgName = null;
- PackageParser.Package newPackage = null;
- boolean dataDirExists = false;
- PackageParser.Package deletedPackage = null;
- PackageRemovedInfo removedInfo = new PackageRemovedInfo();
+ boolean forwardLocked = false;
+ boolean replacingExistingPackage = false;
+
+ // Result object to be returned
+ PackageInstalledInfo res = new PackageInstalledInfo();
+ res.returnCode = PackageManager.INSTALL_SUCCEEDED;
+ res.uid = -1;
+ res.pkg = null;
+ res.removedInfo = new PackageRemovedInfo();
main_flow: try {
tmpPackageFile = createTempPackageFile();
if (tmpPackageFile == null) {
- returnCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
+ res.returnCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
break main_flow;
}
tmpPackageFile.deleteOnExit(); // paranoia
- if (packageURI.getScheme().equals("file")) {
- final File srcPackageFile = new File(packageURI.getPath());
+ if (pPackageURI.getScheme().equals("file")) {
+ final File srcPackageFile = new File(pPackageURI.getPath());
// We copy the source package file to a temp file and then rename it to the
// destination file in order to eliminate a window where the package directory
// scanner notices the new package file but it's not completely copied yet.
if (!FileUtils.copyFile(srcPackageFile, tmpPackageFile)) {
Log.e(TAG, "Couldn't copy package file to temp file.");
- returnCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
+ res.returnCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
break main_flow;
}
- } else if (packageURI.getScheme().equals("content")) {
+ } else if (pPackageURI.getScheme().equals("content")) {
ParcelFileDescriptor fd;
try {
- fd = mContext.getContentResolver().openFileDescriptor(packageURI, "r");
+ fd = mContext.getContentResolver().openFileDescriptor(pPackageURI, "r");
} catch (FileNotFoundException e) {
Log.e(TAG, "Couldn't open file descriptor from download service.");
- returnCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
+ res.returnCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
break main_flow;
}
if (fd == null) {
Log.e(TAG, "Couldn't open file descriptor from download service (null).");
- returnCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
+ res.returnCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
break main_flow;
}
if (Config.LOGV) {
@@ -3091,36 +3520,38 @@ class PackageManagerService extends IPackageManager.Stub {
// scanner notices the new package file but it's not completely copied yet.
if (!FileUtils.copyToFile(dlStream, tmpPackageFile)) {
Log.e(TAG, "Couldn't copy package stream to temp file.");
- returnCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
+ res.returnCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
break main_flow;
}
} else {
- Log.e(TAG, "Package URI is not 'file:' or 'content:' - " + packageURI);
- returnCode = PackageManager.INSTALL_FAILED_INVALID_URI;
+ Log.e(TAG, "Package URI is not 'file:' or 'content:' - " + pPackageURI);
+ res.returnCode = PackageManager.INSTALL_FAILED_INVALID_URI;
break main_flow;
- }
+ }
pkgName = PackageParser.parsePackageName(
tmpPackageFile.getAbsolutePath(), 0);
if (pkgName == null) {
Log.e(TAG, "Couldn't find a package name in : " + tmpPackageFile);
- returnCode = PackageManager.INSTALL_FAILED_INVALID_APK;
+ res.returnCode = PackageManager.INSTALL_FAILED_INVALID_APK;
break main_flow;
}
+ res.name = pkgName;
//initialize some variables before installing pkg
final String pkgFileName = pkgName + ".apk";
- final File destDir = ((flags&PackageManager.FORWARD_LOCK_PACKAGE) != 0)
+ final File destDir = ((pFlags&PackageManager.FORWARD_LOCK_PACKAGE) != 0)
? mDrmAppPrivateInstallDir
: mAppInstallDir;
final File destPackageFile = new File(destDir, pkgFileName);
final String destFilePath = destPackageFile.getAbsolutePath();
File destResourceFile;
- if ((flags&PackageManager.FORWARD_LOCK_PACKAGE) != 0) {
+ if ((pFlags&PackageManager.FORWARD_LOCK_PACKAGE) != 0) {
final String publicZipFileName = pkgName + ".zip";
destResourceFile = new File(mAppInstallDir, publicZipFileName);
+ forwardLocked = true;
} else {
destResourceFile = destPackageFile;
}
- //retrieve PackageSettings and parse package
+ // Retrieve PackageSettings and parse package
int parseFlags = PackageParser.PARSE_CHATTY;
parseFlags |= mDefParseFlags;
PackageParser pp = new PackageParser(tmpPackageFile.getPath());
@@ -3129,204 +3560,79 @@ class PackageManagerService extends IPackageManager.Stub {
final PackageParser.Package pkg = pp.parsePackage(tmpPackageFile,
destPackageFile.getAbsolutePath(), mMetrics, parseFlags);
if (pkg == null) {
- returnCode = pp.getParseError();
+ res.returnCode = pp.getParseError();
break main_flow;
}
if (GET_CERTIFICATES && !pp.collectCertificates(pkg, parseFlags)) {
- returnCode = pp.getParseError();
+ res.returnCode = pp.getParseError();
break main_flow;
}
- boolean replacingExistingPackage = false;
-
synchronized (mPackages) {
//check if installing already existing package
- if ((flags&PackageManager.REPLACE_EXISTING_PACKAGE) != 0
+ if ((pFlags&PackageManager.REPLACE_EXISTING_PACKAGE) != 0
&& mPackages.containsKey(pkgName)) {
replacingExistingPackage = true;
- deletedPackage = mPackages.get(pkgName);
- if(checkSignaturesLP(pkg, deletedPackage) != PackageManager.SIGNATURE_MATCH) {
- returnCode = PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES;
- break main_flow;
- }
- }
- }
-
- if (replacingExistingPackage) {
- if (!deletePackageLI(pkgName, false, PackageManager.DONT_DELETE_DATA,
- removedInfo)) {
- returnCode = PackageManager.INSTALL_FAILED_REPLACE_COULDNT_DELETE;
- break main_flow;
- }
- } else {
- if (mPackages.containsKey(pkgName) || mAppDirs.containsKey(destFilePath)) {
- // Don't allow installation over an existing package with the same name.
- Log.w(TAG, "Attempt to re-install " + pkgName
- + " without first uninstalling.");
- returnCode = PackageManager.INSTALL_FAILED_ALREADY_EXISTS;
- break main_flow;
- }
- if (destPackageFile.exists()) {
- // It's safe to do this because we know (from the above check) that the file
- // isn't currently used for an installed package.
- destPackageFile.delete();
- }
- }
-
- // Remember this for later, in case we need to rollback this install
- dataDirExists = (new File(mAppDataDir, pkgName)).exists();
- mLastScanError = PackageManager.INSTALL_SUCCEEDED;
- newPackage = scanPackageLI(tmpPackageFile, destPackageFile,
- destResourceFile, pkg, parseFlags,
- SCAN_MONITOR | SCAN_FORCE_DEX
- | (!replacingExistingPackage ? SCAN_UPDATE_SIGNATURE : 0)
- | ((flags&PackageManager.FORWARD_LOCK_PACKAGE) != 0
- ? SCAN_FORWARD_LOCKED : 0));
- if (newPackage == null) {
- if (Config.LOGD) {
- Log.w(TAG, "Package couldn't be installed in " + destPackageFile);
- }
- if ((returnCode=mLastScanError) == PackageManager.INSTALL_SUCCEEDED) {
- returnCode = PackageManager.INSTALL_FAILED_INVALID_APK;
}
- break main_flow;
}
- synchronized (mPackages) {
- //write settings. the installStatus will be incomplete at this stage.
- //note that the new package setting would have already been
- //added to mPackages. It hasn't been persisted yet.
- mSettings.setInstallStatus(pkgName, PKG_INSTALL_INCOMPLETE);
- mSettings.writeLP();
- wroteSettings = true;
- }
-
- int retCode = 0;
- if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_HAS_CODE) != 0) {
- retCode = mInstaller.movedex(tmpPackageFile.toString(),
- destPackageFile.toString());
- if (retCode != 0) {
- Log.e(TAG, "Couldn't rename dex file: " + destPackageFile);
- returnCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
- break main_flow;
- }
- }
- // XXX There are probably some big issues here: upon doing
- // the rename, we have reached the point of no return (the
- // original .apk is gone!), so we can't fail. Yet... we can.
- if (tmpPackageFile.renameTo(destPackageFile)) {
- if ((flags&PackageManager.FORWARD_LOCK_PACKAGE) != 0) {
- try {
- extractPublicFiles(newPackage, destResourceFile);
- } catch (IOException e) {
- Log.e(TAG, "Couldn't create a new zip file for the public parts of a" +
- " forward-locked app.");
- returnCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
- break main_flow;
- }
- if (mInstaller != null) {
- retCode = mInstaller.setForwardLockPerm(pkgName,
- newPackage.applicationInfo.uid);
- } else {
- final int filePermissions =
- FileUtils.S_IRUSR|FileUtils.S_IWUSR|FileUtils.S_IRGRP;
- retCode = FileUtils.setPermissions(destFilePath, filePermissions, -1,
- newPackage.applicationInfo.uid);
- }
- } else {
- final int filePermissions =
- FileUtils.S_IRUSR|FileUtils.S_IWUSR|FileUtils.S_IRGRP
- |FileUtils.S_IROTH;
- retCode = FileUtils.setPermissions(destFilePath, filePermissions, -1, -1);
- }
- if (retCode != 0) {
- Log.e(TAG, "Couldn't set new package file permissions for " + destFilePath
- + ". The return code was: " + retCode);
- }
- if (Config.LOGD) {
- Log.d(TAG, "New package installed in " + destPackageFile);
- }
-
- synchronized (mPackages) {
- grantPermissionsLP(newPackage, true);
- installedPackageName = pkgName;
- installedPackageUid = newPackage.applicationInfo.uid;
- installedPackage = newPackage;
- if(replacingExistingPackage) {
- //update signature on the new package setting
- //this should always succeed, since we checked the
- //signature earlier.
- verifySignaturesLP(mSettings.mPackages.get(pkgName), pkg,
- parseFlags, true);
- }
- mSettings.setInstallStatus(pkgName, PKG_INSTALL_COMPLETE);
- returnCode = PackageManager.INSTALL_SUCCEEDED;
- //to update install status
- mSettings.writeLP();
- break main_flow;
- }
+ if(replacingExistingPackage) {
+ replacePackageLI(pkgName, pFlags,
+ tmpPackageFile,
+ destFilePath, destPackageFile, destResourceFile,
+ pkg, forwardLocked,
+ res);
} else {
- Log.e(TAG, "Couldn't move package file to: " + destPackageFile);
- returnCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
- break main_flow;
+ installNewPackageLI(pkgName, pFlags,
+ tmpPackageFile,
+ destFilePath, destPackageFile, destResourceFile,
+ pkg, forwardLocked,
+ res);
}
} finally {
if (tmpPackageFile != null && tmpPackageFile.exists()) {
tmpPackageFile.delete();
}
-
- //if install was successful the pkg's installStatus would have
- //been updated and hence needs to be persisted. if not
- //the pkg info needs to be cleaned up.
- if (returnCode == PackageManager.INSTALL_SUCCEEDED) {
- if (deletedPackage != null) {
- // If we deleted an exisiting package, the old source and resource files that we
- // were keeping around in case we needed them (see below) can now be deleted
- final ApplicationInfo deletedPackageAppInfo = deletedPackage.applicationInfo;
- final ApplicationInfo installedPackageAppInfo =
- installedPackage.applicationInfo;
- if (!deletedPackageAppInfo.sourceDir
- .equals(installedPackageAppInfo.sourceDir)) {
- new File(deletedPackageAppInfo.sourceDir).delete();
- }
- if (!deletedPackageAppInfo.publicSourceDir
- .equals(installedPackageAppInfo.publicSourceDir)) {
- new File(deletedPackageAppInfo.publicSourceDir).delete();
- }
- }
+ return res;
+ }
+ }
+
+ private int setPermissionsLI(String pkgName,
+ PackageParser.Package newPackage,
+ String destFilePath,
+ File destResourceFile,
+ boolean forwardLocked) {
+ int retCode;
+ if (forwardLocked) {
+ try {
+ extractPublicFiles(newPackage, destResourceFile);
+ } catch (IOException e) {
+ Log.e(TAG, "Couldn't create a new zip file for the public parts of a" +
+ " forward-locked app.");
+ return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
+ } finally {
+ //TODO clean up the extracted public files
+ }
+ if (mInstaller != null) {
+ retCode = mInstaller.setForwardLockPerm(pkgName,
+ newPackage.applicationInfo.uid);
} else {
- if (mInstaller != null) {
- mInstaller.rmdex(tmpPackageFile.getPath());
- }
- if (wroteSettings) {
- // remove package from internal structures. Note that we want deletePackageX to
- // delete the package data and cache directories that it created in
- // scanPackageLocked, unless those directories existed before we even tried to
- // install.
- deletePackageLI(
- pkgName, true,
- dataDirExists ? PackageManager.DONT_DELETE_DATA : 0,
- new PackageRemovedInfo());
- if (deletedPackage != null) {
- // Since we failed to install the new package we need to restore the old
- // package that we deleted.
- installPackageLI(
- Uri.fromFile(new File(deletedPackage.mPath)),
- isForwardLocked(deletedPackage)
- ? PackageManager.FORWARD_LOCK_PACKAGE
- : 0);
- }
- }
+ final int filePermissions =
+ FileUtils.S_IRUSR|FileUtils.S_IWUSR|FileUtils.S_IRGRP;
+ retCode = FileUtils.setPermissions(destFilePath, filePermissions, -1,
+ newPackage.applicationInfo.uid);
}
+ } else {
+ final int filePermissions =
+ FileUtils.S_IRUSR|FileUtils.S_IWUSR|FileUtils.S_IRGRP
+ |FileUtils.S_IROTH;
+ retCode = FileUtils.setPermissions(destFilePath, filePermissions, -1, -1);
}
-
- PackageInstalledInfo res = new PackageInstalledInfo();
- res.name = installedPackageName;
- res.uid = installedPackageUid;
- res.pkg = installedPackage;
- res.returnCode = returnCode;
- res.removedInfo = removedInfo;
- return res;
+ if (retCode != 0) {
+ Log.e(TAG, "Couldn't set new package file permissions for " + destFilePath
+ + ". The return code was: " + retCode);
+ }
+ return PackageManager.INSTALL_SUCCEEDED;
}
private boolean isForwardLocked(PackageParser.Package deletedPackage) {
@@ -3470,11 +3776,6 @@ class PackageManagerService extends IPackageManager.Stub {
synchronized (mInstallLock) {
res = deletePackageLI(packageName, deleteCodeAndResources, flags, info);
- if (res) {
- synchronized (mPackages) {
- mSettings.writeLP();
- }
- }
}
if(res && sendBroadCast) {
@@ -3500,44 +3801,117 @@ class PackageManagerService extends IPackageManager.Stub {
}
}
- private boolean deletePackageLI(String packageName,
+ /*
+ * This method deletes the package from internal data structures. If the DONT_DELETE_DATA
+ * flag is not set, the data directory is removed as well.
+ * make sure this flag is set for partially installed apps. If not its meaningless to
+ * delete a partially installed application.
+ */
+ private void removePackageDataLI(PackageParser.Package p, PackageRemovedInfo outInfo,
+ int flags) {
+ String packageName = p.packageName;
+ outInfo.removedPackage = packageName;
+ removePackageLI(p, true);
+ // Retrieve object to delete permissions for shared user later on
+ PackageSetting deletedPs;
+ synchronized (mPackages) {
+ deletedPs = mSettings.mPackages.get(packageName);
+ }
+ if ((flags&PackageManager.DONT_DELETE_DATA) == 0) {
+ if (mInstaller != null) {
+ int retCode = mInstaller.remove(packageName);
+ if (retCode < 0) {
+ Log.w(TAG, "Couldn't remove app data or cache directory for package: "
+ + packageName + ", retcode=" + retCode);
+ // we don't consider this to be a failure of the core package deletion
+ }
+ } else {
+ //for emulator
+ PackageParser.Package pkg = mPackages.get(packageName);
+ File dataDir = new File(pkg.applicationInfo.dataDir);
+ dataDir.delete();
+ }
+ synchronized (mPackages) {
+ outInfo.removedUid = mSettings.removePackageLP(packageName);
+ }
+ }
+ synchronized (mPackages) {
+ if ( (deletedPs != null) && (deletedPs.sharedUser != null)) {
+ // remove permissions associated with package
+ mSettings.updateSharedUserPerms (deletedPs);
+ }
+ // Save settings now
+ mSettings.writeLP ();
+ }
+ }
+
+ /*
+ * Tries to delete system package.
+ */
+ private boolean deleteSystemPackageLI(PackageParser.Package p,
boolean deleteCodeAndResources, int flags, PackageRemovedInfo outInfo) {
- if (packageName == null) {
- Log.w(TAG, "Attempt to delete null packageName.");
+ ApplicationInfo applicationInfo = p.applicationInfo;
+ //applicable for non-partially installed applications only
+ if (applicationInfo == null) {
+ Log.w(TAG, "Package " + p.packageName + " has no applicationInfo.");
return false;
}
- PackageParser.Package p;
+ PackageSetting ps = null;
+ // Confirm if the system package has been updated
+ // An updated system app can be deleted. This will also have to restore
+ // the system pkg from system partition
synchronized (mPackages) {
- p = mPackages.get(packageName);
+ ps = mSettings.getDisabledSystemPkg(p.packageName);
}
- if (p == null) {
- Log.w(TAG, "Package named '" + packageName +"' doesn't exist.");
+ if (ps == null) {
+ Log.w(TAG, "Attempt to delete system package "+ p.packageName);
return false;
+ } else {
+ Log.i(TAG, "Deleting system pkg from data partition");
}
- final ApplicationInfo applicationInfo = p.applicationInfo;
- if (applicationInfo == null) {
- Log.w(TAG, "Package " + packageName + " has no applicationInfo.");
+ // Delete the updated package
+ boolean ret = deleteInstalledPackageLI(p, deleteCodeAndResources, flags, outInfo);
+ if (!ret) {
return false;
}
-
- // NB: This is a public nonfinal boolean so it theoretically
- // could be altered by anyone. In practice, that can only be
- // done from within this same process, and anyway file
- // permissions will prevent unauthorized deletion of system
- // packages.
- if ((applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
- Log.w(TAG, "Attempt to delete system package "+ packageName);
+ synchronized (mPackages) {
+ // Reinstate the old system package
+ mSettings.enableSystemPackageLP(p.packageName);
+ }
+ // Install the system package
+ PackageParser.Package newPkg = scanPackageLI(ps.codePath, ps.codePath, ps.resourcePath,
+ PackageParser.PARSE_MUST_BE_APK | PackageParser.PARSE_IS_SYSTEM,
+ SCAN_MONITOR);
+
+ if (newPkg == null) {
+ Log.w(TAG, "Failed to restore system package:"+p.packageName+" with error:" + mLastScanError);
return false;
}
- final File sourceFile = new File(applicationInfo.sourceDir);
+ synchronized (mPackages) {
+ mSettings.writeLP();
+ }
+ return true;
+ }
+
+ private boolean deleteInstalledPackageLI(PackageParser.Package p,
+ boolean deleteCodeAndResources, int flags, PackageRemovedInfo outInfo) {
+ ApplicationInfo applicationInfo = p.applicationInfo;
+ if (applicationInfo == null) {
+ Log.w(TAG, "Package " + p.packageName + " has no applicationInfo.");
+ return false;
+ }
+ // Delete application's source directory
+ File sourceFile = new File(applicationInfo.sourceDir);
if (!sourceFile.exists()) {
Log.w(TAG, "Package source " + applicationInfo.sourceDir + " does not exist.");
return false;
}
- outInfo.uid = p.applicationInfo.uid;
+ outInfo.uid = applicationInfo.uid;
- outInfo.removedPackage = packageName;
- removePackageLI(p, true);
+ // Delete package data from internal structures and also remove data if flag is set
+ removePackageDataLI(p, outInfo, flags);
+
+ // Delete application code and resources
if (deleteCodeAndResources) {
sourceFile.delete();
final File publicSourceFile = new File(applicationInfo.publicSourceDir);
@@ -3548,30 +3922,61 @@ class PackageManagerService extends IPackageManager.Stub {
int retCode = mInstaller.rmdex(sourceFile.toString());
if (retCode < 0) {
Log.w(TAG, "Couldn't remove dex file for package: "
- + packageName + ", retcode=" + retCode);
+ + p.packageName + " at location " + sourceFile.toString() + ", retcode=" + retCode);
// we don't consider this to be a failure of the core package deletion
}
}
}
- if ((flags&PackageManager.DONT_DELETE_DATA) == 0) {
- if (mInstaller != null) {
- int retCode = mInstaller.remove(packageName);
- if (retCode < 0) {
- Log.w(TAG, "Couldn't remove app data or cache directory for package: "
- + packageName + ", retcode=" + retCode);
- // we don't consider this to be a failure of the core package deletion
+ return true;
+ }
+
+ /*
+ * This method handles package deletion in general
+ */
+ private boolean deletePackageLI(String packageName,
+ boolean deleteCodeAndResources, int flags, PackageRemovedInfo outInfo) {
+ if (packageName == null) {
+ Log.w(TAG, "Attempt to delete null packageName.");
+ return false;
+ }
+ PackageParser.Package p;
+ boolean dataOnly = false;
+ synchronized (mPackages) {
+ p = mPackages.get(packageName);
+ if (p == null) {
+ //this retrieves partially installed apps
+ dataOnly = true;
+ PackageSetting ps = mSettings.mPackages.get(packageName);
+ if (ps == null) {
+ Log.w(TAG, "Package named '" + packageName +"' doesn't exist.");
+ return false;
}
- } else {
- //for emulator
- PackageParser.Package pkg = mPackages.get(packageName);
- File dataDir = new File(pkg.applicationInfo.dataDir);
- dataDir.delete();
- }
- synchronized (mPackages) {
- outInfo.removedUid = mSettings.removePackageLP(packageName);
+ p = ps.pkg;
}
}
- return true;
+ if (p == null) {
+ Log.w(TAG, "Package named '" + packageName +"' doesn't exist.");
+ return false;
+ }
+
+ if (dataOnly) {
+ // Delete application data first
+ removePackageDataLI(p, outInfo, flags);
+ return true;
+ }
+ // At this point the package should have ApplicationInfo associated with it
+ if (p.applicationInfo == null) {
+ Log.w(TAG, "Package " + p.packageName + " has no applicationInfo.");
+ return false;
+ }
+ if ( (p.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
+ Log.i(TAG, "Removing system package:"+p.packageName);
+ // When an updated system application is deleted we delete the existing resources as well and
+ // fall back to existing code in system partition
+ return deleteSystemPackageLI(p, true, flags, outInfo);
+ }
+ Log.i(TAG, "Removing non-system package:"+p.packageName);
+ return deleteInstalledPackageLI (p, deleteCodeAndResources, flags, outInfo);
}
public void clearApplicationUserData(final String packageName,
@@ -3582,21 +3987,21 @@ class PackageManagerService extends IPackageManager.Stub {
mHandler.post(new Runnable() {
public void run() {
mHandler.removeCallbacks(this);
- final boolean succeded;
+ final boolean succeeded;
synchronized (mInstallLock) {
- succeded = clearApplicationUserDataLI(packageName);
- }
- if(succeded) {
- //invoke DeviceMemoryMonitor's update method to clear any notifications
- DeviceMemoryMonitorService dmm = (DeviceMemoryMonitorService)
- ServiceManager.getService("devicememorymonitor");
- if(dmm!=null) {
- dmm.updateMemory();
+ succeeded = clearApplicationUserDataLI(packageName);
+ }
+ if (succeeded) {
+ // invoke DeviceStorageMonitor's update method to clear any notifications
+ DeviceStorageMonitorService dsm = (DeviceStorageMonitorService)
+ ServiceManager.getService(DeviceStorageMonitorService.SERVICE);
+ if (dsm != null) {
+ dsm.updateMemory();
}
}
if(observer != null) {
try {
- observer.onRemoveCompleted(packageName, succeded);
+ observer.onRemoveCompleted(packageName, succeeded);
} catch (RemoteException e) {
Log.i(TAG, "Observer no longer exists.");
}
@@ -3611,23 +4016,36 @@ class PackageManagerService extends IPackageManager.Stub {
return false;
}
PackageParser.Package p;
+ boolean dataOnly = false;
synchronized (mPackages) {
p = mPackages.get(packageName);
+ if(p == null) {
+ dataOnly = true;
+ PackageSetting ps = mSettings.mPackages.get(packageName);
+ if((ps == null) || (ps.pkg == null)) {
+ Log.w(TAG, "Package named '" + packageName +"' doesn't exist.");
+ return false;
+ }
+ p = ps.pkg;
+ }
}
- if (p == null) {
- Log.w(TAG, "Package named '" + packageName +"' doesn't exist.");
- return false;
- }
- final ApplicationInfo applicationInfo = p.applicationInfo;
- if (applicationInfo == null) {
- Log.w(TAG, "Package " + packageName + " has no applicationInfo.");
- return false;
+ if(!dataOnly) {
+ //need to check this only for fully installed applications
+ if (p == null) {
+ Log.w(TAG, "Package named '" + packageName +"' doesn't exist.");
+ return false;
+ }
+ final ApplicationInfo applicationInfo = p.applicationInfo;
+ if (applicationInfo == null) {
+ Log.w(TAG, "Package " + packageName + " has no applicationInfo.");
+ return false;
+ }
}
if (mInstaller != null) {
int retCode = mInstaller.clearUserData(packageName);
if (retCode < 0) {
Log.w(TAG, "Couldn't remove cache files for package: "
- + packageName);
+ + packageName);
return false;
}
}
@@ -3716,22 +4134,31 @@ class PackageManagerService extends IPackageManager.Stub {
return false;
}
PackageParser.Package p;
+ boolean dataOnly = false;
synchronized (mPackages) {
p = mPackages.get(packageName);
+ if(p == null) {
+ dataOnly = true;
+ PackageSetting ps = mSettings.mPackages.get(packageName);
+ if((ps == null) || (ps.pkg == null)) {
+ Log.w(TAG, "Package named '" + packageName +"' doesn't exist.");
+ return false;
+ }
+ p = ps.pkg;
+ }
}
- if (p == null) {
- Log.w(TAG, "Package named '" + packageName +"' doesn't exist.");
- return false;
- }
- final ApplicationInfo applicationInfo = p.applicationInfo;
- if (applicationInfo == null) {
- Log.w(TAG, "Package " + packageName + " has no applicationInfo.");
- return false;
+ String publicSrcDir = null;
+ if(!dataOnly) {
+ final ApplicationInfo applicationInfo = p.applicationInfo;
+ if (applicationInfo == null) {
+ Log.w(TAG, "Package " + packageName + " has no applicationInfo.");
+ return false;
+ }
+ publicSrcDir = isForwardLocked(p) ? applicationInfo.publicSourceDir : null;
}
if (mInstaller != null) {
int res = mInstaller.getSizeInfo(packageName, p.mPath,
- isForwardLocked(p) ? applicationInfo.publicSourceDir : null,
- pStats);
+ publicSrcDir, pStats);
if (res < 0) {
return false;
} else {
@@ -4051,7 +4478,7 @@ class PackageManagerService extends IPackageManager.Stub {
if (ps.pkg != null) {
pw.println(" dataDir=" + ps.pkg.applicationInfo.dataDir);
}
- pw.println(" timeStamp=" + ps.timeStamp);
+ pw.println(" timeStamp=" + ps.getTimeStampStr());
pw.println(" signatures=" + ps.signatures);
pw.println(" permissionsFixed=" + ps.permissionsFixed
+ " pkgFlags=0x" + Integer.toHexString(ps.pkgFlags)
@@ -4569,8 +4996,8 @@ class PackageManagerService extends IPackageManager.Stub {
final String codePathString;
final File resourcePath;
final String resourcePathString;
- long timeStamp;
- String timeStampString = "0";
+ private long timeStamp;
+ private String timeStampString = "0";
PackageSignatures signatures = new PackageSignatures();
@@ -4612,6 +5039,14 @@ class PackageManagerService extends IPackageManager.Stub {
timeStamp = newStamp;
timeStampString = newStampStr;
}
+
+ public long getTimeStamp() {
+ return timeStamp;
+ }
+
+ public String getTimeStampStr() {
+ return timeStampString;
+ }
public void copyFrom(PackageSettingBase base) {
grantedPermissions = base.grantedPermissions;
@@ -4709,6 +5144,10 @@ class PackageManagerService extends IPackageManager.Stub {
// First is the most preferred.
private final ArrayList<PackageSetting> mPreferredPackages =
new ArrayList<PackageSetting>();
+ // List of replaced system applications
+ final HashMap<String, PackageSetting> mDisabledSysPackages =
+ new HashMap<String, PackageSetting>();
+
// The user's preferred activities associated with particular intent
// filters.
private final IntentResolver<PreferredActivity, PreferredActivity> mPreferredActivities =
@@ -4781,6 +5220,7 @@ class PackageManagerService extends IPackageManager.Stub {
final String name = pkg.packageName;
PackageSetting p = getPackageLP(name, sharedUser, codePath,
resourcePath, pkgFlags, create);
+
if (p != null) {
p.pkg = pkg;
}
@@ -4836,6 +5276,39 @@ class PackageManagerService extends IPackageManager.Stub {
return s;
}
+ int disableSystemPackageLP(String name) {
+ PackageSetting p = mPackages.get(name);
+ if(p == null) {
+ Log.w(TAG, "Package:"+name+" is not an installed package");
+ return -1;
+ }
+ PackageSetting dp = mDisabledSysPackages.get(name);
+ // always make sure the system package code and resource paths dont change
+ if(dp == null) {
+ if((p.pkg != null) && (p.pkg.applicationInfo != null)) {
+ p.pkg.applicationInfo.flags |= ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
+ }
+ mDisabledSysPackages.put(name, p);
+ }
+ return removePackageLP(name);
+ }
+
+ PackageSetting enableSystemPackageLP(String name) {
+ PackageSetting p = mDisabledSysPackages.get(name);
+ if(p == null) {
+ Log.w(TAG, "Package:"+name+" is not disabled");
+ return null;
+ }
+ // Reset flag in ApplicationInfo object
+ if((p.pkg != null) && (p.pkg.applicationInfo != null)) {
+ p.pkg.applicationInfo.flags &= ~ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
+ }
+ PackageSetting ret = addPackageLP(name, p.codePath,
+ p.resourcePath, p.userId, p.pkgFlags);
+ mDisabledSysPackages.remove(name);
+ return ret;
+ }
+
PackageSetting addPackageLP(String name, File codePath,
File resourcePath, int uid, int pkgFlags) {
PackageSetting p = mPackages.get(name);
@@ -4881,10 +5354,22 @@ class PackageManagerService extends IPackageManager.Stub {
PackageSetting p = mPackages.get(name);
if (p != null) {
if (!p.codePath.equals(codePath)) {
- reportSettingsProblem(Log.WARN,
- "Package " + name + " codePath changed from " + p.codePath
- + " to " + codePath + "; replacing with new");
- p = null;
+ // Check to see if its a disabled system app
+ PackageSetting ps = mDisabledSysPackages.get(name);
+ if((ps != null) && ((ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) != 0)) {
+ // Could be a replaced system package
+ // Note that if the user replaced a system app, the user has to physically
+ // delete the new one in order to revert to the system app. So even
+ // if the user updated the system app via an update, the user still
+ // has to delete the one installed in the data partition in order to pick up the
+ // new system package.
+ return p;
+ } else {
+ reportSettingsProblem(Log.WARN,
+ "Package " + name + " codePath changed from " + p.codePath
+ + " to " + codePath + "; replacing with new");
+ p = null;
+ }
} else if (p.sharedUser != sharedUser) {
reportSettingsProblem(Log.WARN,
"Package " + name + " shared user changed from "
@@ -4896,10 +5381,13 @@ class PackageManagerService extends IPackageManager.Stub {
}
}
if (p == null) {
+ // Create a new PackageSettings entry. this can end up here because
+ // of code path mismatch or user id mismatch of an updated system partition
if (!create) {
return null;
}
p = new PackageSetting(name, codePath, resourcePath, pkgFlags);
+ p.setTimeStamp(codePath.lastModified());
if (sharedUser != null) {
p.userId = sharedUser.userId;
} else if (MULTIPLE_APPLICATION_UIDS) {
@@ -4935,10 +5423,45 @@ class PackageManagerService extends IPackageManager.Stub {
p.sharedUser = sharedUser;
p.userId = sharedUser.userId;
}
-
return p;
}
+ private void updateSharedUserPerms (PackageSetting deletedPs) {
+ if ( (deletedPs == null) || (deletedPs.pkg == null)) {
+ Log.i(TAG, "Trying to update info for null package. Just ignoring");
+ return;
+ }
+ // No sharedUserId
+ if (deletedPs.sharedUser == null) {
+ return;
+ }
+ SharedUserSetting sus = deletedPs.sharedUser;
+ // Update permissions
+ for (String eachPerm: deletedPs.pkg.requestedPermissions) {
+ boolean used = false;
+ if (!sus.grantedPermissions.contains (eachPerm)) {
+ continue;
+ }
+ for (PackageSetting pkg:sus.packages) {
+ if (pkg.grantedPermissions.contains (eachPerm)) {
+ used = true;
+ break;
+ }
+ }
+ if (!used) {
+ // can safely delete this permission from list
+ sus.grantedPermissions.remove(eachPerm);
+ sus.loadedPermissions.remove(eachPerm);
+ }
+ }
+ // Update gids
+ int newGids[] = null;
+ for (PackageSetting pkg:sus.packages) {
+ newGids = appendInts(newGids, pkg.gids);
+ }
+ sus.gids = newGids;
+ }
+
private int removePackageLP(String name) {
PackageSetting p = mPackages.get(name);
if (p != null) {
@@ -5047,16 +5570,17 @@ class PackageManagerService extends IPackageManager.Stub {
serializer.endTag(null, "permissions");
for (PackageSetting pkg : mPackages.values()) {
- serializer.startTag(null, "package");
+ writePackage(serializer, pkg);
+ }
+
+ for (PackageSetting pkg : mDisabledSysPackages.values()) {
+ serializer.startTag(null, "updated-package");
serializer.attribute(null, "name", pkg.name);
serializer.attribute(null, "codePath", pkg.codePathString);
+ serializer.attribute(null, "ts", pkg.getTimeStampStr());
if (!pkg.resourcePathString.equals(pkg.codePathString)) {
serializer.attribute(null, "resourcePath", pkg.resourcePathString);
}
- serializer.attribute(null, "system",
- (pkg.pkgFlags&ApplicationInfo.FLAG_SYSTEM) != 0
- ? "true" : "false");
- serializer.attribute(null, "ts", pkg.timeStampString);
if (pkg.sharedUser == null) {
serializer.attribute(null, "userId",
Integer.toString(pkg.userId));
@@ -5064,50 +5588,9 @@ class PackageManagerService extends IPackageManager.Stub {
serializer.attribute(null, "sharedUserId",
Integer.toString(pkg.userId));
}
- if (pkg.enabled != COMPONENT_ENABLED_STATE_DEFAULT) {
- serializer.attribute(null, "enabled",
- pkg.enabled == COMPONENT_ENABLED_STATE_ENABLED
- ? "true" : "false");
- }
- if(pkg.installStatus == PKG_INSTALL_INCOMPLETE) {
- serializer.attribute(null, "installStatus", "false");
- }
- pkg.signatures.writeXml(serializer, "sigs", mPastSignatures);
- if ((pkg.pkgFlags&ApplicationInfo.FLAG_SYSTEM) == 0) {
- serializer.startTag(null, "perms");
- if (pkg.sharedUser == null) {
- // If this is a shared user, the permissions will
- // be written there. We still need to write an
- // empty permissions list so permissionsFixed will
- // be set.
- for (String name : pkg.grantedPermissions) {
- serializer.startTag(null, "item");
- serializer.attribute(null, "name", name);
- serializer.endTag(null, "item");
- }
- }
- serializer.endTag(null, "perms");
- }
- if (pkg.disabledComponents.size() > 0) {
- serializer.startTag(null, "disabled-components");
- for (String name : pkg.disabledComponents) {
- serializer.startTag(null, "item");
- serializer.attribute(null, "name", name);
- serializer.endTag(null, "item");
- }
- serializer.endTag(null, "disabled-components");
- }
- if (pkg.enabledComponents.size() > 0) {
- serializer.startTag(null, "enabled-components");
- for (String name : pkg.enabledComponents) {
- serializer.startTag(null, "item");
- serializer.attribute(null, "name", name);
- serializer.endTag(null, "item");
- }
- serializer.endTag(null, "enabled-components");
- }
- serializer.endTag(null, "package");
+ serializer.endTag(null, "updated-package");
}
+
serializer.startTag(null, "preferred-packages");
int N = mPreferredPackages.size();
@@ -5169,7 +5652,71 @@ class PackageManagerService extends IPackageManager.Stub {
//Debug.stopMethodTracing();
}
-
+
+ void writePackage(XmlSerializer serializer, final PackageSetting pkg)
+ throws java.io.IOException {
+ serializer.startTag(null, "package");
+ serializer.attribute(null, "name", pkg.name);
+ serializer.attribute(null, "codePath", pkg.codePathString);
+ if (!pkg.resourcePathString.equals(pkg.codePathString)) {
+ serializer.attribute(null, "resourcePath", pkg.resourcePathString);
+ }
+ serializer.attribute(null, "system",
+ (pkg.pkgFlags&ApplicationInfo.FLAG_SYSTEM) != 0
+ ? "true" : "false");
+ serializer.attribute(null, "ts", pkg.getTimeStampStr());
+ if (pkg.sharedUser == null) {
+ serializer.attribute(null, "userId",
+ Integer.toString(pkg.userId));
+ } else {
+ serializer.attribute(null, "sharedUserId",
+ Integer.toString(pkg.userId));
+ }
+ if (pkg.enabled != COMPONENT_ENABLED_STATE_DEFAULT) {
+ serializer.attribute(null, "enabled",
+ pkg.enabled == COMPONENT_ENABLED_STATE_ENABLED
+ ? "true" : "false");
+ }
+ if(pkg.installStatus == PKG_INSTALL_INCOMPLETE) {
+ serializer.attribute(null, "installStatus", "false");
+ }
+ pkg.signatures.writeXml(serializer, "sigs", mPastSignatures);
+ if ((pkg.pkgFlags&ApplicationInfo.FLAG_SYSTEM) == 0) {
+ serializer.startTag(null, "perms");
+ if (pkg.sharedUser == null) {
+ // If this is a shared user, the permissions will
+ // be written there. We still need to write an
+ // empty permissions list so permissionsFixed will
+ // be set.
+ for (final String name : pkg.grantedPermissions) {
+ serializer.startTag(null, "item");
+ serializer.attribute(null, "name", name);
+ serializer.endTag(null, "item");
+ }
+ }
+ serializer.endTag(null, "perms");
+ }
+ if (pkg.disabledComponents.size() > 0) {
+ serializer.startTag(null, "disabled-components");
+ for (final String name : pkg.disabledComponents) {
+ serializer.startTag(null, "item");
+ serializer.attribute(null, "name", name);
+ serializer.endTag(null, "item");
+ }
+ serializer.endTag(null, "disabled-components");
+ }
+ if (pkg.enabledComponents.size() > 0) {
+ serializer.startTag(null, "enabled-components");
+ for (final String name : pkg.enabledComponents) {
+ serializer.startTag(null, "item");
+ serializer.attribute(null, "name", name);
+ serializer.endTag(null, "item");
+ }
+ serializer.endTag(null, "enabled-components");
+ }
+ serializer.endTag(null, "package");
+ }
+
void writePermission(XmlSerializer serializer, BasePermission bp)
throws XmlPullParserException, java.io.IOException {
if (bp.type != BasePermission.TYPE_BUILTIN
@@ -5281,6 +5828,34 @@ class PackageManagerService extends IPackageManager.Stub {
readPreferredPackagesLP(parser);
} else if (tagName.equals("preferred-activities")) {
readPreferredActivitiesLP(parser);
+ } else if(tagName.equals("updated-package")) {
+ String name = parser.getAttributeValue(null, "name");
+ String codePathStr = parser.getAttributeValue(null, "codePath");
+ String resourcePathStr = parser.getAttributeValue(null, "resourcePath");
+ if(resourcePathStr == null) {
+ resourcePathStr = codePathStr;
+ }
+
+ int pkgFlags = 0;
+ pkgFlags |= ApplicationInfo.FLAG_SYSTEM;
+ PackageSetting ps = new PackageSetting(name,
+ new File(codePathStr),
+ new File(resourcePathStr), pkgFlags);
+ String timeStampStr = parser.getAttributeValue(null, "ts");
+ if (timeStampStr != null) {
+ try {
+ long timeStamp = Long.parseLong(timeStampStr);
+ ps.setTimeStamp(timeStamp, timeStampStr);
+ } catch (NumberFormatException e) {
+ }
+ }
+ String idStr = parser.getAttributeValue(null, "userId");
+ ps.userId = idStr != null ? Integer.parseInt(idStr) : 0;
+ if(ps.userId <= 0) {
+ String sharedIdStr = parser.getAttributeValue(null, "sharedUserId");
+ ps.userId = sharedIdStr != null ? Integer.parseInt(sharedIdStr) : 0;
+ }
+ mDisabledSysPackages.put(name, ps);
} else {
Log.w(TAG, "Unknown element under <packages>: "
+ parser.getName());
@@ -5811,6 +6386,13 @@ class PackageManagerService extends IPackageManager.Stub {
mUserIds.add(obj);
return FIRST_APPLICATION_UID + N;
}
+
+ public PackageSetting getDisabledSystemPkg(String name) {
+ synchronized(mPackages) {
+ PackageSetting ps = mDisabledSysPackages.get(name);
+ return ps;
+ }
+ }
boolean isEnabledLP(ComponentInfo componentInfo, int flags) {
final PackageSetting packageSettings = mPackages.get(componentInfo.packageName);
diff --git a/services/java/com/android/server/PowerManagerService.java b/services/java/com/android/server/PowerManagerService.java
index 4ff0844..3fa2087 100644
--- a/services/java/com/android/server/PowerManagerService.java
+++ b/services/java/com/android/server/PowerManagerService.java
@@ -17,7 +17,7 @@
package com.android.server;
import com.android.internal.app.IBatteryStats;
-import com.android.server.am.BatteryStats;
+import com.android.server.am.BatteryStatsService;
import android.app.ActivityManagerNative;
import android.app.IActivityManager;
@@ -29,6 +29,7 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.database.Cursor;
+import android.os.BatteryStats;
import android.os.Binder;
import android.os.Handler;
import android.os.HandlerThread;
@@ -74,11 +75,15 @@ class PowerManagerService extends IPowerManager.Stub implements LocalPowerManage
| PowerManager.FULL_WAKE_LOCK;
// time since last state: time since last event:
- private static final int SHORT_KEYLIGHT_DELAY = 6000; // t+6 sec
+ // The short keylight delay comes from Gservices; this is the default.
+ private static final int SHORT_KEYLIGHT_DELAY_DEFAULT = 6000; // t+6 sec
private static final int MEDIUM_KEYLIGHT_DELAY = 15000; // t+15 sec
private static final int LONG_KEYLIGHT_DELAY = 6000; // t+6 sec
private static final int LONG_DIM_TIME = 7000; // t+N-5 sec
+ // Cached Gservices settings; see updateGservicesValues()
+ private int mShortKeylightDelay = SHORT_KEYLIGHT_DELAY_DEFAULT;
+
// flags for setPowerState
private static final int SCREEN_ON_BIT = 0x00000001;
private static final int SCREEN_BRIGHT_BIT = 0x00000002;
@@ -129,7 +134,7 @@ class PowerManagerService extends IPowerManager.Stub implements LocalPowerManage
private final int MY_UID;
private boolean mDoneBooting = false;
- private boolean mStayOnWhilePluggedIn;
+ private int mStayOnConditions = 0;
private int mNotificationQueue = -1;
private int mNotificationWhy;
private int mPartialCount = 0;
@@ -163,7 +168,6 @@ class PowerManagerService extends IPowerManager.Stub implements LocalPowerManage
= new BrightnessState(Power.KEYBOARD_LIGHT);
private final BrightnessState mButtonBrightness
= new BrightnessState(Power.BUTTON_LIGHT);
- private ContentResolver mContentResolver;
private boolean mIsPowered = false;
private IActivityManager mActivityService;
private IBatteryStats mBatteryStats;
@@ -285,10 +289,20 @@ class PowerManagerService extends IPowerManager.Stub implements LocalPowerManage
}
}
- public void setStayOnSetting(boolean val) {
+ /**
+ * 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,
+ * when the device is connected to that source, causes the device to stay on.
+ * See {@link android.os.BatteryManager} for the list of power sources that
+ * can be specified. Current values include {@link android.os.BatteryManager#BATTERY_PLUGGED_AC}
+ * and {@link android.os.BatteryManager#BATTERY_PLUGGED_USB}
+ * @param val an {@code int} containing the bits that specify which power sources
+ * should cause the device to stay on.
+ */
+ public void setStayOnSetting(int val) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WRITE_SETTINGS, null);
Settings.System.putInt(mContext.getContentResolver(),
- Settings.System.STAY_ON_WHILE_PLUGGED_IN, val ? 1 : 0);
+ Settings.System.STAY_ON_WHILE_PLUGGED_IN, val);
}
private class SettingsObserver implements Observer {
@@ -299,7 +313,7 @@ class PowerManagerService extends IPowerManager.Stub implements LocalPowerManage
public void update(Observable o, Object arg) {
synchronized (mLocks) {
// STAY_ON_WHILE_PLUGGED_IN
- mStayOnWhilePluggedIn = getInt(STAY_ON_WHILE_PLUGGED_IN) != 0;
+ mStayOnConditions = getInt(STAY_ON_WHILE_PLUGGED_IN);
updateWakeLockLocked();
// SCREEN_OFF_TIMEOUT
@@ -337,7 +351,7 @@ class PowerManagerService extends IPowerManager.Stub implements LocalPowerManage
void init(Context context, IActivityManager activity, BatteryService battery) {
mContext = context;
mActivityService = activity;
- mBatteryStats = BatteryStats.getService();
+ mBatteryStats = BatteryStatsService.getService();
mBatteryService = battery;
mHandlerThread = new HandlerThread("PowerManagerService") {
@@ -376,10 +390,7 @@ class PowerManagerService extends IPowerManager.Stub implements LocalPowerManage
mScreenOffIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
ContentResolver resolver = mContext.getContentResolver();
- mContentResolver = resolver;
-
-
- Cursor settingsCursor = mContentResolver.query(Settings.System.CONTENT_URI, null,
+ Cursor settingsCursor = resolver.query(Settings.System.CONTENT_URI, null,
"(" + Settings.System.NAME + "=?) or ("
+ Settings.System.NAME + "=?) or ("
+ Settings.System.NAME + "=?)",
@@ -397,6 +408,13 @@ class PowerManagerService extends IPowerManager.Stub implements LocalPowerManage
filter.addAction(Intent.ACTION_BATTERY_CHANGED);
mContext.registerReceiver(new BatteryReceiver(), filter);
+ // Listen for Gservices changes
+ IntentFilter gservicesChangedFilter =
+ new IntentFilter(Settings.Gservices.CHANGED_ACTION);
+ mContext.registerReceiver(new GservicesChangedReceiver(), gservicesChangedFilter);
+ // And explicitly do the initial update of our cached settings
+ updateGservicesValues();
+
// turn everything on
setPowerState(ALL_BRIGHT);
@@ -444,7 +462,7 @@ class PowerManagerService extends IPowerManager.Stub implements LocalPowerManage
}
private void updateWakeLockLocked() {
- if (mStayOnWhilePluggedIn && mBatteryService.isPowered()) {
+ if (mStayOnConditions != 0 && mBatteryService.isPowered(mStayOnConditions)) {
// keep the device on if we're plugged in and mStayOnWhilePluggedIn is set.
mStayOnWhilePluggedInScreenDimLock.acquire();
mStayOnWhilePluggedInPartialLock.acquire();
@@ -758,7 +776,7 @@ class PowerManagerService extends IPowerManager.Stub implements LocalPowerManage
pw.println(" mNextTimeout=" + mNextTimeout + " now=" + now
+ " " + ((mNextTimeout-now)/1000) + "s from now");
pw.println(" mDimScreen=" + mDimScreen
- + " mStayOnWhilePluggedIn=" + mStayOnWhilePluggedIn);
+ + " mStayOnConditions=" + mStayOnConditions);
pw.println(" mOffBecauseOfUser=" + mOffBecauseOfUser
+ " mUserState=" + mUserState);
pw.println(" mNotificationQueue=" + mNotificationQueue
@@ -1209,7 +1227,7 @@ class PowerManagerService extends IPowerManager.Stub implements LocalPowerManage
// was dim
steps = (int)(ANIM_STEPS*ratio);
}
- if (mStayOnWhilePluggedIn && mBatteryService.isPowered()) {
+ if (mStayOnConditions != 0 && mBatteryService.isPowered(mStayOnConditions)) {
// If the "stay on while plugged in" option is
// turned on, then the screen will often not
// automatically turn off while plugged in. To
@@ -1362,7 +1380,8 @@ class PowerManagerService extends IPowerManager.Stub implements LocalPowerManage
private int getPreferredBrightness() {
try {
- final int brightness = Settings.System.getInt(mContentResolver, SCREEN_BRIGHTNESS);
+ final int brightness = Settings.System.getInt(mContext.getContentResolver(),
+ SCREEN_BRIGHTNESS);
// Don't let applications turn the screen all the way off
return Math.max(brightness, Power.BRIGHTNESS_DIM);
} catch (SettingNotFoundException snfe) {
@@ -1519,7 +1538,7 @@ class PowerManagerService extends IPowerManager.Stub implements LocalPowerManage
* */
private void setScreenOffTimeoutsLocked() {
if ((mPokey & POKE_LOCK_SHORT_TIMEOUT) != 0) {
- mKeylightDelay = SHORT_KEYLIGHT_DELAY;
+ mKeylightDelay = mShortKeylightDelay; // Configurable via Gservices
mDimDelay = -1;
mScreenOffDelay = 0;
} else if ((mPokey & POKE_LOCK_MEDIUM_TIMEOUT) != 0) {
@@ -1553,6 +1572,31 @@ class PowerManagerService extends IPowerManager.Stub implements LocalPowerManage
}
}
+ /**
+ * Refreshes cached Gservices settings. Called once on startup, and
+ * on subsequent Settings.Gservices.CHANGED_ACTION broadcasts (see
+ * GservicesChangedReceiver).
+ */
+ private void updateGservicesValues() {
+ mShortKeylightDelay = Settings.Gservices.getInt(
+ mContext.getContentResolver(),
+ Settings.Gservices.SHORT_KEYLIGHT_DELAY_MS,
+ SHORT_KEYLIGHT_DELAY_DEFAULT);
+ // Log.i(TAG, "updateGservicesValues(): mShortKeylightDelay now " + mShortKeylightDelay);
+ }
+
+ /**
+ * Receiver for the Gservices.CHANGED_ACTION broadcast intent,
+ * which tells us we need to refresh our cached Gservices settings.
+ */
+ private class GservicesChangedReceiver extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ // Log.i(TAG, "GservicesChangedReceiver.onReceive(): " + intent);
+ updateGservicesValues();
+ }
+ }
+
private class LockList extends ArrayList<WakeLock>
{
void addLock(WakeLock wl)
diff --git a/services/java/com/android/server/SensorService.java b/services/java/com/android/server/SensorService.java
index f4b3f87..f56088c 100644
--- a/services/java/com/android/server/SensorService.java
+++ b/services/java/com/android/server/SensorService.java
@@ -16,24 +16,20 @@
package com.android.server;
-import android.app.Notification;
-import android.app.NotificationManager;
-import android.app.PendingIntent;
import android.content.Context;
-import android.content.Intent;
import android.hardware.ISensorService;
-import android.hardware.SensorManager;
import android.os.Binder;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.os.IBinder;
-import android.os.SystemProperties;
import android.util.Config;
import android.util.Log;
-import com.android.internal.R;
import java.util.ArrayList;
+import com.android.internal.app.IBatteryStats;
+import com.android.server.am.BatteryStatsService;
+
/**
* Class that manages the device's sensors. It register clients and activate
@@ -43,46 +39,50 @@ import java.util.ArrayList;
*/
class SensorService extends ISensorService.Stub {
- private static final int SENSOR_NOTIFICATION_ACCURACY_LEVEL = 1;
- private static final String TAG = SensorService.class.getSimpleName();
+ static final String TAG = SensorService.class.getSimpleName();
private static final boolean DEBUG = false;
private static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV;
private static final int SENSOR_DISABLE = -1;
- private NotificationManager mNotificationManager;
- private int mCompassAccuracy = -1;
- private final Context mContext;
+
+ /**
+ * Battery statistics to be updated when sensors are enabled and diabled.
+ */
+ final IBatteryStats mBatteryStats = BatteryStatsService.getService();
private final class Listener implements IBinder.DeathRecipient {
- final IBinder mListener;
+ final IBinder mToken;
int mSensors = 0;
int mDelay = 0x7FFFFFFF;
- Listener(IBinder listener) {
- mListener = listener;
+ Listener(IBinder token) {
+ mToken = token;
}
void addSensor(int sensor, int delay) {
- mSensors |= sensor;
+ mSensors |= (1<<sensor);
if (mDelay > delay)
mDelay = delay;
}
void removeSensor(int sensor) {
- mSensors &= ~sensor;
+ mSensors &= ~(1<<sensor);
}
boolean hasSensor(int sensor) {
- return ((mSensors & sensor) != 0);
+ return ((mSensors & (1<<sensor)) != 0);
}
public void binderDied() {
if (localLOGV) Log.d(TAG, "sensor listener died");
-
synchronized(mListeners) {
mListeners.remove(this);
- for (int sensor = SensorManager.SENSOR_MAX; sensor > 0; sensor >>>= 1) {
+ mToken.unlinkToDeath(this, 0);
+ // go through the lists of sensors used by the listener that
+ // died and deactivate them.
+ for (int sensor=0 ; sensor<32 && mSensors!=0 ; sensor++) {
if (hasSensor(sensor)) {
+ removeSensor(sensor);
try {
deactivateIfUnused(sensor);
} catch (RemoteException e) {
@@ -95,60 +95,31 @@ class SensorService extends ISensorService.Stub {
}
}
+ @SuppressWarnings("unused")
public SensorService(Context context) {
if (localLOGV) Log.d(TAG, "SensorService startup");
_sensors_control_init();
- mNotificationManager = (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE);
- mContext = context;
}
public ParcelFileDescriptor getDataChanel() throws RemoteException {
return _sensors_control_open();
}
- public void reportAccuracy(int sensor, int value) {
- if ((sensor & (SensorManager.SENSOR_ORIENTATION|SensorManager.SENSOR_ORIENTATION_RAW)) != 0) {
- synchronized (mNotificationManager) {
- if (value != mCompassAccuracy) {
- Log.d(TAG, "Compass needs calibration, accuracy=" + value);
- if (!SystemProperties.getBoolean("debug.sensors.notification", false)) {
- // don't show the sensors notification by default
- return;
- }
- mCompassAccuracy = value;
- if (value == -1) {
- mNotificationManager.cancel(0);
- } else {
- if (value <= SENSOR_NOTIFICATION_ACCURACY_LEVEL) {
- long token = Binder.clearCallingIdentity();
- try {
- CharSequence banner = mContext.getString(R.string.compass_accuracy_banner);
- CharSequence title = mContext.getString(R.string.compass_accuracy_notificaction_title);
- CharSequence body = mContext.getString(R.string.compass_accuracy_notificaction_body);
- Notification n = new Notification(R.drawable.stat_notify_calibrate_compass,
- banner, System.currentTimeMillis());
- Intent bogusIntent = new Intent(mContext, SensorService.class);
- PendingIntent contentIntent = PendingIntent.getActivity(mContext, 0, bogusIntent,
- PendingIntent.FLAG_CANCEL_CURRENT|PendingIntent.FLAG_ONE_SHOT);
- n.setLatestEventInfo(mContext, title, body, contentIntent);
- mNotificationManager.notify(0, n);
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- } else {
- mNotificationManager.cancel(0);
- }
- }
- }
- }
- }
- }
-
- public boolean enableSensor(IBinder listener, int sensor, int enable)
+ public boolean enableSensor(IBinder binder, int sensor, int enable)
throws RemoteException {
if (localLOGV) Log.d(TAG, "enableSensor " + sensor + " " + enable);
+
+ // Inform battery statistics service of status change
+ int uid = Binder.getCallingUid();
+ long identity = Binder.clearCallingIdentity();
+ if (enable == SENSOR_DISABLE) {
+ mBatteryStats.noteStopSensor(uid, sensor);
+ } else {
+ mBatteryStats.noteStartSensor(uid, sensor);
+ }
+ Binder.restoreCallingIdentity(identity);
- if (listener == null) throw new NullPointerException("listener is null in enableSensor");
+ if (binder == null) throw new NullPointerException("listener is null in enableSensor");
synchronized(mListeners) {
if (enable!=SENSOR_DISABLE && !_sensors_control_activate(sensor, true)) {
@@ -156,22 +127,18 @@ class SensorService extends ISensorService.Stub {
return false;
}
- IBinder binder = listener;
Listener l = null;
-
int minDelay = enable;
- int size = mListeners.size();
- for (int i = 0; i < size ; i++) {
- Listener test = mListeners.get(i);
- if (binder.equals(test.mListener)) {
- l = test;
+ for (Listener listener : mListeners) {
+ if (binder == listener.mToken) {
+ l = listener;
}
- if (minDelay > test.mDelay)
- minDelay = test.mDelay;
+ if (minDelay > listener.mDelay)
+ minDelay = listener.mDelay;
}
if (l == null && enable!=SENSOR_DISABLE) {
- l = new Listener(listener);
+ l = new Listener(binder);
binder.linkToDeath(l, 0);
mListeners.add(l);
mListeners.notify();
@@ -182,7 +149,7 @@ class SensorService extends ISensorService.Stub {
}
if (minDelay >= 0) {
- _sensors_control_set_delay(minDelay);
+ _sensors_control_set_delay(minDelay);
}
if (enable != SENSOR_DISABLE) {
@@ -196,24 +163,28 @@ class SensorService extends ISensorService.Stub {
mListeners.notify();
}
}
+
+ if (mListeners.size() == 0) {
+ _sensors_control_wake();
+ }
}
return true;
}
- private void deactivateIfUnused(int sensor) throws RemoteException {
+ void deactivateIfUnused(int sensor) throws RemoteException {
int size = mListeners.size();
- for (int i = 0; i < size ; i++) {
+ for (int i=0 ; i<size ; i++) {
if (mListeners.get(i).hasSensor(sensor))
return;
}
_sensors_control_activate(sensor, false);
- reportAccuracy(sensor, -1);
}
- private ArrayList<Listener> mListeners = new ArrayList<Listener>();
+ ArrayList<Listener> mListeners = new ArrayList<Listener>();
private static native int _sensors_control_init();
private static native ParcelFileDescriptor _sensors_control_open();
private static native boolean _sensors_control_activate(int sensor, boolean activate);
private static native int _sensors_control_set_delay(int ms);
+ private static native int _sensors_control_wake();
}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index ff74472..baf57bc 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -33,11 +33,13 @@ import android.os.IBinder;
import android.provider.Settings;
import android.provider.Contacts.People;
import android.server.BluetoothDeviceService;
+import android.server.BluetoothA2dpService;
import android.server.checkin.FallbackCheckinService;
import android.server.search.SearchManagerService;
import android.util.EventLog;
import android.util.Log;
+import dalvik.system.TouchDex;
import dalvik.system.VMRuntime;
import com.android.server.am.ActivityManagerService;
@@ -46,7 +48,6 @@ import com.android.server.status.StatusBarService;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
-
class ServerThread extends Thread {
private static final String TAG = "SystemServer";
private final static boolean INCLUDE_DEMO = false;
@@ -61,9 +62,9 @@ class ServerThread extends Thread {
}
@Override
public void onChange(boolean selfChange) {
- boolean enableAdb = (Settings.System.getInt(mContentResolver,
- Settings.System.ADB_ENABLED, 0) > 0);
- // setting this system property will start or stop adbd
+ boolean enableAdb = (Settings.Secure.getInt(mContentResolver,
+ Settings.Secure.ADB_ENABLED, 0) > 0);
+ // setting this secure property will start or stop adbd
SystemProperties.set("persist.service.adb.enable", enableAdb ? "1" : "0");
}
}
@@ -83,12 +84,13 @@ class ServerThread extends Thread {
String factoryTestStr = SystemProperties.get("ro.factorytest");
int factoryTest = "".equals(factoryTestStr) ? SystemServer.FACTORY_TEST_OFF
: Integer.parseInt(factoryTestStr);
-
+
PowerManagerService power = null;
IPackageManager pm = null;
Context context = null;
WindowManagerService wm = null;
BluetoothDeviceService bluetooth = null;
+ BluetoothA2dpService bluetoothA2dp = null;
HeadsetObserver headset = null;
// Critical services...
@@ -96,7 +98,7 @@ class ServerThread extends Thread {
Log.i(TAG, "Starting Power Manager.");
power = new PowerManagerService();
ServiceManager.addService(Context.POWER_SERVICE, power);
-
+
Log.i(TAG, "Starting Activity Manager.");
context = ActivityManagerService.main(factoryTest);
@@ -104,43 +106,44 @@ class ServerThread extends Thread {
ServiceManager.addService("telephony.registry", new TelephonyRegistry(context));
AttributeCache.init(context);
-
+
Log.i(TAG, "Starting Package Manager.");
pm = PackageManagerService.main(context,
factoryTest != SystemServer.FACTORY_TEST_OFF);
ActivityManagerService.setSystemProcess();
-
+
mContentResolver = context.getContentResolver();
-
+
Log.i(TAG, "Starting Content Manager.");
ContentService.main(context,
factoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL);
-
+
Log.i(TAG, "Starting System Content Providers.");
ActivityManagerService.installSystemProviders();
-
+
Log.i(TAG, "Starting Battery Service.");
BatteryService battery = new BatteryService(context);
ServiceManager.addService("battery", battery);
- // only initialize the power service after we have started the
+ // only initialize the power service after we have started the
// content providers and the batter service.
power.init(context, ActivityManagerService.getDefault(), battery);
-
+
Log.i(TAG, "Starting Alarm Manager.");
AlarmManagerService alarm = new AlarmManagerService(context);
ServiceManager.addService(Context.ALARM_SERVICE, alarm);
Watchdog.getInstance().init(context, battery, power, alarm,
ActivityManagerService.self());
-
+
// Sensor Service is needed by Window Manager, so this goes first
Log.i(TAG, "Starting Sensor Service.");
ServiceManager.addService(Context.SENSOR_SERVICE, new SensorService(context));
Log.i(TAG, "Starting Window Manager.");
- wm = WindowManagerService.main(context, power);
+ wm = WindowManagerService.main(context, power,
+ factoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL);
ServiceManager.addService(Context.WINDOW_SERVICE, wm);
((ActivityManagerService)ServiceManager.getService("activity"))
@@ -160,9 +163,12 @@ class ServerThread extends Thread {
bluetooth = new BluetoothDeviceService(context);
bluetooth.init();
ServiceManager.addService(Context.BLUETOOTH_SERVICE, bluetooth);
+ bluetoothA2dp = new BluetoothA2dpService(context);
+ ServiceManager.addService(BluetoothA2dpService.BLUETOOTH_A2DP_SERVICE,
+ bluetoothA2dp);
- int bluetoothOn = Settings.System.getInt(mContentResolver,
- Settings.System.BLUETOOTH_ON, 0);
+ int bluetoothOn = Settings.Secure.getInt(mContentResolver,
+ Settings.Secure.BLUETOOTH_ON, 0);
if (bluetoothOn > 0) {
bluetooth.enable(null);
}
@@ -172,8 +178,10 @@ class ServerThread extends Thread {
Log.e("System", "Failure starting core service", e);
}
+ StatusBarService statusBar = null;
+ InputMethodManagerService imm = null;
+
if (factoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
- StatusBarService statusBar = null;
try {
Log.i(TAG, "Starting Status Bar Service.");
statusBar = new StatusBarService(context);
@@ -182,7 +190,22 @@ class ServerThread extends Thread {
} catch (Throwable e) {
Log.e(TAG, "Failure starting StatusBarService", e);
}
-
+
+ try {
+ Log.i(TAG, "Starting Clipboard Service.");
+ ServiceManager.addService("clipboard", new ClipboardService(context));
+ } catch (Throwable e) {
+ Log.e(TAG, "Failure starting Clipboard Service", e);
+ }
+
+ try {
+ Log.i(TAG, "Starting Input Method Service.");
+ imm = new InputMethodManagerService(context, statusBar);
+ ServiceManager.addService(Context.INPUT_METHOD_SERVICE, imm);
+ } catch (Throwable e) {
+ Log.e(TAG, "Failure starting Input Manager Service", e);
+ }
+
try {
Log.i(TAG, "Starting Hardware Service.");
ServiceManager.addService("hardware", new HardwareService(context));
@@ -199,7 +222,7 @@ class ServerThread extends Thread {
try {
Log.i(TAG, "Starting Connectivity Service.");
- ServiceManager.addService(Context.CONNECTIVITY_SERVICE,
+ ServiceManager.addService(Context.CONNECTIVITY_SERVICE,
ConnectivityService.getInstance(context));
} catch (Throwable e) {
Log.e(TAG, "Failure starting Connectivity Service", e);
@@ -217,25 +240,25 @@ class ServerThread extends Thread {
// MountService must start after NotificationManagerService
Log.i(TAG, "Starting Mount Service.");
ServiceManager.addService("mount", new MountService(context));
-
} catch (Throwable e) {
Log.e(TAG, "Failure starting Mount Service", e);
}
try {
- Log.i(TAG, "Starting DeviceMemoryMonitor service");
- ServiceManager.addService("devicememorymonitor", new DeviceMemoryMonitorService(context));
+ Log.i(TAG, "Starting DeviceStorageMonitor service");
+ ServiceManager.addService(DeviceStorageMonitorService.SERVICE,
+ new DeviceStorageMonitorService(context));
} catch (Throwable e) {
- Log.e(TAG, "Failure starting DeviceMemoryMonitor service", e);
+ Log.e(TAG, "Failure starting DeviceStorageMonitor service", e);
}
-
+
try {
Log.i(TAG, "Starting Location Manager.");
ServiceManager.addService(Context.LOCATION_SERVICE, new LocationManagerService(context));
} catch (Throwable e) {
Log.e(TAG, "Failure starting Location Manager", e);
}
-
+
try {
Log.i(TAG, "Starting Search Service.");
ServiceManager.addService( Context.SEARCH_SERVICE, new SearchManagerService(context) );
@@ -243,18 +266,11 @@ class ServerThread extends Thread {
Log.e(TAG, "Failure starting Search Service", e);
}
- try {
- Log.i(TAG, "Starting Clipboard Service.");
- ServiceManager.addService("clipboard", new ClipboardService(context));
- } catch (Throwable e) {
- Log.e(TAG, "Failure starting Clipboard Service", e);
- }
-
if (INCLUDE_DEMO) {
Log.i(TAG, "Installing demo data...");
(new DemoThread(context)).start();
}
-
+
try {
Log.i(TAG, "Starting Checkin Service");
addService(context, "checkin", "com.google.android.server.checkin.CheckinService",
@@ -276,7 +292,7 @@ class ServerThread extends Thread {
} catch (Throwable e) {
Log.e(TAG, "Failure starting Volume Service", e);
}
-
+
try {
Log.i(TAG, "Starting HeadsetObserver");
// Listen for wired headset changes
@@ -286,30 +302,36 @@ class ServerThread extends Thread {
}
}
- // make sure the ADB_ENABLED setting value matches the system property value
- Settings.System.putInt(mContentResolver, Settings.System.ADB_ENABLED,
+ // make sure the ADB_ENABLED setting value matches the secure property value
+ Settings.Secure.putInt(mContentResolver, Settings.Secure.ADB_ENABLED,
"1".equals(SystemProperties.get("persist.service.adb.enable")) ? 1 : 0);
// register observer to listen for settings changes
- mContentResolver.registerContentObserver(Settings.System.getUriFor(Settings.System.ADB_ENABLED),
+ mContentResolver.registerContentObserver(Settings.Secure.getUriFor(Settings.Secure.ADB_ENABLED),
false, new AdbSettingsObserver());
// It is now time to start up the app processes...
+ if (statusBar != null) {
+ statusBar.systemReady();
+ }
+ if (imm != null) {
+ imm.systemReady();
+ }
wm.systemReady();
power.systemReady();
try {
pm.systemReady();
} catch (RemoteException e) {
}
-
+
// After making the following code, third party code may be running...
try {
ActivityManagerNative.getDefault().systemReady();
} catch (RemoteException e) {
}
-
+
Watchdog.getInstance().start();
-
+
Looper.loop();
Log.d(TAG, "System ServerThread is exiting!");
}
diff --git a/services/java/com/android/server/TelephonyRegistry.java b/services/java/com/android/server/TelephonyRegistry.java
index 70ade1d..dbaf086 100644
--- a/services/java/com/android/server/TelephonyRegistry.java
+++ b/services/java/com/android/server/TelephonyRegistry.java
@@ -16,19 +16,18 @@
package com.android.server;
-import android.app.ActivityManagerNative;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
-import android.os.Bundle;
import android.os.Binder;
+import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.telephony.CellLocation;
import android.telephony.PhoneStateListener;
import android.telephony.ServiceState;
import android.telephony.TelephonyManager;
-import android.util.Log;
+import android.text.TextUtils;
import java.util.ArrayList;
import java.io.FileDescriptor;
@@ -41,9 +40,6 @@ import com.android.internal.telephony.Phone;
import com.android.internal.telephony.PhoneStateIntentReceiver;
import com.android.internal.telephony.TelephonyIntents;
-import static android.Manifest.permission.READ_PHONE_STATE;
-import static android.Manifest.permission.ACCESS_COARSE_LOCATION;
-
/**
* Since phone process can be restarted, this class provides a centralized
@@ -408,21 +404,23 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
Bundle data = new Bundle();
state.fillInNotifierBundle(data);
intent.putExtras(data);
- broadcastStickyIntent(intent);
+ mContext.sendStickyBroadcast(intent);
}
private void broadcastSignalStrengthChanged(int asu) {
Intent intent = new Intent(TelephonyIntents.ACTION_SIGNAL_STRENGTH_CHANGED);
intent.putExtra(PhoneStateIntentReceiver.INTENT_KEY_ASU, asu);
- broadcastStickyIntent(intent);
+ mContext.sendStickyBroadcast(intent);
}
private void broadcastCallStateChanged(int state, String incomingNumber) {
- Intent intent = new Intent(TelephonyIntents.ACTION_PHONE_STATE_CHANGED);
+ Intent intent = new Intent(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
intent.putExtra(Phone.STATE_KEY,
DefaultPhoneNotifier.convertCallState(state).toString());
- intent.putExtra(PhoneStateIntentReceiver.INTENT_KEY_NUM, incomingNumber);
- broadcastStickyIntent(intent);
+ if (!TextUtils.isEmpty(incomingNumber)) {
+ intent.putExtra(TelephonyManager.EXTRA_INCOMING_NUMBER, incomingNumber);
+ }
+ mContext.sendBroadcast(intent, android.Manifest.permission.READ_PHONE_STATE);
}
private void broadcastDataConnectionStateChanged(int state, boolean isDataConnectivityPossible,
@@ -437,16 +435,12 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
}
intent.putExtra(Phone.DATA_APN_KEY, apn);
intent.putExtra(Phone.DATA_IFACE_NAME_KEY, interfaceName);
- broadcastStickyIntent(intent);
+ mContext.sendStickyBroadcast(intent);
}
private void broadcastDataConnectionFailed(String reason) {
Intent intent = new Intent(TelephonyIntents.ACTION_DATA_CONNECTION_FAILED);
intent.putExtra(Phone.FAILURE_REASON_KEY, reason);
- broadcastStickyIntent(intent);
- }
-
- private static void broadcastStickyIntent(Intent intent) {
- ActivityManagerNative.broadcastStickyIntent(intent, null);
+ mContext.sendStickyBroadcast(intent);
}
}
diff --git a/services/java/com/android/server/Watchdog.java b/services/java/com/android/server/Watchdog.java
index 70f54ca..70c3110 100644
--- a/services/java/com/android/server/Watchdog.java
+++ b/services/java/com/android/server/Watchdog.java
@@ -783,7 +783,15 @@ public class Watchdog extends Thread {
c.set(Calendar.SECOND, (int)secondsSinceMidnight - (val*60));
c.set(Calendar.MILLISECOND, 0);
- return c.getTimeInMillis();
+ long newTime = c.getTimeInMillis();
+ if (newTime < curTime) {
+ // The given time (in seconds since midnight) has already passed for today, so advance
+ // by one day (due to daylight savings, etc., the delta may differ from 24 hours).
+ c.add(Calendar.DAY_OF_MONTH, 1);
+ newTime = c.getTimeInMillis();
+ }
+
+ return newTime;
}
@Override
diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java
index 8f69235..7a0deff 100644
--- a/services/java/com/android/server/WifiService.java
+++ b/services/java/com/android/server/WifiService.java
@@ -47,8 +47,8 @@ import android.os.Looper;
import android.os.Message;
import android.os.PowerManager;
import android.os.RemoteException;
+import android.os.BatteryManager;
import android.provider.Settings;
-import android.provider.Settings.Gservices;
import android.util.Log;
import android.text.TextUtils;
@@ -72,7 +72,7 @@ import java.io.PrintWriter;
public class WifiService extends IWifiManager.Stub {
private static final String TAG = "WifiService";
private static final boolean DBG = false;
- private static final Pattern scanResultPattern = Pattern.compile("\t{1,}");
+ private static final Pattern scanResultPattern = Pattern.compile("\t+");
private final WifiStateTracker mWifiStateTracker;
private Context mContext;
@@ -81,15 +81,16 @@ public class WifiService extends IWifiManager.Stub {
private AlarmManager mAlarmManager;
private PendingIntent mIdleIntent;
private static final int IDLE_REQUEST = 0;
+ private boolean mScreenOff;
private boolean mDeviceIdle;
- private boolean mChargerAttached;
- private final LockList mLocks = new LockList();
+ private int mPluggedType;
+ private final LockList mLocks = new LockList();
/**
- * See {@link Gservices#WIFI_IDLE_MS}. This is the default value if a
- * Gservices value is not present.
+ * See {@link Settings.System#WIFI_IDLE_MS}. This is the default value if a
+ * Settings.System value is not present.
*/
- private long mIdleMillis = 2 * 60 * 1000; /* 2 minutes */
+ private static final long DEFAULT_IDLE_MILLIS = 2 * 60 * 1000; /* 2 minutes */
private static final String WAKELOCK_TAG = "WifiService";
@@ -99,10 +100,11 @@ public class WifiService extends IWifiManager.Stub {
* observed to take about 5 seconds under normal circumstances. This
* provides a bit of extra margin.
* <p>
- * See {@link Gservices#WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS}.
- * This is the default value if a Gservices value is not present.
+ * See {@link android.provider.Settings.Secure#WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS}.
+ * This is the default value if a Settings.System value is not present.
*/
- private int mWakelockTimeout = 8000;
+ private static final int DEFAULT_WAKELOCK_TIMEOUT = 8000;
+
// Wake lock used by driver-stop operation
private static PowerManager.WakeLock mDriverStopWakeLock;
// Wake lock used by other operations
@@ -151,6 +153,12 @@ public class WifiService extends IWifiManager.Stub {
private char[] mScanResultBuffer;
private boolean mNeedReconfig;
+ /**
+ * Number of allowed radio frequency channels in various regulatory domains.
+ * This list is sufficient for 802.11b/g networks (2.4GHz range).
+ */
+ private static int[] sValidRegulatoryChannelCounts = new int[] {11, 13, 14};
+
private static final String ACTION_DEVICE_IDLE =
"com.android.server.WifiManager.action.DEVICE_IDLE";
@@ -164,11 +172,6 @@ public class WifiService extends IWifiManager.Stub {
mIsHiddenNetworkPresent = new HashMap<Integer, Boolean>();
mNumHiddenNetworkPresent = 0;
- ContentResolver contentResolver = context.getContentResolver();
- mIdleMillis = Gservices.getLong(contentResolver, Gservices.WIFI_IDLE_MS, mIdleMillis);
- mWakelockTimeout = Gservices.getInt(contentResolver,
- Gservices.WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS, mWakelockTimeout);
-
mScanResultCache = new LinkedHashMap<String, ScanResult>(
SCAN_RESULT_CACHE_SIZE, 0.75f, true) {
/*
@@ -214,7 +217,7 @@ public class WifiService extends IWifiManager.Stub {
Log.d(TAG, "WifiService starting up with Wi-Fi " +
(wifiEnabled ? "enabled" : "disabled"));
registerForBroadcasts();
- setWifiEnabledBlocking(wifiEnabled);
+ setWifiEnabledBlocking(wifiEnabled, false);
}
/**
@@ -369,16 +372,16 @@ public class WifiService extends IWifiManager.Stub {
private boolean getPersistedWifiEnabled() {
final ContentResolver cr = mContext.getContentResolver();
try {
- return Settings.System.getInt(cr, Settings.System.WIFI_ON) == 1;
+ return Settings.Secure.getInt(cr, Settings.Secure.WIFI_ON) == 1;
} catch (Settings.SettingNotFoundException e) {
- Settings.System.putInt(cr, Settings.System.WIFI_ON, 0);
+ Settings.Secure.putInt(cr, Settings.Secure.WIFI_ON, 0);
return false;
}
}
private void persistWifiEnabled(boolean enabled) {
final ContentResolver cr = mContext.getContentResolver();
- Settings.System.putInt(cr, Settings.System.WIFI_ON, enabled ? 1 : 0);
+ Settings.Secure.putInt(cr, Settings.Secure.WIFI_ON, enabled ? 1 : 0);
}
NetworkStateTracker getNetworkStateTracker() {
@@ -433,9 +436,7 @@ public class WifiService extends IWifiManager.Stub {
*/
synchronized (mWifiHandler) {
mWakeLock.acquire();
-
- mWifiHandler.obtainMessage(
- enable ? MESSAGE_ENABLE_WIFI : MESSAGE_DISABLE_WIFI).sendToTarget();
+ sendEnableMessage(enable, true);
}
return true;
@@ -444,10 +445,11 @@ public class WifiService extends IWifiManager.Stub {
/**
* Enables/disables Wi-Fi synchronously.
* @param enable {@code true} to turn Wi-Fi on, {@code false} to turn it off.
+ * @param persist {@code true} if the setting should be persisted.
* @return {@code true} if the operation succeeds (or if the existing state
* is the same as the requested state)
*/
- private boolean setWifiEnabledBlocking(boolean enable) {
+ private boolean setWifiEnabledBlocking(boolean enable, boolean persist) {
final int eventualWifiState = enable ? WIFI_STATE_ENABLED : WIFI_STATE_DISABLED;
if (mWifiState == eventualWifiState) {
@@ -501,13 +503,17 @@ public class WifiService extends IWifiManager.Stub {
// Success!
- persistWifiEnabled(enable);
+ if (persist) {
+ persistWifiEnabled(enable);
+ }
updateWifiState(eventualWifiState);
/*
- * Initiliaze the hidden networs state if the Wi-Fi is being turned on.
+ * Initialize the hidden networks state and the number of allowed
+ * radio channels if Wi-Fi is being turned on.
*/
if (enable) {
+ mWifiStateTracker.setNumAllowedChannels();
initializeHiddenNetworksState();
}
@@ -799,7 +805,7 @@ public class WifiService extends IWifiManager.Stub {
*/
int netId = config.networkId;
boolean newNetwork = netId == -1;
- boolean doReconfig = false;
+ boolean doReconfig;
int currentPriority;
// networkId of -1 means we want to create a new network
if (newNetwork) {
@@ -1350,6 +1356,78 @@ public class WifiService extends IWifiManager.Stub {
}
/**
+ * Set the number of radio frequency channels that are allowed to be used
+ * in the current regulatory domain. This method should be used only
+ * if the correct number of channels cannot be determined automatically
+ * for some reason. If the operation is successful, the new value is
+ * persisted as a System setting.
+ * @param numChannels the number of allowed channels. Must be greater than 0
+ * and less than or equal to 16.
+ * @return {@code true} if the operation succeeds, {@code false} otherwise, e.g.,
+ * {@code numChannels} is outside the valid range.
+ */
+ public boolean setNumAllowedChannels(int numChannels) {
+ enforceChangePermission();
+ /*
+ * Validate the argument. We'd like to let the Wi-Fi driver do this,
+ * but if Wi-Fi isn't currently enabled, that's not possible, and
+ * we want to persist the setting anyway,so that it will take
+ * effect when Wi-Fi does become enabled.
+ */
+ boolean found = false;
+ for (int validChan : sValidRegulatoryChannelCounts) {
+ if (validChan == numChannels) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ return false;
+ }
+
+ Settings.Secure.putInt(mContext.getContentResolver(),
+ Settings.Secure.WIFI_NUM_ALLOWED_CHANNELS,
+ numChannels);
+ mWifiStateTracker.setNumAllowedChannels(numChannels);
+ return true;
+ }
+
+ /**
+ * Return the number of frequency channels that are allowed
+ * to be used in the current regulatory domain.
+ * @return the number of allowed channels, or {@code -1} if an error occurs
+ */
+ public int getNumAllowedChannels() {
+ int numChannels;
+
+ enforceAccessPermission();
+ synchronized (mWifiStateTracker) {
+ /*
+ * If we can't get the value from the driver (e.g., because
+ * Wi-Fi is not currently enabled), get the value from
+ * Settings.
+ */
+ numChannels = WifiNative.getNumAllowedChannelsCommand();
+ if (numChannels < 0) {
+ numChannels = Settings.Secure.getInt(mContext.getContentResolver(),
+ Settings.Secure.WIFI_NUM_ALLOWED_CHANNELS,
+ -1);
+ }
+ }
+ return numChannels;
+ }
+
+ /**
+ * Return the list of valid values for the number of allowed radio channels
+ * for various regulatory domains.
+ * @return the list of channel counts
+ */
+ public int[] getValidChannelCounts() {
+ enforceAccessPermission();
+ return sValidRegulatoryChannelCounts;
+ }
+
+ /**
* Return the DHCP-assigned addresses from the last successful DHCP request,
* if any.
* @return the DHCP information
@@ -1364,29 +1442,83 @@ public class WifiService extends IWifiManager.Stub {
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
+ long idleMillis = Settings.System.getLong(mContext.getContentResolver(),
+ Settings.System.WIFI_IDLE_MS, DEFAULT_IDLE_MILLIS);
+ int stayAwakeConditions =
+ Settings.System.getInt(mContext.getContentResolver(),
+ Settings.System.STAY_ON_WHILE_PLUGGED_IN, 0);
if (action.equals(Intent.ACTION_AIRPLANE_MODE_CHANGED)) {
/* do nothing, we'll check isAirplaneModeOn later. */
} else if (action.equals(Intent.ACTION_SCREEN_ON)) {
mAlarmManager.cancel(mIdleIntent);
mDeviceIdle = false;
+ mScreenOff = false;
} else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
- long triggerTime = System.currentTimeMillis() + mIdleMillis;
- mAlarmManager.set(AlarmManager.RTC_WAKEUP, triggerTime, mIdleIntent);
+ mScreenOff = true;
+ /*
+ * Set a timer to put Wi-Fi to sleep, but only if the screen is off
+ * AND the "stay on while plugged in" setting doesn't match the
+ * current power conditions (i.e, not plugged in, plugged in to USB,
+ * or plugged in to AC).
+ */
+ if (!shouldStayAwake(stayAwakeConditions, mPluggedType)) {
+ long triggerTime = System.currentTimeMillis() + idleMillis;
+ mAlarmManager.set(AlarmManager.RTC_WAKEUP, triggerTime, mIdleIntent);
+ }
/* we can return now -- there's nothing to do until we get the idle intent back */
return;
} else if (action.equals(ACTION_DEVICE_IDLE)) {
mDeviceIdle = true;
} else if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {
- int plugged = intent.getIntExtra("plugged", 0);
- mChargerAttached = (plugged != 0);
+ /*
+ * Set a timer to put Wi-Fi to sleep, but only if the screen is off
+ * AND we are transitioning from a state in which the device was supposed
+ * to stay awake and a state in which it is not supposed to stay awake.
+ * If "stay awake" state is not changing, we do nothing, to avoid resetting
+ * the already-set timer.
+ */
+ int pluggedType = intent.getIntExtra("plugged", 0);
+ if (mScreenOff && shouldStayAwake(stayAwakeConditions, mPluggedType) &&
+ !shouldStayAwake(stayAwakeConditions, pluggedType)) {
+ long triggerTime = System.currentTimeMillis() + idleMillis;
+ mAlarmManager.set(AlarmManager.RTC_WAKEUP, triggerTime, mIdleIntent);
+ mPluggedType = pluggedType;
+ return;
+ }
+ mPluggedType = pluggedType;
} else {
return;
}
updateWifiState();
}
+
+ /**
+ * Determine whether the bit value corresponding to {@code pluggedType} is set in
+ * the bit string {@code stayAwakeConditions}. Because a {@code pluggedType} value
+ * of {@code 0} isn't really a plugged type, but rather an indication that the
+ * device isn't plugged in at all, there is no bit value corresponding to a
+ * {@code pluggedType} value of {@code 0}. That is why we shift by
+ * {@code pluggedType&nbsp;&mdash;&nbsp;1} instead of by {@code pluggedType}.
+ * @param stayAwakeConditions a bit string specifying which "plugged types" should
+ * keep the device (and hence Wi-Fi) awake.
+ * @param pluggedType the type of plug (USB, AC, or none) for which the check is
+ * being made
+ * @return {@code true} if {@code pluggedType} indicates that the device is
+ * supposed to stay awake, {@code false} otherwise.
+ */
+ private boolean shouldStayAwake(int stayAwakeConditions, int pluggedType) {
+ return (stayAwakeConditions & pluggedType) != 0;
+ }
};
+ private void sendEnableMessage(boolean enable, boolean persist) {
+ Message msg = Message.obtain(mWifiHandler,
+ (enable ? MESSAGE_ENABLE_WIFI : MESSAGE_DISABLE_WIFI),
+ (persist ? 1 : 0), 0);
+ msg.sendToTarget();
+ }
+
private void updateWifiState() {
boolean wifiEnabled = getPersistedWifiEnabled();
boolean airplaneMode = isAirplaneModeOn();
@@ -1399,17 +1531,22 @@ public class WifiService extends IWifiManager.Stub {
if (wifiShouldBeEnabled) {
if (wifiShouldBeStarted) {
mWakeLock.acquire();
- mWifiHandler.obtainMessage(MESSAGE_ENABLE_WIFI).sendToTarget();
+ sendEnableMessage(true, false);
mWakeLock.acquire();
- mWifiHandler.obtainMessage(MESSAGE_START_WIFI).sendToTarget();
+ mWifiHandler.sendEmptyMessage(MESSAGE_START_WIFI);
} else {
+ int wakeLockTimeout =
+ Settings.Secure.getInt(
+ mContext.getContentResolver(),
+ Settings.Secure.WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS,
+ DEFAULT_WAKELOCK_TIMEOUT);
mDriverStopWakeLock.acquire();
- mWifiHandler.obtainMessage(MESSAGE_STOP_WIFI).sendToTarget();
- mWifiHandler.sendEmptyMessageDelayed(MESSAGE_RELEASE_WAKELOCK, mWakelockTimeout);
+ mWifiHandler.sendEmptyMessage(MESSAGE_STOP_WIFI);
+ mWifiHandler.sendEmptyMessageDelayed(MESSAGE_RELEASE_WAKELOCK, wakeLockTimeout);
}
} else {
mWakeLock.acquire();
- mWifiHandler.obtainMessage(MESSAGE_DISABLE_WIFI).sendToTarget();
+ sendEnableMessage(false, false);
}
}
}
@@ -1454,24 +1591,24 @@ public class WifiService extends IWifiManager.Stub {
switch (msg.what) {
case MESSAGE_ENABLE_WIFI: {
- setWifiEnabledBlocking(true);
+ setWifiEnabledBlocking(true, msg.arg1 == 1);
/* fall through */
}
case MESSAGE_START_WIFI: {
- WifiNative.startDriverCommand();
+ mWifiStateTracker.startDriver();
mWakeLock.release();
break;
}
case MESSAGE_DISABLE_WIFI: {
- setWifiEnabledBlocking(false);
+ setWifiEnabledBlocking(false, msg.arg1 == 1);
mWakeLock.release();
break;
}
case MESSAGE_STOP_WIFI: {
- WifiNative.stopDriverCommand();
+ mWifiStateTracker.stopDriver();
// don't release wakelock
break;
}
@@ -1487,7 +1624,7 @@ public class WifiService extends IWifiManager.Stub {
}
}
}
-
+
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (mContext.checkCallingPermission(android.Manifest.permission.DUMP)
@@ -1498,6 +1635,9 @@ public class WifiService extends IWifiManager.Stub {
return;
}
pw.println("Wi-Fi is " + stateName(mWifiState));
+ pw.println("stay-awake conditions: " +
+ Settings.System.getInt(mContext.getContentResolver(),
+ Settings.System.STAY_ON_WHILE_PLUGGED_IN, 0));
pw.println();
pw.println("Latest scan results:");
diff --git a/services/java/com/android/server/WifiWatchdogService.java b/services/java/com/android/server/WifiWatchdogService.java
index f9edab4..e686bf0 100644
--- a/services/java/com/android/server/WifiWatchdogService.java
+++ b/services/java/com/android/server/WifiWatchdogService.java
@@ -31,7 +31,7 @@ import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.SystemProperties;
-import android.provider.Settings.System;
+import android.provider.Settings;
import android.text.TextUtils;
import android.util.Config;
import android.util.Log;
@@ -139,7 +139,7 @@ public class WifiWatchdogService {
private void registerForSettingsChanges() {
ContentResolver contentResolver = mContext.getContentResolver();
contentResolver.registerContentObserver(
- System.getUriFor(System.WIFI_WATCHDOG_ON), false,
+ Settings.Secure.getUriFor(Settings.Secure.WIFI_WATCHDOG_ON), false,
new ContentObserver(mHandler) {
@Override
public void onChange(boolean selfChange) {
@@ -156,84 +156,90 @@ public class WifiWatchdogService {
}
/**
- * @see System#WIFI_WATCHDOG_ON
+ * @see android.provider.Settings.Secure#WIFI_WATCHDOG_ON
*/
private boolean isWatchdogEnabled() {
- return System.getInt(mContentResolver, System.WIFI_WATCHDOG_ON, 1) == 1;
+ return Settings.Secure.getInt(mContentResolver, Settings.Secure.WIFI_WATCHDOG_ON, 1) == 1;
}
/**
- * @see System#WIFI_WATCHDOG_AP_COUNT
+ * @see android.provider.Settings.Secure#WIFI_WATCHDOG_AP_COUNT
*/
private int getApCount() {
- return System.getInt(mContentResolver, System.WIFI_WATCHDOG_AP_COUNT, 2);
+ return Settings.Secure.getInt(mContentResolver,
+ Settings.Secure.WIFI_WATCHDOG_AP_COUNT, 2);
}
/**
- * @see System#WIFI_WATCHDOG_INITIAL_IGNORED_PING_COUNT
+ * @see android.provider.Settings.Secure#WIFI_WATCHDOG_INITIAL_IGNORED_PING_COUNT
*/
private int getInitialIgnoredPingCount() {
- return System.getInt(mContentResolver, System.WIFI_WATCHDOG_INITIAL_IGNORED_PING_COUNT , 2);
+ return Settings.Secure.getInt(mContentResolver,
+ Settings.Secure.WIFI_WATCHDOG_INITIAL_IGNORED_PING_COUNT , 2);
}
/**
- * @see System#WIFI_WATCHDOG_PING_COUNT
+ * @see android.provider.Settings.Secure#WIFI_WATCHDOG_PING_COUNT
*/
private int getPingCount() {
- return System.getInt(mContentResolver, System.WIFI_WATCHDOG_PING_COUNT, 4);
+ return Settings.Secure.getInt(mContentResolver,
+ Settings.Secure.WIFI_WATCHDOG_PING_COUNT, 4);
}
/**
- * @see System#WIFI_WATCHDOG_PING_TIMEOUT_MS
+ * @see android.provider.Settings.Secure#WIFI_WATCHDOG_PING_TIMEOUT_MS
*/
private int getPingTimeoutMs() {
- return System.getInt(mContentResolver, System.WIFI_WATCHDOG_PING_TIMEOUT_MS, 500);
+ return Settings.Secure.getInt(mContentResolver,
+ Settings.Secure.WIFI_WATCHDOG_PING_TIMEOUT_MS, 500);
}
/**
- * @see System#WIFI_WATCHDOG_PING_DELAY_MS
+ * @see android.provider.Settings.Secure#WIFI_WATCHDOG_PING_DELAY_MS
*/
private int getPingDelayMs() {
- return System.getInt(mContentResolver, System.WIFI_WATCHDOG_PING_DELAY_MS, 250);
+ return Settings.Secure.getInt(mContentResolver,
+ Settings.Secure.WIFI_WATCHDOG_PING_DELAY_MS, 250);
}
/**
- * @see System#WIFI_WATCHDOG_ACCEPTABLE_PACKET_LOSS_PERCENTAGE
+ * @see android.provider.Settings.Secure#WIFI_WATCHDOG_ACCEPTABLE_PACKET_LOSS_PERCENTAGE
*/
private int getAcceptablePacketLossPercentage() {
- return System.getInt(mContentResolver,
- System.WIFI_WATCHDOG_ACCEPTABLE_PACKET_LOSS_PERCENTAGE, 25);
+ return Settings.Secure.getInt(mContentResolver,
+ Settings.Secure.WIFI_WATCHDOG_ACCEPTABLE_PACKET_LOSS_PERCENTAGE, 25);
}
/**
- * @see System#WIFI_WATCHDOG_MAX_AP_CHECKS
+ * @see android.provider.Settings.Secure#WIFI_WATCHDOG_MAX_AP_CHECKS
*/
private int getMaxApChecks() {
- return System.getInt(mContentResolver, System.WIFI_WATCHDOG_MAX_AP_CHECKS, 7);
+ return Settings.Secure.getInt(mContentResolver,
+ Settings.Secure.WIFI_WATCHDOG_MAX_AP_CHECKS, 7);
}
/**
- * @see System#WIFI_WATCHDOG_BACKGROUND_CHECK_ENABLED
+ * @see android.provider.Settings.Secure#WIFI_WATCHDOG_BACKGROUND_CHECK_ENABLED
*/
private boolean isBackgroundCheckEnabled() {
- return System.getInt(mContentResolver, System.WIFI_WATCHDOG_BACKGROUND_CHECK_ENABLED, 1)
- == 1;
+ return Settings.Secure.getInt(mContentResolver,
+ Settings.Secure.WIFI_WATCHDOG_BACKGROUND_CHECK_ENABLED, 1) == 1;
}
/**
- * @see System#WIFI_WATCHDOG_BACKGROUND_CHECK_DELAY_MS
+ * @see android.provider.Settings.Secure#WIFI_WATCHDOG_BACKGROUND_CHECK_DELAY_MS
*/
private int getBackgroundCheckDelayMs() {
- return System.getInt(mContentResolver,
- System.WIFI_WATCHDOG_BACKGROUND_CHECK_DELAY_MS, 5000);
+ return Settings.Secure.getInt(mContentResolver,
+ Settings.Secure.WIFI_WATCHDOG_BACKGROUND_CHECK_DELAY_MS, 5000);
}
/**
- * @see System#WIFI_WATCHDOG_BACKGROUND_CHECK_TIMEOUT_MS
+ * @see android.provider.Settings.Secure#WIFI_WATCHDOG_BACKGROUND_CHECK_TIMEOUT_MS
*/
private int getBackgroundCheckTimeoutMs() {
- return System.getInt(mContentResolver,
- System.WIFI_WATCHDOG_BACKGROUND_CHECK_TIMEOUT_MS, 1000);
+ return Settings.Secure.getInt(mContentResolver,
+ Settings.Secure.WIFI_WATCHDOG_BACKGROUND_CHECK_TIMEOUT_MS, 1000);
}
/**
@@ -326,7 +332,7 @@ public class WifiWatchdogService {
int pingDelay = getPingDelayMs();
int acceptableLoss = getAcceptablePacketLossPercentage();
- /** See {@link System#WIFI_WATCHDOG_INITIAL_IGNORED_PING_COUNT} */
+ /** See {@link Secure#WIFI_WATCHDOG_INITIAL_IGNORED_PING_COUNT} */
int ignoredPingCounter = 0;
int pingCounter = 0;
int successCounter = 0;
@@ -959,7 +965,7 @@ public class WifiWatchdogService {
* thread will ensure when it sees the message that the state is still
* valid for going to sleep.
* <p>
- * For an explanation of sleep, see {@link System#WIFI_WATCHDOG_MAX_AP_CHECKS}.
+ * For an explanation of sleep, see {@link android.provider.Settings.Secure#WIFI_WATCHDOG_MAX_AP_CHECKS}.
*/
static final int MESSAGE_SLEEP = 101;
/** Disables the watchdog. */
@@ -1166,7 +1172,7 @@ public class WifiWatchdogService {
private static class DnsPinger {
/** Number of bytes for the query */
- private static final int DNS_QUERY_BASE_SIZE = 12;
+ private static final int DNS_QUERY_BASE_SIZE = 33;
/** The DNS port */
private static final int DNS_PORT = 53;
@@ -1227,21 +1233,54 @@ public class WifiWatchdogService {
}
private static void fillQuery(byte[] buf) {
- int i = 0;
- // See RFC2929, section 2
+ /*
+ * See RFC2929 (though the bit tables in there are misleading for
+ * us. For example, the recursion desired bit is the 0th bit for us,
+ * but looking there it would appear as the 7th bit of the byte
+ */
+
+ // Make sure it's all zeroed out
+ for (int i = 0; i < buf.length; i++) buf[i] = 0;
+
+ // Form a query for www.android.com
- // [0-1] bytes are an ID
- buf[i++] = (byte) sRandom.nextInt(256);
- buf[i++] = (byte) sRandom.nextInt(256);
+ // [0-1] bytes are an ID, generate random ID for this query
+ buf[0] = (byte) sRandom.nextInt(256);
+ buf[1] = (byte) sRandom.nextInt(256);
// [2-3] bytes are for flags.
- // The Opcode is '2' for server status. It is on bits [1-4] of this byte.
- buf[i++] = 4;
- buf[i++] = 0;
+ buf[2] = 1; // Recursion desired
+
+ // [4-5] bytes are for the query count
+ buf[5] = 1; // One query
+
+ // [6-7] [8-9] [10-11] are all counts of other fields we don't use
+
+ // [12-15] for www
+ writeString(buf, 12, "www");
- // [4-5] [6-7] [8-9] [10-11] are all counts of other fields we don't use
- for (; i <= 11; i++) buf[i] = 0;
+ // [16-23] for android
+ writeString(buf, 16, "android");
+
+ // [24-27] for com
+ writeString(buf, 24, "com");
+
+ // [29-30] bytes are for QTYPE, set to 1
+ buf[30] = 1;
+
+ // [31-32] bytes are for QCLASS, set to 1
+ buf[32] = 1;
+ }
+
+ private static void writeString(byte[] buf, int startPos, String string) {
+ int pos = startPos;
+
+ // Write the length first
+ buf[pos++] = (byte) string.length();
+ for (int i = 0; i < string.length(); i++) {
+ buf[pos++] = (byte) string.charAt(i);
+ }
}
}
}
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index 4ad2c42..9671743 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -25,6 +25,8 @@ import static android.view.WindowManager.LayoutParams.FLAG_BLUR_BEHIND;
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_SYSTEM_ERROR;
+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.LAST_APPLICATION_WINDOW;
import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW;
import static android.view.WindowManager.LayoutParams.MEMORY_TYPE_GPU;
@@ -32,11 +34,16 @@ import static android.view.WindowManager.LayoutParams.MEMORY_TYPE_HARDWARE;
import static android.view.WindowManager.LayoutParams.MEMORY_TYPE_PUSH_BUFFERS;
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_INPUT_METHOD;
+import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
import com.android.internal.app.IBatteryStats;
import com.android.internal.policy.PolicyManager;
+import com.android.internal.view.IInputContext;
+import com.android.internal.view.IInputMethodClient;
+import com.android.internal.view.IInputMethodManager;
import com.android.server.KeyInputQueue.QueuedEvent;
-import com.android.server.am.BatteryStats;
+import com.android.server.am.BatteryStatsService;
import android.Manifest;
import android.app.ActivityManagerNative;
@@ -49,6 +56,7 @@ import android.graphics.Matrix;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.Region;
+import android.os.BatteryStats;
import android.os.Binder;
import android.os.Debug;
import android.os.Handler;
@@ -84,6 +92,7 @@ import android.view.RawInputEvent;
import android.view.Surface;
import android.view.SurfaceSession;
import android.view.View;
+import android.view.ViewTreeObserver;
import android.view.WindowManager;
import android.view.WindowManagerImpl;
import android.view.WindowManagerPolicy;
@@ -152,6 +161,16 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
*/
static final int MAX_ANIMATION_DURATION = 10*1000;
+ /** Amount of time (in milliseconds) to animate the dim surface from one
+ * value to another, when no window animation is driving it.
+ */
+ static final int DEFAULT_DIM_DURATION = 200;
+
+ static final int UPDATE_FOCUS_NORMAL = 0;
+ static final int UPDATE_FOCUS_WILL_ASSIGN_LAYERS = 1;
+ static final int UPDATE_FOCUS_PLACING_SURFACES = 2;
+ static final int UPDATE_FOCUS_WILL_PLACE_SURFACES = 3;
+
private static final String SYSTEM_SECURE = "ro.secure";
/**
@@ -177,6 +196,8 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
final Context mContext;
+ final boolean mHaveInputMethods;
+
final WindowManagerPolicy mPolicy = PolicyManager.makeNewWindowManager();
final IActivityManager mActivityManager;
@@ -207,6 +228,12 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
final ArrayList<WindowToken> mTokenList = new ArrayList<WindowToken>();
/**
+ * Window tokens that are in the process of exiting, but still
+ * on screen for animations.
+ */
+ final ArrayList<WindowToken> mExitingTokens = new ArrayList<WindowToken>();
+
+ /**
* Z-ordered (bottom-most first) list of all application tokens, for
* controlling the ordering of windows in different applications. This
* contains WindowToken objects.
@@ -259,9 +286,15 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
*/
ArrayList<WindowState> mForceRemoves;
+ IInputMethodManager mInputMethodManager;
+
SurfaceSession mFxSession;
Surface mDimSurface;
boolean mDimShown;
+ float mDimCurrentAlpha;
+ float mDimTargetAlpha;
+ float mDimDeltaPerMs;
+ long mLastDimAnimTime;
Surface mBlurSurface;
boolean mBlurShown;
@@ -306,13 +339,20 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
WindowState mCurrentFocus = null;
WindowState mLastFocus = null;
+
+ // This just indicates the window the input method is on top of, not
+ // necessarily the window its input is going to.
+ WindowState mInputMethodTarget = null;
+
+ WindowState mInputMethodWindow = null;
+ final ArrayList<WindowState> mInputMethodDialogs = new ArrayList<WindowState>();
AppWindowToken mFocusedApp = null;
PowerManagerService mPowerManager;
float mWindowAnimationScale = 1.0f;
- float mTransitionAnimationScale = 0.0f;
+ float mTransitionAnimationScale = 1.0f;
final KeyWaiter mKeyWaiter = new KeyWaiter();
final KeyQ mQueue;
@@ -329,9 +369,11 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
private ViewServer mViewServer;
- public static WindowManagerService main(
- Context context, PowerManagerService pm) {
- WMThread thr = new WMThread(context, pm);
+ final Rect mTempRect = new Rect();
+
+ public static WindowManagerService main(Context context,
+ PowerManagerService pm, boolean haveInputMethods) {
+ WMThread thr = new WMThread(context, pm, haveInputMethods);
thr.start();
synchronized (thr) {
@@ -351,16 +393,20 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
private final Context mContext;
private final PowerManagerService mPM;
+ private final boolean mHaveInputMethods;
- public WMThread(Context context, PowerManagerService pm) {
+ public WMThread(Context context, PowerManagerService pm,
+ boolean haveInputMethods) {
super("WindowManager");
mContext = context;
mPM = pm;
+ mHaveInputMethods = haveInputMethods;
}
public void run() {
Looper.prepare();
- WindowManagerService s = new WindowManagerService(mContext, mPM);
+ WindowManagerService s = new WindowManagerService(mContext, mPM,
+ mHaveInputMethods);
android.os.Process.setThreadPriority(
android.os.Process.THREAD_PRIORITY_DISPLAY);
@@ -407,14 +453,16 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
}
- private WindowManagerService(Context context, PowerManagerService pm) {
+ private WindowManagerService(Context context, PowerManagerService pm,
+ boolean haveInputMethods) {
mContext = context;
+ mHaveInputMethods = haveInputMethods;
mPowerManager = pm;
mPowerManager.setPolicy(mPolicy);
mActivityManager = ActivityManagerNative.getDefault();
- mBatteryStats = BatteryStats.getService();
+ mBatteryStats = BatteryStatsService.getService();
// Get persisted window scale setting
mWindowAnimationScale = Settings.System.getFloat(context.getContentResolver(),
@@ -450,7 +498,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
try {
return super.onTransact(code, data, reply, flags);
} catch (RuntimeException e) {
- // The activity manager only throws security exceptions, so let's
+ // The window manager only throws security exceptions, so let's
// log all others.
if (!(e instanceof SecurityException)) {
Log.e(TAG, "Window Manager Crash", e);
@@ -674,9 +722,144 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
}
+ int findDesiredInputMethodWindowIndexLocked() {
+ final ArrayList localmWindows = mWindows;
+ final int N = localmWindows.size();
+ WindowState w = null;
+ int i = N;
+ while (i > 0) {
+ i--;
+ w = (WindowState)localmWindows.get(i);
+ final int fl = w.mAttrs.flags
+ & (FLAG_NOT_FOCUSABLE|FLAG_ALT_FOCUSABLE_IM);
+ //Log.i(TAG, "Checking window @" + i + " " + w + " fl=0x"
+ // + Integer.toHexString(fl));
+ if (fl == 0 || fl == (FLAG_NOT_FOCUSABLE|FLAG_ALT_FOCUSABLE_IM)) {
+ //Log.i(TAG, "Putting input method here!");
+ if (w.isVisibleOrAdding()) {
+ break;
+ }
+ }
+ }
+ //Log.i(TAG, "Placing input method @" + (i+1));
+ if (w != null) {
+ mInputMethodTarget = w;
+ return i+1;
+ }
+ mInputMethodTarget = null;
+ return -1;
+ }
+
+ void addInputMethodWindowToListLocked(WindowState win) {
+ int pos = findDesiredInputMethodWindowIndexLocked();
+ if (pos >= 0) {
+ win.mTargetAppToken = mInputMethodTarget.mAppToken;
+ mWindows.add(pos, win);
+ moveInputMethodDialogsLocked(pos+1);
+ return;
+ }
+ win.mTargetAppToken = null;
+ addWindowToListInOrderLocked(win);
+ moveInputMethodDialogsLocked(pos);
+ }
+
+ void moveInputMethodDialogsLocked(int pos) {
+ ArrayList<WindowState> dialogs = mInputMethodDialogs;
+ final int N = dialogs.size();
+ for (int i=0; i<N; i++) {
+ int wpos = mWindows.indexOf(dialogs.get(i));
+ if (wpos >= 0) {
+ if (wpos < pos) pos--;
+ mWindows.remove(wpos);
+ }
+ }
+ if (pos >= 0) {
+ final AppWindowToken targetAppToken = mInputMethodTarget.mAppToken;
+ WindowState wp = (WindowState)mWindows.get(pos);
+ if (wp == mInputMethodWindow) {
+ pos++;
+ }
+ for (int i=0; i<N; i++) {
+ WindowState win = dialogs.get(i);
+ win.mTargetAppToken = targetAppToken;
+ mWindows.add(pos, win);
+ pos++;
+ }
+ return;
+ }
+ for (int i=0; i<N; i++) {
+ WindowState win = dialogs.get(i);
+ win.mTargetAppToken = null;
+ addWindowToListInOrderLocked(win);
+ }
+ }
+
+ boolean moveInputMethodWindowsIfNeededLocked(boolean needAssignLayers) {
+ final WindowState imWin = mInputMethodWindow;
+ final int DN = mInputMethodDialogs.size();
+ if (imWin == null && DN == 0) {
+ return false;
+ }
+
+ int imPos = findDesiredInputMethodWindowIndexLocked();
+ if (imPos >= 0) {
+ // In this case, the input method windows are to be placed
+ // immediately above the window they are targeting.
+
+ WindowState firstImWin = imPos < DN
+ ? (WindowState)mWindows.get(imPos) : null;
+ if (imWin != null) {
+ if (imWin == firstImWin) {
+ // Already at the correct location!
+ return false;
+ }
+ } else {
+ if (mInputMethodDialogs.get(0) == firstImWin) {
+ // Already at the correct location!
+ return false;
+ }
+ }
+
+ if (imWin != null) {
+ int oldPos = mWindows.indexOf(imWin);
+ mWindows.remove(oldPos);
+ if (imPos > oldPos) imPos--;
+ imWin.mTargetAppToken = mInputMethodTarget.mAppToken;
+ mWindows.add(imPos, imWin);
+ if (DN > 0) moveInputMethodDialogsLocked(imPos+1);
+ } else {
+ moveInputMethodDialogsLocked(imPos);
+ }
+
+ } else {
+ // In this case, the input method windows go in a fixed layer,
+ // because they aren't currently associated with a focus window.
+
+ if (imWin != null) {
+ mWindows.remove(imWin);
+ imWin.mTargetAppToken = null;
+ addWindowToListInOrderLocked(imWin);
+ if (DN > 0) moveInputMethodDialogsLocked(-1);;
+ } else {
+ moveInputMethodDialogsLocked(-1);;
+ }
+
+ }
+
+ if (needAssignLayers) {
+ assignLayersLocked();
+ }
+
+ return true;
+ }
+
+ void adjustInputMethodDialogsLocked() {
+ moveInputMethodDialogsLocked(findDesiredInputMethodWindowIndexLocked());
+ }
+
public int addWindow(Session session, IWindow client,
WindowManager.LayoutParams attrs, int viewVisibility,
- Rect outCoveredInsets) {
+ Rect outContentInsets) {
int res = mPolicy.checkAddPermission(attrs);
if (res != WindowManagerImpl.ADD_OKAY) {
return res;
@@ -703,7 +886,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
if (attrs.type >= FIRST_SUB_WINDOW && attrs.type <= LAST_SUB_WINDOW) {
- attachedWindow = windowForClientLocked(session, attrs.token);
+ attachedWindow = windowForClientLocked(null, attrs.token);
if (attachedWindow == null) {
Log.w(TAG, "Attempted to add window with token that is not a window: "
+ attrs.token + ". Aborting.");
@@ -726,7 +909,12 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
+ attrs.token + ". Aborting.");
return WindowManagerImpl.ADD_BAD_APP_TOKEN;
}
- token = new WindowToken(attrs.token);
+ if (attrs.type == TYPE_INPUT_METHOD) {
+ Log.w(TAG, "Attempted to add input method window with unknown token "
+ + attrs.token + ". Aborting.");
+ return WindowManagerImpl.ADD_BAD_APP_TOKEN;
+ }
+ token = new WindowToken(attrs.token, -1);
addToken = true;
} else if (attrs.type >= FIRST_APPLICATION_WINDOW
&& attrs.type <= LAST_APPLICATION_WINDOW) {
@@ -746,6 +934,12 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
TAG, "**** NO NEED TO START: " + attrs.getTitle());
return WindowManagerImpl.ADD_STARTING_NOT_NEEDED;
}
+ } else if (attrs.type == TYPE_INPUT_METHOD) {
+ if (token.windowType != TYPE_INPUT_METHOD) {
+ Log.w(TAG, "Attempted to add input method window with bad token "
+ + attrs.token + ". Aborting.");
+ return WindowManagerImpl.ADD_BAD_APP_TOKEN;
+ }
}
win = new WindowState(session, client, token,
@@ -783,19 +977,25 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
token.appWindowToken.startingWindow = win;
}
- addWindowToListInOrderLocked(win);
+ boolean imMayMove = true;
- assignLayersLocked();
- // Don't do layout here, the window must call
- // relayout to be displayed, so we'll do it there.
+ if (attrs.type == TYPE_INPUT_METHOD) {
+ mInputMethodWindow = win;
+ addInputMethodWindowToListLocked(win);
+ imMayMove = false;
+ } else if (attrs.type == TYPE_INPUT_METHOD_DIALOG) {
+ mInputMethodDialogs.add(win);
+ adjustInputMethodDialogsLocked();
+ imMayMove = false;
+ } else {
+ addWindowToListInOrderLocked(win);
+ }
- //dump();
-
Binder.restoreCallingIdentity(origId);
win.mEnterAnimationPending = true;
- mPolicy.getCoveredInsetHintLw(attrs, outCoveredInsets);
+ mPolicy.getContentInsetHintLw(attrs, outContentInsets);
if (mInTouchMode) {
res |= WindowManagerImpl.ADD_FLAG_IN_TOUCH_MODE;
@@ -805,9 +1005,21 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
if (win.canReceiveKeys()) {
- updateFocusedWindowLocked();
+ if (updateFocusedWindowLocked(UPDATE_FOCUS_WILL_ASSIGN_LAYERS)) {
+ imMayMove = false;
+ }
+ }
+
+ if (imMayMove) {
+ moveInputMethodWindowsIfNeededLocked(false);
}
+ assignLayersLocked();
+ // Don't do layout here, the window must call
+ // relayout to be displayed, so we'll do it there.
+
+ //dump();
+
if (localLOGV) Log.v(
TAG, "New client " + client.asBinder()
+ ": window=" + win);
@@ -859,7 +1071,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
if (win.mSurface != null && !mDisplayFrozen) {
// If we are not currently running the exit animation, we
// need to see about starting one.
- if (!win.mExiting && !win.mDrawPending && !win.mCommitDrawPending) {
+ if (win.isVisible()) {
int transit = WindowManagerPolicy.TRANSIT_EXIT;
if (win.getAttrs().type == TYPE_APPLICATION_STARTING) {
transit = WindowManagerPolicy.TRANSIT_PREVIEW_DONE;
@@ -875,8 +1087,8 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
win.mExiting = true;
win.mRemoveOnExit = true;
mLayoutNeeded = true;
+ updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES);
performLayoutAndPlaceSurfacesLocked();
- updateFocusedWindowLocked();
if (win.mAppToken != null) {
win.mAppToken.updateReportedVisibilityLocked();
}
@@ -887,7 +1099,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
removeWindowInnerLocked(session, win);
- updateFocusedWindowLocked();
+ updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL);
Binder.restoreCallingIdentity(origId);
}
@@ -901,6 +1113,12 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
mWindowMap.remove(win.mClient.asBinder());
mWindows.remove(win);
+ if (mInputMethodWindow == win) {
+ mInputMethodWindow = null;
+ } else if (win.mAttrs.type == TYPE_INPUT_METHOD_DIALOG) {
+ mInputMethodDialogs.remove(win);
+ }
+
final WindowToken token = win.mToken;
final AppWindowToken atoken = win.mAppToken;
token.windows.remove(win);
@@ -967,10 +1185,44 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
}
+ void setInsetsWindow(Session session, IWindow client,
+ int touchableInsets, Rect contentInsets,
+ Rect visibleInsets) {
+ long origId = Binder.clearCallingIdentity();
+ try {
+ synchronized (mWindowMap) {
+ WindowState w = windowForClientLocked(session, client);
+ if (w != null) {
+ w.mGivenInsetsPending = false;
+ w.mGivenContentInsets.set(contentInsets);
+ w.mGivenVisibleInsets.set(visibleInsets);
+ w.mTouchableInsets = touchableInsets;
+ mLayoutNeeded = true;
+ performLayoutAndPlaceSurfacesLocked();
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(origId);
+ }
+ }
+
+ public void getWindowDisplayFrame(Session session, IWindow client,
+ Rect outDisplayFrame) {
+ synchronized(mWindowMap) {
+ WindowState win = windowForClientLocked(session, client);
+ if (win == null) {
+ outDisplayFrame.setEmpty();
+ return;
+ }
+ outDisplayFrame.set(win.mDisplayFrame);
+ }
+ }
- public int relayoutWindow(Session session, IWindow client, WindowManager.LayoutParams attrs,
- int requestedWidth, int requestedHeight, int viewVisibility, Rect outFrame,
- Rect outCoveredInsets, Surface outSurface) {
+ public int relayoutWindow(Session session, IWindow client,
+ WindowManager.LayoutParams attrs, int requestedWidth,
+ int requestedHeight, int viewVisibility, boolean insetsPending,
+ Rect outFrame, Rect outContentInsets, Rect outVisibleInsets,
+ Surface outSurface) {
boolean displayed = false;
boolean inTouchMode;
@@ -988,12 +1240,12 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
mPolicy.adjustWindowParamsLw(attrs);
}
- boolean windowfocusabilityChanged = attrs != null &&
- ((attrs.flags & WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE) !=
- (win.mAttrs.flags & WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE));
-
int attrChanges = 0;
- if (attrs != null) attrChanges = win.mAttrs.copyFrom(attrs);
+ int flagChanges = 0;
+ if (attrs != null) {
+ flagChanges = win.mAttrs.flags ^= attrs.flags;
+ attrChanges = win.mAttrs.copyFrom(attrs);
+ }
if (localLOGV) Log.v(
TAG, "Relayout given client " + client.asBinder()
@@ -1016,10 +1268,16 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
(attrs.height / (float)requestedHeight) : 1.0f;
}
+ boolean imMayMove = (flagChanges&(
+ WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM |
+ WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE)) != 0;
+
boolean focusMayChange = win.mViewVisibility != viewVisibility
- || windowfocusabilityChanged
+ || ((flagChanges&WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE) != 0)
|| (!win.mRelayoutCalled);
+
win.mRelayoutCalled = true;
+ final int oldVisibility = win.mViewVisibility;
win.mViewVisibility = viewVisibility;
if (viewVisibility == View.VISIBLE &&
(win.mAppToken == null || !win.mAppToken.clientHidden)) {
@@ -1032,6 +1290,9 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
win.mDestroying = false;
mDestroySurface.remove(win);
}
+ if (oldVisibility == View.GONE) {
+ win.mEnterAnimationPending = true;
+ }
if (displayed && win.mSurface != null && !win.mDrawPending
&& !win.mCommitDrawPending && !mDisplayFrozen) {
applyEnterAnimationLocked(win);
@@ -1053,7 +1314,13 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
if (displayed) {
focusMayChange = true;
}
+ if (win.mAttrs.type == TYPE_INPUT_METHOD
+ && mInputMethodWindow == null) {
+ mInputMethodWindow = win;
+ imMayMove = true;
+ }
} else {
+ win.mEnterAnimationPending = false;
if (win.mSurface != null) {
// If we are not currently running the exit animation, we
// need to see about starting one.
@@ -1064,7 +1331,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
if (win.getAttrs().type == TYPE_APPLICATION_STARTING) {
transit = WindowManagerPolicy.TRANSIT_PREVIEW_DONE;
}
- if (!win.mExiting && !win.mDrawPending &&
+ if (win.isVisible() &&
applyAnimationLocked(win, transit, false)) {
win.mExiting = true;
mKeyWaiter.finishedKey(session, client, true,
@@ -1078,16 +1345,41 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
}
}
+ if (mInputMethodWindow == win) {
+ mInputMethodWindow = null;
+ }
outSurface.clear();
}
+ boolean assignLayers = false;
+
+ if (focusMayChange) {
+ //System.out.println("Focus may change: " + win.mAttrs.getTitle());
+ if (updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES)) {
+ assignLayers = true;
+ imMayMove = false;
+ }
+ //System.out.println("Relayout " + win + ": focus=" + mCurrentFocus);
+ }
+
+ if (imMayMove) {
+ if (moveInputMethodWindowsIfNeededLocked(false)) {
+ assignLayers = true;
+ }
+ }
+
mLayoutNeeded = true;
+ win.mGivenInsetsPending = insetsPending;
+ if (assignLayers) {
+ assignLayersLocked();
+ }
performLayoutAndPlaceSurfacesLocked();
if (win.mAppToken != null) {
win.mAppToken.updateReportedVisibilityLocked();
}
outFrame.set(win.mFrame);
- outCoveredInsets.set(win.mCoveredInsets);
+ outContentInsets.set(win.mContentInsets);
+ outVisibleInsets.set(win.mVisibleInsets);
if (localLOGV) Log.v(
TAG, "Relayout given client " + client.asBinder()
+ ", requestedWidth=" + requestedWidth
@@ -1099,12 +1391,6 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
if (localLOGV || DEBUG_FOCUS) Log.v(
TAG, "Relayout of " + win + ": focusMayChange=" + focusMayChange);
- if (focusMayChange) {
- //System.out.println("Focus may change: " + win.mAttrs.getTitle());
- updateFocusedWindowLocked();
- //System.out.println("Relayout " + win + ": focus=" + mCurrentFocus);
- }
-
inTouchMode = mInTouchMode;
}
@@ -1348,6 +1634,76 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
return wtoken.appWindowToken;
}
+ public void addWindowToken(IBinder token, int type) {
+ if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
+ "addWindowToken()")) {
+ return;
+ }
+
+ synchronized(mWindowMap) {
+ WindowToken wtoken = mTokenMap.get(token);
+ if (wtoken != null) {
+ Log.w(TAG, "Attempted to add existing input method token: " + token);
+ return;
+ }
+ wtoken = new WindowToken(token, type);
+ mTokenMap.put(token, wtoken);
+ mTokenList.add(wtoken);
+ }
+ }
+
+ public void removeWindowToken(IBinder token) {
+ if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
+ "removeWindowToken()")) {
+ return;
+ }
+
+ final long origId = Binder.clearCallingIdentity();
+ synchronized(mWindowMap) {
+ WindowToken wtoken = mTokenMap.remove(token);
+ mTokenList.remove(wtoken);
+ if (wtoken != null) {
+ boolean delayed = false;
+ if (!wtoken.hidden) {
+ wtoken.hidden = true;
+
+ final int N = wtoken.windows.size();
+ boolean changed = false;
+
+ for (int i=0; i<N; i++) {
+ WindowState win = wtoken.windows.get(i);
+
+ if (win.isAnimating()) {
+ delayed = true;
+ }
+
+ if (win.isVisibleNow()) {
+ applyAnimationLocked(win,
+ WindowManagerPolicy.TRANSIT_EXIT, false);
+ mKeyWaiter.finishedKey(win.mSession, win.mClient, true,
+ KeyWaiter.RETURN_NOTHING);
+ changed = true;
+ }
+ }
+
+ if (changed) {
+ mLayoutNeeded = true;
+ performLayoutAndPlaceSurfacesLocked();
+ updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL);
+ }
+
+ if (delayed) {
+ mExitingTokens.add(wtoken);
+ }
+ }
+
+ } else {
+ Log.w(TAG, "Attempted to remove non-existing token: " + token);
+ }
+ }
+ Binder.restoreCallingIdentity(origId);
+ }
+
public void addAppToken(int addPos, IApplicationToken token,
int groupId, int requestedOrientation, boolean fullscreen) {
if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
@@ -1523,7 +1879,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
if (moveFocusNow && changed) {
final long origId = Binder.clearCallingIdentity();
- updateFocusedWindowLocked();
+ updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL);
Binder.restoreCallingIdentity(origId);
}
}
@@ -1665,10 +2021,10 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
ttoken.updateLayers();
}
+ updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES);
assignLayersLocked();
mLayoutNeeded = true;
performLayoutAndPlaceSurfacesLocked();
- updateFocusedWindowLocked();
Binder.restoreCallingIdentity(origId);
return;
} else if (ttoken.startingData != null) {
@@ -1743,11 +2099,16 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
TAG, "Changing app " + wtoken + " hidden=" + wtoken.hidden
+ " performLayout=" + performLayout);
+ boolean runningAppAnimation = false;
+
if (transit != WindowManagerPolicy.TRANSIT_NONE) {
+ if (wtoken.animation == sDummyAnimation) {
+ wtoken.animation = null;
+ }
applyAnimationLocked(wtoken, lp, transit, visible);
changed = true;
if (wtoken.animation != null) {
- delayed = true;
+ delayed = runningAppAnimation = true;
}
}
@@ -1764,10 +2125,18 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
//Log.i(TAG, "Window " + win + ": vis=" + win.isVisible());
//win.dump(" ");
if (visible) {
- if (!win.isVisible()) {
+ if (!win.isVisibleNow()) {
+ if (!runningAppAnimation) {
+ applyAnimationLocked(win,
+ WindowManagerPolicy.TRANSIT_ENTER, true);
+ }
changed = true;
}
- } else if (win.isVisible()) {
+ } else if (win.isVisibleNow()) {
+ if (!runningAppAnimation) {
+ applyAnimationLocked(win,
+ WindowManagerPolicy.TRANSIT_EXIT, false);
+ }
mKeyWaiter.finishedKey(win.mSession, win.mClient, true,
KeyWaiter.RETURN_NOTHING);
changed = true;
@@ -1793,8 +2162,9 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
if (changed && performLayout) {
mLayoutNeeded = true;
+ updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES);
+ assignLayersLocked();
performLayoutAndPlaceSurfacesLocked();
- updateFocusedWindowLocked();
}
}
@@ -2007,10 +2377,10 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
+ " animation=" + wtoken.animation
+ " animating=" + wtoken.animating);
if (delayed) {
+ // set the token aside because it has an active animation to be finished
mExitingAppTokens.add(wtoken);
- } else {
- mAppTokens.remove(wtoken);
}
+ mAppTokens.remove(wtoken);
wtoken.removed = true;
if (wtoken.startingData != null) {
startingToken = wtoken;
@@ -2019,7 +2389,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
if (mFocusedApp == wtoken) {
if (DEBUG_FOCUS) Log.v(TAG, "Removing focused app token:" + wtoken);
mFocusedApp = null;
- updateFocusedWindowLocked();
+ updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL);
mKeyWaiter.tickle();
}
} else {
@@ -2169,10 +2539,10 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
reAddAppWindowsLocked(findWindowOffsetLocked(index), wtoken);
if (DEBUG_REORDER) Log.v(TAG, "Final window list:");
if (DEBUG_REORDER) dumpWindowsLocked();
+ updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES);
assignLayersLocked();
mLayoutNeeded = true;
performLayoutAndPlaceSurfacesLocked();
- updateFocusedWindowLocked();
}
Binder.restoreCallingIdentity(origId);
}
@@ -2217,10 +2587,10 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
}
+ updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES);
assignLayersLocked();
mLayoutNeeded = true;
performLayoutAndPlaceSurfacesLocked();
- updateFocusedWindowLocked();
//dump();
}
@@ -2888,6 +3258,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
config.orientation = orientation;
config.keyboardHidden = Configuration.KEYBOARDHIDDEN_NO;
+ config.hardKeyboardHidden = Configuration.HARDKEYBOARDHIDDEN_NO;
mPolicy.adjustConfigurationLw(config);
Log.i(TAG, "Input configuration changed: " + config);
long now = SystemClock.uptimeMillis();
@@ -3074,6 +3445,25 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
KeyWaiter.RETURN_PENDING_POINTER, qev);
ev = null;
} else {
+ if (action == MotionEvent.ACTION_DOWN) {
+ WindowState out = mKeyWaiter.mOutsideTouchTargets;
+ if (out != null) {
+ MotionEvent oev = MotionEvent.obtain(ev);
+ oev.setAction(MotionEvent.ACTION_OUTSIDE);
+ do {
+ final Rect frame = out.mFrame;
+ oev.offsetLocation(-(float)frame.left, -(float)frame.top);
+ try {
+ out.mClient.dispatchPointer(oev, eventTime);
+ } catch (android.os.RemoteException e) {
+ Log.i(TAG, "WINDOW DIED during outside motion dispatch: " + out);
+ }
+ oev.offsetLocation((float)frame.left, (float)frame.top);
+ out = out.mNextOutsideTouch;
+ } while (out != null);
+ mKeyWaiter.mOutsideTouchTargets = null;
+ }
+ }
final Rect frame = target.mFrame;
ev.offsetLocation(-(float)frame.left, -(float)frame.top);
mKeyWaiter.bindTargetWindowLocked(target);
@@ -3303,7 +3693,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
/**
* Inject a pointer (touch) event into the UI.
*
- * @param ev A motion event describing the trackball action. (As noted in
+ * @param ev A motion event describing the pointer (touch) action. (As noted in
* {@link MotionEvent#obtain(long, long, int, float, float, int)}, be sure to use
* {@link SystemClock#uptimeMillis()} as the timebase.)
* @param sync If true, wait for the event to be completed before returning to the caller.
@@ -3368,6 +3758,10 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
// Target of Motion events
WindowState mMotionTarget;
+
+ // Windows above the target who would like to receive an "outside"
+ // touch event for any down events outside of them.
+ WindowState mOutsideTouchTargets;
/**
* Wait for the last event dispatch to complete, then find the next
@@ -3563,6 +3957,8 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
Object findTargetWindow(KeyEvent nextKey, QueuedEvent qev,
MotionEvent nextMotion, boolean isPointerEvent) {
+ mOutsideTouchTargets = null;
+
if (nextKey != null) {
// Find the target window for a normal key event.
final int keycode = nextKey.getKeyCode();
@@ -3654,8 +4050,10 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
final ArrayList windows = mWindows;
final int N = windows.size();
WindowState topErrWindow = null;
+ final Rect tmpRect = mTempRect;
for (int i=N-1; i>=0; i--) {
WindowState child = (WindowState)windows.get(i);
+ //Log.i(TAG, "Checking dispatch to: " + child);
final int flags = child.mAttrs.flags;
if ((flags & WindowManager.LayoutParams.FLAG_SYSTEM_ERROR) != 0) {
if (topErrWindow == null) {
@@ -3663,24 +4061,59 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
}
if (!child.isVisible()) {
+ //Log.i(TAG, "Not visible!");
continue;
}
- final Rect frame = child.mFrame;
if ((flags & WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE) != 0) {
+ //Log.i(TAG, "Not touchable!");
+ if ((flags & WindowManager.LayoutParams
+ .FLAG_WATCH_OUTSIDE_TOUCH) != 0) {
+ child.mNextOutsideTouch = mOutsideTouchTargets;
+ mOutsideTouchTargets = child;
+ }
continue;
}
+ tmpRect.set(child.mFrame);
+ if (child.mTouchableInsets == ViewTreeObserver
+ .InternalInsetsInfo.TOUCHABLE_INSETS_CONTENT) {
+ // The touch is inside of the window if it is
+ // inside the frame, AND the content part of that
+ // frame that was given by the application.
+ tmpRect.left += child.mGivenContentInsets.left;
+ tmpRect.top += child.mGivenContentInsets.top;
+ tmpRect.right -= child.mGivenContentInsets.right;
+ tmpRect.bottom -= child.mGivenContentInsets.bottom;
+ } else if (child.mTouchableInsets == ViewTreeObserver
+ .InternalInsetsInfo.TOUCHABLE_INSETS_VISIBLE) {
+ // The touch is inside of the window if it is
+ // inside the frame, AND the visible part of that
+ // frame that was given by the application.
+ tmpRect.left += child.mGivenVisibleInsets.left;
+ tmpRect.top += child.mGivenVisibleInsets.top;
+ tmpRect.right -= child.mGivenVisibleInsets.right;
+ tmpRect.bottom -= child.mGivenVisibleInsets.bottom;
+ }
final int touchFlags = flags &
(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
|WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL);
- if (frame.contains(x, y) || (touchFlags == 0)) {
+ if (tmpRect.contains(x, y) || touchFlags == 0) {
+ //Log.i(TAG, "Using this target!");
if (!screenWasOff || (flags &
WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING) != 0) {
mMotionTarget = child;
} else {
+ //Log.i(TAG, "Waking, skip!");
mMotionTarget = null;
}
break;
}
+
+ if ((flags & WindowManager.LayoutParams
+ .FLAG_WATCH_OUTSIDE_TOUCH) != 0) {
+ child.mNextOutsideTouch = mOutsideTouchTargets;
+ mOutsideTouchTargets = child;
+ //Log.i(TAG, "Adding to outside target list: " + child);
+ }
}
// if there's an error window but it's not accepting
@@ -3816,10 +4249,10 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
MotionEvent res = (MotionEvent)qev.event;
if (DEBUG_INPUT) Log.v(TAG,
"Returning pending motion: " + res);
+ mQueue.recycleEvent(qev);
if (win != null && returnWhat == RETURN_PENDING_POINTER) {
res.offsetLocation(-win.mFrame.left, -win.mFrame.top);
}
- mQueue.recycleEvent(qev);
return res;
}
return null;
@@ -4261,7 +4694,8 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
private final class Session extends IWindowSession.Stub
implements IBinder.DeathRecipient {
- final IBinder mToken;
+ final IInputMethodClient mClient;
+ final IInputContext mInputContext;
final int mUid;
final int mPid;
SurfaceSession mSurfaceSession;
@@ -4282,14 +4716,39 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
QueuedEvent mPendingTrackballMove;
WindowState mPendingTrackballWindow;
- public Session(IBinder token) {
- mToken = token;
+ public Session(IInputMethodClient client, IInputContext inputContext) {
+ mClient = client;
+ mInputContext = inputContext;
mUid = Binder.getCallingUid();
mPid = Binder.getCallingPid();
+ synchronized (mWindowMap) {
+ if (mInputMethodManager == null && mHaveInputMethods) {
+ IBinder b = ServiceManager.getService(
+ Context.INPUT_METHOD_SERVICE);
+ mInputMethodManager = IInputMethodManager.Stub.asInterface(b);
+ }
+ }
+ long ident = Binder.clearCallingIdentity();
try {
- token.linkToDeath(this, 0);
+ // Note: it is safe to call in to the input method manager
+ // here because we are not holding our lock.
+ if (mInputMethodManager != null) {
+ mInputMethodManager.addClient(client, inputContext,
+ mUid, mPid);
+ } else {
+ client.setUsingInputMethod(false);
+ }
+ client.asBinder().linkToDeath(this, 0);
} catch (RemoteException e) {
// The caller has died, so we can just forget about this.
+ try {
+ if (mInputMethodManager != null) {
+ mInputMethodManager.removeClient(client);
+ }
+ } catch (RemoteException ee) {
+ }
+ } finally {
+ Binder.restoreCallingIdentity(ident);
}
}
@@ -4308,6 +4767,14 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
public void binderDied() {
+ // Note: it is safe to call in to the input method manager
+ // here because we are not holding our lock.
+ try {
+ if (mInputMethodManager != null) {
+ mInputMethodManager.removeClient(mClient);
+ }
+ } catch (RemoteException e) {
+ }
synchronized(mWindowMap) {
mClientDead = true;
killSessionLocked();
@@ -4315,8 +4782,8 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
public int add(IWindow window, WindowManager.LayoutParams attrs,
- int viewVisibility, Rect outCoveredInsets) {
- return addWindow(this, window, attrs, viewVisibility, outCoveredInsets);
+ int viewVisibility, Rect outContentInsets) {
+ return addWindow(this, window, attrs, viewVisibility, outContentInsets);
}
public void remove(IWindow window) {
@@ -4325,10 +4792,25 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
public int relayout(IWindow window, WindowManager.LayoutParams attrs,
int requestedWidth, int requestedHeight, int viewFlags,
- Rect outFrame, Rect outCoveredInsets, Surface outSurface) {
+ boolean insetsPending, Rect outFrame, Rect outContentInsets,
+ Rect outVisibleInsets, Surface outSurface) {
return relayoutWindow(this, window, attrs,
- requestedWidth, requestedHeight, viewFlags,
- outFrame, outCoveredInsets, outSurface);
+ requestedWidth, requestedHeight, viewFlags, insetsPending,
+ outFrame, outContentInsets, outVisibleInsets, outSurface);
+ }
+
+ public void setTransparentRegion(IWindow window, Region region) {
+ setTransparentRegionWindow(this, window, region);
+ }
+
+ public void setInsets(IWindow window, int touchableInsets,
+ Rect contentInsets, Rect visibleInsets) {
+ setInsetsWindow(this, window, touchableInsets, contentInsets,
+ visibleInsets);
+ }
+
+ public void getDisplayFrame(IWindow window, Rect outDisplayFrame) {
+ getWindowDisplayFrame(this, window, outDisplayFrame);
}
public void finishDrawing(IWindow window) {
@@ -4357,10 +4839,6 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
return mKeyWaiter.finishedKey(this, window, false,
KeyWaiter.RETURN_PENDING_TRACKBALL);
}
-
- public void setTransparentRegion(IWindow window, Region region) {
- setTransparentRegionWindow(this, window, region);
- }
public void setInTouchMode(boolean mode) {
synchronized(mWindowMap) {
@@ -4435,12 +4913,14 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
final IWindow mClient;
WindowToken mToken;
AppWindowToken mAppToken;
+ AppWindowToken mTargetAppToken;
final WindowManager.LayoutParams mAttrs = new WindowManager.LayoutParams();
final DeathRecipient mDeathRecipient;
final WindowState mAttachedWindow;
final ArrayList mChildWindows = new ArrayList();
final int mBaseLayer;
final int mSubLayer;
+ final boolean mLayoutAttached;
int mViewVisibility;
boolean mPolicyVisibility = true;
boolean mAppFreezing;
@@ -4458,15 +4938,52 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
int mLastLayer;
boolean mHaveFrame;
+ WindowState mNextOutsideTouch;
+
// Actual frame shown on-screen (may be modified by animation)
final Rect mShownFrame = new Rect();
final Rect mLastShownFrame = new Rect();
/**
+ * Insets that determine the actually visible area
+ */
+ final Rect mVisibleInsets = new Rect();
+ final Rect mLastVisibleInsets = new Rect();
+ boolean mVisibleInsetsChanged;
+
+ /**
* Insets that are covered by system windows
*/
- final Rect mCoveredInsets = new Rect();
+ final Rect mContentInsets = new Rect();
+ final Rect mLastContentInsets = new Rect();
+ boolean mContentInsetsChanged;
+ /**
+ * Set to true if we are waiting for this window to receive its
+ * given internal insets before laying out other windows based on it.
+ */
+ boolean mGivenInsetsPending;
+
+ /**
+ * These are the content insets that were given during layout for
+ * this window, to be applied to windows behind it.
+ */
+ final Rect mGivenContentInsets = new Rect();
+
+ /**
+ * These are the visible insets that were given during layout for
+ * this window, to be applied to windows behind it.
+ */
+ final Rect mGivenVisibleInsets = new Rect();
+
+ /**
+ * Flag indicating whether the touchable region should be adjusted by
+ * the visible insets; if false the area outside the visible insets is
+ * NOT touchable, so we must use those to adjust the frame during hit
+ * tests.
+ */
+ int mTouchableInsets = ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME;
+
// Current transformation being applied.
float mDsDx=1, mDtDx=0, mDsDy=0, mDtDy=1;
float mLastDsDx=1, mLastDtDx=0, mLastDsDy=0, mLastDtDy=1;
@@ -4479,6 +4996,9 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
final Rect mLastFrame = new Rect();
final Rect mContainingFrame = new Rect();
+ final Rect mDisplayFrame = new Rect();
+ final Rect mContentFrame = new Rect();
+ final Rect mVisibleFrame = new Rect();
float mShownAlpha = 1;
float mAlpha = 1;
@@ -4550,14 +5070,15 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
} catch (RemoteException e) {
mDeathRecipient = null;
mAttachedWindow = null;
+ mLayoutAttached = false;
mBaseLayer = 0;
mSubLayer = 0;
return;
}
mDeathRecipient = deathRecipient;
- if (mAttrs.type >= mAttrs.FIRST_SUB_WINDOW &&
- mAttrs.type <= mAttrs.LAST_SUB_WINDOW) {
+ if ((mAttrs.type >= FIRST_SUB_WINDOW &&
+ mAttrs.type <= LAST_SUB_WINDOW)) {
// The multiplier here is to reserve space for multiple
// windows in the same type layer.
mBaseLayer = mPolicy.windowTypeToLayerLw(
@@ -4566,6 +5087,8 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
mSubLayer = mPolicy.subWindowTypeToLayerLw(a.type);
mAttachedWindow = attachedWindow;
mAttachedWindow.mChildWindows.add(this);
+ mLayoutAttached = mAttrs.type !=
+ WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
} else {
// The multiplier here is to reserve space for multiple
// windows in the same type layer.
@@ -4574,6 +5097,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
+ TYPE_LAYER_OFFSET;
mSubLayer = 0;
mAttachedWindow = null;
+ mLayoutAttached = false;
}
WindowState appWin = this;
@@ -4609,12 +5133,11 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
mSession.windowAddedLocked();
}
- public void computeFrameLw(int pl, int pt, int pr, int pb,
- int dl, int dt, int dr, int db) {
+ public void computeFrameLw(Rect pf, Rect df, Rect cf, Rect vf) {
mHaveFrame = true;
- final int pw = pr-pl;
- final int ph = pb-pt;
+ final int pw = pf.right-pf.left;
+ final int ph = pf.bottom-pf.top;
int w,h;
if ((mAttrs.flags & mAttrs.FLAG_SCALED) != 0) {
@@ -4626,11 +5149,17 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
final Rect container = mContainingFrame;
- container.left = pl;
- container.top = pt;
- container.right = pr;
- container.bottom = pb;
+ container.set(pf);
+
+ final Rect display = mDisplayFrame;
+ display.set(df);
+ final Rect content = mContentFrame;
+ content.set(cf);
+
+ final Rect visible = mVisibleFrame;
+ visible.set(vf);
+
final Rect frame = mFrame;
//System.out.println("In: w=" + w + " h=" + h + " container=" +
@@ -4643,63 +5172,85 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
//System.out.println("Out: " + mFrame);
// Now make sure the window fits in the overall display.
- int off = 0;
- if (frame.left < dl) off = dl-frame.left;
- else if (frame.right > dr) off = dr-frame.right;
- if (off != 0) {
- if (frame.width() > (dr-dl)) {
- frame.left = dl;
- frame.right = dr;
- } else {
- frame.left += off;
- frame.right += off;
- }
- }
- off = 0;
- if (frame.top < dt) off = dt-frame.top;
- else if (frame.bottom > db) off = db-frame.bottom;
- if (off != 0) {
- if (frame.height() > (db-dt)) {
- frame.top = dt;
- frame.bottom = db;
- } else {
- frame.top += off;
- frame.bottom += off;
- }
- }
+ Gravity.applyDisplay(mAttrs.gravity, df, frame);
+
+ // Make sure the content and visible frames are inside of the
+ // final window frame.
+ if (content.left < frame.left) content.left = frame.left;
+ if (content.top < frame.top) content.top = frame.top;
+ if (content.right > frame.right) content.right = frame.right;
+ if (content.bottom > frame.bottom) content.bottom = frame.bottom;
+ if (visible.left < frame.left) visible.left = frame.left;
+ if (visible.top < frame.top) visible.top = frame.top;
+ if (visible.right > frame.right) visible.right = frame.right;
+ if (visible.bottom > frame.bottom) visible.bottom = frame.bottom;
+
+ final Rect contentInsets = mContentInsets;
+ contentInsets.left = content.left-frame.left;
+ contentInsets.top = content.top-frame.top;
+ contentInsets.right = frame.right-content.right;
+ contentInsets.bottom = frame.bottom-content.bottom;
+
+ final Rect visibleInsets = mVisibleInsets;
+ visibleInsets.left = visible.left-frame.left;
+ visibleInsets.top = visible.top-frame.top;
+ visibleInsets.right = frame.right-visible.right;
+ visibleInsets.bottom = frame.bottom-visible.bottom;
- if (localLOGV) Log.v(TAG, "Resolving (mRequestedWidth="
- + mRequestedWidth + ", mRequestedheight="
- + mRequestedHeight + ") to" + " (pw=" + pw + ", dh=" + ph
- + "): frame=" + mFrame);
+ if (localLOGV) {
+ //if ("com.google.android.youtube".equals(mAttrs.packageName)
+ // && mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_PANEL) {
+ Log.v(TAG, "Resolving (mRequestedWidth="
+ + mRequestedWidth + ", mRequestedheight="
+ + mRequestedHeight + ") to" + " (pw=" + pw + ", ph=" + ph
+ + "): frame=" + mFrame.toShortString()
+ + " ci=" + contentInsets.toShortString()
+ + " vi=" + visibleInsets.toShortString());
+ //}
+ }
}
- public void setFrameLw(int left, int top, int right, int bottom)
- {
- mHaveFrame = true;
- mFrame.left = left;
- mFrame.top = top;
- mFrame.right = right;
- mFrame.bottom = bottom;
+ public Rect getFrameLw() {
+ return mFrame;
}
- public Rect getFrameLw()
- {
- return mFrame;
+ public Rect getDisplayFrameLw() {
+ return mDisplayFrame;
+ }
+
+ public Rect getContentFrameLw() {
+ return mContentFrame;
}
- public WindowManager.LayoutParams getAttrs()
- {
+ public Rect getVisibleFrameLw() {
+ return mVisibleFrame;
+ }
+
+ public boolean getGivenInsetsPendingLw() {
+ return mGivenInsetsPending;
+ }
+
+ public Rect getGivenContentInsetsLw() {
+ return mGivenContentInsets;
+ }
+
+ public Rect getGivenVisibleInsetsLw() {
+ return mGivenVisibleInsets;
+ }
+
+ public WindowManager.LayoutParams getAttrs() {
return mAttrs;
}
- public IApplicationToken getAppToken()
- {
+ public int getSurfaceLayer() {
+ return mLayer;
+ }
+
+ public IApplicationToken getAppToken() {
return mAppToken != null ? mAppToken.appToken : null;
}
- public boolean hasAppShownWindows()
- {
+ public boolean hasAppShownWindows() {
return mAppToken != null ? mAppToken.firstWindowDrawn : false;
}
@@ -5125,9 +5676,9 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
// transforming since it is more important to have that
// animation be smooth.
mShownAlpha = mAlpha;
- if (!PixelFormat.formatHasAlpha(mAttrs.format)
+ if (false && (!PixelFormat.formatHasAlpha(mAttrs.format)
|| (isIdentityMatrix(mDsDx, mDtDx, mDsDy, mDtDy)
- && x == frame.left && y == frame.top)) {
+ && x == frame.left && y == frame.top))) {
//Log.i(TAG, "Applying alpha transform");
if (selfTransformation) {
mShownAlpha *= mTransformation.getAlpha();
@@ -5154,9 +5705,11 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
mDtDy = 1;
}
- // Is this window visible? It is not visible if there is no
- // surface, or we are in the process of running an exit animation
- // that will remove the surface.
+ /**
+ * Is this window visible? It is not visible if there is no
+ * surface, or we are in the process of running an exit animation
+ * that will remove the surface.
+ */
boolean isVisible() {
final AppWindowToken atoken = mAppToken;
return mSurface != null && mPolicyVisibility && !mAttachedHidden
@@ -5164,8 +5717,19 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
&& !mExiting && !mDestroying;
}
- // Same as isVisible(), but we also count it as visible between the
- // call to IWindowSession.add() and the first relayout().
+ /**
+ * The same as isVisible(), but follows the current hidden state of
+ * the associated app token, not the pending requested hidden state.
+ */
+ boolean isVisibleNow() {
+ return mSurface != null && mPolicyVisibility && !mAttachedHidden
+ && !mToken.hidden && !mExiting && !mDestroying;
+ }
+
+ /**
+ * Same as isVisible(), but we also count it as visible between the
+ * call to IWindowSession.add() and the first relayout().
+ */
boolean isVisibleOrAdding() {
final AppWindowToken atoken = mAppToken;
return (mSurface != null
@@ -5175,9 +5739,11 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
&& !mExiting && !mDestroying;
}
- // Is this window currently on-screen? It is on-screen either if it
- // is visible or it is currently running an animation before no longer
- // being visible.
+ /**
+ * Is this window currently on-screen? It is on-screen either if it
+ * is visible or it is currently running an animation before no longer
+ * being visible.
+ */
boolean isOnScreen() {
final AppWindowToken atoken = mAppToken;
if (atoken != null) {
@@ -5190,21 +5756,19 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
}
- // Like isOnScreen(), but we don't return true if the window is part
- // of a transition that has not yet been started.
+ /**
+ * Like isOnScreen(), but we don't return true if the window is part
+ * of a transition that has not yet been started.
+ */
boolean isReadyForDisplay() {
final AppWindowToken atoken = mAppToken;
- if (atoken != null) {
- return mSurface != null && mPolicyVisibility && !mDestroying
- && ((!mAttachedHidden && !atoken.hidden)
- || mAnimating || atoken.animating);
- } else {
- return mSurface != null && mPolicyVisibility && !mDestroying
- && (!mAttachedHidden || mAnimating);
- }
+ final boolean animating = atoken != null ? atoken.animating : false;
+ return mSurface != null && mPolicyVisibility && !mDestroying
+ && ((!mAttachedHidden && !mToken.hidden)
+ || mAnimating || animating);
}
- // Is the window or its container currently animating?
+ /** Is the window or its container currently animating? */
boolean isAnimating() {
final WindowState attached = mAttachedWindow;
final AppWindowToken atoken = mAppToken;
@@ -5215,13 +5779,15 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
|| atoken.inPendingTransaction));
}
- // Is this window currently animating?
+ /** Is this window currently animating? */
boolean isWindowAnimating() {
return mAnimation != null;
}
- // Like isOnScreen, but returns false if the surface hasn't yet
- // been drawn.
+ /**
+ * Like isOnScreen, but returns false if the surface hasn't yet
+ * been drawn.
+ */
public boolean isDisplayedLw() {
final AppWindowToken atoken = mAppToken;
return mSurface != null && mPolicyVisibility && !mDestroying
@@ -5320,16 +5886,19 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
pw.println(prefix + "mSession=" + mSession
+ " mClient=" + mClient.asBinder());
pw.println(prefix + "mAttrs=" + mAttrs);
- pw.println(prefix + "mAttachedWindow=" + mAttachedWindow);
+ pw.println(prefix + "mAttachedWindow=" + mAttachedWindow
+ + " mLayoutAttached=" + mLayoutAttached);
pw.println(prefix + "mBaseLayer=" + mBaseLayer
+ " mSubLayer=" + mSubLayer
+ " mAnimLayer=" + mLayer + "+"
- + (mAppToken != null ? mAppToken.animLayerAdjustment : 0)
+ + (mTargetAppToken != null ? mTargetAppToken.animLayerAdjustment
+ : (mAppToken != null ? mAppToken.animLayerAdjustment : 0))
+ "=" + mAnimLayer
+ " mLastLayer=" + mLastLayer);
pw.println(prefix + "mSurface=" + mSurface);
pw.println(prefix + "mToken=" + mToken);
pw.println(prefix + "mAppToken=" + mAppToken);
+ pw.println(prefix + "mTargetAppToken=" + mTargetAppToken);
pw.println(prefix + "mViewVisibility=0x" + Integer.toHexString(mViewVisibility)
+ " mPolicyVisibility=" + mPolicyVisibility
+ " mAttachedHidden=" + mAttachedHidden
@@ -5337,18 +5906,29 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
+ " mHaveFrame=" + mHaveFrame);
pw.println(prefix + "Requested w=" + mRequestedWidth + " h=" + mRequestedHeight
+ " x=" + mReqXPos + " y=" + mReqYPos);
- pw.println(prefix + "mShownFrame=" + mShownFrame
- + " last=" + mLastShownFrame);
- pw.println(prefix + "mFrame=" + mFrame + " last=" + mLastFrame);
- pw.println(prefix + "mContainingFrame=" + mContainingFrame
- + " mCoveredInsets=" + mCoveredInsets);
+ pw.println(prefix + "mGivenContentInsets=" + mGivenContentInsets.toShortString()
+ + " mGivenVisibleInsets=" + mGivenVisibleInsets.toShortString()
+ + " mTouchableInsets=" + mTouchableInsets
+ + " pending=" + mGivenInsetsPending);
+ pw.println(prefix + "mShownFrame=" + mShownFrame.toShortString()
+ + " last=" + mLastShownFrame.toShortString());
+ pw.println(prefix + "mFrame=" + mFrame.toShortString()
+ + " last=" + mLastFrame.toShortString());
+ pw.println(prefix + "mContainingFrame=" + mContainingFrame.toShortString()
+ + " mDisplayFrame=" + mDisplayFrame.toShortString());
+ pw.println(prefix + "mContentFrame=" + mContentFrame.toShortString()
+ + " mVisibleFrame=" + mVisibleFrame.toShortString());
+ pw.println(prefix + "mContentInsets=" + mContentInsets.toShortString()
+ + " last=" + mLastContentInsets.toShortString()
+ + " mVisibleInsets=" + mVisibleInsets.toShortString()
+ + " last=" + mLastVisibleInsets.toShortString());
pw.println(prefix + "mShownAlpha=" + mShownAlpha
+ " mAlpha=" + mAlpha + " mLastAlpha=" + mLastAlpha);
pw.println(prefix + "mAnimating=" + mAnimating
+ " mAnimationIsEntrance=" + mAnimationIsEntrance
+ " mAnimation=" + mAnimation);
- pw.println(prefix + "mHasTransformation=" + mHasTransformation
- + " mTransformation=" + mTransformation);
+ pw.println(prefix + "XForm: has=" + mHasTransformation
+ + " " + mTransformation.toShortString());
pw.println(prefix + "mDrawPending=" + mDrawPending
+ " mCommitDrawPending=" + mCommitDrawPending
+ " mReadyToShow=" + mReadyToShow
@@ -5366,10 +5946,6 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
+ Integer.toHexString(System.identityHashCode(this))
+ " " + mAttrs.getTitle() + "}";
}
-
- public void setCoveredInsetsLw(int l, int t, int r, int b) {
- mCoveredInsets.set(l, t, r, b);
- }
}
// -------------------------------------------------------------
@@ -5380,6 +5956,9 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
// The actual token.
final IBinder token;
+ // The type of window this token is for, as per WindowManager.LayoutParams.
+ final int windowType;
+
// If this is an AppWindowToken, this is non-null.
AppWindowToken appWindowToken;
@@ -5389,14 +5968,23 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
// Is key dispatching paused for this token?
boolean paused = false;
- WindowToken(IBinder _token) {
+ // Should this token's windows be hidden?
+ boolean hidden;
+
+ // Temporary for finding which tokens no longer have visible windows.
+ boolean hasVisible;
+
+ WindowToken(IBinder _token, int type) {
token = _token;
+ windowType = type;
}
void dump(PrintWriter pw, String prefix) {
pw.println(prefix + this);
pw.println(prefix + "token=" + token);
pw.println(prefix + "windows=" + windows);
+ pw.println(prefix + "windowType=" + windowType + " hidden=" + hidden
+ + " hasVisible=" + hasVisible);
}
@Override
@@ -5432,9 +6020,6 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
// won't be taken into account for setting the screen orientation.
boolean willBeHidden;
- // Should this token's windows be hidden?
- boolean hidden;
-
// Is this window's surface needed? This is almost like hidden, except
// it will sometimes be true a little earlier: when the token has
// been shown, but is still waiting for its app transition to execute
@@ -5444,9 +6029,6 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
// Have we told the window clients to hide themselves?
boolean clientHidden;
- // Temporary for finding which tokens no longer have visible windows.
- boolean hasVisible;
-
// Last visibility state we reported to the app token.
boolean reportedVisible;
@@ -5474,7 +6056,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
boolean firstWindowDrawn;
AppWindowToken(IApplicationToken _token) {
- super(_token.asBinder());
+ super(_token.asBinder(), WindowManager.LayoutParams.TYPE_APPLICATION);
appWindowToken = this;
appToken = _token;
}
@@ -5517,9 +6099,22 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
void updateLayers() {
final int N = allAppWindows.size();
+ final int adj = animLayerAdjustment;
for (int i=0; i<N; i++) {
WindowState w = allAppWindows.get(i);
- w.mAnimLayer = w.mLayer + animLayerAdjustment;
+ w.mAnimLayer = w.mLayer + adj;
+ if (w == mInputMethodTarget) {
+ WindowState imw = mInputMethodWindow;
+ if (imw != null) {
+ imw.mAnimLayer = imw.mLayer + adj;
+ }
+ int di = mInputMethodDialogs.size();
+ while (di > 0) {
+ di --;
+ imw = mInputMethodDialogs.get(di);
+ imw.mAnimLayer = imw.mLayer + adj;
+ }
+ }
}
}
@@ -5691,22 +6286,20 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
pw.println(prefix + "allAppWindows=" + allAppWindows);
pw.println(prefix + "groupId=" + groupId
+ " requestedOrientation=" + requestedOrientation);
- pw.println(prefix + "hidden=" + hidden
- + " hiddenRequested=" + hiddenRequested
+ pw.println(prefix + "hiddenRequested=" + hiddenRequested
+ " clientHidden=" + clientHidden
- + " willBeHidden=" + willBeHidden);
+ + " willBeHidden=" + willBeHidden
+ + " reportedVisible=" + reportedVisible);
pw.println(prefix + "paused=" + paused
+ " freezingScreen=" + freezingScreen);
pw.println(prefix + "numInterestingWindows=" + numInterestingWindows
+ " numDrawnWindows=" + numDrawnWindows
+ " inPendingTransaction=" + inPendingTransaction
+ " allDrawn=" + allDrawn);
- pw.println(prefix + "hasVisible=" + hasVisible
- + " reportedVisible=" + reportedVisible);
pw.println(prefix + "animating=" + animating
+ " animation=" + animation);
pw.println(prefix + "animLayerAdjustment=" + animLayerAdjustment
- + " transformation=" + transformation);
+ + " transformation=" + transformation.toShortString());
pw.println(prefix + "startingData=" + startingData
+ " removed=" + removed
+ " firstWindowDrawn=" + firstWindowDrawn);
@@ -6149,10 +6742,29 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
// IWindowManager API
// -------------------------------------------------------------
- public IWindowSession openSession(IBinder token) {
- return new Session(token);
+ public IWindowSession openSession(IInputMethodClient client,
+ IInputContext inputContext) {
+ if (client == null) throw new IllegalArgumentException("null client");
+ if (inputContext == null) throw new IllegalArgumentException("null inputContext");
+ return new Session(client, inputContext);
}
+ public boolean inputMethodClientHasFocus(IInputMethodClient client) {
+ synchronized (mWindowMap) {
+ // The focus for the client is the window immediately below
+ // where we would place the input method window.
+ int idx = findDesiredInputMethodWindowIndexLocked();
+ if (idx > 0) {
+ WindowState imFocus = (WindowState)mWindows.get(idx-1);
+ if (imFocus != null && imFocus.mSession.mClient != null &&
+ imFocus.mSession.mClient.asBinder() == client.asBinder()) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
// -------------------------------------------------------------
// Internals
// -------------------------------------------------------------
@@ -6170,7 +6782,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
Log.w(TAG, "Requested window " + client + " does not exist", ex);
return null;
}
- if (win.mSession != session) {
+ if (session != null && win.mSession != session) {
RuntimeException ex = new RuntimeException();
Log.w(TAG, "Requested window " + client + " is in session " +
win.mSession + ", not " + session, ex);
@@ -6198,12 +6810,21 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
if (w.mBaseLayer == curBaseLayer) {
curLayer += WINDOW_LAYER_MULTIPLIER;
w.mLayer = curLayer;
+ } else if (w.mAttrs.type == TYPE_INPUT_METHOD
+ || w.mAttrs.type == TYPE_INPUT_METHOD_DIALOG) {
+ curLayer += WINDOW_LAYER_MULTIPLIER;
+ w.mLayer = curLayer;
} else {
curBaseLayer = curLayer = w.mBaseLayer;
w.mLayer = curLayer;
}
- w.mAnimLayer = w.mAppToken != null
- ? (w.mLayer + w.mAppToken.animLayerAdjustment) : w.mLayer;
+ if (w.mTargetAppToken != null) {
+ w.mAnimLayer = w.mLayer + w.mTargetAppToken.animLayerAdjustment;
+ } else if (w.mAppToken != null) {
+ w.mAnimLayer = w.mLayer + w.mAppToken.animLayerAdjustment;
+ } else {
+ w.mAnimLayer = w.mLayer;
+ }
//System.out.println(
// "Assigned layer " + curLayer + " to " + w.mClient.asBinder());
}
@@ -6295,14 +6916,14 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
// windows, since that means "perform layout as normal,
// just don't display").
if (!gone || !win.mHaveFrame) {
- if (win.mAttachedWindow == null) {
+ if (!win.mLayoutAttached) {
mPolicy.layoutWindowLw(win, win.mAttrs, null);
} else {
if (topAttached < 0) topAttached = i;
}
}
}
-
+
// Now perform layout of attached windows, which usually
// depend on the position of the window they are attached to.
// XXX does not deal with windows that are attached to windows
@@ -6315,10 +6936,11 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
// if they want. (We do the normal layout for INVISIBLE
// windows, since that means "perform layout as normal,
// just don't display").
- if ((win.mViewVisibility != View.GONE && win.mRelayoutCalled)
- || !win.mHaveFrame) {
-
- mPolicy.layoutWindowLw(win, win.mAttrs, win.mAttachedWindow);
+ if (win.mLayoutAttached) {
+ if ((win.mViewVisibility != View.GONE && win.mRelayoutCalled)
+ || !win.mHaveFrame) {
+ mPolicy.layoutWindowLw(win, win.mAttrs, win.mAttachedWindow);
+ }
}
}
@@ -6346,8 +6968,13 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
if (SHOW_TRANSACTIONS) Log.i(TAG, ">>> OPEN TRANSACTION");
+ // Initialize state of exiting tokens.
+ for (i=mExitingTokens.size()-1; i>=0; i--) {
+ mExitingTokens.get(i).hasVisible = false;
+ }
+
// Initialize state of exiting applications.
- for (i=0; i<mExitingAppTokens.size(); i++) {
+ for (i=mExitingAppTokens.size()-1; i>=0; i--) {
mExitingAppTokens.get(i).hasVisible = false;
}
@@ -6365,7 +6992,8 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
do {
final int transactionSequence = ++mTransactionSequence;
- // Update animations of all applications.
+ // Update animations of all applications, including those
+ // associated with exiting/removed apps
boolean tokensAnimating = false;
final int NAT = mAppTokens.size();
for (i=0; i<NAT; i++) {
@@ -6373,6 +7001,12 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
tokensAnimating = true;
}
}
+ final int NEAT = mExitingAppTokens.size();
+ for (i=0; i<NEAT; i++) {
+ if (mExitingAppTokens.get(i).stepAnimationLocked(currentTime, dw, dh)) {
+ tokensAnimating = true;
+ }
+ }
animating = tokensAnimating;
restart = false;
@@ -6561,7 +7195,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
// a new layout to get them all up-to-date.
mLayoutNeeded = true;
performLayoutLockedInner();
- updateFocusedWindowLocked();
+ updateFocusedWindowLocked(UPDATE_FOCUS_PLACING_SURFACES);
restart = true;
}
@@ -6651,8 +7285,16 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
}
if (!w.mAppFreezing) {
- if (!w.mLastFrame.equals(w.mFrame)) {
+ w.mContentInsetsChanged =
+ !w.mLastContentInsets.equals(w.mContentInsets);
+ w.mVisibleInsetsChanged =
+ !w.mLastVisibleInsets.equals(w.mVisibleInsets);
+ if (!w.mLastFrame.equals(w.mFrame)
+ || w.mContentInsetsChanged
+ || w.mVisibleInsetsChanged) {
w.mLastFrame.set(w.mFrame);
+ w.mLastContentInsets.set(w.mContentInsets);
+ w.mLastVisibleInsets.set(w.mVisibleInsets);
// If the orientation is changing, then we need to
// hold off on unfreezing the display until this
// window has been redrawn; to do that, we need
@@ -6784,8 +7426,8 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
w.mOrientationChanging = false;
}
}
- if (w.mAppToken != null && w.mSurface != null) {
- w.mAppToken.hasVisible = true;
+ if (w.mSurface != null) {
+ w.mToken.hasVisible = true;
}
} else {
displayed = true;
@@ -6809,9 +7451,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
"Orientation change complete in " + w);
}
}
- if (w.mAppToken != null) {
- w.mAppToken.hasVisible = true;
- }
+ w.mToken.hasVisible = true;
}
} else if (w.mOrientationChanging) {
if (DEBUG_ORIENTATION) Log.v(TAG,
@@ -6842,82 +7482,136 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
+ ": blurring=" + blurring
+ " obscured=" + obscured
+ " displayed=" + displayed);
- if (!dimming && (attrFlags&FLAG_DIM_BEHIND) != 0) {
- //Log.i(TAG, "DIM BEHIND: " + w);
- dimming = true;
- mDimShown = true;
- if (mDimSurface == null) {
+ if ((attrFlags&FLAG_DIM_BEHIND) != 0) {
+ if (!dimming) {
+ //Log.i(TAG, "DIM BEHIND: " + w);
+ dimming = true;
+ mDimShown = true;
+ if (mDimSurface == null) {
+ if (SHOW_TRANSACTIONS) Log.i(TAG, " DIM "
+ + mDimSurface + ": CREATE");
+ try {
+ mDimSurface = new Surface(mFxSession, 0,
+ -1, 16, 16,
+ PixelFormat.OPAQUE,
+ Surface.FX_SURFACE_DIM);
+ } catch (Exception e) {
+ Log.e(TAG, "Exception creating Dim surface", e);
+ }
+ }
if (SHOW_TRANSACTIONS) Log.i(TAG, " DIM "
- + mDimSurface + ": CREATE");
- try {
- mDimSurface = new Surface(mFxSession, 0,
- -1, 16, 16,
- PixelFormat.OPAQUE,
- Surface.FX_SURFACE_DIM);
- } catch (Exception e) {
- Log.e(TAG, "Exception creating Dim surface", e);
+ + mDimSurface + ": SHOW pos=(0,0) (" +
+ dw + "x" + dh + "), layer=" + (w.mAnimLayer-1));
+ if (mDimSurface != null) {
+ try {
+ mDimSurface.setPosition(0, 0);
+ mDimSurface.setSize(dw, dh);
+ mDimSurface.show();
+ } catch (RuntimeException e) {
+ Log.w(TAG, "Failure showing dim surface", e);
+ }
}
}
- if (SHOW_TRANSACTIONS) Log.i(TAG, " DIM "
- + mDimSurface + ": SHOW pos=(0,0) (" +
- dw + "x" + dh + "), layer=" + (w.mAnimLayer-1));
- if (mDimSurface != null) {
- try {
- mDimSurface.setPosition(0, 0);
- mDimSurface.setSize(dw, dh);
- mDimSurface.setLayer(w.mAnimLayer-1);
- mDimSurface.setAlpha(attrs.dimAmount);
- mDimSurface.show();
- } catch (RuntimeException e) {
- Log.w(TAG, "Failure showing dim surface", e);
- }
+ mDimSurface.setLayer(w.mAnimLayer-1);
+ final float target = w.mExiting ? 0 : attrs.dimAmount;
+ if (mDimTargetAlpha != target) {
+ // If the desired dim level has changed, then
+ // start an animation to it.
+ mLastDimAnimTime = currentTime;
+ long duration = (w.mAnimating && w.mAnimation != null)
+ ? w.mAnimation.computeDurationHint()
+ : DEFAULT_DIM_DURATION;
+ mDimTargetAlpha = target;
+ mDimDeltaPerMs = (mDimTargetAlpha-mDimCurrentAlpha)
+ / duration;
}
}
- if (!blurring && (attrFlags&FLAG_BLUR_BEHIND) != 0) {
- //Log.i(TAG, "BLUR BEHIND: " + w);
- blurring = true;
- mBlurShown = true;
- if (mBlurSurface == null) {
- if (SHOW_TRANSACTIONS) Log.i(TAG, " BLUR "
- + mBlurSurface + ": CREATE");
- try {
- mBlurSurface = new Surface(mFxSession, 0,
- -1, 16, 16,
- PixelFormat.OPAQUE,
- Surface.FX_SURFACE_BLUR);
- } catch (Exception e) {
- Log.e(TAG, "Exception creating Blur surface", e);
+ if ((attrFlags&FLAG_BLUR_BEHIND) != 0) {
+ if (!blurring) {
+ //Log.i(TAG, "BLUR BEHIND: " + w);
+ blurring = true;
+ mBlurShown = true;
+ if (mBlurSurface == null) {
+ if (SHOW_TRANSACTIONS) Log.i(TAG, " BLUR "
+ + mBlurSurface + ": CREATE");
+ try {
+ mBlurSurface = new Surface(mFxSession, 0,
+ -1, 16, 16,
+ PixelFormat.OPAQUE,
+ Surface.FX_SURFACE_BLUR);
+ } catch (Exception e) {
+ Log.e(TAG, "Exception creating Blur surface", e);
+ }
}
- }
- if (SHOW_TRANSACTIONS) Log.i(TAG, " BLUR "
- + mBlurSurface + ": SHOW pos=(0,0) (" +
- dw + "x" + dh + "), layer=" + (w.mAnimLayer-1));
- if (mBlurSurface != null) {
- mBlurSurface.setPosition(0, 0);
- mBlurSurface.setSize(dw, dh);
- mBlurSurface.setLayer(w.mAnimLayer-2);
- try {
- mBlurSurface.show();
- } catch (RuntimeException e) {
- Log.w(TAG, "Failure showing blur surface", e);
+ if (SHOW_TRANSACTIONS) Log.i(TAG, " BLUR "
+ + mBlurSurface + ": SHOW pos=(0,0) (" +
+ dw + "x" + dh + "), layer=" + (w.mAnimLayer-1));
+ if (mBlurSurface != null) {
+ mBlurSurface.setPosition(0, 0);
+ mBlurSurface.setSize(dw, dh);
+ try {
+ mBlurSurface.show();
+ } catch (RuntimeException e) {
+ Log.w(TAG, "Failure showing blur surface", e);
+ }
}
}
+ mBlurSurface.setLayer(w.mAnimLayer-2);
}
}
}
}
if (!dimming && mDimShown) {
- if (SHOW_TRANSACTIONS) Log.i(TAG, " DIM " + mDimSurface
- + ": HIDE");
- try {
- mDimSurface.hide();
- } catch (RuntimeException e) {
- Log.w(TAG, "Illegal argument exception hiding dim surface");
+ // Time to hide the dim surface... start fading.
+ if (mDimTargetAlpha != 0) {
+ mLastDimAnimTime = currentTime;
+ mDimTargetAlpha = 0;
+ mDimDeltaPerMs = (-mDimCurrentAlpha) / DEFAULT_DIM_DURATION;
}
- mDimShown = false;
}
+ if (mDimShown && mLastDimAnimTime != 0) {
+ mDimCurrentAlpha += mDimDeltaPerMs
+ * (currentTime-mLastDimAnimTime);
+ boolean more = true;
+ if (mDimDeltaPerMs > 0) {
+ if (mDimCurrentAlpha > mDimTargetAlpha) {
+ more = false;
+ }
+ } else if (mDimDeltaPerMs < 0) {
+ if (mDimCurrentAlpha < mDimTargetAlpha) {
+ more = false;
+ }
+ } else {
+ more = false;
+ }
+
+ // Do we need to continue animating?
+ if (more) {
+ if (SHOW_TRANSACTIONS) Log.i(TAG, " DIM "
+ + mDimSurface + ": alpha=" + mDimCurrentAlpha);
+ mDimSurface.setAlpha(mDimCurrentAlpha);
+ animating = true;
+ } else {
+ mDimCurrentAlpha = mDimTargetAlpha;
+ mLastDimAnimTime = 0;
+ if (SHOW_TRANSACTIONS) Log.i(TAG, " DIM "
+ + mDimSurface + ": final alpha=" + mDimCurrentAlpha);
+ mDimSurface.setAlpha(mDimCurrentAlpha);
+ if (!dimming) {
+ if (SHOW_TRANSACTIONS) Log.i(TAG, " DIM " + mDimSurface
+ + ": HIDE");
+ try {
+ mDimSurface.hide();
+ } catch (RuntimeException e) {
+ Log.w(TAG, "Illegal argument exception hiding dim surface");
+ }
+ mDimShown = false;
+ }
+ }
+ }
+
if (!blurring && mBlurShown) {
if (SHOW_TRANSACTIONS) Log.i(TAG, " BLUR " + mBlurSurface
+ ": HIDE");
@@ -6956,7 +7650,10 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
WindowState win = mResizingWindows.get(i);
try {
win.mClient.resized(win.mFrame.width(),
- win.mFrame.height(), win.mDrawPending);
+ win.mFrame.height(), win.mLastContentInsets,
+ win.mLastVisibleInsets, win.mDrawPending);
+ win.mContentInsetsChanged = false;
+ win.mVisibleInsetsChanged = false;
} catch (RemoteException e) {
win.mOrientationChanging = false;
}
@@ -6976,14 +7673,20 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
mDestroySurface.clear();
}
+ // Time to remove any exiting tokens?
+ for (i=mExitingTokens.size()-1; i>=0; i--) {
+ WindowToken token = mExitingTokens.get(i);
+ if (!token.hasVisible) {
+ mExitingTokens.remove(i);
+ }
+ }
+
// Time to remove any exiting applications?
- for (i=0; i<mExitingAppTokens.size(); i++) {
+ for (i=mExitingAppTokens.size()-1; i>=0; i--) {
AppWindowToken token = mExitingAppTokens.get(i);
if (!token.hasVisible && !mClosingApps.contains(token)) {
mAppTokens.remove(token);
mExitingAppTokens.remove(i);
- i--;
- //dump();
}
}
@@ -7118,7 +7821,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
}
- private boolean updateFocusedWindowLocked() {
+ private boolean updateFocusedWindowLocked(int mode) {
WindowState newFocus = computeFocusedWindowLocked();
if (mCurrentFocus != newFocus) {
// This check makes sure that we don't already have the focus
@@ -7128,11 +7831,26 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
if (localLOGV) Log.v(
TAG, "Changing focus from " + mCurrentFocus + " to " + newFocus);
+ final WindowState oldFocus = mCurrentFocus;
mCurrentFocus = newFocus;
mLosingFocus.remove(newFocus);
if (newFocus != null) {
mKeyWaiter.handleNewWindowLocked(newFocus);
}
+
+ final WindowState imWindow = mInputMethodWindow;
+ if (newFocus != imWindow && oldFocus != imWindow) {
+ moveInputMethodWindowsIfNeededLocked(
+ mode != UPDATE_FOCUS_WILL_ASSIGN_LAYERS &&
+ mode != UPDATE_FOCUS_WILL_PLACE_SURFACES);
+ mLayoutNeeded = true;
+ if (mode == UPDATE_FOCUS_PLACING_SURFACES) {
+ performLayoutLockedInner();
+ } else if (mode != UPDATE_FOCUS_WILL_PLACE_SURFACES) {
+ mLayoutNeeded = true;
+ performLayoutAndPlaceSurfacesLocked();
+ }
+ }
return true;
}
return false;
@@ -7286,6 +8004,14 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
pw.println(" Window #" + i + ":");
w.dump(pw, " ");
}
+ if (mInputMethodDialogs.size() > 0) {
+ pw.println(" ");
+ pw.println(" Input method dialogs:");
+ for (int i=mInputMethodDialogs.size()-1; i>=0; i--) {
+ WindowState w = mInputMethodDialogs.get(i);
+ pw.println(" IM Dialog #" + i + ": " + w);
+ }
+ }
if (mPendingRemove.size() > 0) {
pw.println(" ");
pw.println(" Remove pending for:");
@@ -7295,6 +8021,15 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
w.dump(pw, " ");
}
}
+ if (mForceRemoves != null && mForceRemoves.size() > 0) {
+ pw.println(" ");
+ pw.println(" Windows force removing:");
+ for (int i=mForceRemoves.size()-1; i>=0; i--) {
+ WindowState w = mForceRemoves.get(i);
+ pw.println(" Removing #" + i + ":");
+ w.dump(pw, " ");
+ }
+ }
if (mDestroySurface.size() > 0) {
pw.println(" ");
pw.println(" Windows waiting to destroy their surface:");
@@ -7333,13 +8068,18 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
token.dump(pw, " ");
}
}
+ if (mTokenList.size() > 0) {
+ pw.println(" ");
+ pw.println(" Window token list:");
+ for (int i=0; i<mTokenList.size(); i++) {
+ pw.println(" WindowToken #" + i + ": " + mTokenList.get(i));
+ }
+ }
if (mAppTokens.size() > 0) {
pw.println(" ");
pw.println(" Application tokens in Z order:");
for (int i=mAppTokens.size()-1; i>=0; i--) {
- WindowToken token = mAppTokens.get(i);
- pw.println(" App Token #" + i + ":");
- token.dump(pw, " ");
+ pw.println(" AppWindowToken #" + i + ": " + mAppTokens.get(i));
}
}
if (mFinishedStarting.size() > 0) {
@@ -7351,6 +8091,15 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
token.dump(pw, " ");
}
}
+ if (mExitingTokens.size() > 0) {
+ pw.println(" ");
+ pw.println(" Exiting tokens:");
+ for (int i=mExitingTokens.size()-1; i>=0; i--) {
+ WindowToken token = mExitingTokens.get(i);
+ pw.println(" Exiting Token #" + i + ":");
+ token.dump(pw, " ");
+ }
+ }
if (mExitingAppTokens.size() > 0) {
pw.println(" ");
pw.println(" Exiting application tokens:");
@@ -7364,13 +8113,19 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
pw.println(" mCurrentFocus=" + mCurrentFocus);
pw.println(" mLastFocus=" + mLastFocus);
pw.println(" mFocusedApp=" + mFocusedApp);
+ pw.println(" mInputMethodTarget=" + mInputMethodTarget);
+ pw.println(" mInputMethodWindow=" + mInputMethodWindow);
pw.println(" mInTouchMode=" + mInTouchMode);
pw.println(" mSystemBooted=" + mSystemBooted
+ " mDisplayEnabled=" + mDisplayEnabled);
pw.println(" mLayoutNeeded=" + mLayoutNeeded
+ " mSurfacesChanged=" + mSurfacesChanged
- + " mBlurShown=" + mBlurShown
- + " mDimShown=" + mDimShown);
+ + " mBlurShown=" + mBlurShown);
+ pw.println(" mDimShown=" + mDimShown
+ + " current=" + mDimCurrentAlpha
+ + " target=" + mDimTargetAlpha
+ + " delta=" + mDimDeltaPerMs
+ + " lastAnimTime=" + mLastDimAnimTime);
pw.println(" mDisplayFrozen=" + mDisplayFrozen
+ " mWindowsFreezingScreen=" + mWindowsFreezingScreen
+ " mAppsFreezingScreen=" + mAppsFreezingScreen);
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index db1a43a..6c58997f 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -16,6 +16,7 @@
package com.android.server.am;
+import com.android.internal.os.BatteryStatsImpl;
import com.android.internal.os.RuntimeInit;
import com.android.server.IntentResolver;
import com.android.server.ProcessMap;
@@ -37,6 +38,7 @@ import android.app.IIntentReceiver;
import android.app.IIntentSender;
import android.app.IServiceConnection;
import android.app.IThumbnailReceiver;
+import android.app.Instrumentation;
import android.app.PendingIntent;
import android.app.ResultInfo;
import android.content.ComponentName;
@@ -87,6 +89,8 @@ import android.view.View;
import android.view.WindowManager;
import android.view.WindowManagerPolicy;
+import dalvik.system.Zygote;
+
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
@@ -619,7 +623,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
* All information we have collected about the runtime performance of
* any user id that can impact battery performance.
*/
- final BatteryStats mBatteryStats;
+ final BatteryStatsService mBatteryStatsService;
/**
* Current configuration information. HistoryRecord objects are given
@@ -1041,7 +1045,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
m.mLaunchingActivity = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Launch");
m.mLaunchingActivity.setReferenceCounted(false);
- m.mBatteryStats.publish(context);
+ m.mBatteryStatsService.publish(context);
synchronized (thr) {
thr.mReady = true;
@@ -1209,10 +1213,10 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
File dataDir = Environment.getDataDirectory();
File systemDir = new File(dataDir, "system");
systemDir.mkdirs();
- mBatteryStats = new BatteryStats(new File(
+ mBatteryStatsService = new BatteryStatsService(new File(
systemDir, "batterystats.bin").toString());
- mBatteryStats.readLocked();
- mBatteryStats.writeLocked();
+ mBatteryStatsService.getActiveStatistics().readLocked();
+ mBatteryStatsService.getActiveStatistics().writeLocked();
mConfiguration.makeDefault();
mProcessStats.init();
@@ -1336,19 +1340,18 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
}
- synchronized(mBatteryStats) {
+ synchronized(mBatteryStatsService.getActiveStatistics()) {
synchronized(mPidsSelfLocked) {
if (haveNewCpuStats) {
- if (mBatteryStats.isOnBattery()) {
+ if (mBatteryStatsService.isOnBattery()) {
final int N = mProcessStats.countWorkingStats();
for (int i=0; i<N; i++) {
ProcessStats.Stats st
= mProcessStats.getWorkingStats(i);
ProcessRecord pr = mPidsSelfLocked.get(st.pid);
if (pr != null) {
- BatteryStats.Uid.Proc ps = pr.batteryStats;
- ps.userTime += st.rel_utime;
- ps.systemTime += st.rel_stime;
+ BatteryStatsImpl.Uid.Proc ps = pr.batteryStats;
+ ps.addCpuTimeLocked(st.rel_utime, st.rel_stime);
}
}
}
@@ -1357,7 +1360,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
if (mLastWriteTime < (now-BATTERY_STATS_TIME)) {
mLastWriteTime = now;
- mBatteryStats.writeLocked();
+ mBatteryStatsService.getActiveStatistics().writeLocked();
}
}
}
@@ -1627,11 +1630,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
app = newProcessRecordLocked(null, info, processName);
mProcessNames.put(processName, info.uid, app);
} else {
- // If this is a new package in the process, then the process does
- // not have a unique package name.
- if (!info.packageName.equals(app.uniquePackage)) {
- app.uniquePackage = null;
- }
+ // If this is a new package in the process, add the package to the list
+ app.addPackage(info.packageName);
}
// If the system is not ready yet, then hold off on starting this
@@ -1684,13 +1684,23 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
uid = 0;
}
}
+ int debugFlags = 0;
+ if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
+ debugFlags |= Zygote.DEBUG_ENABLE_DEBUGGER;
+ }
+ if ("1".equals(SystemProperties.get("debug.checkjni"))) {
+ debugFlags |= Zygote.DEBUG_ENABLE_CHECKJNI;
+ }
+ if ("1".equals(SystemProperties.get("debug.assert"))) {
+ debugFlags |= Zygote.DEBUG_ENABLE_ASSERT;
+ }
int pid = Process.start("android.app.ActivityThread",
mSimpleProcessManagement ? app.processName : null, uid, uid,
- gids, ((app.info.flags&ApplicationInfo.FLAG_DEBUGGABLE) != 0), null);
- BatteryStats bs = app.batteryStats.getBatteryStats();
+ gids, debugFlags, null);
+ BatteryStatsImpl bs = app.batteryStats.getBatteryStats();
synchronized (bs) {
if (bs.isOnBattery()) {
- app.batteryStats.starts++;
+ app.batteryStats.incStartsLocked();
}
}
@@ -2989,8 +2999,11 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
intent.setComponent(new ComponentName(
aInfo.applicationInfo.packageName, aInfo.name));
+ // Don't debug things in the system process
if (debug) {
- setDebugApp(aInfo.processName, true, false);
+ if (!aInfo.processName.equals("system")) {
+ setDebugApp(aInfo.processName, true, false);
+ }
}
}
@@ -3195,7 +3208,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
private final void stopActivityLocked(HistoryRecord r) {
if (DEBUG_SWITCH) Log.d(TAG, "Stopping: " + r);
- if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_HISTORY) != 0) {
+ if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_HISTORY) != 0
+ || (r.info.flags&ActivityInfo.FLAG_NO_HISTORY) != 0) {
if (!r.finishing) {
requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
"no-history");
@@ -4311,7 +4325,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
thread.asBinder().linkToDeath(new AppDeathRecipient(
app, pid, thread), 0);
} catch (RemoteException e) {
- app.uniquePackage = app.info.packageName;
+ app.resetPackageList();
startProcessLocked(app, "link fail", processName);
return false;
}
@@ -4353,7 +4367,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// an infinite loop of restarting processes...
Log.w(TAG, "Exception thrown during bind!", e);
- app.uniquePackage = app.info.packageName;
+ app.resetPackageList();
startProcessLocked(app, "bind fail", processName);
return false;
}
@@ -4799,6 +4813,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
String msg = "Permission Denial: getIntentSender() from pid="
+ Binder.getCallingPid()
+ ", uid=" + Binder.getCallingUid()
+ + ", (need uid=" + uid + ")"
+ " is not allowed to send as package " + packageName;
Log.w(TAG, msg);
throw new SecurityException(msg);
@@ -4821,7 +4836,9 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
final boolean noCreate = (flags&PendingIntent.FLAG_NO_CREATE) != 0;
final boolean cancelCurrent = (flags&PendingIntent.FLAG_CANCEL_CURRENT) != 0;
- flags &= ~(PendingIntent.FLAG_NO_CREATE|PendingIntent.FLAG_CANCEL_CURRENT);
+ final boolean updateCurrent = (flags&PendingIntent.FLAG_UPDATE_CURRENT) != 0;
+ flags &= ~(PendingIntent.FLAG_NO_CREATE|PendingIntent.FLAG_CANCEL_CURRENT
+ |PendingIntent.FLAG_UPDATE_CURRENT);
PendingIntentRecord.Key key = new PendingIntentRecord.Key(
type, packageName, activity, resultWho,
@@ -4831,6 +4848,9 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
PendingIntentRecord rec = ref != null ? ref.get() : null;
if (rec != null) {
if (!cancelCurrent) {
+ if (updateCurrent) {
+ rec.key.requestIntent.replaceExtras(intent);
+ }
return rec;
}
rec.canceled = true;
@@ -5721,10 +5741,12 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
continue;
}
+ final int flags = target.info.flags;
+
final boolean finishOnTaskLaunch =
- (target.info.flags&ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH) != 0;
+ (flags&ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH) != 0;
final boolean allowTaskReparenting =
- (target.info.flags&ActivityInfo.FLAG_ALLOW_TASK_REPARENTING) != 0;
+ (flags&ActivityInfo.FLAG_ALLOW_TASK_REPARENTING) != 0;
if (target.task == task) {
// We are inside of the task being reset... we'll either
@@ -5736,6 +5758,9 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
taskTopI = targetI;
}
if (below != null && below.task == task) {
+ final boolean clearWhenTaskReset =
+ (target.intent.getFlags()
+ &Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0;
if (!finishOnTaskLaunch && target.resultTo != null) {
// If this activity is sending a reply to a previous
// activity, we can't do anything with it now until
@@ -5808,12 +5833,24 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
replyChainEnd = -1;
addRecentTask(target.task);
- } else if (forceReset || finishOnTaskLaunch) {
+ } else if (forceReset || finishOnTaskLaunch
+ || clearWhenTaskReset) {
// If the activity should just be removed -- either
// because it asks for it, or the task should be
// cleared -- then finish it and anything that is
// part of its reply chain.
- if (replyChainEnd < 0) {
+ if (clearWhenTaskReset) {
+ // In this case, we want to finish this activity
+ // and everything above it, so be sneaky and pretend
+ // like these are all in the reply chain.
+ replyChainEnd = targetI+1;
+ while (replyChainEnd < mHistory.size() &&
+ ((HistoryRecord)mHistory.get(
+ replyChainEnd)).task == task) {
+ replyChainEnd++;
+ }
+ replyChainEnd--;
+ } else if (replyChainEnd < 0) {
replyChainEnd = targetI;
}
HistoryRecord p = null;
@@ -6377,9 +6414,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
mProvidersByClass.put(cpi.name, cpr);
}
app.pubProviders.put(cpi.name, cpr);
- if (!cpi.applicationInfo.packageName.equals(app.uniquePackage)) {
- app.uniquePackage = null;
- }
+ app.addPackage(cpi.applicationInfo.packageName);
}
}
return providers;
@@ -6725,9 +6760,10 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
final ProcessRecord newProcessRecordLocked(IApplicationThread thread,
ApplicationInfo info, String customProcess) {
String proc = customProcess != null ? customProcess : info.processName;
- BatteryStats.Uid.Proc ps = null;
- synchronized (mBatteryStats) {
- ps = mBatteryStats.getProcessStatsLocked(info.uid, proc);
+ BatteryStatsImpl.Uid.Proc ps = null;
+ BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
+ synchronized (stats) {
+ ps = stats.getProcessStatsLocked(info.uid, proc);
}
return new ProcessRecord(ps, thread, info, proc);
}
@@ -6931,15 +6967,16 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
if (!(sender instanceof PendingIntentRecord)) {
return;
}
- synchronized(mBatteryStats) {
- if (mBatteryStats.isOnBattery()) {
- mBatteryStats.enforceCallingPermission();
+ BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
+ synchronized (stats) {
+ if (mBatteryStatsService.isOnBattery()) {
+ mBatteryStatsService.enforceCallingPermission();
PendingIntentRecord rec = (PendingIntentRecord)sender;
int MY_UID = Binder.getCallingUid();
int uid = rec.uid == MY_UID ? Process.SYSTEM_UID : rec.uid;
- BatteryStats.Uid.Pkg pkg = mBatteryStats.getPackageStatsLocked(uid,
- rec.key.packageName);
- pkg.wakeups++;
+ BatteryStatsImpl.Uid.Pkg pkg =
+ stats.getPackageStatsLocked(uid, rec.key.packageName);
+ pkg.incWakeupsLocked();
}
}
}
@@ -7539,6 +7576,29 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
return errList;
}
+
+ public List<ActivityManager.RunningAppProcessInfo> getRunningAppProcesses() {
+ // Lazy instantiation of list
+ List<ActivityManager.RunningAppProcessInfo> runList = null;
+ synchronized (this) {
+ // Iterate across all processes
+ final int N = mLRUProcesses.size();
+ for (int i = 0; i < N; i++) {
+ ProcessRecord app = mLRUProcesses.get(i);
+ if ((app.thread != null) && (!app.crashing && !app.notResponding)) {
+ // Generate process state info for running application
+ ActivityManager.RunningAppProcessInfo currApp =
+ new ActivityManager.RunningAppProcessInfo(app.processName,
+ app.pid, app.getPackageList());
+ if (runList == null) {
+ runList = new ArrayList<ActivityManager.RunningAppProcessInfo>();
+ }
+ runList.add(currApp);
+ }
+ }
+ }
+ return runList;
+ }
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
@@ -8268,7 +8328,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
app.crashing = false;
app.notResponding = false;
- app.uniquePackage = app.info.packageName;
+ app.resetPackageList();
app.thread = null;
app.forcingToForeground = null;
app.foregroundServices = false;
@@ -8532,9 +8592,10 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
if (r == null) {
filter = new Intent.FilterComparison(service.cloneFilter());
ServiceRestarter res = new ServiceRestarter();
- BatteryStats.Uid.Pkg.Serv ss = null;
- synchronized (mBatteryStats) {
- ss = mBatteryStats.getServiceStatsLocked(
+ BatteryStatsImpl.Uid.Pkg.Serv ss = null;
+ BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
+ synchronized (stats) {
+ ss = stats.getServiceStatsLocked(
sInfo.applicationInfo.uid, sInfo.packageName,
sInfo.name);
}
@@ -9616,8 +9677,9 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
final int uid = intentExtras != null
? intentExtras.getInt(Intent.EXTRA_UID) : -1;
if (uid >= 0) {
- synchronized (mBatteryStats) {
- mBatteryStats.uidStats.remove(uid);
+ BatteryStatsImpl bs = mBatteryStatsService.getActiveStatistics();
+ synchronized (bs) {
+ bs.removeUidStatsLocked(uid);
}
}
} else {
@@ -9652,11 +9714,11 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// Add to the sticky list if requested.
if (sticky) {
- if (checkCallingPermission(android.Manifest.permission.BROADCAST_STICKY)
+ if (checkPermission(android.Manifest.permission.BROADCAST_STICKY,
+ callingPid, callingUid)
!= PackageManager.PERMISSION_GRANTED) {
String msg = "Permission Denial: broadcastIntent() requesting a sticky broadcast from pid="
- + Binder.getCallingPid()
- + ", uid=" + Binder.getCallingUid()
+ + callingPid + ", uid=" + callingUid
+ " requires " + android.Manifest.permission.BROADCAST_STICKY;
Log.w(TAG, msg);
throw new SecurityException(msg);
@@ -10433,13 +10495,13 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
} catch (PackageManager.NameNotFoundException e) {
}
if (ii == null) {
- Log.w(TAG, "Unable to find instrumentation info for: "
- + className);
+ reportStartInstrumentationFailure(watcher, className,
+ "Unable to find instrumentation info for: " + className);
return false;
}
if (ai == null) {
- Log.w(TAG, "Unable to find instrumentation target package: "
- + ii.targetPackage);
+ reportStartInstrumentationFailure(watcher, className,
+ "Unable to find instrumentation target package: " + ii.targetPackage);
return false;
}
@@ -10453,7 +10515,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
+ " not allowed because package " + ii.packageName
+ " does not have a signature matching the target "
+ ii.targetPackage;
- Log.w(TAG, msg);
+ reportStartInstrumentationFailure(watcher, className, msg);
throw new SecurityException(msg);
}
@@ -10470,6 +10532,30 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
return true;
}
+
+ /**
+ * Report errors that occur while attempting to start Instrumentation. Always writes the
+ * error to the logs, but if somebody is watching, send the report there too. This enables
+ * the "am" command to report errors with more information.
+ *
+ * @param watcher The IInstrumentationWatcher. Null if there isn't one.
+ * @param cn The component name of the instrumentation.
+ * @param report The error report.
+ */
+ private void reportStartInstrumentationFailure(IInstrumentationWatcher watcher,
+ ComponentName cn, String report) {
+ Log.w(TAG, report);
+ try {
+ if (watcher != null) {
+ Bundle results = new Bundle();
+ results.putString(Instrumentation.REPORT_KEY_IDENTIFIER, "ActivityManagerService");
+ results.putString("Error", report);
+ watcher.instrumentationStatus(cn, -1, results);
+ }
+ } catch (RemoteException e) {
+ Log.w(TAG, e);
+ }
+ }
void finishInstrumentationLocked(ProcessRecord app, int resultCode, Bundle results) {
if (app.instrumentationWatcher != null) {
@@ -10549,19 +10635,20 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
Configuration newConfig = new Configuration(mConfiguration);
changes = newConfig.updateFrom(values);
if (changes != 0) {
- mConfiguration = newConfig;
-
if (DEBUG_SWITCH) {
Log.i(TAG, "Updating configuration to: " + values);
}
EventLog.writeEvent(LOG_CONFIGURATION_CHANGED, changes);
-
- if (values.locale != null &&
- !mConfiguration.locale.equals(values.locale)) {
- saveLocaleLocked(values.locale);
+
+ if (values.locale != null) {
+ saveLocaleLocked(values.locale,
+ !values.locale.equals(mConfiguration.locale),
+ values.userSetLocale);
}
-
+
+ mConfiguration = newConfig;
+
Message msg = mHandler.obtainMessage(UPDATE_CONFIGURATION_MSG);
msg.obj = new Configuration(mConfiguration);
mHandler.sendMessage(msg);
@@ -10744,10 +10831,17 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
/**
* Save the locale. You must be inside a synchronized (this) block.
*/
- private void saveLocaleLocked(Locale l) {
- SystemProperties.set("persist.locale.lang", l.getLanguage());
- SystemProperties.set("persist.locale.country", l.getCountry());
- SystemProperties.set("persist.locale.var", l.getVariant());
+ private void saveLocaleLocked(Locale l, boolean isDiff, boolean isPersist) {
+ if(isDiff) {
+ SystemProperties.set("user.language", l.getLanguage());
+ SystemProperties.set("user.region", l.getCountry());
+ }
+
+ if(isPersist) {
+ SystemProperties.set("persist.sys.language", l.getLanguage());
+ SystemProperties.set("persist.sys.country", l.getCountry());
+ SystemProperties.set("persist.sys.localevar", l.getVariant());
+ }
}
// =========================================================
diff --git a/services/java/com/android/server/am/AppErrorDialog.java b/services/java/com/android/server/am/AppErrorDialog.java
index 627ff09..3fcfad0 100644
--- a/services/java/com/android/server/am/AppErrorDialog.java
+++ b/services/java/com/android/server/am/AppErrorDialog.java
@@ -44,7 +44,7 @@ class AppErrorDialog extends BaseErrorDialog {
mProc = app;
mResult = result;
CharSequence name;
- if (app.uniquePackage != null &&
+ if ((app.pkgList.size() == 1) &&
(name=context.getPackageManager().getApplicationLabel(app.info)) != null) {
setMessage(res.getString(
com.android.internal.R.string.aerr_application,
diff --git a/services/java/com/android/server/am/AppNotRespondingDialog.java b/services/java/com/android/server/am/AppNotRespondingDialog.java
index 353dd7d..7390ed0 100644
--- a/services/java/com/android/server/am/AppNotRespondingDialog.java
+++ b/services/java/com/android/server/am/AppNotRespondingDialog.java
@@ -44,7 +44,7 @@ class AppNotRespondingDialog extends BaseErrorDialog {
? activity.info.loadLabel(context.getPackageManager())
: null;
CharSequence name2 = null;
- if (app.uniquePackage != null &&
+ if ((app.pkgList.size() == 1) &&
(name2=context.getPackageManager().getApplicationLabel(app.info)) != null) {
if (name1 != null) {
resid = com.android.internal.R.string.anr_activity_application;
diff --git a/services/java/com/android/server/am/BatteryStats.java b/services/java/com/android/server/am/BatteryStats.java
deleted file mode 100644
index ea31dc0..0000000
--- a/services/java/com/android/server/am/BatteryStats.java
+++ /dev/null
@@ -1,1146 +0,0 @@
-/*
- * Copyright (C) 2006 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.am;
-
-import com.android.internal.app.IBatteryStats;
-
-import android.content.Context;
-import android.os.Binder;
-import android.os.IBinder;
-import android.os.Parcel;
-import android.os.Process;
-import android.os.ServiceManager;
-import android.os.SystemClock;
-import android.util.Config;
-import android.util.Log;
-import android.util.SparseArray;
-
-import java.io.File;
-import java.io.FileDescriptor;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.PrintWriter;
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * All information we are collecting about things that can happen that impact
- * battery life.
- */
-public final class BatteryStats extends IBatteryStats.Stub {
- public static final int WAKE_TYPE_PARTIAL = 0;
- public static final int WAKE_TYPE_FULL = 1;
- public static final int WAKE_TYPE_WINDOW = 2;
-
- /**
- * Include all of the loaded data in the stats.
- */
- public static final int STATS_LOADED = 0;
-
- /**
- * Include only the last run in the stats.
- */
- public static final int STATS_LAST = 1;
-
- /**
- * Include only the current run in the stats.
- */
- public static final int STATS_CURRENT = 2;
-
- static final int VERSION = 11;
-
- static IBatteryStats sService;
-
- final File mFile;
- final File mBackupFile;
-
- Context mContext;
-
- /**
- * The statistics we have collected organized by uids.
- */
- final SparseArray<Uid> uidStats = new SparseArray<Uid>();
-
- int mStartCount;
-
- long mBatteryUptime;
- long mBatteryUptimeStart;
- long mBatteryLastUptime;
- long mBatteryRealtime;
- long mBatteryRealtimeStart;
- long mBatteryLastRealtime;
-
- long mUptime;
- long mUptimeStart;
- long mLastUptime;
- long mRealtime;
- long mRealtimeStart;
- long mLastRealtime;
-
- /**
- * These provide time bases that discount the time the device is plugged
- * in to power.
- */
- boolean mOnBattery = true;
- long mTrackBatteryPastUptime = 0;
- long mTrackBatteryUptimeStart = 0;
- long mTrackBatteryPastRealtime = 0;
- long mTrackBatteryRealtimeStart = 0;
-
- /**
- * State for keeping track of timing information.
- */
- final static class Timer {
- long totalTime;
- long startTime;
- int nesting;
- int count;
- long loadedTotalTime;
- int loadedCount;
- long lastTotalTime;
- int lastCount;
-
- void startRunningLocked(BatteryStats stats) {
- if (nesting == 0) {
- nesting = 1;
- startTime = stats.getBatteryUptimeLocked();
- count++;
- } else {
- nesting++;
- }
- }
-
- void stopRunningLocked(BatteryStats stats) {
- if (nesting == 1) {
- nesting = 0;
- long heldTime = stats.getBatteryUptimeLocked() - startTime;
- if (heldTime != 0) {
- totalTime += heldTime;
- } else {
- count--;
- }
- } else {
- nesting--;
- }
- }
-
- long computeRunTimeLocked(long curTime) {
- return totalTime + (nesting > 0 ? (curTime-startTime) : 0);
- }
-
- void writeLocked(Parcel out, long curTime) throws java.io.IOException {
- long runTime = computeRunTimeLocked(curTime);
- out.writeLong(runTime);
- out.writeLong(runTime - loadedTotalTime);
- out.writeInt(count);
- out.writeInt(count - loadedCount);
- }
-
- void readLocked(Parcel in) throws java.io.IOException {
- totalTime = loadedTotalTime = in.readLong();
- lastTotalTime = in.readLong();
- count = loadedCount = in.readInt();
- lastCount = in.readInt();
- nesting = 0;
- }
- }
-
- /**
- * The statistics associated with a particular uid.
- */
- final class Uid {
- /**
- * The statics we have collected for this uid's wake locks.
- */
- final HashMap<String, Wakelock> wakelockStats = new HashMap<String, Wakelock>();
-
- /**
- * The statics we have collected for this uid's processes.
- */
- final HashMap<String, Proc> processStats = new HashMap<String, Proc>();
-
- /**
- * The statics we have collected for this uid's processes.
- */
- final HashMap<String, Pkg> packageStats = new HashMap<String, Pkg>();
-
- /**
- * The statistics associated with a particular wake lock.
- */
- final class Wakelock {
- /**
- * How long (in ms) this uid has been keeping the device partially awake.
- */
- Timer wakeTimePartial;
-
- /**
- * How long (in ms) this uid has been keeping the device fully awake.
- */
- Timer wakeTimeFull;
-
- /**
- * How long (in ms) this uid has had a window keeping the device awake.
- */
- Timer wakeTimeWindow;
- }
-
- /**
- * The statistics associated with a particular process.
- */
- final class Proc {
- /**
- * Total time (in 1/100 sec) spent executing in user code.
- */
- long userTime;
-
- /**
- * Total time (in 1/100 sec) spent executing in kernel code.
- */
- long systemTime;
-
- /**
- * Number of times the process has been started.
- */
- int starts;
-
- /**
- * The amount of user time loaded from a previous save.
- */
- long loadedUserTime;
-
- /**
- * The amount of system time loaded from a previous save.
- */
- long loadedSystemTime;
-
- /**
- * The number of times the process has started from a previous save.
- */
- int loadedStarts;
-
- /**
- * The amount of user time loaded from the previous run.
- */
- long lastUserTime;
-
- /**
- * The amount of system time loaded from the previous run.
- */
- long lastSystemTime;
-
- /**
- * The number of times the process has started from the previous run.
- */
- int lastStarts;
-
- BatteryStats getBatteryStats() {
- return BatteryStats.this;
- }
- }
-
- /**
- * The statistics associated with a particular package.
- */
- final class Pkg {
- /**
- * Number of times this package has done something that could wake up the
- * device from sleep.
- */
- int wakeups;
-
- /**
- * Number of things that could wake up the device loaded from a
- * previous save.
- */
- int loadedWakeups;
-
- /**
- * Number of things that could wake up the device as of the
- * last run.
- */
- int lastWakeups;
-
- /**
- * The statics we have collected for this package's services.
- */
- final HashMap<String, Serv> serviceStats = new HashMap<String, Serv>();
-
- /**
- * The statistics associated with a particular service.
- */
- final class Serv {
- /**
- * Total time (ms) the service has been left started.
- */
- long startTime;
-
- /**
- * If service has been started and not yet stopped, this is
- * when it was started.
- */
- long runningSince;
-
- /**
- * True if we are currently running.
- */
- boolean running;
-
- /**
- * Total number of times startService() has been called.
- */
- int starts;
-
- /**
- * Total time (ms) the service has been left launched.
- */
- long launchedTime;
-
- /**
- * If service has been launched and not yet exited, this is
- * when it was launched.
- */
- long launchedSince;
-
- /**
- * True if we are currently launched.
- */
- boolean launched;
-
- /**
- * Total number times the service has been launched.
- */
- int launches;
-
- /**
- * The amount of time spent started loaded from a previous save.
- */
- long loadedStartTime;
-
- /**
- * The number of starts loaded from a previous save.
- */
- int loadedStarts;
-
- /**
- * The number of launches loaded from a previous save.
- */
- int loadedLaunches;
-
- /**
- * The amount of time spent started as of the last run.
- */
- long lastStartTime;
-
- /**
- * The number of starts as of the last run.
- */
- int lastStarts;
-
- /**
- * The number of launches as of the last run.
- */
- int lastLaunches;
-
- long getLaunchTimeToNowLocked(long now) {
- if (!launched) return launchedTime;
- return launchedTime + now - launchedSince;
- }
-
- long getStartTimeToNowLocked(long now) {
- if (!running) return startTime;
- return startTime + now - runningSince;
- }
-
- void startLaunchedLocked() {
- if (!launched) {
- launches++;
- launchedSince = getBatteryUptimeLocked();
- launched = true;
- }
- }
-
- void stopLaunchedLocked() {
- if (launched) {
- long time = getBatteryUptimeLocked() - launchedSince;
- if (time > 0) {
- launchedTime += time;
- } else {
- launches--;
- }
- launched = false;
- }
- }
-
- void startRunningLocked() {
- if (!running) {
- starts++;
- runningSince = getBatteryUptimeLocked();
- running = true;
- }
- }
-
- void stopRunningLocked() {
- if (running) {
- long time = getBatteryUptimeLocked() - runningSince;
- if (time > 0) {
- startTime += time;
- } else {
- starts--;
- }
- running = false;
- }
- }
-
- BatteryStats getBatteryStats() {
- return BatteryStats.this;
- }
- }
-
- BatteryStats getBatteryStats() {
- return BatteryStats.this;
- }
-
- private final Serv newServiceStatsLocked() {
- return new Serv();
- }
- }
-
- /**
- * Retrieve the statistics object for a particular process, creating
- * if needed.
- */
- Proc getProcessStatsLocked(String name) {
- Proc ps = processStats.get(name);
- if (ps == null) {
- ps = new Proc();
- processStats.put(name, ps);
- }
-
- return ps;
- }
-
- /**
- * Retrieve the statistics object for a particular service, creating
- * if needed.
- */
- Pkg getPackageStatsLocked(String name) {
- Pkg ps = packageStats.get(name);
- if (ps == null) {
- ps = new Pkg();
- packageStats.put(name, ps);
- }
-
- return ps;
- }
-
- /**
- * Retrieve the statistics object for a particular service, creating
- * if needed.
- */
- Pkg.Serv getServiceStatsLocked(String pkg, String serv) {
- Pkg ps = getPackageStatsLocked(pkg);
- Pkg.Serv ss = ps.serviceStats.get(serv);
- if (ss == null) {
- ss = ps.newServiceStatsLocked();
- ps.serviceStats.put(serv, ss);
- }
-
- return ss;
- }
-
- Timer getWakeTimerLocked(String name, int type) {
- Wakelock wl = wakelockStats.get(name);
- if (wl == null) {
- wl = new Wakelock();
- wakelockStats.put(name, wl);
- }
- Timer t = null;
- switch (type) {
- case WAKE_TYPE_PARTIAL:
- t = wl.wakeTimePartial;
- if (t == null) {
- t = new Timer();
- wl.wakeTimePartial = t;
- }
- return t;
- case WAKE_TYPE_FULL:
- t = wl.wakeTimeFull;
- if (t == null) {
- t = new Timer();
- wl.wakeTimeFull = t;
- }
- return t;
- case WAKE_TYPE_WINDOW:
- t = wl.wakeTimeWindow;
- if (t == null) {
- t = new Timer();
- wl.wakeTimeWindow = t;
- }
- return t;
- }
- return t;
- }
-
- void noteStartWakeLocked(String name, int type) {
- Timer t = getWakeTimerLocked(name, type);
- if (t != null) {
- t.startRunningLocked(BatteryStats.this);
- }
- }
-
- void noteStopWakeLocked(String name, int type) {
- Timer t = getWakeTimerLocked(name, type);
- if (t != null) {
- t.stopRunningLocked(BatteryStats.this);
- }
- }
-
- BatteryStats getBatteryStats() {
- return BatteryStats.this;
- }
- }
-
- BatteryStats(String filename) {
- mFile = new File(filename);
- mBackupFile = new File(filename + ".bak");
- mStartCount++;
- mUptimeStart = SystemClock.uptimeMillis();
- mRealtimeStart = SystemClock.elapsedRealtime();
- }
-
- public void publish(Context context) {
- mContext = context;
- ServiceManager.addService("batteryinfo", asBinder());
- }
-
- public static IBatteryStats getService() {
- if (sService != null) {
- return sService;
- }
- IBinder b = ServiceManager.getService("batteryinfo");
- sService = asInterface(b);
- return sService;
- }
-
- public void noteStartWakelock(int uid, String name, int type) {
- enforceCallingPermission();
- synchronized(this) {
- getUidStatsLocked(uid).noteStartWakeLocked(name, type);
- }
- }
-
- public void noteStopWakelock(int uid, String name, int type) {
- enforceCallingPermission();
- synchronized(this) {
- getUidStatsLocked(uid).noteStopWakeLocked(name, type);
- }
- }
-
- public boolean isOnBattery() {
- return mOnBattery;
- }
-
- public void setOnBattery(boolean onBattery) {
- enforceCallingPermission();
- synchronized(this) {
- if (mOnBattery != onBattery) {
- if (onBattery) {
- mTrackBatteryUptimeStart = SystemClock.uptimeMillis();
- mTrackBatteryRealtimeStart = SystemClock.elapsedRealtime();
- } else {
- mTrackBatteryPastUptime +=
- SystemClock.uptimeMillis() - mTrackBatteryUptimeStart;
- mTrackBatteryPastRealtime +=
- SystemClock.elapsedRealtime() - mTrackBatteryRealtimeStart;
- }
- mOnBattery = onBattery;
- }
- }
- }
-
- public long getAwakeTimeBattery() {
- return computeBatteryUptime(getBatteryUptimeLocked(), STATS_CURRENT);
- }
-
- public long getAwakeTimePlugged() {
- return SystemClock.uptimeMillis() - getAwakeTimeBattery();
- }
-
- long getBatteryUptimeLocked() {
- long time = mTrackBatteryPastUptime;
- if (mOnBattery) {
- time += SystemClock.uptimeMillis() - mTrackBatteryUptimeStart;
- }
- return time;
- }
-
- long getBatteryRealtimeLocked() {
- long time = mTrackBatteryPastRealtime;
- if (mOnBattery) {
- time += SystemClock.elapsedRealtime() - mTrackBatteryRealtimeStart;
- }
- return time;
- }
-
- long computeUptime(long curTime, int which) {
- switch (which) {
- case STATS_LOADED: return mUptime + (curTime-mUptimeStart);
- case STATS_LAST: return mLastUptime;
- case STATS_CURRENT: return (curTime-mUptimeStart);
- }
- return 0;
- }
-
- long computeRealtime(long curTime, int which) {
- switch (which) {
- case STATS_LOADED: return mRealtime + (curTime-mRealtimeStart);
- case STATS_LAST: return mLastRealtime;
- case STATS_CURRENT: return (curTime-mRealtimeStart);
- }
- return 0;
- }
-
- long computeBatteryUptime(long curTime, int which) {
- switch (which) {
- case STATS_LOADED: return mBatteryUptime + (curTime-mBatteryUptimeStart);
- case STATS_LAST: return mBatteryLastUptime;
- case STATS_CURRENT: return (curTime-mBatteryUptimeStart);
- }
- return 0;
- }
-
- long computeBatteryRealtime(long curTime, int which) {
- switch (which) {
- case STATS_LOADED: return mBatteryRealtime + (curTime-mBatteryRealtimeStart);
- case STATS_LAST: return mBatteryLastRealtime;
- case STATS_CURRENT: return (curTime-mBatteryRealtimeStart);
- }
- return 0;
- }
-
- public void enforceCallingPermission() {
- if (Binder.getCallingPid() == Process.myPid()) {
- return;
- }
- mContext.enforcePermission(android.Manifest.permission.BATTERY_STATS,
- Binder.getCallingPid(), Binder.getCallingUid(), null);
- }
-
- /**
- * Retrieve the statistics object for a particular uid, creating if needed.
- */
- Uid getUidStatsLocked(int uid) {
- Uid u = uidStats.get(uid);
- if (u == null) {
- u = new Uid();
- uidStats.put(uid, u);
- }
- return u;
- }
-
- /**
- * Retrieve the statistics object for a particular process, creating
- * if needed.
- */
- Uid.Proc getProcessStatsLocked(int uid, String name) {
- Uid u = getUidStatsLocked(uid);
- return u.getProcessStatsLocked(name);
- }
-
- /**
- * Retrieve the statistics object for a particular process, creating
- * if needed.
- */
- Uid.Pkg getPackageStatsLocked(int uid, String pkg) {
- Uid u = getUidStatsLocked(uid);
- return u.getPackageStatsLocked(pkg);
- }
-
- /**
- * Retrieve the statistics object for a particular service, creating
- * if needed.
- */
- Uid.Pkg.Serv getServiceStatsLocked(int uid, String pkg, String name) {
- Uid u = getUidStatsLocked(uid);
- return u.getServiceStatsLocked(pkg, name);
- }
-
- private final static String formatTime(long time) {
- long sec = time/100;
- StringBuilder sb = new StringBuilder();
- sb.append(sec);
- if (time != 0) {
- sb.append('.');
- sb.append((char)(((time/10)%10)+'0'));
- sb.append((char)((time%10)+'0'));
- }
- sb.append(" sec");
- return sb.toString();
- }
-
- private final static String formatTimeMs(long time) {
- long sec = time/1000;
- StringBuilder sb = new StringBuilder();
- sb.append(sec);
- if (time != 0) {
- sb.append('.');
- sb.append((char)(((time/100)%10)+'0'));
- sb.append((char)(((time/10)%10)+'0'));
- sb.append((char)((time%10)+'0'));
- }
- sb.append(" sec");
- return sb.toString();
- }
-
- final String printWakeLock(StringBuilder sb, Timer timer, long now,
- String name, int which, String linePrefix) {
- if (timer != null) {
- long totalTime;
- int count;
- if (which == STATS_LAST) {
- totalTime = timer.lastTotalTime;
- count = timer.lastCount;
- } else {
- totalTime = timer.computeRunTimeLocked(now);
- count = timer.count;
- if (which == STATS_CURRENT) {
- totalTime -= timer.loadedTotalTime;
- count -= timer.loadedCount;
- }
- }
- if (totalTime != 0) {
- sb.append(linePrefix);
- sb.append(formatTimeMs(totalTime));
- sb.append(' ');
- sb.append(name);
- sb.append(' ');
- sb.append('(');
- sb.append(count);
- sb.append(" times)");
- return ", ";
- }
- }
- return linePrefix;
- }
-
- final void dumpLocked(FileDescriptor fd, PrintWriter pw, String prefix,
- int which) {
- final long NOW = getBatteryUptimeLocked();
-
- StringBuilder sb = new StringBuilder();
- if (which == STATS_LOADED) {
- pw.println(prefix + "Current and Historic Battery Usage Statistics:");
- pw.println(prefix + " System starts: " + mStartCount);
- } else if (which == STATS_LAST) {
- pw.println(prefix + "Last Battery Usage Statistics:");
- } else {
- pw.println(prefix + "Current Battery Usage Statistics:");
- }
- pw.println(prefix
- + " On battery: "
- + formatTimeMs(computeBatteryUptime(NOW, which))
- + " uptime, "
- + formatTimeMs(computeBatteryRealtime(getBatteryRealtimeLocked(),
- which))
- + " realtime");
- pw.println(prefix
- + " Total: "
- + formatTimeMs(computeUptime(SystemClock.uptimeMillis(), which))
- + " uptime, "
- + formatTimeMs(computeRealtime(SystemClock.elapsedRealtime(),
- which))
- + " realtime");
-
- pw.println(" ");
- final int NU = uidStats.size();
- for (int iu=0; iu<NU; iu++) {
- final int uid = uidStats.keyAt(iu);
- Uid u = uidStats.valueAt(iu);
- pw.println(prefix + " #" + uid + ":");
- boolean uidActivity = false;
- if (u.wakelockStats.size() > 0) {
- for (Map.Entry<String, BatteryStats.Uid.Wakelock> ent
- : u.wakelockStats.entrySet()) {
- Uid.Wakelock wl = ent.getValue();
- String linePrefix = ": ";
- sb.setLength(0);
- sb.append(prefix);
- sb.append(" Wake lock ");
- sb.append(ent.getKey());
- linePrefix = printWakeLock(sb, wl.wakeTimeFull, NOW,
- "full", which, linePrefix);
- linePrefix = printWakeLock(sb, wl.wakeTimePartial, NOW,
- "partial", which, linePrefix);
- linePrefix = printWakeLock(sb, wl.wakeTimeWindow, NOW,
- "window", which, linePrefix);
- if (linePrefix.equals(": ")) {
- sb.append(": (nothing executed)");
- }
- pw.println(sb.toString());
- uidActivity = true;
- }
- }
- if (u.processStats.size() > 0) {
- for (Map.Entry<String, BatteryStats.Uid.Proc> ent
- : u.processStats.entrySet()) {
- BatteryStats.Uid.Proc ps = ent.getValue();
- long userTime;
- long systemTime;
- int starts;
- if (which == STATS_LAST) {
- userTime = ps.lastUserTime;
- systemTime = ps.lastSystemTime;
- starts = ps.lastStarts;
- } else {
- userTime = ps.userTime;
- systemTime = ps.systemTime;
- starts = ps.starts;
- if (which == STATS_CURRENT) {
- userTime -= ps.loadedUserTime;
- systemTime -= ps.loadedSystemTime;
- starts -= ps.loadedStarts;
- }
- }
- if (userTime != 0 || systemTime != 0 || starts != 0) {
- pw.println(prefix + " Proc " + ent.getKey() + ":");
- pw.println(prefix + " CPU: " + formatTime(userTime) + " user + "
- + formatTime(systemTime) + " kernel");
- pw.println(prefix + " " + starts + " process starts");
- uidActivity = true;
- }
- }
- }
- if (u.packageStats.size() > 0) {
- for (Map.Entry<String, BatteryStats.Uid.Pkg> ent
- : u.packageStats.entrySet()) {
- pw.println(prefix + " Apk " + ent.getKey() + ":");
- boolean apkActivity = false;
- BatteryStats.Uid.Pkg ps = ent.getValue();
- int wakeups;
- if (which == STATS_LAST) {
- wakeups = ps.lastWakeups;
- } else {
- wakeups = ps.wakeups;
- if (which == STATS_CURRENT) {
- wakeups -= ps.loadedWakeups;
- }
- }
- if (wakeups != 0) {
- pw.println(prefix + " " + wakeups + " wakeup alarms");
- apkActivity = true;
- }
- if (ps.serviceStats.size() > 0) {
- for (Map.Entry<String, BatteryStats.Uid.Pkg.Serv> sent
- : ps.serviceStats.entrySet()) {
- BatteryStats.Uid.Pkg.Serv ss = sent.getValue();
- long time;
- int starts;
- int launches;
- if (which == STATS_LAST) {
- time = ss.lastStartTime;
- starts = ss.lastStarts;
- launches = ss.lastLaunches;
- } else {
- time = ss.getStartTimeToNowLocked(NOW);
- starts = ss.starts;
- launches = ss.launches;
- if (which == STATS_CURRENT) {
- time -= ss.loadedStartTime;
- starts -= ss.loadedStarts;
- launches -= ss.loadedLaunches;
- }
- }
- if (time != 0 || starts != 0 || launches != 0) {
- pw.println(prefix + " Service " + sent.getKey() + ":");
- pw.println(prefix + " Time spent started: "
- + formatTimeMs(time));
- pw.println(prefix + " Starts: " + starts
- + ", launches: " + launches);
- apkActivity = true;
- }
- }
- }
- if (!apkActivity) {
- pw.println(prefix + " (nothing executed)");
- }
- uidActivity = true;
- }
- }
- if (!uidActivity) {
- pw.println(prefix + " (nothing executed)");
- }
- }
- }
-
- @Override
- protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- synchronized (this) {
- dumpLocked(fd, pw, "", STATS_LOADED);
- pw.println("");
- dumpLocked(fd, pw, "", STATS_LAST);
- pw.println("");
- dumpLocked(fd, pw, "", STATS_CURRENT);
- }
- }
-
- void writeLocked() {
- // Keep the old file around until we know the new one has
- // been successfully written.
- if (mFile.exists()) {
- if (mBackupFile.exists()) {
- mBackupFile.delete();
- }
- mFile.renameTo(mBackupFile);
- }
-
- try {
- FileOutputStream stream = new FileOutputStream(mFile);
-
- final long NOW = getBatteryUptimeLocked();
- final long NOWREAL = getBatteryRealtimeLocked();
- final long NOW_SYS = SystemClock.uptimeMillis();
- final long NOWREAL_SYS = SystemClock.elapsedRealtime();
-
- Parcel out = Parcel.obtain();
- out.writeInt(VERSION);
- out.writeInt(mStartCount);
- out.writeLong(computeBatteryUptime(NOW, STATS_LOADED));
- out.writeLong(computeBatteryUptime(NOW, STATS_CURRENT));
- out.writeLong(computeBatteryRealtime(NOWREAL, STATS_LOADED));
- out.writeLong(computeBatteryRealtime(NOWREAL, STATS_CURRENT));
- out.writeLong(computeUptime(NOW_SYS, STATS_LOADED));
- out.writeLong(computeUptime(NOW_SYS, STATS_CURRENT));
- out.writeLong(computeRealtime(NOWREAL_SYS, STATS_LOADED));
- out.writeLong(computeRealtime(NOWREAL_SYS, STATS_CURRENT));
-
- final int NU = uidStats.size();
- out.writeInt(NU);
- for (int iu=0; iu<NU; iu++) {
- out.writeInt(uidStats.keyAt(iu));
- Uid u = uidStats.valueAt(iu);
- int NW = u.wakelockStats.size();
- out.writeInt(NW);
- if (NW > 0) {
- for (Map.Entry<String, BatteryStats.Uid.Wakelock> ent
- : u.wakelockStats.entrySet()) {
- out.writeString(ent.getKey());
- Uid.Wakelock wl = ent.getValue();
- if (wl.wakeTimeFull != null) {
- out.writeInt(1);
- wl.wakeTimeFull.writeLocked(out, NOW);
- } else {
- out.writeInt(0);
- }
- if (wl.wakeTimePartial != null) {
- out.writeInt(1);
- wl.wakeTimePartial.writeLocked(out, NOW);
- } else {
- out.writeInt(0);
- }
- if (wl.wakeTimeWindow != null) {
- out.writeInt(1);
- wl.wakeTimeWindow.writeLocked(out, NOW);
- } else {
- out.writeInt(0);
- }
- }
- }
-
- int NP = u.processStats.size();
- out.writeInt(NP);
- if (NP > 0) {
- for (Map.Entry<String, BatteryStats.Uid.Proc> ent
- : u.processStats.entrySet()) {
- out.writeString(ent.getKey());
- BatteryStats.Uid.Proc ps = ent.getValue();
- out.writeLong(ps.userTime);
- out.writeLong(ps.userTime - ps.loadedUserTime);
- out.writeLong(ps.systemTime);
- out.writeLong(ps.systemTime - ps.loadedSystemTime);
- out.writeInt(ps.starts);
- out.writeInt(ps.starts - ps.loadedStarts);
- }
- }
-
- NP = u.packageStats.size();
- out.writeInt(NP);
- if (NP > 0) {
- for (Map.Entry<String, BatteryStats.Uid.Pkg> ent
- : u.packageStats.entrySet()) {
- out.writeString(ent.getKey());
- BatteryStats.Uid.Pkg ps = ent.getValue();
- out.writeInt(ps.wakeups);
- out.writeInt(ps.wakeups - ps.loadedWakeups);
- final int NS = ps.serviceStats.size();
- out.writeInt(NS);
- if (NS > 0) {
- for (Map.Entry<String, BatteryStats.Uid.Pkg.Serv> sent
- : ps.serviceStats.entrySet()) {
- out.writeString(sent.getKey());
- BatteryStats.Uid.Pkg.Serv ss = sent.getValue();
- long time = ss.getStartTimeToNowLocked(NOW);
- out.writeLong(time);
- out.writeLong(time - ss.loadedStartTime);
- out.writeInt(ss.starts);
- out.writeInt(ss.starts - ss.loadedStarts);
- out.writeInt(ss.launches);
- out.writeInt(ss.launches - ss.loadedLaunches);
- }
- }
- }
- }
- }
-
- stream.write(out.marshall());
- out.recycle();
-
- stream.flush();
- stream.close();
- mBackupFile.delete();
-
- } catch(java.io.IOException e) {
- Log.e("BatteryStats", "Error writing battery statistics", e);
-
- }
- }
-
- static byte[] readFully(FileInputStream stream) throws java.io.IOException {
- int pos = 0;
- int avail = stream.available();
- byte[] data = new byte[avail];
- while (true) {
- int amt = stream.read(data, pos, data.length-pos);
- //Log.i("foo", "Read " + amt + " bytes at " + pos
- // + " of avail " + data.length);
- if (amt <= 0) {
- //Log.i("foo", "**** FINISHED READING: pos=" + pos
- // + " len=" + data.length);
- return data;
- }
- pos += amt;
- avail = stream.available();
- if (avail > data.length-pos) {
- byte[] newData = new byte[pos+avail];
- System.arraycopy(data, 0, newData, 0, pos);
- data = newData;
- }
- }
- }
-
- void readLocked() {
- uidStats.clear();
-
- FileInputStream stream = null;
- if (mBackupFile.exists()) {
- try {
- stream = new FileInputStream(mBackupFile);
- } catch (java.io.IOException e) {
- // We'll try for the normal settings file.
- }
- }
-
- try {
- if (stream == null) {
- if (!mFile.exists()) {
- return;
- }
- stream = new FileInputStream(mFile);
- }
-
- byte[] raw = readFully(stream);
- Parcel in = Parcel.obtain();
- in.unmarshall(raw, 0, raw.length);
- in.setDataPosition(0);
-
- stream.close();
-
- final int version = in.readInt();
- //Log.i("foo", "Read version: got " + version + ", expecting " + VERSION);
- if (version != VERSION) {
- return;
- }
-
- mStartCount = in.readInt();
- mBatteryUptime = in.readLong();
- mBatteryLastUptime = in.readLong();
- mBatteryRealtime = in.readLong();
- mBatteryLastRealtime = in.readLong();
- mUptime = in.readLong();
- mLastUptime = in.readLong();
- mRealtime = in.readLong();
- mLastRealtime = in.readLong();
- //Log.i("foo", "Start count: " + mStartCount);
- mStartCount++;
-
- final int NU = in.readInt();
- //Log.i("foo", "Number uids: " + NU);
- for (int iu=0; iu<NU; iu++) {
- int uid = in.readInt();
- //Log.i("foo", "Uid #" + iu + ": " + uid);
- Uid u = new Uid();
- uidStats.put(uid, u);
- int NW = in.readInt();
- for (int iw=0; iw<NW; iw++) {
- String wlName = in.readString();
- if (in.readInt() != 0) {
- u.getWakeTimerLocked(wlName, WAKE_TYPE_FULL).readLocked(in);
- }
- if (in.readInt() != 0) {
- u.getWakeTimerLocked(wlName, WAKE_TYPE_PARTIAL).readLocked(in);
- }
- if (in.readInt() != 0) {
- u.getWakeTimerLocked(wlName, WAKE_TYPE_WINDOW).readLocked(in);
- }
- }
-
- int NP = in.readInt();
- for (int ip=0; ip<NP; ip++) {
- String procName = in.readString();
- Uid.Proc p = u.getProcessStatsLocked(procName);
- p.userTime = p.loadedUserTime = in.readLong();
- p.lastUserTime = in.readLong();
- p.systemTime = p.loadedSystemTime = in.readLong();
- p.lastSystemTime = in.readLong();
- p.starts = p.loadedStarts = in.readInt();
- p.lastStarts = in.readInt();
- }
-
- NP = in.readInt();
- for (int ip=0; ip<NP; ip++) {
- String pkgName = in.readString();
- Uid.Pkg p = u.getPackageStatsLocked(pkgName);
- p.wakeups = p.loadedWakeups = in.readInt();
- p.lastWakeups = in.readInt();
- final int NS = in.readInt();
- for (int is=0; is<NS; is++) {
- String servName = in.readString();
- Uid.Pkg.Serv s = u.getServiceStatsLocked(pkgName, servName);
- s.startTime = s.loadedStartTime = in.readLong();
- s.lastStartTime = in.readLong();
- s.starts = s.loadedStarts = in.readInt();
- s.lastStarts = in.readInt();
- s.launches = s.loadedLaunches = in.readInt();
- s.lastLaunches = in.readInt();
- }
- }
- }
-
- } catch(java.io.IOException e) {
- Log.e("BatteryStats", "Error reading battery statistics", e);
- }
- }
-}
diff --git a/services/java/com/android/server/am/BatteryStatsService.java b/services/java/com/android/server/am/BatteryStatsService.java
new file mode 100644
index 0000000..bf1bc8c
--- /dev/null
+++ b/services/java/com/android/server/am/BatteryStatsService.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2006-2007 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.am;
+
+import com.android.internal.app.IBatteryStats;
+import com.android.internal.os.BatteryStatsImpl;
+
+import android.content.Context;
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.Process;
+import android.os.ServiceManager;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
+/**
+ * All information we are collecting about things that can happen that impact
+ * battery life.
+ */
+public final class BatteryStatsService extends IBatteryStats.Stub {
+ static IBatteryStats sService;
+
+ final BatteryStatsImpl mStats;
+ Context mContext;
+
+ BatteryStatsService(String filename) {
+ mStats = new BatteryStatsImpl(filename);
+ }
+
+ public void publish(Context context) {
+ mContext = context;
+ ServiceManager.addService("batteryinfo", asBinder());
+ }
+
+ public static IBatteryStats getService() {
+ if (sService != null) {
+ return sService;
+ }
+ IBinder b = ServiceManager.getService("batteryinfo");
+ sService = asInterface(b);
+ return sService;
+ }
+
+ /**
+ * @return the current statistics object, which may be modified
+ * to reflect events that affect battery usage.
+ */
+ public BatteryStatsImpl getActiveStatistics() {
+ return mStats;
+ }
+
+ public BatteryStatsImpl getStatistics() {
+ return mStats;
+ }
+
+ public void noteStartWakelock(int uid, String name, int type) {
+ enforceCallingPermission();
+ synchronized (mStats) {
+ mStats.getUidStatsLocked(uid).noteStartWakeLocked(name, type);
+ }
+ }
+
+ public void noteStopWakelock(int uid, String name, int type) {
+ enforceCallingPermission();
+ synchronized (mStats) {
+ mStats.getUidStatsLocked(uid).noteStopWakeLocked(name, type);
+ }
+ }
+
+ public void noteStartSensor(int uid, int sensor) {
+ enforceCallingPermission();
+ synchronized (mStats) {
+ mStats.getUidStatsLocked(uid).noteStartSensor(sensor);
+ }
+ }
+
+ public void noteStopSensor(int uid, int sensor) {
+ enforceCallingPermission();
+ synchronized (mStats) {
+ mStats.getUidStatsLocked(uid).noteStopSensor(sensor);
+ }
+ }
+
+ public boolean isOnBattery() {
+ return mStats.isOnBattery();
+ }
+
+ public void setOnBattery(boolean onBattery) {
+ enforceCallingPermission();
+ mStats.setOnBattery(onBattery);
+ }
+
+ public long getAwakeTimeBattery() {
+ return mStats.getAwakeTimeBattery();
+ }
+
+ public long getAwakeTimePlugged() {
+ return mStats.getAwakeTimePlugged();
+ }
+
+ public void enforceCallingPermission() {
+ if (Binder.getCallingPid() == Process.myPid()) {
+ return;
+ }
+ mContext.enforcePermission(android.Manifest.permission.BATTERY_STATS,
+ Binder.getCallingPid(), Binder.getCallingUid(), null);
+ }
+
+ @Override
+ protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ synchronized (this) {
+ mStats.dumpLocked(fd, pw, args);
+ }
+ }
+}
diff --git a/services/java/com/android/server/am/ProcessRecord.java b/services/java/com/android/server/am/ProcessRecord.java
index bf95f46..a1320df 100644
--- a/services/java/com/android/server/am/ProcessRecord.java
+++ b/services/java/com/android/server/am/ProcessRecord.java
@@ -16,6 +16,7 @@
package com.android.server.am;
+import com.android.internal.os.BatteryStatsImpl;
import com.android.server.Watchdog;
import android.app.ActivityManager;
@@ -38,10 +39,11 @@ import java.util.HashSet;
* is currently running.
*/
class ProcessRecord implements Watchdog.PssRequestor {
- final BatteryStats.Uid.Proc batteryStats; // where to collect runtime statistics
+ final BatteryStatsImpl.Uid.Proc batteryStats; // where to collect runtime statistics
final ApplicationInfo info; // all about the first app in the process
final String processName; // name of the process
- String uniquePackage; // Name of package if only one in the process
+ // List of packages running in the process
+ final HashSet<String> pkgList = new HashSet();
IApplicationThread thread; // the actual proc... may be null only if
// 'persistent' is true (in which case we
// are in the process of launching the app)
@@ -107,7 +109,7 @@ class ProcessRecord implements Watchdog.PssRequestor {
pw.println(prefix+"manageSpaceActivityName="+info.manageSpaceActivityName);
pw.println(prefix + "dir=" + info.sourceDir + " publicDir=" + info.publicSourceDir
+ " data=" + info.dataDir);
- pw.println(prefix + "uniquePackage=" + uniquePackage);
+ pw.println(prefix + "packageList=" + pkgList);
pw.println(prefix + "instrumentationClass=" + instrumentationClass
+ " instrumentationProfileFile=" + instrumentationProfileFile);
pw.println(prefix + "instrumentationArguments=" + instrumentationArguments);
@@ -136,12 +138,12 @@ class ProcessRecord implements Watchdog.PssRequestor {
pw.println(prefix + "receivers=" + receivers);
}
- ProcessRecord(BatteryStats.Uid.Proc _batteryStats, IApplicationThread _thread,
+ ProcessRecord(BatteryStatsImpl.Uid.Proc _batteryStats, IApplicationThread _thread,
ApplicationInfo _info, String _processName) {
batteryStats = _batteryStats;
info = _info;
processName = _processName;
- uniquePackage = _info.packageName;
+ pkgList.add(_info.packageName);
thread = _thread;
maxAdj = ActivityManagerService.EMPTY_APP_ADJ;
hiddenAdj = ActivityManagerService.HIDDEN_APP_MIN_ADJ;
@@ -190,4 +192,33 @@ class ProcessRecord implements Watchdog.PssRequestor {
+ Integer.toHexString(System.identityHashCode(this))
+ " " + pid + ":" + processName + "/" + info.uid + "}";
}
+
+ /*
+ * Return true if package has been added false if not
+ */
+ public boolean addPackage(String pkg) {
+ if (!pkgList.contains(pkg)) {
+ pkgList.add(pkg);
+ return true;
+ }
+ return false;
+ }
+
+ /*
+ * Delete all packages from list except the package indicated in info
+ */
+ public void resetPackageList() {
+ pkgList.clear();
+ pkgList.add(info.packageName);
+ }
+
+ public String[] getPackageList() {
+ int size = pkgList.size();
+ if (size == 0) {
+ return null;
+ }
+ String list[] = new String[size];
+ pkgList.toArray(list);
+ return list;
+ }
}
diff --git a/services/java/com/android/server/am/ServiceRecord.java b/services/java/com/android/server/am/ServiceRecord.java
index 55644a6..4b90600 100644
--- a/services/java/com/android/server/am/ServiceRecord.java
+++ b/services/java/com/android/server/am/ServiceRecord.java
@@ -16,6 +16,8 @@
package com.android.server.am;
+import com.android.internal.os.BatteryStatsImpl;
+
import android.content.ComponentName;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
@@ -34,7 +36,7 @@ import java.util.List;
* A running application service.
*/
class ServiceRecord extends Binder {
- final BatteryStats.Uid.Pkg.Serv stats;
+ final BatteryStatsImpl.Uid.Pkg.Serv stats;
final ComponentName name; // service component.
final String shortName; // name.flattenToShortString().
final Intent.FilterComparison intent;
@@ -114,7 +116,7 @@ class ServiceRecord extends Binder {
}
}
- ServiceRecord(BatteryStats.Uid.Pkg.Serv servStats, ComponentName name,
+ ServiceRecord(BatteryStatsImpl.Uid.Pkg.Serv servStats, ComponentName name,
Intent.FilterComparison intent, ServiceInfo sInfo, Runnable restarter) {
this.stats = servStats;
this.name = name;
diff --git a/services/java/com/android/server/status/DateView.java b/services/java/com/android/server/status/DateView.java
index 35a0bae..7c44d67 100644
--- a/services/java/com/android/server/status/DateView.java
+++ b/services/java/com/android/server/status/DateView.java
@@ -4,7 +4,7 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
-import android.pim.DateFormat;
+import android.text.format.DateFormat;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.TextView;
diff --git a/services/java/com/android/server/status/StatusBarIcon.java b/services/java/com/android/server/status/StatusBarIcon.java
index 6c66f9d..6d09919 100644
--- a/services/java/com/android/server/status/StatusBarIcon.java
+++ b/services/java/com/android/server/status/StatusBarIcon.java
@@ -152,9 +152,9 @@ class StatusBarIcon {
try {
return r.getDrawable(data.iconId);
} catch (RuntimeException e) {
- Log.e(StatusBarService.TAG, "Icon not found in "
+ Log.w(StatusBarService.TAG, "Icon not found in "
+ (data.iconPackage != null ? data.iconId : "<system>")
- + ": " + Integer.toHexString(data.iconId), e);
+ + ": " + Integer.toHexString(data.iconId));
}
return null;
diff --git a/services/java/com/android/server/status/StatusBarPolicy.java b/services/java/com/android/server/status/StatusBarPolicy.java
index ad027db..00ff7be 100644
--- a/services/java/com/android/server/status/StatusBarPolicy.java
+++ b/services/java/com/android/server/status/StatusBarPolicy.java
@@ -22,6 +22,7 @@ import com.android.internal.telephony.SimCard;
import com.android.internal.telephony.TelephonyIntents;
import android.app.AlertDialog;
+import android.bluetooth.BluetoothA2dp;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHeadset;
import android.bluetooth.BluetoothIntent;
@@ -39,11 +40,11 @@ import android.net.wifi.WifiManager;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
-import android.pim.DateFormat;
import android.provider.Settings;
import android.telephony.PhoneStateListener;
import android.telephony.ServiceState;
import android.telephony.TelephonyManager;
+import android.text.format.DateFormat;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
@@ -154,6 +155,8 @@ public class StatusBarPolicy {
// bluetooth device status
private IBinder mBluetoothIcon;
private IconData mBluetoothData;
+ private int mBluetoothHeadsetState;
+ private int mBluetoothA2dpState;
// wifi
private static final int[] sWifiSignalImages = new int[] {
@@ -196,6 +199,9 @@ public class StatusBarPolicy {
else if (action.equals(Intent.ACTION_TIME_CHANGED)) {
updateClock();
}
+ else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED)) {
+ updateClock();
+ }
else if (action.equals(Intent.ACTION_TIMEZONE_CHANGED)) {
String tz = intent.getStringExtra("time-zone");
mCalendar = Calendar.getInstance(TimeZone.getTimeZone(tz));
@@ -212,7 +218,8 @@ public class StatusBarPolicy {
}
else if (action.equals(BluetoothIntent.ENABLED_ACTION) ||
action.equals(BluetoothIntent.DISABLED_ACTION) ||
- action.equals(BluetoothIntent.HEADSET_STATE_CHANGED_ACTION) ) {
+ action.equals(BluetoothIntent.HEADSET_STATE_CHANGED_ACTION) ||
+ action.equals(BluetoothA2dp.SINK_STATE_CHANGED_ACTION)) {
updateBluetooth(intent);
}
else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION) ||
@@ -315,6 +322,7 @@ public class StatusBarPolicy {
// Register for Intent broadcasts for...
filter.addAction(Intent.ACTION_TIME_TICK);
filter.addAction(Intent.ACTION_TIME_CHANGED);
+ filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
filter.addAction(Intent.ACTION_BATTERY_CHANGED);
filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
filter.addAction(Intent.ACTION_ALARM_CHANGED);
@@ -324,7 +332,9 @@ public class StatusBarPolicy {
filter.addAction(BluetoothIntent.ENABLED_ACTION);
filter.addAction(BluetoothIntent.DISABLED_ACTION);
filter.addAction(BluetoothIntent.HEADSET_STATE_CHANGED_ACTION);
+ filter.addAction(BluetoothA2dp.SINK_STATE_CHANGED_ACTION);
filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
+ filter.addAction(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION);
filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
filter.addAction(WifiManager.RSSI_CHANGED_ACTION);
filter.addAction(GpsLocationProvider.GPS_ENABLED_CHANGE_ACTION);
@@ -652,7 +662,11 @@ public class StatusBarPolicy {
return;
}
- if (-1 == asu) asu = 0;
+ // ASU ranges from 0 to 31 - TS 27.007 Sec 8.5
+ // asu = 0 (-113dB or less) is very weak
+ // signal, its better to show 0 bars to the user in such cases.
+ // asu = 99 is a special case, where the signal strength is unknown.
+ if (asu <= 0 || asu == 99) asu = 0;
else if (asu >= 16) asu = 4;
else if (asu >= 8) asu = 3;
else if (asu >= 4) asu = 2;
@@ -753,10 +767,13 @@ public class StatusBarPolicy {
}
private final void updateBluetooth(Intent intent) {
- boolean visible;
+ boolean visible = false;
if (intent == null) { // Initialize
- visible = ((BluetoothDevice)
- mContext.getSystemService(Context.BLUETOOTH_SERVICE)).isEnabled();
+ BluetoothDevice bluetooth =
+ (BluetoothDevice) mContext.getSystemService(Context.BLUETOOTH_SERVICE);
+ if (bluetooth != null) {
+ visible = bluetooth.isEnabled();
+ }
mService.setIconVisibility(mBluetoothIcon, visible);
return;
}
@@ -770,14 +787,21 @@ public class StatusBarPolicy {
visible = true;
} else if (action.equals(BluetoothIntent.HEADSET_STATE_CHANGED_ACTION)) {
visible = true;
- int state = intent.getIntExtra(BluetoothIntent.HEADSET_STATE,
- BluetoothHeadset.STATE_ERROR);
- if (state == BluetoothHeadset.STATE_CONNECTED) {
- iconId = com.android.internal.R.drawable.stat_sys_data_bluetooth_connected;
- }
+ mBluetoothHeadsetState = intent.getIntExtra(BluetoothIntent.HEADSET_STATE,
+ BluetoothHeadset.STATE_ERROR);
+ } else if (action.equals(BluetoothA2dp.SINK_STATE_CHANGED_ACTION)) {
+ visible = true;
+ mBluetoothA2dpState = intent.getIntExtra(BluetoothA2dp.SINK_STATE,
+ BluetoothA2dp.STATE_DISCONNECTED);
} else {
return;
}
+
+ if (mBluetoothHeadsetState == BluetoothHeadset.STATE_CONNECTED ||
+ mBluetoothA2dpState == BluetoothA2dp.STATE_CONNECTED ||
+ mBluetoothA2dpState == BluetoothA2dp.STATE_PLAYING) {
+ iconId = com.android.internal.R.drawable.stat_sys_data_bluetooth_connected;
+ }
mBluetoothData.iconId = iconId;
mService.updateIcon(mBluetoothIcon, mBluetoothData, null);
@@ -796,8 +820,14 @@ public class StatusBarPolicy {
mService.setIconVisibility(mWifiIcon, false);
}
+ } else if (action.equals(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION)) {
+ final boolean enabled = intent.getBooleanExtra(WifiManager.EXTRA_SUPPLICANT_CONNECTED,
+ false);
+ if (!enabled) {
+ mService.setIconVisibility(mWifiIcon, false);
+ }
} else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
-
+
final NetworkInfo networkInfo = (NetworkInfo)
intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
diff --git a/services/java/com/android/server/status/StatusBarService.java b/services/java/com/android/server/status/StatusBarService.java
index 38b2e77..31f55c8 100644
--- a/services/java/com/android/server/status/StatusBarService.java
+++ b/services/java/com/android/server/status/StatusBarService.java
@@ -147,10 +147,11 @@ public class StatusBarService extends IStatusBar.Stub
final Context mContext;
final Display mDisplay;
StatusBarView mStatusBarView;
+ int mPixelFormat;
H mHandler = new H();
ArrayList<PendingOp> mQueue = new ArrayList<PendingOp>();
NotificationCallbacks mNotificationCallbacks;
-
+
// All accesses to mIconMap and mNotificationData are syncronized on those objects,
// but this is only so dump() can work correctly. Modifying these outside of the UI
// thread will not work, there are places in the code that unlock and reaquire between
@@ -181,7 +182,7 @@ public class StatusBarService extends IStatusBar.Stub
View mNoNotificationsTitle;
TextView mSpnLabel;
TextView mPlmnLabel;
- View mClearButton;
+ TextView mClearButton;
CloseDragHandle mCloseView;
int[] mCloseLocation = new int[2];
boolean mExpanded;
@@ -252,10 +253,10 @@ public class StatusBarService extends IStatusBar.Stub
sb.mService = this;
// figure out which pixel-format to use for the status bar.
- int pixelFormat = PixelFormat.TRANSLUCENT;
+ mPixelFormat = PixelFormat.TRANSLUCENT;
Drawable bg = sb.getBackground();
if (bg != null) {
- pixelFormat = bg.getOpacity();
+ mPixelFormat = bg.getOpacity();
}
mStatusBarView = sb;
@@ -273,7 +274,7 @@ public class StatusBarService extends IStatusBar.Stub
mLatestTitle = expanded.findViewById(R.id.latestTitle);
mLatestItems = (LinearLayout)expanded.findViewById(R.id.latestItems);
mNoNotificationsTitle = expanded.findViewById(R.id.noNotificationsTitle);
- mClearButton = expanded.findViewById(R.id.clear_all_button);
+ mClearButton = (TextView)expanded.findViewById(R.id.clear_all_button);
mClearButton.setOnClickListener(mClearButtonListener);
mSpnLabel = (TextView)expanded.findViewById(R.id.spnLabel);
mPlmnLabel = (TextView)expanded.findViewById(R.id.plmnLabel);
@@ -294,18 +295,6 @@ public class StatusBarService extends IStatusBar.Stub
mCloseView = (CloseDragHandle)mTrackingView.findViewById(R.id.close);
mCloseView.mService = this;
- WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
- ViewGroup.LayoutParams.FILL_PARENT,
- 25,
- WindowManager.LayoutParams.TYPE_STATUS_BAR,
- WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE|
- WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING,
- pixelFormat);
- lp.gravity = Gravity.TOP | Gravity.FILL_HORIZONTAL;
- lp.setTitle("StatusBar");
-
- WindowManagerImpl.getDefault().addView(sb, lp);
-
// add the more icon for the notifications
IconData moreData = IconData.makeIcon(null, context.getPackageName(),
R.drawable.stat_notify_more, 0, 42);
@@ -326,11 +315,26 @@ public class StatusBarService extends IStatusBar.Stub
// receive broadcasts
IntentFilter filter = new IntentFilter();
+ filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
filter.addAction(Telephony.Intents.SPN_STRINGS_UPDATED_ACTION);
context.registerReceiver(mBroadcastReceiver, filter);
}
+ public void systemReady() {
+ WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
+ ViewGroup.LayoutParams.FILL_PARENT,
+ 25,
+ WindowManager.LayoutParams.TYPE_STATUS_BAR,
+ WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE|
+ WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING,
+ mPixelFormat);
+ lp.gravity = Gravity.TOP | Gravity.FILL_HORIZONTAL;
+ lp.setTitle("StatusBar");
+
+ WindowManagerImpl.getDefault().addView(mStatusBarView, lp);
+ }
+
// ================================================================================
// From IStatusBar
// ================================================================================
@@ -665,7 +669,12 @@ public class StatusBarService extends IStatusBar.Stub
notification.data = n;
updateNotificationView(notification, oldData);
}
- if (n.tickerText != null
+ // Show the ticker if one is requested, and the text is different
+ // than the currently displayed ticker. Also don't do this
+ // until status bar window is attached to the window manager,
+ // because... well, what's the point otherwise? And trying to
+ // run a ticker without being attached will crash!
+ if (n.tickerText != null && mStatusBarView.getWindowToken() != null
&& (oldData == null
|| oldData.tickerText == null
|| !CharSequences.equals(oldData.tickerText, n.tickerText))) {
@@ -788,6 +797,14 @@ public class StatusBarService extends IStatusBar.Stub
}
}
+ View.OnFocusChangeListener mFocusChangeListener = new View.OnFocusChangeListener() {
+ public void onFocusChange(View v, boolean hasFocus) {
+ // Because 'v' is a ViewGroup, all its children will be (un)selected
+ // too, which allows marqueeing to work.
+ v.setSelected(hasFocus);
+ }
+ };
+
View makeNotificationView(StatusBarNotification notification, ViewGroup parent) {
NotificationData n = notification.data;
RemoteViews remoteViews = n.contentView;
@@ -803,6 +820,7 @@ public class StatusBarService extends IStatusBar.Stub
// bind the click event to the content area
ViewGroup content = (ViewGroup)row.findViewById(com.android.internal.R.id.content);
content.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
+ content.setOnFocusChangeListener(mFocusChangeListener);
PendingIntent contentIntent = n.contentIntent;
if (contentIntent != null) {
content.setOnClickListener(new Launcher(contentIntent, n.pkg, n.id));
@@ -862,18 +880,19 @@ public class StatusBarService extends IStatusBar.Stub
mNotificationData.update(notification);
try {
n.contentView.reapply(mContext, notification.contentView);
+
+ // update the contentIntent
+ ViewGroup content = (ViewGroup)notification.view.findViewById(
+ com.android.internal.R.id.content);
+ PendingIntent contentIntent = n.contentIntent;
+ if (contentIntent != null) {
+ content.setOnClickListener(new Launcher(contentIntent, n.pkg, n.id));
+ }
}
catch (RuntimeException e) {
- Log.e(TAG, "couldn't reapply views for package "
- + n.contentView.getPackage(), e);
- }
-
- // update the contentIntent
- ViewGroup content = (ViewGroup)notification.view.findViewById(
- com.android.internal.R.id.content);
- PendingIntent contentIntent = n.contentIntent;
- if (contentIntent != null) {
- content.setOnClickListener(new Launcher(contentIntent, n.pkg, n.id));
+ // It failed to add cleanly. Log, and remove the view from the panel.
+ Log.w(TAG, "couldn't reapply views for package " + n.contentView.getPackage(), e);
+ removeNotificationView(notification);
}
} else {
mNotificationData.update(notification);
@@ -1426,7 +1445,8 @@ public class StatusBarService extends IStatusBar.Stub
ViewGroup.LayoutParams.FILL_PARENT,
WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL,
WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
- | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS,
+ | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
+ | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
pixelFormat);
// lp.token = mStatusBarView.getWindowToken();
lp.gravity = Gravity.TOP | Gravity.FILL_HORIZONTAL;
@@ -1629,6 +1649,9 @@ public class StatusBarService extends IStatusBar.Stub
intent.getBooleanExtra(Telephony.Intents.EXTRA_SHOW_PLMN, false),
intent.getStringExtra(Telephony.Intents.EXTRA_PLMN));
}
+ else if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) {
+ updateResources();
+ }
}
};
@@ -1659,6 +1682,18 @@ public class StatusBarService extends IStatusBar.Stub
}
}
+ /**
+ * Reload some of our resources when the configuration changes.
+ *
+ * We don't reload everything when the configuration changes -- we probably
+ * should, but getting that smooth is tough. Someday we'll fix that. In the
+ * meantime, just update the things that we know change.
+ */
+ void updateResources() {
+ mClearButton.setText(mContext.getText(R.string.status_bar_clear_all_button));
+ Log.d(TAG, "updateResources");
+ }
+
//
// tracing
//