summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--api/current.txt26
-rw-r--r--core/java/android/app/ActivityThread.java354
-rw-r--r--core/java/android/app/AppOpsManager.java154
-rw-r--r--core/java/android/app/ContextImpl.java13
-rw-r--r--core/java/android/app/LoadedApk.java8
-rw-r--r--core/java/android/app/ResourcesManager.java300
-rw-r--r--core/java/android/content/res/Resources.java7
-rw-r--r--core/java/android/content/res/ResourcesKey.java89
-rw-r--r--core/java/android/os/BatteryStats.java11
-rw-r--r--core/java/android/os/UserHandle.java10
-rw-r--r--core/java/android/view/GraphicBuffer.java69
-rw-r--r--core/java/android/view/HardwareRenderer.java1
-rw-r--r--core/java/android/view/transition/Fade.java13
-rw-r--r--core/java/android/view/transition/TransitionGroup.java2
-rw-r--r--core/java/android/widget/CompoundButton.java2
-rw-r--r--core/java/com/android/internal/inputmethod/InputMethodUtils.java11
-rw-r--r--core/java/com/android/internal/view/menu/ListMenuItemView.java9
-rw-r--r--docs/html/sdk/installing/studio-tips.jd2
-rw-r--r--graphics/java/android/graphics/Matrix.java42
-rw-r--r--packages/SystemUI/res/anim/heads_up_enter.xml (renamed from packages/SystemUI/res/anim/priority_alert_enter.xml)0
-rw-r--r--packages/SystemUI/res/anim/heads_up_exit.xml (renamed from packages/SystemUI/res/anim/priority_alert_exit.xml)0
-rw-r--r--packages/SystemUI/res/drawable/heads_up_notification_row_bg.xml (renamed from packages/SystemUI/res/drawable/intruder_row_bg.xml)5
-rw-r--r--packages/SystemUI/res/drawable/heads_up_window_bg.9.png (renamed from packages/SystemUI/res/drawable/intruder_window_bg.9.png)bin272 -> 272 bytes
-rw-r--r--packages/SystemUI/res/layout/heads_up.xml (renamed from packages/SystemUI/res/layout/intruder_alert.xml)12
-rw-r--r--packages/SystemUI/res/values/colors.xml2
-rw-r--r--packages/SystemUI/res/values/styles.xml8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java77
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java125
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java (renamed from packages/SystemUI/src/com/android/systemui/statusbar/policy/IntruderAlertView.java)47
-rw-r--r--services/java/com/android/server/InputMethodManagerService.java13
-rw-r--r--services/java/com/android/server/LocationManagerService.java24
-rw-r--r--services/java/com/android/server/am/ActivityManagerService.java10
-rw-r--r--services/java/com/android/server/am/BroadcastQueue.java4
-rw-r--r--services/java/com/android/server/am/ProcessRecord.java10
-rw-r--r--services/java/com/android/server/am/ProcessTracker.java444
-rw-r--r--services/java/com/android/server/pm/KeySetManager.java45
-rw-r--r--services/java/com/android/server/pm/UserManagerService.java25
-rw-r--r--tests/CanvasCompare/res/layout/manual_layout.xml2
-rw-r--r--tests/CanvasCompare/src/com/android/test/hwuicompare/ManualActivity.java1
-rw-r--r--tests/CanvasCompare/src/com/android/test/hwuicompare/NearestImageView.java47
-rw-r--r--tests/TransitionTests/AndroidManifest.xml7
-rw-r--r--tests/TransitionTests/res/layout/crossfade_image.xml28
-rw-r--r--tests/TransitionTests/src/com/android/transitiontests/CrossfadeImage.java68
-rw-r--r--wifi/java/android/net/wifi/WifiNative.java4
-rw-r--r--wifi/java/android/net/wifi/WifiStateMachine.java2
45 files changed, 1411 insertions, 722 deletions
diff --git a/api/current.txt b/api/current.txt
index cf1d923df6b6..e5156e8328c4 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -3139,6 +3139,32 @@ package android.app {
ctor public AliasActivity();
}
+ public class AppOpsManager {
+ method public int checkOp(int, int, java.lang.String);
+ method public int checkOpNoThrow(int, int, java.lang.String);
+ method public void finishOp(int, int, java.lang.String);
+ method public void finishOp(int);
+ method public int noteOp(int, int, java.lang.String);
+ method public int noteOpNoThrow(int, int, java.lang.String);
+ method public static java.lang.String opToName(int);
+ method public int startOp(int, int, java.lang.String);
+ method public int startOpNoThrow(int, int, java.lang.String);
+ method public void startWatchingMode(int, java.lang.String, android.app.AppOpsManager.Callback);
+ method public void stopWatchingMode(android.app.AppOpsManager.Callback);
+ field public static final int MODE_ALLOWED = 0; // 0x0
+ field public static final int MODE_ERRORED = 2; // 0x2
+ field public static final int MODE_IGNORED = 1; // 0x1
+ field public static final int OP_COARSE_LOCATION = 0; // 0x0
+ field public static final int OP_FINE_LOCATION = 1; // 0x1
+ field public static final int OP_GPS = 2; // 0x2
+ field public static final int OP_MONITOR_LOCATION = 41; // 0x29
+ field public static final int OP_NONE = -1; // 0xffffffff
+ }
+
+ public static abstract interface AppOpsManager.Callback {
+ method public abstract void opChanged(int, java.lang.String);
+ }
+
public class Application extends android.content.ContextWrapper implements android.content.ComponentCallbacks2 {
ctor public Application();
method public void onConfigurationChanged(android.content.res.Configuration);
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index a23f3044307c..b24aeb017109 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -16,8 +16,6 @@
package android.app;
-import static android.view.DisplayAdjustments.DEVELOPMENT_RESOURCES_DEPEND_ON_ACTIVITY_TOKEN;
-
import android.app.backup.BackupAgent;
import android.content.BroadcastReceiver;
import android.content.ComponentCallbacks2;
@@ -77,7 +75,6 @@ import android.util.Log;
import android.util.LogPrinter;
import android.util.PrintWriterPrinter;
import android.util.Slog;
-import android.view.DisplayAdjustments;
import android.view.Display;
import android.view.HardwareRenderer;
import android.view.View;
@@ -150,7 +147,7 @@ public final class ActivityThread {
public static final boolean DEBUG_BROADCAST = false;
private static final boolean DEBUG_RESULTS = false;
private static final boolean DEBUG_BACKUP = false;
- private static final boolean DEBUG_CONFIGURATION = false;
+ public static final boolean DEBUG_CONFIGURATION = false;
private static final boolean DEBUG_SERVICE = false;
private static final boolean DEBUG_MEMORY_TRIM = false;
private static final boolean DEBUG_PROVIDER = false;
@@ -182,8 +179,6 @@ public final class ActivityThread {
boolean mDensityCompatMode;
Configuration mConfiguration;
Configuration mCompatConfiguration;
- Configuration mResConfiguration;
- CompatibilityInfo mResCompatibilityInfo;
Application mInitialApplication;
final ArrayList<Application> mAllApplications
= new ArrayList<Application>();
@@ -212,14 +207,12 @@ public final class ActivityThread {
= new HashMap<String, WeakReference<LoadedApk>>();
final HashMap<String, WeakReference<LoadedApk>> mResourcePackages
= new HashMap<String, WeakReference<LoadedApk>>();
- final HashMap<DisplayAdjustments, DisplayMetrics> mDefaultDisplayMetrics
- = new HashMap<DisplayAdjustments, DisplayMetrics>();
- final HashMap<ResourcesKey, WeakReference<Resources> > mActiveResources
- = new HashMap<ResourcesKey, WeakReference<Resources> >();
final ArrayList<ActivityClientRecord> mRelaunchingActivities
= new ArrayList<ActivityClientRecord>();
Configuration mPendingConfiguration = null;
+ private final ResourcesManager mResourcesManager;
+
private static final class ProviderKey {
final String authority;
final int userId;
@@ -555,7 +548,7 @@ public final class ActivityThread {
private static final int ACTIVITY_THREAD_CHECKIN_VERSION = 3;
private void updatePendingConfiguration(Configuration config) {
- synchronized (mPackages) {
+ synchronized (mResourcesManager) {
if (mPendingConfiguration == null ||
mPendingConfiguration.isOtherSeqNewer(config)) {
mPendingConfiguration = config;
@@ -1616,72 +1609,6 @@ public final class ActivityThread {
}
}
- private static class ResourcesKey {
- final private String mResDir;
- final private int mDisplayId;
- final private Configuration mOverrideConfiguration;
- final private float mScale;
- final private int mHash;
- final private IBinder mToken;
-
- ResourcesKey(String resDir, int displayId, Configuration overrideConfiguration,
- float scale, IBinder token) {
- mResDir = resDir;
- mDisplayId = displayId;
- if (overrideConfiguration != null) {
- if (Configuration.EMPTY.equals(overrideConfiguration)) {
- overrideConfiguration = null;
- }
- }
- mOverrideConfiguration = overrideConfiguration;
- mScale = scale;
- int hash = 17;
- hash = 31 * hash + mResDir.hashCode();
- hash = 31 * hash + mDisplayId;
- hash = 31 * hash + (mOverrideConfiguration != null
- ? mOverrideConfiguration.hashCode() : 0);
- hash = 31 * hash + Float.floatToIntBits(mScale);
- if (DEVELOPMENT_RESOURCES_DEPEND_ON_ACTIVITY_TOKEN) {
- mToken = token;
- hash = 31 * hash + (mToken == null ? 0 : mToken.hashCode());
- } else {
- mToken = null;
- }
- mHash = hash;
- }
-
- @Override
- public int hashCode() {
- return mHash;
- }
-
- @Override
- public boolean equals(Object obj) {
- if (!(obj instanceof ResourcesKey)) {
- return false;
- }
- ResourcesKey peer = (ResourcesKey) obj;
- if (!mResDir.equals(peer.mResDir)) {
- return false;
- }
- if (mDisplayId != peer.mDisplayId) {
- return false;
- }
- if (mOverrideConfiguration != peer.mOverrideConfiguration) {
- if (mOverrideConfiguration == null || peer.mOverrideConfiguration == null) {
- return false;
- }
- if (!mOverrideConfiguration.equals(peer.mOverrideConfiguration)) {
- return false;
- }
- }
- if (mScale != peer.mScale) {
- return false;
- }
- return true;
- }
- }
-
public static ActivityThread currentActivityThread() {
return sCurrentActivityThread;
}
@@ -1715,49 +1642,6 @@ public final class ActivityThread {
return sPackageManager;
}
- private void flushDisplayMetricsLocked() {
- mDefaultDisplayMetrics.clear();
- }
-
- DisplayMetrics getDisplayMetricsLocked(int displayId) {
- return getDisplayMetricsLocked(displayId, DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS);
- }
-
- DisplayMetrics getDisplayMetricsLocked(int displayId, DisplayAdjustments daj) {
- boolean isDefaultDisplay = (displayId == Display.DEFAULT_DISPLAY);
- DisplayMetrics dm = isDefaultDisplay ? mDefaultDisplayMetrics.get(daj) : null;
- if (dm != null) {
- return dm;
- }
- dm = new DisplayMetrics();
-
- DisplayManagerGlobal displayManager = DisplayManagerGlobal.getInstance();
- if (displayManager == null) {
- // may be null early in system startup
- dm.setToDefaults();
- return dm;
- }
-
- if (isDefaultDisplay) {
- mDefaultDisplayMetrics.put(daj, dm);
- }
-
- Display d = displayManager.getCompatibleDisplay(displayId, daj);
- if (d != null) {
- d.getMetrics(dm);
- } else {
- // Display no longer exists
- // FIXME: This would not be a problem if we kept the Display object around
- // instead of using the raw display id everywhere. The Display object caches
- // its information even after the display has been removed.
- dm.setToDefaults();
- }
- //Slog.i("foo", "New metrics: w=" + metrics.widthPixels + " h="
- // + metrics.heightPixels + " den=" + metrics.density
- // + " xdpi=" + metrics.xdpi + " ydpi=" + metrics.ydpi);
- return dm;
- }
-
private Configuration mMainThreadConfig = new Configuration();
Configuration applyConfigCompatMainThread(int displayDensity, Configuration config,
CompatibilityInfo compat) {
@@ -1773,90 +1657,12 @@ public final class ActivityThread {
}
/**
- * Creates the top level Resources for applications with the given compatibility info.
- *
- * @param resDir the resource directory.
- * @param compatInfo the compability info. Must not be null.
- * @param token the application token for determining stack bounds.
- */
- Resources getTopLevelResources(String resDir, int displayId,
- Configuration overrideConfiguration, CompatibilityInfo compatInfo, IBinder token) {
- final float scale = compatInfo.applicationScale;
- ResourcesKey key = new ResourcesKey(resDir, displayId, overrideConfiguration, scale,
- token);
- Resources r;
- synchronized (mPackages) {
- // Resources is app scale dependent.
- if (false) {
- Slog.w(TAG, "getTopLevelResources: " + resDir + " / " + scale);
- }
- WeakReference<Resources> wr = mActiveResources.get(key);
- r = wr != null ? wr.get() : null;
- //if (r != null) Slog.i(TAG, "isUpToDate " + resDir + ": " + r.getAssets().isUpToDate());
- if (r != null && r.getAssets().isUpToDate()) {
- if (false) {
- Slog.w(TAG, "Returning cached resources " + r + " " + resDir
- + ": appScale=" + r.getCompatibilityInfo().applicationScale);
- }
- return r;
- }
- }
-
- //if (r != null) {
- // Slog.w(TAG, "Throwing away out-of-date resources!!!! "
- // + r + " " + resDir);
- //}
-
- AssetManager assets = new AssetManager();
- if (assets.addAssetPath(resDir) == 0) {
- return null;
- }
-
- //Slog.i(TAG, "Resource: key=" + key + ", display metrics=" + metrics);
- DisplayMetrics dm = getDisplayMetricsLocked(displayId);
- Configuration config;
- boolean isDefaultDisplay = (displayId == Display.DEFAULT_DISPLAY);
- if (!isDefaultDisplay || key.mOverrideConfiguration != null) {
- config = new Configuration(getConfiguration());
- if (!isDefaultDisplay) {
- applyNonDefaultDisplayMetricsToConfigurationLocked(dm, config);
- }
- if (key.mOverrideConfiguration != null) {
- config.updateFrom(key.mOverrideConfiguration);
- }
- } else {
- config = getConfiguration();
- }
- r = new Resources(assets, dm, config, compatInfo, token);
- if (false) {
- Slog.i(TAG, "Created app resources " + resDir + " " + r + ": "
- + r.getConfiguration() + " appScale="
- + r.getCompatibilityInfo().applicationScale);
- }
-
- synchronized (mPackages) {
- WeakReference<Resources> wr = mActiveResources.get(key);
- Resources existing = wr != null ? wr.get() : null;
- if (existing != null && existing.getAssets().isUpToDate()) {
- // Someone else already created the resources while we were
- // unlocked; go ahead and use theirs.
- r.getAssets().close();
- return existing;
- }
-
- // XXX need to remove entries when weak references go away
- mActiveResources.put(key, new WeakReference<Resources>(r));
- return r;
- }
- }
-
- /**
* Creates the top level resources for the given package.
*/
Resources getTopLevelResources(String resDir,
int displayId, Configuration overrideConfiguration,
LoadedApk pkgInfo) {
- return getTopLevelResources(resDir, displayId, overrideConfiguration,
+ return mResourcesManager.getTopLevelResources(resDir, displayId, overrideConfiguration,
pkgInfo.getCompatibilityInfo(), null);
}
@@ -1871,7 +1677,7 @@ public final class ActivityThread {
public final LoadedApk getPackageInfo(String packageName, CompatibilityInfo compatInfo,
int flags, int userId) {
- synchronized (mPackages) {
+ synchronized (mResourcesManager) {
WeakReference<LoadedApk> ref;
if ((flags&Context.CONTEXT_INCLUDE_CODE) != 0) {
ref = mPackages.get(packageName);
@@ -1941,7 +1747,7 @@ public final class ActivityThread {
}
public final LoadedApk peekPackageInfo(String packageName, boolean includeCode) {
- synchronized (mPackages) {
+ synchronized (mResourcesManager) {
WeakReference<LoadedApk> ref;
if (includeCode) {
ref = mPackages.get(packageName);
@@ -1954,7 +1760,7 @@ public final class ActivityThread {
private LoadedApk getPackageInfo(ApplicationInfo aInfo, CompatibilityInfo compatInfo,
ClassLoader baseLoader, boolean securityViolation, boolean includeCode) {
- synchronized (mPackages) {
+ synchronized (mResourcesManager) {
WeakReference<LoadedApk> ref;
if (includeCode) {
ref = mPackages.get(aInfo.packageName);
@@ -1986,6 +1792,7 @@ public final class ActivityThread {
}
ActivityThread() {
+ mResourcesManager = ResourcesManager.getInstance();
}
public ApplicationThread getApplicationThread()
@@ -1998,10 +1805,6 @@ public final class ActivityThread {
return mInstrumentation;
}
- public Configuration getConfiguration() {
- return mResConfiguration;
- }
-
public boolean isProfiling() {
return mProfiler != null && mProfiler.profileFile != null
&& mProfiler.profileFd == null;
@@ -2031,8 +1834,8 @@ public final class ActivityThread {
LoadedApk info = new LoadedApk(this, "android", context, null,
CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO);
context.init(info, null, this);
- context.getResources().updateConfiguration(getConfiguration(),
- getDisplayMetricsLocked(Display.DEFAULT_DISPLAY));
+ context.getResources().updateConfiguration(mResourcesManager.getConfiguration(),
+ mResourcesManager.getDisplayMetricsLocked(Display.DEFAULT_DISPLAY));
mSystemContext = context;
//Slog.i(TAG, "Created system resources " + context.getResources()
// + ": " + context.getResources().getConfiguration());
@@ -3434,7 +3237,7 @@ public final class ActivityThread {
}
private void handleSetCoreSettings(Bundle coreSettings) {
- synchronized (mPackages) {
+ synchronized (mResourcesManager) {
mCoreSettings = coreSettings;
}
}
@@ -3524,7 +3327,7 @@ public final class ActivityThread {
private ActivityClientRecord performDestroyActivity(IBinder token, boolean finishing,
int configChanges, boolean getNonConfigInstance) {
ActivityClientRecord r = mActivities.get(token);
- Class activityClass = null;
+ Class<? extends Activity> activityClass = null;
if (localLOGV) Slog.v(TAG, "Performing finish of " + r);
if (r != null) {
activityClass = r.activity.getClass();
@@ -3679,7 +3482,7 @@ public final class ActivityThread {
boolean fromServer) {
ActivityClientRecord target = null;
- synchronized (mPackages) {
+ synchronized (mResourcesManager) {
for (int i=0; i<mRelaunchingActivities.size(); i++) {
ActivityClientRecord r = mRelaunchingActivities.get(i);
if (r.token == token) {
@@ -3740,7 +3543,7 @@ public final class ActivityThread {
// First: make sure we have the most recent configuration and most
// recent version of the activity, or skip it if some previous call
// had taken a more recent version.
- synchronized (mPackages) {
+ synchronized (mResourcesManager) {
int N = mRelaunchingActivities.size();
IBinder token = tmp.token;
tmp = null;
@@ -3869,7 +3672,7 @@ public final class ActivityThread {
ArrayList<ComponentCallbacks2> callbacks
= new ArrayList<ComponentCallbacks2>();
- synchronized (mPackages) {
+ synchronized (mResourcesManager) {
final int N = mAllApplications.size();
for (int i=0; i<N; i++) {
callbacks.add(mAllApplications.get(i));
@@ -3963,114 +3766,18 @@ public final class ActivityThread {
}
public final void applyConfigurationToResources(Configuration config) {
- synchronized (mPackages) {
- applyConfigurationToResourcesLocked(config, null);
+ synchronized (mResourcesManager) {
+ mResourcesManager.applyConfigurationToResourcesLocked(config, null);
}
}
- final boolean applyConfigurationToResourcesLocked(Configuration config,
- CompatibilityInfo compat) {
- if (mResConfiguration == null) {
- mResConfiguration = new Configuration();
- }
- if (!mResConfiguration.isOtherSeqNewer(config) && compat == null) {
- if (DEBUG_CONFIGURATION) Slog.v(TAG, "Skipping new config: curSeq="
- + mResConfiguration.seq + ", newSeq=" + config.seq);
- return false;
- }
- int changes = mResConfiguration.updateFrom(config);
- flushDisplayMetricsLocked();
- DisplayMetrics defaultDisplayMetrics = getDisplayMetricsLocked(Display.DEFAULT_DISPLAY);
-
- if (compat != null && (mResCompatibilityInfo == null ||
- !mResCompatibilityInfo.equals(compat))) {
- mResCompatibilityInfo = compat;
- changes |= ActivityInfo.CONFIG_SCREEN_LAYOUT
- | ActivityInfo.CONFIG_SCREEN_SIZE
- | ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE;
- }
-
- // set it for java, this also affects newly created Resources
- if (config.locale != null) {
- Locale.setDefault(config.locale);
- }
-
- Resources.updateSystemConfiguration(config, defaultDisplayMetrics, compat);
-
- ApplicationPackageManager.configurationChanged();
- //Slog.i(TAG, "Configuration changed in " + currentPackageName());
-
- Configuration tmpConfig = null;
-
- Iterator<Map.Entry<ResourcesKey, WeakReference<Resources>>> it =
- mActiveResources.entrySet().iterator();
- while (it.hasNext()) {
- Map.Entry<ResourcesKey, WeakReference<Resources>> entry = it.next();
- Resources r = entry.getValue().get();
- if (r != null) {
- if (DEBUG_CONFIGURATION) Slog.v(TAG, "Changing resources "
- + r + " config to: " + config);
- int displayId = entry.getKey().mDisplayId;
- boolean isDefaultDisplay = (displayId == Display.DEFAULT_DISPLAY);
- DisplayMetrics dm = defaultDisplayMetrics;
- Configuration overrideConfig = entry.getKey().mOverrideConfiguration;
- if (!isDefaultDisplay || overrideConfig != null) {
- if (tmpConfig == null) {
- tmpConfig = new Configuration();
- }
- tmpConfig.setTo(config);
- if (!isDefaultDisplay) {
- dm = getDisplayMetricsLocked(displayId);
- applyNonDefaultDisplayMetricsToConfigurationLocked(dm, tmpConfig);
- }
- if (overrideConfig != null) {
- tmpConfig.updateFrom(overrideConfig);
- }
- r.updateConfiguration(tmpConfig, dm, compat);
- } else {
- r.updateConfiguration(config, dm, compat);
- }
- //Slog.i(TAG, "Updated app resources " + v.getKey()
- // + " " + r + ": " + r.getConfiguration());
- } else {
- //Slog.i(TAG, "Removing old resources " + v.getKey());
- it.remove();
- }
- }
-
- return changes != 0;
- }
-
- final void applyNonDefaultDisplayMetricsToConfigurationLocked(
- DisplayMetrics dm, Configuration config) {
- config.touchscreen = Configuration.TOUCHSCREEN_NOTOUCH;
- config.densityDpi = dm.densityDpi;
- config.screenWidthDp = (int)(dm.widthPixels / dm.density);
- config.screenHeightDp = (int)(dm.heightPixels / dm.density);
- int sl = Configuration.resetScreenLayout(config.screenLayout);
- if (dm.widthPixels > dm.heightPixels) {
- config.orientation = Configuration.ORIENTATION_LANDSCAPE;
- config.screenLayout = Configuration.reduceScreenLayout(sl,
- config.screenWidthDp, config.screenHeightDp);
- } else {
- config.orientation = Configuration.ORIENTATION_PORTRAIT;
- config.screenLayout = Configuration.reduceScreenLayout(sl,
- config.screenHeightDp, config.screenWidthDp);
- }
- config.smallestScreenWidthDp = config.screenWidthDp; // assume screen does not rotate
- config.compatScreenWidthDp = config.screenWidthDp;
- config.compatScreenHeightDp = config.screenHeightDp;
- config.compatSmallestScreenWidthDp = config.smallestScreenWidthDp;
- }
-
final Configuration applyCompatConfiguration(int displayDensity) {
Configuration config = mConfiguration;
if (mCompatConfiguration == null) {
mCompatConfiguration = new Configuration();
}
mCompatConfiguration.setTo(mConfiguration);
- if (mResCompatibilityInfo != null && !mResCompatibilityInfo.supportsScreen()) {
- mResCompatibilityInfo.applyToConfiguration(displayDensity, mCompatConfiguration);
+ if (mResourcesManager.applyCompatConfiguration(displayDensity, mCompatConfiguration)) {
config = mCompatConfiguration;
}
return config;
@@ -4080,7 +3787,7 @@ public final class ActivityThread {
int configDiff = 0;
- synchronized (mPackages) {
+ synchronized (mResourcesManager) {
if (mPendingConfiguration != null) {
if (!mPendingConfiguration.isOtherSeqNewer(config)) {
config = mPendingConfiguration;
@@ -4096,9 +3803,9 @@ public final class ActivityThread {
if (DEBUG_CONFIGURATION) Slog.v(TAG, "Handle configuration changed: "
+ config);
-
- applyConfigurationToResourcesLocked(config, compat);
-
+
+ mResourcesManager.applyConfigurationToResourcesLocked(config, compat);
+
if (mConfiguration == null) {
mConfiguration = new Configuration();
}
@@ -4348,7 +4055,7 @@ public final class ActivityThread {
* reflect configuration changes. The configuration object passed
* in AppBindData can be safely assumed to be up to date
*/
- applyConfigurationToResourcesLocked(data.config, data.compatInfo);
+ mResourcesManager.applyConfigurationToResourcesLocked(data.config, data.compatInfo);
mCurDefaultDisplayDpi = data.config.densityDpi;
applyCompatConfiguration(mCurDefaultDisplayDpi);
@@ -5060,6 +4767,7 @@ public final class ActivityThread {
mSystemThread = system;
if (!system) {
ViewRootImpl.addFirstDrawHandler(new Runnable() {
+ @Override
public void run() {
ensureJitEnabled();
}
@@ -5096,12 +4804,13 @@ public final class ActivityThread {
DropBox.setReporter(new DropBoxReporter());
ViewRootImpl.addConfigCallback(new ComponentCallbacks2() {
+ @Override
public void onConfigurationChanged(Configuration newConfig) {
- synchronized (mPackages) {
+ synchronized (mResourcesManager) {
// We need to apply this change to the resources
// immediately, because upon returning the view
// hierarchy will be informed about it.
- if (applyConfigurationToResourcesLocked(newConfig, null)) {
+ if (mResourcesManager.applyConfigurationToResourcesLocked(newConfig, null)) {
// This actually changed the resources! Tell
// everyone about it.
if (mPendingConfiguration == null ||
@@ -5113,8 +4822,10 @@ public final class ActivityThread {
}
}
}
+ @Override
public void onLowMemory() {
}
+ @Override
public void onTrimMemory(int level) {
}
});
@@ -5134,12 +4845,11 @@ public final class ActivityThread {
}
public int getIntCoreSetting(String key, int defaultValue) {
- synchronized (mPackages) {
+ synchronized (mResourcesManager) {
if (mCoreSettings != null) {
return mCoreSettings.getInt(key, defaultValue);
- } else {
- return defaultValue;
}
+ return defaultValue;
}
}
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 32bb71e33388..de94bb7c0401 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -33,21 +33,22 @@ import android.os.RemoteException;
/**
* API for interacting with "application operation" tracking. Allows you to:
*
- * - Note when operations are happening, and find out if they are allowed for the current caller.
- * - Disallow specific apps from doing specific operations.
- * - Collect all of the current information about operations that have been executed or are not
- * being allowed.
- * - Monitor for changes in whether an operation is allowed.
+ * <ul>
+ * <li> Note when operations are happening, and find out if they are allowed for the current
+ * caller.</li>
+ * <li> Disallow specific apps from doing specific operations.</li>
+ * <li> Collect all of the current information about operations that have been executed or are not
+ * being allowed.</li>
+ * <li> Monitor for changes in whether an operation is allowed.</li>
+ * </ul>
*
- * Each operation is identified by a single integer; these integers are a fixed set of
+ * <p>Each operation is identified by a single integer; these integers are a fixed set of
* operations, enumerated by the OP_* constants.
*
- * When checking operations, the result is a "mode" integer indicating the current setting
+ * <p></p>When checking operations, the result is a "mode" integer indicating the current setting
* for the operation under that caller: MODE_ALLOWED, MODE_IGNORED (don't execute the operation but
* fake its behavior enough so that the caller doesn't crash), MODE_ERRORED (through a
* SecurityException back to the caller; the normal operation calls will do this for you).
- *
- * @hide
*/
public class AppOpsManager {
final Context mContext;
@@ -63,50 +64,95 @@ public class AppOpsManager {
// - increment _NUM_OP
// - add rows to sOpToSwitch, sOpNames, sOpPerms
// - add descriptive strings to Settings/res/values/arrays.xml
+
+ /** No operation specified. */
public static final int OP_NONE = -1;
+ /** Access to coarse location information. */
public static final int OP_COARSE_LOCATION = 0;
+ /** Access to fine location information. */
public static final int OP_FINE_LOCATION = 1;
+ /** Causing GPS to run. */
public static final int OP_GPS = 2;
+ /** @hide */
public static final int OP_VIBRATE = 3;
+ /** @hide */
public static final int OP_READ_CONTACTS = 4;
+ /** @hide */
public static final int OP_WRITE_CONTACTS = 5;
+ /** @hide */
public static final int OP_READ_CALL_LOG = 6;
+ /** @hide */
public static final int OP_WRITE_CALL_LOG = 7;
+ /** @hide */
public static final int OP_READ_CALENDAR = 8;
+ /** @hide */
public static final int OP_WRITE_CALENDAR = 9;
+ /** @hide */
public static final int OP_WIFI_SCAN = 10;
+ /** @hide */
public static final int OP_POST_NOTIFICATION = 11;
+ /** @hide */
public static final int OP_NEIGHBORING_CELLS = 12;
+ /** @hide */
public static final int OP_CALL_PHONE = 13;
+ /** @hide */
public static final int OP_READ_SMS = 14;
+ /** @hide */
public static final int OP_WRITE_SMS = 15;
+ /** @hide */
public static final int OP_RECEIVE_SMS = 16;
+ /** @hide */
public static final int OP_RECEIVE_EMERGECY_SMS = 17;
+ /** @hide */
public static final int OP_RECEIVE_MMS = 18;
+ /** @hide */
public static final int OP_RECEIVE_WAP_PUSH = 19;
+ /** @hide */
public static final int OP_SEND_SMS = 20;
+ /** @hide */
public static final int OP_READ_ICC_SMS = 21;
+ /** @hide */
public static final int OP_WRITE_ICC_SMS = 22;
+ /** @hide */
public static final int OP_WRITE_SETTINGS = 23;
+ /** @hide */
public static final int OP_SYSTEM_ALERT_WINDOW = 24;
+ /** @hide */
public static final int OP_ACCESS_NOTIFICATIONS = 25;
+ /** @hide */
public static final int OP_CAMERA = 26;
+ /** @hide */
public static final int OP_RECORD_AUDIO = 27;
+ /** @hide */
public static final int OP_PLAY_AUDIO = 28;
+ /** @hide */
public static final int OP_READ_CLIPBOARD = 29;
+ /** @hide */
public static final int OP_WRITE_CLIPBOARD = 30;
+ /** @hide */
public static final int OP_TAKE_MEDIA_BUTTONS = 31;
+ /** @hide */
public static final int OP_TAKE_AUDIO_FOCUS = 32;
+ /** @hide */
public static final int OP_AUDIO_MASTER_VOLUME = 33;
+ /** @hide */
public static final int OP_AUDIO_VOICE_VOLUME = 34;
+ /** @hide */
public static final int OP_AUDIO_RING_VOLUME = 35;
+ /** @hide */
public static final int OP_AUDIO_MEDIA_VOLUME = 36;
+ /** @hide */
public static final int OP_AUDIO_ALARM_VOLUME = 37;
+ /** @hide */
public static final int OP_AUDIO_NOTIFICATION_VOLUME = 38;
+ /** @hide */
public static final int OP_AUDIO_BLUETOOTH_VOLUME = 39;
+ /** @hide */
public static final int OP_WAKE_LOCK = 40;
+ /** Continually monitoring location data. */
+ public static final int OP_MONITOR_LOCATION = 41;
/** @hide */
- public static final int _NUM_OP = 41;
+ public static final int _NUM_OP = 42;
/**
* This maps each operation to the operation that serves as the
@@ -158,6 +204,7 @@ public class AppOpsManager {
OP_AUDIO_NOTIFICATION_VOLUME,
OP_AUDIO_BLUETOOTH_VOLUME,
OP_WAKE_LOCK,
+ OP_COARSE_LOCATION,
};
/**
@@ -206,6 +253,7 @@ public class AppOpsManager {
"AUDIO_NOTIFICATION_VOLUME",
"AUDIO_BLUETOOTH_VOLUME",
"WAKE_LOCK",
+ "MONITOR_LOCATION",
};
/**
@@ -254,10 +302,12 @@ public class AppOpsManager {
null, // no permission for changing notification volume
null, // no permission for changing bluetooth volume
android.Manifest.permission.WAKE_LOCK,
+ null, // no permission for generic location monitoring
};
/**
* Retrieve the op switch that controls the given operation.
+ * @hide
*/
public static int opToSwitch(int op) {
return sOpToSwitch[op];
@@ -273,6 +323,7 @@ public class AppOpsManager {
/**
* Retrieve the permission associated with an operation, or null if there is not one.
+ * @hide
*/
public static String opToPermission(int op) {
return sOpPerms[op];
@@ -280,6 +331,7 @@ public class AppOpsManager {
/**
* Class holding all of the operation information associated with an app.
+ * @hide
*/
public static class PackageOps implements Parcelable {
private final String mPackageName;
@@ -342,6 +394,7 @@ public class AppOpsManager {
/**
* Class holding the information about one unique operation of an application.
+ * @hide
*/
public static class OpEntry implements Parcelable {
private final int mOp;
@@ -422,7 +475,7 @@ public class AppOpsManager {
public void opChanged(int op, String packageName);
}
- public AppOpsManager(Context context, IAppOpsService service) {
+ AppOpsManager(Context context, IAppOpsService service) {
mContext = context;
mService = service;
}
@@ -431,6 +484,7 @@ public class AppOpsManager {
* Retrieve current operation state for all applications.
*
* @param ops The set of operations you are interested in, or null if you want all of them.
+ * @hide
*/
public List<AppOpsManager.PackageOps> getPackagesForOps(int[] ops) {
try {
@@ -446,6 +500,7 @@ public class AppOpsManager {
* @param uid The uid of the application of interest.
* @param packageName The name of the application of interest.
* @param ops The set of operations you are interested in, or null if you want all of them.
+ * @hide
*/
public List<AppOpsManager.PackageOps> getOpsForPackage(int uid, String packageName, int[] ops) {
try {
@@ -455,6 +510,7 @@ public class AppOpsManager {
return null;
}
+ /** @hide */
public void setMode(int code, int uid, String packageName, int mode) {
try {
mService.setMode(code, uid, packageName, mode);
@@ -462,6 +518,12 @@ public class AppOpsManager {
}
}
+ /**
+ * Monitor for changes to the operating mode for the given op in the given app package.
+ * @param op The operation to monitor, one of OP_*.
+ * @param packageName The name of the application to monitor.
+ * @param callback Where to report changes.
+ */
public void startWatchingMode(int op, String packageName, final Callback callback) {
synchronized (mModeWatchers) {
IAppOpsCallback cb = mModeWatchers.get(callback);
@@ -480,6 +542,10 @@ public class AppOpsManager {
}
}
+ /**
+ * Stop monitoring that was previously started with {@link #startWatchingMode}. All
+ * monitoring associated with this callback will be removed.
+ */
public void stopWatchingMode(Callback callback) {
synchronized (mModeWatchers) {
IAppOpsCallback cb = mModeWatchers.get(callback);
@@ -492,6 +558,22 @@ public class AppOpsManager {
}
}
+ /**
+ * Do a quick check for whether an application might be able to perform an operation.
+ * This is <em>not</em> a security check; you must use {@link #noteOp(int, int, String)}
+ * or {@link #startOp(int, int, String)} for your actual security checks, which also
+ * ensure that the given uid and package name are consistent. This function can just be
+ * used for a quick check to see if an operation has been disabled for the application,
+ * as an early reject of some work. This does not modify the time stamp or other data
+ * about the operation.
+ * @param op The operation to check. One of the OP_* constants.
+ * @param uid The user id of the application attempting to perform the operation.
+ * @param packageName The name of the application attempting to perform the operation.
+ * @return Returns {@link #MODE_ALLOWED} if the operation is allowed, or
+ * {@link #MODE_IGNORED} if it is not allowed and should be silently ignored (without
+ * causing the app to crash).
+ * @throws SecurityException If the app has been configured to crash on this op.
+ */
public int checkOp(int op, int uid, String packageName) {
try {
int mode = mService.checkOperation(op, uid, packageName);
@@ -504,6 +586,10 @@ public class AppOpsManager {
return MODE_IGNORED;
}
+ /**
+ * Like {@link #checkOp} but instead of throwing a {@link SecurityException} it
+ * returns {@link #MODE_ERRORED}.
+ */
public int checkOpNoThrow(int op, int uid, String packageName) {
try {
return mService.checkOperation(op, uid, packageName);
@@ -512,6 +598,20 @@ public class AppOpsManager {
return MODE_IGNORED;
}
+ /**
+ * Make note of an application performing an operation. Note that you must pass
+ * in both the uid and name of the application to be checked; this function will verify
+ * that these two match, and if not, return {@link #MODE_IGNORED}. If this call
+ * succeeds, the last execution time of the operation for this app will be updated to
+ * the current time.
+ * @param op The operation to note. One of the OP_* constants.
+ * @param uid The user id of the application attempting to perform the operation.
+ * @param packageName The name of the application attempting to perform the operation.
+ * @return Returns {@link #MODE_ALLOWED} if the operation is allowed, or
+ * {@link #MODE_IGNORED} if it is not allowed and should be silently ignored (without
+ * causing the app to crash).
+ * @throws SecurityException If the app has been configured to crash on this op.
+ */
public int noteOp(int op, int uid, String packageName) {
try {
int mode = mService.noteOperation(op, uid, packageName);
@@ -524,6 +624,10 @@ public class AppOpsManager {
return MODE_IGNORED;
}
+ /**
+ * Like {@link #noteOp} but instead of throwing a {@link SecurityException} it
+ * returns {@link #MODE_ERRORED}.
+ */
public int noteOpNoThrow(int op, int uid, String packageName) {
try {
return mService.noteOperation(op, uid, packageName);
@@ -532,10 +636,27 @@ public class AppOpsManager {
return MODE_IGNORED;
}
+ /** @hide */
public int noteOp(int op) {
return noteOp(op, Process.myUid(), mContext.getBasePackageName());
}
+ /**
+ * Report that an application has started executing a long-running operation. Note that you
+ * must pass in both the uid and name of the application to be checked; this function will
+ * verify that these two match, and if not, return {@link #MODE_IGNORED}. If this call
+ * succeeds, the last execution time of the operation for this app will be updated to
+ * the current time and the operation will be marked as "running". In this case you must
+ * later call {@link #finishOp(int, int, String)} to report when the application is no
+ * longer performing the operation.
+ * @param op The operation to start. One of the OP_* constants.
+ * @param uid The user id of the application attempting to perform the operation.
+ * @param packageName The name of the application attempting to perform the operation.
+ * @return Returns {@link #MODE_ALLOWED} if the operation is allowed, or
+ * {@link #MODE_IGNORED} if it is not allowed and should be silently ignored (without
+ * causing the app to crash).
+ * @throws SecurityException If the app has been configured to crash on this op.
+ */
public int startOp(int op, int uid, String packageName) {
try {
int mode = mService.startOperation(op, uid, packageName);
@@ -548,6 +669,10 @@ public class AppOpsManager {
return MODE_IGNORED;
}
+ /**
+ * Like {@link #startOp} but instead of throwing a {@link SecurityException} it
+ * returns {@link #MODE_ERRORED}.
+ */
public int startOpNoThrow(int op, int uid, String packageName) {
try {
return mService.startOperation(op, uid, packageName);
@@ -556,10 +681,17 @@ public class AppOpsManager {
return MODE_IGNORED;
}
+ /** @hide */
public int startOp(int op) {
return startOp(op, Process.myUid(), mContext.getBasePackageName());
}
+ /**
+ * Report that an application is no longer performing an operation that had previously
+ * been started with {@link #startOp(int, int, String)}. There is no validation of input
+ * or result; the parameters supplied here must be the exact same ones previously passed
+ * in when starting the operation.
+ */
public void finishOp(int op, int uid, String packageName) {
try {
mService.finishOperation(op, uid, packageName);
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index a5106e45223d..6a0fbd59bee3 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -192,6 +192,7 @@ class ContextImpl extends Context {
private Context mReceiverRestrictedContext = null;
private boolean mRestricted;
private UserHandle mUser;
+ private ResourcesManager mResourcesManager;
private final Object mSync = new Object();
@@ -1832,8 +1833,9 @@ class ContextImpl extends Context {
ContextImpl c = new ContextImpl();
c.init(mPackageInfo, null, mMainThread);
- c.mResources = mMainThread.getTopLevelResources(mPackageInfo.getResDir(), getDisplayId(),
- overrideConfiguration, mResources.getCompatibilityInfo(), mActivityToken);
+ c.mResources = mResourcesManager.getTopLevelResources(mPackageInfo.getResDir(),
+ getDisplayId(), overrideConfiguration, mResources.getCompatibilityInfo(),
+ mActivityToken);
return c;
}
@@ -1849,8 +1851,8 @@ class ContextImpl extends Context {
context.init(mPackageInfo, null, mMainThread);
context.mDisplay = display;
DisplayAdjustments daj = getDisplayAdjustments(displayId);
- context.mResources = mMainThread.getTopLevelResources(mPackageInfo.getResDir(), displayId,
- null, daj.getCompatibilityInfo(), null);
+ context.mResources = mResourcesManager.getTopLevelResources(mPackageInfo.getResDir(),
+ displayId, null, daj.getCompatibilityInfo(), null);
return context;
}
@@ -1929,6 +1931,7 @@ class ContextImpl extends Context {
mPackageInfo = packageInfo;
mBasePackageName = basePackageName != null ? basePackageName : packageInfo.mPackageName;
mResources = mPackageInfo.getResources(mainThread);
+ mResourcesManager = ResourcesManager.getInstance();
CompatibilityInfo compatInfo =
container == null ? null : container.getCompatibilityInfo();
@@ -1945,7 +1948,7 @@ class ContextImpl extends Context {
}
mDisplayAdjustments.setCompatibilityInfo(compatInfo);
mDisplayAdjustments.setActivityToken(activityToken);
- mResources = mainThread.getTopLevelResources(mPackageInfo.getResDir(),
+ mResources = mResourcesManager.getTopLevelResources(mPackageInfo.getResDir(),
Display.DEFAULT_DISPLAY, null, compatInfo, activityToken);
} else {
mDisplayAdjustments.setCompatibilityInfo(packageInfo.getCompatibilityInfo());
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index 573a6aad6ded..05d3a47ee98b 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -138,11 +138,11 @@ public final class LoadedApk {
if (ActivityThread.mSystemContext == null) {
ActivityThread.mSystemContext =
ContextImpl.createSystemContext(mainThread);
+ ResourcesManager resourcesManager = ResourcesManager.getInstance();
ActivityThread.mSystemContext.getResources().updateConfiguration(
- mainThread.getConfiguration(),
- mainThread.getDisplayMetricsLocked(
- Display.DEFAULT_DISPLAY, mDisplayAdjustments),
- compatInfo);
+ resourcesManager.getConfiguration(),
+ resourcesManager.getDisplayMetricsLocked(
+ Display.DEFAULT_DISPLAY, mDisplayAdjustments), compatInfo);
//Slog.i(TAG, "Created system resources "
// + mSystemContext.getResources() + ": "
// + mSystemContext.getResources().getConfiguration());
diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java
new file mode 100644
index 000000000000..e9693dd8a9c3
--- /dev/null
+++ b/core/java/android/app/ResourcesManager.java
@@ -0,0 +1,300 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app;
+
+import static android.app.ActivityThread.DEBUG_CONFIGURATION;
+
+import android.app.ApplicationPackageManager;
+import android.content.pm.ActivityInfo;
+import android.content.res.AssetManager;
+import android.content.res.CompatibilityInfo;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.content.res.ResourcesKey;
+import android.hardware.display.DisplayManagerGlobal;
+import android.os.IBinder;
+import android.util.ArrayMap;
+import android.util.DisplayMetrics;
+import android.util.Slog;
+import android.view.Display;
+import android.view.DisplayAdjustments;
+
+import java.lang.ref.WeakReference;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Locale;
+import java.util.Map;
+
+/** @hide */
+public class ResourcesManager {
+ static final String TAG = "ResourcesManager";
+ static final boolean DEBUG_CACHE = false;
+ static final boolean DEBUG_STATS = true;
+
+ private static ResourcesManager sResourcesManager;
+ final HashMap<ResourcesKey, WeakReference<Resources> > mActiveResources
+ = new HashMap<ResourcesKey, WeakReference<Resources> >();
+
+ final ArrayMap<DisplayAdjustments, DisplayMetrics> mDefaultDisplayMetrics
+ = new ArrayMap<DisplayAdjustments, DisplayMetrics>();
+
+ CompatibilityInfo mResCompatibilityInfo;
+
+ Configuration mResConfiguration;
+ final Configuration mTmpConfig = new Configuration();
+
+ public static ResourcesManager getInstance() {
+ synchronized (ResourcesManager.class) {
+ if (sResourcesManager == null) {
+ sResourcesManager = new ResourcesManager();
+ }
+ return sResourcesManager;
+ }
+ }
+
+ public Configuration getConfiguration() {
+ return mResConfiguration;
+ }
+
+ public void flushDisplayMetricsLocked() {
+ mDefaultDisplayMetrics.clear();
+ }
+
+ public DisplayMetrics getDisplayMetricsLocked(int displayId) {
+ return getDisplayMetricsLocked(displayId, DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS);
+ }
+
+ public DisplayMetrics getDisplayMetricsLocked(int displayId, DisplayAdjustments daj) {
+ boolean isDefaultDisplay = (displayId == Display.DEFAULT_DISPLAY);
+ DisplayMetrics dm = isDefaultDisplay ? mDefaultDisplayMetrics.get(daj) : null;
+ if (dm != null) {
+ return dm;
+ }
+ dm = new DisplayMetrics();
+
+ DisplayManagerGlobal displayManager = DisplayManagerGlobal.getInstance();
+ if (displayManager == null) {
+ // may be null early in system startup
+ dm.setToDefaults();
+ return dm;
+ }
+
+ if (isDefaultDisplay) {
+ mDefaultDisplayMetrics.put(daj, dm);
+ }
+
+ Display d = displayManager.getCompatibleDisplay(displayId, daj);
+ if (d != null) {
+ d.getMetrics(dm);
+ } else {
+ // Display no longer exists
+ // FIXME: This would not be a problem if we kept the Display object around
+ // instead of using the raw display id everywhere. The Display object caches
+ // its information even after the display has been removed.
+ dm.setToDefaults();
+ }
+ //Slog.i("foo", "New metrics: w=" + metrics.widthPixels + " h="
+ // + metrics.heightPixels + " den=" + metrics.density
+ // + " xdpi=" + metrics.xdpi + " ydpi=" + metrics.ydpi);
+ return dm;
+ }
+
+ final void applyNonDefaultDisplayMetricsToConfigurationLocked(
+ DisplayMetrics dm, Configuration config) {
+ config.touchscreen = Configuration.TOUCHSCREEN_NOTOUCH;
+ config.densityDpi = dm.densityDpi;
+ config.screenWidthDp = (int)(dm.widthPixels / dm.density);
+ config.screenHeightDp = (int)(dm.heightPixels / dm.density);
+ int sl = Configuration.resetScreenLayout(config.screenLayout);
+ if (dm.widthPixels > dm.heightPixels) {
+ config.orientation = Configuration.ORIENTATION_LANDSCAPE;
+ config.screenLayout = Configuration.reduceScreenLayout(sl,
+ config.screenWidthDp, config.screenHeightDp);
+ } else {
+ config.orientation = Configuration.ORIENTATION_PORTRAIT;
+ config.screenLayout = Configuration.reduceScreenLayout(sl,
+ config.screenHeightDp, config.screenWidthDp);
+ }
+ config.smallestScreenWidthDp = config.screenWidthDp; // assume screen does not rotate
+ config.compatScreenWidthDp = config.screenWidthDp;
+ config.compatScreenHeightDp = config.screenHeightDp;
+ config.compatSmallestScreenWidthDp = config.smallestScreenWidthDp;
+ }
+
+ public boolean applyCompatConfiguration(int displayDensity,
+ Configuration compatConfiguration) {
+ if (mResCompatibilityInfo != null && !mResCompatibilityInfo.supportsScreen()) {
+ mResCompatibilityInfo.applyToConfiguration(displayDensity, compatConfiguration);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Creates the top level Resources for applications with the given compatibility info.
+ *
+ * @param resDir the resource directory.
+ * @param compatInfo the compability info. Must not be null.
+ * @param token the application token for determining stack bounds.
+ */
+ public Resources getTopLevelResources(String resDir, int displayId,
+ Configuration overrideConfiguration, CompatibilityInfo compatInfo, IBinder token) {
+ final float scale = compatInfo.applicationScale;
+ ResourcesKey key = new ResourcesKey(resDir, displayId, overrideConfiguration, scale,
+ token);
+ Resources r;
+ synchronized (this) {
+ // Resources is app scale dependent.
+ if (false) {
+ Slog.w(TAG, "getTopLevelResources: " + resDir + " / " + scale);
+ }
+ WeakReference<Resources> wr = mActiveResources.get(key);
+ r = wr != null ? wr.get() : null;
+ //if (r != null) Slog.i(TAG, "isUpToDate " + resDir + ": " + r.getAssets().isUpToDate());
+ if (r != null && r.getAssets().isUpToDate()) {
+ if (false) {
+ Slog.w(TAG, "Returning cached resources " + r + " " + resDir
+ + ": appScale=" + r.getCompatibilityInfo().applicationScale);
+ }
+ return r;
+ }
+ }
+
+ //if (r != null) {
+ // Slog.w(TAG, "Throwing away out-of-date resources!!!! "
+ // + r + " " + resDir);
+ //}
+
+ AssetManager assets = new AssetManager();
+ if (assets.addAssetPath(resDir) == 0) {
+ return null;
+ }
+
+ //Slog.i(TAG, "Resource: key=" + key + ", display metrics=" + metrics);
+ DisplayMetrics dm = getDisplayMetricsLocked(displayId);
+ Configuration config;
+ boolean isDefaultDisplay = (displayId == Display.DEFAULT_DISPLAY);
+ final boolean hasOverrideConfig = key.hasOverrideConfiguration();
+ if (!isDefaultDisplay || hasOverrideConfig) {
+ config = new Configuration(getConfiguration());
+ if (!isDefaultDisplay) {
+ applyNonDefaultDisplayMetricsToConfigurationLocked(dm, config);
+ }
+ if (hasOverrideConfig) {
+ config.updateFrom(key.mOverrideConfiguration);
+ }
+ } else {
+ config = getConfiguration();
+ }
+ r = new Resources(assets, dm, config, compatInfo, token);
+ if (false) {
+ Slog.i(TAG, "Created app resources " + resDir + " " + r + ": "
+ + r.getConfiguration() + " appScale="
+ + r.getCompatibilityInfo().applicationScale);
+ }
+
+ synchronized (this) {
+ WeakReference<Resources> wr = mActiveResources.get(key);
+ Resources existing = wr != null ? wr.get() : null;
+ if (existing != null && existing.getAssets().isUpToDate()) {
+ // Someone else already created the resources while we were
+ // unlocked; go ahead and use theirs.
+ r.getAssets().close();
+ return existing;
+ }
+
+ // XXX need to remove entries when weak references go away
+ mActiveResources.put(key, new WeakReference<Resources>(r));
+ return r;
+ }
+ }
+
+ public final boolean applyConfigurationToResourcesLocked(Configuration config,
+ CompatibilityInfo compat) {
+ if (mResConfiguration == null) {
+ mResConfiguration = new Configuration();
+ }
+ if (!mResConfiguration.isOtherSeqNewer(config) && compat == null) {
+ if (DEBUG_CONFIGURATION) Slog.v(TAG, "Skipping new config: curSeq="
+ + mResConfiguration.seq + ", newSeq=" + config.seq);
+ return false;
+ }
+ int changes = mResConfiguration.updateFrom(config);
+ flushDisplayMetricsLocked();
+ DisplayMetrics defaultDisplayMetrics = getDisplayMetricsLocked(Display.DEFAULT_DISPLAY);
+
+ if (compat != null && (mResCompatibilityInfo == null ||
+ !mResCompatibilityInfo.equals(compat))) {
+ mResCompatibilityInfo = compat;
+ changes |= ActivityInfo.CONFIG_SCREEN_LAYOUT
+ | ActivityInfo.CONFIG_SCREEN_SIZE
+ | ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE;
+ }
+
+ // set it for java, this also affects newly created Resources
+ if (config.locale != null) {
+ Locale.setDefault(config.locale);
+ }
+
+ Resources.updateSystemConfiguration(config, defaultDisplayMetrics, compat);
+
+ ApplicationPackageManager.configurationChanged();
+ //Slog.i(TAG, "Configuration changed in " + currentPackageName());
+
+ Configuration tmpConfig = null;
+
+ Iterator<Map.Entry<ResourcesKey, WeakReference<Resources>>> it =
+ mActiveResources.entrySet().iterator();
+ while (it.hasNext()) {
+ Map.Entry<ResourcesKey, WeakReference<Resources>> entry = it.next();
+ Resources r = entry.getValue().get();
+ if (r != null) {
+ if (DEBUG_CONFIGURATION) Slog.v(TAG, "Changing resources "
+ + r + " config to: " + config);
+ int displayId = entry.getKey().mDisplayId;
+ boolean isDefaultDisplay = (displayId == Display.DEFAULT_DISPLAY);
+ DisplayMetrics dm = defaultDisplayMetrics;
+ ResourcesKey resourcesKey = entry.getKey();
+ final boolean hasOverrideConfiguration = resourcesKey.hasOverrideConfiguration();
+ if (!isDefaultDisplay || hasOverrideConfiguration) {
+ if (tmpConfig == null) {
+ tmpConfig = new Configuration();
+ }
+ tmpConfig.setTo(config);
+ if (!isDefaultDisplay) {
+ dm = getDisplayMetricsLocked(displayId);
+ applyNonDefaultDisplayMetricsToConfigurationLocked(dm, tmpConfig);
+ }
+ if (hasOverrideConfiguration) {
+ tmpConfig.updateFrom(resourcesKey.mOverrideConfiguration);
+ }
+ r.updateConfiguration(tmpConfig, dm, compat);
+ } else {
+ r.updateConfiguration(config, dm, compat);
+ }
+ //Slog.i(TAG, "Updated app resources " + v.getKey()
+ // + " " + r + ": " + r.getConfiguration());
+ } else {
+ //Slog.i(TAG, "Removing old resources " + v.getKey());
+ it.remove();
+ }
+ }
+
+ return changes != 0;
+ }
+
+}
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index c24e0ee2bac9..6483cd979dff 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -1668,13 +1668,6 @@ public class Resources {
}
/**
- * @hide
- */
- public static void updateSystemConfiguration(Configuration config, DisplayMetrics metrics) {
- updateSystemConfiguration(config, metrics, null);
- }
-
- /**
* Return the current display metrics that are in effect for this resource
* object. The returned object should be treated as read-only.
*
diff --git a/core/java/android/content/res/ResourcesKey.java b/core/java/android/content/res/ResourcesKey.java
new file mode 100644
index 000000000000..53e0f2c00e0d
--- /dev/null
+++ b/core/java/android/content/res/ResourcesKey.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.res;
+
+import android.os.IBinder;
+
+/** @hide */
+public final class ResourcesKey {
+ final String mResDir;
+ final float mScale;
+ private final int mHash;
+ private final IBinder mToken;
+
+ public final int mDisplayId;
+ public final Configuration mOverrideConfiguration = new Configuration();
+
+ public ResourcesKey(String resDir, int displayId, Configuration overrideConfiguration,
+ float scale, IBinder token) {
+ mResDir = resDir;
+ mDisplayId = displayId;
+ if (overrideConfiguration != null) {
+ mOverrideConfiguration.setTo(overrideConfiguration);
+ }
+ mScale = scale;
+ mToken = token;
+
+ int hash = 17;
+ hash = 31 * hash + (mResDir == null ? 0 : mResDir.hashCode());
+ hash = 31 * hash + mDisplayId;
+ hash = 31 * hash + (mOverrideConfiguration != null
+ ? mOverrideConfiguration.hashCode() : 0);
+ hash = 31 * hash + Float.floatToIntBits(mScale);
+ mHash = hash;
+ }
+
+ public boolean hasOverrideConfiguration() {
+ return !Configuration.EMPTY.equals(mOverrideConfiguration);
+ }
+
+ @Override
+ public int hashCode() {
+ return mHash;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof ResourcesKey)) {
+ return false;
+ }
+ ResourcesKey peer = (ResourcesKey) obj;
+ if (!mResDir.equals(peer.mResDir)) {
+ return false;
+ }
+ if (mDisplayId != peer.mDisplayId) {
+ return false;
+ }
+ if (mOverrideConfiguration != peer.mOverrideConfiguration) {
+ if (mOverrideConfiguration == null || peer.mOverrideConfiguration == null) {
+ return false;
+ }
+ if (!mOverrideConfiguration.equals(peer.mOverrideConfiguration)) {
+ return false;
+ }
+ }
+ if (mScale != peer.mScale) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ return Integer.toHexString(mHash);
+ }
+}
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 8e0935da2186..12646bde77f2 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -1803,8 +1803,8 @@ public abstract class BatteryStats implements Parcelable {
for (int i=0; i<timers.size(); i++) {
TimerEntry timer = timers.get(i);
sb.setLength(0);
- sb.append(" Wake lock #");
- sb.append(timer.mId);
+ sb.append(" Wake lock ");
+ UserHandle.formatUid(sb, timer.mId);
sb.append(" ");
sb.append(timer.mName);
printWakeLock(sb, timer.mTimer, batteryRealtime, null, which, ": ");
@@ -1822,8 +1822,11 @@ public abstract class BatteryStats implements Parcelable {
}
Uid u = uidStats.valueAt(iu);
-
- pw.println(prefix + " #" + uid + ":");
+
+ pw.print(prefix);
+ pw.print(" ");
+ UserHandle.formatUid(pw, uid);
+ pw.println(":");
boolean uidActivity = false;
long mobileRxBytes = u.getNetworkActivityCount(NETWORK_MOBILE_RX_BYTES, which);
diff --git a/core/java/android/os/UserHandle.java b/core/java/android/os/UserHandle.java
index d2052539ccb9..6e693a41230f 100644
--- a/core/java/android/os/UserHandle.java
+++ b/core/java/android/os/UserHandle.java
@@ -168,8 +168,11 @@ public final class UserHandle implements Parcelable {
if (appId >= Process.FIRST_ISOLATED_UID && appId <= Process.LAST_ISOLATED_UID) {
sb.append('i');
sb.append(appId - Process.FIRST_ISOLATED_UID);
- } else {
+ } else if (appId >= Process.FIRST_APPLICATION_UID) {
sb.append('a');
+ sb.append(appId - Process.FIRST_APPLICATION_UID);
+ } else {
+ sb.append('s');
sb.append(appId);
}
}
@@ -190,8 +193,11 @@ public final class UserHandle implements Parcelable {
if (appId >= Process.FIRST_ISOLATED_UID && appId <= Process.LAST_ISOLATED_UID) {
pw.print('i');
pw.print(appId - Process.FIRST_ISOLATED_UID);
- } else {
+ } else if (appId >= Process.FIRST_APPLICATION_UID) {
pw.print('a');
+ pw.print(appId - Process.FIRST_APPLICATION_UID);
+ } else {
+ pw.print('s');
pw.print(appId);
}
}
diff --git a/core/java/android/view/GraphicBuffer.java b/core/java/android/view/GraphicBuffer.java
index b4576f367b94..30c077c2e879 100644
--- a/core/java/android/view/GraphicBuffer.java
+++ b/core/java/android/view/GraphicBuffer.java
@@ -62,6 +62,9 @@ public class GraphicBuffer implements Parcelable {
private Canvas mCanvas;
private int mSaveCount;
+ // If set to true, this GraphicBuffer instance cannot be used anymore
+ private boolean mDestroyed;
+
/**
* Creates new <code>GraphicBuffer</code> instance. This method will return null
* if the buffer cannot be created.
@@ -128,10 +131,14 @@ public class GraphicBuffer implements Parcelable {
* <p>The content of the buffer is preserved between unlockCanvas()
* and lockCanvas().</p>
*
+ * <p>If this method is called after {@link #destroy()}, the return value will
+ * always be null.</p>
+ *
* @return A Canvas used to draw into the buffer, or null.
*
* @see #lockCanvas(android.graphics.Rect)
* @see #unlockCanvasAndPost(android.graphics.Canvas)
+ * @see #isDestroyed()
*/
public Canvas lockCanvas() {
return lockCanvas(null);
@@ -141,14 +148,22 @@ public class GraphicBuffer implements Parcelable {
* Just like {@link #lockCanvas()} but allows specification of a dirty
* rectangle.
*
+ * <p>If this method is called after {@link #destroy()}, the return value will
+ * always be null.</p>
+ *
* @param dirty Area of the buffer that may be modified.
- * @return A Canvas used to draw into the surface or null
+ * @return A Canvas used to draw into the surface, or null.
*
* @see #lockCanvas()
* @see #unlockCanvasAndPost(android.graphics.Canvas)
+ * @see #isDestroyed()
*/
public Canvas lockCanvas(Rect dirty) {
+ if (mDestroyed) {
+ return null;
+ }
+
if (mCanvas == null) {
mCanvas = new Canvas();
}
@@ -164,13 +179,17 @@ public class GraphicBuffer implements Parcelable {
/**
* Finish editing pixels in the buffer.
*
+ * <p>This method doesn't do anything if {@link #destroy()} was
+ * previously called.</p>
+ *
* @param canvas The Canvas previously returned by lockCanvas()
*
* @see #lockCanvas()
* @see #lockCanvas(android.graphics.Rect)
+ * @see #isDestroyed()
*/
public void unlockCanvasAndPost(Canvas canvas) {
- if (mCanvas != null && canvas == mCanvas) {
+ if (!mDestroyed && mCanvas != null && canvas == mCanvas) {
canvas.restoreToCount(mSaveCount);
mSaveCount = 0;
@@ -178,10 +197,39 @@ public class GraphicBuffer implements Parcelable {
}
}
+ /**
+ * Destroyes this buffer immediately. Calling this method frees up any
+ * underlying native resources. After calling this method, this buffer
+ * must not be used in any way ({@link #lockCanvas()} must not be called,
+ * etc.)
+ *
+ * @see #isDestroyed()
+ */
+ public void destroy() {
+ if (!mDestroyed) {
+ mDestroyed = true;
+ nDestroyGraphicBuffer(mNativeObject);
+ }
+ }
+
+ /**
+ * Indicates whether this buffer has been destroyed. A destroyed buffer
+ * cannot be used in any way: locking a Canvas will return null, the buffer
+ * cannot be written to a parcel, etc.
+ *
+ * @return True if this <code>GraphicBuffer</code> is in a destroyed state,
+ * false otherwise.
+ *
+ * @see #destroy()
+ */
+ public boolean isDestroyed() {
+ return mDestroyed;
+ }
+
@Override
protected void finalize() throws Throwable {
try {
- nDestroyGraphicBuffer(mNativeObject);
+ if (!mDestroyed) nDestroyGraphicBuffer(mNativeObject);
} finally {
super.finalize();
}
@@ -192,8 +240,23 @@ public class GraphicBuffer implements Parcelable {
return 0;
}
+ /**
+ * Flatten this object in to a Parcel.
+ *
+ * <p>Calling this method will throw an <code>IllegalStateException</code> if
+ * {@link #destroy()} has been previously called.</p>
+ *
+ * @param dest The Parcel in which the object should be written.
+ * @param flags Additional flags about how the object should be written.
+ * May be 0 or {@link #PARCELABLE_WRITE_RETURN_VALUE}.
+ */
@Override
public void writeToParcel(Parcel dest, int flags) {
+ if (mDestroyed) {
+ throw new IllegalStateException("This GraphicBuffer has been destroyed and cannot be "
+ + "written to a parcel.");
+ }
+
dest.writeInt(mWidth);
dest.writeInt(mHeight);
dest.writeInt(mFormat);
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index 281bd7e9a2b7..d9e4600d42db 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -1983,6 +1983,7 @@ public abstract class HardwareRenderer {
if (map != null) {
GLES20Canvas.initAtlas(buffer, map);
}
+ buffer.destroy();
}
}
} catch (RemoteException e) {
diff --git a/core/java/android/view/transition/Fade.java b/core/java/android/view/transition/Fade.java
index 3c5b6fad622e..c2aa90beba76 100644
--- a/core/java/android/view/transition/Fade.java
+++ b/core/java/android/view/transition/Fade.java
@@ -96,12 +96,19 @@ public class Fade extends Visibility {
protected Animator appear(ViewGroup sceneRoot,
TransitionValues startValues, int startVisibility,
TransitionValues endValues, int endVisibility) {
- View endView = (endValues != null) ? endValues.view : null;
- if ((mFadingMode & IN) != IN) {
+ if ((mFadingMode & IN) != IN || endValues == null) {
return null;
}
+ final View endView = endValues.view;
endView.setAlpha(0);
- return runAnimation(endView, 0, 1, null);
+ final Animator.AnimatorListener endListener = new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ // Always end animation with full alpha, in case it's canceled mid-stream
+ endView.setAlpha(1);
+ }
+ };
+ return runAnimation(endView, 0, 1, endListener);
}
@Override
diff --git a/core/java/android/view/transition/TransitionGroup.java b/core/java/android/view/transition/TransitionGroup.java
index d0e61ea28c4b..313e33e601bd 100644
--- a/core/java/android/view/transition/TransitionGroup.java
+++ b/core/java/android/view/transition/TransitionGroup.java
@@ -104,7 +104,7 @@ public class TransitionGroup extends Transition {
mTransitions.add(transitions[i]);
transitions[i].mParent = this;
if (mDuration >= 0) {
- transitions[0].setDuration(mDuration);
+ transitions[i].setDuration(mDuration);
}
}
}
diff --git a/core/java/android/widget/CompoundButton.java b/core/java/android/widget/CompoundButton.java
index c4406ac66d69..05a8dc825e12 100644
--- a/core/java/android/widget/CompoundButton.java
+++ b/core/java/android/widget/CompoundButton.java
@@ -199,10 +199,8 @@ public abstract class CompoundButton extends Button implements Checkable {
unscheduleDrawable(mButtonDrawable);
}
d.setCallback(this);
- d.setState(getDrawableState());
d.setVisible(getVisibility() == VISIBLE, false);
mButtonDrawable = d;
- mButtonDrawable.setState(null);
setMinHeight(mButtonDrawable.getIntrinsicHeight());
}
diff --git a/core/java/com/android/internal/inputmethod/InputMethodUtils.java b/core/java/com/android/internal/inputmethod/InputMethodUtils.java
index 4e213247e503..78389c5121f2 100644
--- a/core/java/com/android/internal/inputmethod/InputMethodUtils.java
+++ b/core/java/com/android/internal/inputmethod/InputMethodUtils.java
@@ -432,6 +432,17 @@ public class InputMethodUtils {
}
}
+ public static CharSequence getImeAndSubtypeDisplayName(Context context, InputMethodInfo imi,
+ InputMethodSubtype subtype) {
+ final CharSequence imiLabel = imi.loadLabel(context.getPackageManager());
+ return subtype != null
+ ? TextUtils.concat(subtype.getDisplayName(context,
+ imi.getPackageName(), imi.getServiceInfo().applicationInfo),
+ (TextUtils.isEmpty(imiLabel) ?
+ "" : " - " + imiLabel))
+ : imiLabel;
+ }
+
/**
* Utility class for putting and getting settings for InputMethod
* TODO: Move all putters and getters of settings to this class.
diff --git a/core/java/com/android/internal/view/menu/ListMenuItemView.java b/core/java/com/android/internal/view/menu/ListMenuItemView.java
index 464ae2f5e8dd..35b76dd2213f 100644
--- a/core/java/com/android/internal/view/menu/ListMenuItemView.java
+++ b/core/java/com/android/internal/view/menu/ListMenuItemView.java
@@ -242,17 +242,20 @@ public class ListMenuItemView extends RelativeLayout implements MenuView.ItemVie
private void insertIconView() {
mIconView = (ImageView) getInflater()
- .inflate(com.android.internal.R.layout.list_menu_item_icon, this, true);
+ .inflate(com.android.internal.R.layout.list_menu_item_icon, this, false);
+ addView(mIconView);
}
private void insertRadioButton() {
mRadioButton = (RadioButton) getInflater()
- .inflate(com.android.internal.R.layout.list_menu_item_radio, this, true);
+ .inflate(com.android.internal.R.layout.list_menu_item_radio, this, false);
+ addView(mRadioButton);
}
private void insertCheckBox() {
mCheckBox = (CheckBox) getInflater()
- .inflate(com.android.internal.R.layout.list_menu_item_checkbox, this, true);
+ .inflate(com.android.internal.R.layout.list_menu_item_checkbox, this, false);
+ addView(mCheckBox);
}
private void alignTextToStartOf(View v) {
diff --git a/docs/html/sdk/installing/studio-tips.jd b/docs/html/sdk/installing/studio-tips.jd
index a686efdfad24..12d252710a28 100644
--- a/docs/html/sdk/installing/studio-tips.jd
+++ b/docs/html/sdk/installing/studio-tips.jd
@@ -10,6 +10,8 @@ page.title=Android Studio Tips and Tricks
>Eclipse Compatibility Mode</a></li>
<li><a href="http://confluence.jetbrains.com/display/IntelliJIDEA/FAQ+on+Migrating+to+IntelliJ+IDEA" class="external-link"
>FAQ on Migrating</a></li>
+ <li><a href="http://android-developers.blogspot.com/2013/06/adding-backend-to-your-app-in-android.html"
+ class="external-link">Adding a Backend to Your App In Android Studio</a></li>
</ul>
</div>
</div>
diff --git a/graphics/java/android/graphics/Matrix.java b/graphics/java/android/graphics/Matrix.java
index a837294ecb82..4e064486f0d4 100644
--- a/graphics/java/android/graphics/Matrix.java
+++ b/graphics/java/android/graphics/Matrix.java
@@ -267,13 +267,23 @@ public class Matrix {
native_set(native_instance, src.native_instance);
}
}
-
+
/** Returns true iff obj is a Matrix and its values equal our values.
*/
+ @Override
public boolean equals(Object obj) {
- return obj != null &&
- obj instanceof Matrix &&
- native_equals(native_instance, ((Matrix)obj).native_instance);
+ //if (obj == this) return true; -- NaN value would mean matrix != itself
+ if (!(obj instanceof Matrix)) return false;
+ return native_equals(native_instance, ((Matrix)obj).native_instance);
+ }
+
+ @Override
+ public int hashCode() {
+ // This should generate the hash code by performing some arithmetic operation on all
+ // the matrix elements -- our equals() does an element-by-element comparison, and we
+ // need to ensure that the hash code for two equal objects is the same. We're not
+ // really using this at the moment, so we take the easy way out.
+ return 44;
}
/** Set the matrix to identity */
@@ -512,7 +522,7 @@ public class Matrix {
*/
END (3);
- // the native values must match those in SkMatrix.h
+ // the native values must match those in SkMatrix.h
ScaleToFit(int nativeInt) {
this.nativeInt = nativeInt;
}
@@ -535,7 +545,7 @@ public class Matrix {
}
return native_setRectToRect(native_instance, src, dst, stf.nativeInt);
}
-
+
// private helper to perform range checks on arrays of "points"
private static void checkPointArrays(float[] src, int srcIndex,
float[] dst, int dstIndex,
@@ -598,7 +608,7 @@ public class Matrix {
native_mapPoints(native_instance, dst, dstIndex, src, srcIndex,
pointCount, true);
}
-
+
/**
* Apply this matrix to the array of 2D vectors specified by src, and write
* the transformed vectors into the array of vectors specified by dst. The
@@ -620,7 +630,7 @@ public class Matrix {
native_mapPoints(native_instance, dst, dstIndex, src, srcIndex,
vectorCount, false);
}
-
+
/**
* Apply this matrix to the array of 2D points specified by src, and write
* the transformed points into the array of points specified by dst. The
@@ -713,7 +723,7 @@ public class Matrix {
public float mapRadius(float radius) {
return native_mapRadius(native_instance, radius);
}
-
+
/** Copy 9 values from the matrix into the array.
*/
public void getValues(float[] values) {
@@ -736,13 +746,14 @@ public class Matrix {
native_setValues(native_instance, values);
}
+ @Override
public String toString() {
StringBuilder sb = new StringBuilder(64);
sb.append("Matrix{");
toShortString(sb);
sb.append('}');
return sb.toString();
-
+
}
public String toShortString() {
@@ -780,13 +791,18 @@ public class Matrix {
pw.print(values[5]); pw.print("][");
pw.print(values[6]); pw.print(", "); pw.print(values[7]); pw.print(", ");
pw.print(values[8]); pw.print(']');
-
+
}
+ @Override
protected void finalize() throws Throwable {
- finalizer(native_instance);
+ try {
+ finalizer(native_instance);
+ } finally {
+ super.finalize();
+ }
}
-
+
/*package*/ final int ni() {
return native_instance;
}
diff --git a/packages/SystemUI/res/anim/priority_alert_enter.xml b/packages/SystemUI/res/anim/heads_up_enter.xml
index 4fd6a7c9d2f7..4fd6a7c9d2f7 100644
--- a/packages/SystemUI/res/anim/priority_alert_enter.xml
+++ b/packages/SystemUI/res/anim/heads_up_enter.xml
diff --git a/packages/SystemUI/res/anim/priority_alert_exit.xml b/packages/SystemUI/res/anim/heads_up_exit.xml
index 05c144a1720d..05c144a1720d 100644
--- a/packages/SystemUI/res/anim/priority_alert_exit.xml
+++ b/packages/SystemUI/res/anim/heads_up_exit.xml
diff --git a/packages/SystemUI/res/drawable/intruder_row_bg.xml b/packages/SystemUI/res/drawable/heads_up_notification_row_bg.xml
index 1c7c9c454602..59d9fcfc7a16 100644
--- a/packages/SystemUI/res/drawable/intruder_row_bg.xml
+++ b/packages/SystemUI/res/drawable/heads_up_notification_row_bg.xml
@@ -15,6 +15,7 @@
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android"
- android:exitFadeDuration="@android:integer/config_mediumAnimTime">
- <item android:state_pressed="true" android:drawable="@drawable/intruder_bg_pressed" />
+ android:exitFadeDuration="@android:integer/config_mediumAnimTime">
+ <item android:state_pressed="true"
+ android:drawable="@drawable/heads_up_notification_bg_pressed" />
</selector>
diff --git a/packages/SystemUI/res/drawable/intruder_window_bg.9.png b/packages/SystemUI/res/drawable/heads_up_window_bg.9.png
index caad1691b226..caad1691b226 100644
--- a/packages/SystemUI/res/drawable/intruder_window_bg.9.png
+++ b/packages/SystemUI/res/drawable/heads_up_window_bg.9.png
Binary files differ
diff --git a/packages/SystemUI/res/layout/intruder_alert.xml b/packages/SystemUI/res/layout/heads_up.xml
index c4141ae9a5ae..b7c1666fd781 100644
--- a/packages/SystemUI/res/layout/intruder_alert.xml
+++ b/packages/SystemUI/res/layout/heads_up.xml
@@ -19,7 +19,7 @@
-->
<!-- android:background="@drawable/status_bar_closed_default_background" -->
-<com.android.systemui.statusbar.policy.IntruderAlertView
+<com.android.systemui.statusbar.policy.HeadsUpNotificationView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="wrap_content"
android:layout_width="match_parent"
@@ -29,12 +29,6 @@
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:id="@+id/contentHolder"
- android:background="@drawable/intruder_window_bg"
+ android:background="@drawable/heads_up_window_bg"
/>
-<!-- <ImageView
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:src="@drawable/title_bar_shadow"
- android:scaleType="fitXY"
- /> -->
-</com.android.systemui.statusbar.policy.IntruderAlertView>
+</com.android.systemui.statusbar.policy.HeadsUpNotificationView>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index ca6e06df232a..4a7d09067acb 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -27,7 +27,7 @@
<color name="notification_list_shadow_top">#80000000</color>
<drawable name="recents_callout_line">#99ffffff</drawable>
<drawable name="notification_item_background_legacy_color">#ffaaaaaa</drawable>
- <drawable name="intruder_bg_pressed">#ff33B5E5</drawable>
+ <drawable name="heads_up_notification_bg_pressed">#ff33B5E5</drawable>
<drawable name="notification_header_bg">#FF000000</drawable>
<color name="notification_panel_scrim_color">#B0000000</color>
</resources>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 7ddf261416bf..11940a3e3d58 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -34,7 +34,7 @@
<item name="android:wallpaperIntraOpenExitAnimation">@anim/wallpaper_recents_launch_from_launcher_exit</item>
</style>
- <style name="TextAppearance.StatusBar.IntruderAlert"
+ <style name="TextAppearance.StatusBar.HeadsUp"
parent="@*android:style/TextAppearance.StatusBar">
</style>
@@ -154,9 +154,9 @@
<style name="Animation.StatusBar">
</style>
- <style name="Animation.StatusBar.IntruderAlert">
- <item name="android:windowEnterAnimation">@anim/priority_alert_enter</item>
- <item name="android:windowExitAnimation">@anim/priority_alert_exit</item>
+ <style name="Animation.StatusBar.HeadsUp">
+ <item name="android:windowEnterAnimation">@anim/heads_up_enter</item>
+ <item name="android:windowExitAnimation">@anim/heads_up_exit</item>
</style>
<style name="TextAppearance.StatusBar.PhoneTicker"
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 3583081e4651..69fc3cff7b08 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -35,10 +35,13 @@ import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
+import android.os.PowerManager;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
import android.provider.Settings;
+import android.service.dreams.DreamService;
+import android.service.dreams.IDreamManager;
import android.service.notification.StatusBarNotification;
import android.text.TextUtils;
import android.util.Log;
@@ -83,16 +86,19 @@ public abstract class BaseStatusBar extends SystemUI implements
protected static final int MSG_CANCEL_PRELOAD_RECENT_APPS = 1023;
protected static final int MSG_OPEN_SEARCH_PANEL = 1024;
protected static final int MSG_CLOSE_SEARCH_PANEL = 1025;
- protected static final int MSG_SHOW_INTRUDER = 1026;
- protected static final int MSG_HIDE_INTRUDER = 1027;
+ protected static final int MSG_SHOW_HEADS_UP = 1026;
+ protected static final int MSG_HIDE_HEADS_UP = 1027;
- protected static final boolean ENABLE_INTRUDERS = false;
+ protected static final boolean ENABLE_HEADS_UP = true;
+ // scores above this threshold should be displayed in heads up mode.
+ private static final int INTERRUPTION_THRESHOLD = 10;
// Should match the value in PhoneWindowManager
public static final String SYSTEM_DIALOG_REASON_RECENT_APPS = "recentapps";
public static final int EXPANDED_LEAVE_ALONE = -10000;
public static final int EXPANDED_FULL_OPEN = -10001;
+ private static final String SETTING_HEADS_UP = "heads_up_enabled";
protected CommandQueue mCommandQueue;
protected IStatusBarService mBarService;
@@ -102,7 +108,7 @@ public abstract class BaseStatusBar extends SystemUI implements
protected NotificationData mNotificationData = new NotificationData();
protected NotificationRowLayout mPile;
- protected StatusBarNotification mCurrentlyIntrudingNotification;
+ protected StatusBarNotification mCurrentlyInterruptingNotification;
// used to notify status bar for suppressing notification LED
protected boolean mPanelSlightlyVisible;
@@ -116,6 +122,11 @@ public abstract class BaseStatusBar extends SystemUI implements
protected int mLayoutDirection;
private Locale mLocale;
+ protected boolean mUseHeadsUp = true;
+
+ protected IDreamManager mDreamManager;
+ KeyguardManager mKeyguardManager;
+ PowerManager mPowerManager;
// UI-specific methods
@@ -155,6 +166,19 @@ public abstract class BaseStatusBar extends SystemUI implements
}
};
+ final private ContentObserver mHeadsUpObserver = new ContentObserver(mHandler) {
+ @Override
+ public void onChange(boolean selfChange) {
+ mUseHeadsUp = ENABLE_HEADS_UP && 0 != Settings.Global.getInt(
+ mContext.getContentResolver(), SETTING_HEADS_UP, 0);
+ Log.d(TAG, "heads up is " + (mUseHeadsUp ? "enabled" : "disabled"));
+ if (!mUseHeadsUp) {
+ Log.d(TAG, "dismissing any existing heads up notification on disable event");
+ mHandler.sendEmptyMessage(MSG_HIDE_HEADS_UP);
+ }
+ }
+ };
+
private RemoteViews.OnClickHandler mOnClickHandler = new RemoteViews.OnClickHandler() {
@Override
public boolean onClickHandler(View view, PendingIntent pendingIntent, Intent fillInIntent) {
@@ -204,11 +228,21 @@ public abstract class BaseStatusBar extends SystemUI implements
mWindowManagerService = WindowManagerGlobal.getWindowManagerService();
mDisplay = mWindowManager.getDefaultDisplay();
+ mDreamManager = IDreamManager.Stub.asInterface(
+ ServiceManager.checkService(DreamService.DREAM_SERVICE));
+ mKeyguardManager = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
+ mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
+
mProvisioningObserver.onChange(false); // set up
mContext.getContentResolver().registerContentObserver(
Settings.Global.getUriFor(Settings.Global.DEVICE_PROVISIONED), true,
mProvisioningObserver);
+ mHeadsUpObserver.onChange(false); // set up
+ mContext.getContentResolver().registerContentObserver(
+ Settings.Global.getUriFor(SETTING_HEADS_UP), true,
+ mHeadsUpObserver);
+
mBarService = IStatusBarService.Stub.asInterface(
ServiceManager.getService(Context.STATUS_BAR_SERVICE));
@@ -398,7 +432,7 @@ public abstract class BaseStatusBar extends SystemUI implements
}
}
- public void dismissIntruder() {
+ public void dismissHeadsUp() {
// pass
}
@@ -677,13 +711,13 @@ public abstract class BaseStatusBar extends SystemUI implements
return new NotificationClicker(intent, pkg, tag, id);
}
- private class NotificationClicker implements View.OnClickListener {
+ protected class NotificationClicker implements View.OnClickListener {
private PendingIntent mIntent;
private String mPkg;
private String mTag;
private int mId;
- NotificationClicker(PendingIntent intent, String pkg, String tag, int id) {
+ public NotificationClicker(PendingIntent intent, String pkg, String tag, int id) {
mIntent = intent;
mPkg = pkg;
mTag = tag;
@@ -730,9 +764,6 @@ public abstract class BaseStatusBar extends SystemUI implements
// close the shade if it was open
animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE);
visibilityChanged(false);
-
- // If this click was on the intruder alert, hide that instead
-// mHandler.sendEmptyMessage(MSG_HIDE_INTRUDER);
}
}
/**
@@ -997,18 +1028,30 @@ public abstract class BaseStatusBar extends SystemUI implements
setAreThereNotifications();
updateExpandedViewPos(EXPANDED_LEAVE_ALONE);
- // See if we need to update the intruder.
- if (ENABLE_INTRUDERS && oldNotification == mCurrentlyIntrudingNotification) {
- if (DEBUG) Log.d(TAG, "updating the current intruder:" + notification);
+ // See if we need to update the heads up.
+ if (ENABLE_HEADS_UP && oldNotification == mCurrentlyInterruptingNotification) {
+ if (DEBUG) Log.d(TAG, "updating the current heads up:" + notification);
// XXX: this is a hack for Alarms. The real implementation will need to *update*
- // the intruder.
- if (notification.getNotification().fullScreenIntent == null) { // TODO(dsandler): consistent logic with add()
- if (DEBUG) Log.d(TAG, "no longer intrudes!");
- mHandler.sendEmptyMessage(MSG_HIDE_INTRUDER);
+ // the heads up.
+ if (!shouldInterrupt(notification)) {
+ if (DEBUG) Log.d(TAG, "no longer interrupts!");
+ mHandler.sendEmptyMessage(MSG_HIDE_HEADS_UP);
}
}
}
+ protected boolean shouldInterrupt(StatusBarNotification notification) {
+ boolean interrupt = notification.getNotification().fullScreenIntent == null
+ && notification.getScore() >= INTERRUPTION_THRESHOLD
+ && mPowerManager.isScreenOn() && !mKeyguardManager.isKeyguardLocked();
+ try {
+ interrupt = interrupt && !mDreamManager.isDreaming();
+ } catch (RemoteException e) {
+ Log.d(TAG, "failed to query dream manager", e);
+ }
+ return interrupt;
+ }
+
// Q: What kinds of notifications should show during setup?
// A: Almost none! Only things coming from the system (package is "android") that also
// have special "kind" tags marking them as relevant for setup (see below).
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index ee94cc830925..fd99f5b1b178 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -45,12 +45,9 @@ import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.RemoteException;
-import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.UserHandle;
import android.provider.Settings;
-import android.service.dreams.DreamService;
-import android.service.dreams.IDreamManager;
import android.service.notification.StatusBarNotification;
import android.util.DisplayMetrics;
import android.util.EventLog;
@@ -76,7 +73,6 @@ import android.widget.LinearLayout;
import android.widget.ScrollView;
import android.widget.TextView;
import android.widget.Toast;
-
import com.android.internal.statusbar.StatusBarIcon;
import com.android.systemui.EventLogTags;
import com.android.systemui.R;
@@ -90,7 +86,7 @@ import com.android.systemui.statusbar.StatusBarIconView;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.statusbar.policy.BluetoothController;
import com.android.systemui.statusbar.policy.DateView;
-import com.android.systemui.statusbar.policy.IntruderAlertView;
+import com.android.systemui.statusbar.policy.HeadsUpNotificationView;
import com.android.systemui.statusbar.policy.LocationController;
import com.android.systemui.statusbar.policy.NetworkController;
import com.android.systemui.statusbar.policy.NotificationRowLayout;
@@ -127,7 +123,7 @@ public class PhoneStatusBar extends BaseStatusBar {
// 1020-1030 reserved for BaseStatusBar
// will likely move to a resource or other tunable param at some point
- private static final int INTRUDER_ALERT_DECAY_MS = 0; // disabled, was 10000;
+ private static final int HEADS_UP_DECAY_MS = 0; // disabled, was 10000;
private static final boolean CLOSE_PANEL_WHEN_EMPTIED = true;
@@ -169,8 +165,6 @@ public class PhoneStatusBar extends BaseStatusBar {
Display mDisplay;
Point mCurrentDisplaySize = new Point();
- IDreamManager mDreamManager;
-
StatusBarWindowView mStatusBarWindow;
PhoneStatusBarView mStatusBarView;
@@ -230,8 +224,8 @@ public class PhoneStatusBar extends BaseStatusBar {
// the date view
DateView mDateView;
- // for immersive activities
- private IntruderAlertView mIntruderAlertView;
+ // for heads up notifications
+ private HeadsUpNotificationView mHeadsUpNotificationView;
// on-screen navigation buttons
private NavigationBarView mNavigationBarView = null;
@@ -358,14 +352,11 @@ public class PhoneStatusBar extends BaseStatusBar {
.getDefaultDisplay();
mDisplay.getSize(mCurrentDisplaySize);
- mDreamManager = IDreamManager.Stub.asInterface(
- ServiceManager.checkService(DreamService.DREAM_SERVICE));
-
super.start(); // calls createAndAddWindows()
addNavigationBar();
- if (ENABLE_INTRUDERS) addIntruderView();
+ if (ENABLE_HEADS_UP) addHeadsUpView();
// Lastly, call to the icon policy to install/update all the icons.
mIconPolicy = new PhoneStatusBarPolicy(mContext);
@@ -424,10 +415,11 @@ public class PhoneStatusBar extends BaseStatusBar {
mNotificationPanel.setBackground(new FastColorDrawable(context.getResources().getColor(
R.color.notification_panel_solid_background)));
}
- if (ENABLE_INTRUDERS) {
- mIntruderAlertView = (IntruderAlertView) View.inflate(context, R.layout.intruder_alert, null);
- mIntruderAlertView.setVisibility(View.GONE);
- mIntruderAlertView.setBar(this);
+ if (ENABLE_HEADS_UP) {
+ mHeadsUpNotificationView =
+ (HeadsUpNotificationView) View.inflate(context, R.layout.heads_up, null);
+ mHeadsUpNotificationView.setVisibility(View.GONE);
+ mHeadsUpNotificationView.setBar(this);
}
if (MULTIUSER_DEBUG) {
mNotificationPanelDebugText = (TextView) mNotificationPanel.findViewById(R.id.header_debug_info);
@@ -833,7 +825,7 @@ public class PhoneStatusBar extends BaseStatusBar {
return lp;
}
- private void addIntruderView() {
+ private void addHeadsUpView() {
WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT,
@@ -847,11 +839,11 @@ public class PhoneStatusBar extends BaseStatusBar {
PixelFormat.TRANSLUCENT);
lp.gravity = Gravity.TOP | Gravity.FILL_HORIZONTAL;
//lp.y += height * 1.5; // FIXME
- lp.setTitle("IntruderAlert");
+ lp.setTitle("Heads Up");
lp.packageName = mContext.getPackageName();
- lp.windowAnimations = R.style.Animation_StatusBar_IntruderAlert;
+ lp.windowAnimations = R.style.Animation_StatusBar_HeadsUp;
- mWindowManager.addView(mIntruderAlertView, lp);
+ mWindowManager.addView(mHeadsUpNotificationView, lp);
}
public void refreshAllStatusBarIcons() {
@@ -895,52 +887,31 @@ public class PhoneStatusBar extends BaseStatusBar {
StatusBarIconView iconView = addNotificationViews(key, notification);
if (iconView == null) return;
- boolean immersive = false;
- try {
- immersive = ActivityManagerNative.getDefault().isTopActivityImmersive();
- if (DEBUG) {
- Log.d(TAG, "Top activity is " + (immersive?"immersive":"not immersive"));
- }
- } catch (RemoteException ex) {
- }
-
- /*
- * DISABLED due to missing API
- if (ENABLE_INTRUDERS && (
- // TODO(dsandler): Only if the screen is on
- notification.notification.intruderView != null)) {
- Log.d(TAG, "Presenting high-priority notification");
- // special new transient ticker mode
- // 1. Populate mIntruderAlertView
-
- if (notification.notification.intruderView == null) {
- Log.e(TAG, notification.notification.toString() + " wanted to intrude but intruderView was null");
- return;
- }
+ if (mUseHeadsUp && shouldInterrupt(notification)) {
+ if (DEBUG) Log.d(TAG, "launching notification in heads up mode");
+ // 1. Populate mHeadsUpNotificationView
// bind the click event to the content area
- PendingIntent contentIntent = notification.notification.contentIntent;
+ PendingIntent contentIntent = notification.getNotification().contentIntent;
final View.OnClickListener listener = (contentIntent != null)
? new NotificationClicker(contentIntent,
- notification.pkg, notification.tag, notification.id)
+ notification.getPackageName(), notification.getTag(), notification.getId())
: null;
- mIntruderAlertView.applyIntruderContent(notification.notification.intruderView, listener);
+ if (mHeadsUpNotificationView.applyContent(notification.getNotification(), listener)) {
- mCurrentlyIntrudingNotification = notification;
+ mCurrentlyInterruptingNotification = notification;
- // 2. Animate mIntruderAlertView in
- mHandler.sendEmptyMessage(MSG_SHOW_INTRUDER);
+ // 2. Animate mHeadsUpNotificationView in
+ mHandler.sendEmptyMessage(MSG_SHOW_HEADS_UP);
- // 3. Set alarm to age the notification off (TODO)
- mHandler.removeMessages(MSG_HIDE_INTRUDER);
- if (INTRUDER_ALERT_DECAY_MS > 0) {
- mHandler.sendEmptyMessageDelayed(MSG_HIDE_INTRUDER, INTRUDER_ALERT_DECAY_MS);
+ // 3. Set alarm to age the notification off (TODO)
+ mHandler.removeMessages(MSG_HIDE_HEADS_UP);
+ if (HEADS_UP_DECAY_MS > 0) {
+ mHandler.sendEmptyMessageDelayed(MSG_HIDE_HEADS_UP, HEADS_UP_DECAY_MS);
+ }
}
- } else
- */
-
- if (notification.getNotification().fullScreenIntent != null) {
+ } else if (notification.getNotification().fullScreenIntent != null) {
// Stop screensaver if the notification has a full-screen intent.
// (like an incoming phone call)
awakenDreams();
@@ -954,8 +925,8 @@ public class PhoneStatusBar extends BaseStatusBar {
} else {
// usual case: status bar visible & not immersive
- // show the ticker if there isn't an intruder too
- if (mCurrentlyIntrudingNotification == null) {
+ // show the ticker if there isn't already a heads up
+ if (mCurrentlyInterruptingNotification == null) {
tick(null, notification, true);
}
}
@@ -976,8 +947,8 @@ public class PhoneStatusBar extends BaseStatusBar {
// Recalculate the position of the sliding windows and the titles.
updateExpandedViewPos(EXPANDED_LEAVE_ALONE);
- if (ENABLE_INTRUDERS && old == mCurrentlyIntrudingNotification) {
- mHandler.sendEmptyMessage(MSG_HIDE_INTRUDER);
+ if (ENABLE_HEADS_UP && old == mCurrentlyInterruptingNotification) {
+ mHandler.sendEmptyMessage(MSG_HIDE_HEADS_UP);
}
if (CLOSE_PANEL_WHEN_EMPTIED && mNotificationData.size() == 0) {
@@ -1359,12 +1330,12 @@ public class PhoneStatusBar extends BaseStatusBar {
case MSG_CLOSE_PANELS:
animateCollapsePanels();
break;
- case MSG_SHOW_INTRUDER:
- setIntruderAlertVisibility(true);
+ case MSG_SHOW_HEADS_UP:
+ setHeadsUpVisibility(true);
break;
- case MSG_HIDE_INTRUDER:
- setIntruderAlertVisibility(false);
- mCurrentlyIntrudingNotification = null;
+ case MSG_HIDE_HEADS_UP:
+ setHeadsUpVisibility(false);
+ mCurrentlyInterruptingNotification = null;
break;
}
}
@@ -2487,22 +2458,20 @@ public class PhoneStatusBar extends BaseStatusBar {
mCurrentUserId);
}
- private void setIntruderAlertVisibility(boolean vis) {
- if (!ENABLE_INTRUDERS) return;
- if (DEBUG) {
- Log.v(TAG, (vis ? "showing" : "hiding") + " intruder alert window");
- }
- mIntruderAlertView.setVisibility(vis ? View.VISIBLE : View.GONE);
+ private void setHeadsUpVisibility(boolean vis) {
+ if (!ENABLE_HEADS_UP) return;
+ if (DEBUG) Log.v(TAG, (vis ? "showing" : "hiding") + " heads up window");
+ mHeadsUpNotificationView.setVisibility(vis ? View.VISIBLE : View.GONE);
}
- public void dismissIntruder() {
- if (mCurrentlyIntrudingNotification == null) return;
+ public void dismissHeadsUp() {
+ if (mCurrentlyInterruptingNotification == null) return;
try {
mBarService.onNotificationClear(
- mCurrentlyIntrudingNotification.getPackageName(),
- mCurrentlyIntrudingNotification.getTag(),
- mCurrentlyIntrudingNotification.getId());
+ mCurrentlyInterruptingNotification.getPackageName(),
+ mCurrentlyInterruptingNotification.getTag(),
+ mCurrentlyInterruptingNotification.getId());
} catch (android.os.RemoteException ex) {
// oh well
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/IntruderAlertView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java
index dbd36affcfd9..dbf9957461c0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/IntruderAlertView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.policy;
+import android.app.Notification;
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Rect;
@@ -27,14 +28,13 @@ import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.widget.LinearLayout;
-import android.widget.RemoteViews;
import com.android.systemui.R;
import com.android.systemui.SwipeHelper;
import com.android.systemui.statusbar.BaseStatusBar;
-public class IntruderAlertView extends LinearLayout implements SwipeHelper.Callback {
- private static final String TAG = "IntruderAlertView";
+public class HeadsUpNotificationView extends LinearLayout implements SwipeHelper.Callback {
+ private static final String TAG = "HeadsUpNotificationView";
private static final boolean DEBUG = false;
Rect mTmpRect = new Rect();
@@ -44,14 +44,14 @@ public class IntruderAlertView extends LinearLayout implements SwipeHelper.Callb
BaseStatusBar mBar;
private ViewGroup mContentHolder;
- private RemoteViews mIntruderRemoteViews;
+ private Notification mHeadsUp;
private OnClickListener mOnClickListener;
- public IntruderAlertView(Context context, AttributeSet attrs) {
+ public HeadsUpNotificationView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
- public IntruderAlertView(Context context, AttributeSet attrs, int defStyle) {
+ public HeadsUpNotificationView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
setOrientation(LinearLayout.VERTICAL);
@@ -64,9 +64,9 @@ public class IntruderAlertView extends LinearLayout implements SwipeHelper.Callb
mSwipeHelper = new SwipeHelper(SwipeHelper.X, this, densityScale, pagingTouchSlop);
mContentHolder = (ViewGroup) findViewById(R.id.contentHolder);
- if (mIntruderRemoteViews != null) {
+ if (mHeadsUp != null) {
// whoops, we're on already!
- applyIntruderContent(mIntruderRemoteViews, mOnClickListener);
+ applyContent(mHeadsUp, mOnClickListener);
}
}
@@ -92,8 +92,8 @@ public class IntruderAlertView extends LinearLayout implements SwipeHelper.Callb
}
public void onChildDismissed(View v) {
- Log.v(TAG, "User swiped intruder to dismiss");
- mBar.dismissIntruder();
+ Log.v(TAG, "User swiped heads up to dismiss");
+ mBar.dismissHeadsUp();
}
public void onBeginDrag(View v) {
@@ -134,33 +134,34 @@ public class IntruderAlertView extends LinearLayout implements SwipeHelper.Callb
}
}
- public void applyIntruderContent(RemoteViews intruderView, OnClickListener listener) {
- if (DEBUG) {
- Log.v(TAG, "applyIntruderContent: view=" + intruderView + " listener=" + listener);
- }
- mIntruderRemoteViews = intruderView;
+ public boolean applyContent(Notification headsUp, OnClickListener listener) {
+ mHeadsUp = headsUp;
mOnClickListener = listener;
- if (mContentHolder == null) {
+ if (mContentHolder == null) {
// too soon!
- return;
+ return false;
+ }
+ if (headsUp.contentView == null) {
+ // bad data
+ return false;
}
mContentHolder.setX(0);
mContentHolder.setVisibility(View.VISIBLE);
mContentHolder.setAlpha(1f);
mContentHolder.removeAllViews();
- final View content = intruderView.apply(getContext(), mContentHolder);
+ final View content = headsUp.contentView.apply(getContext(), mContentHolder);
if (listener != null) {
content.setOnClickListener(listener);
-
- //content.setBackgroundResource(R.drawable.intruder_row_bg);
- Drawable bg = getResources().getDrawable(R.drawable.intruder_row_bg);
+
+ Drawable bg = getResources().getDrawable(R.drawable.heads_up_notification_row_bg);
if (bg == null) {
- Log.e(TAG, String.format("Can't find background drawable id=0x%08x", R.drawable.intruder_row_bg));
+ Log.e(TAG, String.format("Can't find background drawable id=0x%08x",
+ R.drawable.heads_up_notification_row_bg));
} else {
content.setBackgroundDrawable(bg);
}
}
mContentHolder.addView(content);
-
+ return true;
}
} \ No newline at end of file
diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java
index 6e24d68301e7..1c1b0020b462 100644
--- a/services/java/com/android/server/InputMethodManagerService.java
+++ b/services/java/com/android/server/InputMethodManagerService.java
@@ -1511,23 +1511,16 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
final InputMethodInfo imi = mMethodMap.get(mCurMethodId);
if (imi != null && iconVisibility && needsToShowImeSwitchOngoingNotification()) {
// Used to load label
- final PackageManager pm = mContext.getPackageManager();
final CharSequence title = mRes.getText(
com.android.internal.R.string.select_input_method);
- final CharSequence imiLabel = imi.loadLabel(pm);
- final CharSequence summary = mCurrentSubtype != null
- ? TextUtils.concat(mCurrentSubtype.getDisplayName(mContext,
- imi.getPackageName(), imi.getServiceInfo().applicationInfo),
- (TextUtils.isEmpty(imiLabel) ?
- "" : " - " + imiLabel))
- : imiLabel;
+ final CharSequence summary = InputMethodUtils.getImeAndSubtypeDisplayName(
+ mContext, imi, mCurrentSubtype);
mImeSwitcherNotification.setLatestEventInfo(
mContext, title, summary, mImeSwitchPendingIntent);
if (mNotificationManager != null) {
if (DEBUG) {
- Slog.d(TAG, "--- show notification: label = " + imiLabel
- + ", summary = " + summary);
+ Slog.d(TAG, "--- show notification: label = " + summary);
}
mNotificationManager.notifyAsUser(null,
com.android.internal.R.string.select_input_method,
diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java
index 231cfe14c0c8..c6c9845979ad 100644
--- a/services/java/com/android/server/LocationManagerService.java
+++ b/services/java/com/android/server/LocationManagerService.java
@@ -47,7 +47,6 @@ import android.location.LocationRequest;
import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
-import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
@@ -222,6 +221,9 @@ public class LocationManagerService extends ILocationManager.Stub {
AppOpsManager.Callback callback = new AppOpsManager.Callback() {
public void opChanged(int op, String packageName) {
synchronized (mLock) {
+ for (Receiver receiver : mReceivers.values()) {
+ receiver.updateMonitoring(true);
+ }
applyAllProviderRequirementsLocked();
}
}
@@ -460,6 +462,7 @@ public class LocationManagerService extends ILocationManager.Stub {
final HashMap<String,UpdateRecord> mUpdateRecords = new HashMap<String,UpdateRecord>();
+ boolean mOpMonitoring;
int mPendingBroadcasts;
PowerManager.WakeLock mWakeLock;
@@ -477,6 +480,8 @@ public class LocationManagerService extends ILocationManager.Stub {
mPid = pid;
mPackageName = packageName;
+ updateMonitoring(true);
+
// construct/configure wakelock
mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY);
mWakeLock.setWorkSource(new WorkSource(mUid, mPackageName));
@@ -512,6 +517,21 @@ public class LocationManagerService extends ILocationManager.Stub {
return s.toString();
}
+ public void updateMonitoring(boolean allow) {
+ if (!mOpMonitoring) {
+ if (allow) {
+ mOpMonitoring = mAppOps.startOpNoThrow(AppOpsManager.OP_MONITOR_LOCATION,
+ mUid, mPackageName) == AppOpsManager.MODE_ALLOWED;
+ }
+ } else {
+ if (!allow || mAppOps.checkOpNoThrow(AppOpsManager.OP_MONITOR_LOCATION,
+ mUid, mPackageName) != AppOpsManager.MODE_ALLOWED) {
+ mAppOps.finishOp(AppOpsManager.OP_MONITOR_LOCATION, mUid, mPackageName);
+ mOpMonitoring = false;
+ }
+ }
+ }
+
public boolean isListener() {
return mListener != null;
}
@@ -1366,6 +1386,8 @@ public class LocationManagerService extends ILocationManager.Stub {
}
}
+ receiver.updateMonitoring(false);
+
// Record which providers were associated with this listener
HashSet<String> providers = new HashSet<String>();
HashMap<String, UpdateRecord> oldRecords = receiver.mUpdateRecords;
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index e41f6424be8c..f99f4baa540c 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -1782,7 +1782,7 @@ public final class ActivityManagerService extends ActivityManagerNative
return;
}
- mActivityManagerService.dumpProcessTracker(fd, pw, args);
+ mActivityManagerService.mProcessTracker.dump(fd, pw, args);
}
}
@@ -1808,7 +1808,7 @@ public final class ActivityManagerService extends ActivityManagerNative
: mBatteryStatsService.getActiveStatistics().getIsOnBattery();
mBatteryStatsService.getActiveStatistics().setCallback(this);
- mProcessTracker = new ProcessTracker(new File(systemDir, "procstats"));
+ mProcessTracker = new ProcessTracker(this, new File(systemDir, "procstats"));
mUsageStatsService = new UsageStatsService(new File(systemDir, "usagestats").toString());
mAppOpsService = new AppOpsService(new File(systemDir, "appops.xml"));
@@ -11371,12 +11371,6 @@ public final class ActivityManagerService extends ActivityManagerNative
return false;
}
- final void dumpProcessTracker(FileDescriptor fd, PrintWriter pw, String[] args) {
- synchronized (this) {
- mProcessTracker.dumpLocked(fd, pw, args);
- }
- }
-
private final boolean removeDyingProviderLocked(ProcessRecord proc,
ContentProviderRecord cpr, boolean always) {
final boolean inLaunching = mLaunchingProviders.contains(cpr);
diff --git a/services/java/com/android/server/am/BroadcastQueue.java b/services/java/com/android/server/am/BroadcastQueue.java
index 0e7513c926a9..5238bd18f5ba 100644
--- a/services/java/com/android/server/am/BroadcastQueue.java
+++ b/services/java/com/android/server/am/BroadcastQueue.java
@@ -410,7 +410,7 @@ public final class BroadcastQueue {
}
}
if (r.appOp != AppOpsManager.OP_NONE) {
- int mode = mService.mAppOpsService.checkOperation(r.appOp,
+ int mode = mService.mAppOpsService.noteOperation(r.appOp,
filter.receiverList.uid, filter.packageName);
if (mode != AppOpsManager.MODE_ALLOWED) {
if (DEBUG_BROADCAST) Slog.v(TAG,
@@ -717,7 +717,7 @@ public final class BroadcastQueue {
}
}
if (r.appOp != AppOpsManager.OP_NONE) {
- int mode = mService.mAppOpsService.checkOperation(r.appOp,
+ int mode = mService.mAppOpsService.noteOperation(r.appOp,
info.activityInfo.applicationInfo.uid, info.activityInfo.packageName);
if (mode != AppOpsManager.MODE_ALLOWED) {
if (DEBUG_BROADCAST) Slog.v(TAG,
diff --git a/services/java/com/android/server/am/ProcessRecord.java b/services/java/com/android/server/am/ProcessRecord.java
index 1671d24b0d8e..14f410206a6b 100644
--- a/services/java/com/android/server/am/ProcessRecord.java
+++ b/services/java/com/android/server/am/ProcessRecord.java
@@ -425,8 +425,14 @@ final class ProcessRecord {
} else {
sb.append('u');
sb.append(userId);
- sb.append('a');
- sb.append(UserHandle.getAppId(info.uid));
+ int appId = UserHandle.getAppId(info.uid);
+ if (appId >= Process.FIRST_APPLICATION_UID) {
+ sb.append('a');
+ sb.append(appId - Process.FIRST_APPLICATION_UID);
+ } else {
+ sb.append('s');
+ sb.append(appId);
+ }
if (uid != info.uid) {
sb.append('i');
sb.append(UserHandle.getAppId(uid) - Process.FIRST_ISOLATED_UID);
diff --git a/services/java/com/android/server/am/ProcessTracker.java b/services/java/com/android/server/am/ProcessTracker.java
index 488582d4135f..0ea93e828a92 100644
--- a/services/java/com/android/server/am/ProcessTracker.java
+++ b/services/java/com/android/server/am/ProcessTracker.java
@@ -140,9 +140,12 @@ public final class ProcessTracker {
static final int MAX_HISTORIC_STATES = 4; // Maximum number of historic states we will keep.
static final String STATE_FILE_PREFIX = "state-"; // Prefix to use for state filenames.
+ static final String STATE_FILE_SUFFIX = ".bin"; // Suffix to use for state filenames.
+ static final String STATE_FILE_CHECKIN_SUFFIX = ".ci"; // State files that have checked in.
static long WRITE_PERIOD = 30*60*1000; // Write file every 30 minutes or so.
static long COMMIT_PERIOD = 24*60*60*1000; // Commit current stats every day.
+ final Object mLock;
final File mBaseDir;
State mState;
boolean mCommitPending;
@@ -694,7 +697,7 @@ public final class ProcessTracker {
mTimePeriodStartClock).toString();
if (mBaseDir != null) {
mFile = new AtomicFile(new File(mBaseDir,
- STATE_FILE_PREFIX + mTimePeriodStartClockStr));
+ STATE_FILE_PREFIX + mTimePeriodStartClockStr + STATE_FILE_SUFFIX));
}
}
@@ -1255,8 +1258,7 @@ public final class ProcessTracker {
return ps;
}
- void dumpLocked(PrintWriter pw, String reqPackage, boolean dumpAll) {
- final long now = SystemClock.uptimeMillis();
+ void dumpLocked(PrintWriter pw, String reqPackage, long now, boolean dumpAll) {
ArrayMap<String, SparseArray<PackageState>> pkgMap = mPackages.getMap();
boolean printedHeader = false;
for (int ip=0; ip<pkgMap.size(); ip++) {
@@ -1318,29 +1320,53 @@ public final class ProcessTracker {
}
}
- dumpFilteredProcesses(pw, "Processes running while critical mem:", " ",
- new int[] {ADJ_SCREEN_OFF, ADJ_SCREEN_ON},
- new int[] {ADJ_MEM_FACTOR_CRITICAL},
- new int[] {STATE_PERSISTENT, STATE_TOP, STATE_FOREGROUND, STATE_VISIBLE,
- STATE_PERCEPTIBLE, STATE_BACKUP, STATE_SERVICE, STATE_HOME, STATE_PREVIOUS},
- now, reqPackage);
- dumpFilteredProcesses(pw, "Processes running while low mem:", " ",
- new int[] {ADJ_SCREEN_OFF, ADJ_SCREEN_ON},
- new int[] {ADJ_MEM_FACTOR_LOW},
- new int[] {STATE_PERSISTENT, STATE_TOP, STATE_FOREGROUND, STATE_VISIBLE,
- STATE_PERCEPTIBLE, STATE_BACKUP, STATE_SERVICE, STATE_HOME, STATE_PREVIOUS},
- now, reqPackage);
- dumpFilteredProcesses(pw, "Processes running while moderate mem:", " ",
- new int[] {ADJ_SCREEN_OFF, ADJ_SCREEN_ON},
- new int[] {ADJ_MEM_FACTOR_MODERATE},
- new int[] {STATE_PERSISTENT, STATE_TOP, STATE_FOREGROUND, STATE_VISIBLE,
- STATE_PERCEPTIBLE, STATE_BACKUP, STATE_SERVICE, STATE_HOME, STATE_PREVIOUS},
- now, reqPackage);
- dumpFilteredProcesses(pw, "Processes running while normal mem:", " ",
- new int[] {ADJ_SCREEN_OFF, ADJ_SCREEN_ON},
- new int[] {ADJ_MEM_FACTOR_NORMAL},
- new int[] {STATE_PERSISTENT, STATE_TOP, STATE_FOREGROUND, STATE_VISIBLE,
- STATE_PERCEPTIBLE, STATE_BACKUP, STATE_SERVICE, STATE_HOME, STATE_PREVIOUS},
+ if (reqPackage == null) {
+ ArrayMap<String, SparseArray<ProcessState>> procMap = mProcesses.getMap();
+ printedHeader = false;
+ for (int ip=0; ip<procMap.size(); ip++) {
+ String procName = procMap.keyAt(ip);
+ SparseArray<ProcessState> uids = procMap.valueAt(ip);
+ for (int iu=0; iu<uids.size(); iu++) {
+ int uid = uids.keyAt(iu);
+ ProcessState proc = uids.valueAt(iu);
+ if (proc.mDurationsTableSize == 0 && proc.mCurState == STATE_NOTHING
+ && proc.mPssTableSize == 0) {
+ continue;
+ }
+ if (!printedHeader) {
+ pw.println("Process Stats:");
+ printedHeader = true;
+ }
+ pw.print(" * "); pw.print(procName); pw.print(" / ");
+ UserHandle.formatUid(pw, uid);
+ pw.print(" ("); pw.print(proc.mDurationsTableSize);
+ pw.print(" entries)"); pw.println(":");
+ dumpProcessState(pw, " ", proc, ALL_SCREEN_ADJ, ALL_MEM_ADJ,
+ ALL_PROC_STATES, now);
+ dumpProcessPss(pw, " ", proc, ALL_SCREEN_ADJ, ALL_MEM_ADJ,
+ ALL_PROC_STATES);
+ }
+ }
+
+ pw.println();
+ pw.println("Summary:");
+ dumpSummaryLocked(pw, reqPackage, now);
+ }
+
+ if (dumpAll) {
+ pw.println();
+ pw.println("Internal state:");
+ pw.print(" mFile="); pw.println(mFile.getBaseFile());
+ pw.print(" Num long arrays: "); pw.println(mLongs.size());
+ pw.print(" Next long entry: "); pw.println(mNextLong);
+ pw.print(" mRunning="); pw.println(mRunning);
+ }
+ }
+
+ void dumpSummaryLocked(PrintWriter pw, String reqPackage, long now) {
+ dumpFilteredSummaryLocked(pw, null, " ", ALL_SCREEN_ADJ, ALL_MEM_ADJ,
+ new int[] { STATE_PERSISTENT, STATE_TOP, STATE_FOREGROUND, STATE_VISIBLE,
+ STATE_PERCEPTIBLE, STATE_BACKUP, STATE_SERVICE, STATE_HOME, STATE_PREVIOUS },
now, reqPackage);
pw.println();
pw.println("Run time Stats:");
@@ -1352,26 +1378,20 @@ public final class ProcessTracker {
pw.print(" Total elapsed time: ");
TimeUtils.formatDuration(
(mRunning ? SystemClock.elapsedRealtime() : mTimePeriodEndRealtime)
- - mTimePeriodStartRealtime, pw);
+ - mTimePeriodStartRealtime, pw);
pw.println();
- if (dumpAll) {
- pw.println();
- pw.println("Internal state:");
- pw.print(" mFile="); pw.println(mFile.getBaseFile());
- pw.print(" Num long arrays: "); pw.println(mLongs.size());
- pw.print(" Next long entry: "); pw.println(mNextLong);
- pw.print(" mRunning="); pw.println(mRunning);
- }
}
- void dumpFilteredProcesses(PrintWriter pw, String header, String prefix,
+ void dumpFilteredSummaryLocked(PrintWriter pw, String header, String prefix,
int[] screenStates, int[] memStates, int[] procStates, long now, String reqPackage) {
ArrayList<ProcessState> procs = collectProcessesLocked(screenStates, memStates,
procStates, now, reqPackage);
if (procs.size() > 0) {
- pw.println();
- pw.println(header);
- dumpProcessList(pw, prefix, procs, screenStates, memStates, procStates, now);
+ if (header != null) {
+ pw.println();
+ pw.println(header);
+ }
+ dumpProcessSummary(pw, prefix, procs, screenStates, memStates, procStates, now);
}
}
@@ -1542,7 +1562,8 @@ public final class ProcessTracker {
}
}
- public ProcessTracker(File file) {
+ public ProcessTracker(Object lock, File file) {
+ mLock = lock;
mBaseDir = file;
mBaseDir.mkdirs();
mState = new State(mBaseDir, this);
@@ -1637,27 +1658,34 @@ public final class ProcessTracker {
mState.writeStateLocked(sync, commitPending);
}
- private ArrayList<String> getCommittedFiles(int minNum) {
+ private ArrayList<String> getCommittedFiles(int minNum, boolean inclAll) {
File[] files = mBaseDir.listFiles();
if (files == null || files.length <= minNum) {
return null;
}
ArrayList<String> filesArray = new ArrayList<String>(files.length);
- String currentFile = mState.mFile.getBaseFile().toString();
+ String currentFile = mState.mFile.getBaseFile().getPath();
if (DEBUG) Slog.d(TAG, "Collecting " + files.length + " files except: " + currentFile);
for (int i=0; i<files.length; i++) {
File file = files[i];
- if (DEBUG) Slog.d(TAG, "Collecting: " + file);
- if (!file.toString().equals(currentFile)) {
- filesArray.add(files[i].toString());
+ String fileStr = file.getPath();
+ if (DEBUG) Slog.d(TAG, "Collecting: " + fileStr);
+ if (!inclAll && fileStr.endsWith(STATE_FILE_CHECKIN_SUFFIX)) {
+ if (DEBUG) Slog.d(TAG, "Skipping: already checked in");
+ continue;
+ }
+ if (fileStr.equals(currentFile)) {
+ if (DEBUG) Slog.d(TAG, "Skipping: current stats");
+ continue;
}
+ filesArray.add(fileStr);
}
Collections.sort(filesArray);
return filesArray;
}
public void trimHistoricStatesWriteLocked() {
- ArrayList<String> filesArray = getCommittedFiles(MAX_HISTORIC_STATES);
+ ArrayList<String> filesArray = getCommittedFiles(MAX_HISTORIC_STATES, true);
if (filesArray == null) {
return;
}
@@ -1803,6 +1831,76 @@ public final class ProcessTracker {
pw.println();
}
+ static final class ProcessDataCollection {
+ final int[] screenStates;
+ final int[] memStates;
+ final int[] procStates;
+
+ long totalTime;
+ long numPss;
+ long minPss;
+ long avgPss;
+ long maxPss;
+
+ ProcessDataCollection(int[] _screenStates, int[] _memStates, int[] _procStates) {
+ screenStates = _screenStates;
+ memStates = _memStates;
+ procStates = _procStates;
+ }
+
+ void print(PrintWriter pw, boolean full) {
+ TimeUtils.formatDuration(totalTime, pw);
+ if (numPss > 0) {
+ pw.print(" (");
+ printSizeValue(pw, minPss * 1024);
+ pw.print("-");
+ printSizeValue(pw, avgPss * 1024);
+ pw.print("-");
+ printSizeValue(pw, maxPss * 1024);
+ if (full) {
+ pw.print(" over ");
+ pw.print(numPss);
+ }
+ pw.print(")");
+ }
+ }
+ }
+
+ static void computeProcessData(ProcessState proc, ProcessDataCollection data, long now) {
+ data.totalTime = 0;
+ data.numPss = data.minPss = data.avgPss = data.maxPss = 0;
+ for (int is=0; is<data.screenStates.length; is++) {
+ for (int im=0; im<data.memStates.length; im++) {
+ for (int ip=0; ip<data.procStates.length; ip++) {
+ int bucket = ((data.screenStates[is] + data.memStates[im]) * STATE_COUNT)
+ + data.procStates[ip];
+ data.totalTime += proc.getDuration(bucket, now);
+ long samples = proc.getPssSampleCount(bucket);
+ if (samples > 0) {
+ long minPss = proc.getPssMinimum(bucket);
+ long avgPss = proc.getPssAverage(bucket);
+ long maxPss = proc.getPssMaximum(bucket);
+ if (data.numPss == 0) {
+ data.minPss = minPss;
+ data.avgPss = avgPss;
+ data.maxPss = maxPss;
+ } else {
+ if (minPss < data.minPss) {
+ data.minPss = minPss;
+ }
+ data.avgPss = (long)( ((data.avgPss*(double)data.numPss)
+ + (avgPss*(double)samples)) / (data.numPss+samples) );
+ if (maxPss > data.maxPss) {
+ data.maxPss = maxPss;
+ }
+ }
+ data.numPss += samples;
+ }
+ }
+ }
+ }
+ }
+
static long computeProcessTimeLocked(ProcessState proc, int[] screenStates, int[] memStates,
int[] procStates, long now) {
long totalTime = 0;
@@ -1818,7 +1916,7 @@ public final class ProcessTracker {
for (int is=0; is<screenStates.length; is++) {
for (int im=0; im<memStates.length; im++) {
for (int ip=0; ip<procStates.length; ip++) {
- int bucket = ((screenStates[is]+ memStates[im]) * STATE_COUNT)
+ int bucket = ((screenStates[is] + memStates[im]) * STATE_COUNT)
+ procStates[ip];
totalTime += proc.getDuration(bucket, now);
}
@@ -1910,12 +2008,12 @@ public final class ProcessTracker {
pw.print(STATE_NAMES[procStates[ip]]); pw.print(": ");
pw.print(count);
pw.print(" samples ");
- pw.print(proc.getPssMinimum(bucket));
- pw.print("kB ");
- pw.print(proc.getPssAverage(bucket));
- pw.print("kB ");
- pw.print(proc.getPssMaximum(bucket));
- pw.println("kB");
+ printSizeValue(pw, proc.getPssMinimum(bucket) * 1024);
+ pw.print(" ");
+ printSizeValue(pw, proc.getPssAverage(bucket) * 1024);
+ pw.print(" ");
+ printSizeValue(pw, proc.getPssMaximum(bucket) * 1024);
+ pw.println();
}
}
}
@@ -2017,6 +2115,94 @@ public final class ProcessTracker {
}
}
+ static void dumpProcessSummaryDetails(PrintWriter pw, ProcessState proc, String prefix,
+ String label, int[] screenStates, int[] memStates, int[] procStates,
+ long now, boolean full) {
+ ProcessDataCollection totals = new ProcessDataCollection(screenStates,
+ memStates, procStates);
+ computeProcessData(proc, totals, now);
+ if (totals.totalTime != 0 || totals.numPss != 0) {
+ if (prefix != null) {
+ pw.print(prefix);
+ }
+ if (label != null) {
+ pw.print(label);
+ }
+ totals.print(pw, full);
+ if (prefix != null) {
+ pw.println();
+ }
+ }
+ }
+
+ static void dumpProcessSummary(PrintWriter pw, String prefix, ArrayList<ProcessState> procs,
+ int[] screenStates, int[] memStates, int[] procStates, long now) {
+ for (int i=procs.size()-1; i>=0; i--) {
+ ProcessState proc = procs.get(i);
+ pw.print(prefix);
+ pw.print("* ");
+ pw.print(proc.mName);
+ pw.print(" / ");
+ UserHandle.formatUid(pw, proc.mUid);
+ pw.println(":");
+ dumpProcessSummaryDetails(pw, proc, prefix, " TOTAL: ", screenStates, memStates,
+ procStates, now, true);
+ dumpProcessSummaryDetails(pw, proc, prefix, " Persistent: ", screenStates, memStates,
+ new int[] {STATE_PERSISTENT}, now, true);
+ dumpProcessSummaryDetails(pw, proc, prefix, " Top: ", screenStates, memStates,
+ new int[] {STATE_TOP}, now, true);
+ dumpProcessSummaryDetails(pw, proc, prefix, " Foreground: ", screenStates, memStates,
+ new int[] {STATE_FOREGROUND, STATE_VISIBLE, STATE_PERCEPTIBLE}, now, true);
+ dumpProcessSummaryDetails(pw, proc, prefix, " Backup: ", screenStates, memStates,
+ new int[] {STATE_BACKUP}, now, true);
+ dumpProcessSummaryDetails(pw, proc, prefix, " Service: ", screenStates, memStates,
+ new int[] {STATE_SERVICE}, now, true);
+ dumpProcessSummaryDetails(pw, proc, prefix, " Home: ", screenStates, memStates,
+ new int[] {STATE_HOME}, now, true);
+ dumpProcessSummaryDetails(pw, proc, prefix, " Previous: ", screenStates, memStates,
+ new int[] {STATE_PREVIOUS}, now, true);
+ dumpProcessSummaryDetails(pw, proc, prefix, " (Cached): ", screenStates, memStates,
+ new int[] {STATE_CACHED}, now, true);
+ }
+ }
+
+ private static void printSizeValue(PrintWriter pw, long number) {
+ float result = number;
+ String suffix = "";
+ if (result > 900) {
+ suffix = "KB";
+ result = result / 1024;
+ }
+ if (result > 900) {
+ suffix = "MB";
+ result = result / 1024;
+ }
+ if (result > 900) {
+ suffix = "GB";
+ result = result / 1024;
+ }
+ if (result > 900) {
+ suffix = "TB";
+ result = result / 1024;
+ }
+ if (result > 900) {
+ suffix = "PB";
+ result = result / 1024;
+ }
+ String value;
+ if (result < 1) {
+ value = String.format("%.2f", result);
+ } else if (result < 10) {
+ value = String.format("%.2f", result);
+ } else if (result < 100) {
+ value = String.format("%.2f", result);
+ } else {
+ value = String.format("%.0f", result);
+ }
+ pw.print(value);
+ pw.print(suffix);
+ }
+
static void dumpProcessListCsv(PrintWriter pw, ArrayList<ProcessState> procs,
boolean sepScreenStates, int[] screenStates, boolean sepMemStates, int[] memStates,
boolean sepProcStates, int[] procStates, long now) {
@@ -2171,7 +2357,7 @@ public final class ProcessTracker {
static private void dumpHelp(PrintWriter pw) {
pw.println("Process stats (procstats) dump options:");
pw.println(" [--checkin|-c|--csv] [--csv-screen] [--csv-proc] [--csv-mem]");
- pw.println(" [--include-committed] [--commit] [--write] [-h] [<package.name>]");
+ pw.println(" [--details] [--current] [--commit] [--write] [-h] [<package.name>]");
pw.println(" --checkin: perform a checkin: print and delete old committed states.");
pw.println(" --c: print only state in checkin format.");
pw.println(" --csv: output data suitable for putting in a spreadsheet.");
@@ -2179,7 +2365,8 @@ public final class ProcessTracker {
pw.println(" --csv-mem: norm, mod, low, crit.");
pw.println(" --csv-proc: pers, top, fore, vis, precept, backup,");
pw.println(" service, home, prev, cached");
- pw.println(" --include-committed: also dump any old committed states.");
+ pw.println(" --details: dump all execution details, not just summary.");
+ pw.println(" --current: only dump current state.");
pw.println(" --commit: commit current stats to disk and reset to start new stats.");
pw.println(" --write: write current in-memory stats to disk.");
pw.println(" --read: replace current stats with last-written stats.");
@@ -2188,13 +2375,14 @@ public final class ProcessTracker {
pw.println(" <package.name>: optional name of package to filter output by.");
}
- public void dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args) {
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
final long now = SystemClock.uptimeMillis();
boolean isCheckin = false;
boolean isCompact = false;
boolean isCsv = false;
- boolean includeCommitted = false;
+ boolean currentOnly = false;
+ boolean dumpDetails = false;
boolean dumpAll = false;
String reqPackage = null;
boolean csvSepScreenStats = false;
@@ -2264,8 +2452,10 @@ public final class ProcessTracker {
return;
}
csvSepProcStats = sep[0];
- } else if ("--include-committed".equals(arg)) {
- includeCommitted = true;
+ } else if ("--details".equals(arg)) {
+ dumpDetails = true;
+ } else if ("--current".equals(arg)) {
+ currentOnly = true;
} else if ("--commit".equals(arg)) {
mState.writeStateLocked(true, true);
pw.println("Process stats committed.");
@@ -2282,8 +2472,8 @@ public final class ProcessTracker {
dumpHelp(pw);
return;
} else if ("-a".equals(arg)) {
+ dumpDetails = true;
dumpAll = true;
- includeCommitted = true;
} else if (arg.length() > 0 && arg.charAt(0) == '-'){
pw.println("Unknown option: " + arg);
dumpHelp(pw);
@@ -2294,9 +2484,11 @@ public final class ProcessTracker {
IPackageManager pm = AppGlobals.getPackageManager();
if (pm.getPackageUid(arg, UserHandle.getCallingUserId()) >= 0) {
reqPackage = arg;
- // We will automatically include all committed state,
- // since we are going to end up with much less printed.
- includeCommitted = true;
+ // Include all details, since we know we are only going to
+ // be dumping a smaller set of data. In fact only the details
+ // container per-package data, so that are needed to be able
+ // to dump anything at all when filtering by package.
+ dumpDetails = true;
}
} catch (RemoteException e) {
}
@@ -2330,70 +2522,94 @@ public final class ProcessTracker {
}
}
pw.println();
- dumpFilteredProcessesCsvLocked(pw, null,
- csvSepScreenStats, csvScreenStats, csvSepMemStats, csvMemStats,
- csvSepProcStats, csvProcStats, now, reqPackage);
- /*
- dumpFilteredProcessesCsvLocked(pw, "Processes running while critical mem:",
- false, new int[] {ADJ_SCREEN_OFF, ADJ_SCREEN_ON},
- true, new int[] {ADJ_MEM_FACTOR_CRITICAL},
- true, new int[] {STATE_PERSISTENT, STATE_TOP, STATE_FOREGROUND, STATE_VISIBLE,
- STATE_PERCEPTIBLE, STATE_BACKUP, STATE_SERVICE, STATE_HOME,
- STATE_PREVIOUS, STATE_CACHED},
- now, reqPackage);
- dumpFilteredProcessesCsvLocked(pw, "Processes running over all mem:",
- false, new int[] {ADJ_SCREEN_OFF, ADJ_SCREEN_ON},
- false, new int[] {ADJ_MEM_FACTOR_CRITICAL, ADJ_MEM_FACTOR_LOW,
- ADJ_MEM_FACTOR_MODERATE, ADJ_MEM_FACTOR_MODERATE},
- true, new int[] {STATE_PERSISTENT, STATE_TOP, STATE_FOREGROUND, STATE_VISIBLE,
- STATE_PERCEPTIBLE, STATE_BACKUP, STATE_SERVICE, STATE_HOME,
- STATE_PREVIOUS, STATE_CACHED},
- now, reqPackage);
- */
+ synchronized (mLock) {
+ dumpFilteredProcessesCsvLocked(pw, null,
+ csvSepScreenStats, csvScreenStats, csvSepMemStats, csvMemStats,
+ csvSepProcStats, csvProcStats, now, reqPackage);
+ /*
+ dumpFilteredProcessesCsvLocked(pw, "Processes running while critical mem:",
+ false, new int[] {ADJ_SCREEN_OFF, ADJ_SCREEN_ON},
+ true, new int[] {ADJ_MEM_FACTOR_CRITICAL},
+ true, new int[] {STATE_PERSISTENT, STATE_TOP, STATE_FOREGROUND, STATE_VISIBLE,
+ STATE_PERCEPTIBLE, STATE_BACKUP, STATE_SERVICE, STATE_HOME,
+ STATE_PREVIOUS, STATE_CACHED},
+ now, reqPackage);
+ dumpFilteredProcessesCsvLocked(pw, "Processes running over all mem:",
+ false, new int[] {ADJ_SCREEN_OFF, ADJ_SCREEN_ON},
+ false, new int[] {ADJ_MEM_FACTOR_CRITICAL, ADJ_MEM_FACTOR_LOW,
+ ADJ_MEM_FACTOR_MODERATE, ADJ_MEM_FACTOR_MODERATE},
+ true, new int[] {STATE_PERSISTENT, STATE_TOP, STATE_FOREGROUND, STATE_VISIBLE,
+ STATE_PERCEPTIBLE, STATE_BACKUP, STATE_SERVICE, STATE_HOME,
+ STATE_PREVIOUS, STATE_CACHED},
+ now, reqPackage);
+ */
+ }
return;
}
boolean sepNeeded = false;
- if (includeCommitted || isCheckin) {
- ArrayList<String> files = getCommittedFiles(0);
- if (files != null) {
- for (int i=0; i<files.size(); i++) {
- if (DEBUG) Slog.d(TAG, "Retrieving state: " + files.get(i));
- try {
- State state = new State(files.get(i));
- if (isCheckin || isCompact) {
- state.dumpCheckinLocked(pw, reqPackage);
- } else {
- if (sepNeeded) {
- pw.println();
+ if (!currentOnly || isCheckin) {
+ mWriteLock.lock();
+ try {
+ ArrayList<String> files = getCommittedFiles(0, !isCheckin);
+ if (files != null) {
+ for (int i=0; i<files.size(); i++) {
+ if (DEBUG) Slog.d(TAG, "Retrieving state: " + files.get(i));
+ try {
+ State state = new State(files.get(i));
+ String fileStr = state.mFile.getBaseFile().getPath();
+ boolean checkedIn = fileStr.endsWith(STATE_FILE_CHECKIN_SUFFIX);
+ if (isCheckin || isCompact) {
+ // Don't really need to lock because we uniquely own this object.
+ state.dumpCheckinLocked(pw, reqPackage);
} else {
- sepNeeded = true;
+ if (sepNeeded) {
+ pw.println();
+ } else {
+ sepNeeded = true;
+ }
+ pw.print("COMMITTED STATS FROM ");
+ pw.print(state.mTimePeriodStartClockStr);
+ if (checkedIn) pw.print(" (checked in)");
+ pw.println(":");
+ // Don't really need to lock because we uniquely own this object.
+ if (dumpDetails) {
+ state.dumpLocked(pw, reqPackage, now, dumpAll);
+ } else {
+ state.dumpSummaryLocked(pw, reqPackage, now);
+ }
}
- pw.print("COMMITTED STATS FROM ");
- pw.print(state.mTimePeriodStartClockStr);
- pw.println(":");
- state.dumpLocked(pw, reqPackage, dumpAll);
- }
- if (isCheckin) {
- state.mFile.delete();
+ if (isCheckin) {
+ // Rename file suffix to mark that it has checked in.
+ state.mFile.getBaseFile().renameTo(new File(
+ fileStr + STATE_FILE_CHECKIN_SUFFIX));
+ }
+ } catch (Throwable e) {
+ pw.print("**** FAILURE DUMPING STATE: "); pw.println(files.get(i));
+ e.printStackTrace(pw);
}
- } catch (Throwable e) {
- pw.print("**** FAILURE DUMPING STATE: "); pw.println(files.get(i));
- e.printStackTrace(pw);
+ if (DEBUG) Slog.d(TAG, "Deleting state: " + files.get(i));
}
- if (DEBUG) Slog.d(TAG, "Deleting state: " + files.get(i));
}
+ } finally {
+ mWriteLock.unlock();
}
}
if (!isCheckin) {
- if (isCompact) {
- mState.dumpCheckinLocked(pw, reqPackage);
- } else {
- if (sepNeeded) {
- pw.println();
- pw.println("CURRENT STATS:");
+ synchronized (mLock) {
+ if (isCompact) {
+ mState.dumpCheckinLocked(pw, reqPackage);
+ } else {
+ if (sepNeeded) {
+ pw.println();
+ pw.println("CURRENT STATS:");
+ }
+ if (dumpDetails) {
+ mState.dumpLocked(pw, reqPackage, now, dumpAll);
+ } else {
+ mState.dumpSummaryLocked(pw, reqPackage, now);
+ }
}
- mState.dumpLocked(pw, reqPackage, dumpAll);
}
}
}
diff --git a/services/java/com/android/server/pm/KeySetManager.java b/services/java/com/android/server/pm/KeySetManager.java
index 3480b195b3f7..93992c21f328 100644
--- a/services/java/com/android/server/pm/KeySetManager.java
+++ b/services/java/com/android/server/pm/KeySetManager.java
@@ -69,7 +69,7 @@ public class KeySetManager {
mPackages = packages;
}
- /*
+ /**
* Determine if a package is signed by the given KeySet.
*
* Returns false if the package was not signed by all the
@@ -94,7 +94,7 @@ public class KeySetManager {
}
}
- /*
+ /**
* This informs the system that the given package has defined a KeySet
* in its manifest that a) contains the given keys and b) is named
* alias by that package.
@@ -116,7 +116,7 @@ public class KeySetManager {
}
}
- /*
+ /**
* Similar to the above, this informs the system that the given package
* was signed by the provided KeySet.
*/
@@ -153,10 +153,9 @@ public class KeySetManager {
}
}
- /*
- * Fetches the stable identifier associated with the given KeySet.
- *
- * Returns KEYSET_NOT_FOUND if the KeySet... wasn't found.
+ /**
+ * Fetches the stable identifier associated with the given KeySet. Returns
+ * {@link #KEYSET_NOT_FOUND} if the KeySet... wasn't found.
*/
public long getIdByKeySet(KeySet ks) {
synchronized (mLockObject) {
@@ -174,10 +173,11 @@ public class KeySetManager {
return KEYSET_NOT_FOUND;
}
- /*
+ /**
* Fetches the KeySet corresponding to the given stable identifier.
*
- * Returns KEYSET_NOT_FOUND if the identifier doesn't identify a KeySet.
+ * Returns {@link #KEYSET_NOT_FOUND} if the identifier doesn't
+ * identify a {@link KeySet}.
*/
public KeySet getKeySetById(long id) {
synchronized (mLockObject) {
@@ -185,7 +185,7 @@ public class KeySetManager {
}
}
- /*
+ /**
* Fetches the KeySet that a given package refers to by the provided alias.
*
* If the package isn't known to us, throws an IllegalArgumentException.
@@ -205,10 +205,9 @@ public class KeySetManager {
}
}
- /*
- * Fetches all the known KeySets that signed the given package.
- *
- * If the package is unknown to us, throws an IllegalArgumentException.
+ /**
+ * Fetches all the known {@link KeySet KeySets} that signed the given
+ * package. Returns {@code null} if package is unknown.
*/
public Set<KeySet> getSigningKeySetsByPackageName(String packageName) {
synchronized (mLockObject) {
@@ -227,16 +226,16 @@ public class KeySetManager {
}
}
- /*
+ /**
* Creates a new KeySet corresponding to the given keys.
*
- * If the PublicKeys aren't known to the system, this adds them. Otherwise,
- * they're deduped.
+ * If the {@link PublicKey PublicKeys} aren't known to the system, this
+ * adds them. Otherwise, they're deduped.
*
* If the KeySet isn't known to the system, this adds that and creates the
* mapping to the PublicKeys. If it is known, then it's deduped.
*
- * Throws if the provided set is null.
+ * Throws if the provided set is {@code null}.
*/
private KeySet addKeySetLocked(Set<PublicKey> keys) {
if (keys == null) {
@@ -267,7 +266,7 @@ public class KeySetManager {
return ks;
}
- /*
+ /**
* Adds the given PublicKey to the system, deduping as it goes.
*/
private long addPublicKeyLocked(PublicKey key) {
@@ -284,7 +283,7 @@ public class KeySetManager {
return id;
}
- /*
+ /**
* Finds the stable identifier for a KeySet based on a set of PublicKey stable IDs.
*
* Returns KEYSET_NOT_FOUND if there isn't one.
@@ -299,7 +298,7 @@ public class KeySetManager {
return KEYSET_NOT_FOUND;
}
- /*
+ /**
* Finds the stable identifier for a PublicKey or PUBLIC_KEY_NOT_FOUND.
*/
private long getIdForPublicKeyLocked(PublicKey k) {
@@ -314,7 +313,7 @@ public class KeySetManager {
return PUBLIC_KEY_NOT_FOUND;
}
- /*
+ /**
* Gets an unused stable identifier for a KeySet.
*/
private long getFreeKeySetIDLocked() {
@@ -322,7 +321,7 @@ public class KeySetManager {
return lastIssuedKeySetId;
}
- /*
+ /**
* Same as above, but for public keys.
*/
private long getFreePublicKeyIdLocked() {
diff --git a/services/java/com/android/server/pm/UserManagerService.java b/services/java/com/android/server/pm/UserManagerService.java
index d86f2c75c08e..29012127b04e 100644
--- a/services/java/com/android/server/pm/UserManagerService.java
+++ b/services/java/com/android/server/pm/UserManagerService.java
@@ -822,6 +822,11 @@ public class UserManagerService extends IUserManager.Stub {
pinState.failedAttempts = failedAttempts;
pinState.lastAttemptTime = lastAttemptTime;
}
+ // If this is not a restricted profile and there is no restrictions pin, clean up
+ // any restrictions files that might have been left behind.
+ if (!userInfo.isRestricted() && salt == 0) {
+ cleanAppRestrictions(id);
+ }
return userInfo;
} catch (IOException ioe) {
@@ -873,6 +878,26 @@ public class UserManagerService extends IUserManager.Stub {
}
}
+ /**
+ * Removes all the restrictions files (res_<packagename>) for a given user.
+ * Does not do any permissions checking.
+ */
+ private void cleanAppRestrictions(int userId) {
+ synchronized (mPackagesLock) {
+ File dir = Environment.getUserSystemDirectory(userId);
+ String[] files = dir.list();
+ if (files == null) return;
+ for (String fileName : files) {
+ if (fileName.startsWith(RESTRICTIONS_FILE_PREFIX)) {
+ File resFile = new File(dir, fileName);
+ if (resFile.exists()) {
+ resFile.delete();
+ }
+ }
+ }
+ }
+ }
+
@Override
public UserInfo createUser(String name, int flags) {
checkManageUsersPermission("Only the system can create users");
diff --git a/tests/CanvasCompare/res/layout/manual_layout.xml b/tests/CanvasCompare/res/layout/manual_layout.xml
index d7838eb65401..1a9288ce1993 100644
--- a/tests/CanvasCompare/res/layout/manual_layout.xml
+++ b/tests/CanvasCompare/res/layout/manual_layout.xml
@@ -64,7 +64,7 @@
</LinearLayout>
</LinearLayout>
- <com.android.test.hwuicompare.NearestImageView
+ <ImageView
android:id="@+id/compare_image_view"
android:layout_width="@dimen/layer_width_double"
android:layout_height="@dimen/layer_height_double"
diff --git a/tests/CanvasCompare/src/com/android/test/hwuicompare/ManualActivity.java b/tests/CanvasCompare/src/com/android/test/hwuicompare/ManualActivity.java
index 400dff026293..405ff65a34fd 100644
--- a/tests/CanvasCompare/src/com/android/test/hwuicompare/ManualActivity.java
+++ b/tests/CanvasCompare/src/com/android/test/hwuicompare/ManualActivity.java
@@ -82,6 +82,7 @@ public class ManualActivity extends CompareActivity {
mCompareImageView.setImageBitmap(mCompareBitmap);
break;
}
+ mCompareImageView.getDrawable().setFilterBitmap(false);
mCompareImageView.invalidate();
}
diff --git a/tests/CanvasCompare/src/com/android/test/hwuicompare/NearestImageView.java b/tests/CanvasCompare/src/com/android/test/hwuicompare/NearestImageView.java
deleted file mode 100644
index 542b55addba5..000000000000
--- a/tests/CanvasCompare/src/com/android/test/hwuicompare/NearestImageView.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.test.hwuicompare;
-
-import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.PaintFlagsDrawFilter;
-import android.util.AttributeSet;
-import android.widget.ImageView;
-
-public class NearestImageView extends ImageView {
- public NearestImageView(Context context) {
- super(context);
- }
-
- public NearestImageView(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
-
- public NearestImageView(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
- }
-
- final PaintFlagsDrawFilter mFilter = new PaintFlagsDrawFilter(Paint.FILTER_BITMAP_FLAG, 0);
-
- @Override
- public void onDraw(Canvas canvas) {
- canvas.setDrawFilter(mFilter);
- super.onDraw(canvas);
- canvas.setDrawFilter(null);
- }
-} \ No newline at end of file
diff --git a/tests/TransitionTests/AndroidManifest.xml b/tests/TransitionTests/AndroidManifest.xml
index 5483f6490948..9a399d044af6 100644
--- a/tests/TransitionTests/AndroidManifest.xml
+++ b/tests/TransitionTests/AndroidManifest.xml
@@ -233,6 +233,13 @@
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
+ <activity android:label="CrossfadeImage"
+ android:name=".CrossfadeImage">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
</application>
diff --git a/tests/TransitionTests/res/layout/crossfade_image.xml b/tests/TransitionTests/res/layout/crossfade_image.xml
new file mode 100644
index 000000000000..c46327a3e0a6
--- /dev/null
+++ b/tests/TransitionTests/res/layout/crossfade_image.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:id="@+id/container"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <ImageView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/self_portrait_square_100"
+ android:onClick="sendMessage"
+ android:id="@+id/contact_picture"/>
+ <ImageView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/self_portrait_square_100"
+ android:onClick="sendMessage"
+ android:id="@+id/contact_picture1"/>
+ <ImageView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/self_portrait_square_100"
+ android:onClick="sendMessage"
+ android:id="@+id/contact_picture2"/>
+
+</LinearLayout> \ No newline at end of file
diff --git a/tests/TransitionTests/src/com/android/transitiontests/CrossfadeImage.java b/tests/TransitionTests/src/com/android/transitiontests/CrossfadeImage.java
new file mode 100644
index 000000000000..28e055f704fe
--- /dev/null
+++ b/tests/TransitionTests/src/com/android/transitiontests/CrossfadeImage.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.transitiontests;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.transition.Crossfade;
+import android.view.transition.Move;
+import android.view.transition.Scene;
+import android.view.transition.Transition;
+import android.view.transition.TransitionGroup;
+import android.view.transition.TransitionManager;
+import android.widget.ImageView;
+
+public class CrossfadeImage extends Activity {
+ ViewGroup mSceneRoot;
+ static int mCurrentScene;
+ Scene mScene1, mScene2;
+ TransitionManager mTransitionManager;
+ boolean mExpanded = false;
+ Transition mTransition;
+ ImageView mImageView;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.crossfade_image);
+
+ ViewGroup container = (ViewGroup) findViewById(R.id.container);
+ mSceneRoot = container;
+
+ mImageView = (ImageView) findViewById(R.id.contact_picture);
+ mImageView.setScaleType(ImageView.ScaleType.FIT_CENTER);
+
+ Crossfade mCrossfade = new Crossfade();
+ mCrossfade.setTargetIds(R.id.contact_picture);
+
+ TransitionGroup group = new TransitionGroup();
+ group.setDuration(1500);
+ group.addTransitions(mCrossfade, new Move());
+ mTransition = group;
+ }
+
+ public void sendMessage(View view) {
+ TransitionManager.beginDelayedTransition(mSceneRoot, mTransition);
+ if (mExpanded) {
+ mImageView.setImageResource(R.drawable.self_portrait_square_100);
+ } else {
+ mImageView.setImageResource(R.drawable.self_portrait_square_200);
+ }
+ mExpanded = !mExpanded;
+ }
+}
diff --git a/wifi/java/android/net/wifi/WifiNative.java b/wifi/java/android/net/wifi/WifiNative.java
index 375a16071284..ae41c9ac6c86 100644
--- a/wifi/java/android/net/wifi/WifiNative.java
+++ b/wifi/java/android/net/wifi/WifiNative.java
@@ -388,6 +388,10 @@ public class WifiNative {
return doStringCommand("PKTCNT_POLL");
}
+ public void bssFlush() {
+ doBooleanCommand("BSS_FLUSH");
+ }
+
public boolean startWpsPbc(String bssid) {
if (TextUtils.isEmpty(bssid)) {
return doBooleanCommand("WPS_PBC");
diff --git a/wifi/java/android/net/wifi/WifiStateMachine.java b/wifi/java/android/net/wifi/WifiStateMachine.java
index 1f51b2a622f7..d509b371ceec 100644
--- a/wifi/java/android/net/wifi/WifiStateMachine.java
+++ b/wifi/java/android/net/wifi/WifiStateMachine.java
@@ -2497,6 +2497,8 @@ public class WifiStateMachine extends StateMachine {
if (DBG) log("set frequency band " + band);
if (mWifiNative.setBand(band)) {
mFrequencyBand.set(band);
+ // flush old data - like scan results
+ mWifiNative.bssFlush();
//Fetch the latest scan results when frequency band is set
startScanNative(WifiNative.SCAN_WITH_CONNECTION_SETUP);
} else {