Don't show app in deletion helper if it was installed recently.

This solves several problems. The first is that if a user installs
a large app which triggers the deletion helper, the deletion helper
may clear out the recently installed large app to free up space.

The second is that it appears that the usage stats may not be
synced from device to device currently using Backup and Restore.
By considering the installation to be a use for deletion helper
filtering, this should avoid the problem for 60 days (and if the
user hasn't used the app at that point, it should be fair game
to clear).

Bug: 28800057
Change-Id: Idb8545aa45a42e45dc673dc5c179c0197204edfd
diff --git a/src/com/android/settings/deletionhelper/AppStateUsageStatsBridge.java b/src/com/android/settings/deletionhelper/AppStateUsageStatsBridge.java
index 013c801..7bbe8bf 100644
--- a/src/com/android/settings/deletionhelper/AppStateUsageStatsBridge.java
+++ b/src/com/android/settings/deletionhelper/AppStateUsageStatsBridge.java
@@ -20,6 +20,9 @@
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
 
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.util.Log;
 import com.android.settings.applications.AppStateBaseBridge;
 import com.android.settingslib.applications.ApplicationsState;
 import com.android.settingslib.applications.ApplicationsState.AppEntry;
@@ -33,7 +36,9 @@
  * Connects data from the UsageStatsManager to the ApplicationsState.
  */
 public class AppStateUsageStatsBridge extends AppStateBaseBridge {
+    private static final String TAG = "AppStateUsageStatsBridge";
     private UsageStatsManager mUsageStatsManager;
+    private PackageManager mPm;
     public static final long NEVER_USED = -1;
     public static final long UNKNOWN_LAST_USE = -2;
 
@@ -42,6 +47,7 @@
         super(appState, callback);
         mUsageStatsManager =
                 (UsageStatsManager) context.getSystemService(Context.USAGE_STATS_SERVICE);
+        mPm = context.getPackageManager();
     }
 
     @Override
@@ -53,7 +59,8 @@
                 System.currentTimeMillis());
         for (AppEntry entry : apps) {
             UsageStats usageStats = map.get(entry.info.packageName);
-            entry.extraInfo = getDaysSinceLastUse(usageStats);
+            entry.extraInfo = new UsageStatsState(getDaysSinceLastUse(usageStats),
+                    getDaysSinceInstalled(entry.info.packageName));
         }
     }
 
@@ -62,7 +69,8 @@
         Map<String, UsageStats> map = mUsageStatsManager.queryAndAggregateUsageStats(0,
                 System.currentTimeMillis());
         UsageStats usageStats = map.get(app.info.packageName);
-        app.extraInfo = getDaysSinceLastUse(usageStats);
+        app.extraInfo = new UsageStatsState(getDaysSinceLastUse(usageStats),
+                getDaysSinceInstalled(app.info.packageName));
     }
 
     private long getDaysSinceLastUse(UsageStats stats) {
@@ -75,7 +83,21 @@
             return UNKNOWN_LAST_USE;
         }
         return TimeUnit.MILLISECONDS.toDays(System.currentTimeMillis() - lastUsed);
+    }
 
+    private long getDaysSinceInstalled(String packageName) {
+        PackageInfo pi = null;
+        try {
+            pi = mPm.getPackageInfo(packageName, 0);
+        } catch (PackageManager.NameNotFoundException e) {
+            Log.e(TAG, packageName + " was not found.");
+        }
+
+        if (pi == null) {
+            return NEVER_USED;
+        }
+
+        return (TimeUnit.MILLISECONDS.toDays(System.currentTimeMillis() - pi.firstInstallTime));
     }
 
     /**
@@ -92,18 +114,36 @@
         @Override
         public boolean filterApp(AppEntry info) {
             if (info == null) return false;
-            boolean isBundled = (info.info.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
-            return isExtraInfoValid(info.extraInfo) && !isBundled;
+            return isExtraInfoValid(info.extraInfo) && !isBundled(info)
+                    && !isPersistentProcess(info);
         }
 
         private boolean isExtraInfoValid(Object extraInfo) {
-            if (extraInfo == null || !(extraInfo instanceof Long)) {
+            if (extraInfo == null || !(extraInfo instanceof UsageStatsState)) {
                 return false;
             }
 
-            long daysSinceLastUse = (long) extraInfo;
-            return daysSinceLastUse >= UNUSED_DAYS_DELETION_THRESHOLD ||
-                    daysSinceLastUse == NEVER_USED;
+            UsageStatsState state = (UsageStatsState) extraInfo;
+            long mostRecentUse = Math.max(state.daysSinceFirstInstall, state.daysSinceLastUse);
+            return mostRecentUse >= UNUSED_DAYS_DELETION_THRESHOLD || mostRecentUse == NEVER_USED;
+        }
+
+        private boolean isBundled(AppEntry info) {
+            return (info.info.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
+        }
+
+        private boolean isPersistentProcess(AppEntry info) {
+            return (info.info.flags & ApplicationInfo.FLAG_PERSISTENT) != 0;
         }
     };
+
+    private class UsageStatsState {
+        public long daysSinceLastUse;
+        public long daysSinceFirstInstall;
+
+        public UsageStatsState(long daysSinceLastUse, long daysSinceFirstInstall) {
+            this.daysSinceLastUse = daysSinceLastUse;
+            this.daysSinceFirstInstall = daysSinceFirstInstall;
+        }
+    }
 }