Adding optional first run activity to Launcher

Change-Id: I146927d8a065f1cf5ef5cec41c8fb4f9ad09d25c
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index c05769c..269f53b 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -187,6 +187,9 @@
     // Type: int[]
     private static final String RUNTIME_STATE_VIEW_IDS = "launcher.view_ids";
 
+
+    static final String FIRST_RUN_ACTIVITY_DISPLAYED = "launcher.first_run_activity_displayed";
+
     private static final String TOOLBAR_ICON_METADATA_NAME = "com.android.launcher.toolbar_icon";
     private static final String TOOLBAR_SEARCH_ICON_METADATA_NAME =
             "com.android.launcher.toolbar_search_icon";
@@ -476,6 +479,7 @@
         // On large interfaces, we want the screen to auto-rotate based on the current orientation
         unlockScreenOrientation(true);
 
+        showFirstRunActivity();
         showFirstRunCling();
     }
 
@@ -498,6 +502,21 @@
     }
 
     /**
+     * To be overridden by subclasses to indicate that there is an activity to launch
+     * before showing the standard launcher experience.
+     */
+    protected boolean hasFirstRunActivity() {
+        return false;
+    }
+
+    /**
+     * To be overridden by subclasses to launch any first run activity
+     */
+    protected Intent getFirstRunActivity() {
+        return null;
+    }
+
+    /**
      * Invoked by subclasses to signal a change to the {@link #addCustomContentToLeft} value to
      * ensure the custom content page is added or removed if necessary.
      */
@@ -4206,6 +4225,10 @@
         }
     }
 
+    private boolean shouldRunFirstRunActivity() {
+        return !ActivityManager.isRunningInTestHarness();
+    }
+
     /* Cling related */
     private boolean isClingsEnabled() {
         if (DISABLE_CLINGS) {
@@ -4274,15 +4297,9 @@
             final Runnable cleanUpClingCb = new Runnable() {
                 public void run() {
                     cling.cleanup();
-                    // We should update the shared preferences on a background thread
-                    new AsyncTask<Void, Void, Void>() {
-                        public Void doInBackground(Void ... args) {
-                            SharedPreferences.Editor editor = mSharedPrefs.edit();
-                            editor.putBoolean(flag, true);
-                            editor.commit();
-                            return null;
-                        }
-                    }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void) null);
+                    SharedPreferences.Editor editor = mSharedPrefs.edit();
+                    editor.putBoolean(flag, true);
+                    editor.apply();
                     if (postAnimationCb != null) {
                         postAnimationCb.run();
                     }
@@ -4379,10 +4396,29 @@
         }
     }
 
+    public void showFirstRunActivity() {
+        if (shouldRunFirstRunActivity() && hasFirstRunActivity()
+                && !mSharedPrefs.getBoolean(FIRST_RUN_ACTIVITY_DISPLAYED, false)) {
+            Intent firstRunIntent = getFirstRunActivity();
+            if (firstRunIntent != null) {
+                startActivity(firstRunIntent);
+                markFirstRunActivityShown();
+            }
+        }
+    }
+
+    private void markFirstRunActivityShown() {
+        SharedPreferences.Editor editor = mSharedPrefs.edit();
+        editor.putBoolean(FIRST_RUN_ACTIVITY_DISPLAYED, true);
+        editor.apply();
+    }
+
     public void showFirstRunCling() {
         if (isClingsEnabled() &&
                 !mSharedPrefs.getBoolean(Cling.FIRST_RUN_CLING_DISMISSED_KEY, false) &&
                 !skipCustomClingIfNoAccounts() ) {
+
+
             // If we're not using the default workspace layout, replace workspace cling
             // with a custom workspace cling (usually specified in an overlay)
             // For now, only do this on tablets