summaryrefslogtreecommitdiffstats
path: root/services/java
diff options
context:
space:
mode:
Diffstat (limited to 'services/java')
-rw-r--r--services/java/com/android/server/AppWidgetService.java8
-rw-r--r--services/java/com/android/server/BackupManagerService.java8
-rw-r--r--services/java/com/android/server/BatteryService.java25
-rwxr-xr-xservices/java/com/android/server/HardwareService.java247
-rw-r--r--services/java/com/android/server/InputDevice.java120
-rw-r--r--services/java/com/android/server/KeyInputQueue.java283
-rw-r--r--services/java/com/android/server/MasterClearReceiver.java4
-rw-r--r--services/java/com/android/server/PackageManagerService.java3
-rw-r--r--services/java/com/android/server/SystemServer.java28
-rw-r--r--services/java/com/android/server/WifiService.java295
-rw-r--r--services/java/com/android/server/WindowManagerService.java67
-rw-r--r--services/java/com/android/server/am/ActivityManagerService.java70
-rw-r--r--services/java/com/android/server/status/StatusBarPolicy.java104
13 files changed, 755 insertions, 507 deletions
diff --git a/services/java/com/android/server/AppWidgetService.java b/services/java/com/android/server/AppWidgetService.java
index 131e156..78db6f9 100644
--- a/services/java/com/android/server/AppWidgetService.java
+++ b/services/java/com/android/server/AppWidgetService.java
@@ -68,6 +68,7 @@ class AppWidgetService extends IAppWidgetService.Stub
private static final String SETTINGS_FILENAME = "appwidgets.xml";
private static final String SETTINGS_TMP_FILENAME = SETTINGS_FILENAME + ".tmp";
+ private static final int MIN_UPDATE_PERIOD = 30 * 60 * 1000; // 30 minutes
/*
* When identifying a Host or Provider based on the calling process, use the uid field.
@@ -629,9 +630,12 @@ class AppWidgetService extends IAppWidgetService.Stub
Binder.restoreCallingIdentity(token);
}
if (!alreadyRegistered) {
+ long period = p.info.updatePeriodMillis;
+ if (period < MIN_UPDATE_PERIOD) {
+ period = MIN_UPDATE_PERIOD;
+ }
mAlarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
- SystemClock.elapsedRealtime() + p.info.updatePeriodMillis,
- p.info.updatePeriodMillis, p.broadcast);
+ SystemClock.elapsedRealtime() + period, period, p.broadcast);
}
}
}
diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java
index 6e28515..20f0750 100644
--- a/services/java/com/android/server/BackupManagerService.java
+++ b/services/java/com/android/server/BackupManagerService.java
@@ -1490,7 +1490,9 @@ class BackupManagerService extends IBackupManager.Stub {
try {
synchronized(this) {
- if (mRestoreSets == null) {
+ if (mRestoreTransport == null) {
+ Log.w(TAG, "Null transport getting restore sets");
+ } else if (mRestoreSets == null) { // valid transport; do the one-time fetch
mRestoreSets = mRestoreTransport.getAvailableRestoreSets();
}
return mRestoreSets;
@@ -1546,8 +1548,6 @@ class BackupManagerService extends IBackupManager.Stub {
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
synchronized (mQueueLock) {
- long oldId = Binder.clearCallingIdentity();
-
pw.println("Backup Manager is " + (mEnabled ? "enabled" : "disabled")
+ " / " + (!mProvisioned ? "not " : "") + "provisioned");
pw.println("Available transports:");
@@ -1570,8 +1570,6 @@ class BackupManagerService extends IBackupManager.Stub {
for (BackupRequest req : mPendingBackups.values()) {
pw.println(" " + req);
}
-
- Binder.restoreCallingIdentity(oldId);
}
}
}
diff --git a/services/java/com/android/server/BatteryService.java b/services/java/com/android/server/BatteryService.java
index 90d8c9d..5cdce5b 100644
--- a/services/java/com/android/server/BatteryService.java
+++ b/services/java/com/android/server/BatteryService.java
@@ -92,6 +92,9 @@ class BatteryService extends Binder {
// This should probably be exposed in the API, though it's not critical
private static final int BATTERY_PLUGGED_NONE = 0;
+ private static final int BATTERY_LEVEL_CLOSE_WARNING = 20;
+ private static final int BATTERY_LEVEL_WARNING = 15;
+
private final Context mContext;
private final IBatteryStats mBatteryStats;
@@ -120,6 +123,7 @@ class BatteryService extends Binder {
private long mDischargeStartTime;
private int mDischargeStartLevel;
+ private boolean mSentLowBatteryBroadcast = false;
public BatteryService(Context context) {
mContext = context;
@@ -260,6 +264,18 @@ class BatteryService extends Binder {
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
mContext.sendBroadcast(intent);
}
+
+ final boolean plugged = mPlugType != BATTERY_PLUGGED_NONE;
+ final boolean oldPlugged = mLastPlugType != BATTERY_PLUGGED_NONE;
+
+ /* The ACTION_BATTERY_LOW broadcast is sent in these situations:
+ * - is just un-plugged (previously was plugged) and battery level is under WARNING, or
+ * - is not plugged and battery level crosses the WARNING boundary (becomes < 15).
+ */
+ final boolean sendBatteryLow = !plugged
+ && mBatteryStatus != BatteryManager.BATTERY_STATUS_UNKNOWN
+ && mBatteryLevel < BATTERY_LEVEL_WARNING
+ && (oldPlugged || mLastBatteryLevel >= BATTERY_LEVEL_WARNING);
mLastBatteryStatus = mBatteryStatus;
mLastBatteryHealth = mBatteryHealth;
@@ -269,8 +285,15 @@ class BatteryService extends Binder {
mLastBatteryVoltage = mBatteryVoltage;
mLastBatteryTemperature = mBatteryTemperature;
mLastBatteryLevelCritical = mBatteryLevelCritical;
-
+
sendIntent();
+ if (sendBatteryLow) {
+ mSentLowBatteryBroadcast = true;
+ mContext.sendBroadcast(new Intent(Intent.ACTION_BATTERY_LOW));
+ } else if (mSentLowBatteryBroadcast && mLastBatteryLevel >= BATTERY_LEVEL_CLOSE_WARNING) {
+ mSentLowBatteryBroadcast = false;
+ mContext.sendBroadcast(new Intent(Intent.ACTION_BATTERY_OKAY));
+ }
// This needs to be done after sendIntent() so that we get the lastest battery stats.
if (logOutlier && dischargeDuration != 0) {
diff --git a/services/java/com/android/server/HardwareService.java b/services/java/com/android/server/HardwareService.java
index 5bc9b5f..7597f85 100755
--- a/services/java/com/android/server/HardwareService.java
+++ b/services/java/com/android/server/HardwareService.java
@@ -37,6 +37,9 @@ import android.os.Binder;
import android.os.SystemClock;
import android.util.Log;
+import java.util.LinkedList;
+import java.util.ListIterator;
+
public class HardwareService extends IHardwareService.Stub {
private static final String TAG = "HardwareService";
@@ -50,9 +53,62 @@ public class HardwareService extends IHardwareService.Stub {
static final int LIGHT_FLASH_NONE = 0;
static final int LIGHT_FLASH_TIMED = 1;
+ private final LinkedList<Vibration> mVibrations;
+ private Vibration mCurrentVibration;
+
private boolean mAttentionLightOn;
private boolean mPulsing;
+ private class Vibration implements IBinder.DeathRecipient {
+ private final IBinder mToken;
+ private final long mTimeout;
+ private final long mStartTime;
+ private final long[] mPattern;
+ private final int mRepeat;
+
+ Vibration(IBinder token, long millis) {
+ this(token, millis, null, 0);
+ }
+
+ Vibration(IBinder token, long[] pattern, int repeat) {
+ this(token, 0, pattern, repeat);
+ }
+
+ private Vibration(IBinder token, long millis, long[] pattern,
+ int repeat) {
+ mToken = token;
+ mTimeout = millis;
+ mStartTime = SystemClock.uptimeMillis();
+ mPattern = pattern;
+ mRepeat = repeat;
+ }
+
+ public void binderDied() {
+ synchronized (mVibrations) {
+ mVibrations.remove(this);
+ if (this == mCurrentVibration) {
+ doCancelVibrateLocked();
+ startNextVibrationLocked();
+ }
+ }
+ }
+
+ public boolean hasLongerTimeout(long millis) {
+ if (mTimeout == 0) {
+ // This is a pattern, return false to play the simple
+ // vibration.
+ return false;
+ }
+ if ((mStartTime + mTimeout)
+ < (SystemClock.uptimeMillis() + millis)) {
+ // If this vibration will end before the time passed in, let
+ // the new vibration play.
+ return false;
+ }
+ return true;
+ }
+ }
+
HardwareService(Context context) {
// Reset the hardware to a default state, in case this is a runtime
// restart instead of a fresh boot.
@@ -66,6 +122,8 @@ public class HardwareService extends IHardwareService.Stub {
mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
mWakeLock.setReferenceCounted(true);
+ mVibrations = new LinkedList<Vibration>();
+
mBatteryStats = BatteryStatsService.getService();
IntentFilter filter = new IntentFilter();
@@ -78,13 +136,24 @@ public class HardwareService extends IHardwareService.Stub {
super.finalize();
}
- public void vibrate(long milliseconds) {
+ public void vibrate(long milliseconds, IBinder token) {
if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.VIBRATE)
!= PackageManager.PERMISSION_GRANTED) {
throw new SecurityException("Requires VIBRATE permission");
}
- doCancelVibrate();
- vibratorOn(milliseconds);
+ if (mCurrentVibration != null
+ && mCurrentVibration.hasLongerTimeout(milliseconds)) {
+ // Ignore this vibration since the current vibration will play for
+ // longer than milliseconds.
+ return;
+ }
+ Vibration vib = new Vibration(token, milliseconds);
+ synchronized (mVibrations) {
+ removeVibrationLocked(token);
+ doCancelVibrateLocked();
+ mCurrentVibration = vib;
+ startVibrationLocked(vib);
+ }
}
private boolean isAll0(long[] pattern) {
@@ -121,34 +190,25 @@ public class HardwareService extends IHardwareService.Stub {
return;
}
- synchronized (this) {
- Death death = new Death(token);
- try {
- token.linkToDeath(death, 0);
- } catch (RemoteException e) {
- return;
- }
-
- Thread oldThread = mThread;
-
- if (oldThread != null) {
- // stop the old one
- synchronized (mThread) {
- mThread.mDone = true;
- mThread.notify();
- }
- }
+ Vibration vib = new Vibration(token, pattern, repeat);
+ try {
+ token.linkToDeath(vib, 0);
+ } catch (RemoteException e) {
+ return;
+ }
- if (mDeath != null) {
- mToken.unlinkToDeath(mDeath, 0);
+ synchronized (mVibrations) {
+ removeVibrationLocked(token);
+ doCancelVibrateLocked();
+ if (repeat >= 0) {
+ mVibrations.addFirst(vib);
+ startNextVibrationLocked();
+ } else {
+ // A negative repeat means that this pattern is not meant
+ // to repeat. Treat it like a simple vibration.
+ mCurrentVibration = vib;
+ startVibrationLocked(vib);
}
-
- mDeath = death;
- mToken = token;
-
- // start the new thread
- mThread = new VibrateThread(pattern, repeat);
- mThread.start();
}
}
finally {
@@ -156,7 +216,7 @@ public class HardwareService extends IHardwareService.Stub {
}
}
- public void cancelVibrate() {
+ public void cancelVibrate(IBinder token) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.VIBRATE,
"cancelVibrate");
@@ -164,7 +224,13 @@ public class HardwareService extends IHardwareService.Stub {
// so wakelock calls will succeed
long identity = Binder.clearCallingIdentity();
try {
- doCancelVibrate();
+ synchronized (mVibrations) {
+ final Vibration vib = removeVibrationLocked(token);
+ if (vib == mCurrentVibration) {
+ doCancelVibrateLocked();
+ startNextVibrationLocked();
+ }
+ }
}
finally {
Binder.restoreCallingIdentity(identity);
@@ -277,27 +343,74 @@ public class HardwareService extends IHardwareService.Stub {
}
};
- private void doCancelVibrate() {
- synchronized (this) {
- if (mThread != null) {
- synchronized (mThread) {
- mThread.mDone = true;
- mThread.notify();
- }
- mThread = null;
+ private final Runnable mVibrationRunnable = new Runnable() {
+ public void run() {
+ synchronized (mVibrations) {
+ doCancelVibrateLocked();
+ startNextVibrationLocked();
+ }
+ }
+ };
+
+ // Lock held on mVibrations
+ private void doCancelVibrateLocked() {
+ if (mThread != null) {
+ synchronized (mThread) {
+ mThread.mDone = true;
+ mThread.notify();
}
- vibratorOff();
+ mThread = null;
}
+ vibratorOff();
+ mH.removeCallbacks(mVibrationRunnable);
+ }
+
+ // Lock held on mVibrations
+ private void startNextVibrationLocked() {
+ if (mVibrations.size() <= 0) {
+ return;
+ }
+ mCurrentVibration = mVibrations.getFirst();
+ startVibrationLocked(mCurrentVibration);
+ }
+
+ // Lock held on mVibrations
+ private void startVibrationLocked(final Vibration vib) {
+ if (vib.mTimeout != 0) {
+ vibratorOn(vib.mTimeout);
+ mH.postDelayed(mVibrationRunnable, vib.mTimeout);
+ } else {
+ // mThread better be null here. doCancelVibrate should always be
+ // called before startNextVibrationLocked or startVibrationLocked.
+ mThread = new VibrateThread(vib);
+ mThread.start();
+ }
+ }
+
+ // Lock held on mVibrations
+ private Vibration removeVibrationLocked(IBinder token) {
+ ListIterator<Vibration> iter = mVibrations.listIterator(0);
+ while (iter.hasNext()) {
+ Vibration vib = iter.next();
+ if (vib.mToken == token) {
+ iter.remove();
+ return vib;
+ }
+ }
+ // We might be looking for a simple vibration which is only stored in
+ // mCurrentVibration.
+ if (mCurrentVibration != null && mCurrentVibration.mToken == token) {
+ return mCurrentVibration;
+ }
+ return null;
}
private class VibrateThread extends Thread {
- long[] mPattern;
- int mRepeat;
+ final Vibration mVibration;
boolean mDone;
- VibrateThread(long[] pattern, int repeat) {
- mPattern = pattern;
- mRepeat = repeat;
+ VibrateThread(Vibration vib) {
+ mVibration = vib;
mWakeLock.acquire();
}
@@ -323,8 +436,9 @@ public class HardwareService extends IHardwareService.Stub {
Process.setThreadPriority(Process.THREAD_PRIORITY_URGENT_DISPLAY);
synchronized (this) {
int index = 0;
- long[] pattern = mPattern;
+ long[] pattern = mVibration.mPattern;
int len = pattern.length;
+ int repeat = mVibration.mRepeat;
long duration = 0;
while (!mDone) {
@@ -347,50 +461,37 @@ public class HardwareService extends IHardwareService.Stub {
HardwareService.this.vibratorOn(duration);
}
} else {
- if (mRepeat < 0) {
+ if (repeat < 0) {
break;
} else {
- index = mRepeat;
+ index = repeat;
duration = 0;
}
}
}
- if (mDone) {
- // make sure vibrator is off if we were cancelled.
- // otherwise, it will turn off automatically
- // when the last timeout expires.
- HardwareService.this.vibratorOff();
- }
mWakeLock.release();
}
- synchronized (HardwareService.this) {
+ synchronized (mVibrations) {
if (mThread == this) {
mThread = null;
}
- }
- }
- };
-
- private class Death implements IBinder.DeathRecipient {
- IBinder mMe;
-
- Death(IBinder me) {
- mMe = me;
- }
-
- public void binderDied() {
- synchronized (HardwareService.this) {
- if (mMe == mToken) {
- doCancelVibrate();
+ if (!mDone) {
+ // If this vibration finished naturally, start the next
+ // vibration.
+ mVibrations.remove(mVibration);
+ startNextVibrationLocked();
}
}
}
- }
+ };
BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
- doCancelVibrate();
+ synchronized (mVibrations) {
+ doCancelVibrateLocked();
+ mVibrations.clear();
+ }
}
}
};
@@ -407,8 +508,6 @@ public class HardwareService extends IHardwareService.Stub {
private final IBatteryStats mBatteryStats;
volatile VibrateThread mThread;
- volatile Death mDeath;
- volatile IBinder mToken;
private int mNativePointer;
diff --git a/services/java/com/android/server/InputDevice.java b/services/java/com/android/server/InputDevice.java
index 7b8a2a4..a71c39a 100644
--- a/services/java/com/android/server/InputDevice.java
+++ b/services/java/com/android/server/InputDevice.java
@@ -63,22 +63,59 @@ public class InputDevice {
yMoveScale = my != 0 ? (1.0f/my) : 1.0f;
}
- MotionEvent generateMotion(InputDevice device, long curTime,
+ MotionEvent generateMotion(InputDevice device, long curTime, long curTimeNano,
boolean isAbs, Display display, int orientation,
int metaState) {
- if (!changed) {
- return null;
- }
-
float scaledX = x;
float scaledY = y;
float temp;
float scaledPressure = 1.0f;
float scaledSize = 0;
int edgeFlags = 0;
+
+ int action;
+ if (down != lastDown) {
+ if (isAbs) {
+ final AbsoluteInfo absX = device.absX;
+ final AbsoluteInfo absY = device.absY;
+ if (down && absX != null && absY != null) {
+ // We don't let downs start unless we are
+ // inside of the screen. There are two reasons for
+ // this: to avoid spurious touches when holding
+ // the edges of the device near the touchscreen,
+ // and to avoid reporting events if there are virtual
+ // keys on the touchscreen outside of the display
+ // area.
+ if (scaledX < absX.minValue || scaledX > absX.maxValue
+ || scaledY < absY.minValue || scaledY > absY.maxValue) {
+ if (false) Log.v("InputDevice", "Rejecting (" + scaledX + ","
+ + scaledY + "): outside of ("
+ + absX.minValue + "," + absY.minValue
+ + ")-(" + absX.maxValue + ","
+ + absY.maxValue + ")");
+ return null;
+ }
+ }
+ } else {
+ x = y = 0;
+ }
+ lastDown = down;
+ if (down) {
+ action = MotionEvent.ACTION_DOWN;
+ downTime = curTime;
+ } else {
+ action = MotionEvent.ACTION_UP;
+ }
+ currentMove = null;
+ } else {
+ action = MotionEvent.ACTION_MOVE;
+ }
+
if (isAbs) {
- int w = display.getWidth()-1;
- int h = display.getHeight()-1;
+ final int dispW = display.getWidth()-1;
+ final int dispH = display.getHeight()-1;
+ int w = dispW;
+ int h = dispH;
if (orientation == Surface.ROTATION_90
|| orientation == Surface.ROTATION_270) {
int tmp = w;
@@ -120,16 +157,17 @@ public class InputDevice {
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;
+ if (action != MotionEvent.ACTION_DOWN) {
+ if (scaledX <= 0) {
+ edgeFlags += MotionEvent.EDGE_LEFT;
+ } else if (scaledX >= dispW) {
+ edgeFlags += MotionEvent.EDGE_RIGHT;
+ }
+ if (scaledY <= 0) {
+ edgeFlags += MotionEvent.EDGE_TOP;
+ } else if (scaledY >= dispH) {
+ edgeFlags += MotionEvent.EDGE_BOTTOM;
+ }
}
} else {
@@ -153,41 +191,25 @@ public class InputDevice {
}
}
- changed = false;
- if (down != lastDown) {
- int action;
- lastDown = down;
- if (down) {
- action = MotionEvent.ACTION_DOWN;
- downTime = curTime;
- } else {
- action = MotionEvent.ACTION_UP;
- }
- currentMove = null;
- if (!isAbs) {
- x = y = 0;
- }
- return MotionEvent.obtain(downTime, curTime, action,
- scaledX, scaledY, scaledPressure, scaledSize, metaState,
- 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) {
- Log.i("KeyInputQueue", "Updating: " + currentMove);
- }
- return null;
+ 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) {
+ Log.i("KeyInputQueue", "Updating: " + currentMove);
}
- MotionEvent me = MotionEvent.obtain(downTime, curTime,
- MotionEvent.ACTION_MOVE, scaledX, scaledY,
- scaledPressure, scaledSize, metaState,
- xPrecision, yPrecision, device.id, edgeFlags);
+ return null;
+ }
+
+ MotionEvent me = MotionEvent.obtainNano(downTime, curTime,
+ curTimeNano, action, scaledX, scaledY,
+ scaledPressure, scaledSize, metaState,
+ xPrecision, yPrecision, device.id, edgeFlags);
+ if (action == MotionEvent.ACTION_MOVE) {
currentMove = me;
- return me;
}
+ return me;
}
}
diff --git a/services/java/com/android/server/KeyInputQueue.java b/services/java/com/android/server/KeyInputQueue.java
index 411cd6b..fd6b813 100644
--- a/services/java/com/android/server/KeyInputQueue.java
+++ b/services/java/com/android/server/KeyInputQueue.java
@@ -18,8 +18,9 @@ package com.android.server;
import android.content.Context;
import android.content.res.Configuration;
-import android.os.SystemClock;
+import android.os.LatencyTimer;
import android.os.PowerManager;
+import android.os.SystemClock;
import android.util.Log;
import android.util.SparseArray;
import android.view.Display;
@@ -29,10 +30,20 @@ import android.view.RawInputEvent;
import android.view.Surface;
import android.view.WindowManagerPolicy;
+import java.io.BufferedReader;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+
public abstract class KeyInputQueue {
static final String TAG = "KeyInputQueue";
- SparseArray<InputDevice> mDevices = new SparseArray<InputDevice>();
+ static final boolean DEBUG_VIRTUAL_KEYS = false;
+
+ final SparseArray<InputDevice> mDevices = new SparseArray<InputDevice>();
+ final ArrayList<VirtualKey> mVirtualKeys = new ArrayList<VirtualKey>();
int mGlobalMetaState = 0;
boolean mHaveGlobalMetaState = false;
@@ -43,10 +54,14 @@ public abstract class KeyInputQueue {
int mCacheCount;
Display mDisplay = null;
+ int mDisplayWidth;
+ int mDisplayHeight;
int mOrientation = Surface.ROTATION_0;
int[] mKeyRotationMap = null;
+ VirtualKey mPressedVirtualKey = null;
+
PowerManager.WakeLock mWakeLock;
static final int[] KEY_90_MAP = new int[] {
@@ -73,14 +88,17 @@ public abstract class KeyInputQueue {
public static final int FILTER_REMOVE = 0;
public static final int FILTER_KEEP = 1;
public static final int FILTER_ABORT = -1;
-
+
+ private static final boolean MEASURE_LATENCY = false;
+ private LatencyTimer lt;
+
public interface FilterCallback {
int filterEvent(QueuedEvent ev);
}
static class QueuedEvent {
InputDevice inputDevice;
- long when;
+ long whenNano;
int flags; // From the raw event
int classType; // One of the class constants in InputEvent
Object event;
@@ -88,7 +106,7 @@ public abstract class KeyInputQueue {
void copyFrom(QueuedEvent that) {
this.inputDevice = that.inputDevice;
- this.when = that.when;
+ this.whenNano = that.whenNano;
this.flags = that.flags;
this.classType = that.classType;
this.event = that.event;
@@ -106,7 +124,106 @@ public abstract class KeyInputQueue {
QueuedEvent next;
}
+ /**
+ * A key that exists as a part of the touch-screen, outside of the normal
+ * display area of the screen.
+ */
+ static class VirtualKey {
+ int scancode;
+ int centerx;
+ int centery;
+ int width;
+ int height;
+
+ int hitLeft;
+ int hitTop;
+ int hitRight;
+ int hitBottom;
+
+ InputDevice lastDevice;
+ int lastKeycode;
+
+ boolean checkHit(int x, int y) {
+ return (x >= hitLeft && x <= hitRight
+ && y >= hitTop && y <= hitBottom);
+ }
+
+ void computeHitRect(InputDevice dev, int dw, int dh) {
+ if (dev == lastDevice) {
+ return;
+ }
+
+ if (DEBUG_VIRTUAL_KEYS) Log.v(TAG, "computeHitRect for " + scancode
+ + ": dev=" + dev + " absX=" + dev.absX + " absY=" + dev.absY);
+
+ lastDevice = dev;
+
+ int minx = dev.absX.minValue;
+ int maxx = dev.absX.maxValue;
+
+ int halfw = width/2;
+ int left = centerx - halfw;
+ int right = centerx + halfw;
+ hitLeft = minx + ((left*maxx-minx)/dw);
+ hitRight = minx + ((right*maxx-minx)/dw);
+
+ int miny = dev.absY.minValue;
+ int maxy = dev.absY.maxValue;
+
+ int halfh = height/2;
+ int top = centery - halfh;
+ int bottom = centery + halfh;
+ hitTop = miny + ((top*maxy-miny)/dh);
+ hitBottom = miny + ((bottom*maxy-miny)/dh);
+ }
+ }
+
KeyInputQueue(Context context) {
+ if (MEASURE_LATENCY) {
+ lt = new LatencyTimer(100, 1000);
+ }
+
+ try {
+ FileInputStream fis = new FileInputStream(
+ "/sys/board_properties/virtualkeys.synaptics-rmi-touchscreen");
+ InputStreamReader isr = new InputStreamReader(fis);
+ BufferedReader br = new BufferedReader(isr);
+ String str = br.readLine();
+ if (str != null) {
+ String[] it = str.split(":");
+ if (DEBUG_VIRTUAL_KEYS) Log.v(TAG, "***** VIRTUAL KEYS: " + it);
+ final int N = it.length-6;
+ for (int i=0; i<=N; i+=6) {
+ if (!"0x01".equals(it[i])) {
+ Log.w(TAG, "Unknown virtual key type at elem #" + i
+ + ": " + it[i]);
+ continue;
+ }
+ try {
+ VirtualKey sb = new VirtualKey();
+ sb.scancode = Integer.parseInt(it[i+1]);
+ sb.centerx = Integer.parseInt(it[i+2]);
+ sb.centery = Integer.parseInt(it[i+3]);
+ sb.width = Integer.parseInt(it[i+4]);
+ sb.height = Integer.parseInt(it[i+5]);
+ if (DEBUG_VIRTUAL_KEYS) Log.v(TAG, "Virtual key "
+ + sb.scancode + ": center=" + sb.centerx + ","
+ + sb.centery + " size=" + sb.width + "x"
+ + sb.height);
+ mVirtualKeys.add(sb);
+ } catch (NumberFormatException e) {
+ Log.w(TAG, "Bad number at region " + i + " in: "
+ + str, e);
+ }
+ }
+ }
+ br.close();
+ } catch (FileNotFoundException e) {
+ Log.i(TAG, "No virtual keys found");
+ } catch (IOException e) {
+ Log.w(TAG, "Error reading virtual keys", e);
+ }
+
PowerManager pm = (PowerManager)context.getSystemService(
Context.POWER_SERVICE);
mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
@@ -123,6 +240,12 @@ public abstract class KeyInputQueue {
public void setDisplay(Display display) {
mDisplay = display;
+
+ // We assume at this point that the display dimensions reflect the
+ // natural, unrotated display. We will perform hit tests for soft
+ // buttons based on that display.
+ mDisplayWidth = display.getWidth();
+ mDisplayHeight = display.getHeight();
}
public void getInputConfiguration(Configuration config) {
@@ -165,6 +288,7 @@ public abstract class KeyInputQueue {
public static native int getScancodeState(int deviceId, int sw);
public static native int getKeycodeState(int sw);
public static native int getKeycodeState(int deviceId, int sw);
+ public static native int scancodeToKeycode(int deviceId, int scancode);
public static native boolean hasKeys(int[] keycodes, boolean[] keyExists);
public static KeyEvent newKeyEvent(InputDevice device, long downTime,
@@ -241,7 +365,7 @@ public abstract class KeyInputQueue {
if (configChanged) {
synchronized (mFirst) {
- addLocked(di, SystemClock.uptimeMillis(), 0,
+ addLocked(di, System.nanoTime(), 0,
RawInputEvent.CLASS_CONFIGURATION_CHANGED,
null);
}
@@ -256,6 +380,7 @@ public abstract class KeyInputQueue {
// timebase as SystemClock.uptimeMillis().
//curTime = gotOne ? ev.when : SystemClock.uptimeMillis();
final long curTime = SystemClock.uptimeMillis();
+ final long curTimeNano = System.nanoTime();
//Log.i(TAG, "curTime=" + curTime + ", systemClock=" + SystemClock.uptimeMillis());
final int classes = di.classes;
@@ -276,7 +401,7 @@ public abstract class KeyInputQueue {
down = false;
}
int keycode = rotateKeyCodeLocked(ev.keycode);
- addLocked(di, curTime, ev.flags,
+ addLocked(di, curTimeNano, ev.flags,
RawInputEvent.CLASS_KEYBOARD,
newKeyEvent(di, di.mDownTime, curTime, down,
keycode, 0, scancode,
@@ -330,36 +455,127 @@ public abstract class KeyInputQueue {
}
MotionEvent me;
- me = di.mAbs.generateMotion(di, curTime, true,
- mDisplay, mOrientation, mGlobalMetaState);
- if (false) Log.v(TAG, "Absolute: x=" + di.mAbs.x
- + " y=" + di.mAbs.y + " ev=" + me);
- if (me != null) {
- if (WindowManagerPolicy.WATCH_POINTER) {
- Log.i(TAG, "Enqueueing: " + me);
+
+ InputDevice.MotionState ms = di.mAbs;
+ if (ms.changed) {
+ ms.changed = false;
+
+ boolean doMotion = true;
+
+ // Look for virtual buttons.
+ VirtualKey vk = mPressedVirtualKey;
+ if (vk != null) {
+ doMotion = false;
+ if (!ms.down) {
+ mPressedVirtualKey = null;
+ ms.lastDown = ms.down;
+ if (DEBUG_VIRTUAL_KEYS) Log.v(TAG,
+ "Generate key up for: " + vk.scancode);
+ addLocked(di, curTimeNano, ev.flags,
+ RawInputEvent.CLASS_KEYBOARD,
+ newKeyEvent(di, di.mDownTime,
+ curTime, false,
+ vk.lastKeycode,
+ 0, vk.scancode, 0));
+ }
+ } else if (ms.down && !ms.lastDown) {
+ vk = findSoftButton(di);
+ if (vk != null) {
+ doMotion = false;
+ mPressedVirtualKey = vk;
+ vk.lastKeycode = scancodeToKeycode(
+ di.id, vk.scancode);
+ ms.lastDown = ms.down;
+ di.mDownTime = curTime;
+ if (DEBUG_VIRTUAL_KEYS) Log.v(TAG,
+ "Generate key down for: " + vk.scancode
+ + " (keycode=" + vk.lastKeycode + ")");
+ addLocked(di, curTimeNano, ev.flags,
+ RawInputEvent.CLASS_KEYBOARD,
+ newKeyEvent(di, di.mDownTime,
+ curTime, true,
+ vk.lastKeycode, 0,
+ vk.scancode, 0));
+ }
+ }
+
+ if (doMotion) {
+ me = ms.generateMotion(di, curTime,
+ curTimeNano, true, mDisplay,
+ mOrientation, mGlobalMetaState);
+ if (false) Log.v(TAG, "Absolute: x=" + di.mAbs.x
+ + " y=" + di.mAbs.y + " ev=" + me);
+ if (me != null) {
+ if (WindowManagerPolicy.WATCH_POINTER) {
+ Log.i(TAG, "Enqueueing: " + me);
+ }
+ addLocked(di, curTimeNano, ev.flags,
+ RawInputEvent.CLASS_TOUCHSCREEN, me);
+ }
}
- addLocked(di, curTime, ev.flags,
- RawInputEvent.CLASS_TOUCHSCREEN, me);
}
- me = di.mRel.generateMotion(di, curTime, false,
- mDisplay, mOrientation, mGlobalMetaState);
- if (false) Log.v(TAG, "Relative: x=" + di.mRel.x
- + " y=" + di.mRel.y + " ev=" + me);
- if (me != null) {
- addLocked(di, curTime, ev.flags,
- RawInputEvent.CLASS_TRACKBALL, me);
+
+ ms = di.mRel;
+ if (ms.changed) {
+ ms.changed = false;
+
+ me = ms.generateMotion(di, curTime,
+ curTimeNano, false, mDisplay,
+ mOrientation, mGlobalMetaState);
+ if (false) Log.v(TAG, "Relative: x=" + di.mRel.x
+ + " y=" + di.mRel.y + " ev=" + me);
+ if (me != null) {
+ addLocked(di, curTimeNano, ev.flags,
+ RawInputEvent.CLASS_TRACKBALL, me);
+ }
}
}
}
}
}
- }
- catch (RuntimeException exc) {
+
+ } catch (RuntimeException exc) {
Log.e(TAG, "InputReaderThread uncaught exception", exc);
}
}
};
+ private VirtualKey findSoftButton(InputDevice dev) {
+ final int N = mVirtualKeys.size();
+ if (N <= 0) {
+ return null;
+ }
+
+ final InputDevice.AbsoluteInfo absx = dev.absX;
+ final InputDevice.AbsoluteInfo absy = dev.absY;
+ final InputDevice.MotionState absm = dev.mAbs;
+ if (absx == null || absy == null || absm == null) {
+ return null;
+ }
+
+ if (absm.x >= absx.minValue && absm.x <= absx.maxValue
+ && absm.y >= absy.minValue && absm.y <= absy.maxValue) {
+ if (DEBUG_VIRTUAL_KEYS) Log.v(TAG, "Input (" + absm.x
+ + "," + absm.y + ") inside of display");
+ return null;
+ }
+
+ for (int i=0; i<N; i++) {
+ VirtualKey sb = mVirtualKeys.get(i);
+ sb.computeHitRect(dev, mDisplayWidth, mDisplayHeight);
+ if (DEBUG_VIRTUAL_KEYS) Log.v(TAG, "Hit test (" + absm.x + ","
+ + absm.y + ") in code " + sb.scancode + " - (" + sb.hitLeft
+ + "," + sb.hitTop + ")-(" + sb.hitRight + ","
+ + sb.hitBottom + ")");
+ if (sb.checkHit(absm.x, absm.y)) {
+ if (DEBUG_VIRTUAL_KEYS) Log.v(TAG, "Hit!");
+ return sb;
+ }
+ }
+
+ return null;
+ }
+
/**
* Returns a new meta state for the given keys and old state.
*/
@@ -530,7 +746,7 @@ public abstract class KeyInputQueue {
}
}
- private QueuedEvent obtainLocked(InputDevice device, long when,
+ private QueuedEvent obtainLocked(InputDevice device, long whenNano,
int flags, int classType, Object event) {
QueuedEvent ev;
if (mCacheCount == 0) {
@@ -542,7 +758,7 @@ public abstract class KeyInputQueue {
mCacheCount--;
}
ev.inputDevice = device;
- ev.when = when;
+ ev.whenNano = whenNano;
ev.flags = flags;
ev.classType = classType;
ev.event = event;
@@ -561,13 +777,13 @@ public abstract class KeyInputQueue {
}
}
- private void addLocked(InputDevice device, long when, int flags,
+ private void addLocked(InputDevice device, long whenNano, int flags,
int classType, Object event) {
boolean poke = mFirst.next == mLast;
- QueuedEvent ev = obtainLocked(device, when, flags, classType, event);
+ QueuedEvent ev = obtainLocked(device, whenNano, flags, classType, event);
QueuedEvent p = mLast.prev;
- while (p != mFirst && ev.when < p.when) {
+ while (p != mFirst && ev.whenNano < p.whenNano) {
p = p.prev;
}
@@ -578,8 +794,15 @@ public abstract class KeyInputQueue {
ev.inQueue = true;
if (poke) {
+ long time;
+ if (MEASURE_LATENCY) {
+ time = System.nanoTime();
+ }
mFirst.notify();
mWakeLock.acquire();
+ if (MEASURE_LATENCY) {
+ lt.sample("1 addLocked-queued event ", System.nanoTime() - time);
+ }
}
}
diff --git a/services/java/com/android/server/MasterClearReceiver.java b/services/java/com/android/server/MasterClearReceiver.java
index 5a42e76..3c366da 100644
--- a/services/java/com/android/server/MasterClearReceiver.java
+++ b/services/java/com/android/server/MasterClearReceiver.java
@@ -30,8 +30,8 @@ public class MasterClearReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
- if (intent.getAction().equals("android.intent.action.GTALK_DATA_MESSAGE_RECEIVED")) {
- if (!intent.getBooleanExtra("from_trusted_server", false)) {
+ if (intent.getAction().equals(Intent.ACTION_REMOTE_INTENT)) {
+ if (!intent.getBooleanExtra("android.intent.extra.from_trusted_server", false)) {
Log.w(TAG, "Ignoring master clear request -- not from trusted server.");
return;
}
diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java
index b85cf2c..682eaa7 100644
--- a/services/java/com/android/server/PackageManagerService.java
+++ b/services/java/com/android/server/PackageManagerService.java
@@ -1683,6 +1683,9 @@ class PackageManagerService extends IPackageManager.Stub {
}
}
+ /**
+ * @deprecated
+ */
public void querySyncProviders(List outNames, List outInfo) {
synchronized (mPackages) {
Iterator<Map.Entry<String, PackageParser.Provider>> i
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index b038a64..48d97ec 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -32,12 +32,7 @@ import android.content.pm.IPackageManager;
import android.database.ContentObserver;
import android.database.Cursor;
import android.media.AudioService;
-import android.os.IBinder;
-import android.os.Looper;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.os.SystemClock;
-import android.os.SystemProperties;
+import android.os.*;
import android.provider.Contacts.People;
import android.provider.Settings;
import android.server.BluetoothA2dpService;
@@ -45,6 +40,7 @@ import android.server.BluetoothDeviceService;
import android.server.search.SearchManagerService;
import android.util.EventLog;
import android.util.Log;
+import android.accounts.AccountManagerService;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
@@ -120,6 +116,14 @@ class ServerThread extends Thread {
mContentResolver = context.getContentResolver();
+ try {
+ Log.i(TAG, "Starting Account Manager.");
+ ServiceManager.addService(Context.ACCOUNT_SERVICE,
+ new AccountManagerService(context));
+ } catch (Throwable e) {
+ Log.e(TAG, "Failure starting Account Manager", e);
+ }
+
Log.i(TAG, "Starting Content Manager.");
ContentService.main(context,
factoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL);
@@ -172,7 +176,7 @@ class ServerThread extends Thread {
bluetooth = new BluetoothDeviceService(context);
bluetooth.init();
ServiceManager.addService(Context.BLUETOOTH_SERVICE, bluetooth);
- bluetoothA2dp = new BluetoothA2dpService(context);
+ bluetoothA2dp = new BluetoothA2dpService(context, bluetooth);
ServiceManager.addService(BluetoothA2dpService.BLUETOOTH_A2DP_SERVICE,
bluetoothA2dp);
@@ -419,19 +423,19 @@ public class SystemServer
public static final int FACTORY_TEST_OFF = 0;
public static final int FACTORY_TEST_LOW_LEVEL = 1;
public static final int FACTORY_TEST_HIGH_LEVEL = 2;
-
- /**
- * This method is called from Zygote to initialize the system. This will cause the native
+
+ /**
+ * This method is called from Zygote to initialize the system. This will cause the native
* services (SurfaceFlinger, AudioFlinger, etc..) to be started. After that it will call back
* up into init2() to start the Android services.
- */
+ */
native public static void init1(String[] args);
public static void main(String[] args) {
// The system server has to run all of the time, so it needs to be
// as efficient as possible with its memory usage.
VMRuntime.getRuntime().setTargetHeapUtilization(0.8f);
-
+
System.loadLibrary("android_servers");
init1(args);
}
diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java
index b4754b6..67e8cf3 100644
--- a/services/java/com/android/server/WifiService.java
+++ b/services/java/com/android/server/WifiService.java
@@ -41,6 +41,7 @@ import android.net.wifi.WifiConfiguration;
import android.net.wifi.SupplicantState;
import android.net.NetworkStateTracker;
import android.net.DhcpInfo;
+import android.net.NetworkUtils;
import android.os.Binder;
import android.os.Handler;
import android.os.HandlerThread;
@@ -142,28 +143,6 @@ public class WifiService extends IWifiManager.Stub {
private final WifiHandler mWifiHandler;
/*
- * Map used to keep track of hidden networks presence, which
- * is needed to switch between active and passive scan modes.
- * If there is at least one hidden network that is currently
- * present (enabled), we want to do active scans instead of
- * passive.
- */
- private final Map<Integer, Boolean> mIsHiddenNetworkPresent;
- /*
- * The number of currently present hidden networks. When this
- * counter goes from 0 to 1 or from 1 to 0, we change the
- * scan mode to active or passive respectively. Initially, we
- * set the counter to 0 and we increment it every time we add
- * a new present (enabled) hidden network.
- */
- private int mNumHiddenNetworkPresent;
- /*
- * Whether we change the scan mode is due to a hidden network
- * (in this class, this is always the case)
- */
- private final static boolean SET_DUE_TO_A_HIDDEN_NETWORK = true;
-
- /*
* Cache of scan results objects (size is somewhat arbitrary)
*/
private static final int SCAN_RESULT_CACHE_SIZE = 80;
@@ -195,12 +174,6 @@ public class WifiService extends IWifiManager.Stub {
mWifiStateTracker.enableRssiPolling(true);
mBatteryStats = BatteryStatsService.getService();
- /*
- * Initialize the hidden-networks state
- */
- mIsHiddenNetworkPresent = new HashMap<Integer, Boolean>();
- mNumHiddenNetworkPresent = 0;
-
mScanResultCache = new LinkedHashMap<String, ScanResult>(
SCAN_RESULT_CACHE_SIZE, 0.75f, true) {
/*
@@ -254,155 +227,6 @@ public class WifiService extends IWifiManager.Stub {
setWifiEnabledBlocking(wifiEnabled, false, Process.myUid());
}
- /**
- * Initializes the hidden networks state. Must be called when we
- * enable Wi-Fi.
- */
- private synchronized void initializeHiddenNetworksState() {
- // First, reset the state
- resetHiddenNetworksState();
-
- // ... then add networks that are marked as hidden
- List<WifiConfiguration> networks = getConfiguredNetworks();
- if (!networks.isEmpty()) {
- for (WifiConfiguration config : networks) {
- if (config != null && config.hiddenSSID) {
- addOrUpdateHiddenNetwork(
- config.networkId,
- config.status != WifiConfiguration.Status.DISABLED);
- }
- }
-
- }
- }
-
- /**
- * Resets the hidden networks state.
- */
- private synchronized void resetHiddenNetworksState() {
- mNumHiddenNetworkPresent = 0;
- mIsHiddenNetworkPresent.clear();
- }
-
- /**
- * Marks all but netId network as not present.
- */
- private synchronized void markAllHiddenNetworksButOneAsNotPresent(int netId) {
- for (Map.Entry<Integer, Boolean> entry : mIsHiddenNetworkPresent.entrySet()) {
- if (entry != null) {
- Integer networkId = entry.getKey();
- if (networkId != netId) {
- updateNetworkIfHidden(
- networkId, false);
- }
- }
- }
- }
-
- /**
- * Updates the netId network presence status if netId is an existing
- * hidden network.
- */
- private synchronized void updateNetworkIfHidden(int netId, boolean present) {
- if (isHiddenNetwork(netId)) {
- addOrUpdateHiddenNetwork(netId, present);
- }
- }
-
- /**
- * Updates the netId network presence status if netId is an existing
- * hidden network. If the network does not exist, adds the network.
- */
- private synchronized void addOrUpdateHiddenNetwork(int netId, boolean present) {
- if (0 <= netId) {
-
- // If we are adding a new entry or modifying an existing one
- Boolean isPresent = mIsHiddenNetworkPresent.get(netId);
- if (isPresent == null || isPresent != present) {
- if (present) {
- incrementHiddentNetworkPresentCounter();
- } else {
- // If we add a new hidden network, no need to change
- // the counter (it must be 0)
- if (isPresent != null) {
- decrementHiddentNetworkPresentCounter();
- }
- }
- mIsHiddenNetworkPresent.put(netId, present);
- }
- } else {
- Log.e(TAG, "addOrUpdateHiddenNetwork(): Invalid (negative) network id!");
- }
- }
-
- /**
- * Removes the netId network if it is hidden (being kept track of).
- */
- private synchronized void removeNetworkIfHidden(int netId) {
- if (isHiddenNetwork(netId)) {
- removeHiddenNetwork(netId);
- }
- }
-
- /**
- * Removes the netId network. For the call to be successful, the network
- * must be hidden.
- */
- private synchronized void removeHiddenNetwork(int netId) {
- if (0 <= netId) {
- Boolean isPresent =
- mIsHiddenNetworkPresent.remove(netId);
- if (isPresent != null) {
- // If we remove an existing hidden network that is not
- // present, no need to change the counter
- if (isPresent) {
- decrementHiddentNetworkPresentCounter();
- }
- } else {
- if (DBG) {
- Log.d(TAG, "removeHiddenNetwork(): Removing a non-existent network!");
- }
- }
- } else {
- Log.e(TAG, "removeHiddenNetwork(): Invalid (negative) network id!");
- }
- }
-
- /**
- * Returns true if netId is an existing hidden network.
- */
- private synchronized boolean isHiddenNetwork(int netId) {
- return mIsHiddenNetworkPresent.containsKey(netId);
- }
-
- /**
- * Increments the present (enabled) hidden networks counter. If the
- * counter value goes from 0 to 1, changes the scan mode to active.
- */
- private void incrementHiddentNetworkPresentCounter() {
- ++mNumHiddenNetworkPresent;
- if (1 == mNumHiddenNetworkPresent) {
- // Switch the scan mode to "active"
- mWifiStateTracker.setScanMode(true, SET_DUE_TO_A_HIDDEN_NETWORK);
- }
- }
-
- /**
- * Decrements the present (enabled) hidden networks counter. If the
- * counter goes from 1 to 0, changes the scan mode back to passive.
- */
- private void decrementHiddentNetworkPresentCounter() {
- if (0 < mNumHiddenNetworkPresent) {
- --mNumHiddenNetworkPresent;
- if (0 == mNumHiddenNetworkPresent) {
- // Switch the scan mode to "passive"
- mWifiStateTracker.setScanMode(false, SET_DUE_TO_A_HIDDEN_NETWORK);
- }
- } else {
- Log.e(TAG, "Hidden-network counter invariant violation!");
- }
- }
-
private boolean getPersistedWifiEnabled() {
final ContentResolver cr = mContext.getContentResolver();
try {
@@ -522,7 +346,7 @@ public class WifiService extends IWifiManager.Stub {
}
// We must reset the interface before we unload the driver
- mWifiStateTracker.resetInterface();
+ mWifiStateTracker.resetInterface(false);
if (!WifiNative.unloadDriver()) {
Log.e(TAG, "Failed to unload Wi-Fi driver.");
@@ -544,12 +368,10 @@ public class WifiService extends IWifiManager.Stub {
setWifiEnabledState(eventualWifiState, uid);
/*
- * Initialize the hidden networks state and the number of allowed
- * radio channels if Wi-Fi is being turned on.
+ * Initialize the number of allowed radio channels if Wi-Fi is being turned on.
*/
if (enable) {
mWifiStateTracker.setNumAllowedChannels();
- initializeHiddenNetworksState();
}
return true;
@@ -884,15 +706,6 @@ public class WifiService extends IWifiManager.Stub {
}
mNeedReconfig = mNeedReconfig || doReconfig;
- /*
- * If we have hidden networks, we may have to change the scan mode
- */
- if (config.hiddenSSID) {
- // Mark the network as present unless it is disabled
- addOrUpdateHiddenNetwork(
- netId, config.status != WifiConfiguration.Status.DISABLED);
- }
-
setVariables: {
/*
* Note that if a networkId for a non-existent network
@@ -1220,11 +1033,6 @@ public class WifiService extends IWifiManager.Stub {
public boolean removeNetwork(int netId) {
enforceChangePermission();
- /*
- * If we have hidden networks, we may have to change the scan mode
- */
- removeNetworkIfHidden(netId);
-
return mWifiStateTracker.removeNetwork(netId);
}
@@ -1238,18 +1046,14 @@ public class WifiService extends IWifiManager.Stub {
public boolean enableNetwork(int netId, boolean disableOthers) {
enforceChangePermission();
- /*
- * If we have hidden networks, we may have to change the scan mode
- */
- synchronized(this) {
- if (disableOthers) {
- markAllHiddenNetworksButOneAsNotPresent(netId);
- }
- updateNetworkIfHidden(netId, true);
- }
-
synchronized (mWifiStateTracker) {
- return WifiNative.enableNetworkCommand(netId, disableOthers);
+ String ifname = mWifiStateTracker.getInterfaceName();
+ NetworkUtils.enableInterface(ifname);
+ boolean result = WifiNative.enableNetworkCommand(netId, disableOthers);
+ if (!result) {
+ NetworkUtils.disableInterface(ifname);
+ }
+ return result;
}
}
@@ -1262,11 +1066,6 @@ public class WifiService extends IWifiManager.Stub {
public boolean disableNetwork(int netId) {
enforceChangePermission();
- /*
- * If we have hidden networks, we may have to change the scan mode
- */
- updateNetworkIfHidden(netId, false);
-
synchronized (mWifiStateTracker) {
return WifiNative.disableNetworkCommand(netId);
}
@@ -1364,39 +1163,42 @@ public class WifiService extends IWifiManager.Stub {
level = 0;
}
- // bssid is the hash key
- scanResult = mScanResultCache.get(bssid);
- if (scanResult != null) {
- scanResult.level = level;
- } else {
- /*
- * The formatting of the results returned by
- * wpa_supplicant is intended to make the fields
- * line up nicely when printed,
- * not to make them easy to parse. So we have to
- * apply some heuristics to figure out which field
- * is the SSID and which field is the flags.
- */
- String ssid;
- String flags;
- if (result.length == 4) {
- if (result[3].charAt(0) == '[') {
- flags = result[3];
- ssid = "";
- } else {
- flags = "";
- ssid = result[3];
- }
- } else if (result.length == 5) {
+ /*
+ * The formatting of the results returned by
+ * wpa_supplicant is intended to make the fields
+ * line up nicely when printed,
+ * not to make them easy to parse. So we have to
+ * apply some heuristics to figure out which field
+ * is the SSID and which field is the flags.
+ */
+ String ssid;
+ String flags;
+ if (result.length == 4) {
+ if (result[3].charAt(0) == '[') {
flags = result[3];
- ssid = result[4];
+ ssid = "";
} else {
- // Here, we must have 3 fields: no flags and ssid
- // set
flags = "";
- ssid = "";
+ ssid = result[3];
}
+ } else if (result.length == 5) {
+ flags = result[3];
+ ssid = result[4];
+ } else {
+ // Here, we must have 3 fields: no flags and ssid
+ // set
+ flags = "";
+ ssid = "";
+ }
+ // bssid is the hash key
+ scanResult = mScanResultCache.get(bssid);
+ if (scanResult != null) {
+ scanResult.level = level;
+ scanResult.SSID = ssid;
+ scanResult.capabilities = flags;
+ scanResult.frequency = frequency;
+ } else {
// Do not add scan results that have no SSID set
if (0 < ssid.trim().length()) {
scanResult =
@@ -1468,14 +1270,17 @@ 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
+ * for some reason. If the operation is successful, the new value may be
* persisted as a Secure setting.
* @param numChannels the number of allowed channels. Must be greater than 0
* and less than or equal to 16.
+ * @param persist {@code true} if the setting should be remembered.
* @return {@code true} if the operation succeeds, {@code false} otherwise, e.g.,
* {@code numChannels} is outside the valid range.
*/
- public boolean setNumAllowedChannels(int numChannels) {
+ public boolean setNumAllowedChannels(int numChannels, boolean persist) {
+ Log.i(TAG, "WifiService trying to setNumAllowed to "+numChannels+
+ " with persist set to "+persist);
enforceChangePermission();
/*
* Validate the argument. We'd like to let the Wi-Fi driver do this,
@@ -1494,9 +1299,11 @@ public class WifiService extends IWifiManager.Stub {
return false;
}
- Settings.Secure.putInt(mContext.getContentResolver(),
- Settings.Secure.WIFI_NUM_ALLOWED_CHANNELS,
- numChannels);
+ if (persist) {
+ Settings.Secure.putInt(mContext.getContentResolver(),
+ Settings.Secure.WIFI_NUM_ALLOWED_CHANNELS,
+ numChannels);
+ }
mWifiStateTracker.setNumAllowedChannels(numChannels);
return true;
}
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index ad882a9..25aff5c 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -64,6 +64,7 @@ import android.os.Binder;
import android.os.Debug;
import android.os.Handler;
import android.os.IBinder;
+import android.os.LatencyTimer;
import android.os.LocalPowerManager;
import android.os.Looper;
import android.os.Message;
@@ -135,6 +136,8 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
static final boolean DEBUG_STARTING_WINDOW = false;
static final boolean DEBUG_REORDER = false;
static final boolean SHOW_TRANSACTIONS = false;
+ static final boolean MEASURE_LATENCY = false;
+ static private LatencyTimer lt;
static final boolean PROFILE_ORIENTATION = false;
static final boolean BLUR = true;
@@ -509,6 +512,10 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
private WindowManagerService(Context context, PowerManagerService pm,
boolean haveInputMethods) {
+ if (MEASURE_LATENCY) {
+ lt = new LatencyTimer(100, 1000);
+ }
+
mContext = context;
mHaveInputMethods = haveInputMethods;
mLimitedAlphaCompositing = context.getResources().getBoolean(
@@ -3793,7 +3800,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
private final void wakeupIfNeeded(WindowState targetWin, int eventType) {
long curTime = SystemClock.uptimeMillis();
- if (eventType == LONG_TOUCH_EVENT || eventType == CHEEK_EVENT) {
+ if (eventType == TOUCH_EVENT || eventType == LONG_TOUCH_EVENT || eventType == CHEEK_EVENT) {
if (mLastTouchEventType == eventType &&
(curTime - mLastUserActivityCallTime) < MIN_TIME_BETWEEN_USERACTIVITIES) {
return;
@@ -3853,8 +3860,16 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
if (DEBUG_INPUT || WindowManagerPolicy.WATCH_POINTER) Log.v(TAG,
"dispatchPointer " + ev);
+ if (MEASURE_LATENCY) {
+ lt.sample("3 Wait for last dispatch ", System.nanoTime() - qev.whenNano);
+ }
+
Object targetObj = mKeyWaiter.waitForNextEventTarget(null, qev,
ev, true, false, pid, uid);
+
+ if (MEASURE_LATENCY) {
+ lt.sample("3 Last dispatch finished ", System.nanoTime() - qev.whenNano);
+ }
int action = ev.getAction();
@@ -3892,7 +3907,8 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
WindowState target = (WindowState)targetObj;
final long eventTime = ev.getEventTime();
-
+ final long eventTimeNano = ev.getEventTimeNano();
+
//Log.i(TAG, "Sending " + ev + " to " + target);
if (uid != 0 && uid != target.mSession.mUid) {
@@ -3909,6 +3925,10 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
return INJECT_NO_PERMISSION;
}
}
+
+ if (MEASURE_LATENCY) {
+ lt.sample("4 in dispatchPointer ", System.nanoTime() - eventTimeNano);
+ }
if ((target.mAttrs.flags &
WindowManager.LayoutParams.FLAG_IGNORE_CHEEK_PRESSES) != 0) {
@@ -3992,6 +4012,10 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
}
+ if (MEASURE_LATENCY) {
+ lt.sample("5 in dispatchPointer ", System.nanoTime() - eventTimeNano);
+ }
+
synchronized(mWindowMap) {
if (qev != null && action == MotionEvent.ACTION_MOVE) {
mKeyWaiter.bindTargetWindowLocked(target,
@@ -4029,7 +4053,16 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
if (DEBUG_INPUT || DEBUG_FOCUS || WindowManagerPolicy.WATCH_POINTER) {
Log.v(TAG, "Delivering pointer " + qev + " to " + target);
}
+
+ if (MEASURE_LATENCY) {
+ lt.sample("6 before svr->client ipc ", System.nanoTime() - eventTimeNano);
+ }
+
target.mClient.dispatchPointer(ev, eventTime);
+
+ if (MEASURE_LATENCY) {
+ lt.sample("7 after svr->client ipc ", System.nanoTime() - eventTimeNano);
+ }
return INJECT_SUCCEEDED;
} catch (android.os.RemoteException e) {
Log.i(TAG, "WINDOW DIED during motion dispatch: " + target);
@@ -5198,7 +5231,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
}
}
- };
+ }
public boolean detectSafeMode() {
mSafeMode = mPolicy.detectSafeMode();
@@ -5263,9 +5296,13 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
if (DEBUG_INPUT && ev != null) Log.v(
TAG, "Event: type=" + ev.classType + " data=" + ev.event);
+ if (MEASURE_LATENCY) {
+ lt.sample("2 got event ", System.nanoTime() - ev.whenNano);
+ }
+
try {
if (ev != null) {
- curTime = ev.when;
+ curTime = SystemClock.uptimeMillis();
int eventType;
if (ev.classType == RawInputEvent.CLASS_TOUCHSCREEN) {
eventType = eventType((MotionEvent)ev.event);
@@ -5276,17 +5313,29 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
eventType = LocalPowerManager.OTHER_EVENT;
}
try {
- long now = SystemClock.uptimeMillis();
-
- if ((now - mLastBatteryStatsCallTime)
+ if ((curTime - mLastBatteryStatsCallTime)
>= MIN_TIME_BETWEEN_USERACTIVITIES) {
- mLastBatteryStatsCallTime = now;
+ mLastBatteryStatsCallTime = curTime;
mBatteryStats.noteInputEvent();
}
} catch (RemoteException e) {
// Ignore
}
- mPowerManager.userActivity(curTime, false, eventType, false);
+
+ if (eventType != TOUCH_EVENT
+ && eventType != LONG_TOUCH_EVENT
+ && eventType != CHEEK_EVENT) {
+ mPowerManager.userActivity(curTime, false,
+ eventType, false);
+ } else if (mLastTouchEventType != eventType
+ || (curTime - mLastUserActivityCallTime)
+ >= MIN_TIME_BETWEEN_USERACTIVITIES) {
+ mLastUserActivityCallTime = curTime;
+ mLastTouchEventType = eventType;
+ mPowerManager.userActivity(curTime, false,
+ eventType, false);
+ }
+
switch (ev.classType) {
case RawInputEvent.CLASS_KEYBOARD:
KeyEvent ke = (KeyEvent)ev.event;
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 442e9ce..25991f2 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -319,6 +319,12 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// Memory pages are 4K.
static final int PAGE_SIZE = 4*1024;
+ // System property defining error report receiver for system apps
+ static final String SYSTEM_APPS_ERROR_RECEIVER_PROPERTY = "ro.error.receiver.system.apps";
+
+ // System property defining default error report receiver
+ static final String DEFAULT_ERROR_RECEIVER_PROPERTY = "ro.error.receiver.default";
+
// Corresponding memory levels for above adjustments.
final int EMPTY_APP_MEM;
final int HIDDEN_APP_MEM;
@@ -8084,27 +8090,62 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
private ComponentName getErrorReportReceiver(ProcessRecord app) {
IPackageManager pm = ActivityThread.getPackageManager();
+
try {
- // was an installer package name specified when this app was
- // installed?
- String installerPackageName = pm.getInstallerPackageName(app.info.packageName);
- if (installerPackageName == null) {
- return null;
+ // look for receiver in the installer package
+ String candidate = pm.getInstallerPackageName(app.info.packageName);
+ ComponentName result = getErrorReportReceiver(pm, app.info.packageName, candidate);
+ if (result != null) {
+ return result;
}
- // is there an Activity in this package that handles ACTION_APP_ERROR?
- Intent intent = new Intent(Intent.ACTION_APP_ERROR);
- intent.setPackage(installerPackageName);
- ResolveInfo info = pm.resolveIntent(intent, null, 0);
- if (info == null || info.activityInfo == null) {
- return null;
+ // if the error app is on the system image, look for system apps
+ // error receiver
+ if ((app.info.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
+ candidate = SystemProperties.get(SYSTEM_APPS_ERROR_RECEIVER_PROPERTY);
+ result = getErrorReportReceiver(pm, app.info.packageName, candidate);
+ if (result != null) {
+ return result;
+ }
}
- return new ComponentName(installerPackageName, info.activityInfo.name);
+ // if there is a default receiver, try that
+ candidate = SystemProperties.get(DEFAULT_ERROR_RECEIVER_PROPERTY);
+ return getErrorReportReceiver(pm, app.info.packageName, candidate);
} catch (RemoteException e) {
- // will return null and no error report will be delivered
+ // should not happen
+ Log.e(TAG, "error talking to PackageManager", e);
+ return null;
}
- return null;
+ }
+
+ /**
+ * Return activity in receiverPackage that handles ACTION_APP_ERROR.
+ *
+ * @param pm PackageManager isntance
+ * @param errorPackage package which caused the error
+ * @param receiverPackage candidate package to receive the error
+ * @return activity component within receiverPackage which handles
+ * ACTION_APP_ERROR, or null if not found
+ */
+ private ComponentName getErrorReportReceiver(IPackageManager pm, String errorPackage,
+ String receiverPackage) throws RemoteException {
+ if (receiverPackage == null || receiverPackage.length() == 0) {
+ return null;
+ }
+
+ // break the loop if it's the error report receiver package that crashed
+ if (receiverPackage.equals(errorPackage)) {
+ return null;
+ }
+
+ Intent intent = new Intent(Intent.ACTION_APP_ERROR);
+ intent.setPackage(receiverPackage);
+ ResolveInfo info = pm.resolveIntent(intent, null, 0);
+ if (info == null || info.activityInfo == null) {
+ return null;
+ }
+ return new ComponentName(receiverPackage, info.activityInfo.name);
}
void makeAppNotRespondingLocked(ProcessRecord app,
@@ -8426,6 +8467,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
report.crashInfo.throwFileName = trace.getFileName();
report.crashInfo.throwClassName = trace.getClassName();
report.crashInfo.throwMethodName = trace.getMethodName();
+ report.crashInfo.throwLineNumber = trace.getLineNumber();
} else if (r.notResponding) {
report.type = ApplicationErrorReport.TYPE_ANR;
report.anrInfo = new ApplicationErrorReport.AnrInfo();
diff --git a/services/java/com/android/server/status/StatusBarPolicy.java b/services/java/com/android/server/status/StatusBarPolicy.java
index 7a8d4e5..c8db95b 100644
--- a/services/java/com/android/server/status/StatusBarPolicy.java
+++ b/services/java/com/android/server/status/StatusBarPolicy.java
@@ -76,15 +76,8 @@ public class StatusBarPolicy {
private static StatusBarPolicy sInstance;
// message codes for the handler
- private static final int EVENT_DATA_CONN_STATE_CHANGED = 2;
- private static final int EVENT_DATA_ACTIVITY = 3;
private static final int EVENT_BATTERY_CLOSE = 4;
- // indices into mBatteryThresholds
- private static final int BATTERY_THRESHOLD_CLOSE_WARNING = 0;
- private static final int BATTERY_THRESHOLD_WARNING = 1;
- private static final int BATTERY_THRESHOLD_EMPTY = 2;
-
private final Context mContext;
private final StatusBarService mService;
private final Handler mHandler = new StatusBarHandler();
@@ -99,16 +92,13 @@ public class StatusBarPolicy {
private IBinder mBatteryIcon;
private IconData mBatteryData;
private boolean mBatteryFirst = true;
- private int mBatteryPlugged;
+ private boolean mBatteryPlugged;
private int mBatteryLevel;
- private int mBatteryThreshold = 0; // index into mBatteryThresholds
- private int[] mBatteryThresholds = new int[] { 20, 15, -1 };
private AlertDialog mLowBatteryDialog;
private TextView mBatteryLevelTextView;
private View mBatteryView;
private int mBatteryViewSequence;
private boolean mBatteryShowLowOnEndCall = false;
- private boolean mSentLowBatteryBroadcast = false;
private static final boolean SHOW_LOW_BATTERY_WARNING = true;
// phone
@@ -363,6 +353,9 @@ public class StatusBarPolicy {
else if (action.equals(Intent.ACTION_TIME_CHANGED)) {
updateClock();
}
+ else if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {
+ updateBattery(intent);
+ }
else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED)) {
updateClock();
}
@@ -377,8 +370,11 @@ public class StatusBarPolicy {
else if (action.equals(Intent.ACTION_SYNC_STATE_CHANGED)) {
updateSyncState(intent);
}
- else if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {
- updateBattery(intent);
+ else if (action.equals(Intent.ACTION_BATTERY_LOW)) {
+ onBatteryLow(intent);
+ }
+ else if (action.equals(Intent.ACTION_BATTERY_OKAY)) {
+ onBatteryOkay(intent);
}
else if (action.equals(BluetoothIntent.BLUETOOTH_STATE_CHANGED_ACTION) ||
action.equals(BluetoothIntent.HEADSET_STATE_CHANGED_ACTION) ||
@@ -521,6 +517,8 @@ public class StatusBarPolicy {
filter.addAction(Intent.ACTION_TIME_CHANGED);
filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
filter.addAction(Intent.ACTION_BATTERY_CHANGED);
+ filter.addAction(Intent.ACTION_BATTERY_LOW);
+ filter.addAction(Intent.ACTION_BATTERY_OKAY);
filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
filter.addAction(Intent.ACTION_ALARM_CHANGED);
filter.addAction(Intent.ACTION_SYNC_STATE_CHANGED);
@@ -564,38 +562,22 @@ public class StatusBarPolicy {
//mService.setIconVisibility(mSyncFailingIcon, isFailing && !isActive);
}
- private void pickNextBatteryLevel(int level) {
- final int N = mBatteryThresholds.length;
- for (int i=0; i<N; i++) {
- if (level >= mBatteryThresholds[i]) {
- mBatteryThreshold = i;
- break;
- }
- }
- if (mBatteryThreshold >= N) {
- mBatteryThreshold = N-1;
- }
- }
-
private final void updateBattery(Intent intent) {
mBatteryData.iconId = intent.getIntExtra("icon-small", 0);
mBatteryData.iconLevel = intent.getIntExtra("level", 0);
mService.updateIcon(mBatteryIcon, mBatteryData, null);
- int plugged = intent.getIntExtra("plugged", 0);
+ boolean plugged = intent.getIntExtra("plugged", 0) != 0;
int level = intent.getIntExtra("level", -1);
if (false) {
Log.d(TAG, "updateBattery level=" + level
+ " plugged=" + plugged
+ " mBatteryPlugged=" + mBatteryPlugged
+ " mBatteryLevel=" + mBatteryLevel
- + " mBatteryThreshold=" + mBatteryThreshold
+ " mBatteryFirst=" + mBatteryFirst);
}
- int oldPlugged = mBatteryPlugged;
- int oldThreshold = mBatteryThreshold;
- pickNextBatteryLevel(level);
+ boolean oldPlugged = mBatteryPlugged;
mBatteryPlugged = plugged;
mBatteryLevel = level;
@@ -617,44 +599,34 @@ public class StatusBarPolicy {
}
*/
if (false) {
- Log.d(TAG, "plugged=" + plugged + " oldPlugged=" + oldPlugged + " level=" + level
- + " mBatteryThreshold=" + mBatteryThreshold + " oldThreshold=" + oldThreshold);
+ Log.d(TAG, "plugged=" + plugged + " oldPlugged=" + oldPlugged + " level=" + level);
}
- if (plugged == 0
- && ((oldPlugged != 0 && level < mBatteryThresholds[BATTERY_THRESHOLD_WARNING])
- || (mBatteryThreshold > oldThreshold
- && mBatteryThreshold > BATTERY_THRESHOLD_WARNING))) {
- // Broadcast the low battery warning
- mSentLowBatteryBroadcast = true;
- mContext.sendBroadcast(new Intent(Intent.ACTION_BATTERY_LOW));
-
- if (SHOW_LOW_BATTERY_WARNING) {
- if (false) {
- Log.d(TAG, "mPhoneState=" + mPhoneState
- + " mLowBatteryDialog=" + mLowBatteryDialog
- + " mBatteryShowLowOnEndCall=" + mBatteryShowLowOnEndCall);
- }
+ }
- if (mPhoneState == TelephonyManager.CALL_STATE_IDLE) {
- showLowBatteryWarning();
- } else {
- mBatteryShowLowOnEndCall = true;
- }
+ private void onBatteryLow(Intent intent) {
+ if (SHOW_LOW_BATTERY_WARNING) {
+ if (false) {
+ Log.d(TAG, "mPhoneState=" + mPhoneState
+ + " mLowBatteryDialog=" + mLowBatteryDialog
+ + " mBatteryShowLowOnEndCall=" + mBatteryShowLowOnEndCall);
}
- } else if (mBatteryThreshold < BATTERY_THRESHOLD_WARNING) {
- if (mSentLowBatteryBroadcast == true) {
- mSentLowBatteryBroadcast = false;
- mContext.sendBroadcast(new Intent(Intent.ACTION_BATTERY_OKAY));
- }
- if (SHOW_LOW_BATTERY_WARNING) {
- if (mLowBatteryDialog != null) {
- mLowBatteryDialog.dismiss();
- mBatteryShowLowOnEndCall = false;
- }
+
+ if (mPhoneState == TelephonyManager.CALL_STATE_IDLE) {
+ showLowBatteryWarning();
+ } else {
+ mBatteryShowLowOnEndCall = true;
}
}
}
+ private void onBatteryOkay(Intent intent) {
+ if (mLowBatteryDialog != null
+ && SHOW_LOW_BATTERY_WARNING) {
+ mLowBatteryDialog.dismiss();
+ mBatteryShowLowOnEndCall = false;
+ }
+ }
+
private void showBatteryView() {
closeLastBatteryView();
if (mLowBatteryDialog != null) {
@@ -716,9 +688,11 @@ public class StatusBarPolicy {
private void showLowBatteryWarning() {
closeLastBatteryView();
- int level = mBatteryThresholds[mBatteryThreshold > 1 ? mBatteryThreshold - 1 : 0];
+ /* Show exact battery level.
+ * Add 1 because the text says "less than X%".
+ */
CharSequence levelText = mContext.getString(
- com.android.internal.R.string.battery_low_percent_format, level);
+ com.android.internal.R.string.battery_low_percent_format, mBatteryLevel + 1);
if (mBatteryLevelTextView != null) {
mBatteryLevelTextView.setText(levelText);
@@ -769,7 +743,7 @@ public class StatusBarPolicy {
}
if (mPhoneState == TelephonyManager.CALL_STATE_IDLE) {
if (mBatteryShowLowOnEndCall) {
- if (mBatteryPlugged == 0) {
+ if (!mBatteryPlugged) {
showLowBatteryWarning();
}
mBatteryShowLowOnEndCall = false;