am bfb752f8: Merge "Fix issue #6761130: Clearing app data in settings does not clear app\'s USB storage" into jb-dev

* commit 'bfb752f8f0e4d73dc251c19d2ef79649fbbe4fd1':
  Fix issue #6761130: Clearing app data in settings does not clear app's USB storage
diff --git a/core/java/com/android/internal/app/IMediaContainerService.aidl b/core/java/com/android/internal/app/IMediaContainerService.aidl
index c9f7a58..c82834f7 100755
--- a/core/java/com/android/internal/app/IMediaContainerService.aidl
+++ b/core/java/com/android/internal/app/IMediaContainerService.aidl
@@ -35,4 +35,5 @@
     long calculateDirectorySize(in String directory);
     /** Return file system stats: [0] is total bytes, [1] is available bytes */
     long[] getFileSystemStats(in String path);
+    void clearDirectory(in String directory);
 }
diff --git a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
index f09c010..a28b8a4 100644
--- a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
+++ b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
@@ -246,6 +246,16 @@
                 throw new IllegalStateException(e);
             }
         }
+
+        @Override
+        public void clearDirectory(String path) throws RemoteException {
+            Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
+
+            final File directory = new File(path);
+            if (directory.exists() && directory.isDirectory()) {
+                eraseFiles(directory);
+            }
+        }
     };
 
     public DefaultContainerService() {
diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
index e20cd02..3501e47 100644
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -7728,6 +7728,80 @@
         return ret;
     }
 
+    private final class ClearStorageConnection implements ServiceConnection {
+        IMediaContainerService mContainerService;
+
+        @Override
+        public void onServiceConnected(ComponentName name, IBinder service) {
+            synchronized (this) {
+                mContainerService = IMediaContainerService.Stub.asInterface(service);
+                notifyAll();
+            }
+        }
+
+        @Override
+        public void onServiceDisconnected(ComponentName name) {
+        }
+    }
+
+    private void clearExternalStorageDataSync(String packageName, boolean allData) {
+        final boolean mounted;
+        if (Environment.isExternalStorageEmulated()) {
+            mounted = true;
+        } else {
+            final String status = Environment.getExternalStorageState();
+
+            mounted = status.equals(Environment.MEDIA_MOUNTED)
+                    || status.equals(Environment.MEDIA_MOUNTED_READ_ONLY);
+        }
+
+        if (!mounted) {
+            return;
+        }
+
+        final Intent containerIntent = new Intent().setComponent(DEFAULT_CONTAINER_COMPONENT);
+        ClearStorageConnection conn = new ClearStorageConnection();
+        if (mContext.bindService(containerIntent, conn, Context.BIND_AUTO_CREATE)) {
+            try {
+                long timeout = SystemClock.uptimeMillis() + 5000;
+                synchronized (conn) {
+                    long now = SystemClock.uptimeMillis();
+                    while (conn.mContainerService == null && now < timeout) {
+                        try {
+                            conn.wait(timeout - now);
+                        } catch (InterruptedException e) {
+                        }
+                    }
+                }
+                if (conn.mContainerService == null) {
+                    return;
+                }
+                final File externalCacheDir = Environment
+                        .getExternalStorageAppCacheDirectory(packageName);
+                try {
+                    conn.mContainerService.clearDirectory(externalCacheDir.toString());
+                } catch (RemoteException e) {
+                }
+                if (allData) {
+                    final File externalDataDir = Environment
+                            .getExternalStorageAppDataDirectory(packageName);
+                    try {
+                        conn.mContainerService.clearDirectory(externalDataDir.toString());
+                    } catch (RemoteException e) {
+                    }
+                    final File externalMediaDir = Environment
+                            .getExternalStorageAppMediaDirectory(packageName);
+                    try {
+                        conn.mContainerService.clearDirectory(externalMediaDir.toString());
+                    } catch (RemoteException e) {
+                    }
+                }
+            } finally {
+                mContext.unbindService(conn);
+            }
+        }
+    }
+
     @Override
     public void clearApplicationUserData(final String packageName,
             final IPackageDataObserver observer, final int userId) {
@@ -7742,6 +7816,7 @@
                 synchronized (mInstallLock) {
                     succeeded = clearApplicationUserDataLI(packageName, userId);
                 }
+                clearExternalStorageDataSync(packageName, true);
                 if (succeeded) {
                     // invoke DeviceStorageMonitor's update method to clear any notifications
                     DeviceStorageMonitorService dsm = (DeviceStorageMonitorService)
@@ -7815,6 +7890,7 @@
                 synchronized (mInstallLock) {
                     succeded = deleteApplicationCacheFilesLI(packageName, userId);
                 }
+                clearExternalStorageDataSync(packageName, false);
                 if(observer != null) {
                     try {
                         observer.onRemoveCompleted(packageName, succeded);