Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0debc9af authored by Adam Lesinski's avatar Adam Lesinski
Browse files

First iteration of a public UsageStats API

UsageStats API that allows apps to get a list of packages that have been
recently used, along with basic stats like how long they have been in
the foreground and the most recent time they were running.

Bug: 15165667

Change-Id: I2a2d1ff69bd0b5703ac3d9de1780df42ad90d439
parent d3de42ca
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -93,6 +93,7 @@ LOCAL_SRC_FILES += \
	core/java/android/app/backup/IFullBackupRestoreObserver.aidl \
	core/java/android/app/backup/IRestoreObserver.aidl \
	core/java/android/app/backup/IRestoreSession.aidl \
	core/java/android/app/usage/IUsageStatsManager.aidl \
	core/java/android/bluetooth/IBluetooth.aidl \
	core/java/android/bluetooth/IBluetoothA2dp.aidl \
	core/java/android/bluetooth/IBluetoothA2dpSink.aidl \
@@ -251,7 +252,6 @@ LOCAL_SRC_FILES += \
	core/java/com/android/internal/app/IAppOpsService.aidl \
	core/java/com/android/internal/app/IBatteryStats.aidl \
	core/java/com/android/internal/app/IProcessStats.aidl \
	core/java/com/android/internal/app/IUsageStats.aidl \
	core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl \
	core/java/com/android/internal/app/IVoiceInteractor.aidl \
	core/java/com/android/internal/app/IVoiceInteractorCallback.aidl \
+46 −0
Original line number Diff line number Diff line
@@ -5602,6 +5602,52 @@ package android.app.job {
}
package android.app.usage {
  public final class PackageUsageStats implements android.os.Parcelable {
    method public int describeContents();
    method public long getLastTimeUsed();
    method public java.lang.String getPackageName();
    method public long getTotalTimeSpent();
    method public void writeToParcel(android.os.Parcel, int);
    field public static final android.os.Parcelable.Creator CREATOR;
  }
  public final class UsageStats implements android.os.Parcelable {
    ctor public UsageStats(android.app.usage.UsageStats);
    method public int describeContents();
    method public long getFirstTimeStamp();
    method public long getLastTimeStamp();
    method public android.app.usage.PackageUsageStats getPackage(int);
    method public android.app.usage.PackageUsageStats getPackage(java.lang.String);
    method public int getPackageCount();
    method public void writeToParcel(android.os.Parcel, int);
    field public static final android.os.Parcelable.Creator CREATOR;
  }
  public static class UsageStats.Event implements android.os.Parcelable {
    ctor public UsageStats.Event();
    method public int describeContents();
    method public void writeToParcel(android.os.Parcel, int);
    field public static final android.os.Parcelable.Creator CREATOR;
    field public static final int MOVE_TO_BACKGROUND = 2; // 0x2
    field public static final int MOVE_TO_FOREGROUND = 1; // 0x1
    field public static final int NONE = 0; // 0x0
    field public int eventType;
    field public java.lang.String packageName;
    field public long timeStamp;
  }
  public final class UsageStatsManager {
    method public android.app.usage.UsageStats[] getDailyStatsSince(long);
    method public android.app.usage.UsageStats[] getMonthlyStatsSince(long);
    method public android.app.usage.UsageStats getRecentStatsSince(long);
    method public android.app.usage.UsageStats[] getWeeklyStatsSince(long);
    method public android.app.usage.UsageStats[] getYearlyStatsSince(long);
  }
}
package android.appwidget {
  public class AppWidgetHost {
+2 −21
Original line number Diff line number Diff line
@@ -19,7 +19,6 @@ package android.app;
import android.os.BatteryStats;
import android.os.IBinder;
import android.os.ParcelFileDescriptor;
import com.android.internal.app.IUsageStats;
import com.android.internal.app.ProcessStats;
import com.android.internal.os.TransferPipe;
import com.android.internal.util.FastPrintWriter;
@@ -2226,7 +2225,7 @@ public class ActivityManager {
     *
     * @hide
     */
    public Map<String, Integer> getAllPackageLaunchCounts() {
    /*public Map<String, Integer> getAllPackageLaunchCounts() {
        try {
            IUsageStats usageStatsService = IUsageStats.Stub.asInterface(
                    ServiceManager.getService("usagestats"));
@@ -2250,7 +2249,7 @@ public class ActivityManager {
            Log.w(TAG, "Could not query launch counts", e);
            return new HashMap<String, Integer>();
        }
    }
    }*/

    /** @hide */
    public static int checkComponentPermission(String permission, int uid,
@@ -2351,24 +2350,6 @@ public class ActivityManager {
        }
    }

    /**
     * Returns the usage statistics of each installed package.
     *
     * @hide
     */
    public UsageStats.PackageStats[] getAllPackageUsageStats() {
        try {
            IUsageStats usageStatsService = IUsageStats.Stub.asInterface(
                    ServiceManager.getService("usagestats"));
            if (usageStatsService != null) {
                return usageStatsService.getAllPkgUsageStats(ActivityThread.currentPackageName());
            }
        } catch (RemoteException e) {
            Log.w(TAG, "Could not query usage stats", e);
        }
        return new UsageStats.PackageStats[0];
    }

    /**
     * @param userid the user's id. Zero indicates the default user 
     * @hide
+10 −4
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@

package android.app;

import android.app.usage.IUsageStatsManager;
import android.app.usage.UsageStatsManager;
import android.os.Build;

import android.service.persistentdata.IPersistentDataBlockService;
@@ -729,7 +731,8 @@ class ContextImpl extends Context {
                IBinder iBinder = ServiceManager.getService(TV_INPUT_SERVICE);
                ITvInputManager service = ITvInputManager.Stub.asInterface(iBinder);
                return new TvInputManager(service, UserHandle.myUserId());
            }});
            }
        });

        registerService(TV_PARENTAL_CONTROL_SERVICE, new ServiceFetcher() {
                public Object getService(ContextImpl ctx) {
@@ -744,8 +747,11 @@ class ContextImpl extends Context {

        registerService(USAGE_STATS_SERVICE, new ServiceFetcher() {
            public Object createService(ContextImpl ctx) {
                return new UsageStatsManager(ctx.getOuterContext());
        }});
                IBinder iBinder = ServiceManager.getService(USAGE_STATS_SERVICE);
                IUsageStatsManager service = IUsageStatsManager.Stub.asInterface(iBinder);
                return new UsageStatsManager(ctx.getOuterContext(), service);
            }
        });

        registerService(JOB_SCHEDULER_SERVICE, new ServiceFetcher() {
            public Object createService(ContextImpl ctx) {
+0 −406
Original line number Diff line number Diff line
/*
 * 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];
        }
    };
}
Loading