Configuration of workspace through app restrictions

> Checking for a grid specific layout before loading the default layout

Change-Id: I1e8d4176341e61d0876b0a9bea9ad8010e3a0f6a
diff --git a/src/com/android/launcher3/AutoInstallsLayout.java b/src/com/android/launcher3/AutoInstallsLayout.java
index cbab08b..9180dcf 100644
--- a/src/com/android/launcher3/AutoInstallsLayout.java
+++ b/src/com/android/launcher3/AutoInstallsLayout.java
@@ -45,6 +45,7 @@
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.Locale;
 
 /**
  * Layout parsing code for auto installs layout
@@ -57,6 +58,11 @@
     static final String ACTION_LAUNCHER_CUSTOMIZATION =
             "android.autoinstalls.config.action.PLAY_AUTO_INSTALL";
 
+    /**
+     * Layout resource which also includes grid size and hotseat count, e.g., default_layout_6x6_h5
+     */
+    private static final String FORMATTED_LAYOUT_RES_WITH_HOSTEAT = "default_layout_%dx%d_h%s";
+    private static final String FORMATTED_LAYOUT_RES = "default_layout_%dx%d";
     private static final String LAYOUT_RES = "default_layout";
 
     static AutoInstallsLayout get(Context context, AppWidgetHost appWidgetHost,
@@ -66,15 +72,39 @@
         if (customizationApkInfo == null) {
             return null;
         }
+        return get(context, customizationApkInfo.first, customizationApkInfo.second,
+                appWidgetHost, callback);
+    }
 
-        String pkg = customizationApkInfo.first;
-        Resources res = customizationApkInfo.second;
-        int layoutId = res.getIdentifier(LAYOUT_RES, "xml", pkg);
+    static AutoInstallsLayout get(Context context, String pkg, Resources targetRes,
+            AppWidgetHost appWidgetHost, LayoutParserCallback callback) {
+        DeviceProfile grid = LauncherAppState.getInstance().getDynamicGrid().getDeviceProfile();
+
+        // Try with grid size and hotseat count
+        String layoutName = String.format(Locale.ENGLISH, FORMATTED_LAYOUT_RES_WITH_HOSTEAT,
+                (int) grid.numColumns, (int) grid.numRows, (int) grid.numHotseatIcons);
+        int layoutId = targetRes.getIdentifier(layoutName, "xml", pkg);
+
+        // Try with only grid size
+        if (layoutId == 0) {
+            Log.d(TAG, "Formatted layout: " + layoutName
+                    + " not found. Trying layout without hosteat");
+            layoutName = String.format(Locale.ENGLISH, FORMATTED_LAYOUT_RES,
+                    (int) grid.numColumns, (int) grid.numRows);
+            layoutId = targetRes.getIdentifier(layoutName, "xml", pkg);
+        }
+
+        // Try the default layout
+        if (layoutId == 0) {
+            Log.d(TAG, "Formatted layout: " + layoutName + " not found. Trying the default layout");
+            layoutId = targetRes.getIdentifier(LAYOUT_RES, "xml", pkg);
+        }
+
         if (layoutId == 0) {
             Log.e(TAG, "Layout definition not found in package: " + pkg);
             return null;
         }
-        return new AutoInstallsLayout(context, appWidgetHost, callback, res, layoutId,
+        return new AutoInstallsLayout(context, appWidgetHost, callback, targetRes, layoutId,
                 TAG_WORKSPACE);
     }
 
diff --git a/src/com/android/launcher3/LauncherProvider.java b/src/com/android/launcher3/LauncherProvider.java
index 6dd1305..dfacfa3 100644
--- a/src/com/android/launcher3/LauncherProvider.java
+++ b/src/com/android/launcher3/LauncherProvider.java
@@ -16,6 +16,7 @@
 
 package com.android.launcher3;
 
+import android.annotation.TargetApi;
 import android.appwidget.AppWidgetHost;
 import android.appwidget.AppWidgetManager;
 import android.content.ComponentName;
@@ -29,6 +30,7 @@
 import android.content.Intent;
 import android.content.OperationApplicationException;
 import android.content.SharedPreferences;
+import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.res.Resources;
 import android.database.Cursor;
 import android.database.SQLException;
@@ -36,7 +38,10 @@
 import android.database.sqlite.SQLiteOpenHelper;
 import android.database.sqlite.SQLiteQueryBuilder;
 import android.net.Uri;
+import android.os.Build;
+import android.os.Bundle;
 import android.os.StrictMode;
+import android.os.UserManager;
 import android.text.TextUtils;
 import android.util.Log;
 import android.util.SparseArray;
@@ -70,6 +75,8 @@
 
     private static final String URI_PARAM_IS_EXTERNAL_ADD = "isExternalAdd";
 
+    private static final String RESTRICTION_PACKAGE_NAME = "workspace.configuration.package.name";
+
     private LauncherProviderChangeListener mListener;
 
     /**
@@ -267,9 +274,10 @@
 
     /**
      * Loads the default workspace based on the following priority scheme:
-     *   1) From a package provided by play store
-     *   2) From a partner configuration APK, already in the system image
-     *   3) The default configuration for the particular device
+     *   1) From the app restrictions
+     *   2) From a package provided by play store
+     *   3) From a partner configuration APK, already in the system image
+     *   4) The default configuration for the particular device
      */
     synchronized public void loadDefaultFavoritesIfNecessary() {
         String spKey = LauncherAppState.getSharedPreferencesKey();
@@ -278,9 +286,11 @@
         if (sp.getBoolean(EMPTY_DATABASE_CREATED, false)) {
             Log.d(TAG, "loading default workspace");
 
-            AutoInstallsLayout loader = AutoInstallsLayout.get(getContext(),
-                    mOpenHelper.mAppWidgetHost, mOpenHelper);
-
+            AutoInstallsLayout loader = createWorkspaceLoaderFromAppRestriction();
+            if (loader == null) {
+                loader = AutoInstallsLayout.get(getContext(),
+                        mOpenHelper.mAppWidgetHost, mOpenHelper);
+            }
             if (loader == null) {
                 final Partner partner = Partner.get(getContext().getPackageManager());
                 if (partner != null && partner.hasDefaultLayout()) {
@@ -314,6 +324,37 @@
         }
     }
 
+    /**
+     * Creates workspace loader from an XML resource listed in the app restrictions.
+     *
+     * @return the loader if the restrictions are set and the resource exists; null otherwise.
+     */
+    @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
+    private AutoInstallsLayout createWorkspaceLoaderFromAppRestriction() {
+        // UserManager.getApplicationRestrictions() requires minSdkVersion >= 18
+        if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2) {
+            return null;
+        }
+
+        Context ctx = getContext();
+        UserManager um = (UserManager) ctx.getSystemService(Context.USER_SERVICE);
+        Bundle bundle = um.getApplicationRestrictions(ctx.getPackageName());
+        String packageName = bundle.getString(RESTRICTION_PACKAGE_NAME);
+
+        if (packageName != null) {
+            try {
+                Resources targetResources = ctx.getPackageManager()
+                        .getResourcesForApplication(packageName);
+                return AutoInstallsLayout.get(ctx, packageName, targetResources,
+                        mOpenHelper.mAppWidgetHost, mOpenHelper);
+            } catch (NameNotFoundException e) {
+                Log.e(TAG, "Target package for restricted profile not found", e);
+                return null;
+            }
+        }
+        return null;
+    }
+
     private DefaultLayoutParser getDefaultLayoutParser() {
         int defaultLayout = LauncherAppState.getInstance()
                 .getDynamicGrid().getDeviceProfile().defaultLayoutId;