diff options
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); } /** |