summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.mk4
-rw-r--r--api/current.txt1
-rw-r--r--core/java/android/app/Activity.java1
-rw-r--r--core/java/android/app/ActivityManager.java14
-rw-r--r--core/java/android/app/AppOpsManager.java11
-rw-r--r--core/java/android/app/ContextImpl.java5
-rw-r--r--core/java/android/app/UsageStats.aidl20
-rw-r--r--core/java/android/app/UsageStats.java406
-rw-r--r--core/java/android/app/UsageStatsManager.java51
-rw-r--r--core/java/android/content/Context.java10
-rw-r--r--core/java/android/content/pm/PackageManager.java10
-rw-r--r--core/java/android/os/ParcelableParcel.aidl (renamed from core/java/com/android/internal/os/PkgUsageStats.aidl)25
-rw-r--r--core/java/android/print/PrintManager.java62
-rw-r--r--core/java/com/android/internal/app/IUsageStats.aidl10
-rw-r--r--core/java/com/android/internal/os/PkgUsageStats.java94
-rw-r--r--docs/html/guide/topics/manifest/uses-feature-element.jd11
-rw-r--r--libs/hwui/Android.mk3
-rw-r--r--libs/hwui/Matrix.cpp4
-rw-r--r--libs/hwui/Matrix.h2
-rw-r--r--libs/hwui/OpenGLRenderer.cpp20
-rw-r--r--libs/hwui/Rect.h8
-rw-r--r--libs/hwui/Snapshot.cpp26
-rw-r--r--libs/hwui/utils/GLUtils.cpp52
-rw-r--r--libs/hwui/utils/GLUtils.h35
-rw-r--r--libs/hwui/utils/MathUtils.h2
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java21
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java3
-rw-r--r--services/core/java/com/android/server/VibratorService.java34
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java2
-rw-r--r--services/core/java/com/android/server/am/UsageStatsService.java384
-rw-r--r--services/core/java/com/android/server/wm/AppTransition.java30
34 files changed, 1031 insertions, 351 deletions
diff --git a/Android.mk b/Android.mk
index 99d73fa98f32..5e634c1a839f 100644
--- a/Android.mk
+++ b/Android.mk
@@ -76,8 +76,8 @@ LOCAL_SRC_FILES += \
core/java/android/app/ISearchManagerCallback.aidl \
core/java/android/app/IServiceConnection.aidl \
core/java/android/app/IStopUserCallback.aidl \
- core/java/android/app/task/ITaskCallback.aidl \
- core/java/android/app/task/ITaskService.aidl \
+ core/java/android/app/task/ITaskCallback.aidl \
+ core/java/android/app/task/ITaskService.aidl \
core/java/android/app/IThumbnailRetriever.aidl \
core/java/android/app/ITransientNotification.aidl \
core/java/android/app/IUiAutomationConnection.aidl \
diff --git a/api/current.txt b/api/current.txt
index 0f87d1398891..5ca1f592ba6e 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -8049,6 +8049,7 @@ package android.content.pm {
field public static final java.lang.String FEATURE_CAMERA = "android.hardware.camera";
field public static final java.lang.String FEATURE_CAMERA_ANY = "android.hardware.camera.any";
field public static final java.lang.String FEATURE_CAMERA_AUTOFOCUS = "android.hardware.camera.autofocus";
+ field public static final java.lang.String FEATURE_CAMERA_EXTERNAL = "android.hardware.camera.external";
field public static final java.lang.String FEATURE_CAMERA_FLASH = "android.hardware.camera.flash";
field public static final java.lang.String FEATURE_CAMERA_FRONT = "android.hardware.camera.front";
field public static final java.lang.String FEATURE_CONSUMER_IR = "android.hardware.consumerir";
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 36f9f4b697ec..ef6fcb726a17 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -4807,6 +4807,7 @@ public class Activity extends ContextThemeWrapper
public void setRecentsActivityValues(ActivityManager.RecentsActivityValues values) {
ActivityManager.RecentsActivityValues activityValues =
new ActivityManager.RecentsActivityValues(values);
+ // Scale the icon down to something reasonable
if (values.icon != null) {
final int size = ActivityManager.getLauncherLargeIconSizeInner(this);
activityValues.icon = Bitmap.createScaledBitmap(values.icon, size, size, true);
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 5d809d81263d..044727d12182 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -20,7 +20,6 @@ import android.os.BatteryStats;
import android.os.IBinder;
import com.android.internal.app.IUsageStats;
import com.android.internal.app.ProcessStats;
-import com.android.internal.os.PkgUsageStats;
import com.android.internal.os.TransferPipe;
import com.android.internal.util.FastPrintWriter;
@@ -2130,14 +2129,15 @@ public class ActivityManager {
return new HashMap<String, Integer>();
}
- PkgUsageStats[] allPkgUsageStats = usageStatsService.getAllPkgUsageStats();
+ UsageStats.PackageStats[] allPkgUsageStats = usageStatsService.getAllPkgUsageStats(
+ ActivityThread.currentPackageName());
if (allPkgUsageStats == null) {
return new HashMap<String, Integer>();
}
Map<String, Integer> launchCounts = new HashMap<String, Integer>();
- for (PkgUsageStats pkgUsageStats : allPkgUsageStats) {
- launchCounts.put(pkgUsageStats.packageName, pkgUsageStats.launchCount);
+ for (UsageStats.PackageStats pkgUsageStats : allPkgUsageStats) {
+ launchCounts.put(pkgUsageStats.getPackageName(), pkgUsageStats.getLaunchCount());
}
return launchCounts;
@@ -2251,17 +2251,17 @@ public class ActivityManager {
*
* @hide
*/
- public PkgUsageStats[] getAllPackageUsageStats() {
+ public UsageStats.PackageStats[] getAllPackageUsageStats() {
try {
IUsageStats usageStatsService = IUsageStats.Stub.asInterface(
ServiceManager.getService("usagestats"));
if (usageStatsService != null) {
- return usageStatsService.getAllPkgUsageStats();
+ return usageStatsService.getAllPkgUsageStats(ActivityThread.currentPackageName());
}
} catch (RemoteException e) {
Log.w(TAG, "Could not query usage stats", e);
}
- return new PkgUsageStats[0];
+ return new UsageStats.PackageStats[0];
}
/**
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index b616c1e59827..d813dab50e0f 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -16,6 +16,7 @@
package android.app;
+import android.Manifest;
import android.os.Binder;
import android.os.IBinder;
import android.util.ArrayMap;
@@ -184,8 +185,10 @@ public class AppOpsManager {
public static final int OP_MONITOR_LOCATION = 41;
/** @hide Continually monitoring location data with a relatively high power request. */
public static final int OP_MONITOR_HIGH_POWER_LOCATION = 42;
+ /** @hide Retrieve current usage stats via {@link UsageStatsManager}. */
+ public static final int OP_GET_USAGE_STATS = 43;
/** @hide */
- public static final int _NUM_OP = 43;
+ public static final int _NUM_OP = 44;
/** Access to coarse location information. */
public static final String OPSTR_COARSE_LOCATION =
@@ -252,6 +255,7 @@ public class AppOpsManager {
OP_WAKE_LOCK,
OP_COARSE_LOCATION,
OP_COARSE_LOCATION,
+ OP_GET_USAGE_STATS,
};
/**
@@ -302,6 +306,7 @@ public class AppOpsManager {
null,
OPSTR_MONITOR_LOCATION,
OPSTR_MONITOR_HIGH_POWER_LOCATION,
+ null,
};
/**
@@ -352,6 +357,7 @@ public class AppOpsManager {
"WAKE_LOCK",
"MONITOR_LOCATION",
"MONITOR_HIGH_POWER_LOCATION",
+ "GET_USAGE_STATS"
};
/**
@@ -402,6 +408,7 @@ public class AppOpsManager {
android.Manifest.permission.WAKE_LOCK,
null, // no permission for generic location monitoring
null, // no permission for high power location monitoring
+ android.Manifest.permission.PACKAGE_USAGE_STATS,
};
/**
@@ -451,6 +458,7 @@ public class AppOpsManager {
AppOpsManager.MODE_ALLOWED,
AppOpsManager.MODE_ALLOWED,
AppOpsManager.MODE_ALLOWED,
+ AppOpsManager.MODE_IGNORED, // OP_GET_USAGE_STATS
};
/**
@@ -504,6 +512,7 @@ public class AppOpsManager {
false,
false,
false,
+ false,
};
private static HashMap<String, Integer> sOpStrToOp = new HashMap<String, Integer>();
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 5ed503077470..801182d62d75 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -678,6 +678,11 @@ class ContextImpl extends Context {
return new NetworkScoreManager(ctx);
}
});
+
+ registerService(USAGE_STATS_SERVICE, new ServiceFetcher() {
+ public Object createService(ContextImpl ctx) {
+ return new UsageStatsManager(ctx.getOuterContext());
+ }});
}
static ContextImpl getImpl(Context context) {
diff --git a/core/java/android/app/UsageStats.aidl b/core/java/android/app/UsageStats.aidl
new file mode 100644
index 000000000000..7dee70a7861f
--- /dev/null
+++ b/core/java/android/app/UsageStats.aidl
@@ -0,0 +1,20 @@
+/**
+ * Copyright (c) 2014, 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;
+
+parcelable UsageStats;
+parcelable UsageStats.PackageStats;
diff --git a/core/java/android/app/UsageStats.java b/core/java/android/app/UsageStats.java
new file mode 100644
index 000000000000..0aeba59c3f9a
--- /dev/null
+++ b/core/java/android/app/UsageStats.java
@@ -0,0 +1,406 @@
+/*
+ * Copyright (C) 2014 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 android.content.res.Configuration;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.SystemClock;
+import android.util.ArrayMap;
+
+import java.util.Map;
+
+/**
+ * Snapshot of current usage stats data.
+ * @hide
+ */
+public class UsageStats implements Parcelable {
+ /** @hide */
+ public final ArrayMap<String, PackageStats> mPackages = new ArrayMap<String, PackageStats>();
+ /** @hide */
+ public final ArrayMap<Configuration, ConfigurationStats> mConfigurations
+ = new ArrayMap<Configuration, ConfigurationStats>();
+
+ public static class PackageStats implements Parcelable {
+ private final String mPackageName;
+ private int mLaunchCount;
+ private long mUsageTime;
+ private long mResumedTime;
+
+ /** @hide */
+ public final ArrayMap<String, Long> componentResumeTimes;
+
+ public static final Parcelable.Creator<PackageStats> CREATOR
+ = new Parcelable.Creator<PackageStats>() {
+ public PackageStats createFromParcel(Parcel in) {
+ return new PackageStats(in);
+ }
+
+ public PackageStats[] newArray(int size) {
+ return new PackageStats[size];
+ }
+ };
+
+ public String toString() {
+ return "PackageStats{"
+ + Integer.toHexString(System.identityHashCode(this))
+ + " " + mPackageName + "}";
+ }
+
+ /** @hide */
+ public PackageStats(String pkgName) {
+ mPackageName = pkgName;
+ componentResumeTimes = new ArrayMap<String, Long>();
+ }
+
+ /** @hide */
+ public PackageStats(String pkgName, int count, long time, Map<String, Long> lastResumeTimes) {
+ mPackageName = pkgName;
+ mLaunchCount = count;
+ mUsageTime = time;
+ componentResumeTimes = new ArrayMap<String, Long>();
+ componentResumeTimes.putAll(lastResumeTimes);
+ }
+
+ /** @hide */
+ public PackageStats(Parcel source) {
+ mPackageName = source.readString();
+ mLaunchCount = source.readInt();
+ mUsageTime = source.readLong();
+ final int N = source.readInt();
+ componentResumeTimes = new ArrayMap<String, Long>(N);
+ for (int i = 0; i < N; i++) {
+ String component = source.readString();
+ long lastResumeTime = source.readLong();
+ componentResumeTimes.put(component, lastResumeTime);
+ }
+ }
+
+ /** @hide */
+ public PackageStats(PackageStats pStats) {
+ mPackageName = pStats.mPackageName;
+ mLaunchCount = pStats.mLaunchCount;
+ mUsageTime = pStats.mUsageTime;
+ componentResumeTimes = new ArrayMap<String, Long>(pStats.componentResumeTimes);
+ }
+
+ /** @hide */
+ public void resume(boolean launched) {
+ if (launched) {
+ mLaunchCount++;
+ }
+ mResumedTime = SystemClock.elapsedRealtime();
+ }
+
+ /** @hide */
+ public void pause() {
+ if (mResumedTime > 0) {
+ mUsageTime += SystemClock.elapsedRealtime() - mResumedTime;
+ }
+ mResumedTime = 0;
+ }
+
+ public final String getPackageName() {
+ return mPackageName;
+ }
+
+ public final long getUsageTime(long elapsedRealtime) {
+ return mUsageTime + (mResumedTime > 0 ? (elapsedRealtime- mResumedTime) : 0);
+ }
+
+ public final int getLaunchCount() {
+ return mLaunchCount;
+ }
+
+ /** @hide */
+ public boolean clearUsageTimes() {
+ mLaunchCount = 0;
+ mUsageTime = 0;
+ return mResumedTime <= 0 && componentResumeTimes.isEmpty();
+ }
+
+ public final int describeContents() {
+ return 0;
+ }
+
+ public final void writeToParcel(Parcel dest, int parcelableFlags) {
+ writeToParcel(dest, parcelableFlags, 0);
+ }
+
+ final void writeToParcel(Parcel dest, int parcelableFlags, long elapsedRealtime) {
+ dest.writeString(mPackageName);
+ dest.writeInt(mLaunchCount);
+ dest.writeLong(elapsedRealtime > 0 ? getUsageTime(elapsedRealtime) : mUsageTime);
+ dest.writeInt(componentResumeTimes.size());
+ for (Map.Entry<String, Long> ent : componentResumeTimes.entrySet()) {
+ dest.writeString(ent.getKey());
+ dest.writeLong(ent.getValue());
+ }
+ }
+
+ /** @hide */
+ public void writeExtendedToParcel(Parcel dest, int parcelableFlags) {
+ }
+ }
+
+ public static class ConfigurationStats implements Parcelable {
+ private final Configuration mConfiguration;
+ private long mLastUsedTime;
+ private int mUsageCount;
+ private long mUsageTime;
+ private long mStartedTime;
+
+ public static final Parcelable.Creator<ConfigurationStats> CREATOR
+ = new Parcelable.Creator<ConfigurationStats>() {
+ public ConfigurationStats createFromParcel(Parcel in) {
+ return new ConfigurationStats(in);
+ }
+
+ public ConfigurationStats[] newArray(int size) {
+ return new ConfigurationStats[size];
+ }
+ };
+
+ public String toString() {
+ return "ConfigurationStats{"
+ + Integer.toHexString(System.identityHashCode(this))
+ + " " + mConfiguration + "}";
+ }
+
+ /** @hide */
+ public ConfigurationStats(Configuration config) {
+ mConfiguration = config;
+ }
+
+ /** @hide */
+ public ConfigurationStats(Parcel source) {
+ mConfiguration = Configuration.CREATOR.createFromParcel(source);
+ mLastUsedTime = source.readLong();
+ mUsageCount = source.readInt();
+ mUsageTime = source.readLong();
+ }
+
+ /** @hide */
+ public ConfigurationStats(ConfigurationStats pStats) {
+ mConfiguration = pStats.mConfiguration;
+ mLastUsedTime = pStats.mLastUsedTime;
+ mUsageCount = pStats.mUsageCount;
+ mUsageTime = pStats.mUsageTime;
+ }
+
+ public final Configuration getConfiguration() {
+ return mConfiguration;
+ }
+
+ public final long getLastUsedTime() {
+ return mLastUsedTime;
+ }
+
+ public final long getUsageTime(long elapsedRealtime) {
+ return mUsageTime + (mStartedTime > 0 ? (elapsedRealtime- mStartedTime) : 0);
+ }
+
+ public final int getUsageCount() {
+ return mUsageCount;
+ }
+
+ /** @hide */
+ public void start() {
+ mLastUsedTime = System.currentTimeMillis();
+ mUsageCount++;
+ mStartedTime = SystemClock.elapsedRealtime();
+ }
+
+ /** @hide */
+ public void stop() {
+ if (mStartedTime > 0) {
+ mUsageTime += SystemClock.elapsedRealtime() - mStartedTime;
+ }
+ mStartedTime = 0;
+ }
+
+ /** @hide */
+ public boolean clearUsageTimes() {
+ mUsageCount = 0;
+ mUsageTime = 0;
+ return mLastUsedTime == 0 && mStartedTime <= 0;
+ }
+
+ public final int describeContents() {
+ return 0;
+ }
+
+ public final void writeToParcel(Parcel dest, int parcelableFlags) {
+ writeToParcel(dest, parcelableFlags, 0);
+ }
+
+ final void writeToParcel(Parcel dest, int parcelableFlags, long elapsedRealtime) {
+ mConfiguration.writeToParcel(dest, parcelableFlags);
+ dest.writeLong(mLastUsedTime);
+ dest.writeInt(mUsageCount);
+ dest.writeLong(elapsedRealtime > 0 ? getUsageTime(elapsedRealtime) : mUsageTime);
+ }
+
+ /** @hide */
+ public void writeExtendedToParcel(Parcel dest, int parcelableFlags) {
+ }
+ }
+
+ /** @hide */
+ public UsageStats() {
+ }
+
+ /** @hide */
+ public UsageStats(Parcel source, boolean extended) {
+ int N = source.readInt();
+ for (int i=0; i<N; i++) {
+ PackageStats pkg = extended ? onNewPackageStats(source) : new PackageStats(source);
+ mPackages.put(pkg.getPackageName(), pkg);
+ }
+ N = source.readInt();
+ for (int i=0; i<N; i++) {
+ ConfigurationStats config = extended ? onNewConfigurationStats(source)
+ : new ConfigurationStats(source);
+ mConfigurations.put(config.getConfiguration(), config);
+ }
+ }
+
+ public int getPackageStatsCount() {
+ return mPackages.size();
+ }
+
+ public PackageStats getPackageStatsAt(int index) {
+ return mPackages.valueAt(index);
+ }
+
+ public PackageStats getPackageStats(String pkgName) {
+ return mPackages.get(pkgName);
+ }
+
+ /** @hide */
+ public PackageStats getOrCreatePackageStats(String pkgName) {
+ PackageStats ps = mPackages.get(pkgName);
+ if (ps == null) {
+ ps = onNewPackageStats(pkgName);
+ mPackages.put(pkgName, ps);
+ }
+ return ps;
+ }
+
+ public int getConfigurationStatsCount() {
+ return mConfigurations.size();
+ }
+
+ public ConfigurationStats getConfigurationStatsAt(int index) {
+ return mConfigurations.valueAt(index);
+ }
+
+ public ConfigurationStats getConfigurationStats(Configuration config) {
+ return mConfigurations.get(config);
+ }
+
+ /** @hide */
+ public ConfigurationStats getOrCreateConfigurationStats(Configuration config) {
+ ConfigurationStats cs = mConfigurations.get(config);
+ if (cs == null) {
+ cs = onNewConfigurationStats(config);
+ mConfigurations.put(config, cs);
+ }
+ return cs;
+ }
+
+ /** @hide */
+ public void clearUsageTimes() {
+ for (int i=mPackages.size()-1; i>=0; i--) {
+ if (mPackages.valueAt(i).clearUsageTimes()) {
+ mPackages.removeAt(i);
+ }
+ }
+ for (int i=mConfigurations.size()-1; i>=0; i--) {
+ if (mConfigurations.valueAt(i).clearUsageTimes()) {
+ mConfigurations.removeAt(i);
+ }
+ }
+ }
+
+ /** @hide */
+ public PackageStats onNewPackageStats(String pkgName) {
+ return new PackageStats(pkgName);
+ }
+
+ /** @hide */
+ public PackageStats onNewPackageStats(Parcel source) {
+ return new PackageStats(source);
+ }
+
+ /** @hide */
+ public ConfigurationStats onNewConfigurationStats(Configuration config) {
+ return new ConfigurationStats(config);
+ }
+
+ /** @hide */
+ public ConfigurationStats onNewConfigurationStats(Parcel source) {
+ return new ConfigurationStats(source);
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel dest, int parcelableFlags) {
+ writeToParcelInner(dest, parcelableFlags, false);
+ }
+
+ /** @hide */
+ public void writeExtendedToParcel(Parcel dest, int parcelableFlags) {
+ writeToParcelInner(dest, parcelableFlags, true);
+ }
+
+ private void writeToParcelInner(Parcel dest, int parcelableFlags, boolean extended) {
+ final long elapsedRealtime = SystemClock.elapsedRealtime();
+
+ int N = mPackages.size();
+ dest.writeInt(N);
+ for (int i=0; i<N; i++) {
+ PackageStats ps = mPackages.valueAt(i);
+ ps.writeToParcel(dest, parcelableFlags, elapsedRealtime);
+ if (extended) {
+ ps.writeExtendedToParcel(dest, parcelableFlags);
+ }
+ }
+ N = mConfigurations.size();
+ dest.writeInt(N);
+ for (int i=0; i<N; i++) {
+ ConfigurationStats cs = mConfigurations.valueAt(i);
+ cs.writeToParcel(dest, parcelableFlags, elapsedRealtime);
+ if (extended) {
+ cs.writeExtendedToParcel(dest, parcelableFlags);
+ }
+ }
+ }
+
+ public static final Parcelable.Creator<UsageStats> CREATOR
+ = new Parcelable.Creator<UsageStats>() {
+ public UsageStats createFromParcel(Parcel in) {
+ return new UsageStats(in, false);
+ }
+
+ public UsageStats[] newArray(int size) {
+ return new UsageStats[size];
+ }
+ };
+}
diff --git a/core/java/android/app/UsageStatsManager.java b/core/java/android/app/UsageStatsManager.java
new file mode 100644
index 000000000000..fbf9c3bc92a2
--- /dev/null
+++ b/core/java/android/app/UsageStatsManager.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2014 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 android.content.Context;
+import android.os.ParcelableParcel;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import com.android.internal.app.IUsageStats;
+
+/**
+ * Access to usage stats data.
+ * @hide
+ */
+public class UsageStatsManager {
+ final Context mContext;
+ final IUsageStats mService;
+
+ /** @hide */
+ public UsageStatsManager(Context context) {
+ mContext = context;
+ mService = IUsageStats.Stub.asInterface(ServiceManager.getService(
+ Context.USAGE_STATS_SERVICE));
+ }
+
+ public UsageStats getCurrentStats() {
+ try {
+ ParcelableParcel in = mService.getCurrentStats(mContext.getOpPackageName());
+ if (in != null) {
+ return new UsageStats(in.getParcel(), false);
+ }
+ } catch (RemoteException e) {
+ // About to die.
+ }
+ return new UsageStats();
+ }
+}
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 042ee281d69c..a059e484dd48 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -2683,6 +2683,16 @@ public abstract class Context {
public static final String NETWORK_SCORE_SERVICE = "network_score";
/**
+ * Use with {@link #getSystemService} to retrieve a {@link
+ * android.app.UsageStatsManager} for interacting with the status bar.
+ *
+ * @see #getSystemService
+ * @see android.app.UsageStatsManager
+ * @hide
+ */
+ public static final String USAGE_STATS_SERVICE = "usagestats";
+
+ /**
* Determine whether the given permission is allowed for a particular
* process and user ID running in the system.
*
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 52a169b2dbbe..eb2c11fe895f 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -936,13 +936,21 @@ public abstract class PackageManager {
/**
* Feature for {@link #getSystemAvailableFeatures} and
* {@link #hasSystemFeature}: The device has at least one camera pointing in
- * some direction.
+ * some direction, or can support an external camera being connected to it.
*/
@SdkConstant(SdkConstantType.FEATURE)
public static final String FEATURE_CAMERA_ANY = "android.hardware.camera.any";
/**
* Feature for {@link #getSystemAvailableFeatures} and
+ * {@link #hasSystemFeature}: The device can support having an external camera connected to it.
+ * The external camera may not always be connected or available to applications to use.
+ */
+ @SdkConstant(SdkConstantType.FEATURE)
+ public static final String FEATURE_CAMERA_EXTERNAL = "android.hardware.camera.external";
+
+ /**
+ * Feature for {@link #getSystemAvailableFeatures} and
* {@link #hasSystemFeature}: The device's camera supports flash.
*/
@SdkConstant(SdkConstantType.FEATURE)
diff --git a/core/java/com/android/internal/os/PkgUsageStats.aidl b/core/java/android/os/ParcelableParcel.aidl
index 83052717bf1f..61f730c1a75a 100644
--- a/core/java/com/android/internal/os/PkgUsageStats.aidl
+++ b/core/java/android/os/ParcelableParcel.aidl
@@ -1,20 +1,19 @@
-/* //device/java/android/android/content/Intent.aidl
+/*
+** Copyright 2014, The Android Open Source Project
**
-** Copyright 2007, The Android Open Source Project
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
**
-** 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
**
-** 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
+** 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.internal.os;
+package android.os;
-parcelable PkgUsageStats;
+parcelable ParcelableParcel;
diff --git a/core/java/android/print/PrintManager.java b/core/java/android/print/PrintManager.java
index e4f73cb40b27..811751d18fef 100644
--- a/core/java/android/print/PrintManager.java
+++ b/core/java/android/print/PrintManager.java
@@ -167,7 +167,7 @@ public final class PrintManager {
/**
* Callback notifying that a print job state changed.
- *
+ *
* @param printJobId The print job id.
*/
public void onPrintJobStateChanged(PrintJobId printJobId);
@@ -175,7 +175,7 @@ public final class PrintManager {
/**
* Creates a new instance.
- *
+ *
* @param context The current context in which to operate.
* @param service The backing system service.
* @hide
@@ -207,13 +207,17 @@ public final class PrintManager {
/**
* Creates an instance that can access all print jobs.
- *
+ *
* @param userId The user id for which to get all print jobs.
* @return An instance if the caller has the permission to access all print
* jobs, null otherwise.
* @hide
*/
public PrintManager getGlobalPrintManagerForUser(int userId) {
+ if (mService == null) {
+ Log.w(LOG_TAG, "Feature android.software.print not available");
+ return null;
+ }
return new PrintManager(mContext, mService, userId, APP_ID_ANY);
}
@@ -228,11 +232,15 @@ public final class PrintManager {
/**
* Adds a listener for observing the state of print jobs.
- *
+ *
* @param listener The listener to add.
* @hide
*/
public void addPrintJobStateChangeListener(PrintJobStateChangeListener listener) {
+ if (mService == null) {
+ Log.w(LOG_TAG, "Feature android.software.print not available");
+ return;
+ }
if (mPrintJobStateChangeListeners == null) {
mPrintJobStateChangeListeners = new ArrayMap<PrintJobStateChangeListener,
PrintJobStateChangeListenerWrapper>();
@@ -249,11 +257,15 @@ public final class PrintManager {
/**
* Removes a listener for observing the state of print jobs.
- *
+ *
* @param listener The listener to remove.
* @hide
*/
public void removePrintJobStateChangeListener(PrintJobStateChangeListener listener) {
+ if (mService == null) {
+ Log.w(LOG_TAG, "Feature android.software.print not available");
+ return;
+ }
if (mPrintJobStateChangeListeners == null) {
return;
}
@@ -275,12 +287,16 @@ public final class PrintManager {
/**
* Gets a print job given its id.
- *
+ *
* @return The print job list.
* @see PrintJob
* @hide
*/
public PrintJob getPrintJob(PrintJobId printJobId) {
+ if (mService == null) {
+ Log.w(LOG_TAG, "Feature android.software.print not available");
+ return null;
+ }
try {
PrintJobInfo printJob = mService.getPrintJobInfo(printJobId, mAppId, mUserId);
if (printJob != null) {
@@ -294,11 +310,15 @@ public final class PrintManager {
/**
* Gets the print jobs for this application.
- *
+ *
* @return The print job list.
* @see PrintJob
*/
public List<PrintJob> getPrintJobs() {
+ if (mService == null) {
+ Log.w(LOG_TAG, "Feature android.software.print not available");
+ return Collections.emptyList();
+ }
try {
List<PrintJobInfo> printJobInfos = mService.getPrintJobInfos(mAppId, mUserId);
if (printJobInfos == null) {
@@ -317,6 +337,10 @@ public final class PrintManager {
}
void cancelPrintJob(PrintJobId printJobId) {
+ if (mService == null) {
+ Log.w(LOG_TAG, "Feature android.software.print not available");
+ return;
+ }
try {
mService.cancelPrintJob(printJobId, mAppId, mUserId);
} catch (RemoteException re) {
@@ -325,6 +349,10 @@ public final class PrintManager {
}
void restartPrintJob(PrintJobId printJobId) {
+ if (mService == null) {
+ Log.w(LOG_TAG, "Feature android.software.print not available");
+ return;
+ }
try {
mService.restartPrintJob(printJobId, mAppId, mUserId);
} catch (RemoteException re) {
@@ -383,6 +411,10 @@ public final class PrintManager {
*/
public PrintJob print(String printJobName, PrintDocumentAdapter documentAdapter,
PrintAttributes attributes) {
+ if (mService == null) {
+ Log.w(LOG_TAG, "Feature android.software.print not available");
+ return null;
+ }
if (!(mContext instanceof Activity)) {
throw new IllegalStateException("Can print only from an activity");
}
@@ -418,11 +450,15 @@ public final class PrintManager {
/**
* Gets the list of enabled print services.
- *
+ *
* @return The enabled service list or an empty list.
* @hide
*/
public List<PrintServiceInfo> getEnabledPrintServices() {
+ if (mService == null) {
+ Log.w(LOG_TAG, "Feature android.software.print not available");
+ return Collections.emptyList();
+ }
try {
List<PrintServiceInfo> enabledServices = mService.getEnabledPrintServices(mUserId);
if (enabledServices != null) {
@@ -436,11 +472,15 @@ public final class PrintManager {
/**
* Gets the list of installed print services.
- *
+ *
* @return The installed service list or an empty list.
* @hide
*/
public List<PrintServiceInfo> getInstalledPrintServices() {
+ if (mService == null) {
+ Log.w(LOG_TAG, "Feature android.software.print not available");
+ return Collections.emptyList();
+ }
try {
List<PrintServiceInfo> installedServices = mService.getInstalledPrintServices(mUserId);
if (installedServices != null) {
@@ -456,6 +496,10 @@ public final class PrintManager {
* @hide
*/
public PrinterDiscoverySession createPrinterDiscoverySession() {
+ if (mService == null) {
+ Log.w(LOG_TAG, "Feature android.software.print not available");
+ return null;
+ }
return new PrinterDiscoverySession(mService, mContext, mUserId);
}
diff --git a/core/java/com/android/internal/app/IUsageStats.aidl b/core/java/com/android/internal/app/IUsageStats.aidl
index 1ea74090a419..7e7f0e17c6d5 100644
--- a/core/java/com/android/internal/app/IUsageStats.aidl
+++ b/core/java/com/android/internal/app/IUsageStats.aidl
@@ -16,13 +16,17 @@
package com.android.internal.app;
+import android.app.UsageStats;
import android.content.ComponentName;
-import com.android.internal.os.PkgUsageStats;
+import android.content.res.Configuration;
+import android.os.ParcelableParcel;
interface IUsageStats {
void noteResumeComponent(in ComponentName componentName);
void notePauseComponent(in ComponentName componentName);
void noteLaunchTime(in ComponentName componentName, int millis);
- PkgUsageStats getPkgUsageStats(in ComponentName componentName);
- PkgUsageStats[] getAllPkgUsageStats();
+ void noteStartConfig(in Configuration config);
+ UsageStats.PackageStats getPkgUsageStats(String callingPkg, in ComponentName componentName);
+ UsageStats.PackageStats[] getAllPkgUsageStats(String callingPkg);
+ ParcelableParcel getCurrentStats(String callingPkg);
}
diff --git a/core/java/com/android/internal/os/PkgUsageStats.java b/core/java/com/android/internal/os/PkgUsageStats.java
deleted file mode 100644
index 8c2c4052d20a..000000000000
--- a/core/java/com/android/internal/os/PkgUsageStats.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright (C) 2009 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.internal.os;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * implementation of PkgUsageStats associated with an
- * application package.
- * @hide
- */
-public class PkgUsageStats implements Parcelable {
- public String packageName;
- public int launchCount;
- public long usageTime;
- public Map<String, Long> componentResumeTimes;
-
- public static final Parcelable.Creator<PkgUsageStats> CREATOR
- = new Parcelable.Creator<PkgUsageStats>() {
- public PkgUsageStats createFromParcel(Parcel in) {
- return new PkgUsageStats(in);
- }
-
- public PkgUsageStats[] newArray(int size) {
- return new PkgUsageStats[size];
- }
- };
-
- public String toString() {
- return "PkgUsageStats{"
- + Integer.toHexString(System.identityHashCode(this))
- + " " + packageName + "}";
- }
-
- public PkgUsageStats(String pkgName, int count, long time, Map<String, Long> lastResumeTimes) {
- packageName = pkgName;
- launchCount = count;
- usageTime = time;
- componentResumeTimes = new HashMap<String, Long>(lastResumeTimes);
- }
-
- public PkgUsageStats(Parcel source) {
- packageName = source.readString();
- launchCount = source.readInt();
- usageTime = source.readLong();
- final int N = source.readInt();
- componentResumeTimes = new HashMap<String, Long>(N);
- for (int i = 0; i < N; i++) {
- String component = source.readString();
- long lastResumeTime = source.readLong();
- componentResumeTimes.put(component, lastResumeTime);
- }
- }
-
- public PkgUsageStats(PkgUsageStats pStats) {
- packageName = pStats.packageName;
- launchCount = pStats.launchCount;
- usageTime = pStats.usageTime;
- componentResumeTimes = new HashMap<String, Long>(pStats.componentResumeTimes);
- }
-
- public int describeContents() {
- return 0;
- }
-
- public void writeToParcel(Parcel dest, int parcelableFlags) {
- dest.writeString(packageName);
- dest.writeInt(launchCount);
- dest.writeLong(usageTime);
- dest.writeInt(componentResumeTimes.size());
- for (Map.Entry<String, Long> ent : componentResumeTimes.entrySet()) {
- dest.writeString(ent.getKey());
- dest.writeLong(ent.getValue());
- }
- }
-}
diff --git a/docs/html/guide/topics/manifest/uses-feature-element.jd b/docs/html/guide/topics/manifest/uses-feature-element.jd
index 4057736c2715..6143b4b6a61d 100644
--- a/docs/html/guide/topics/manifest/uses-feature-element.jd
+++ b/docs/html/guide/topics/manifest/uses-feature-element.jd
@@ -584,9 +584,14 @@ is sensitive to delays or lag in sound input or output.</td>
</tr>
<tr>
<td><code>android.hardware.camera.any</code></td>
- <td>The application uses at least one camera facing in any direction. Use this
-in preference to <code>android.hardware.camera</code> if a back-facing camera is
-not required.</td>
+ <td>The application uses at least one camera facing in any direction, or an
+external camera device if one is connected. Use this in preference to
+<code>android.hardware.camera</code> if a back-facing camera is not required.
+ </td>
+</tr>
+<tr>
+ <td><code>android.hardware.camera.external</code></td>
+ <td>The application uses an external camera device if one is connected.</td>
</tr>
<tr>
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index eb0cac8944df..2cadf09dc63a 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -6,6 +6,7 @@ include $(CLEAR_VARS)
ifeq ($(USE_OPENGL_RENDERER),true)
LOCAL_SRC_FILES := \
utils/Blur.cpp \
+ utils/GLUtils.cpp \
utils/SortedListImpl.cpp \
thread/TaskManager.cpp \
font/CacheTexture.cpp \
@@ -53,7 +54,7 @@ ifeq ($(USE_OPENGL_RENDERER),true)
TextureCache.cpp \
TextDropShadowCache.cpp
- # RenderThread stuff
+# RenderThread stuff
LOCAL_SRC_FILES += \
renderthread/CanvasContext.cpp \
renderthread/DrawFrameTask.cpp \
diff --git a/libs/hwui/Matrix.cpp b/libs/hwui/Matrix.cpp
index f06106b14ee7..22683865c7a6 100644
--- a/libs/hwui/Matrix.cpp
+++ b/libs/hwui/Matrix.cpp
@@ -482,8 +482,8 @@ void Matrix4::decomposeScale(float& sx, float& sy) const {
sy = copysignf(sqrtf(len), data[mat4::kScaleY]);
}
-void Matrix4::dump() const {
- ALOGD("Matrix4[simple=%d, type=0x%x", isSimple(), getType());
+void Matrix4::dump(const char* label) const {
+ ALOGD("%s[simple=%d, type=0x%x", label ? label : "Matrix4", isSimple(), getType());
ALOGD(" %f %f %f %f", data[kScaleX], data[kSkewX], data[8], data[kTranslateX]);
ALOGD(" %f %f %f %f", data[kSkewY], data[kScaleY], data[9], data[kTranslateY]);
ALOGD(" %f %f %f %f", data[2], data[6], data[kScaleZ], data[kTranslateZ]);
diff --git a/libs/hwui/Matrix.h b/libs/hwui/Matrix.h
index 26cb05fe686e..e33a0013a929 100644
--- a/libs/hwui/Matrix.h
+++ b/libs/hwui/Matrix.h
@@ -209,7 +209,7 @@ public:
void decomposeScale(float& sx, float& sy) const;
- void dump() const;
+ void dump(const char* label = NULL) const;
static const Matrix4& identity();
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 87b07b30b791..5a977c836d52 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -37,6 +37,7 @@
#include "PathTessellator.h"
#include "Properties.h"
#include "ShadowTessellator.h"
+#include "utils/GLUtils.h"
#include "Vector.h"
#include "VertexBuffer.h"
@@ -296,24 +297,7 @@ void OpenGLRenderer::finish() {
if (!suppressErrorChecks()) {
#if DEBUG_OPENGL
- GLenum status = GL_NO_ERROR;
- while ((status = glGetError()) != GL_NO_ERROR) {
- ALOGD("GL error from OpenGLRenderer: 0x%x", status);
- switch (status) {
- case GL_INVALID_ENUM:
- ALOGE(" GL_INVALID_ENUM");
- break;
- case GL_INVALID_VALUE:
- ALOGE(" GL_INVALID_VALUE");
- break;
- case GL_INVALID_OPERATION:
- ALOGE(" GL_INVALID_OPERATION");
- break;
- case GL_OUT_OF_MEMORY:
- ALOGE(" Out of memory!");
- break;
- }
- }
+ GLUtils::dumpGLErrors();
#endif
#if DEBUG_MEMORY_USAGE
diff --git a/libs/hwui/Rect.h b/libs/hwui/Rect.h
index 92964a8ca624..f38d8b7d0ef6 100644
--- a/libs/hwui/Rect.h
+++ b/libs/hwui/Rect.h
@@ -175,6 +175,10 @@ public:
bottom += dy;
}
+ void inset(float delta) {
+ outset(-delta);
+ }
+
void outset(float delta) {
left -= delta;
top -= delta;
@@ -230,8 +234,8 @@ public:
bottom = ceilf(bottom);
}
- void dump() const {
- ALOGD("Rect[l=%f t=%f r=%f b=%f]", left, top, right, bottom);
+ void dump(const char* label) const {
+ ALOGD("%s[l=%f t=%f r=%f b=%f]", label ? label : "Rect", left, top, right, bottom);
}
private:
diff --git a/libs/hwui/Snapshot.cpp b/libs/hwui/Snapshot.cpp
index d26ee3884433..6bfa2033f8fc 100644
--- a/libs/hwui/Snapshot.cpp
+++ b/libs/hwui/Snapshot.cpp
@@ -27,9 +27,15 @@ namespace uirenderer {
// Constructors
///////////////////////////////////////////////////////////////////////////////
-Snapshot::Snapshot(): flags(0), previous(NULL), layer(NULL), fbo(0),
- invisible(false), empty(false), alpha(1.0f) {
-
+Snapshot::Snapshot()
+ : flags(0)
+ , previous(NULL)
+ , layer(NULL)
+ , fbo(0)
+ , invisible(false)
+ , empty(false)
+ , height(0)
+ , alpha(1.0f) {
transform = &mTransformRoot;
clipRect = &mClipRectRoot;
region = NULL;
@@ -40,10 +46,16 @@ Snapshot::Snapshot(): flags(0), previous(NULL), layer(NULL), fbo(0),
* Copies the specified snapshot/ The specified snapshot is stored as
* the previous snapshot.
*/
-Snapshot::Snapshot(const sp<Snapshot>& s, int saveFlags):
- flags(0), previous(s), layer(s->layer), fbo(s->fbo),
- invisible(s->invisible), empty(false),
- viewport(s->viewport), height(s->height), alpha(s->alpha) {
+Snapshot::Snapshot(const sp<Snapshot>& s, int saveFlags)
+ : flags(0)
+ , previous(s)
+ , layer(s->layer)
+ , fbo(s->fbo)
+ , invisible(s->invisible)
+ , empty(false)
+ , viewport(s->viewport)
+ , height(s->height)
+ , alpha(s->alpha) {
if (saveFlags & SkCanvas::kMatrix_SaveFlag) {
mTransformRoot.load(*s->transform);
diff --git a/libs/hwui/utils/GLUtils.cpp b/libs/hwui/utils/GLUtils.cpp
new file mode 100644
index 000000000000..9b298ca2011d
--- /dev/null
+++ b/libs/hwui/utils/GLUtils.cpp
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+
+#define LOG_TAG "OpenGLRenderer"
+
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+
+#include <utils/Log.h>
+
+#include "GLUtils.h"
+
+namespace android {
+namespace uirenderer {
+
+void GLUtils::dumpGLErrors() {
+ GLenum status = GL_NO_ERROR;
+ while ((status = glGetError()) != GL_NO_ERROR) {
+ switch (status) {
+ case GL_INVALID_ENUM:
+ ALOGE("GL error: GL_INVALID_ENUM");
+ break;
+ case GL_INVALID_VALUE:
+ ALOGE("GL error: GL_INVALID_VALUE");
+ break;
+ case GL_INVALID_OPERATION:
+ ALOGE("GL error: GL_INVALID_OPERATION");
+ break;
+ case GL_OUT_OF_MEMORY:
+ ALOGE("GL error: Out of memory!");
+ break;
+ default:
+ ALOGE("GL error: 0x%x", status);
+ }
+ }
+}
+
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/utils/GLUtils.h b/libs/hwui/utils/GLUtils.h
new file mode 100644
index 000000000000..890e3740ef9f
--- /dev/null
+++ b/libs/hwui/utils/GLUtils.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+#ifndef GLUTILS_H
+#define GLUTILS_H
+
+namespace android {
+namespace uirenderer {
+
+class GLUtils {
+private:
+public:
+ /**
+ * Print out any GL errors with ALOGE
+ */
+ static void dumpGLErrors();
+
+}; // class GLUtils
+
+} /* namespace uirenderer */
+} /* namespace android */
+
+#endif /* GLUTILS_H */
diff --git a/libs/hwui/utils/MathUtils.h b/libs/hwui/utils/MathUtils.h
index 7deabe981727..8ba44dca2e2d 100644
--- a/libs/hwui/utils/MathUtils.h
+++ b/libs/hwui/utils/MathUtils.h
@@ -38,4 +38,4 @@ public:
} /* namespace uirenderer */
} /* namespace android */
-#endif /* RENDERNODE_H */
+#endif /* MATHUTILS_H */
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java
index f3e411f999cc..c64ca5456762 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java
@@ -554,14 +554,16 @@ public class RecentsTaskLoader {
}
/** Completely removes the resource data from the pool. */
- public void deleteTaskData(Task t) {
+ public void deleteTaskData(Task t, boolean notifyTaskDataUnloaded) {
Console.log(Constants.Log.App.TaskDataLoader,
"[RecentsTaskLoader|deleteTask]", t);
mLoadQueue.removeTask(t);
mThumbnailCache.remove(t.key);
mApplicationIconCache.remove(t.key);
- t.notifyTaskDataUnloaded(mDefaultThumbnail, mDefaultApplicationIcon);
+ if (notifyTaskDataUnloaded) {
+ t.notifyTaskDataUnloaded(mDefaultThumbnail, mDefaultApplicationIcon);
+ }
}
/** Stops the task loader and clears all pending tasks */
diff --git a/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java
index b41555f288ca..0d3ee382da0b 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java
@@ -165,11 +165,12 @@ public class SystemServicesProxy {
}
/** Removes the task and kills the process */
- public void removeTask(int taskId) {
+ public void removeTask(int taskId, boolean isDocument) {
if (mAm == null) return;
if (Constants.DebugFlags.App.EnableSystemServicesProxy) return;
- mAm.removeTask(taskId, ActivityManager.REMOVE_TASK_KILL_PROCESS);
+ // Remove the task, and only kill the process if it is not a document
+ mAm.removeTask(taskId, isDocument ? 0 : ActivityManager.REMOVE_TASK_KILL_PROCESS);
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
index 816861990fec..a6d7e676b362 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -346,7 +346,7 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV
RecentsTaskLoader.getInstance().getSystemServicesProxy()
.moveTaskToFront(task.key.id, opts);
} else {
- // Launch the activity with the desired animation
+ // Launch the activity anew with the desired animation
Intent i = new Intent(task.key.baseIntent);
i.setFlags(Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY
| Intent.FLAG_ACTIVITY_TASK_ON_HOME
@@ -361,6 +361,9 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV
} catch (ActivityNotFoundException anfe) {
Console.logError(getContext(), "Could not start Activity");
}
+
+ // And clean up the old task
+ onTaskRemoved(task);
}
Console.logTraceTime(Constants.Log.App.TimeRecentsLaunchTask,
@@ -390,6 +393,22 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV
.addNextIntentWithParentStack(intent).startActivities();
}
+ @Override
+ public void onTaskRemoved(Task t) {
+ // Remove any stored data from the loader. We currently don't bother notifying the views
+ // that the data has been unloaded because at the point we call onTaskRemoved(), the views
+ // either don't need to be updated, or have already been removed.
+ RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
+ loader.deleteTaskData(t, false);
+
+ // Remove the old task from activity manager
+ int flags = t.key.baseIntent.getFlags();
+ boolean isDocument = (flags & Intent.FLAG_ACTIVITY_NEW_DOCUMENT) ==
+ Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
+ RecentsTaskLoader.getInstance().getSystemServicesProxy().removeTask(t.key.id,
+ isDocument);
+ }
+
/**** RecentsPackageMonitor.PackageCallbacks Implementation ****/
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
index ad0f2f8228a9..55c38a9aa62e 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -23,6 +23,7 @@ import android.animation.ValueAnimator;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
+import android.content.Intent;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.Region;
@@ -60,6 +61,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
interface TaskStackViewCallbacks {
public void onTaskLaunched(TaskStackView stackView, TaskView tv, TaskStack stack, Task t);
public void onTaskAppInfoLaunched(Task t);
+ public void onTaskRemoved(Task t);
}
TaskStack mStack;
@@ -1480,12 +1482,8 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback {
// Remove the task from the view
mSv.mStack.removeTask(task);
- // Remove any stored data from the loader
- RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
- loader.deleteTaskData(task);
-
- // Remove the task from activity manager
- RecentsTaskLoader.getInstance().getSystemServicesProxy().removeTask(tv.getTask().key.id);
+ // Notify the callback that we've removed the task and it can clean up after it
+ mSv.mCb.onTaskRemoved(task);
// Disable HW layers
mSv.decHwLayersRefCount("swipeComplete");
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index ecefc39eb472..898f06e2fe43 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -1029,6 +1029,9 @@ public abstract class BaseStatusBar extends SystemUI implements
}
protected void addNotificationViews(NotificationData.Entry entry) {
+ if (entry == null) {
+ return;
+ }
// Add the expanded view and icon.
int pos = mNotificationData.add(entry);
if (DEBUG) {
diff --git a/services/core/java/com/android/server/VibratorService.java b/services/core/java/com/android/server/VibratorService.java
index 132ca007e7f2..ea9de1e83ccc 100644
--- a/services/core/java/com/android/server/VibratorService.java
+++ b/services/core/java/com/android/server/VibratorService.java
@@ -41,6 +41,7 @@ import android.provider.Settings;
import android.provider.Settings.SettingNotFoundException;
import android.util.Slog;
import android.view.InputDevice;
+import android.media.AudioManager;
import com.android.internal.app.IAppOpsService;
import com.android.internal.app.IBatteryStats;
@@ -73,6 +74,8 @@ public class VibratorService extends IVibratorService.Stub
private boolean mInputDeviceListenerRegistered; // guarded by mInputDeviceVibrators
private int mCurVibUid = -1;
+ private boolean mLowPowerMode;
+ private SettingsObserver mSettingObserver;
native static boolean vibratorExists();
native static void vibratorOn(long milliseconds);
@@ -159,15 +162,15 @@ public class VibratorService extends IVibratorService.Stub
public void systemReady() {
mIm = (InputManager)mContext.getSystemService(Context.INPUT_SERVICE);
+ mSettingObserver = new SettingsObserver(mH);
mContext.getContentResolver().registerContentObserver(
- Settings.System.getUriFor(Settings.System.VIBRATE_INPUT_DEVICES), true,
- new ContentObserver(mH) {
- @Override
- public void onChange(boolean selfChange) {
- updateInputDeviceVibrators();
- }
- }, UserHandle.USER_ALL);
+ Settings.System.getUriFor(Settings.System.VIBRATE_INPUT_DEVICES),
+ true, mSettingObserver, UserHandle.USER_ALL);
+
+ mContext.getContentResolver().registerContentObserver(
+ Settings.Global.getUriFor(Settings.Global.LOW_POWER_MODE), false,
+ mSettingObserver, UserHandle.USER_ALL);
mContext.registerReceiver(new BroadcastReceiver() {
@Override
@@ -179,6 +182,17 @@ public class VibratorService extends IVibratorService.Stub
updateInputDeviceVibrators();
}
+ private final class SettingsObserver extends ContentObserver {
+ public SettingsObserver(Handler handler) {
+ super(handler);
+ }
+
+ @Override
+ public void onChange(boolean SelfChange) {
+ updateInputDeviceVibrators();
+ }
+ }
+
public boolean hasVibrator() {
return doVibratorExists();
}
@@ -346,6 +360,9 @@ public class VibratorService extends IVibratorService.Stub
// Lock held on mVibrations
private void startVibrationLocked(final Vibration vib) {
try {
+ if (mLowPowerMode && vib.mStreamHint != AudioManager.STREAM_RING)
+ return;
+
int mode = mAppOpsService.checkAudioOperation(AppOpsManager.OP_VIBRATE,
vib.mStreamHint, vib.mUid, vib.mOpPkg);
if (mode == AppOpsManager.MODE_ALLOWED) {
@@ -425,6 +442,9 @@ public class VibratorService extends IVibratorService.Stub
} catch (SettingNotFoundException snfe) {
}
+ mLowPowerMode = Settings.Global.getInt(mContext.getContentResolver(),
+ Settings.Global.LOW_POWER_MODE, 0) != 0;
+
if (mVibrateInputDevicesSetting) {
if (!mInputDeviceListenerRegistered) {
mInputDeviceListenerRegistered = true;
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index efc56064d6e8..09e7e12140a7 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -9570,6 +9570,7 @@ public final class ActivityManagerService extends ActivityManagerNative
}
mAppOpsService.systemReady();
+ mUsageStatsService.systemReady();
mSystemReady = true;
}
@@ -14391,6 +14392,7 @@ public final class ActivityManagerService extends ActivityManagerNative
newConfig.seq = mConfigurationSeq;
mConfiguration = newConfig;
Slog.i(TAG, "Config changes=" + Integer.toHexString(changes) + " " + newConfig);
+ mUsageStatsService.noteStartConfig(newConfig);
final Configuration configCopy = new Configuration(mConfiguration);
diff --git a/services/core/java/com/android/server/am/UsageStatsService.java b/services/core/java/com/android/server/am/UsageStatsService.java
index 42cf9004ed68..4a5a554b30a2 100644
--- a/services/core/java/com/android/server/am/UsageStatsService.java
+++ b/services/core/java/com/android/server/am/UsageStatsService.java
@@ -17,26 +17,31 @@
package com.android.server.am;
import android.app.AppGlobals;
+import android.app.AppOpsManager;
+import android.app.UsageStats;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
+import android.content.res.Configuration;
import android.os.Binder;
import android.os.IBinder;
import android.os.FileUtils;
import android.os.Parcel;
+import android.os.ParcelableParcel;
import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
+import android.text.format.DateFormat;
import android.util.ArrayMap;
import android.util.AtomicFile;
import android.util.Slog;
+import android.util.TimeUtils;
import android.util.Xml;
import com.android.internal.app.IUsageStats;
import com.android.internal.content.PackageMonitor;
-import com.android.internal.os.PkgUsageStats;
import com.android.internal.util.FastXmlSerializer;
import org.xmlpull.v1.XmlPullParser;
@@ -46,7 +51,6 @@ import org.xmlpull.v1.XmlSerializer;
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
-import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
@@ -55,8 +59,6 @@ import java.util.Calendar;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
-import java.util.Map;
-import java.util.Set;
import java.util.TimeZone;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
@@ -75,7 +77,7 @@ public final class UsageStatsService extends IUsageStats.Stub {
private static final String TAG = "UsageStats";
// Current on-disk Parcel version
- private static final int VERSION = 1008;
+ private static final int VERSION = 1010;
private static final int CHECKIN_VERSION = 4;
@@ -94,13 +96,10 @@ public final class UsageStatsService extends IUsageStats.Stub {
static IUsageStats sService;
private Context mContext;
- // structure used to maintain statistics since the last checkin.
- final private ArrayMap<String, PkgUsageStatsExtended> mStats
- = new ArrayMap<String, PkgUsageStatsExtended>();
+ private AppOpsManager mAppOps;
- // Maintains the last time any component was resumed, for all time.
- final private ArrayMap<String, ArrayMap<String, Long>> mLastResumeTimes
- = new ArrayMap<String, ArrayMap<String, Long>>();
+ // structure used to maintain statistics since the last checkin.
+ private LocalUsageStats mStats = new LocalUsageStats();
// To remove last-resume time stats when a pacakge is removed.
private PackageMonitor mPackageMonitor;
@@ -115,6 +114,7 @@ public final class UsageStatsService extends IUsageStats.Stub {
private String mLastResumedPkg;
private String mLastResumedComp;
private boolean mIsResumed;
+ private ConfigUsageStatsExtended mCurrentConfigStats;
private File mFile;
private AtomicFile mHistoryFile;
private String mFileLeaf;
@@ -127,6 +127,30 @@ public final class UsageStatsService extends IUsageStats.Stub {
private final AtomicLong mLastWriteElapsedTime = new AtomicLong(0);
private final AtomicBoolean mUnforcedDiskWriteRunning = new AtomicBoolean(false);
+ static class LocalUsageStats extends UsageStats {
+ public LocalUsageStats() {
+ }
+ public LocalUsageStats(Parcel in, boolean extended) {
+ super(in, extended);
+ }
+ @Override
+ public PackageStats onNewPackageStats(String pkgName) {
+ return new PkgUsageStatsExtended(pkgName);
+ }
+ @Override
+ public PackageStats onNewPackageStats(Parcel in) {
+ return new PkgUsageStatsExtended(in);
+ }
+ @Override
+ public ConfigurationStats onNewConfigurationStats(Configuration config) {
+ return new ConfigUsageStatsExtended(config);
+ }
+ @Override
+ public ConfigurationStats onNewConfigurationStats(Parcel source) {
+ return new ConfigUsageStatsExtended(source);
+ }
+ }
+
static class TimeStats {
int mCount;
final int[] mTimes = new int[NUM_LAUNCH_TIME_BINS];
@@ -166,27 +190,18 @@ public final class UsageStatsService extends IUsageStats.Stub {
}
}
- static class PkgUsageStatsExtended {
+ static class PkgUsageStatsExtended extends UsageStats.PackageStats {
final ArrayMap<String, TimeStats> mLaunchTimes
= new ArrayMap<String, TimeStats>();
final ArrayMap<String, TimeStats> mFullyDrawnTimes
= new ArrayMap<String, TimeStats>();
- int mLaunchCount;
- long mUsageTime;
- long mPausedTime;
- long mResumedTime;
- PkgUsageStatsExtended() {
- mLaunchCount = 0;
- mUsageTime = 0;
+ PkgUsageStatsExtended(String pkgName) {
+ super(pkgName);
}
PkgUsageStatsExtended(Parcel in) {
- mLaunchCount = in.readInt();
- mUsageTime = in.readLong();
- if (localLOGV) Slog.v(TAG, "Launch count: " + mLaunchCount
- + ", Usage time:" + mUsageTime);
-
+ super(in);
final int numLaunchTimeStats = in.readInt();
if (localLOGV) Slog.v(TAG, "Reading launch times: " + numLaunchTimeStats);
mLaunchTimes.ensureCapacity(numLaunchTimeStats);
@@ -208,18 +223,6 @@ public final class UsageStatsService extends IUsageStats.Stub {
}
}
- void updateResume(String comp, boolean launched) {
- if (launched) {
- mLaunchCount++;
- }
- mResumedTime = SystemClock.elapsedRealtime();
- }
-
- void updatePause() {
- mPausedTime = SystemClock.elapsedRealtime();
- mUsageTime += (mPausedTime - mResumedTime);
- }
-
void addLaunchCount(String comp) {
TimeStats times = mLaunchTimes.get(comp);
if (times == null) {
@@ -247,9 +250,7 @@ public final class UsageStatsService extends IUsageStats.Stub {
times.add(millis);
}
- void writeToParcel(Parcel out) {
- out.writeInt(mLaunchCount);
- out.writeLong(mUsageTime);
+ public void writeExtendedToParcel(Parcel out, int parcelableFlags) {
final int numLaunchTimeStats = mLaunchTimes.size();
out.writeInt(numLaunchTimeStats);
for (int i=0; i<numLaunchTimeStats; i++) {
@@ -264,11 +265,21 @@ public final class UsageStatsService extends IUsageStats.Stub {
}
}
- void clear() {
+ @Override
+ public boolean clearUsageTimes() {
mLaunchTimes.clear();
mFullyDrawnTimes.clear();
- mLaunchCount = 0;
- mUsageTime = 0;
+ return super.clearUsageTimes();
+ }
+ }
+
+ static class ConfigUsageStatsExtended extends UsageStats.ConfigurationStats {
+ ConfigUsageStatsExtended(Configuration config) {
+ super(config);
+ }
+
+ ConfigUsageStatsExtended(Parcel in) {
+ super(in);
}
}
@@ -364,18 +375,9 @@ public final class UsageStatsService extends IUsageStats.Stub {
+ VERSION + "; dropping");
return;
}
- int N = in.readInt();
- while (N > 0) {
- N--;
- String pkgName = in.readString();
- if (pkgName == null) {
- break;
- }
- if (localLOGV) Slog.v(TAG, "Reading package #" + N + ": " + pkgName);
- PkgUsageStatsExtended pus = new PkgUsageStatsExtended(in);
- synchronized (mStatsLock) {
- mStats.put(pkgName, pus);
- }
+ LocalUsageStats stats = new LocalUsageStats(in, true);
+ synchronized (mStatsLock) {
+ mStats = stats;
}
}
@@ -419,12 +421,9 @@ public final class UsageStatsService extends IUsageStats.Stub {
try {
long lastResumeTime = Long.parseLong(lastResumeTimeStr);
synchronized (mStatsLock) {
- ArrayMap<String, Long> lrt = mLastResumeTimes.get(pkg);
- if (lrt == null) {
- lrt = new ArrayMap<String, Long>();
- mLastResumeTimes.put(pkg, lrt);
- }
- lrt.put(comp, lastResumeTime);
+ PkgUsageStatsExtended pus = (PkgUsageStatsExtended)
+ mStats.getOrCreatePackageStats(pkg);
+ pus.componentResumeTimes.put(comp, lastResumeTime);
}
} catch (NumberFormatException e) {
}
@@ -543,6 +542,15 @@ public final class UsageStatsService extends IUsageStats.Stub {
return;
}
+ Parcel out = Parcel.obtain();
+ synchronized (mStatsLock) {
+ out.writeInt(VERSION);
+ mStats.writeExtendedToParcel(out, 0);
+ if (dayChanged) {
+ mStats.clearUsageTimes();
+ }
+ }
+
synchronized (mFileLock) {
// Get the most recent file
mFileLeaf = getCurrentDateStr(FILE_PREFIX);
@@ -553,6 +561,7 @@ public final class UsageStatsService extends IUsageStats.Stub {
if (!backupFile.exists()) {
if (!mFile.renameTo(backupFile)) {
Slog.w(TAG, "Failed to persist new stats");
+ out.recycle();
return;
}
} else {
@@ -562,14 +571,10 @@ public final class UsageStatsService extends IUsageStats.Stub {
try {
// Write mStats to file
- writeStatsFLOCK(mFile);
+ writeStatsFLOCK(mFile, out);
mLastWriteElapsedTime.set(currElapsedTime);
if (dayChanged) {
mLastWriteDay.set(curDay);
- // clear stats
- synchronized (mStats) {
- mStats.clear();
- }
mFile = new File(mDir, mFileLeaf);
checkFileLimitFLOCK();
}
@@ -590,17 +595,15 @@ public final class UsageStatsService extends IUsageStats.Stub {
backupFile.renameTo(mFile);
}
}
+ out.recycle();
}
if (localLOGV) Slog.d(TAG, "Dumped usage stats.");
}
- private void writeStatsFLOCK(File file) throws IOException {
+ private void writeStatsFLOCK(File file, Parcel parcel) throws IOException {
FileOutputStream stream = new FileOutputStream(file);
try {
- Parcel out = Parcel.obtain();
- writeStatsToParcelFLOCK(out);
- stream.write(out.marshall());
- out.recycle();
+ stream.write(parcel.marshall());
stream.flush();
} finally {
FileUtils.sync(stream);
@@ -608,29 +611,14 @@ public final class UsageStatsService extends IUsageStats.Stub {
}
}
- private void writeStatsToParcelFLOCK(Parcel out) {
- synchronized (mStatsLock) {
- out.writeInt(VERSION);
- Set<String> keys = mStats.keySet();
- out.writeInt(keys.size());
- for (String key : keys) {
- PkgUsageStatsExtended pus = mStats.get(key);
- out.writeString(key);
- pus.writeToParcel(out);
- }
- }
- }
-
/** Filter out stats for any packages which aren't present anymore. */
private void filterHistoryStats() {
synchronized (mStatsLock) {
IPackageManager pm = AppGlobals.getPackageManager();
- for (int i=0; i<mLastResumeTimes.size(); i++) {
- String pkg = mLastResumeTimes.keyAt(i);
+ for (int i=mStats.mPackages.size()-1; i>=0; i--) {
try {
- if (pm.getPackageUid(pkg, 0) < 0) {
- mLastResumeTimes.removeAt(i);
- i--;
+ if (pm.getPackageUid(mStats.mPackages.valueAt(i).getPackageName(), 0) < 0) {
+ mStats.mPackages.removeAt(i);
}
} catch (RemoteException e) {
}
@@ -648,10 +636,12 @@ public final class UsageStatsService extends IUsageStats.Stub {
out.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
out.startTag(null, "usage-history");
synchronized (mStatsLock) {
- for (int i=0; i<mLastResumeTimes.size(); i++) {
+ int NP = mStats.mPackages.size();
+ for (int i=0; i<NP; i++) {
+ UsageStats.PackageStats ps = mStats.mPackages.valueAt(i);
out.startTag(null, "pkg");
- out.attribute(null, "name", mLastResumeTimes.keyAt(i));
- ArrayMap<String, Long> comp = mLastResumeTimes.valueAt(i);
+ out.attribute(null, "name", ps.getPackageName());
+ ArrayMap<String, Long> comp = ps.componentResumeTimes;
for (int j=0; j<comp.size(); j++) {
out.startTag(null, "comp");
out.attribute(null, "name", comp.keyAt(j));
@@ -678,6 +668,10 @@ public final class UsageStatsService extends IUsageStats.Stub {
ServiceManager.addService(SERVICE_NAME, asBinder());
}
+ public void systemReady() {
+ mAppOps = (AppOpsManager)mContext.getSystemService(Context.APP_OPS_SERVICE);
+ }
+
/**
* Start watching packages to remove stats when a package is uninstalled.
* May only be called when the package manager is ready.
@@ -687,7 +681,7 @@ public final class UsageStatsService extends IUsageStats.Stub {
@Override
public void onPackageRemovedAllUsers(String packageName, int uid) {
synchronized (mStatsLock) {
- mLastResumeTimes.remove(packageName);
+ mStats.mPackages.remove(packageName);
}
}
};
@@ -729,9 +723,10 @@ public final class UsageStatsService extends IUsageStats.Stub {
// to recover.
if (REPORT_UNEXPECTED) Slog.i(TAG, "Unexpected resume of " + pkgName
+ " while already resumed in " + mLastResumedPkg);
- PkgUsageStatsExtended pus = mStats.get(mLastResumedPkg);
+ PkgUsageStatsExtended pus = (PkgUsageStatsExtended)mStats.getPackageStats(
+ mLastResumedPkg);
if (pus != null) {
- pus.updatePause();
+ pus.pause();
}
}
}
@@ -744,22 +739,13 @@ public final class UsageStatsService extends IUsageStats.Stub {
mLastResumedComp = componentName.getClassName();
if (localLOGV) Slog.i(TAG, "started component:" + pkgName);
- PkgUsageStatsExtended pus = mStats.get(pkgName);
- if (pus == null) {
- pus = new PkgUsageStatsExtended();
- mStats.put(pkgName, pus);
- }
- pus.updateResume(mLastResumedComp, !samePackage);
+ PkgUsageStatsExtended pus = (PkgUsageStatsExtended)
+ mStats.getOrCreatePackageStats(pkgName);
+ pus.resume(!samePackage);
if (!sameComp) {
pus.addLaunchCount(mLastResumedComp);
}
-
- ArrayMap<String, Long> componentResumeTimes = mLastResumeTimes.get(pkgName);
- if (componentResumeTimes == null) {
- componentResumeTimes = new ArrayMap<String, Long>();
- mLastResumeTimes.put(pkgName, componentResumeTimes);
- }
- componentResumeTimes.put(mLastResumedComp, System.currentTimeMillis());
+ pus.componentResumeTimes.put(mLastResumedComp, System.currentTimeMillis());
}
}
@@ -782,13 +768,13 @@ public final class UsageStatsService extends IUsageStats.Stub {
if (localLOGV) Slog.i(TAG, "paused component:"+pkgName);
- PkgUsageStatsExtended pus = mStats.get(pkgName);
+ PkgUsageStatsExtended pus = (PkgUsageStatsExtended)mStats.getPackageStats(pkgName);
if (pus == null) {
// Weird some error here
Slog.i(TAG, "No package stats for pkg:"+pkgName);
return;
}
- pus.updatePause();
+ pus.pause();
}
// Persist current data to file if needed.
@@ -808,7 +794,7 @@ public final class UsageStatsService extends IUsageStats.Stub {
writeStatsToFile(false, false);
synchronized (mStatsLock) {
- PkgUsageStatsExtended pus = mStats.get(pkgName);
+ PkgUsageStatsExtended pus = (PkgUsageStatsExtended)mStats.getPackageStats(pkgName);
if (pus != null) {
pus.addLaunchTime(componentName.getClassName(), millis);
}
@@ -827,13 +813,29 @@ public final class UsageStatsService extends IUsageStats.Stub {
writeStatsToFile(false, false);
synchronized (mStatsLock) {
- PkgUsageStatsExtended pus = mStats.get(pkgName);
+ PkgUsageStatsExtended pus = (PkgUsageStatsExtended)mStats.getPackageStats(pkgName);
if (pus != null) {
pus.addFullyDrawnTime(componentName.getClassName(), millis);
}
}
}
+ public void noteStartConfig(Configuration config) {
+ enforceCallingPermission();
+ synchronized (mStatsLock) {
+ config = new Configuration(config);
+ ConfigUsageStatsExtended cus = (ConfigUsageStatsExtended)
+ mStats.getOrCreateConfigurationStats(config);
+ if (cus != mCurrentConfigStats) {
+ if (mCurrentConfigStats != null) {
+ mCurrentConfigStats.stop();
+ }
+ cus.start();
+ mCurrentConfigStats = cus;
+ }
+ }
+ }
+
public void enforceCallingPermission() {
if (Binder.getCallingPid() == Process.myPid()) {
return;
@@ -843,53 +845,71 @@ public final class UsageStatsService extends IUsageStats.Stub {
}
@Override
- public PkgUsageStats getPkgUsageStats(ComponentName componentName) {
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.PACKAGE_USAGE_STATS, null);
+ public UsageStats.PackageStats getPkgUsageStats(String callingPkg,
+ ComponentName componentName) {
+ checkCallerPermission(callingPkg, "getPkgUsageStats");
String pkgName;
if ((componentName == null) ||
((pkgName = componentName.getPackageName()) == null)) {
return null;
}
synchronized (mStatsLock) {
- PkgUsageStatsExtended pus = mStats.get(pkgName);
- Map<String, Long> lastResumeTimes = mLastResumeTimes.get(pkgName);
- if (pus == null && lastResumeTimes == null) {
+ PkgUsageStatsExtended pus = (PkgUsageStatsExtended)mStats.getPackageStats(pkgName);
+ if (pus == null) {
return null;
}
- int launchCount = pus != null ? pus.mLaunchCount : 0;
- long usageTime = pus != null ? pus.mUsageTime : 0;
- return new PkgUsageStats(pkgName, launchCount, usageTime, lastResumeTimes);
+ return new UsageStats.PackageStats(pus);
}
}
@Override
- public PkgUsageStats[] getAllPkgUsageStats() {
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.PACKAGE_USAGE_STATS, null);
+ public UsageStats.PackageStats[] getAllPkgUsageStats(String callingPkg) {
+ checkCallerPermission(callingPkg, "getAllPkgUsageStats");
synchronized (mStatsLock) {
- int size = mLastResumeTimes.size();
- if (size <= 0) {
+ int NP = mStats.mPackages.size();
+ if (NP <= 0) {
return null;
}
- PkgUsageStats retArr[] = new PkgUsageStats[size];
- for (int i=0; i<size; i++) {
- String pkg = mLastResumeTimes.keyAt(i);
- long usageTime = 0;
- int launchCount = 0;
-
- PkgUsageStatsExtended pus = mStats.get(pkg);
- if (pus != null) {
- usageTime = pus.mUsageTime;
- launchCount = pus.mLaunchCount;
- }
- retArr[i] = new PkgUsageStats(pkg, launchCount, usageTime,
- mLastResumeTimes.valueAt(i));
+ UsageStats.PackageStats retArr[] = new UsageStats.PackageStats[NP];
+ for (int p=0; p<NP; p++) {
+ UsageStats.PackageStats ps = mStats.mPackages.valueAt(p);
+ retArr[p] = new UsageStats.PackageStats(ps);
}
return retArr;
}
}
+ @Override
+ public ParcelableParcel getCurrentStats(String callingPkg) {
+ checkCallerPermission(callingPkg, "getCurrentStats");
+ synchronized (mStatsLock) {
+ ParcelableParcel out = new ParcelableParcel(null);
+ mStats.writeToParcel(out.getParcel(), 0);
+ return out;
+ }
+ }
+
+ private void checkCallerPermission(String callingPkg, String callingOp) {
+ // Because the permission for this is system-only, its use with
+ // app ops is a little different: the op is disabled by default,
+ // and enabling it allows apps to get access even if they don't
+ // hold the permission.
+ int mode = mAppOps.noteOpNoThrow(AppOpsManager.OP_GET_USAGE_STATS, Binder.getCallingUid(),
+ callingPkg);
+ if (mode == AppOpsManager.MODE_ALLOWED) {
+ return;
+ } else if (mode != AppOpsManager.MODE_IGNORED) {
+ if (mContext.checkCallingOrSelfPermission(
+ android.Manifest.permission.PACKAGE_USAGE_STATS)
+ == PackageManager.PERMISSION_GRANTED) {
+ return;
+ }
+ }
+
+ String msg = "Package " + callingPkg + " not allowed to call " + callingOp;
+ throw new SecurityException(msg);
+ }
+
static byte[] readFully(FileInputStream stream) throws IOException {
int pos = 0;
int avail = stream.available();
@@ -963,31 +983,28 @@ public final class UsageStatsService extends IUsageStats.Stub {
return;
}
- pw.println(sb.toString());
- int N = in.readInt();
+ final LocalUsageStats stats = new LocalUsageStats(in, true);
+ final long time = SystemClock.elapsedRealtime();
- while (N > 0) {
- N--;
- String pkgName = in.readString();
- if (pkgName == null) {
- break;
- }
+ pw.println(sb.toString());
+ int NP = stats.mPackages.size();
+ for (int p=0; p<NP; p++) {
+ PkgUsageStatsExtended pus = (PkgUsageStatsExtended)stats.mPackages.valueAt(p);
sb.setLength(0);
- PkgUsageStatsExtended pus = new PkgUsageStatsExtended(in);
- if (packages != null && !packages.contains(pkgName)) {
+ if (packages != null && !packages.contains(pus.getPackageName())) {
// This package has not been requested -- don't print
// anything for it.
} else if (isCompactOutput) {
sb.append("P:");
- sb.append(pkgName);
+ sb.append(pus.getPackageName());
sb.append(',');
- sb.append(pus.mLaunchCount);
+ sb.append(pus.getLaunchCount());
sb.append(',');
- sb.append(pus.mUsageTime);
+ sb.append(pus.getUsageTime(time));
sb.append('\n');
final int NLT = pus.mLaunchTimes.size();
for (int i=0; i<NLT; i++) {
- sb.append("A:");
+ sb.append("L:");
String activity = pus.mLaunchTimes.keyAt(i);
sb.append(activity);
TimeStats times = pus.mLaunchTimes.valueAt(i);
@@ -1001,7 +1018,7 @@ public final class UsageStatsService extends IUsageStats.Stub {
}
final int NFDT = pus.mFullyDrawnTimes.size();
for (int i=0; i<NFDT; i++) {
- sb.append("A:");
+ sb.append("D:");
String activity = pus.mFullyDrawnTimes.keyAt(i);
sb.append(activity);
TimeStats times = pus.mFullyDrawnTimes.valueAt(i);
@@ -1011,15 +1028,23 @@ public final class UsageStatsService extends IUsageStats.Stub {
}
sb.append('\n');
}
+ final int NC = pus.componentResumeTimes.size();
+ for (int c=0; c<NC; c++) {
+ pw.print("R:"); pw.print(pus.componentResumeTimes.keyAt(c)); pw.print(",");
+ pw.println(pus.componentResumeTimes.valueAt(c));
+ }
} else {
sb.append(" ");
- sb.append(pkgName);
- sb.append(": ");
- sb.append(pus.mLaunchCount);
- sb.append(" times, ");
- sb.append(pus.mUsageTime);
- sb.append(" ms");
+ sb.append(pus.getPackageName());
+ if (pus.getLaunchCount() != 0 || pus.getUsageTime(time) != 0) {
+ sb.append(": ");
+ sb.append(pus.getLaunchCount());
+ sb.append(" times, ");
+ TimeUtils.formatDuration(pus.getUsageTime(time), sb);
+ } else {
+ sb.append(":");
+ }
sb.append('\n');
final int NLT = pus.mLaunchTimes.size();
for (int i=0; i<NLT; i++) {
@@ -1084,10 +1109,50 @@ public final class UsageStatsService extends IUsageStats.Stub {
}
sb.append('\n');
}
+ final int NC = pus.componentResumeTimes.size();
+ for (int c=0; c<NC; c++) {
+ sb.append(" ");
+ sb.append(pus.componentResumeTimes.keyAt(c));
+ sb.append(" last resumed ");
+ sb.append(DateFormat.format("yyyy-MM-dd-HH-mm-ss",
+ pus.componentResumeTimes.valueAt(c)).toString());
+ sb.append('\n');
+ }
}
pw.write(sb.toString());
}
+ if (packages == null) {
+ int NC = stats.mConfigurations.size();
+ for (int c=0; c<NC; c++) {
+ ConfigUsageStatsExtended cus
+ = (ConfigUsageStatsExtended)stats.mConfigurations.valueAt(c);
+ sb.setLength(0);
+ if (isCompactOutput) {
+ sb.append("C:"); sb.append(cus.getConfiguration().toString());
+ sb.append(","); sb.append(cus.getUsageCount()); sb.append(",");
+ sb.append(cus.getUsageTime(time));
+ } else {
+ sb.append(" ");
+ sb.append(cus.getConfiguration().toString());
+ sb.append(":\n");
+ if (cus.getUsageCount() != 0 || cus.getUsageTime(time) != 0) {
+ sb.append(" Used ");
+ sb.append(cus.getUsageCount());
+ sb.append(" times, ");
+ TimeUtils.formatDuration(cus.getUsageTime(time), sb);
+ sb.append("\n");
+ }
+ if (cus.getLastUsedTime() > 0) {
+ sb.append(" Last used: ");
+ sb.append(DateFormat.format("yyyy-MM-dd-HH-mm-ss",
+ cus.getLastUsedTime()).toString());
+ sb.append("\n");
+ }
+ }
+ pw.write(sb.toString());
+ }
+ }
}
/**
@@ -1174,5 +1239,4 @@ public final class UsageStatsService extends IUsageStats.Stub {
collectDumpInfoFLOCK(pw, isCompactOutput, deleteAfterPrint, packages);
}
}
-
}
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index 90392369b856..99ec242902ce 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -116,7 +116,8 @@ public class AppTransition implements Dump {
/** Fraction of animation at which the recents thumbnail becomes completely transparent */
private static final float RECENTS_THUMBNAIL_FADEOUT_FRACTION = 0.25f;
- private static final long DEFAULT_APP_TRANSITION_DURATION = 250;
+ private static final int DEFAULT_APP_TRANSITION_DURATION = 250;
+ private static final int THUMBNAIL_APP_TRANSITION_DURATION = 225;
private final Context mContext;
private final Handler mH;
@@ -160,6 +161,7 @@ public class AppTransition implements Dump {
private final int mConfigShortAnimTime;
private final Interpolator mDecelerateInterpolator;
private final Interpolator mThumbnailFadeoutInterpolator;
+ private final Interpolator mThumbnailCubicInterpolator;
private int mCurrentUserId = 0;
@@ -170,6 +172,8 @@ public class AppTransition implements Dump {
com.android.internal.R.integer.config_shortAnimTime);
mDecelerateInterpolator = AnimationUtils.loadInterpolator(context,
com.android.internal.R.interpolator.decelerate_cubic);
+ mThumbnailCubicInterpolator = AnimationUtils.loadInterpolator(context,
+ com.android.internal.R.interpolator.fast_out_slow_in);
mThumbnailFadeoutInterpolator = new Interpolator() {
@Override
public float getInterpolation(float input) {
@@ -401,11 +405,23 @@ public class AppTransition implements Dump {
/**
* Prepares the specified animation with a standard duration, interpolator, etc.
*/
+ Animation prepareThumbnailAnimationWithDuration(Animation a, int appWidth, int appHeight,
+ int duration, Interpolator interpolator) {
+ a.setDuration(duration);
+ a.setFillAfter(true);
+ a.setInterpolator(interpolator);
+ a.initialize(appWidth, appHeight, appWidth, appHeight);
+ return a;
+ }
+
+ /**
+ * Prepares the specified animation with a standard duration, interpolator, etc.
+ */
Animation prepareThumbnailAnimation(Animation a, int appWidth, int appHeight, int transit) {
// Pick the desired duration. If this is an inter-activity transition,
// it is the standard duration for that. Otherwise we use the longer
// task transition duration.
- final long duration;
+ final int duration;
switch (transit) {
case TRANSIT_ACTIVITY_OPEN:
case TRANSIT_ACTIVITY_CLOSE:
@@ -415,11 +431,8 @@ public class AppTransition implements Dump {
duration = DEFAULT_APP_TRANSITION_DURATION;
break;
}
- a.setDuration(duration);
- a.setFillAfter(true);
- a.setInterpolator(mDecelerateInterpolator);
- a.initialize(appWidth, appHeight, appWidth, appHeight);
- return a;
+ return prepareThumbnailAnimationWithDuration(a, appWidth, appHeight, duration,
+ mDecelerateInterpolator);
}
/**
@@ -594,7 +607,8 @@ public class AppTransition implements Dump {
throw new RuntimeException("Invalid thumbnail transition state");
}
- return prepareThumbnailAnimation(a, appWidth, appHeight, transit);
+ return prepareThumbnailAnimationWithDuration(a, appWidth, appHeight,
+ THUMBNAIL_APP_TRANSITION_DURATION, mThumbnailCubicInterpolator);
}
/**