Add a secondary launcher activity (1/2)

This secondary launcher activity with new category SECONDARY_HOME and
multiple instance supporrted could be used on sencondary display.

Bug: 118206886
Bug: 114329798
Test: Manual
Change-Id: Ibaecf8ef7614389760d0fcc547ef6d378a921583
diff --git a/Android.mk b/Android.mk
index e5a712f..28f0bc2 100644
--- a/Android.mk
+++ b/Android.mk
@@ -108,7 +108,9 @@
 LOCAL_USE_AAPT2 := true
 LOCAL_MODULE_TAGS := optional
 
-LOCAL_STATIC_ANDROID_LIBRARIES := Launcher3CommonDepsLib
+LOCAL_STATIC_ANDROID_LIBRARIES := \
+    Launcher3CommonDepsLib \
+    SecondaryDisplayLauncherLib
 LOCAL_SRC_FILES := \
     $(call all-java-files-under, src) \
     $(call all-java-files-under, src_shortcuts_overrides) \
diff --git a/SecondaryDisplayLauncher/Android.mk b/SecondaryDisplayLauncher/Android.mk
new file mode 100644
index 0000000..4fb5eba
--- /dev/null
+++ b/SecondaryDisplayLauncher/Android.mk
@@ -0,0 +1,39 @@
+#
+# Copyright (C) 2018 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_USE_AAPT2 := true
+LOCAL_AAPT2_ONLY := true
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_STATIC_ANDROID_LIBRARIES := androidx.design_design
+
+LOCAL_STATIC_JAVA_LIBRARIES := LauncherPluginLib
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
+
+LOCAL_PROGUARD_ENABLED := disabled
+
+LOCAL_SDK_VERSION := current
+LOCAL_MIN_SDK_VERSION := 21
+LOCAL_MODULE := SecondaryDisplayLauncherLib
+LOCAL_PRIVILEGED_MODULE := true
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/SecondaryDisplayLauncher/AndroidManifest.xml b/SecondaryDisplayLauncher/AndroidManifest.xml
new file mode 100644
index 0000000..ebf6b02
--- /dev/null
+++ b/SecondaryDisplayLauncher/AndroidManifest.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2018, 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.
+*/
+-->
+<manifest
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.launcher3">
+
+    <application>
+
+        <activity
+            android:name="com.android.launcher3.SecondaryDisplayLauncher"
+            android:theme="@style/SecondaryLauncherTheme"
+            android:launchMode="singleTop"
+            android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout|colorMode|density"
+            android:enabled="true">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.SECONDARY_HOME" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+        </activity>
+
+    </application>
+</manifest>
diff --git a/SecondaryDisplayLauncher/res/drawable/ic_apps.xml b/SecondaryDisplayLauncher/res/drawable/ic_apps.xml
new file mode 100644
index 0000000..db779c2
--- /dev/null
+++ b/SecondaryDisplayLauncher/res/drawable/ic_apps.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2018 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.
+  -->
+
+<vector android:height="24dp" android:tint="#FFFFFF"
+        android:viewportHeight="24.0" android:viewportWidth="24.0"
+        android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
+    <path android:fillColor="#FF000000" android:pathData="M4,8h4L8,4L4,4v4zM10,20h4v-4h-4v4zM4,20h4v-4L4,16v4zM4,14h4v-4L4,10v4zM10,14h4v-4h-4v4zM16,4v4h4L20,4h-4zM10,8h4L14,4h-4v4zM16,14h4v-4h-4v4zM16,20h4v-4h-4v4z"/>
+</vector>
diff --git a/SecondaryDisplayLauncher/res/drawable/ic_settings.xml b/SecondaryDisplayLauncher/res/drawable/ic_settings.xml
new file mode 100644
index 0000000..c269c3b
--- /dev/null
+++ b/SecondaryDisplayLauncher/res/drawable/ic_settings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2018 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.
+  -->
+
+<vector android:height="24dp" android:tint="#FFFFFF"
+        android:viewportHeight="24.0" android:viewportWidth="24.0"
+        android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
+    <path android:fillColor="#FF000000" android:pathData="M19.43,12.98c0.04,-0.32 0.07,-0.64 0.07,-0.98s-0.03,-0.66 -0.07,-0.98l2.11,-1.65c0.19,-0.15 0.24,-0.42 0.12,-0.64l-2,-3.46c-0.12,-0.22 -0.39,-0.3 -0.61,-0.22l-2.49,1c-0.52,-0.4 -1.08,-0.73 -1.69,-0.98l-0.38,-2.65C14.46,2.18 14.25,2 14,2h-4c-0.25,0 -0.46,0.18 -0.49,0.42l-0.38,2.65c-0.61,0.25 -1.17,0.59 -1.69,0.98l-2.49,-1c-0.23,-0.09 -0.49,0 -0.61,0.22l-2,3.46c-0.13,0.22 -0.07,0.49 0.12,0.64l2.11,1.65c-0.04,0.32 -0.07,0.65 -0.07,0.98s0.03,0.66 0.07,0.98l-2.11,1.65c-0.19,0.15 -0.24,0.42 -0.12,0.64l2,3.46c0.12,0.22 0.39,0.3 0.61,0.22l2.49,-1c0.52,0.4 1.08,0.73 1.69,0.98l0.38,2.65c0.03,0.24 0.24,0.42 0.49,0.42h4c0.25,0 0.46,-0.18 0.49,-0.42l0.38,-2.65c0.61,-0.25 1.17,-0.59 1.69,-0.98l2.49,1c0.23,0.09 0.49,0 0.61,-0.22l2,-3.46c0.12,-0.22 0.07,-0.49 -0.12,-0.64l-2.11,-1.65zM12,15.5c-1.93,0 -3.5,-1.57 -3.5,-3.5s1.57,-3.5 3.5,-3.5 3.5,1.57 3.5,3.5 -1.57,3.5 -3.5,3.5z"/>
+</vector>
diff --git a/SecondaryDisplayLauncher/res/layout-sw600dp/secondary_display_launcher.xml b/SecondaryDisplayLauncher/res/layout-sw600dp/secondary_display_launcher.xml
new file mode 100644
index 0000000..46f1674
--- /dev/null
+++ b/SecondaryDisplayLauncher/res/layout-sw600dp/secondary_display_launcher.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2018 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.
+  -->
+
+<androidx.coordinatorlayout.widget.CoordinatorLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/RootView"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:background="@color/launcher_bg_color"
+    android:fitsSystemWindows="true" >
+
+    <GridView
+        android:id="@+id/pinned_app_grid"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:layout_marginTop="@dimen/app_grid_margin_top"
+        android:layout_marginStart="@dimen/app_grid_margin_left"
+        android:layout_marginEnd="@dimen/app_grid_margin_right"
+        android:columnWidth="@dimen/app_list_col_width"
+        android:verticalSpacing="@dimen/app_list_horizontal_spacing"
+        android:horizontalSpacing="@dimen/app_list_vertical_spacing"
+        android:numColumns="auto_fit" />
+
+    <ImageButton
+        android:id="@+id/OptionsButton"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="bottom|start"
+        android:layout_marginStart="@dimen/options_button_margin"
+        android:layout_marginBottom="@dimen/options_button_margin"
+        android:src="@drawable/ic_settings"
+        android:background="@null"/>
+
+    <FrameLayout
+        android:layout_width="@dimen/app_picker_width"
+        android:layout_height="@dimen/app_picker_height"
+        android:layout_gravity="bottom|end"
+        android:layout_margin="@dimen/app_picker_fab_margin">
+
+        <include layout="@layout/app_picker_layout"/>
+    </FrameLayout>
+</androidx.coordinatorlayout.widget.CoordinatorLayout>
diff --git a/SecondaryDisplayLauncher/res/layout-sw720dp/secondary_display_launcher.xml b/SecondaryDisplayLauncher/res/layout-sw720dp/secondary_display_launcher.xml
new file mode 100644
index 0000000..6653a77
--- /dev/null
+++ b/SecondaryDisplayLauncher/res/layout-sw720dp/secondary_display_launcher.xml
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2018 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.
+  -->
+
+<androidx.coordinatorlayout.widget.CoordinatorLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/RootView"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:background="@color/launcher_bg_color"
+    android:fitsSystemWindows="true" >
+
+    <GridView
+        android:id="@+id/pinned_app_grid"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:layout_marginTop="@dimen/app_grid_margin_top"
+        android:layout_marginStart="@dimen/app_grid_margin_left"
+        android:layout_marginEnd="@dimen/app_grid_margin_right"
+        android:columnWidth="@dimen/app_list_col_width"
+        android:verticalSpacing="@dimen/app_list_horizontal_spacing"
+        android:horizontalSpacing="@dimen/app_list_vertical_spacing"
+        android:numColumns="auto_fit" />
+
+    <ImageButton
+        android:id="@+id/OptionsButton"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="bottom|start"
+        android:layout_marginStart="@dimen/options_button_margin"
+        android:layout_marginBottom="@dimen/options_button_margin"
+        android:src="@drawable/ic_settings"
+        android:background="@null"/>
+
+    <FrameLayout
+        android:layout_width="@dimen/app_picker_width"
+        android:layout_height="@dimen/app_picker_height"
+        android:layout_gravity="bottom|end"
+        android:layout_marginEnd="@dimen/app_picker_fab_margin"
+        android:layout_marginBottom="@dimen/app_picker_fab_margin">
+
+        <include layout="@layout/app_picker_layout"/>
+    </FrameLayout>
+</androidx.coordinatorlayout.widget.CoordinatorLayout>
diff --git a/SecondaryDisplayLauncher/res/layout/app_grid_item.xml b/SecondaryDisplayLauncher/res/layout/app_grid_item.xml
new file mode 100644
index 0000000..ee5158a
--- /dev/null
+++ b/SecondaryDisplayLauncher/res/layout/app_grid_item.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2018 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.
+  -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:gravity="center">
+
+    <ImageView
+        android:id="@+id/app_icon"
+        android:layout_width="@dimen/app_icon_width"
+        android:layout_height="@dimen/app_icon_height" />
+
+    <TextView
+        android:id="@+id/app_name"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:gravity="center"
+        android:maxLines="1" />
+</LinearLayout>
diff --git a/SecondaryDisplayLauncher/res/layout/app_picker_dialog.xml b/SecondaryDisplayLauncher/res/layout/app_picker_dialog.xml
new file mode 100644
index 0000000..563a1af
--- /dev/null
+++ b/SecondaryDisplayLauncher/res/layout/app_picker_dialog.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2018 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.
+  -->
+
+<FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <GridView
+        android:id="@+id/picker_app_grid"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:layout_marginTop="@dimen/app_grid_margin_top"
+        android:layout_marginStart="@dimen/app_grid_margin_left"
+        android:layout_marginEnd="@dimen/app_grid_margin_right"
+        android:columnWidth="@dimen/app_list_col_width"
+        android:verticalSpacing="@dimen/app_list_horizontal_spacing"
+        android:horizontalSpacing="@dimen/app_list_vertical_spacing"
+        android:numColumns="auto_fit" />
+</FrameLayout>
diff --git a/SecondaryDisplayLauncher/res/layout/app_picker_layout.xml b/SecondaryDisplayLauncher/res/layout/app_picker_layout.xml
new file mode 100644
index 0000000..fbaeac4
--- /dev/null
+++ b/SecondaryDisplayLauncher/res/layout/app_picker_layout.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2018 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.
+  -->
+
+<androidx.coordinatorlayout.widget.CoordinatorLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <android.support.design.circularreveal.cardview.CircularRevealCardView
+        android:id="@+id/FloatingSheet"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:visibility="invisible">
+
+        <GridView
+            android:id="@+id/app_grid"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:layout_marginTop="@dimen/app_grid_margin_top"
+            android:columnWidth="@dimen/app_list_col_width"
+            android:verticalSpacing="@dimen/app_list_horizontal_spacing"
+            android:horizontalSpacing="@dimen/app_list_vertical_spacing"
+            android:numColumns="auto_fit" />
+    </android.support.design.circularreveal.cardview.CircularRevealCardView>
+
+    <android.support.design.widget.FloatingActionButton
+        android:id="@+id/FloatingActionButton"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="bottom|end"
+        android:src="@drawable/ic_apps"/>
+</androidx.coordinatorlayout.widget.CoordinatorLayout>
diff --git a/SecondaryDisplayLauncher/res/layout/secondary_display_launcher.xml b/SecondaryDisplayLauncher/res/layout/secondary_display_launcher.xml
new file mode 100644
index 0000000..49cd499
--- /dev/null
+++ b/SecondaryDisplayLauncher/res/layout/secondary_display_launcher.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2018 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.
+  -->
+
+<androidx.coordinatorlayout.widget.CoordinatorLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/RootView"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:background="@color/launcher_bg_color"
+    android:fitsSystemWindows="true" >
+
+    <GridView
+        android:id="@+id/pinned_app_grid"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:layout_marginTop="@dimen/app_grid_margin_top"
+        android:layout_marginStart="@dimen/app_grid_margin_left"
+        android:layout_marginEnd="@dimen/app_grid_margin_right"
+        android:columnWidth="@dimen/app_list_col_width"
+        android:verticalSpacing="@dimen/app_list_horizontal_spacing"
+        android:horizontalSpacing="@dimen/app_list_vertical_spacing"
+        android:numColumns="auto_fit" />
+
+    <ImageButton
+        android:id="@+id/OptionsButton"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="bottom|start"
+        android:layout_marginStart="@dimen/options_button_margin"
+        android:layout_marginBottom="@dimen/options_button_margin"
+        android:src="@drawable/ic_settings"
+        android:background="@null"/>
+
+    <FrameLayout
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:layout_gravity="bottom|end"
+        android:layout_margin="@dimen/app_picker_fab_margin">
+
+        <include layout="@layout/app_picker_layout"/>
+    </FrameLayout>
+</androidx.coordinatorlayout.widget.CoordinatorLayout>
diff --git a/SecondaryDisplayLauncher/res/menu/context_menu.xml b/SecondaryDisplayLauncher/res/menu/context_menu.xml
new file mode 100644
index 0000000..6263842
--- /dev/null
+++ b/SecondaryDisplayLauncher/res/menu/context_menu.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2018 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.
+  -->
+
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:id="@+id/add_app_shortcut"
+          android:title="@string/add_app_shortcut" />
+    <item android:id="@+id/set_wallpaper"
+          android:title="@string/set_wallpaper" />
+</menu>
diff --git a/SecondaryDisplayLauncher/res/values-sw600dp/dimens.xml b/SecondaryDisplayLauncher/res/values-sw600dp/dimens.xml
new file mode 100644
index 0000000..f33a8db
--- /dev/null
+++ b/SecondaryDisplayLauncher/res/values-sw600dp/dimens.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2018 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.
+  -->
+
+<resources>
+    <dimen name="app_picker_width">400dp</dimen>
+    <dimen name="app_picker_height">400dp</dimen>
+    <dimen name="app_picker_fab_margin">60dp</dimen>
+</resources>
diff --git a/SecondaryDisplayLauncher/res/values-sw720dp/dimens.xml b/SecondaryDisplayLauncher/res/values-sw720dp/dimens.xml
new file mode 100644
index 0000000..524e52a
--- /dev/null
+++ b/SecondaryDisplayLauncher/res/values-sw720dp/dimens.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2018 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.
+  -->
+
+<resources>
+    <dimen name="app_picker_width">660dp</dimen>
+    <dimen name="app_picker_height">660dp</dimen>
+    <dimen name="app_picker_fab_margin">70dp</dimen>
+</resources>
diff --git a/SecondaryDisplayLauncher/res/values/colors.xml b/SecondaryDisplayLauncher/res/values/colors.xml
new file mode 100644
index 0000000..66b41a2
--- /dev/null
+++ b/SecondaryDisplayLauncher/res/values/colors.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/assets/res/any/colors.xml
+**
+** Copyright 2018, 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.
+*/
+-->
+<resources>
+    <color name="launcher_bg_color">#884e8391</color>
+</resources>
diff --git a/SecondaryDisplayLauncher/res/values/dimens.xml b/SecondaryDisplayLauncher/res/values/dimens.xml
new file mode 100644
index 0000000..7cca607
--- /dev/null
+++ b/SecondaryDisplayLauncher/res/values/dimens.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 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.
+-->
+
+<resources>
+    <dimen name="app_list_col_width">72dp</dimen>
+    <dimen name="app_list_horizontal_spacing">24dp</dimen>
+    <dimen name="app_list_vertical_spacing">24dp</dimen>
+    <dimen name="app_icon_width">64dp</dimen>
+    <dimen name="app_icon_height">64dp</dimen>
+    <dimen name="app_grid_margin_top">24dp</dimen>
+    <dimen name="app_grid_margin_left">8dp</dimen>
+    <dimen name="app_grid_margin_right">8dp</dimen>
+
+    <dimen name="app_picker_width">300dp</dimen>
+    <dimen name="app_picker_height">300dp</dimen>
+    <dimen name="app_picker_fab_margin">20dp</dimen>
+    <dimen name="options_button_margin">20dp</dimen>
+</resources>
diff --git a/SecondaryDisplayLauncher/res/values/strings.xml b/SecondaryDisplayLauncher/res/values/strings.xml
new file mode 100644
index 0000000..0f906c4
--- /dev/null
+++ b/SecondaryDisplayLauncher/res/values/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+* Copyright (C) 2018 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.
+*/
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name">SecondaryDisplayLauncher</string>
+    <string name="couldnt_launch">Couldn\'t launch the activity</string>
+    <string name="add_app_shortcut">Add app shortcut</string>
+    <string name="set_wallpaper">Set wallpaper</string>
+</resources>
diff --git a/SecondaryDisplayLauncher/res/values/styles.xml b/SecondaryDisplayLauncher/res/values/styles.xml
new file mode 100644
index 0000000..4bfda6a
--- /dev/null
+++ b/SecondaryDisplayLauncher/res/values/styles.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+* Copyright (C) 2018 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.
+*/
+-->
+
+<resources>
+    <style name="SecondaryLauncherTheme" parent="Theme.AppCompat.Light.NoActionBar" >
+        <item name="android:windowShowWallpaper">true</item>
+        <item name="android:windowNoTitle">true</item>
+        <item name="android:windowIsTranslucent">true</item>
+        <item name="android:windowTranslucentStatus">true</item>
+        <item name="android:windowTranslucentNavigation">true</item>
+        <item name="android:colorBackgroundCacheHint">@null</item>
+        <item name="android:windowBackground">@android:color/transparent</item>
+    </style>
+</resources>
diff --git a/SecondaryDisplayLauncher/src/com/android/launcher3/AppEntry.java b/SecondaryDisplayLauncher/src/com/android/launcher3/AppEntry.java
new file mode 100644
index 0000000..3017b81
--- /dev/null
+++ b/SecondaryDisplayLauncher/src/com/android/launcher3/AppEntry.java
@@ -0,0 +1,58 @@
+/**
+ * Copyright (c) 2018 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.ComponentName;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.graphics.drawable.Drawable;
+
+/** An entry that represents a single activity that can be launched. */
+public  class AppEntry {
+
+    private String mLabel;
+    private Drawable mIcon;
+    private Intent mLaunchIntent;
+
+    AppEntry(ResolveInfo info, PackageManager packageManager) {
+        mLabel = info.loadLabel(packageManager).toString();
+        mIcon = info.loadIcon(packageManager);
+        mLaunchIntent = new Intent();
+        mLaunchIntent.setComponent(new ComponentName(info.activityInfo.packageName,
+                info.activityInfo.name));
+    }
+
+    String getLabel() {
+        return mLabel;
+    }
+
+    Drawable getIcon() {
+        return mIcon;
+    }
+
+    Intent getLaunchIntent() { return mLaunchIntent; }
+
+    ComponentName getComponentName() {
+        return mLaunchIntent.getComponent();
+    }
+
+    @Override
+    public String toString() {
+        return mLabel;
+    }
+}
diff --git a/SecondaryDisplayLauncher/src/com/android/launcher3/AppListAdapter.java b/SecondaryDisplayLauncher/src/com/android/launcher3/AppListAdapter.java
new file mode 100644
index 0000000..aa115cb
--- /dev/null
+++ b/SecondaryDisplayLauncher/src/com/android/launcher3/AppListAdapter.java
@@ -0,0 +1,63 @@
+/**
+ * Copyright (c) 2018 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.Context;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import com.android.launcher3.R;
+
+import java.util.List;
+
+/** Adapter for available apps list. */
+public class AppListAdapter extends ArrayAdapter<AppEntry> {
+    private final LayoutInflater mInflater;
+
+    AppListAdapter(Context context) {
+        super(context, android.R.layout.simple_list_item_2);
+        mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+    }
+
+    void setData(List<AppEntry> data) {
+        clear();
+        if (data != null) {
+            addAll(data);
+        }
+    }
+
+    @Override
+    public View getView(int position, View convertView, ViewGroup parent) {
+        View view;
+
+        if (convertView == null) {
+            view = mInflater.inflate(R.layout.app_grid_item, parent, false);
+        } else {
+            view = convertView;
+        }
+
+        AppEntry item = getItem(position);
+        ((ImageView)view.findViewById(R.id.app_icon)).setImageDrawable(item.getIcon());
+        ((TextView)view.findViewById(R.id.app_name)).setText(item.getLabel());
+
+        return view;
+    }
+}
diff --git a/SecondaryDisplayLauncher/src/com/android/launcher3/AppListViewModel.java b/SecondaryDisplayLauncher/src/com/android/launcher3/AppListViewModel.java
new file mode 100644
index 0000000..914fd5e
--- /dev/null
+++ b/SecondaryDisplayLauncher/src/com/android/launcher3/AppListViewModel.java
@@ -0,0 +1,126 @@
+/**
+ * Copyright (c) 2018 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.app.Application;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.os.AsyncTask;
+
+import androidx.lifecycle.AndroidViewModel;
+import androidx.lifecycle.LiveData;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A view model that provides a list of activities that can be launched.
+ */
+public class AppListViewModel extends AndroidViewModel {
+
+    private final AppListLiveData mLiveData;
+    private final PackageIntentReceiver
+            mPackageIntentReceiver;
+
+    public AppListViewModel(Application application) {
+        super(application);
+        mLiveData = new AppListLiveData(application);
+        mPackageIntentReceiver = new PackageIntentReceiver(mLiveData, application);
+    }
+
+    public LiveData<List<AppEntry>> getAppList() {
+        return mLiveData;
+    }
+
+    protected void onCleared() {
+        getApplication().unregisterReceiver(mPackageIntentReceiver);
+    }
+}
+
+class AppListLiveData extends LiveData<List<AppEntry>> {
+
+    private final PackageManager mPackageManager;
+    private int mCurrentDataVersion;
+
+    public AppListLiveData(Context context) {
+        mPackageManager = context.getPackageManager();
+        loadData();
+    }
+
+    void loadData() {
+        final int loadDataVersion = ++mCurrentDataVersion;
+
+        new AsyncTask<Void, Void, List<AppEntry>>() {
+            @Override
+            protected List<AppEntry> doInBackground(Void... voids) {
+                Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
+                mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
+
+                List<ResolveInfo> apps = mPackageManager.queryIntentActivities(mainIntent,
+                        PackageManager.GET_META_DATA);
+
+                List<AppEntry> entries = new ArrayList<>();
+                if (apps != null) {
+                    for (ResolveInfo app : apps) {
+                        AppEntry entry = new AppEntry(app, mPackageManager);
+                        entries.add(entry);
+                    }
+                }
+                return entries;
+            }
+
+            @Override
+            protected void onPostExecute(List<AppEntry> data) {
+                if (mCurrentDataVersion == loadDataVersion) {
+                    setValue(data);
+                }
+            }
+        }.execute();
+    }
+}
+
+/**
+ * Receiver used to notify live data about app list changes.
+ */
+class PackageIntentReceiver extends BroadcastReceiver {
+
+    private final AppListLiveData mLiveData;
+
+    public PackageIntentReceiver(AppListLiveData liveData, Context context) {
+        mLiveData = liveData;
+        IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
+        filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+        filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
+        filter.addDataScheme("package");
+        context.registerReceiver(this, filter);
+
+        // Register for events related to sdcard installation.
+        IntentFilter sdFilter = new IntentFilter();
+        sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
+        sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
+        context.registerReceiver(this, sdFilter);
+    }
+
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        mLiveData.loadData();
+    }
+}
\ No newline at end of file
diff --git a/SecondaryDisplayLauncher/src/com/android/launcher3/PinnedAppListViewModel.java b/SecondaryDisplayLauncher/src/com/android/launcher3/PinnedAppListViewModel.java
new file mode 100644
index 0000000..4f92038
--- /dev/null
+++ b/SecondaryDisplayLauncher/src/com/android/launcher3/PinnedAppListViewModel.java
@@ -0,0 +1,120 @@
+/**
+ * Copyright (c) 2018 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 static com.android.launcher3.PinnedAppListViewModel.PINNED_APPS_KEY;
+
+import android.app.Application;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.os.AsyncTask;
+
+import androidx.lifecycle.AndroidViewModel;
+import androidx.lifecycle.LiveData;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * A view model that provides a list of activities that were pinned by user to always display on
+ * home screen.
+ * The pinned activities are stored in {@link SharedPreferences} to keep the sample simple :).
+ */
+public class PinnedAppListViewModel extends AndroidViewModel {
+
+    final static String PINNED_APPS_KEY = "pinned_apps";
+
+    private final PinnedAppListLiveData mLiveData;
+
+    public PinnedAppListViewModel(Application application) {
+        super(application);
+        mLiveData = new PinnedAppListLiveData(application);
+    }
+
+    public LiveData<List<AppEntry>> getPinnedAppList() {
+        return mLiveData;
+    }
+}
+
+class PinnedAppListLiveData extends LiveData<List<AppEntry>> {
+
+    private final Context mContext;
+    private final PackageManager mPackageManager;
+    // Store listener reference, so it won't be GC-ed.
+    private final SharedPreferences.OnSharedPreferenceChangeListener mChangeListener;
+    private int mCurrentDataVersion;
+
+    public PinnedAppListLiveData(Context context) {
+        mContext = context;
+        mPackageManager = context.getPackageManager();
+
+        final SharedPreferences prefs = context.getSharedPreferences(PINNED_APPS_KEY, 0);
+        mChangeListener = (preferences, key) -> {
+            loadData();
+        };
+        prefs.registerOnSharedPreferenceChangeListener(mChangeListener);
+
+        loadData();
+    }
+
+    private void loadData() {
+        final int loadDataVersion = ++mCurrentDataVersion;
+
+        new AsyncTask<Void, Void, List<AppEntry>>() {
+            @Override
+            protected List<AppEntry> doInBackground(Void... voids) {
+                List<AppEntry> entries = new ArrayList<>();
+
+                final SharedPreferences sp = mContext.getSharedPreferences(PINNED_APPS_KEY, 0);
+                final Set<String> pinnedAppsComponents = sp.getStringSet(PINNED_APPS_KEY, null);
+                if (pinnedAppsComponents == null) {
+                    return null;
+                }
+
+                for (String componentString : pinnedAppsComponents) {
+                    final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
+                    mainIntent.setComponent(ComponentName.unflattenFromString(componentString));
+                    mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
+
+                    final List<ResolveInfo> apps = mPackageManager.queryIntentActivities(mainIntent,
+                            PackageManager.GET_META_DATA);
+
+                    if (apps != null) {
+                        for (ResolveInfo app : apps) {
+                            final AppEntry entry = new AppEntry(app, mPackageManager);
+                            entries.add(entry);
+                        }
+                    }
+                }
+
+                return entries;
+            }
+
+            @Override
+            protected void onPostExecute(List<AppEntry> data) {
+                if (mCurrentDataVersion == loadDataVersion) {
+                    setValue(data);
+                }
+            }
+        }.execute();
+    }
+}
\ No newline at end of file
diff --git a/SecondaryDisplayLauncher/src/com/android/launcher3/PinnedAppPickerDialog.java b/SecondaryDisplayLauncher/src/com/android/launcher3/PinnedAppPickerDialog.java
new file mode 100644
index 0000000..02e6e4a
--- /dev/null
+++ b/SecondaryDisplayLauncher/src/com/android/launcher3/PinnedAppPickerDialog.java
@@ -0,0 +1,74 @@
+/**
+ * Copyright (c) 2018 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.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.GridView;
+
+import androidx.fragment.app.DialogFragment;
+
+import com.android.launcher3.R;
+
+/**
+ * Callback to be invoked when an app was picked.
+ */
+interface AppPickedCallback {
+    void onAppPicked(AppEntry appEntry);
+}
+
+/**
+ * Dialog that provides the user with a list of available apps to pin to the home screen.
+ */
+public class PinnedAppPickerDialog extends DialogFragment {
+
+    private AppListAdapter mAppListAdapter;
+    private AppPickedCallback mAppPickerCallback;
+
+    public PinnedAppPickerDialog() {
+    }
+
+    public static PinnedAppPickerDialog newInstance(AppListAdapter appListAdapter,
+            AppPickedCallback callback) {
+        PinnedAppPickerDialog
+                frag = new PinnedAppPickerDialog();
+        frag.mAppListAdapter = appListAdapter;
+        frag.mAppPickerCallback = callback;
+        return frag;
+    }
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+            Bundle savedInstanceState) {
+        return inflater.inflate(R.layout.app_picker_dialog, container);
+    }
+
+    @Override
+    public void onViewCreated(View view, Bundle savedInstanceState) {
+        super.onViewCreated(view, savedInstanceState);
+
+        GridView appGridView = view.findViewById(R.id.picker_app_grid);
+        appGridView.setAdapter(mAppListAdapter);
+        appGridView.setOnItemClickListener((adapterView, itemView, position, id) -> {
+            final AppEntry entry = mAppListAdapter.getItem(position);
+            mAppPickerCallback.onAppPicked(entry);
+            dismiss();
+        });
+    }
+}
\ No newline at end of file
diff --git a/SecondaryDisplayLauncher/src/com/android/launcher3/SecondaryDisplayLauncher.java b/SecondaryDisplayLauncher/src/com/android/launcher3/SecondaryDisplayLauncher.java
new file mode 100644
index 0000000..5e8b402
--- /dev/null
+++ b/SecondaryDisplayLauncher/src/com/android/launcher3/SecondaryDisplayLauncher.java
@@ -0,0 +1,217 @@
+/**
+ * Copyright (c) 2018 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 static com.android.launcher3.PinnedAppListViewModel.PINNED_APPS_KEY;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.app.AlertDialog;
+import android.app.Application;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.res.Configuration;
+import android.os.Bundle;
+import android.support.design.circularreveal.cardview.CircularRevealCardView;
+import android.support.design.widget.FloatingActionButton;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewAnimationUtils;
+import android.widget.GridView;
+import android.widget.ImageButton;
+import android.widget.PopupMenu;
+
+import androidx.fragment.app.FragmentActivity;
+import androidx.fragment.app.FragmentManager;
+import androidx.lifecycle.ViewModelProvider;
+import androidx.lifecycle.ViewModelProvider.AndroidViewModelFactory;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Secondary launcher activity. It's launch mode is configured as "singleTop" to allow showing on
+ * multiple displays and to ensure a single instance per each display.
+ */
+public class SecondaryDisplayLauncher extends FragmentActivity implements AppPickedCallback,
+        PopupMenu.OnMenuItemClickListener {
+
+    private AppListAdapter mAppListAdapter;
+    private AppListAdapter mPinnedAppListAdapter;
+    private CircularRevealCardView mAppDrawerView;
+    private FloatingActionButton mFab;
+
+    private boolean mAppDrawerShown;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.secondary_display_launcher);
+
+        mAppDrawerView = findViewById(R.id.FloatingSheet);
+        mFab = findViewById(R.id.FloatingActionButton);
+
+        mFab.setOnClickListener((View v) -> {
+            showAppDrawer(true);
+        });
+
+        final ViewModelProvider viewModelProvider = new ViewModelProvider(getViewModelStore(),
+                new AndroidViewModelFactory((Application) getApplicationContext()));
+
+        mPinnedAppListAdapter = new AppListAdapter(this);
+        final GridView pinnedAppGridView = findViewById(R.id.pinned_app_grid);
+        pinnedAppGridView.setAdapter(mPinnedAppListAdapter);
+        pinnedAppGridView.setOnItemClickListener((adapterView, view, position, id) -> {
+            final AppEntry entry = mPinnedAppListAdapter.getItem(position);
+            launch(entry.getLaunchIntent());
+        });
+        final PinnedAppListViewModel pinnedAppListViewModel =
+                viewModelProvider.get(PinnedAppListViewModel.class);
+        pinnedAppListViewModel.getPinnedAppList().observe(this, data -> {
+            mPinnedAppListAdapter.setData(data);
+        });
+
+        mAppListAdapter = new AppListAdapter(this);
+        final GridView appGridView = findViewById(R.id.app_grid);
+        appGridView.setAdapter(mAppListAdapter);
+        appGridView.setOnItemClickListener((adapterView, view, position, id) -> {
+            final AppEntry entry = mAppListAdapter.getItem(position);
+            launch(entry.getLaunchIntent());
+        });
+        final AppListViewModel appListViewModel = viewModelProvider.get(AppListViewModel.class);
+        appListViewModel.getAppList().observe(this, data -> {
+            mAppListAdapter.setData(data);
+        });
+
+        ImageButton optionsButton = findViewById(R.id.OptionsButton);
+        optionsButton.setOnClickListener((View v) -> {
+            PopupMenu popup = new PopupMenu(this,v);
+            popup.setOnMenuItemClickListener(this);
+            MenuInflater inflater = popup.getMenuInflater();
+            inflater.inflate(R.menu.context_menu, popup.getMenu());
+            popup.show();
+        });
+    }
+
+    @Override
+    public boolean onMenuItemClick(MenuItem item) {
+        // Respond to picking one of the popup menu items.
+        final int id = item.getItemId();
+        if (id == R.id.add_app_shortcut) {
+            FragmentManager fm = getSupportFragmentManager();
+            PinnedAppPickerDialog pickerDialogFragment =
+                    PinnedAppPickerDialog.newInstance(mAppListAdapter, this);
+            pickerDialogFragment.show(fm, "fragment_app_picker");
+            return true;
+        } else if (id == R.id.set_wallpaper) {
+            Intent intent = new Intent(Intent.ACTION_SET_WALLPAPER);
+            startActivity(Intent.createChooser(intent, getString(R.string.set_wallpaper)));
+            return true;
+        }
+
+        return true;
+    }
+
+    @Override
+    public void onConfigurationChanged(Configuration newConfig) {
+        super.onConfigurationChanged(newConfig);
+        showAppDrawer(false);
+    }
+
+    public void onBackPressed() {
+        // If the app drawer was shown - hide it. Otherwise, not doing anything since we don't want
+        // to close the launcher.
+        showAppDrawer(false);
+    }
+
+    public void onNewIntent(Intent intent) {
+        super.onNewIntent(intent);
+        // A new intent will bring the launcher to top. Hide the app drawer to reset the state.
+        showAppDrawer(false);
+    }
+
+    void launch(Intent launchIntent) {
+        launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        try {
+            startActivity(launchIntent);
+        } catch (Exception e) {
+            final AlertDialog.Builder builder =
+                    new AlertDialog.Builder(this, android.R.style.Theme_Material_Dialog_Alert);
+            builder.setTitle(R.string.couldnt_launch)
+                    .setMessage(e.getLocalizedMessage())
+                    .setIcon(android.R.drawable.ic_dialog_alert)
+                    .show();
+        }
+    }
+
+    /**
+     * Store the picked app to persistent pinned list and update the loader.
+     */
+    @Override
+    public void onAppPicked(AppEntry appEntry) {
+        final SharedPreferences sp = getSharedPreferences(PINNED_APPS_KEY, 0);
+        Set<String> pinnedApps = sp.getStringSet(PINNED_APPS_KEY, null);
+        if (pinnedApps == null) {
+            pinnedApps = new HashSet<String>();
+        } else {
+            // Always need to create a new object to make sure that the changes are persisted.
+            pinnedApps = new HashSet<String>(pinnedApps);
+        }
+        pinnedApps.add(appEntry.getComponentName().flattenToString());
+
+        final SharedPreferences.Editor editor = sp.edit();
+        editor.putStringSet(PINNED_APPS_KEY, pinnedApps);
+        editor.apply();
+    }
+
+    /**
+     * Show/hide app drawer card with animation.
+     */
+    private void showAppDrawer(boolean show) {
+        if (show == mAppDrawerShown) {
+            return;
+        }
+
+        final Animator animator = revealAnimator(mAppDrawerView, show);
+        if (show) {
+            mAppDrawerShown = true;
+            mAppDrawerView.setVisibility(View.VISIBLE);
+            mFab.setVisibility(View.INVISIBLE);
+        } else {
+            mAppDrawerShown = false;
+            animator.addListener(new AnimatorListenerAdapter() {
+                @Override
+                public void onAnimationEnd(Animator animation) {
+                    super.onAnimationEnd(animation);
+                    mAppDrawerView.setVisibility(View.INVISIBLE);
+                    mFab.setVisibility(View.VISIBLE);
+                }
+            });
+        }
+        animator.start();
+    }
+
+    /**
+     * Create reveal/hide animator for app list card.
+     */
+    private Animator revealAnimator(View view, boolean open) {
+        final int radius = (int) Math.hypot((double) view.getWidth(), (double) view.getHeight());
+        return ViewAnimationUtils.createCircularReveal(view, view.getRight(), view.getBottom(),
+                open ? 0 : radius, open ? radius : 0);
+    }
+}