summaryrefslogtreecommitdiffstats
path: root/services
diff options
context:
space:
mode:
authorJean-Baptiste Queru <jbq@google.com>2009-07-29 14:25:07 -0700
committerJean-Baptiste Queru <jbq@google.com>2009-07-29 14:25:07 -0700
commita8675f67e33bc7337d148358783b0fd138b501ff (patch)
tree71fb9d10330ef9161b3ead71d01074b3ef9e53ba /services
parentcf4550c3198d6b3d92cdc52707fe70d7cc0caa9f (diff)
downloadframeworks_base-a8675f67e33bc7337d148358783b0fd138b501ff.zip
frameworks_base-a8675f67e33bc7337d148358783b0fd138b501ff.tar.gz
frameworks_base-a8675f67e33bc7337d148358783b0fd138b501ff.tar.bz2
donut snapshot
Diffstat (limited to 'services')
-rw-r--r--services/java/com/android/server/AppWidgetService.java8
-rw-r--r--services/java/com/android/server/BackupManagerService.java26
-rw-r--r--services/java/com/android/server/MountListener.java1
-rw-r--r--services/java/com/android/server/NotificationManagerService.java20
-rw-r--r--services/java/com/android/server/PackageManagerService.java80
-rw-r--r--services/java/com/android/server/SystemServer.java17
-rw-r--r--services/java/com/android/server/WifiService.java7
-rw-r--r--services/java/com/android/server/WindowManagerService.java596
-rw-r--r--services/java/com/android/server/am/ActivityManagerService.java150
-rw-r--r--services/java/com/android/server/am/BatteryStatsService.java2
-rwxr-xr-xservices/java/com/android/server/am/UsageStatsService.java54
-rw-r--r--services/java/com/android/server/status/StatusBarPolicy.java8
12 files changed, 698 insertions, 271 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 3b82284..6e28515 100644
--- a/services/java/com/android/server/BackupManagerService.java
+++ b/services/java/com/android/server/BackupManagerService.java
@@ -810,17 +810,25 @@ class BackupManagerService extends IBackupManager.Stub {
// Now propagate the newly-backed-up data to the transport
if (success) {
- if (DEBUG) Log.v(TAG, "doBackup() success; calling transport");
- backupData =
- ParcelFileDescriptor.open(backupDataName, ParcelFileDescriptor.MODE_READ_ONLY);
- if (!transport.performBackup(packInfo, backupData)) {
- // STOPSHIP TODO: handle errors
- Log.e(TAG, "Backup failure in performBackup()");
+ if (DEBUG) Log.v(TAG, "doBackup() success");
+ if (backupDataName.length() > 0) {
+ backupData =
+ ParcelFileDescriptor.open(backupDataName,
+ ParcelFileDescriptor.MODE_READ_ONLY);
+ if (!transport.performBackup(packInfo, backupData)) {
+ // STOPSHIP TODO: handle errors
+ Log.e(TAG, "Backup failure in performBackup()");
+ }
+ } else {
+ if (DEBUG) {
+ Log.i(TAG, "no backup data written; not calling transport");
+ }
}
- // !!! TODO: After successful transport, delete the now-stale data
- // and juggle the files so that next time the new state is passed
- //backupDataName.delete();
+ // After successful transport, delete the now-stale data
+ // and juggle the files so that next time we supply the agent
+ // with the new state file it just created.
+ backupDataName.delete();
newStateName.renameTo(savedStateName);
}
} catch (Exception e) {
diff --git a/services/java/com/android/server/MountListener.java b/services/java/com/android/server/MountListener.java
index 2e430c8..3e53585 100644
--- a/services/java/com/android/server/MountListener.java
+++ b/services/java/com/android/server/MountListener.java
@@ -202,6 +202,7 @@ final class MountListener implements Runnable {
byte[] buffer = new byte[100];
writeCommand(VOLD_CMD_SEND_UMS_STATUS);
+ mountMedia(Environment.getExternalStorageDirectory().getAbsolutePath());
while (true) {
int count = inputStream.read(buffer);
diff --git a/services/java/com/android/server/NotificationManagerService.java b/services/java/com/android/server/NotificationManagerService.java
index 854138c..38fb7c9 100644
--- a/services/java/com/android/server/NotificationManagerService.java
+++ b/services/java/com/android/server/NotificationManagerService.java
@@ -49,6 +49,7 @@ import android.os.IBinder;
import android.os.Message;
import android.os.Power;
import android.os.RemoteException;
+import android.os.SystemProperties;
import android.os.Vibrator;
import android.provider.Settings;
import android.text.TextUtils;
@@ -88,7 +89,8 @@ class NotificationManagerService extends INotificationManager.Stub
private NotificationRecord mSoundNotification;
private AsyncPlayer mSound;
- private int mDisabledNotifications;
+ private boolean mSystemReady;
+ private int mDisabledNotifications = StatusBarManager.DISABLE_NOTIFICATION_ALERTS;
private NotificationRecord mVibrateNotification;
private Vibrator mVibrator = new Vibrator();
@@ -377,6 +379,11 @@ class NotificationManagerService extends INotificationManager.Stub
mSettingsObserver.observe();
}
+ void systemReady() {
+ // no beeping until we're basically done booting
+ mSystemReady = true;
+ }
+
// Toasts
// ============================================================================
public void enqueueToast(String pkg, ITransientNotification callback, int duration)
@@ -637,7 +644,7 @@ class NotificationManagerService extends INotificationManager.Stub
}
}
- sendAccessibilityEventTypeNotificationChangedDoCheck(notification, pkg);
+ sendAccessibilityEvent(notification, pkg);
} else {
if (old != null && old.statusBarKey != null) {
@@ -654,7 +661,8 @@ class NotificationManagerService extends INotificationManager.Stub
// If we're not supposed to beep, vibrate, etc. then don't.
if (((mDisabledNotifications & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) == 0)
&& (!(old != null
- && (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0 ))) {
+ && (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0 ))
+ && mSystemReady) {
// sound
final boolean useDefaultSound =
(notification.defaults & Notification.DEFAULT_SOUND) != 0;
@@ -721,8 +729,7 @@ class NotificationManagerService extends INotificationManager.Stub
idOut[0] = id;
}
- private void sendAccessibilityEventTypeNotificationChangedDoCheck(Notification notification,
- CharSequence packageName) {
+ private void sendAccessibilityEvent(Notification notification, CharSequence packageName) {
AccessibilityManager manager = AccessibilityManager.getInstance(mContext);
if (!manager.isEnabled()) {
return;
@@ -939,6 +946,9 @@ class NotificationManagerService extends INotificationManager.Stub
// to accidentally lose.
private void updateAdbNotification() {
if (mAdbEnabled && mBatteryPlugged == BatteryManager.BATTERY_PLUGGED_USB) {
+ if ("0".equals(SystemProperties.get("persist.adb.notify"))) {
+ return;
+ }
if (!mAdbNotificationShown) {
NotificationManager notificationManager = (NotificationManager) mContext
.getSystemService(Context.NOTIFICATION_SERVICE);
diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java
index 06435c8..ee53274 100644
--- a/services/java/com/android/server/PackageManagerService.java
+++ b/services/java/com/android/server/PackageManagerService.java
@@ -56,12 +56,11 @@ import android.content.pm.ProviderInfo;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.content.pm.Signature;
-import android.content.res.CompatibilityInfo;
-import android.content.res.Configuration;
import android.net.Uri;
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
+import android.os.Debug;
import android.os.HandlerThread;
import android.os.Parcel;
import android.os.RemoteException;
@@ -251,6 +250,9 @@ class PackageManagerService extends IPackageManager.Stub {
final HashMap<String, PackageParser.PermissionGroup> mPermissionGroups =
new HashMap<String, PackageParser.PermissionGroup>();
+ // Broadcast actions that are only available to the system.
+ final HashSet<String> mProtectedBroadcasts = new HashSet<String>();
+
boolean mSystemReady;
boolean mSafeMode;
boolean mHasSystemUidErrors;
@@ -260,7 +262,6 @@ class PackageManagerService extends IPackageManager.Stub {
final ResolveInfo mResolveInfo = new ResolveInfo();
ComponentName mResolveComponentName;
PackageParser.Package mPlatformPackage;
- private boolean mCompatibilityModeEnabled = true;
public static final IPackageManager main(Context context, boolean factoryTest) {
PackageManagerService m = new PackageManagerService(context, factoryTest);
@@ -763,7 +764,7 @@ class PackageManagerService extends IPackageManager.Stub {
synchronized (mPackages) {
PackageParser.Package p = mPackages.get(packageName);
if (Config.LOGV) Log.v(
- TAG, "getApplicationInfo " + packageName
+ TAG, "getPackageInfo " + packageName
+ ": " + p);
if (p != null) {
return generatePackageInfo(p, flags);
@@ -794,7 +795,7 @@ class PackageManagerService extends IPackageManager.Stub {
synchronized (mPackages) {
PackageParser.Package p = mPackages.get(packageName);
if (Config.LOGV) Log.v(
- TAG, "getApplicationInfo " + packageName
+ TAG, "getPackageGids" + packageName
+ ": " + p);
if (p != null) {
final PackageSetting ps = (PackageSetting)p.mExtras;
@@ -892,11 +893,7 @@ class PackageManagerService extends IPackageManager.Stub {
+ ": " + p);
if (p != null) {
// Note: isEnabledLP() does not apply here - always return info
- ApplicationInfo appInfo = PackageParser.generateApplicationInfo(p, flags);
- if (!mCompatibilityModeEnabled) {
- appInfo.disableCompatibilityMode();
- }
- return appInfo;
+ return PackageParser.generateApplicationInfo(p, flags);
}
if ("android".equals(packageName)||"system".equals(packageName)) {
return mAndroidApplication;
@@ -1128,6 +1125,12 @@ class PackageManagerService extends IPackageManager.Stub {
}
}
+ public boolean isProtectedBroadcast(String actionName) {
+ synchronized (mPackages) {
+ return mProtectedBroadcasts.contains(actionName);
+ }
+ }
+
public int checkSignatures(String pkg1, String pkg2) {
synchronized (mPackages) {
PackageParser.Package p1 = mPackages.get(pkg1);
@@ -2039,8 +2042,9 @@ class PackageManagerService extends IPackageManager.Stub {
+ suid.userId + "): packages=" + suid.packages);
}
}
-
- // Just create the setting, don't add it yet
+
+ // Just create the setting, don't add it yet. For already existing packages
+ // the PkgSetting exists already and doesn't have to be created.
pkgSetting = mSettings.getPackageLP(pkg, suid, destCodeFile,
destResourceFile, pkg.applicationInfo.flags, true, false);
if (pkgSetting == null) {
@@ -2265,7 +2269,7 @@ class PackageManagerService extends IPackageManager.Stub {
// Add the new setting to mSettings
mSettings.insertPackageSettingLP(pkgSetting, pkg.packageName, suid);
// Add the new setting to mPackages
- mPackages.put(pkg.applicationInfo.packageName, pkg);
+ mPackages.put(pkg.applicationInfo.packageName, pkg);
int N = pkg.providers.size();
StringBuilder r = null;
int i;
@@ -2500,6 +2504,13 @@ class PackageManagerService extends IPackageManager.Stub {
if (Config.LOGD) Log.d(TAG, " Instrumentation: " + r);
}
+ if (pkg.protectedBroadcasts != null) {
+ N = pkg.protectedBroadcasts.size();
+ for (i=0; i<N; i++) {
+ mProtectedBroadcasts.add(pkg.protectedBroadcasts.get(i));
+ }
+ }
+
pkgSetting.setTimeStamp(scanFileTime);
}
@@ -4801,11 +4812,12 @@ class PackageManagerService extends IPackageManager.Stub {
mSystemReady = true;
// Read the compatibilty setting when the system is ready.
- mCompatibilityModeEnabled = android.provider.Settings.System.getInt(
+ boolean compatibilityModeEnabled = android.provider.Settings.System.getInt(
mContext.getContentResolver(),
android.provider.Settings.System.COMPATIBILITY_MODE, 1) == 1;
+ PackageParser.setCompatibilityModeEnabled(compatibilityModeEnabled);
if (DEBUG_SETTINGS) {
- Log.d(TAG, "compatibility mode:" + mCompatibilityModeEnabled);
+ Log.d(TAG, "compatibility mode:" + compatibilityModeEnabled);
}
}
@@ -4889,6 +4901,26 @@ class PackageManagerService extends IPackageManager.Stub {
pw.print(" resourcePath="); pw.println(ps.resourcePathString);
if (ps.pkg != null) {
pw.print(" dataDir="); pw.println(ps.pkg.applicationInfo.dataDir);
+ pw.print(" targetSdk="); pw.println(ps.pkg.applicationInfo.targetSdkVersion);
+ pw.print(" densities="); pw.println(ps.pkg.supportsDensityList);
+ ArrayList<String> screens = new ArrayList<String>();
+ if ((ps.pkg.applicationInfo.flags &
+ ApplicationInfo.FLAG_SUPPORTS_NORMAL_SCREENS) != 0) {
+ screens.add("medium");
+ }
+ if ((ps.pkg.applicationInfo.flags &
+ ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS) != 0) {
+ screens.add("large");
+ }
+ if ((ps.pkg.applicationInfo.flags &
+ ApplicationInfo.FLAG_SUPPORTS_SMALL_SCREENS) != 0) {
+ screens.add("small,");
+ }
+ if ((ps.pkg.applicationInfo.flags &
+ ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS) != 0) {
+ screens.add("resizeable,");
+ }
+ pw.print(" supportsScreens="); pw.println(screens);
}
pw.print(" timeStamp="); pw.println(ps.getTimeStampStr());
pw.print(" signatures="); pw.println(ps.signatures);
@@ -5408,10 +5440,10 @@ class PackageManagerService extends IPackageManager.Stub {
*/
static class PackageSettingBase extends GrantedPermissions {
final String name;
- final File codePath;
- final String codePathString;
- final File resourcePath;
- final String resourcePathString;
+ File codePath;
+ String codePathString;
+ File resourcePath;
+ String resourcePathString;
private long timeStamp;
private String timeStampString = "0";
final int versionCode;
@@ -5809,11 +5841,16 @@ class PackageManagerService extends IPackageManager.Stub {
// and data partition. Just let the most recent version
// take precedence.
return p;
- } else if ((p.pkg != null) && (p.pkg.applicationInfo != null)) {
+ } else {
// Let the app continue with previous uid if code path changes.
reportSettingsProblem(Log.WARN,
"Package " + name + " codePath changed from " + p.codePath
- + " to " + codePath + "; Retaining data and using new code");
+ + " to " + codePath + "; Retaining data and using new code from " +
+ codePath);
+ p.codePath = codePath;
+ p.resourcePath = resourcePath;
+ p.codePathString = codePath.toString();
+ p.resourcePathString = resourcePath.toString();
}
} else if (p.sharedUser != sharedUser) {
reportSettingsProblem(Log.WARN,
@@ -5837,6 +5874,7 @@ class PackageManagerService extends IPackageManager.Stub {
if (sharedUser != null) {
p.userId = sharedUser.userId;
} else if (MULTIPLE_APPLICATION_UIDS) {
+ // Assign new user id
p.userId = newUserIdLP(p);
} else {
p.userId = FIRST_APPLICATION_UID;
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 3e4d5f9..aa1a5cf 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -52,6 +52,7 @@ import java.lang.reflect.InvocationTargetException;
class ServerThread extends Thread {
private static final String TAG = "SystemServer";
private final static boolean INCLUDE_DEMO = false;
+ private final static boolean INCLUDE_BACKUP = false;
private static final int LOG_BOOT_PROGRESS_SYSTEM_RUN = 3010;
@@ -190,6 +191,7 @@ class ServerThread extends Thread {
StatusBarService statusBar = null;
InputMethodManagerService imm = null;
AppWidgetService appWidget = null;
+ NotificationManagerService notification = null;
if (factoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
try {
@@ -240,8 +242,8 @@ class ServerThread extends Thread {
try {
Log.i(TAG, "Starting Notification Manager.");
- ServiceManager.addService(Context.NOTIFICATION_SERVICE,
- new NotificationManagerService(context, statusBar, hardware));
+ notification = new NotificationManagerService(context, statusBar, hardware);
+ ServiceManager.addService(Context.NOTIFICATION_SERVICE, notification);
} catch (Throwable e) {
Log.e(TAG, "Failure starting Notification Manager", e);
}
@@ -317,8 +319,10 @@ class ServerThread extends Thread {
}
try {
- Log.i(TAG, "Starting Backup Service");
- ServiceManager.addService(Context.BACKUP_SERVICE, new BackupManagerService(context));
+ if (INCLUDE_BACKUP) {
+ Log.i(TAG, "Starting Backup Service");
+ ServiceManager.addService(Context.BACKUP_SERVICE, new BackupManagerService(context));
+ }
} catch (Throwable e) {
Log.e(TAG, "Failure starting Backup Service", e);
}
@@ -348,6 +352,11 @@ class ServerThread extends Thread {
// It is now time to start up the app processes...
boolean safeMode = wm.detectSafeMode();
+
+ if (notification != null) {
+ notification.systemReady();
+ }
+
if (statusBar != null) {
statusBar.systemReady();
}
diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java
index a940af3..b4754b6 100644
--- a/services/java/com/android/server/WifiService.java
+++ b/services/java/com/android/server/WifiService.java
@@ -192,6 +192,7 @@ public class WifiService extends IWifiManager.Stub {
WifiService(Context context, WifiStateTracker tracker) {
mContext = context;
mWifiStateTracker = tracker;
+ mWifiStateTracker.enableRssiPolling(true);
mBatteryStats = BatteryStatsService.getService();
/*
@@ -436,7 +437,7 @@ public class WifiService extends IWifiManager.Stub {
* see {@link android.net.wifi.WifiManager#startScan()}
* @return {@code true} if the operation succeeds
*/
- public boolean startScan() {
+ public boolean startScan(boolean forceActive) {
enforceChangePermission();
synchronized (mWifiStateTracker) {
switch (mWifiStateTracker.getSupplicantState()) {
@@ -450,7 +451,7 @@ public class WifiService extends IWifiManager.Stub {
WifiStateTracker.SUPPL_SCAN_HANDLING_LIST_ONLY);
break;
}
- return WifiNative.scanCommand();
+ return WifiNative.scanCommand(forceActive);
}
}
@@ -1560,9 +1561,11 @@ public class WifiService extends IWifiManager.Stub {
mAlarmManager.cancel(mIdleIntent);
mDeviceIdle = false;
mScreenOff = false;
+ mWifiStateTracker.enableRssiPolling(true);
} else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
Log.d(TAG, "ACTION_SCREEN_OFF");
mScreenOff = true;
+ mWifiStateTracker.enableRssiPolling(false);
/*
* 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
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index 2dd70ef..0be8417 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -24,8 +24,10 @@ import static android.os.LocalPowerManager.TOUCH_UP_EVENT;
import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
import static android.view.WindowManager.LayoutParams.FLAG_BLUR_BEHIND;
+import static android.view.WindowManager.LayoutParams.FLAG_COMPATIBLE_WINDOW;
import static android.view.WindowManager.LayoutParams.FLAG_DIM_BEHIND;
import static android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
+import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
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;
@@ -53,6 +55,7 @@ import android.app.IActivityManager;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
+import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
import android.graphics.Matrix;
import android.graphics.PixelFormat;
@@ -100,6 +103,7 @@ import android.view.WindowManager;
import android.view.WindowManagerImpl;
import android.view.WindowManagerPolicy;
import android.view.WindowManager.LayoutParams;
+import android.view.animation.AccelerateInterpolator;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.view.animation.Transformation;
@@ -171,6 +175,11 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
*/
static final int DEFAULT_DIM_DURATION = 200;
+ /** Amount of time (in milliseconds) to animate the fade-in-out transition for
+ * compatible windows.
+ */
+ static final int DEFAULT_FADE_IN_OUT_DURATION = 400;
+
/** Adjustment to time to perform a dim, to make it more dramatic.
*/
static final int DIM_DURATION_MULTIPLIER = 6;
@@ -324,12 +333,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
IInputMethodManager mInputMethodManager;
SurfaceSession mFxSession;
- Surface mDimSurface;
- boolean mDimShown;
- float mDimCurrentAlpha;
- float mDimTargetAlpha;
- float mDimDeltaPerMs;
- long mLastDimAnimTime;
+ private DimAnimator mDimAnimator = null;
Surface mBlurSurface;
boolean mBlurShown;
@@ -416,8 +420,14 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
final Rect mTempRect = new Rect();
final Configuration mTempConfiguration = new Configuration();
- int screenLayout = Configuration.SCREENLAYOUT_UNDEFINED;
-
+ int mScreenLayout = Configuration.SCREENLAYOUT_SIZE_UNDEFINED;
+
+ // The frame use to limit the size of the app running in compatibility mode.
+ Rect mCompatibleScreenFrame = new Rect();
+ // The surface used to fill the outer rim of the app running in compatibility mode.
+ Surface mBackgroundFillerSurface = null;
+ boolean mBackgroundFillerShown = false;
+
public static WindowManagerService main(Context context,
PowerManagerService pm, boolean haveInputMethods) {
WMThread thr = new WMThread(context, pm, haveInputMethods);
@@ -1847,44 +1857,51 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
// artifacts when we unfreeze the display if some different animation
// is running.
if (!mDisplayFrozen) {
- int animAttr = 0;
- switch (transit) {
- case WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN:
- animAttr = enter
- ? com.android.internal.R.styleable.WindowAnimation_activityOpenEnterAnimation
- : com.android.internal.R.styleable.WindowAnimation_activityOpenExitAnimation;
- break;
- case WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE:
- animAttr = enter
- ? com.android.internal.R.styleable.WindowAnimation_activityCloseEnterAnimation
- : com.android.internal.R.styleable.WindowAnimation_activityCloseExitAnimation;
- break;
- case WindowManagerPolicy.TRANSIT_TASK_OPEN:
- animAttr = enter
- ? com.android.internal.R.styleable.WindowAnimation_taskOpenEnterAnimation
- : com.android.internal.R.styleable.WindowAnimation_taskOpenExitAnimation;
- break;
- case WindowManagerPolicy.TRANSIT_TASK_CLOSE:
- animAttr = enter
- ? com.android.internal.R.styleable.WindowAnimation_taskCloseEnterAnimation
- : com.android.internal.R.styleable.WindowAnimation_taskCloseExitAnimation;
- break;
- case WindowManagerPolicy.TRANSIT_TASK_TO_FRONT:
- animAttr = enter
- ? com.android.internal.R.styleable.WindowAnimation_taskToFrontEnterAnimation
- : com.android.internal.R.styleable.WindowAnimation_taskToFrontExitAnimation;
- break;
- case WindowManagerPolicy.TRANSIT_TASK_TO_BACK:
- animAttr = enter
- ? com.android.internal.R.styleable.WindowAnimation_taskToBackEnterAnimation
- : com.android.internal.R.styleable.WindowAnimation_taskToBackExitAnimation;
- break;
+ Animation a;
+ if (lp != null && (lp.flags & FLAG_COMPATIBLE_WINDOW) != 0) {
+ a = new FadeInOutAnimation(enter);
+ if (DEBUG_ANIM) Log.v(TAG,
+ "applying FadeInOutAnimation for a window in compatibility mode");
+ } else {
+ int animAttr = 0;
+ switch (transit) {
+ case WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN:
+ animAttr = enter
+ ? com.android.internal.R.styleable.WindowAnimation_activityOpenEnterAnimation
+ : com.android.internal.R.styleable.WindowAnimation_activityOpenExitAnimation;
+ break;
+ case WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE:
+ animAttr = enter
+ ? com.android.internal.R.styleable.WindowAnimation_activityCloseEnterAnimation
+ : com.android.internal.R.styleable.WindowAnimation_activityCloseExitAnimation;
+ break;
+ case WindowManagerPolicy.TRANSIT_TASK_OPEN:
+ animAttr = enter
+ ? com.android.internal.R.styleable.WindowAnimation_taskOpenEnterAnimation
+ : com.android.internal.R.styleable.WindowAnimation_taskOpenExitAnimation;
+ break;
+ case WindowManagerPolicy.TRANSIT_TASK_CLOSE:
+ animAttr = enter
+ ? com.android.internal.R.styleable.WindowAnimation_taskCloseEnterAnimation
+ : com.android.internal.R.styleable.WindowAnimation_taskCloseExitAnimation;
+ break;
+ case WindowManagerPolicy.TRANSIT_TASK_TO_FRONT:
+ animAttr = enter
+ ? com.android.internal.R.styleable.WindowAnimation_taskToFrontEnterAnimation
+ : com.android.internal.R.styleable.WindowAnimation_taskToFrontExitAnimation;
+ break;
+ case WindowManagerPolicy.TRANSIT_TASK_TO_BACK:
+ animAttr = enter
+ ? com.android.internal.R.styleable.WindowAnimation_taskToBackEnterAnimation
+ : com.android.internal.R.styleable.WindowAnimation_taskToBackExitAnimation;
+ break;
+ }
+ a = loadAnimation(lp, animAttr);
+ if (DEBUG_ANIM) Log.v(TAG, "applyAnimation: wtoken=" + wtoken
+ + " anim=" + a
+ + " animAttr=0x" + Integer.toHexString(animAttr)
+ + " transit=" + transit);
}
- Animation a = loadAnimation(lp, animAttr);
- if (DEBUG_ANIM) Log.v(TAG, "applyAnimation: wtoken=" + wtoken
- + " anim=" + a
- + " animAttr=0x" + Integer.toHexString(animAttr)
- + " transit=" + transit);
if (a != null) {
if (DEBUG_ANIM) {
RuntimeException e = new RuntimeException();
@@ -3738,12 +3755,14 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
config.orientation = orientation;
- if (screenLayout == Configuration.SCREENLAYOUT_UNDEFINED) {
+ DisplayMetrics dm = new DisplayMetrics();
+ mDisplay.getMetrics(dm);
+ CompatibilityInfo.updateCompatibleScreenFrame(dm, orientation, mCompatibleScreenFrame);
+
+ if (mScreenLayout == Configuration.SCREENLAYOUT_SIZE_UNDEFINED) {
// Note we only do this once because at this point we don't
// expect the screen to change in this way at runtime, and want
// to avoid all of this computation for every config change.
- DisplayMetrics dm = new DisplayMetrics();
- mDisplay.getMetrics(dm);
int longSize = dw;
int shortSize = dh;
if (longSize < shortSize) {
@@ -3753,23 +3772,42 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
longSize = (int)(longSize/dm.density);
shortSize = (int)(shortSize/dm.density);
-
+
// These semi-magic numbers define our compatibility modes for
// applications with different screens. Don't change unless you
// make sure to test lots and lots of apps!
if (longSize < 470) {
// This is shorter than an HVGA normal density screen (which
// is 480 pixels on its long side).
- screenLayout = Configuration.SCREENLAYOUT_SMALL;
- } else if (longSize > 490 && shortSize > 330) {
- // This is larger than an HVGA normal density screen (which
- // is 480x320 pixels).
- screenLayout = Configuration.SCREENLAYOUT_LARGE;
+ mScreenLayout = Configuration.SCREENLAYOUT_SIZE_SMALL
+ | Configuration.SCREENLAYOUT_LONG_NO;
} else {
- screenLayout = Configuration.SCREENLAYOUT_NORMAL;
+ // Is this a large screen?
+ if (longSize > 640 && shortSize >= 480) {
+ // VGA or larger screens at medium density are the point
+ // at which we consider it to be a large screen.
+ mScreenLayout = Configuration.SCREENLAYOUT_SIZE_LARGE;
+ } else {
+ mScreenLayout = Configuration.SCREENLAYOUT_SIZE_NORMAL;
+
+ // If this screen is wider than normal HVGA, or taller
+ // than FWVGA, then for old apps we want to run in size
+ // compatibility mode.
+ if (shortSize > 321 || longSize > 570) {
+ mScreenLayout |= Configuration.SCREENLAYOUT_COMPAT_NEEDED;
+ }
+ }
+
+ // Is this a long screen?
+ if (((longSize*3)/5) >= (shortSize-1)) {
+ // Anything wider than WVGA (5:3) is considering to be long.
+ mScreenLayout |= Configuration.SCREENLAYOUT_LONG_YES;
+ } else {
+ mScreenLayout |= Configuration.SCREENLAYOUT_LONG_NO;
+ }
}
}
- config.screenLayout = screenLayout;
+ config.screenLayout = mScreenLayout;
config.keyboardHidden = Configuration.KEYBOARDHIDDEN_NO;
config.hardKeyboardHidden = Configuration.HARDKEYBOARDHIDDEN_NO;
@@ -5845,8 +5883,21 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
public void computeFrameLw(Rect pf, Rect df, Rect cf, Rect vf) {
mHaveFrame = true;
- final int pw = pf.right-pf.left;
- final int ph = pf.bottom-pf.top;
+ final Rect container = mContainingFrame;
+ container.set(pf);
+
+ final Rect display = mDisplayFrame;
+ display.set(df);
+
+ if ((mAttrs.flags & FLAG_COMPATIBLE_WINDOW) != 0) {
+ container.intersect(mCompatibleScreenFrame);
+ if ((mAttrs.flags & FLAG_LAYOUT_NO_LIMITS) == 0) {
+ display.intersect(mCompatibleScreenFrame);
+ }
+ }
+
+ final int pw = container.right - container.left;
+ final int ph = container.bottom - container.top;
int w,h;
if ((mAttrs.flags & mAttrs.FLAG_SCALED) != 0) {
@@ -5857,12 +5908,6 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
h = mAttrs.height== mAttrs.FILL_PARENT ? ph : mRequestedHeight;
}
- final Rect container = mContainingFrame;
- container.set(pf);
-
- final Rect display = mDisplayFrame;
- display.set(df);
-
final Rect content = mContentFrame;
content.set(cf);
@@ -5882,7 +5927,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
// Now make sure the window fits in the overall display.
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;
@@ -6565,24 +6610,45 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
return false;
}
final Rect frame = shownFrame ? mShownFrame : mFrame;
- if (frame.left <= 0 && frame.top <= 0
- && frame.right >= screenWidth
- && frame.bottom >= screenHeight) {
- return true;
+
+ if ((mAttrs.flags & FLAG_COMPATIBLE_WINDOW) != 0) {
+ return frame.left <= mCompatibleScreenFrame.left &&
+ frame.top <= mCompatibleScreenFrame.top &&
+ frame.right >= mCompatibleScreenFrame.right &&
+ frame.bottom >= mCompatibleScreenFrame.bottom;
+ } else {
+ return frame.left <= 0 && frame.top <= 0
+ && frame.right >= screenWidth
+ && frame.bottom >= screenHeight;
}
- return false;
}
- boolean isFullscreenOpaque(int screenWidth, int screenHeight) {
- if (mAttrs.format != PixelFormat.OPAQUE || mSurface == null
- || mAnimation != null || mDrawPending || mCommitDrawPending) {
- return false;
- }
- if (mFrame.left <= 0 && mFrame.top <= 0 &&
- mFrame.right >= screenWidth && mFrame.bottom >= screenHeight) {
- return true;
- }
- return false;
+ /**
+ * Return true if the window is opaque and fully drawn.
+ */
+ boolean isOpaqueDrawn() {
+ return mAttrs.format == PixelFormat.OPAQUE && mSurface != null
+ && mAnimation == null && !mDrawPending && !mCommitDrawPending;
+ }
+
+ boolean needsBackgroundFiller(int screenWidth, int screenHeight) {
+ return
+ // only if the application is requesting compatible window
+ (mAttrs.flags & FLAG_COMPATIBLE_WINDOW) != 0 &&
+ // only if it's visible
+ mHasDrawn && mViewVisibility == View.VISIBLE &&
+ // and only if the application fills the compatible screen
+ mFrame.left <= mCompatibleScreenFrame.left &&
+ mFrame.top <= mCompatibleScreenFrame.top &&
+ mFrame.right >= mCompatibleScreenFrame.right &&
+ mFrame.bottom >= mCompatibleScreenFrame.bottom &&
+ // and starting window do not need background filler
+ mAttrs.type != mAttrs.TYPE_APPLICATION_STARTING;
+ }
+
+ boolean isFullscreen(int screenWidth, int screenHeight) {
+ return mFrame.left <= 0 && mFrame.top <= 0 &&
+ mFrame.right >= screenWidth && mFrame.bottom >= screenHeight;
}
void removeLocked() {
@@ -7190,17 +7256,27 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
public static WindowManager.LayoutParams findAnimations(
ArrayList<AppWindowToken> order,
- ArrayList<AppWindowToken> tokenList1,
- ArrayList<AppWindowToken> tokenList2) {
+ ArrayList<AppWindowToken> openingTokenList1,
+ ArrayList<AppWindowToken> closingTokenList2) {
// We need to figure out which animation to use...
+
+ // First, check if there is a compatible window in opening/closing
+ // apps, and use it if exists.
WindowManager.LayoutParams animParams = null;
int animSrc = 0;
-
+ animParams = findCompatibleWindowParams(openingTokenList1);
+ if (animParams == null) {
+ animParams = findCompatibleWindowParams(closingTokenList2);
+ }
+ if (animParams != null) {
+ return animParams;
+ }
+
//Log.i(TAG, "Looking for animations...");
for (int i=order.size()-1; i>=0; i--) {
AppWindowToken wtoken = order.get(i);
//Log.i(TAG, "Token " + wtoken + " with " + wtoken.windows.size() + " windows");
- if (tokenList1.contains(wtoken) || tokenList2.contains(wtoken)) {
+ if (openingTokenList1.contains(wtoken) || closingTokenList2.contains(wtoken)) {
int j = wtoken.windows.size();
while (j > 0) {
j--;
@@ -7228,6 +7304,21 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
return animParams;
}
+ private static LayoutParams findCompatibleWindowParams(ArrayList<AppWindowToken> tokenList) {
+ for (int appCount = tokenList.size() - 1; appCount >= 0; appCount--) {
+ AppWindowToken wtoken = tokenList.get(appCount);
+ // Just checking one window is sufficient as all windows have the compatible flag
+ // if the application is in compatibility mode.
+ if (wtoken.windows.size() > 0) {
+ WindowManager.LayoutParams params = wtoken.windows.get(0).mAttrs;
+ if ((params.flags & FLAG_COMPATIBLE_WINDOW) != 0) {
+ return params;
+ }
+ }
+ }
+ return null;
+ }
+
// -------------------------------------------------------------
// DummyAnimation
// -------------------------------------------------------------
@@ -8102,6 +8193,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
boolean dimming = false;
boolean covered = false;
boolean syswin = false;
+ boolean backgroundFillerShown = false;
for (i=N-1; i>=0; i--) {
WindowState w = (WindowState)mWindows.get(i);
@@ -8371,11 +8463,39 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
syswin = true;
}
}
- if (w.isFullscreenOpaque(dw, dh)) {
+
+ boolean opaqueDrawn = w.isOpaqueDrawn();
+ if (opaqueDrawn && w.isFullscreen(dw, dh)) {
// This window completely covers everything behind it,
// so we want to leave all of them as unblurred (for
// performance reasons).
obscured = true;
+ } else if (opaqueDrawn && w.needsBackgroundFiller(dw, dh)) {
+ if (SHOW_TRANSACTIONS) Log.d(TAG, "showing background filler");
+ // This window is in compatibility mode, and needs background filler.
+ obscured = true;
+ if (mBackgroundFillerSurface == null) {
+ try {
+ mBackgroundFillerSurface = new Surface(mFxSession, 0,
+ 0, dw, dh,
+ PixelFormat.OPAQUE,
+ Surface.FX_SURFACE_NORMAL);
+ } catch (Exception e) {
+ Log.e(TAG, "Exception creating filler surface", e);
+ }
+ }
+ try {
+ mBackgroundFillerSurface.setPosition(0, 0);
+ mBackgroundFillerSurface.setSize(dw, dh);
+ // Using the same layer as Dim because they will never be shown at the
+ // same time.
+ mBackgroundFillerSurface.setLayer(w.mAnimLayer - 1);
+ mBackgroundFillerSurface.show();
+ } catch (RuntimeException e) {
+ Log.e(TAG, "Exception showing filler surface");
+ }
+ backgroundFillerShown = true;
+ mBackgroundFillerShown = true;
} else if (canBeSeen && !obscured &&
(attrFlags&FLAG_BLUR_BEHIND|FLAG_DIM_BEHIND) != 0) {
if (localLOGV) Log.v(TAG, "Win " + w
@@ -8386,56 +8506,12 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
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 + ": 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);
- }
- }
- }
- 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;
- if (target > mDimTargetAlpha) {
- // This is happening behind the activity UI,
- // so we can make it run a little longer to
- // give a stronger impression without disrupting
- // the user.
- duration *= DIM_DURATION_MULTIPLIER;
- }
- if (duration < 1) {
- // Don't divide by zero
- duration = 1;
+ if (mDimAnimator == null) {
+ mDimAnimator = new DimAnimator(mFxSession);
}
- mDimTargetAlpha = target;
- mDimDeltaPerMs = (mDimTargetAlpha-mDimCurrentAlpha)
- / duration;
+ mDimAnimator.show(dw, dh);
}
+ mDimAnimator.updateParameters(w, currentTime);
}
if ((attrFlags&FLAG_BLUR_BEHIND) != 0) {
if (!blurring) {
@@ -8472,59 +8548,19 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
}
}
-
- if (!dimming && mDimShown) {
- // Time to hide the dim surface... start fading.
- if (mDimTargetAlpha != 0) {
- mLastDimAnimTime = currentTime;
- mDimTargetAlpha = 0;
- mDimDeltaPerMs = (-mDimCurrentAlpha) / DEFAULT_DIM_DURATION;
+
+ if (backgroundFillerShown == false && mBackgroundFillerShown) {
+ mBackgroundFillerShown = false;
+ if (SHOW_TRANSACTIONS) Log.d(TAG, "hiding background filler");
+ try {
+ mBackgroundFillerSurface.hide();
+ } catch (RuntimeException e) {
+ Log.e(TAG, "Exception hiding filler surface", e);
}
}
- if (mDimShown && mLastDimAnimTime != 0) {
- mDimCurrentAlpha += mDimDeltaPerMs
- * (currentTime-mLastDimAnimTime);
- boolean more = true;
- if (mDisplayFrozen) {
- // If the display is frozen, there is no reason to animate.
- more = false;
- } else 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);
- mLastDimAnimTime = currentTime;
- 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 (mDimAnimator != null && mDimAnimator.mDimShown) {
+ animating |= mDimAnimator.updateSurface(dimming, currentTime, mDisplayFrozen);
}
if (!blurring && mBlurShown) {
@@ -9067,11 +9103,11 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
pw.print(" mDisplayEnabled="); pw.println(mDisplayEnabled);
pw.print(" mLayoutNeeded="); pw.print(mLayoutNeeded);
pw.print(" mBlurShown="); pw.println(mBlurShown);
- pw.print(" mDimShown="); pw.print(mDimShown);
- pw.print(" current="); pw.print(mDimCurrentAlpha);
- pw.print(" target="); pw.print(mDimTargetAlpha);
- pw.print(" delta="); pw.print(mDimDeltaPerMs);
- pw.print(" lastAnimTime="); pw.println(mLastDimAnimTime);
+ if (mDimAnimator != null) {
+ mDimAnimator.printTo(pw);
+ } else {
+ pw.print( " no DimAnimator ");
+ }
pw.print(" mInputMethodAnimLayerAdjustment=");
pw.println(mInputMethodAnimLayerAdjustment);
pw.print(" mDisplayFrozen="); pw.print(mDisplayFrozen);
@@ -9112,4 +9148,188 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
synchronized (mKeyguardDisabled) { }
synchronized (mKeyWaiter) { }
}
+
+ /**
+ * DimAnimator class that controls the dim animation. This holds the surface and
+ * all state used for dim animation.
+ */
+ private static class DimAnimator {
+ Surface mDimSurface;
+ boolean mDimShown = false;
+ float mDimCurrentAlpha;
+ float mDimTargetAlpha;
+ float mDimDeltaPerMs;
+ long mLastDimAnimTime;
+
+ DimAnimator (SurfaceSession session) {
+ if (mDimSurface == null) {
+ if (SHOW_TRANSACTIONS) Log.i(TAG, " DIM "
+ + mDimSurface + ": CREATE");
+ try {
+ mDimSurface = new Surface(session, 0, -1, 16, 16, PixelFormat.OPAQUE,
+ Surface.FX_SURFACE_DIM);
+ } catch (Exception e) {
+ Log.e(TAG, "Exception creating Dim surface", e);
+ }
+ }
+ }
+
+ /**
+ * Show the dim surface.
+ */
+ void show(int dw, int dh) {
+ if (SHOW_TRANSACTIONS) Log.i(TAG, " DIM " + mDimSurface + ": SHOW pos=(0,0) (" +
+ dw + "x" + dh + ")");
+ mDimShown = true;
+ try {
+ mDimSurface.setPosition(0, 0);
+ mDimSurface.setSize(dw, dh);
+ mDimSurface.show();
+ } catch (RuntimeException e) {
+ Log.w(TAG, "Failure showing dim surface", e);
+ }
+ }
+
+ /**
+ * Set's the dim surface's layer and update dim parameters that will be used in
+ * {@link updateSurface} after all windows are examined.
+ */
+ void updateParameters(WindowState w, long currentTime) {
+ mDimSurface.setLayer(w.mAnimLayer-1);
+
+ final float target = w.mExiting ? 0 : w.mAttrs.dimAmount;
+ if (SHOW_TRANSACTIONS) Log.i(TAG, "layer=" + (w.mAnimLayer-1) + ", target=" + target);
+ 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;
+ if (target > mDimTargetAlpha) {
+ // This is happening behind the activity UI,
+ // so we can make it run a little longer to
+ // give a stronger impression without disrupting
+ // the user.
+ duration *= DIM_DURATION_MULTIPLIER;
+ }
+ if (duration < 1) {
+ // Don't divide by zero
+ duration = 1;
+ }
+ mDimTargetAlpha = target;
+ mDimDeltaPerMs = (mDimTargetAlpha-mDimCurrentAlpha) / duration;
+ }
+ }
+
+ /**
+ * Updating the surface's alpha. Returns true if the animation continues, or returns
+ * false when the animation is finished and the dim surface is hidden.
+ */
+ boolean updateSurface(boolean dimming, long currentTime, boolean displayFrozen) {
+ if (!dimming) {
+ if (mDimTargetAlpha != 0) {
+ mLastDimAnimTime = currentTime;
+ mDimTargetAlpha = 0;
+ mDimDeltaPerMs = (-mDimCurrentAlpha) / DEFAULT_DIM_DURATION;
+ }
+ }
+
+ boolean animating = false;
+ if (mLastDimAnimTime != 0) {
+ mDimCurrentAlpha += mDimDeltaPerMs
+ * (currentTime-mLastDimAnimTime);
+ boolean more = true;
+ if (displayFrozen) {
+ // If the display is frozen, there is no reason to animate.
+ more = false;
+ } else 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);
+ mLastDimAnimTime = currentTime;
+ 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;
+ }
+ }
+ }
+ return animating;
+ }
+
+ public void printTo(PrintWriter pw) {
+ pw.print(" mDimShown="); pw.print(mDimShown);
+ pw.print(" current="); pw.print(mDimCurrentAlpha);
+ pw.print(" target="); pw.print(mDimTargetAlpha);
+ pw.print(" delta="); pw.print(mDimDeltaPerMs);
+ pw.print(" lastAnimTime="); pw.println(mLastDimAnimTime);
+ }
+ }
+
+ /**
+ * Animation that fade in after 0.5 interpolate time, or fade out in reverse order.
+ * This is used for opening/closing transition for apps in compatible mode.
+ */
+ private static class FadeInOutAnimation extends Animation {
+ int mWidth;
+ boolean mFadeIn;
+
+ public FadeInOutAnimation(boolean fadeIn) {
+ setInterpolator(new AccelerateInterpolator());
+ setDuration(DEFAULT_FADE_IN_OUT_DURATION);
+ mFadeIn = fadeIn;
+ }
+
+ @Override
+ protected void applyTransformation(float interpolatedTime, Transformation t) {
+ float x = interpolatedTime;
+ if (!mFadeIn) {
+ x = 1.0f - x; // reverse the interpolation for fade out
+ }
+ if (x < 0.5) {
+ // move the window out of the screen.
+ t.getMatrix().setTranslate(mWidth, 0);
+ } else {
+ t.getMatrix().setTranslate(0, 0);// show
+ t.setAlpha((x - 0.5f) * 2);
+ }
+ }
+
+ @Override
+ public void initialize(int width, int height, int parentWidth, int parentHeight) {
+ // width is the screen width {@see AppWindowToken#stepAnimatinoLocked}
+ mWidth = width;
+ }
+
+ @Override
+ public int getZAdjustment() {
+ return Animation.ZORDER_TOP;
+ }
+ }
}
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 2fe4dd4..d9c40ec 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -32,6 +32,7 @@ import android.app.ActivityThread;
import android.app.AlertDialog;
import android.app.ApplicationErrorReport;
import android.app.Dialog;
+import android.app.IActivityController;
import android.app.IActivityWatcher;
import android.app.IApplicationThread;
import android.app.IInstrumentationWatcher;
@@ -56,6 +57,7 @@ import android.content.pm.IPackageDataObserver;
import android.content.pm.IPackageManager;
import android.content.pm.InstrumentationInfo;
import android.content.pm.PackageManager;
+import android.content.pm.PathPermission;
import android.content.pm.ProviderInfo;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
@@ -75,6 +77,7 @@ import android.os.Parcel;
import android.os.ParcelFileDescriptor;
import android.os.PowerManager;
import android.os.Process;
+import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
@@ -824,8 +827,11 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
String mOrigDebugApp = null;
boolean mOrigWaitForDebugger = false;
boolean mAlwaysFinishActivities = false;
- IActivityWatcher mWatcher = null;
+ IActivityController mController = null;
+ final RemoteCallbackList<IActivityWatcher> mWatchers
+ = new RemoteCallbackList<IActivityWatcher>();
+
/**
* Callback of last caller to {@link #requestPss}.
*/
@@ -1622,7 +1628,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
/**
* This is a simplified version of topRunningActivityLocked that provides a number of
- * optional skip-over modes. It is intended for use with the ActivityWatcher hook only.
+ * optional skip-over modes. It is intended for use with the ActivityController hook only.
*
* @param token If non-null, any history records matching this token will be skipped.
* @param taskId If non-zero, we'll attempt to skip over records with the same task ID.
@@ -1727,10 +1733,9 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
ensurePackageDexOpt(r.intent.getComponent().getPackageName());
app.thread.scheduleLaunchActivity(new Intent(r.intent), r,
+ System.identityHashCode(r),
r.info, r.icicle, results, newIntents, !andResume,
isNextTransitionForward());
- // Update usage stats for launched activity
- updateUsageStats(r, true);
} catch (RemoteException e) {
if (r.launchFailed) {
// This is the second time we failed -- finish activity
@@ -2183,6 +2188,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
mHandler.sendMessage(msg);
}
+ reportResumedActivity(next);
+
next.thumbnail = null;
setFocusedActivityLocked(next);
next.resumeKeyDispatchingLocked();
@@ -2453,6 +2460,26 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
}
+ private void reportResumedActivity(HistoryRecord r) {
+ //Log.i(TAG, "**** REPORT RESUME: " + r);
+
+ final int identHash = System.identityHashCode(r);
+ updateUsageStats(r, true);
+
+ int i = mWatchers.beginBroadcast();
+ while (i > 0) {
+ i--;
+ IActivityWatcher w = mWatchers.getBroadcastItem(i);
+ if (w != null) {
+ try {
+ w.activityResuming(identHash);
+ } catch (RemoteException e) {
+ }
+ }
+ }
+ mWatchers.finishBroadcast();
+ }
+
/**
* Ensure that the top activity in the stack is resumed.
*
@@ -2641,10 +2668,10 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
EventLog.writeEvent(LOG_AM_RESUME_ACTIVITY,
System.identityHashCode(next),
next.task.taskId, next.shortComponentName);
- updateUsageStats(next, true);
next.app.thread.scheduleResumeActivity(next,
isNextTransitionForward());
+
pauseIfSleepingLocked();
} catch (Exception e) {
@@ -3061,16 +3088,16 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
throw new SecurityException(msg);
}
- if (mWatcher != null) {
+ if (mController != null) {
boolean abort = false;
try {
// The Intent we give to the watcher has the extra data
// stripped off, since it can contain private information.
Intent watchIntent = intent.cloneFilter();
- abort = !mWatcher.activityStarting(watchIntent,
+ abort = !mController.activityStarting(watchIntent,
aInfo.applicationInfo.packageName);
} catch (RemoteException e) {
- mWatcher = null;
+ mController = null;
}
if (abort) {
@@ -3495,8 +3522,6 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
intent = new Intent(intent);
// Collect information about the target of the Intent.
- // Must do this before locking, because resolving the intent
- // may require launching a process to run its content provider.
ActivityInfo aInfo;
try {
ResolveInfo rInfo =
@@ -3630,17 +3655,24 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
}
- final int startActivityInPackage(int uid,
+ public final int startActivityInPackage(int uid,
Intent intent, String resolvedType, IBinder resultTo,
String resultWho, int requestCode, boolean onlyIfNeeded) {
+
+ // This is so super not safe, that only the system (or okay root)
+ // can do it.
+ final int callingUid = Binder.getCallingUid();
+ if (callingUid != 0 && callingUid != Process.myUid()) {
+ throw new SecurityException(
+ "startActivityInPackage only available to the system");
+ }
+
final boolean componentSpecified = intent.getComponent() != null;
// Don't modify the client's object!
intent = new Intent(intent);
// Collect information about the target of the Intent.
- // Must do this before locking, because resolving the intent
- // may require launching a process to run its content provider.
ActivityInfo aInfo;
try {
ResolveInfo rInfo =
@@ -3967,16 +3999,16 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
synchronized(this) {
- if (mWatcher != null) {
+ if (mController != null) {
// Find the first activity that is not finishing.
HistoryRecord next = topRunningActivityLocked(token, 0);
if (next != null) {
// ask watcher if this is allowed
boolean resumeOK = true;
try {
- resumeOK = mWatcher.activityResuming(next.packageName);
+ resumeOK = mController.activityResuming(next.packageName);
} catch (RemoteException e) {
- mWatcher = null;
+ mController = null;
}
if (!resumeOK) {
@@ -4468,9 +4500,9 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
}
- if (mWatcher != null) {
+ if (mController != null) {
try {
- int res = mWatcher.appNotResponding(app.processName,
+ int res = mController.appNotResponding(app.processName,
app.pid, info.toString());
if (res != 0) {
if (res < 0) {
@@ -4486,7 +4518,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
}
} catch (RemoteException e) {
- mWatcher = null;
+ mController = null;
}
}
@@ -6611,7 +6643,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
/**
- * TODO: Add mWatcher hook
+ * TODO: Add mController hook
*/
public void moveTaskToFront(int task) {
enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
@@ -6756,7 +6788,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// If we have a watcher, preflight the move before committing to it. First check
// for *other* available tasks, but if none are available, then try again allowing the
// current task to be selected.
- if (mWatcher != null) {
+ if (mController != null) {
HistoryRecord next = topRunningActivityLocked(null, task);
if (next == null) {
next = topRunningActivityLocked(null, 0);
@@ -6765,9 +6797,9 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// ask watcher if this is allowed
boolean moveOK = true;
try {
- moveOK = mWatcher.activityResuming(next.packageName);
+ moveOK = mController.activityResuming(next.packageName);
} catch (RemoteException e) {
- mWatcher = null;
+ mController = null;
}
if (!moveOK) {
return false;
@@ -7072,6 +7104,27 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
== PackageManager.PERMISSION_GRANTED) {
return null;
}
+
+ PathPermission[] pps = cpi.pathPermissions;
+ if (pps != null) {
+ int i = pps.length;
+ while (i > 0) {
+ i--;
+ PathPermission pp = pps[i];
+ if (checkComponentPermission(pp.getReadPermission(), callingPid, callingUid,
+ cpi.exported ? -1 : cpi.applicationInfo.uid)
+ == PackageManager.PERMISSION_GRANTED
+ && mode == ParcelFileDescriptor.MODE_READ_ONLY || mode == -1) {
+ return null;
+ }
+ if (checkComponentPermission(pp.getWritePermission(), callingPid, callingUid,
+ cpi.exported ? -1 : cpi.applicationInfo.uid)
+ == PackageManager.PERMISSION_GRANTED) {
+ return null;
+ }
+ }
+ }
+
String msg = "Permission Denial: opening provider " + cpi.name
+ " from " + (r != null ? r : "(null)") + " (pid=" + callingPid
+ ", uid=" + callingUid + ") requires "
@@ -7657,14 +7710,22 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
}
- public void setActivityWatcher(IActivityWatcher watcher) {
+ public void setActivityController(IActivityController controller) {
enforceCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER,
- "setActivityWatcher()");
+ "setActivityController()");
synchronized (this) {
- mWatcher = watcher;
+ mController = controller;
}
}
+ public void registerActivityWatcher(IActivityWatcher watcher) {
+ mWatchers.register(watcher);
+ }
+
+ public void unregisterActivityWatcher(IActivityWatcher watcher) {
+ mWatchers.unregister(watcher);
+ }
+
public final void enterSafeMode() {
synchronized(this) {
// It only makes sense to do this before the system is ready
@@ -8225,11 +8286,11 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
//Process.sendSignal(MY_PID, Process.SIGNAL_QUIT);
}
- if (mWatcher != null) {
+ if (mController != null) {
try {
String name = r != null ? r.processName : null;
int pid = r != null ? r.pid : Binder.getCallingPid();
- if (!mWatcher.appCrashed(name, pid,
+ if (!mController.appCrashed(name, pid,
shortMsg, longMsg, crashData)) {
Log.w(TAG, "Force-killing crashed app " + name
+ " at watcher's request");
@@ -8237,7 +8298,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
return 0;
}
} catch (RemoteException e) {
- mWatcher = null;
+ mController = null;
}
}
@@ -8663,7 +8724,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
+ " mDebugTransient=" + mDebugTransient
+ " mOrigWaitForDebugger=" + mOrigWaitForDebugger);
pw.println(" mAlwaysFinishActivities=" + mAlwaysFinishActivities
- + " mWatcher=" + mWatcher);
+ + " mController=" + mController);
}
}
@@ -10810,6 +10871,29 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
mHandler.sendEmptyMessage(UPDATE_TIME_ZONE);
}
+ /*
+ * Prevent non-system code (defined here to be non-persistent
+ * processes) from sending protected broadcasts.
+ */
+ if (callingUid == Process.SYSTEM_UID || callingUid == Process.PHONE_UID
+ || callingUid == Process.SHELL_UID || callingUid == 0) {
+ // Always okay.
+ } else if (callerApp == null || !callerApp.persistent) {
+ try {
+ if (ActivityThread.getPackageManager().isProtectedBroadcast(
+ intent.getAction())) {
+ String msg = "Permission Denial: not allowed to send broadcast "
+ + intent.getAction() + " from pid="
+ + callingPid + ", uid=" + callingUid;
+ Log.w(TAG, msg);
+ throw new SecurityException(msg);
+ }
+ } catch (RemoteException e) {
+ Log.w(TAG, "Remote exception", e);
+ return BROADCAST_SUCCESS;
+ }
+ }
+
// Add to the sticky list if requested.
if (sticky) {
if (checkPermission(android.Manifest.permission.BROADCAST_STICKY,
@@ -11755,10 +11839,12 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
config.reqTouchScreen = mConfiguration.touchscreen;
config.reqKeyboardType = mConfiguration.keyboard;
config.reqNavigation = mConfiguration.navigation;
- if (mConfiguration.navigation != Configuration.NAVIGATION_NONAV) {
+ if (mConfiguration.navigation == Configuration.NAVIGATION_DPAD
+ || mConfiguration.navigation == Configuration.NAVIGATION_TRACKBALL) {
config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_FIVE_WAY_NAV;
}
- if (mConfiguration.keyboard != Configuration.KEYBOARD_UNDEFINED) {
+ if (mConfiguration.keyboard != Configuration.KEYBOARD_UNDEFINED
+ && mConfiguration.keyboard != Configuration.KEYBOARD_NOKEYS) {
config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD;
}
}
diff --git a/services/java/com/android/server/am/BatteryStatsService.java b/services/java/com/android/server/am/BatteryStatsService.java
index 39a1ee0..c834b34 100644
--- a/services/java/com/android/server/am/BatteryStatsService.java
+++ b/services/java/com/android/server/am/BatteryStatsService.java
@@ -41,7 +41,7 @@ public final class BatteryStatsService extends IBatteryStats.Stub {
final BatteryStatsImpl mStats;
Context mContext;
-
+
BatteryStatsService(String filename) {
mStats = new BatteryStatsImpl(filename);
}
diff --git a/services/java/com/android/server/am/UsageStatsService.java b/services/java/com/android/server/am/UsageStatsService.java
index 2d58659..d458911 100755
--- a/services/java/com/android/server/am/UsageStatsService.java
+++ b/services/java/com/android/server/am/UsageStatsService.java
@@ -39,6 +39,7 @@ import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -617,7 +618,7 @@ public final class UsageStatsService extends IUsageStats.Stub {
}
private void collectDumpInfoFLOCK(PrintWriter pw, boolean isCompactOutput,
- boolean deleteAfterPrint) {
+ boolean deleteAfterPrint, HashSet<String> packages) {
List<String> fileList = getUsageStatsFileListFLOCK();
if (fileList == null) {
return;
@@ -633,7 +634,8 @@ public final class UsageStatsService extends IUsageStats.Stub {
String dateStr = file.substring(FILE_PREFIX.length());
try {
Parcel in = getParcelForFile(dFile);
- collectDumpInfoFromParcelFLOCK(in, pw, dateStr, isCompactOutput);
+ collectDumpInfoFromParcelFLOCK(in, pw, dateStr, isCompactOutput,
+ packages);
if (deleteAfterPrint) {
// Delete old file after collecting info only for checkin requests
dFile.delete();
@@ -648,7 +650,7 @@ public final class UsageStatsService extends IUsageStats.Stub {
}
private void collectDumpInfoFromParcelFLOCK(Parcel in, PrintWriter pw,
- String date, boolean isCompactOutput) {
+ String date, boolean isCompactOutput, HashSet<String> packages) {
StringBuilder sb = new StringBuilder(512);
if (isCompactOutput) {
sb.append("D:");
@@ -678,7 +680,10 @@ public final class UsageStatsService extends IUsageStats.Stub {
}
sb.setLength(0);
PkgUsageStatsExtended pus = new PkgUsageStatsExtended(in);
- if (isCompactOutput) {
+ if (packages != null && !packages.contains(pkgName)) {
+ // This package has not been requested -- don't print
+ // anything for it.
+ } else if (isCompactOutput) {
sb.append("P:");
sb.append(pkgName);
sb.append(',');
@@ -765,6 +770,25 @@ public final class UsageStatsService extends IUsageStats.Stub {
return false;
}
+ /**
+ * Searches array of arguments for the specified string's data
+ * @param args array of argument strings
+ * @param value value to search for
+ * @return the string of data after the arg, or null if there is none
+ */
+ private static String scanArgsData(String[] args, String value) {
+ if (args != null) {
+ final int N = args.length;
+ for (int i=0; i<N; i++) {
+ if (value.equals(args[i])) {
+ i++;
+ return i < N ? args[i] : null;
+ }
+ }
+ }
+ return null;
+ }
+
@Override
/*
* The data persisted to file is parsed and the stats are computed.
@@ -773,6 +797,7 @@ public final class UsageStatsService extends IUsageStats.Stub {
final boolean isCheckinRequest = scanArgs(args, "--checkin");
final boolean isCompactOutput = isCheckinRequest || scanArgs(args, "-c");
final boolean deleteAfterPrint = isCheckinRequest || scanArgs(args, "-d");
+ final String rawPackages = scanArgsData(args, "--packages");
// Make sure the current stats are written to the file. This
// doesn't need to be done if we are deleting files after printing,
@@ -781,8 +806,27 @@ public final class UsageStatsService extends IUsageStats.Stub {
writeStatsToFile(true);
}
+ HashSet<String> packages = null;
+ if (rawPackages != null) {
+ if (!"*".equals(rawPackages)) {
+ // A * is a wildcard to show all packages.
+ String[] names = rawPackages.split(",");
+ for (String n : names) {
+ if (packages == null) {
+ packages = new HashSet<String>();
+ }
+ packages.add(n);
+ }
+ }
+ } else if (isCheckinRequest) {
+ // If checkin doesn't specify any packages, then we simply won't
+ // show anything.
+ Log.w(TAG, "Checkin without packages");
+ return;
+ }
+
synchronized (mFileLock) {
- collectDumpInfoFLOCK(pw, isCompactOutput, deleteAfterPrint);
+ collectDumpInfoFLOCK(pw, isCompactOutput, deleteAfterPrint, packages);
}
}
diff --git a/services/java/com/android/server/status/StatusBarPolicy.java b/services/java/com/android/server/status/StatusBarPolicy.java
index 7a8d4e5..a4b47b5 100644
--- a/services/java/com/android/server/status/StatusBarPolicy.java
+++ b/services/java/com/android/server/status/StatusBarPolicy.java
@@ -626,7 +626,9 @@ public class StatusBarPolicy {
&& mBatteryThreshold > BATTERY_THRESHOLD_WARNING))) {
// Broadcast the low battery warning
mSentLowBatteryBroadcast = true;
- mContext.sendBroadcast(new Intent(Intent.ACTION_BATTERY_LOW));
+ Intent batIntent = new Intent(Intent.ACTION_BATTERY_LOW);
+ batIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+ mContext.sendBroadcast(batIntent);
if (SHOW_LOW_BATTERY_WARNING) {
if (false) {
@@ -644,7 +646,9 @@ public class StatusBarPolicy {
} else if (mBatteryThreshold < BATTERY_THRESHOLD_WARNING) {
if (mSentLowBatteryBroadcast == true) {
mSentLowBatteryBroadcast = false;
- mContext.sendBroadcast(new Intent(Intent.ACTION_BATTERY_OKAY));
+ Intent batIntent = new Intent(Intent.ACTION_BATTERY_OKAY);
+ batIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+ mContext.sendBroadcast(batIntent);
}
if (SHOW_LOW_BATTERY_WARNING) {
if (mLowBatteryDialog != null) {