Adding broadcast receiver to handle SESSION_COMMIT broadcast

> Disabling Install shortcut broadcast for O and above
> Adding a preference to control automatic icon addition on homescreen
> Adding icons on homescreen for new installs based on the above preference

Bug: 32920609
Bug: 27967412
Change-Id: I92e5cb7c841fb445dc8bc058d975f212ee54f8d1
diff --git a/AndroidManifest-common.xml b/AndroidManifest-common.xml
index da1679f..50fb2d7 100644
--- a/AndroidManifest-common.xml
+++ b/AndroidManifest-common.xml
@@ -58,12 +58,21 @@
         <!-- Intent received used to install shortcuts from other applications -->
         <receiver
             android:name="com.android.launcher3.InstallShortcutReceiver"
-            android:permission="com.android.launcher.permission.INSTALL_SHORTCUT">
+            android:permission="com.android.launcher.permission.INSTALL_SHORTCUT"
+            android:enabled="@bool/enable_install_shortcut_api" >
             <intent-filter>
                 <action android:name="com.android.launcher.action.INSTALL_SHORTCUT" />
             </intent-filter>
         </receiver>
 
+        <!-- Intent received when a session is committed -->
+        <receiver
+            android:name="com.android.launcher3.SessionCommitReceiver" >
+            <intent-filter>
+                <action android:name="android.content.pm.action.SESSION_COMMITTED" />
+            </intent-filter>
+        </receiver>
+
         <!-- Intent received used to initialize a restored widget -->
         <receiver android:name="com.android.launcher3.AppWidgetsRestoredReceiver" >
             <intent-filter>
diff --git a/res/values-v26/bools.xml b/res/values-v26/bools.xml
index 1093f78..30537fe 100644
--- a/res/values-v26/bools.xml
+++ b/res/values-v26/bools.xml
@@ -18,4 +18,6 @@
 
 <resources>
     <bool name="notification_badging_enabled">true</bool>
+
+    <bool name="enable_install_shortcut_api">false</bool>
 </resources>
\ No newline at end of file
diff --git a/res/values/bools.xml b/res/values/bools.xml
index cc4a7ba..53c67e2 100644
--- a/res/values/bools.xml
+++ b/res/values/bools.xml
@@ -18,4 +18,6 @@
 
 <resources>
     <bool name="notification_badging_enabled">false</bool>
+
+    <bool name="enable_install_shortcut_api">true</bool>
 </resources>
\ No newline at end of file
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 58bfb49..423a772 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -179,6 +179,11 @@
     <!-- Text explaining that rotation is disabled in Display settings. 'Display' refers to the Display section in system settings [CHAR LIMIT=100] -->
     <string name="allow_rotation_blocked_desc">Current Display setting doesn\'t permit rotation</string>
 
+    <!-- Label for the setting that allows the automatic placement of launcher shortcuts for applications and games installed on the device [CHAR LIMIT=40] -->
+    <string name="auto_add_shortcuts_label">Add icon to Home screen</string>
+    <!-- Text description of the setting that allows the automatic placement of launcher shortcuts for applications and games installed on the device [CHAR LIMIT=NONE] -->
+    <string name="auto_add_shortcuts_description">For new apps</string>
+
     <!-- Label on an icon that references an uninstalled package, for which we have no information about when it might be installed. [CHAR_LIMIT=15] -->
     <string name="package_state_unknown">Unknown</string>
 
diff --git a/res/xml/launcher_preferences.xml b/res/xml/launcher_preferences.xml
index 624d9eb..a16583d 100644
--- a/res/xml/launcher_preferences.xml
+++ b/res/xml/launcher_preferences.xml
@@ -23,4 +23,11 @@
             android:persistent="true"
     />
 
+    <SwitchPreference
+        android:key="pref_add_icon_to_home"
+        android:title="@string/auto_add_shortcuts_label"
+        android:summary="@string/auto_add_shortcuts_description"
+        android:defaultValue="true"
+        android:persistent="true"
+        />
 </PreferenceScreen>
diff --git a/src/com/android/launcher3/InstallShortcutReceiver.java b/src/com/android/launcher3/InstallShortcutReceiver.java
index 1bab774..80dec16 100644
--- a/src/com/android/launcher3/InstallShortcutReceiver.java
+++ b/src/com/android/launcher3/InstallShortcutReceiver.java
@@ -218,6 +218,10 @@
         queuePendingShortcutInfo(new PendingInstallShortcutInfo(info, widgetId, context), context);
     }
 
+    public static void queueActivityInfo(LauncherActivityInfo activity, Context context) {
+        queuePendingShortcutInfo(new PendingInstallShortcutInfo(activity, context), context);
+    }
+
     public static HashSet<ShortcutKey> getPendingShortcuts(Context context) {
         HashSet<ShortcutKey> result = new HashSet<>();
 
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index f9e6f4b..5e08c2a 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -1152,9 +1152,10 @@
         if (mLauncherCallbacks != null) {
             return mLauncherCallbacks.hasSettings();
         } else {
-            // On devices with a locked orientation, we will at least have the allow rotation
-            // setting.
-            return !getResources().getBoolean(R.bool.allow_rotation);
+            // On O and above we there is always some setting present settings (add icon to
+            // home screen or icon badging). On earlier APIs we will have the allow rotation
+            // setting, on devices with a locked orientation,
+            return Utilities.isAtLeastO() || !getResources().getBoolean(R.bool.allow_rotation);
         }
     }
 
diff --git a/src/com/android/launcher3/SessionCommitReceiver.java b/src/com/android/launcher3/SessionCommitReceiver.java
new file mode 100644
index 0000000..e8bf0a5
--- /dev/null
+++ b/src/com/android/launcher3/SessionCommitReceiver.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2008 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.launcher3;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.LauncherActivityInfo;
+import android.content.pm.PackageInstaller;
+import android.content.pm.PackageInstaller.SessionInfo;
+import android.os.Process;
+import android.os.UserHandle;
+import android.text.TextUtils;
+
+import com.android.launcher3.compat.LauncherAppsCompat;
+
+import java.util.List;
+
+/**
+ * BroadcastReceiver to handle session commit intent.
+ */
+public class SessionCommitReceiver extends BroadcastReceiver {
+
+    // Preference key for automatically adding icon to homescreen.
+    public static final String ADD_ICON_PREFERENCE_KEY = "pref_add_icon_to_home";
+
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        if (!isEnabled(context)) {
+            // User has decided to not add icons on homescreen.
+            return;
+        }
+
+        SessionInfo info = intent.getParcelableExtra(PackageInstaller.EXTRA_SESSION);
+        UserHandle user = intent.getParcelableExtra(Intent.EXTRA_USER);
+        // TODO: Verify install reason
+        if (TextUtils.isEmpty(info.getAppPackageName())) {
+            return;
+        }
+
+        if (!Process.myUserHandle().equals(user)) {
+            // Managed profile is handled using ManagedProfileHeuristic
+            return;
+        }
+
+        List<LauncherActivityInfo> activities = LauncherAppsCompat.getInstance(context)
+                .getActivityList(info.getAppPackageName(), user);
+        if (activities == null || activities.isEmpty()) {
+            // no activity found
+            return;
+        }
+        InstallShortcutReceiver.queueActivityInfo(activities.get(0), context);
+    }
+
+    public static boolean isEnabled(Context context) {
+        return Utilities.getPrefs(context).getBoolean(ADD_ICON_PREFERENCE_KEY, true);
+    }
+}
diff --git a/src/com/android/launcher3/SettingsActivity.java b/src/com/android/launcher3/SettingsActivity.java
index cedeb39..552e24a 100644
--- a/src/com/android/launcher3/SettingsActivity.java
+++ b/src/com/android/launcher3/SettingsActivity.java
@@ -25,6 +25,7 @@
 import android.preference.PreferenceFragment;
 import android.provider.Settings;
 import android.provider.Settings.System;
+import android.support.v4.os.BuildCompat;
 
 /**
  * Settings activity for Launcher. Currently implements the following setting: Allow rotation
@@ -72,6 +73,11 @@
                 mRotationLockObserver.onChange(true);
                 rotationPref.setDefaultValue(Utilities.getAllowRotationDefaultValue(getActivity()));
             }
+
+            if (!BuildCompat.isAtLeastO()) {
+                getPreferenceScreen().removePreference(
+                        findPreference(SessionCommitReceiver.ADD_ICON_PREFERENCE_KEY));
+            }
         }
 
         @Override
diff --git a/src/com/android/launcher3/util/ManagedProfileHeuristic.java b/src/com/android/launcher3/util/ManagedProfileHeuristic.java
index 189c690..85a000c 100644
--- a/src/com/android/launcher3/util/ManagedProfileHeuristic.java
+++ b/src/com/android/launcher3/util/ManagedProfileHeuristic.java
@@ -21,6 +21,7 @@
 import android.content.pm.LauncherActivityInfo;
 import android.os.Process;
 import android.os.UserHandle;
+import android.support.v4.os.BuildCompat;
 
 import com.android.launcher3.AppInfo;
 import com.android.launcher3.FolderInfo;
@@ -31,6 +32,7 @@
 import com.android.launcher3.LauncherModel;
 import com.android.launcher3.MainThreadExecutor;
 import com.android.launcher3.R;
+import com.android.launcher3.SessionCommitReceiver;
 import com.android.launcher3.ShortcutInfo;
 import com.android.launcher3.compat.UserManagerCompat;
 import com.android.launcher3.shortcuts.ShortcutInfoCompat;
@@ -68,12 +70,15 @@
     private final LauncherModel mModel;
     private final UserHandle mUser;
     private final IconCache mIconCache;
+    private final boolean mAddIconsToHomescreen;
 
     private ManagedProfileHeuristic(Context context, UserHandle user) {
         mContext = context;
         mUser = user;
         mModel = LauncherAppState.getInstance(context).getModel();
         mIconCache = LauncherAppState.getInstance(context).getIconCache();
+        mAddIconsToHomescreen =
+                !BuildCompat.isAtLeastO() || SessionCommitReceiver.isEnabled(context);
     }
 
     public void processPackageRemoved(String[] packages) {
@@ -127,7 +132,7 @@
             // Do not add shortcuts on the homescreen for the first time. This prevents the launcher
             // getting filled with the managed user apps, when it start with a fresh DB (or after
             // a very long time).
-            if (userAppsExisted && !homescreenApps.isEmpty()) {
+            if (userAppsExisted && !homescreenApps.isEmpty() && mAddIconsToHomescreen) {
                 mModel.addAndBindAddedWorkspaceItems(new ArrayList<ItemInfo>(homescreenApps));
             }
         }
@@ -147,6 +152,13 @@
             }
             // Try to get a work folder.
             String folderIdKey = USER_FOLDER_ID_PREFIX + mUserManager.getSerialNumberForUser(user);
+            if (!mAddIconsToHomescreen) {
+                if (!mPrefs.contains(folderIdKey)) {
+                    // Just mark the folder id preference to avoid new folder creation later.
+                    mPrefs.edit().putLong(folderIdKey, -1).apply();
+                }
+                return;
+            }
             if (mPrefs.contains(folderIdKey)) {
                 long folderId = mPrefs.getLong(folderIdKey, 0);
                 final FolderInfo workFolder = mModel.findFolderById(folderId);