Copying out AlertController and its relevant resources

To remove dependency of PackageInstaller package on the internal
AlertController, we are copying out all classes, style, drawables
etc from the internal/ directory into packageinstaller/, to make the
AlertController functional as is

Subsequent change will remove the resources not required by the
PackageInstaller in order to make the AlertController work.

Test: Manual UI testing.
Bug: 241139604
Change-Id: Ifdb46c37379911a40b5bcf34c13f0c7be35abcfe
diff --git a/packages/PackageInstaller/res/drawable-hdpi/popup_bottom_bright.9.png b/packages/PackageInstaller/res/drawable-hdpi/popup_bottom_bright.9.png
new file mode 100644
index 0000000..6e5fbb5
--- /dev/null
+++ b/packages/PackageInstaller/res/drawable-hdpi/popup_bottom_bright.9.png
Binary files differ
diff --git a/packages/PackageInstaller/res/drawable-hdpi/popup_bottom_dark.9.png b/packages/PackageInstaller/res/drawable-hdpi/popup_bottom_dark.9.png
new file mode 100644
index 0000000..3434b2d
--- /dev/null
+++ b/packages/PackageInstaller/res/drawable-hdpi/popup_bottom_dark.9.png
Binary files differ
diff --git a/packages/PackageInstaller/res/drawable-hdpi/popup_bottom_medium.9.png b/packages/PackageInstaller/res/drawable-hdpi/popup_bottom_medium.9.png
new file mode 100644
index 0000000..673a509
--- /dev/null
+++ b/packages/PackageInstaller/res/drawable-hdpi/popup_bottom_medium.9.png
Binary files differ
diff --git a/packages/PackageInstaller/res/drawable-hdpi/popup_center_bright.9.png b/packages/PackageInstaller/res/drawable-hdpi/popup_center_bright.9.png
new file mode 100644
index 0000000..c2a739c
--- /dev/null
+++ b/packages/PackageInstaller/res/drawable-hdpi/popup_center_bright.9.png
Binary files differ
diff --git a/packages/PackageInstaller/res/drawable-hdpi/popup_center_dark.9.png b/packages/PackageInstaller/res/drawable-hdpi/popup_center_dark.9.png
new file mode 100644
index 0000000..9d2bfb1
--- /dev/null
+++ b/packages/PackageInstaller/res/drawable-hdpi/popup_center_dark.9.png
Binary files differ
diff --git a/packages/PackageInstaller/res/drawable-hdpi/popup_center_medium.9.png b/packages/PackageInstaller/res/drawable-hdpi/popup_center_medium.9.png
new file mode 100644
index 0000000..4375bf2d
--- /dev/null
+++ b/packages/PackageInstaller/res/drawable-hdpi/popup_center_medium.9.png
Binary files differ
diff --git a/packages/PackageInstaller/res/drawable-hdpi/popup_full_bright.9.png b/packages/PackageInstaller/res/drawable-hdpi/popup_full_bright.9.png
new file mode 100644
index 0000000..6b8aa9d
--- /dev/null
+++ b/packages/PackageInstaller/res/drawable-hdpi/popup_full_bright.9.png
Binary files differ
diff --git a/packages/PackageInstaller/res/drawable-hdpi/popup_full_dark.9.png b/packages/PackageInstaller/res/drawable-hdpi/popup_full_dark.9.png
new file mode 100644
index 0000000..2884abe
--- /dev/null
+++ b/packages/PackageInstaller/res/drawable-hdpi/popup_full_dark.9.png
Binary files differ
diff --git a/packages/PackageInstaller/res/drawable-hdpi/popup_top_bright.9.png b/packages/PackageInstaller/res/drawable-hdpi/popup_top_bright.9.png
new file mode 100644
index 0000000..76c35ec
--- /dev/null
+++ b/packages/PackageInstaller/res/drawable-hdpi/popup_top_bright.9.png
Binary files differ
diff --git a/packages/PackageInstaller/res/drawable-hdpi/popup_top_dark.9.png b/packages/PackageInstaller/res/drawable-hdpi/popup_top_dark.9.png
new file mode 100644
index 0000000..f317330
--- /dev/null
+++ b/packages/PackageInstaller/res/drawable-hdpi/popup_top_dark.9.png
Binary files differ
diff --git a/packages/PackageInstaller/res/drawable/ic_dialog_info.png b/packages/PackageInstaller/res/drawable/ic_dialog_info.png
new file mode 100644
index 0000000..efee1ef
--- /dev/null
+++ b/packages/PackageInstaller/res/drawable/ic_dialog_info.png
Binary files differ
diff --git a/packages/PackageInstaller/res/layout-television/alert_dialog_button_bar_leanback.xml b/packages/PackageInstaller/res/layout-television/alert_dialog_button_bar_leanback.xml
new file mode 100644
index 0000000..3ced1db
--- /dev/null
+++ b/packages/PackageInstaller/res/layout-television/alert_dialog_button_bar_leanback.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2021 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.
+-->
+
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+            android:id="@+id/buttonPanel"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:scrollbarAlwaysDrawVerticalTrack="true"
+            android:scrollIndicators="top|bottom"
+            android:fillViewport="true"
+            style="?android:attr/buttonBarStyle">
+    <com.android.packageinstaller.ButtonBarLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layoutDirection="locale"
+        android:orientation="horizontal"
+        android:gravity="start">
+
+        <Button
+            android:id="@+id/button1"
+            style="?android:attr/buttonBarPositiveButtonStyle"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content" />
+
+        <Button
+            android:id="@+id/button2"
+            style="?android:attr/buttonBarNegativeButtonStyle"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content" />
+
+        <Space
+            android:id="@+id/spacer"
+            android:layout_width="0dp"
+            android:layout_height="0dp"
+            android:layout_weight="1"
+            android:visibility="invisible" />
+
+        <Button
+            android:id="@+id/button3"
+            style="?attr/buttonBarNeutralButtonStyle"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content" />
+
+    </com.android.packageinstaller.ButtonBarLayout>
+</ScrollView>
diff --git a/packages/PackageInstaller/res/layout-television/alert_dialog_leanback.xml b/packages/PackageInstaller/res/layout-television/alert_dialog_leanback.xml
new file mode 100644
index 0000000..0290624
--- /dev/null
+++ b/packages/PackageInstaller/res/layout-television/alert_dialog_leanback.xml
@@ -0,0 +1,84 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2021 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.
+-->
+
+<com.android.packageinstaller.AlertDialogLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/parentPanel"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:gravity="start|top"
+    android:orientation="vertical">
+
+    <include layout="@layout/alert_dialog_title_material" />
+
+    <FrameLayout
+        android:id="@+id/contentPanel"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:minHeight="48dp">
+
+        <ScrollView
+            android:id="@+id/scrollView"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:clipToPadding="false">
+
+            <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:orientation="vertical">
+
+                <Space
+                    android:id="@+id/textSpacerNoTitle"
+                    android:visibility="gone"
+                    android:layout_width="match_parent"
+                    android:layout_height="@dimen/dialog_padding_top_material" />
+
+                <TextView
+                    android:id="@+id/message"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:paddingEnd="?android:attr/dialogPreferredPadding"
+                    android:paddingStart="?android:attr/dialogPreferredPadding"
+                    style="@android:style/TextAppearance.Material.Subhead" />
+
+                <Space
+                    android:id="@+id/textSpacerNoButtons"
+                    android:visibility="gone"
+                    android:layout_width="match_parent"
+                    android:layout_height="@dimen/dialog_padding_top_material" />
+            </LinearLayout>
+        </ScrollView>
+    </FrameLayout>
+
+    <FrameLayout
+        android:id="@+id/customPanel"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:minHeight="48dp">
+
+        <FrameLayout
+            android:id="@+id/custom"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content" />
+    </FrameLayout>
+
+    <include
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        layout="@layout/alert_dialog_button_bar_leanback" />
+</com.android.packageinstaller.AlertDialogLayout>
diff --git a/packages/PackageInstaller/res/layout-television/alert_dialog_leanback_button_panel_side.xml b/packages/PackageInstaller/res/layout-television/alert_dialog_leanback_button_panel_side.xml
new file mode 100644
index 0000000..f9668dd
--- /dev/null
+++ b/packages/PackageInstaller/res/layout-television/alert_dialog_leanback_button_panel_side.xml
@@ -0,0 +1,126 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2014 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:id="@+id/parentPanel"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:orientation="horizontal">
+
+   <LinearLayout
+       android:id="@+id/leftPanel"
+       android:layout_width="0dp"
+       android:layout_weight="1"
+       android:layout_height="wrap_content"
+       android:orientation="vertical">
+
+    <LinearLayout android:id="@+id/topPanel"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="vertical">
+        <LinearLayout android:id="@+id/title_template"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="horizontal"
+            android:gravity="center_vertical|start"
+            android:paddingStart="16dip"
+            android:paddingEnd="16dip"
+            android:paddingTop="16dip"
+            android:paddingBottom="8dip">
+            <ImageView android:id="@+id/icon"
+                android:layout_width="32dip"
+                android:layout_height="32dip"
+                android:layout_marginEnd="8dip"
+                android:scaleType="fitCenter"
+                android:src="@null" />
+            <com.android.packageinstaller.DialogTitle android:id="@+id/alertTitle"
+                style="?android:attr/windowTitleStyle"
+                android:singleLine="true"
+                android:ellipsize="end"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:textAlignment="viewStart" />
+        </LinearLayout>
+        <!-- If the client uses a customTitle, it will be added here. -->
+    </LinearLayout>
+
+    <LinearLayout android:id="@+id/contentPanel"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_weight="1"
+        android:orientation="vertical"
+        android:minHeight="64dp">
+        <ScrollView android:id="@+id/scrollView"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:clipToPadding="false">
+            <TextView android:id="@+id/message"
+                style="?android:attr/textAppearanceMedium"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:paddingStart="16dip"
+                android:paddingEnd="16dip"
+                android:paddingTop="16dip"
+                android:paddingBottom="16dip" />
+        </ScrollView>
+    </LinearLayout>
+
+    <FrameLayout android:id="@+id/customPanel"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_weight="1"
+        android:minHeight="64dp">
+        <FrameLayout android:id="@+id/custom"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content" />
+    </FrameLayout>
+    </LinearLayout>
+
+    <LinearLayout android:id="@+id/buttonPanel"
+        style="?attr/buttonBarStyle"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center_vertical"
+        android:orientation="vertical"
+        android:gravity="end">
+        <LinearLayout
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layoutDirection="locale"
+            android:orientation="vertical">
+            <Button android:id="@+id/button3"
+                style="?attr/buttonBarNeutralButtonStyle"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:maxLines="2"
+                android:minHeight="@dimen/alert_dialog_button_bar_height" />
+            <Button android:id="@+id/button2"
+                style="?attr/buttonBarNegativeButtonStyle"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:maxLines="2"
+                android:minHeight="@dimen/alert_dialog_button_bar_height" />
+            <Button android:id="@+id/button1"
+                style="?attr/buttonBarPositiveButtonStyle"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:maxLines="2"
+                android:minHeight="@dimen/alert_dialog_button_bar_height" />
+        </LinearLayout>
+     </LinearLayout>
+</LinearLayout>
diff --git a/packages/PackageInstaller/res/layout/alert_dialog.xml b/packages/PackageInstaller/res/layout/alert_dialog.xml
new file mode 100644
index 0000000..16b6d39
--- /dev/null
+++ b/packages/PackageInstaller/res/layout/alert_dialog.xml
@@ -0,0 +1,152 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/res/layout/alert_dialog.xml
+**
+** Copyright 2006, 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:id="@+id/parentPanel"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:orientation="vertical"
+    android:paddingTop="9dip"
+    android:paddingBottom="3dip"
+    android:paddingStart="3dip"
+    android:paddingEnd="1dip">
+
+    <LinearLayout android:id="@+id/topPanel"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:minHeight="54dip"
+        android:orientation="vertical">
+        <LinearLayout android:id="@+id/title_template"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="horizontal"
+            android:gravity="center_vertical"
+            android:layout_marginTop="6dip"
+            android:layout_marginBottom="9dip"
+            android:layout_marginStart="10dip"
+            android:layout_marginEnd="10dip">
+            <ImageView android:id="@+id/icon"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="top"
+                android:paddingTop="6dip"
+                android:paddingEnd="10dip"
+                android:src="@drawable/ic_dialog_info" />
+            <com.android.packageinstaller.DialogTitle android:id="@+id/alertTitle"
+                style="?android:attr/textAppearanceLarge"
+                android:singleLine="true"
+                android:ellipsize="end"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:textAlignment="viewStart" />
+        </LinearLayout>
+        <ImageView android:id="@+id/titleDivider"
+            android:layout_width="match_parent"
+            android:layout_height="1dip"
+            android:visibility="gone"
+            android:scaleType="fitXY"
+            android:gravity="fill_horizontal"
+            android:src="@android:drawable/divider_horizontal_dark" />
+        <!-- If the client uses a customTitle, it will be added here. -->
+    </LinearLayout>
+
+    <LinearLayout android:id="@+id/contentPanel"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_weight="1"
+        android:orientation="vertical">
+        <ScrollView android:id="@+id/scrollView"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:paddingTop="2dip"
+            android:paddingBottom="12dip"
+            android:paddingStart="14dip"
+            android:paddingEnd="10dip"
+            android:overScrollMode="ifContentScrolls">
+            <TextView android:id="@+id/message"
+                style="?android:attr/textAppearanceMedium"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:padding="5dip" />
+        </ScrollView>
+    </LinearLayout>
+
+    <FrameLayout android:id="@+id/customPanel"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_weight="1">
+        <FrameLayout android:id="@+id/custom"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:paddingTop="5dip"
+            android:paddingBottom="5dip" />
+    </FrameLayout>
+
+    <LinearLayout android:id="@+id/buttonPanel"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:minHeight="54dip"
+        android:orientation="vertical" >
+        <LinearLayout
+            style="?android:attr/buttonBarStyle"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="horizontal"
+            android:paddingTop="4dip"
+            android:paddingStart="2dip"
+            android:paddingEnd="2dip"
+            android:measureWithLargestChild="true">
+            <LinearLayout android:id="@+id/leftSpacer"
+                android:layout_weight="0.25"
+                android:layout_width="0dip"
+                android:layout_height="wrap_content"
+                android:orientation="horizontal"
+                android:visibility="gone" />
+            <Button android:id="@+id/button1"
+                android:layout_width="0dip"
+                android:layout_gravity="start"
+                android:layout_weight="1"
+                style="?android:attr/buttonBarPositiveButtonStyle"
+                android:maxLines="2"
+                android:layout_height="wrap_content" />
+            <Button android:id="@+id/button3"
+                android:layout_width="0dip"
+                android:layout_gravity="center_horizontal"
+                android:layout_weight="1"
+                style="?android:attr/buttonBarNeutralButtonStyle"
+                android:maxLines="2"
+                android:layout_height="wrap_content" />
+            <Button android:id="@+id/button2"
+                android:layout_width="0dip"
+                android:layout_gravity="end"
+                android:layout_weight="1"
+                style="?android:attr/buttonBarNegativeButtonStyle"
+                android:maxLines="2"
+                android:layout_height="wrap_content" />
+            <LinearLayout android:id="@+id/rightSpacer"
+                android:layout_width="0dip"
+                android:layout_weight="0.25"
+                android:layout_height="wrap_content"
+                android:orientation="horizontal"
+                android:visibility="gone" />
+        </LinearLayout>
+     </LinearLayout>
+</LinearLayout>
diff --git a/packages/PackageInstaller/res/layout/alert_dialog_button_bar_material.xml b/packages/PackageInstaller/res/layout/alert_dialog_button_bar_material.xml
new file mode 100644
index 0000000..e4977e7
--- /dev/null
+++ b/packages/PackageInstaller/res/layout/alert_dialog_button_bar_material.xml
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2014 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.
+-->
+
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+            android:id="@+id/buttonPanel"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:scrollbarAlwaysDrawVerticalTrack="true"
+            android:scrollIndicators="top|bottom"
+            android:fillViewport="true"
+            style="?android:attr/buttonBarStyle">
+    <com.android.packageinstaller.ButtonBarLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layoutDirection="locale"
+        android:orientation="horizontal"
+        android:paddingStart="12dp"
+        android:paddingEnd="12dp"
+        android:paddingTop="4dp"
+        android:paddingBottom="4dp"
+        android:gravity="bottom">
+
+        <Button
+            android:id="@+id/button3"
+            style="?android:attr/buttonBarNeutralButtonStyle"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content" />
+
+        <Space
+            android:id="@+id/spacer"
+            android:layout_width="0dp"
+            android:layout_height="0dp"
+            android:layout_weight="1"
+            android:visibility="invisible" />
+
+        <Button
+            android:id="@+id/button2"
+            style="?android:attr/buttonBarNegativeButtonStyle"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content" />
+
+        <Button
+            android:id="@+id/button1"
+            style="?android:attr/buttonBarPositiveButtonStyle"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content" />
+    </com.android.packageinstaller.ButtonBarLayout>
+</ScrollView>
diff --git a/packages/PackageInstaller/res/layout/alert_dialog_holo.xml b/packages/PackageInstaller/res/layout/alert_dialog_holo.xml
new file mode 100644
index 0000000..b5b3927
--- /dev/null
+++ b/packages/PackageInstaller/res/layout/alert_dialog_holo.xml
@@ -0,0 +1,142 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2010, 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:id="@+id/parentPanel"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:layout_marginStart="8dip"
+    android:layout_marginEnd="8dip"
+    android:orientation="vertical">
+
+    <LinearLayout android:id="@+id/topPanel"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="vertical">
+        <View android:id="@+id/titleDividerTop"
+            android:layout_width="match_parent"
+            android:layout_height="2dip"
+            android:visibility="gone"
+            android:background="@android:color/holo_blue_light" />
+        <LinearLayout android:id="@+id/title_template"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="horizontal"
+            android:gravity="center_vertical|start"
+            android:minHeight="@dimen/alert_dialog_title_height"
+            android:layout_marginStart="16dip"
+            android:layout_marginEnd="16dip">
+            <ImageView android:id="@+id/icon"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:paddingEnd="8dip"
+                android:src="@null" />
+            <com.android.packageinstaller.DialogTitle android:id="@+id/alertTitle"
+                style="?android:attr/windowTitleStyle"
+                android:singleLine="true"
+                android:ellipsize="end"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:textAlignment="viewStart" />
+        </LinearLayout>
+        <View android:id="@+id/titleDivider"
+            android:layout_width="match_parent"
+            android:layout_height="2dip"
+            android:visibility="gone"
+            android:background="@android:color/holo_blue_light" />
+        <!-- If the client uses a customTitle, it will be added here. -->
+    </LinearLayout>
+
+    <LinearLayout android:id="@+id/contentPanel"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_weight="1"
+        android:orientation="vertical"
+        android:minHeight="64dp">
+        <ScrollView android:id="@+id/scrollView"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:clipToPadding="false">
+            <TextView android:id="@+id/message"
+                style="?android:attr/textAppearanceMedium"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:paddingStart="16dip"
+                android:paddingEnd="16dip"
+                android:paddingTop="8dip"
+                android:paddingBottom="8dip"/>
+        </ScrollView>
+    </LinearLayout>
+
+    <FrameLayout android:id="@+id/customPanel"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_weight="1"
+        android:minHeight="64dp">
+        <FrameLayout android:id="@+id/custom"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content" />
+    </FrameLayout>
+
+    <LinearLayout android:id="@+id/buttonPanel"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:minHeight="@dimen/alert_dialog_button_bar_height"
+        android:orientation="vertical"
+        android:divider="?android:attr/dividerHorizontal"
+        android:showDividers="beginning"
+        android:dividerPadding="0dip">
+        <LinearLayout
+            style="?android:attr/buttonBarStyle"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="horizontal"
+            android:layoutDirection="locale"
+            android:measureWithLargestChild="true">
+            <Button android:id="@+id/button2"
+                android:layout_width="wrap_content"
+                android:layout_gravity="start"
+                android:layout_weight="1"
+                android:maxLines="2"
+                style="?android:attr/buttonBarButtonStyle"
+                android:textSize="14sp"
+                android:minHeight="@dimen/alert_dialog_button_bar_height"
+                android:layout_height="wrap_content" />
+            <Button android:id="@+id/button3"
+                android:layout_width="wrap_content"
+                android:layout_gravity="center_horizontal"
+                android:layout_weight="1"
+                android:maxLines="2"
+                style="?android:attr/buttonBarButtonStyle"
+                android:textSize="14sp"
+                android:minHeight="@dimen/alert_dialog_button_bar_height"
+                android:layout_height="wrap_content" />
+            <Button android:id="@+id/button1"
+                android:layout_width="wrap_content"
+                android:layout_gravity="end"
+                android:layout_weight="1"
+                android:maxLines="2"
+                android:minHeight="@dimen/alert_dialog_button_bar_height"
+                style="?android:attr/buttonBarButtonStyle"
+                android:textSize="14sp"
+                android:layout_height="wrap_content" />
+        </LinearLayout>
+     </LinearLayout>
+</LinearLayout>
diff --git a/packages/PackageInstaller/res/layout/alert_dialog_material.xml b/packages/PackageInstaller/res/layout/alert_dialog_material.xml
new file mode 100644
index 0000000..10e9149
--- /dev/null
+++ b/packages/PackageInstaller/res/layout/alert_dialog_material.xml
@@ -0,0 +1,84 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2014 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.
+-->
+
+<com.android.packageinstaller.AlertDialogLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/parentPanel"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:gravity="start|top"
+    android:orientation="vertical">
+
+    <include layout="@layout/alert_dialog_title_material" />
+
+    <FrameLayout
+        android:id="@+id/contentPanel"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:minHeight="48dp">
+
+        <ScrollView
+            android:id="@+id/scrollView"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:clipToPadding="false">
+
+            <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:orientation="vertical">
+
+                <Space
+                    android:id="@+id/textSpacerNoTitle"
+                    android:visibility="gone"
+                    android:layout_width="match_parent"
+                    android:layout_height="@dimen/dialog_padding_top_material" />
+
+                <TextView
+                    android:id="@+id/message"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:paddingEnd="?android:attr/dialogPreferredPadding"
+                    android:paddingStart="?android:attr/dialogPreferredPadding"
+                    style="@android:style/TextAppearance.Material.Subhead" />
+
+                <Space
+                    android:id="@+id/textSpacerNoButtons"
+                    android:visibility="gone"
+                    android:layout_width="match_parent"
+                    android:layout_height="@dimen/dialog_padding_top_material" />
+            </LinearLayout>
+        </ScrollView>
+    </FrameLayout>
+
+    <FrameLayout
+        android:id="@+id/customPanel"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:minHeight="48dp">
+
+        <FrameLayout
+            android:id="@+id/custom"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content" />
+    </FrameLayout>
+
+    <include
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        layout="@layout/alert_dialog_button_bar_material" />
+</com.android.packageinstaller.AlertDialogLayout>
diff --git a/packages/PackageInstaller/res/layout/alert_dialog_progress.xml b/packages/PackageInstaller/res/layout/alert_dialog_progress.xml
new file mode 100644
index 0000000..fe06b65
--- /dev/null
+++ b/packages/PackageInstaller/res/layout/alert_dialog_progress.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 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.
+-->
+
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="wrap_content" android:layout_height="match_parent">
+        <ProgressBar android:id="@+id/progress"
+            style="?android:attr/progressBarStyleHorizontal"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="12dip"
+            android:layout_marginBottom="1dip"
+            android:layout_marginStart="10dip"
+            android:layout_marginEnd="10dip"
+            android:layout_centerHorizontal="true" />
+        <TextView
+            android:id="@+id/progress_percent"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:paddingBottom="12dip"
+            android:layout_marginStart="10dip"
+            android:layout_marginEnd="10dip"
+            android:layout_alignParentStart="true"
+            android:layout_below="@id/progress"
+        />
+        <TextView
+            android:id="@+id/progress_number"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:paddingBottom="12dip"
+            android:layout_marginStart="10dip"
+            android:layout_marginEnd="10dip"
+            android:layout_alignParentEnd="true"
+            android:layout_below="@id/progress"
+        />
+</RelativeLayout>
diff --git a/packages/PackageInstaller/res/layout/alert_dialog_progress_material.xml b/packages/PackageInstaller/res/layout/alert_dialog_progress_material.xml
new file mode 100644
index 0000000..fb98259
--- /dev/null
+++ b/packages/PackageInstaller/res/layout/alert_dialog_progress_material.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2014 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.
+-->
+
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="wrap_content"
+    android:layout_height="match_parent"
+    android:paddingStart="?attr/dialogPreferredPadding"
+    android:paddingTop="@dimen/dialog_padding_top_material"
+    android:paddingEnd="?attr/dialogPreferredPadding"
+    android:paddingBottom="@dimen/dialog_padding_top_material">
+    <ProgressBar
+        android:id="@+id/progress"
+        style="?android:attr/progressBarStyleHorizontal"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_centerHorizontal="true" />
+    <TextView
+        android:id="@+id/progress_percent"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignParentStart="true"
+        android:layout_below="@id/progress" />
+    <TextView
+        android:id="@+id/progress_number"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignParentEnd="true"
+        android:layout_below="@id/progress" />
+</RelativeLayout>
diff --git a/packages/PackageInstaller/res/layout/alert_dialog_title_material.xml b/packages/PackageInstaller/res/layout/alert_dialog_title_material.xml
new file mode 100644
index 0000000..45d9bb6
--- /dev/null
+++ b/packages/PackageInstaller/res/layout/alert_dialog_title_material.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2015 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:id="@+id/topPanel"
+              android:layout_width="match_parent"
+              android:layout_height="wrap_content"
+              android:orientation="vertical">
+
+    <!-- If the client uses a customTitle, it will be added here. -->
+
+    <LinearLayout
+        android:id="@+id/title_template"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal"
+        android:gravity="center_vertical|start"
+        android:paddingStart="?android:attr/dialogPreferredPadding"
+        android:paddingEnd="?android:attr/dialogPreferredPadding"
+        android:paddingTop="@dimen/dialog_padding_top_material">
+
+        <ImageView
+            android:id="@+id/icon"
+            android:layout_width="32dip"
+            android:layout_height="32dip"
+            android:layout_marginEnd="8dip"
+            android:scaleType="fitCenter"
+            android:src="@null" />
+
+        <com.android.packageinstaller.DialogTitle
+            android:id="@+id/alertTitle"
+            android:singleLine="true"
+            android:ellipsize="end"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:textAlignment="viewStart"
+            style="?android:attr/windowTitleStyle" />
+    </LinearLayout>
+
+    <Space
+        android:id="@+id/titleDividerNoCustom"
+        android:visibility="gone"
+        android:layout_width="match_parent"
+        android:layout_height="@dimen/dialog_title_divider_material" />
+</LinearLayout>
diff --git a/packages/PackageInstaller/res/layout/progress_dialog.xml b/packages/PackageInstaller/res/layout/progress_dialog.xml
new file mode 100644
index 0000000..0d3cd4a
--- /dev/null
+++ b/packages/PackageInstaller/res/layout/progress_dialog.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/res/layout/alert_dialog.xml
+**
+** Copyright 2006, 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="wrap_content">
+
+    <LinearLayout android:id="@+id/body"
+        android:orientation="horizontal"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:baselineAligned="false"
+        android:paddingStart="8dip"
+        android:paddingTop="10dip"
+        android:paddingEnd="8dip"
+        android:paddingBottom="10dip">
+
+        <ProgressBar android:id="@android:id/progress"
+            style="?android:attr/progressBarStyle"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:max="10000"
+            android:layout_marginEnd="12dip" />
+
+        <TextView android:id="@+id/message"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center_vertical" />
+    </LinearLayout>
+</FrameLayout>
diff --git a/packages/PackageInstaller/res/layout/progress_dialog_material.xml b/packages/PackageInstaller/res/layout/progress_dialog_material.xml
new file mode 100644
index 0000000..2417965
--- /dev/null
+++ b/packages/PackageInstaller/res/layout/progress_dialog_material.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2014 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="wrap_content">
+
+    <LinearLayout
+        android:id="@+id/body"
+        android:orientation="horizontal"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:baselineAligned="false"
+        android:paddingStart="?attr/dialogPreferredPadding"
+        android:paddingTop="@dimen/dialog_padding_top_material"
+        android:paddingEnd="?attr/dialogPreferredPadding"
+        android:paddingBottom="@dimen/dialog_padding_top_material">
+
+        <ProgressBar
+            android:id="@id/progress"
+            style="?android:attr/progressBarStyle"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:max="10000"
+            android:layout_marginEnd="?attr/dialogPreferredPadding" />
+
+        <TextView
+            android:id="@+id/message"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center_vertical" />
+    </LinearLayout>
+</FrameLayout>
diff --git a/packages/PackageInstaller/res/layout/select_dialog.xml b/packages/PackageInstaller/res/layout/select_dialog.xml
new file mode 100644
index 0000000..e2d0739
--- /dev/null
+++ b/packages/PackageInstaller/res/layout/select_dialog.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/res/layout/select_dialog.xml
+**
+** Copyright 2006, 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.
+*/
+-->
+
+<!--
+    This layout file is used by the AlertDialog when displaying a list of items.
+    This layout file is inflated and used as the ListView to display the items.
+    Assign an ID so its state will be saved/restored.
+-->
+<view class="com.android.packageinstaller.AlertController$RecycleListView"
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/select_dialog_listview"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:layout_marginTop="5px"
+    android:cacheColorHint="@null"
+    android:divider="?android:attr/listDividerAlertDialog"
+    android:scrollbars="vertical"
+    android:overScrollMode="ifContentScrolls"
+    android:textAlignment="viewStart" />
diff --git a/packages/PackageInstaller/res/layout/select_dialog_item.xml b/packages/PackageInstaller/res/layout/select_dialog_item.xml
new file mode 100644
index 0000000..835c433
--- /dev/null
+++ b/packages/PackageInstaller/res/layout/select_dialog_item.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/res/layout/select_dialog_item.xml
+**
+** Copyright 2006, 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.
+*/
+-->
+
+<!--
+    This layout file is used by the AlertDialog when displaying a list of items.
+    This layout file is inflated and used as the TextView to display individual
+    items.
+-->
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@android:id/text1"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:minHeight="?android:attr/listPreferredItemHeight"
+    android:textAppearance="?android:attr/textAppearanceLarge"
+    android:textColor="?android:attr/textColorAlertDialogListItem"
+    android:gravity="center_vertical"
+    android:paddingStart="14dip"
+    android:paddingEnd="15dip"
+    android:ellipsize="marquee"
+/>
diff --git a/packages/PackageInstaller/res/layout/select_dialog_item_material.xml b/packages/PackageInstaller/res/layout/select_dialog_item_material.xml
new file mode 100644
index 0000000..b45edc6
--- /dev/null
+++ b/packages/PackageInstaller/res/layout/select_dialog_item_material.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2014 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.
+-->
+
+<!--
+    This layout file is used by the AlertDialog when displaying a list of items.
+    This layout file is inflated and used as the TextView to display individual
+    items.
+-->
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@android:id/text1"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:minHeight="?android:attr/listPreferredItemHeightSmall"
+    android:textAppearance="?android:attr/textAppearanceListItemSmall"
+    android:textColor="?android:attr/textColorAlertDialogListItem"
+    android:gravity="center_vertical"
+    android:paddingStart="?attr/listPreferredItemPaddingStart"
+    android:paddingEnd="?attr/listPreferredItemPaddingEnd"
+    android:ellipsize="marquee" />
diff --git a/packages/PackageInstaller/res/layout/select_dialog_material.xml b/packages/PackageInstaller/res/layout/select_dialog_material.xml
new file mode 100644
index 0000000..125b9b8
--- /dev/null
+++ b/packages/PackageInstaller/res/layout/select_dialog_material.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2014 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.
+-->
+
+<!--
+    This layout file is used by the AlertDialog when displaying a list of items.
+    This layout file is inflated and used as the ListView to display the items.
+    Assign an ID so its state will be saved/restored.
+-->
+<view class="com.android.packageinstaller.AlertController$RecycleListView"
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@id/select_dialog_listview"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:cacheColorHint="@null"
+    android:divider="?attr/listDividerAlertDialog"
+    android:scrollbars="vertical"
+    android:overScrollMode="ifContentScrolls"
+    android:textAlignment="viewStart"
+    android:clipToPadding="false"/>
+    <!--android:paddingBottomNoButtons="@dimen/dialog_list_padding_bottom_no_buttons"
+    android:paddingTopNoTitle="@dimen/dialog_list_padding_top_no_title"/>-->
diff --git a/packages/PackageInstaller/res/layout/select_dialog_multichoice.xml b/packages/PackageInstaller/res/layout/select_dialog_multichoice.xml
new file mode 100644
index 0000000..2dd83a3
--- /dev/null
+++ b/packages/PackageInstaller/res/layout/select_dialog_multichoice.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<CheckedTextView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@android:id/text1"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:minHeight="?android:attr/listPreferredItemHeight"
+    android:textAppearance="?android:attr/textAppearanceLarge"
+    android:textColor="?android:attr/textColorAlertDialogListItem"
+    android:gravity="center_vertical"
+    android:paddingStart="12dip"
+    android:paddingEnd="7dip"
+    android:checkMark="?android:attr/listChoiceIndicatorMultiple"
+    android:ellipsize="marquee"
+/>
+
diff --git a/packages/PackageInstaller/res/layout/select_dialog_multichoice_material.xml b/packages/PackageInstaller/res/layout/select_dialog_multichoice_material.xml
new file mode 100644
index 0000000..52f709e
--- /dev/null
+++ b/packages/PackageInstaller/res/layout/select_dialog_multichoice_material.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2014 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.
+-->
+
+<CheckedTextView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@android:id/text1"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:minHeight="?attr/listPreferredItemHeightSmall"
+    android:textAppearance="?android:attr/textAppearanceMedium"
+    android:textColor="?attr/textColorAlertDialogListItem"
+    android:gravity="center_vertical"
+    android:paddingStart="@dimen/select_dialog_padding_start_material"
+    android:paddingEnd="?attr/dialogPreferredPadding"
+    android:drawableStart="?android:attr/listChoiceIndicatorMultiple"
+    android:drawablePadding="@dimen/select_dialog_drawable_padding_start_material"
+    android:ellipsize="marquee" />
diff --git a/packages/PackageInstaller/res/layout/select_dialog_singlechoice.xml b/packages/PackageInstaller/res/layout/select_dialog_singlechoice.xml
new file mode 100644
index 0000000..1e18b44
--- /dev/null
+++ b/packages/PackageInstaller/res/layout/select_dialog_singlechoice.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<CheckedTextView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@android:id/text1"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:minHeight="?android:attr/listPreferredItemHeight"
+    android:textAppearance="?android:attr/textAppearanceLarge"
+    android:textColor="?android:attr/textColorAlertDialogListItem"
+    android:gravity="center_vertical"
+    android:paddingStart="12dip"
+    android:paddingEnd="7dip"
+    android:checkMark="?android:attr/listChoiceIndicatorSingle"
+    android:ellipsize="marquee"
+/>
diff --git a/packages/PackageInstaller/res/layout/select_dialog_singlechoice_material.xml b/packages/PackageInstaller/res/layout/select_dialog_singlechoice_material.xml
new file mode 100644
index 0000000..8345b18
--- /dev/null
+++ b/packages/PackageInstaller/res/layout/select_dialog_singlechoice_material.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2014 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.
+-->
+
+<CheckedTextView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@android:id/text1"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:minHeight="?attr/listPreferredItemHeightSmall"
+    android:textAppearance="?android:attr/textAppearanceMedium"
+    android:textColor="?attr/textColorAlertDialogListItem"
+    android:gravity="center_vertical"
+    android:paddingStart="@dimen/select_dialog_padding_start_material"
+    android:paddingEnd="?attr/dialogPreferredPadding"
+    android:drawableStart="?android:attr/listChoiceIndicatorSingle"
+    android:drawablePadding="@dimen/select_dialog_drawable_padding_start_material"
+    android:ellipsize="marquee" />
diff --git a/packages/PackageInstaller/res/values-night/themes.xml b/packages/PackageInstaller/res/values-night/themes.xml
index 483b0cf..18320f7 100644
--- a/packages/PackageInstaller/res/values-night/themes.xml
+++ b/packages/PackageInstaller/res/values-night/themes.xml
@@ -18,6 +18,8 @@
 <resources>
 
     <style name="Theme.AlertDialogActivity"
-            parent="@android:style/Theme.DeviceDefault.Dialog.Alert" />
+        parent="@android:style/Theme.DeviceDefault.Dialog.Alert">
+        <item name="alertDialogStyle">@style/AlertDialog</item>
+    </style>
 
 </resources>
diff --git a/packages/PackageInstaller/res/values-television/styles.xml b/packages/PackageInstaller/res/values-television/styles.xml
new file mode 100644
index 0000000..936fff0
--- /dev/null
+++ b/packages/PackageInstaller/res/values-television/styles.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+  ~ Copyright (C) 2022 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="AlertDialog.Leanback" parent="@style/AlertDialog">
+        <item name="buttonPanelSideLayout">@layout/alert_dialog_leanback_button_panel_side</item>
+        <item name="layout">@layout/alert_dialog_leanback</item>
+    </style>
+</resources>
\ No newline at end of file
diff --git a/packages/PackageInstaller/res/values-television/themes.xml b/packages/PackageInstaller/res/values-television/themes.xml
index 5ae4957..1cc6933 100644
--- a/packages/PackageInstaller/res/values-television/themes.xml
+++ b/packages/PackageInstaller/res/values-television/themes.xml
@@ -17,15 +17,20 @@
 
 <resources>
 
-    <style name="Theme.AlertDialogActivity.NoAnimation">
+    <style name="Theme.AlertDialogActivity.NoAnimation"
+           parent="@style/Theme.AlertDialogActivity.NoActionBar">
         <item name="android:windowAnimationStyle">@null</item>
     </style>
 
     <style name="Theme.AlertDialogActivity"
-           parent="@android:style/Theme.DeviceDefault.Light.Dialog.Alert" />
+        parent="@android:style/Theme.DeviceDefault.Light.Dialog.Alert">
+        <item name="alertDialogStyle">@style/AlertDialog.Leanback</item>
+    </style>
 
     <style name="Theme.AlertDialogActivity.NoActionBar"
-           parent="@android:style/Theme.DeviceDefault.Light.NoActionBar">
+        parent="@android:style/Theme.Material.Light.NoActionBar">
+        <item name="android:windowActionBar">false</item>
+        <item name="android:windowNoTitle">true</item>
     </style>
 
 </resources>
diff --git a/packages/PackageInstaller/res/values/attrs.xml b/packages/PackageInstaller/res/values/attrs.xml
index e220f4c..e3070e2 100644
--- a/packages/PackageInstaller/res/values/attrs.xml
+++ b/packages/PackageInstaller/res/values/attrs.xml
@@ -32,4 +32,49 @@
         <attr name="circle_radius_pressed_percent" format="fraction" />
     </declare-styleable>
     <!-- END: Ported from WearableSupport -->
+    <declare-styleable name="Theme">
+        <attr name="alertDialogCenterButtons" format="boolean" />
+    </declare-styleable>
+    <declare-styleable name="AlertDialog">
+        <attr name="fullDark" format="reference|color" />
+        <attr name="topDark" format="reference|color" />
+        <attr name="centerDark" format="reference|color" />
+        <attr name="bottomDark" format="reference|color" />
+        <attr name="fullBright" format="reference|color" />
+        <attr name="topBright" format="reference|color" />
+        <attr name="centerBright" format="reference|color" />
+        <attr name="bottomBright" format="reference|color" />
+        <attr name="bottomMedium" format="reference|color" />
+        <attr name="centerMedium" format="reference|color" />
+        <attr name="layout" format="reference" />
+        <attr name="buttonPanelSideLayout" format="reference" />
+        <attr name="listLayout" format="reference" />
+        <attr name="multiChoiceItemLayout" format="reference" />
+        <attr name="singleChoiceItemLayout" format="reference" />
+        <attr name="listItemLayout" format="reference" />
+        <attr name="progressLayout" format="reference" />
+        <attr name="horizontalProgressLayout" format="reference" />
+        <!-- @hide Not ready for public use. -->
+        <attr name="showTitle" format="boolean" />
+        <!-- Whether fullDark, etc. should use default values if null. -->
+        <attr name="needsDefaultBackgrounds" format="boolean" />
+        <!-- Workaround until we replace AlertController with custom layout. -->
+        <attr name="controllerType">
+            <!-- The default controller. -->
+            <enum name="normal" value="0" />
+            <!-- Controller for micro specific layout. -->
+            <enum name="micro" value="1" />
+        </attr>
+        <!-- Offset when scrolling to a selection. -->
+        <attr name="selectionScrollOffset" format="dimension" />
+    </declare-styleable>
+    <declare-styleable name="ButtonBarLayout">
+        <!-- Whether to automatically stack the buttons when there is not
+             enough space to lay them out side-by-side. -->
+        <attr name="allowStacking" format="boolean" />
+    </declare-styleable>
+    <declare-styleable name="TextAppearance">
+        <!-- Size of the text. Recommended dimension type for text is "sp" for scaled-pixels (example: 15sp). -->
+        <attr name="textSize" format="dimension" />
+    </declare-styleable>
 </resources>
diff --git a/packages/PackageInstaller/res/values/dimens.xml b/packages/PackageInstaller/res/values/dimens.xml
index 112723f..bfea05e 100644
--- a/packages/PackageInstaller/res/values/dimens.xml
+++ b/packages/PackageInstaller/res/values/dimens.xml
@@ -41,4 +41,16 @@
 
     <dimen name="wear_permission_review_pref_padding">8dp</dimen>
     <dimen name="wear_permission_review_icon_size">24dp</dimen>
+
+    <!-- Dialog title height -->
+    <dimen name="alert_dialog_title_height">64dip</dimen>
+    <!-- Dialog button bar height -->
+    <dimen name="alert_dialog_button_bar_height">48dip</dimen>
+    <!-- The amount to offset when scrolling to a selection in an AlertDialog -->
+    <dimen name="config_alertDialogSelectionScrollOffset">0dp</dimen>
+    <dimen name="dialog_padding_top_material">18dp</dimen>
+    <dimen name="dialog_title_divider_material">8dp</dimen>
+    <!-- Dialog padding minus control padding, used to fix alignment. -->
+    <dimen name="select_dialog_padding_start_material">20dp</dimen>
+    <dimen name="select_dialog_drawable_padding_start_material">20dp</dimen>
 </resources>
diff --git a/packages/PackageInstaller/res/values/integers.xml b/packages/PackageInstaller/res/values/integers.xml
new file mode 100644
index 0000000..22ad3a3
--- /dev/null
+++ b/packages/PackageInstaller/res/values/integers.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2022 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>
+    <!-- The alert controller to use for alert dialogs. -->
+    <integer name="config_alertDialogController">0</integer>
+</resources>
\ No newline at end of file
diff --git a/packages/PackageInstaller/res/values/styles.xml b/packages/PackageInstaller/res/values/styles.xml
new file mode 100644
index 0000000..ca797e1
--- /dev/null
+++ b/packages/PackageInstaller/res/values/styles.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2022 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="AlertDialog">
+        <item name="fullDark">@empty</item>
+        <item name="topDark">@empty</item>
+        <item name="centerDark">@empty</item>
+        <item name="bottomDark">@empty</item>
+        <item name="fullBright">@empty</item>
+        <item name="topBright">@empty</item>
+        <item name="centerBright">@empty</item>
+        <item name="bottomBright">@empty</item>
+        <item name="bottomMedium">@empty</item>
+        <item name="centerMedium">@empty</item>
+        <item name="layout">@layout/alert_dialog_material</item>
+        <item name="listLayout">@layout/select_dialog_material</item>
+        <item name="progressLayout">@layout/progress_dialog_material</item>
+        <item name="horizontalProgressLayout">@layout/alert_dialog_progress_material</item>
+        <item name="listItemLayout">@layout/select_dialog_item_material</item>
+        <item name="multiChoiceItemLayout">@layout/select_dialog_multichoice_material</item>
+        <item name="singleChoiceItemLayout">@layout/select_dialog_singlechoice_material</item>
+        <item name="controllerType">@integer/config_alertDialogController</item>
+        <item name="selectionScrollOffset">@dimen/config_alertDialogSelectionScrollOffset</item>
+        <item name="needsDefaultBackgrounds">false</item>
+    </style>
+    <style name="TextAppearance">
+        <item name="textSize">16sp</item>
+    </style>
+</resources>
\ No newline at end of file
diff --git a/packages/PackageInstaller/res/values/themes.xml b/packages/PackageInstaller/res/values/themes.xml
index eecf9a1..9a06229 100644
--- a/packages/PackageInstaller/res/values/themes.xml
+++ b/packages/PackageInstaller/res/values/themes.xml
@@ -23,7 +23,9 @@
     </style>
 
     <style name="Theme.AlertDialogActivity"
-            parent="@android:style/Theme.DeviceDefault.Light.Dialog.Alert" />
+        parent="@android:style/Theme.DeviceDefault.Light.Dialog.Alert">
+        <item name="alertDialogStyle">@style/AlertDialog</item>
+    </style>
 
     <style name="Theme.AlertDialogActivity.NoActionBar">
         <item name="android:windowActionBar">false</item>
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/AlertActivity.java b/packages/PackageInstaller/src/com/android/packageinstaller/AlertActivity.java
new file mode 100644
index 0000000..b96435b
--- /dev/null
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/AlertActivity.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2007 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.packageinstaller;
+
+import android.app.Activity;
+import android.app.Dialog;
+import android.compat.annotation.UnsupportedAppUsage;
+import android.content.DialogInterface;
+import android.os.Bundle;
+import android.view.KeyEvent;
+import android.view.ViewGroup;
+import android.view.accessibility.AccessibilityEvent;
+
+/**
+ * An activity that follows the visual style of an AlertDialog.
+ * 
+ * @see #mAlert
+ * @see #mAlertParams
+ * @see #setupAlert()
+ */
+public abstract class AlertActivity extends Activity implements DialogInterface {
+
+    @UnsupportedAppUsage
+    public AlertActivity() {
+    }
+
+    /**
+     * The model for the alert.
+     * 
+     * @see #mAlertParams
+     */
+    @UnsupportedAppUsage
+    protected AlertController mAlert;
+
+    /**
+     * The parameters for the alert.
+     */
+    @UnsupportedAppUsage
+    protected AlertController.AlertParams mAlertParams;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        mAlert = AlertController.create(this, this, getWindow());
+        mAlertParams = new AlertController.AlertParams(this);
+    }
+
+    public void cancel() {
+        finish();
+    }
+
+    public void dismiss() {
+        // This is called after the click, since we finish when handling the
+        // click, don't do that again here.
+        if (!isFinishing()) {
+            finish();
+        }
+    }
+
+    @Override
+    public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
+        return dispatchPopulateAccessibilityEvent(this, event);
+    }
+
+    public static boolean dispatchPopulateAccessibilityEvent(Activity act,
+            AccessibilityEvent event) {
+        event.setClassName(Dialog.class.getName());
+        event.setPackageName(act.getPackageName());
+
+        ViewGroup.LayoutParams params = act.getWindow().getAttributes();
+        boolean isFullScreen = (params.width == ViewGroup.LayoutParams.MATCH_PARENT) &&
+                (params.height == ViewGroup.LayoutParams.MATCH_PARENT);
+        event.setFullScreen(isFullScreen);
+
+        return false;
+    }
+
+    /**
+     * Sets up the alert, including applying the parameters to the alert model,
+     * and installing the alert's content.
+     *
+     * @see #mAlert
+     * @see #mAlertParams
+     */
+    @UnsupportedAppUsage
+    protected void setupAlert() {
+        mAlert.installContent(mAlertParams);
+    }
+
+    @Override
+    public boolean onKeyDown(int keyCode, KeyEvent event) {
+        if (mAlert.onKeyDown(keyCode, event)) return true;
+        return super.onKeyDown(keyCode, event);
+    }
+
+    @Override
+    public boolean onKeyUp(int keyCode, KeyEvent event) {
+        if (mAlert.onKeyUp(keyCode, event)) return true;
+        return super.onKeyUp(keyCode, event);
+    }
+}
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/AlertController.java b/packages/PackageInstaller/src/com/android/packageinstaller/AlertController.java
new file mode 100644
index 0000000..35d2518
--- /dev/null
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/AlertController.java
@@ -0,0 +1,1302 @@
+/*
+ * 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.packageinstaller;
+
+import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
+
+import android.app.AlertDialog;
+import android.compat.annotation.UnsupportedAppUsage;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.res.TypedArray;
+import android.database.Cursor;
+import android.graphics.drawable.Drawable;
+import android.os.Build;
+import android.os.Handler;
+import android.os.Message;
+import android.text.Layout;
+import android.text.TextUtils;
+import android.text.method.MovementMethod;
+import android.util.AttributeSet;
+import android.util.TypedValue;
+import android.view.Gravity;
+import android.view.KeyEvent;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewGroup.LayoutParams;
+import android.view.ViewParent;
+import android.view.ViewStub;
+import android.view.Window;
+import android.view.WindowManager;
+import android.widget.AdapterView;
+import android.widget.AdapterView.OnItemClickListener;
+import android.widget.ArrayAdapter;
+import android.widget.Button;
+import android.widget.CheckedTextView;
+import android.widget.CursorAdapter;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.ListAdapter;
+import android.widget.ListView;
+import android.widget.ScrollView;
+import android.widget.SimpleCursorAdapter;
+import android.widget.TextView;
+
+import androidx.annotation.Nullable;
+
+import com.android.packageinstaller.R;
+
+import java.lang.ref.WeakReference;
+
+public class AlertController {
+    public static final int MICRO = 1;
+
+    private final Context mContext;
+    private final DialogInterface mDialogInterface;
+    protected final Window mWindow;
+
+    @UnsupportedAppUsage
+    private CharSequence mTitle;
+    protected CharSequence mMessage;
+    protected ListView mListView;
+    @UnsupportedAppUsage
+    private View mView;
+
+    private int mViewLayoutResId;
+
+    private int mViewSpacingLeft;
+    private int mViewSpacingTop;
+    private int mViewSpacingRight;
+    private int mViewSpacingBottom;
+    private boolean mViewSpacingSpecified = false;
+
+    private Button mButtonPositive;
+    private CharSequence mButtonPositiveText;
+    private Message mButtonPositiveMessage;
+
+    private Button mButtonNegative;
+    private CharSequence mButtonNegativeText;
+    private Message mButtonNegativeMessage;
+
+    private Button mButtonNeutral;
+    private CharSequence mButtonNeutralText;
+    private Message mButtonNeutralMessage;
+
+    protected ScrollView mScrollView;
+
+    private int mIconId = 0;
+    private Drawable mIcon;
+
+    private ImageView mIconView;
+    private TextView mTitleView;
+    protected TextView mMessageView;
+    private MovementMethod mMessageMovementMethod;
+    @Layout.HyphenationFrequency // will be removed in cleanup
+    private Integer mMessageHyphenationFrequency; // cleanup
+    @UnsupportedAppUsage
+    private View mCustomTitleView;
+
+    @UnsupportedAppUsage
+    private boolean mForceInverseBackground;
+
+    private ListAdapter mAdapter;
+
+    private int mCheckedItem = -1;
+
+    private int mAlertDialogLayout;
+    private int mButtonPanelSideLayout;
+    private int mListLayout;
+    private int mMultiChoiceItemLayout;
+    private int mSingleChoiceItemLayout;
+    private int mListItemLayout;
+
+    private boolean mShowTitle;
+
+    private int mButtonPanelLayoutHint = AlertDialog.LAYOUT_HINT_NONE;
+
+    private Handler mHandler;
+
+    private final View.OnClickListener mButtonHandler = new View.OnClickListener() {
+        @Override
+        public void onClick(View v) {
+            final Message m;
+            if (v == mButtonPositive && mButtonPositiveMessage != null) {
+                m = Message.obtain(mButtonPositiveMessage);
+            } else if (v == mButtonNegative && mButtonNegativeMessage != null) {
+                m = Message.obtain(mButtonNegativeMessage);
+            } else if (v == mButtonNeutral && mButtonNeutralMessage != null) {
+                m = Message.obtain(mButtonNeutralMessage);
+            } else {
+                m = null;
+            }
+
+            if (m != null) {
+                m.sendToTarget();
+            }
+
+            // Post a message so we dismiss after the above handlers are executed
+            mHandler.obtainMessage(ButtonHandler.MSG_DISMISS_DIALOG, mDialogInterface)
+                    .sendToTarget();
+        }
+    };
+
+    private static final class ButtonHandler extends Handler {
+        // Button clicks have Message.what as the BUTTON{1,2,3} constant
+        private static final int MSG_DISMISS_DIALOG = 1;
+
+        private WeakReference<DialogInterface> mDialog;
+
+        public ButtonHandler(DialogInterface dialog) {
+            mDialog = new WeakReference<>(dialog);
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+
+                case DialogInterface.BUTTON_POSITIVE:
+                case DialogInterface.BUTTON_NEGATIVE:
+                case DialogInterface.BUTTON_NEUTRAL:
+                    ((DialogInterface.OnClickListener) msg.obj).onClick(mDialog.get(), msg.what);
+                    break;
+
+                case MSG_DISMISS_DIALOG:
+                    ((DialogInterface) msg.obj).dismiss();
+            }
+        }
+    }
+
+    private static boolean shouldCenterSingleButton(Context context) {
+        final TypedValue outValue = new TypedValue();
+        context.getTheme().resolveAttribute(R.attr.alertDialogCenterButtons, outValue, true);
+        return outValue.data != 0;
+    }
+
+    public static final AlertController create(Context context, DialogInterface di, Window window) {
+        final TypedArray a = context.obtainStyledAttributes(
+                null, R.styleable.AlertDialog, R.attr.alertDialogStyle,
+                android.R.style.Theme_DeviceDefault_Settings);
+        int controllerType = a.getInt(R.styleable.AlertDialog_controllerType, 0);
+        a.recycle();
+
+        switch (controllerType) {
+            case MICRO:
+                return new MicroAlertController(context, di, window);
+            default:
+                return new AlertController(context, di, window);
+        }
+    }
+
+    @UnsupportedAppUsage
+    protected AlertController(Context context, DialogInterface di, Window window) {
+        mContext = context;
+        mDialogInterface = di;
+        mWindow = window;
+        mHandler = new ButtonHandler(di);
+
+        final TypedArray a = context.obtainStyledAttributes(null,
+                R.styleable.AlertDialog, R.attr.alertDialogStyle, 0);
+
+        mAlertDialogLayout = a.getResourceId(
+                R.styleable.AlertDialog_layout, R.layout.alert_dialog);
+        mButtonPanelSideLayout = a.getResourceId(
+                R.styleable.AlertDialog_buttonPanelSideLayout, 0);
+        mListLayout = a.getResourceId(
+                R.styleable.AlertDialog_listLayout, R.layout.select_dialog);
+
+        mMultiChoiceItemLayout = a.getResourceId(
+                R.styleable.AlertDialog_multiChoiceItemLayout,
+                R.layout.select_dialog_multichoice);
+        mSingleChoiceItemLayout = a.getResourceId(
+                R.styleable.AlertDialog_singleChoiceItemLayout,
+                R.layout.select_dialog_singlechoice);
+        mListItemLayout = a.getResourceId(
+                R.styleable.AlertDialog_listItemLayout,
+                R.layout.select_dialog_item);
+        mShowTitle = a.getBoolean(R.styleable.AlertDialog_showTitle, true);
+
+        a.recycle();
+
+        /* We use a custom title so never request a window title */
+        window.requestFeature(Window.FEATURE_NO_TITLE);
+    }
+
+    static boolean canTextInput(View v) {
+        if (v.onCheckIsTextEditor()) {
+            return true;
+        }
+
+        if (!(v instanceof ViewGroup)) {
+            return false;
+        }
+
+        ViewGroup vg = (ViewGroup)v;
+        int i = vg.getChildCount();
+        while (i > 0) {
+            i--;
+            v = vg.getChildAt(i);
+            if (canTextInput(v)) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    public void installContent(AlertParams params) {
+        params.apply(this);
+        installContent();
+    }
+
+    @UnsupportedAppUsage
+    public void installContent() {
+        int contentView = selectContentView();
+        mWindow.setContentView(contentView);
+        setupView();
+    }
+
+    private int selectContentView() {
+        if (mButtonPanelSideLayout == 0) {
+            return mAlertDialogLayout;
+        }
+        if (mButtonPanelLayoutHint == AlertDialog.LAYOUT_HINT_SIDE) {
+            return mButtonPanelSideLayout;
+        }
+        // TODO: use layout hint side for long messages/lists
+        return mAlertDialogLayout;
+    }
+
+    @UnsupportedAppUsage
+    public void setTitle(CharSequence title) {
+        mTitle = title;
+        if (mTitleView != null) {
+            mTitleView.setText(title);
+        }
+        mWindow.setTitle(title);
+    }
+
+    /**
+     * @see AlertDialog.Builder#setCustomTitle(View)
+     */
+    @UnsupportedAppUsage
+    public void setCustomTitle(View customTitleView) {
+        mCustomTitleView = customTitleView;
+    }
+
+    @UnsupportedAppUsage
+    public void setMessage(CharSequence message) {
+        mMessage = message;
+        if (mMessageView != null) {
+            mMessageView.setText(message);
+        }
+    }
+
+    public void setMessageMovementMethod(MovementMethod movementMethod) {
+        mMessageMovementMethod = movementMethod;
+        if (mMessageView != null) {
+            mMessageView.setMovementMethod(movementMethod);
+        }
+    }
+
+    public void setMessageHyphenationFrequency(
+            @Layout.HyphenationFrequency int hyphenationFrequency) {
+        mMessageHyphenationFrequency = hyphenationFrequency;
+        if (mMessageView != null) {
+            mMessageView.setHyphenationFrequency(hyphenationFrequency);
+        }
+    }
+
+    /**
+     * Set the view resource to display in the dialog.
+     */
+    public void setView(int layoutResId) {
+        mView = null;
+        mViewLayoutResId = layoutResId;
+        mViewSpacingSpecified = false;
+    }
+
+    /**
+     * Set the view to display in the dialog.
+     */
+    @UnsupportedAppUsage
+    public void setView(View view) {
+        mView = view;
+        mViewLayoutResId = 0;
+        mViewSpacingSpecified = false;
+    }
+
+    /**
+     * Set the view to display in the dialog along with the spacing around that view
+     */
+    public void setView(View view, int viewSpacingLeft, int viewSpacingTop, int viewSpacingRight,
+            int viewSpacingBottom) {
+        mView = view;
+        mViewLayoutResId = 0;
+        mViewSpacingSpecified = true;
+        mViewSpacingLeft = viewSpacingLeft;
+        mViewSpacingTop = viewSpacingTop;
+        mViewSpacingRight = viewSpacingRight;
+        mViewSpacingBottom = viewSpacingBottom;
+    }
+
+    /**
+     * Sets a hint for the best button panel layout.
+     */
+    public void setButtonPanelLayoutHint(int layoutHint) {
+        mButtonPanelLayoutHint = layoutHint;
+    }
+
+    /**
+     * Sets a click listener or a message to be sent when the button is clicked.
+     * You only need to pass one of {@code listener} or {@code msg}.
+     *
+     * @param whichButton Which button, can be one of
+     *            {@link DialogInterface#BUTTON_POSITIVE},
+     *            {@link DialogInterface#BUTTON_NEGATIVE}, or
+     *            {@link DialogInterface#BUTTON_NEUTRAL}
+     * @param text The text to display in positive button.
+     * @param listener The {@link DialogInterface.OnClickListener} to use.
+     * @param msg The {@link Message} to be sent when clicked.
+     */
+    @UnsupportedAppUsage
+    public void setButton(int whichButton, CharSequence text,
+            DialogInterface.OnClickListener listener, Message msg) {
+
+        if (msg == null && listener != null) {
+            msg = mHandler.obtainMessage(whichButton, listener);
+        }
+
+        switch (whichButton) {
+
+            case DialogInterface.BUTTON_POSITIVE:
+                mButtonPositiveText = text;
+                mButtonPositiveMessage = msg;
+                break;
+
+            case DialogInterface.BUTTON_NEGATIVE:
+                mButtonNegativeText = text;
+                mButtonNegativeMessage = msg;
+                break;
+
+            case DialogInterface.BUTTON_NEUTRAL:
+                mButtonNeutralText = text;
+                mButtonNeutralMessage = msg;
+                break;
+
+            default:
+                throw new IllegalArgumentException("Button does not exist");
+        }
+    }
+
+    /**
+     * Specifies the icon to display next to the alert title.
+     *
+     * @param resId the resource identifier of the drawable to use as the icon,
+     *            or 0 for no icon
+     */
+    @UnsupportedAppUsage
+    public void setIcon(int resId) {
+        mIcon = null;
+        mIconId = resId;
+
+        if (mIconView != null) {
+            if (resId != 0) {
+                mIconView.setVisibility(View.VISIBLE);
+                mIconView.setImageResource(mIconId);
+            } else {
+                mIconView.setVisibility(View.GONE);
+            }
+        }
+    }
+
+    /**
+     * Specifies the icon to display next to the alert title.
+     *
+     * @param icon the drawable to use as the icon or null for no icon
+     */
+    @UnsupportedAppUsage
+    public void setIcon(Drawable icon) {
+        mIcon = icon;
+        mIconId = 0;
+
+        if (mIconView != null) {
+            if (icon != null) {
+                mIconView.setVisibility(View.VISIBLE);
+                mIconView.setImageDrawable(icon);
+            } else {
+                mIconView.setVisibility(View.GONE);
+            }
+        }
+    }
+
+    /**
+     * @param attrId the attributeId of the theme-specific drawable
+     * to resolve the resourceId for.
+     *
+     * @return resId the resourceId of the theme-specific drawable
+     */
+    public int getIconAttributeResId(int attrId) {
+        TypedValue out = new TypedValue();
+        mContext.getTheme().resolveAttribute(attrId, out, true);
+        return out.resourceId;
+    }
+
+    public void setInverseBackgroundForced(boolean forceInverseBackground) {
+        mForceInverseBackground = forceInverseBackground;
+    }
+
+    @UnsupportedAppUsage
+    public ListView getListView() {
+        return mListView;
+    }
+
+    @UnsupportedAppUsage
+    public Button getButton(int whichButton) {
+        switch (whichButton) {
+            case DialogInterface.BUTTON_POSITIVE:
+                return mButtonPositive;
+            case DialogInterface.BUTTON_NEGATIVE:
+                return mButtonNegative;
+            case DialogInterface.BUTTON_NEUTRAL:
+                return mButtonNeutral;
+            default:
+                return null;
+        }
+    }
+
+    @SuppressWarnings({"UnusedDeclaration"})
+    @UnsupportedAppUsage
+    public boolean onKeyDown(int keyCode, KeyEvent event) {
+        return mScrollView != null && mScrollView.executeKeyEvent(event);
+    }
+
+    @SuppressWarnings({"UnusedDeclaration"})
+    @UnsupportedAppUsage
+    public boolean onKeyUp(int keyCode, KeyEvent event) {
+        return mScrollView != null && mScrollView.executeKeyEvent(event);
+    }
+
+    /**
+     * Resolves whether a custom or default panel should be used. Removes the
+     * default panel if a custom panel should be used. If the resolved panel is
+     * a view stub, inflates before returning.
+     *
+     * @param customPanel the custom panel
+     * @param defaultPanel the default panel
+     * @return the panel to use
+     */
+    @Nullable
+    private ViewGroup resolvePanel(@Nullable View customPanel, @Nullable View defaultPanel) {
+        if (customPanel == null) {
+            // Inflate the default panel, if needed.
+            if (defaultPanel instanceof ViewStub) {
+                defaultPanel = ((ViewStub) defaultPanel).inflate();
+            }
+
+            return (ViewGroup) defaultPanel;
+        }
+
+        // Remove the default panel entirely.
+        if (defaultPanel != null) {
+            final ViewParent parent = defaultPanel.getParent();
+            if (parent instanceof ViewGroup) {
+                ((ViewGroup) parent).removeView(defaultPanel);
+            }
+        }
+
+        // Inflate the custom panel, if needed.
+        if (customPanel instanceof ViewStub) {
+            customPanel = ((ViewStub) customPanel).inflate();
+        }
+
+        return (ViewGroup) customPanel;
+    }
+
+    private void setupView() {
+        final View parentPanel = mWindow.findViewById(R.id.parentPanel);
+        final View defaultTopPanel = parentPanel.findViewById(R.id.topPanel);
+        final View defaultContentPanel = parentPanel.findViewById(R.id.contentPanel);
+        final View defaultButtonPanel = parentPanel.findViewById(R.id.buttonPanel);
+
+        // Install custom content before setting up the title or buttons so
+        // that we can handle panel overrides.
+        final ViewGroup customPanel = (ViewGroup) parentPanel.findViewById(R.id.customPanel);
+        setupCustomContent(customPanel);
+
+        final View customTopPanel = customPanel.findViewById(R.id.topPanel);
+        final View customContentPanel = customPanel.findViewById(R.id.contentPanel);
+        final View customButtonPanel = customPanel.findViewById(R.id.buttonPanel);
+
+        // Resolve the correct panels and remove the defaults, if needed.
+        final ViewGroup topPanel = resolvePanel(customTopPanel, defaultTopPanel);
+        final ViewGroup contentPanel = resolvePanel(customContentPanel, defaultContentPanel);
+        final ViewGroup buttonPanel = resolvePanel(customButtonPanel, defaultButtonPanel);
+
+        setupContent(contentPanel);
+        setupButtons(buttonPanel);
+        setupTitle(topPanel);
+
+        final boolean hasCustomPanel = customPanel != null
+                && customPanel.getVisibility() != View.GONE;
+        final boolean hasTopPanel = topPanel != null
+                && topPanel.getVisibility() != View.GONE;
+        final boolean hasButtonPanel = buttonPanel != null
+                && buttonPanel.getVisibility() != View.GONE;
+
+        if (!parentPanel.isInTouchMode()) {
+            final View content = hasCustomPanel ? customPanel : contentPanel;
+            if (!requestFocusForContent(content)) {
+                requestFocusForDefaultButton();
+            }
+        }
+
+        // Only display the text spacer if we don't have buttons.
+        if (!hasButtonPanel) {
+            if (contentPanel != null) {
+                final View spacer = contentPanel.findViewById(R.id.textSpacerNoButtons);
+                if (spacer != null) {
+                    spacer.setVisibility(View.VISIBLE);
+                }
+            }
+            mWindow.setCloseOnTouchOutsideIfNotSet(true);
+        }
+
+        if (hasTopPanel) {
+            // Only clip scrolling content to padding if we have a title.
+            if (mScrollView != null) {
+                mScrollView.setClipToPadding(true);
+            }
+
+            // Only show the divider if we have a title.
+            View divider = null;
+            if (mMessage != null || mListView != null || hasCustomPanel) {
+                if (!hasCustomPanel) {
+                    divider = topPanel.findViewById(R.id.titleDividerNoCustom);
+                }
+                if (divider == null) {
+                    divider = topPanel.findViewById(R.id.titleDivider);
+                }
+
+            } else {
+                divider = topPanel.findViewById(R.id.titleDividerTop);
+            }
+
+            if (divider != null) {
+                divider.setVisibility(View.VISIBLE);
+            }
+        } else {
+            if (contentPanel != null) {
+                final View spacer = contentPanel.findViewById(R.id.textSpacerNoTitle);
+                if (spacer != null) {
+                    spacer.setVisibility(View.VISIBLE);
+                }
+            }
+        }
+
+        if (mListView instanceof RecycleListView) {
+            ((RecycleListView) mListView).setHasDecor(hasTopPanel, hasButtonPanel);
+        }
+
+        // Update scroll indicators as needed.
+        if (!hasCustomPanel) {
+            final View content = mListView != null ? mListView : mScrollView;
+            if (content != null) {
+                final int indicators = (hasTopPanel ? View.SCROLL_INDICATOR_TOP : 0)
+                        | (hasButtonPanel ? View.SCROLL_INDICATOR_BOTTOM : 0);
+                content.setScrollIndicators(indicators,
+                        View.SCROLL_INDICATOR_TOP | View.SCROLL_INDICATOR_BOTTOM);
+            }
+        }
+
+        final TypedArray a = mContext.obtainStyledAttributes(
+                null, R.styleable.AlertDialog, R.attr.alertDialogStyle, 0);
+        setBackground(a, topPanel, contentPanel, customPanel, buttonPanel,
+                hasTopPanel, hasCustomPanel, hasButtonPanel);
+        a.recycle();
+    }
+
+    private boolean requestFocusForContent(View content) {
+        if (content != null && content.requestFocus()) {
+            return true;
+        }
+
+        if (mListView != null) {
+            mListView.setSelection(0);
+            return true;
+        }
+
+        return false;
+    }
+
+    private void requestFocusForDefaultButton() {
+        if (mButtonPositive.getVisibility() == View.VISIBLE) {
+            mButtonPositive.requestFocus();
+        } else if (mButtonNegative.getVisibility() == View.VISIBLE) {
+            mButtonNegative.requestFocus();
+        } else if (mButtonNeutral.getVisibility() == View.VISIBLE) {
+            mButtonNeutral.requestFocus();
+        }
+    }
+
+    private void setupCustomContent(ViewGroup customPanel) {
+        final View customView;
+        if (mView != null) {
+            customView = mView;
+        } else if (mViewLayoutResId != 0) {
+            final LayoutInflater inflater = LayoutInflater.from(mContext);
+            customView = inflater.inflate(mViewLayoutResId, customPanel, false);
+        } else {
+            customView = null;
+        }
+
+        final boolean hasCustomView = customView != null;
+        if (!hasCustomView || !canTextInput(customView)) {
+            mWindow.setFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
+                    WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
+        }
+
+        if (hasCustomView) {
+            final FrameLayout custom = (FrameLayout) mWindow.findViewById(R.id.custom);
+            custom.addView(customView, new LayoutParams(MATCH_PARENT, MATCH_PARENT));
+
+            if (mViewSpacingSpecified) {
+                custom.setPadding(
+                        mViewSpacingLeft, mViewSpacingTop, mViewSpacingRight, mViewSpacingBottom);
+            }
+
+            if (mListView != null) {
+                ((LinearLayout.LayoutParams) customPanel.getLayoutParams()).weight = 0;
+            }
+        } else {
+            customPanel.setVisibility(View.GONE);
+        }
+    }
+
+    protected void setupTitle(ViewGroup topPanel) {
+        if (mCustomTitleView != null && mShowTitle) {
+            // Add the custom title view directly to the topPanel layout
+            final LayoutParams lp = new LayoutParams(
+                    LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
+
+            topPanel.addView(mCustomTitleView, 0, lp);
+
+            // Hide the title template
+            final View titleTemplate = mWindow.findViewById(R.id.title_template);
+            titleTemplate.setVisibility(View.GONE);
+        } else {
+            mIconView = (ImageView) mWindow.findViewById(R.id.icon);
+
+            final boolean hasTextTitle = !TextUtils.isEmpty(mTitle);
+            if (hasTextTitle && mShowTitle) {
+                // Display the title if a title is supplied, else hide it.
+                mTitleView = (TextView) mWindow.findViewById(R.id.alertTitle);
+                mTitleView.setText(mTitle);
+
+                // Do this last so that if the user has supplied any icons we
+                // use them instead of the default ones. If the user has
+                // specified 0 then make it disappear.
+                if (mIconId != 0) {
+                    mIconView.setImageResource(mIconId);
+                } else if (mIcon != null) {
+                    mIconView.setImageDrawable(mIcon);
+                } else {
+                    // Apply the padding from the icon to ensure the title is
+                    // aligned correctly.
+                    mTitleView.setPadding(mIconView.getPaddingLeft(),
+                            mIconView.getPaddingTop(),
+                            mIconView.getPaddingRight(),
+                            mIconView.getPaddingBottom());
+                    mIconView.setVisibility(View.GONE);
+                }
+            } else {
+                // Hide the title template
+                final View titleTemplate = mWindow.findViewById(R.id.title_template);
+                titleTemplate.setVisibility(View.GONE);
+                mIconView.setVisibility(View.GONE);
+                topPanel.setVisibility(View.GONE);
+            }
+        }
+    }
+
+    protected void setupContent(ViewGroup contentPanel) {
+        mScrollView = (ScrollView) contentPanel.findViewById(R.id.scrollView);
+        mScrollView.setFocusable(false);
+
+        // Special case for users that only want to display a String
+        mMessageView = (TextView) contentPanel.findViewById(R.id.message);
+        if (mMessageView == null) {
+            return;
+        }
+
+        if (mMessage != null) {
+            mMessageView.setText(mMessage);
+            if (mMessageMovementMethod != null) {
+                mMessageView.setMovementMethod(mMessageMovementMethod);
+            }
+            if (mMessageHyphenationFrequency != null) {
+                mMessageView.setHyphenationFrequency(mMessageHyphenationFrequency);
+            }
+        } else {
+            mMessageView.setVisibility(View.GONE);
+            mScrollView.removeView(mMessageView);
+
+            if (mListView != null) {
+                final ViewGroup scrollParent = (ViewGroup) mScrollView.getParent();
+                final int childIndex = scrollParent.indexOfChild(mScrollView);
+                scrollParent.removeViewAt(childIndex);
+                scrollParent.addView(mListView, childIndex,
+                        new LayoutParams(MATCH_PARENT, MATCH_PARENT));
+            } else {
+                contentPanel.setVisibility(View.GONE);
+            }
+        }
+    }
+
+    private static void manageScrollIndicators(View v, View upIndicator, View downIndicator) {
+        if (upIndicator != null) {
+            upIndicator.setVisibility(v.canScrollVertically(-1) ? View.VISIBLE : View.INVISIBLE);
+        }
+        if (downIndicator != null) {
+            downIndicator.setVisibility(v.canScrollVertically(1) ? View.VISIBLE : View.INVISIBLE);
+        }
+    }
+
+    protected void setupButtons(ViewGroup buttonPanel) {
+        int BIT_BUTTON_POSITIVE = 1;
+        int BIT_BUTTON_NEGATIVE = 2;
+        int BIT_BUTTON_NEUTRAL = 4;
+        int whichButtons = 0;
+        mButtonPositive = (Button) buttonPanel.findViewById(R.id.button1);
+        mButtonPositive.setOnClickListener(mButtonHandler);
+
+        if (TextUtils.isEmpty(mButtonPositiveText)) {
+            mButtonPositive.setVisibility(View.GONE);
+        } else {
+            mButtonPositive.setText(mButtonPositiveText);
+            mButtonPositive.setVisibility(View.VISIBLE);
+            whichButtons = whichButtons | BIT_BUTTON_POSITIVE;
+        }
+
+        mButtonNegative = (Button) buttonPanel.findViewById(R.id.button2);
+        mButtonNegative.setOnClickListener(mButtonHandler);
+
+        if (TextUtils.isEmpty(mButtonNegativeText)) {
+            mButtonNegative.setVisibility(View.GONE);
+        } else {
+            mButtonNegative.setText(mButtonNegativeText);
+            mButtonNegative.setVisibility(View.VISIBLE);
+
+            whichButtons = whichButtons | BIT_BUTTON_NEGATIVE;
+        }
+
+        mButtonNeutral = (Button) buttonPanel.findViewById(R.id.button3);
+        mButtonNeutral.setOnClickListener(mButtonHandler);
+
+        if (TextUtils.isEmpty(mButtonNeutralText)) {
+            mButtonNeutral.setVisibility(View.GONE);
+        } else {
+            mButtonNeutral.setText(mButtonNeutralText);
+            mButtonNeutral.setVisibility(View.VISIBLE);
+
+            whichButtons = whichButtons | BIT_BUTTON_NEUTRAL;
+        }
+
+        if (shouldCenterSingleButton(mContext)) {
+            /*
+             * If we only have 1 button it should be centered on the layout and
+             * expand to fill 50% of the available space.
+             */
+            if (whichButtons == BIT_BUTTON_POSITIVE) {
+                centerButton(mButtonPositive);
+            } else if (whichButtons == BIT_BUTTON_NEGATIVE) {
+                centerButton(mButtonNegative);
+            } else if (whichButtons == BIT_BUTTON_NEUTRAL) {
+                centerButton(mButtonNeutral);
+            }
+        }
+
+        final boolean hasButtons = whichButtons != 0;
+        if (!hasButtons) {
+            buttonPanel.setVisibility(View.GONE);
+        }
+    }
+
+    private void centerButton(Button button) {
+        LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) button.getLayoutParams();
+        params.gravity = Gravity.CENTER_HORIZONTAL;
+        params.weight = 0.5f;
+        button.setLayoutParams(params);
+        View leftSpacer = mWindow.findViewById(R.id.leftSpacer);
+        if (leftSpacer != null) {
+            leftSpacer.setVisibility(View.VISIBLE);
+        }
+        View rightSpacer = mWindow.findViewById(R.id.rightSpacer);
+        if (rightSpacer != null) {
+            rightSpacer.setVisibility(View.VISIBLE);
+        }
+    }
+
+    private void setBackground(TypedArray a, View topPanel, View contentPanel, View customPanel,
+            View buttonPanel, boolean hasTitle, boolean hasCustomView, boolean hasButtons) {
+        int fullDark = 0;
+        int topDark = 0;
+        int centerDark = 0;
+        int bottomDark = 0;
+        int fullBright = 0;
+        int topBright = 0;
+        int centerBright = 0;
+        int bottomBright = 0;
+        int bottomMedium = 0;
+
+        // If the needsDefaultBackgrounds attribute is set, we know we're
+        // inheriting from a framework style.
+        final boolean needsDefaultBackgrounds = a.getBoolean(
+                R.styleable.AlertDialog_needsDefaultBackgrounds, true);
+        if (needsDefaultBackgrounds) {
+            fullDark = R.drawable.popup_full_dark;
+            topDark = R.drawable.popup_top_dark;
+            centerDark = R.drawable.popup_center_dark;
+            bottomDark = R.drawable.popup_bottom_dark;
+            fullBright = R.drawable.popup_full_bright;
+            topBright = R.drawable.popup_top_bright;
+            centerBright = R.drawable.popup_center_bright;
+            bottomBright = R.drawable.popup_bottom_bright;
+            bottomMedium = R.drawable.popup_bottom_medium;
+        }
+
+        topBright = a.getResourceId(R.styleable.AlertDialog_topBright, topBright);
+        topDark = a.getResourceId(R.styleable.AlertDialog_topDark, topDark);
+        centerBright = a.getResourceId(R.styleable.AlertDialog_centerBright, centerBright);
+        centerDark = a.getResourceId(R.styleable.AlertDialog_centerDark, centerDark);
+
+        /* We now set the background of all of the sections of the alert.
+         * First collect together each section that is being displayed along
+         * with whether it is on a light or dark background, then run through
+         * them setting their backgrounds.  This is complicated because we need
+         * to correctly use the full, top, middle, and bottom graphics depending
+         * on how many views they are and where they appear.
+         */
+
+        final View[] views = new View[4];
+        final boolean[] light = new boolean[4];
+        View lastView = null;
+        boolean lastLight = false;
+
+        int pos = 0;
+        if (hasTitle) {
+            views[pos] = topPanel;
+            light[pos] = false;
+            pos++;
+        }
+
+        /* The contentPanel displays either a custom text message or
+         * a ListView. If it's text we should use the dark background
+         * for ListView we should use the light background. If neither
+         * are there the contentPanel will be hidden so set it as null.
+         */
+        views[pos] = contentPanel.getVisibility() == View.GONE ? null : contentPanel;
+        light[pos] = mListView != null;
+        pos++;
+
+        if (hasCustomView) {
+            views[pos] = customPanel;
+            light[pos] = mForceInverseBackground;
+            pos++;
+        }
+
+        if (hasButtons) {
+            views[pos] = buttonPanel;
+            light[pos] = true;
+        }
+
+        boolean setView = false;
+        for (pos = 0; pos < views.length; pos++) {
+            final View v = views[pos];
+            if (v == null) {
+                continue;
+            }
+
+            if (lastView != null) {
+                if (!setView) {
+                    lastView.setBackgroundResource(lastLight ? topBright : topDark);
+                } else {
+                    lastView.setBackgroundResource(lastLight ? centerBright : centerDark);
+                }
+                setView = true;
+            }
+
+            lastView = v;
+            lastLight = light[pos];
+        }
+
+        if (lastView != null) {
+            if (setView) {
+                bottomBright = a.getResourceId(R.styleable.AlertDialog_bottomBright, bottomBright);
+                bottomMedium = a.getResourceId(R.styleable.AlertDialog_bottomMedium, bottomMedium);
+                bottomDark = a.getResourceId(R.styleable.AlertDialog_bottomDark, bottomDark);
+
+                // ListViews will use the Bright background, but buttons use the
+                // Medium background.
+                lastView.setBackgroundResource(
+                        lastLight ? (hasButtons ? bottomMedium : bottomBright) : bottomDark);
+            } else {
+                fullBright = a.getResourceId(R.styleable.AlertDialog_fullBright, fullBright);
+                fullDark = a.getResourceId(R.styleable.AlertDialog_fullDark, fullDark);
+
+                lastView.setBackgroundResource(lastLight ? fullBright : fullDark);
+            }
+        }
+
+        final ListView listView = mListView;
+        if (listView != null && mAdapter != null) {
+            listView.setAdapter(mAdapter);
+            final int checkedItem = mCheckedItem;
+            if (checkedItem > -1) {
+                listView.setItemChecked(checkedItem, true);
+                listView.setSelectionFromTop(checkedItem,
+                        a.getDimensionPixelSize(R.styleable.AlertDialog_selectionScrollOffset, 0));
+            }
+        }
+    }
+
+    public static class RecycleListView extends ListView {
+        private final int mPaddingTopNoTitle;
+        private final int mPaddingBottomNoButtons;
+
+        boolean mRecycleOnMeasure = true;
+
+        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+        public RecycleListView(Context context) {
+            this(context, null);
+        }
+
+        @UnsupportedAppUsage
+        public RecycleListView(Context context, AttributeSet attrs) {
+            super(context, attrs);
+
+            final TypedArray ta = context.obtainStyledAttributes(
+                    attrs, R.styleable.RecycleListView);
+            mPaddingBottomNoButtons = ta.getDimensionPixelOffset(
+                    R.styleable.RecycleListView_paddingBottomNoButtons, -1);
+            mPaddingTopNoTitle = ta.getDimensionPixelOffset(
+                    R.styleable.RecycleListView_paddingTopNoTitle, -1);
+        }
+
+        public void setHasDecor(boolean hasTitle, boolean hasButtons) {
+            if (!hasButtons || !hasTitle) {
+                final int paddingLeft = getPaddingLeft();
+                final int paddingTop = hasTitle ? getPaddingTop() : mPaddingTopNoTitle;
+                final int paddingRight = getPaddingRight();
+                final int paddingBottom = hasButtons ? getPaddingBottom() : mPaddingBottomNoButtons;
+                setPadding(paddingLeft, paddingTop, paddingRight, paddingBottom);
+            }
+        }
+
+        @Override
+        protected boolean recycleOnMeasure() {
+            return mRecycleOnMeasure;
+        }
+    }
+
+    public static class AlertParams {
+        @UnsupportedAppUsage
+        public final Context mContext;
+        @UnsupportedAppUsage
+        public final LayoutInflater mInflater;
+
+        @UnsupportedAppUsage
+        public int mIconId = 0;
+        @UnsupportedAppUsage
+        public Drawable mIcon;
+        public int mIconAttrId = 0;
+        @UnsupportedAppUsage
+        public CharSequence mTitle;
+        @UnsupportedAppUsage
+        public View mCustomTitleView;
+        @UnsupportedAppUsage
+        public CharSequence mMessage;
+        @UnsupportedAppUsage
+        public CharSequence mPositiveButtonText;
+        @UnsupportedAppUsage
+        public DialogInterface.OnClickListener mPositiveButtonListener;
+        @UnsupportedAppUsage
+        public CharSequence mNegativeButtonText;
+        @UnsupportedAppUsage
+        public DialogInterface.OnClickListener mNegativeButtonListener;
+        @UnsupportedAppUsage
+        public CharSequence mNeutralButtonText;
+        @UnsupportedAppUsage
+        public DialogInterface.OnClickListener mNeutralButtonListener;
+        @UnsupportedAppUsage
+        public boolean mCancelable;
+        @UnsupportedAppUsage
+        public DialogInterface.OnCancelListener mOnCancelListener;
+        @UnsupportedAppUsage
+        public DialogInterface.OnDismissListener mOnDismissListener;
+        @UnsupportedAppUsage
+        public DialogInterface.OnKeyListener mOnKeyListener;
+        @UnsupportedAppUsage
+        public CharSequence[] mItems;
+        @UnsupportedAppUsage
+        public ListAdapter mAdapter;
+        @UnsupportedAppUsage
+        public DialogInterface.OnClickListener mOnClickListener;
+        public int mViewLayoutResId;
+        @UnsupportedAppUsage
+        public View mView;
+        public int mViewSpacingLeft;
+        public int mViewSpacingTop;
+        public int mViewSpacingRight;
+        public int mViewSpacingBottom;
+        public boolean mViewSpacingSpecified = false;
+        @UnsupportedAppUsage
+        public boolean[] mCheckedItems;
+        @UnsupportedAppUsage
+        public boolean mIsMultiChoice;
+        @UnsupportedAppUsage
+        public boolean mIsSingleChoice;
+        @UnsupportedAppUsage
+        public int mCheckedItem = -1;
+        @UnsupportedAppUsage
+        public DialogInterface.OnMultiChoiceClickListener mOnCheckboxClickListener;
+        @UnsupportedAppUsage
+        public Cursor mCursor;
+        @UnsupportedAppUsage
+        public String mLabelColumn;
+        @UnsupportedAppUsage
+        public String mIsCheckedColumn;
+        public boolean mForceInverseBackground;
+        @UnsupportedAppUsage
+        public AdapterView.OnItemSelectedListener mOnItemSelectedListener;
+        public OnPrepareListViewListener mOnPrepareListViewListener;
+        public boolean mRecycleOnMeasure = true;
+
+        /**
+         * Interface definition for a callback to be invoked before the ListView
+         * will be bound to an adapter.
+         */
+        public interface OnPrepareListViewListener {
+
+            /**
+             * Called before the ListView is bound to an adapter.
+             * @param listView The ListView that will be shown in the dialog.
+             */
+            void onPrepareListView(ListView listView);
+        }
+
+        @UnsupportedAppUsage
+        public AlertParams(Context context) {
+            mContext = context;
+            mCancelable = true;
+            mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+        }
+
+        @UnsupportedAppUsage
+        public void apply(AlertController dialog) {
+            if (mCustomTitleView != null) {
+                dialog.setCustomTitle(mCustomTitleView);
+            } else {
+                if (mTitle != null) {
+                    dialog.setTitle(mTitle);
+                }
+                if (mIcon != null) {
+                    dialog.setIcon(mIcon);
+                }
+                if (mIconId != 0) {
+                    dialog.setIcon(mIconId);
+                }
+                if (mIconAttrId != 0) {
+                    dialog.setIcon(dialog.getIconAttributeResId(mIconAttrId));
+                }
+            }
+            if (mMessage != null) {
+                dialog.setMessage(mMessage);
+            }
+            if (mPositiveButtonText != null) {
+                dialog.setButton(DialogInterface.BUTTON_POSITIVE, mPositiveButtonText,
+                        mPositiveButtonListener, null);
+            }
+            if (mNegativeButtonText != null) {
+                dialog.setButton(DialogInterface.BUTTON_NEGATIVE, mNegativeButtonText,
+                        mNegativeButtonListener, null);
+            }
+            if (mNeutralButtonText != null) {
+                dialog.setButton(DialogInterface.BUTTON_NEUTRAL, mNeutralButtonText,
+                        mNeutralButtonListener, null);
+            }
+            if (mForceInverseBackground) {
+                dialog.setInverseBackgroundForced(true);
+            }
+            // For a list, the client can either supply an array of items or an
+            // adapter or a cursor
+            if ((mItems != null) || (mCursor != null) || (mAdapter != null)) {
+                createListView(dialog);
+            }
+            if (mView != null) {
+                if (mViewSpacingSpecified) {
+                    dialog.setView(mView, mViewSpacingLeft, mViewSpacingTop, mViewSpacingRight,
+                            mViewSpacingBottom);
+                } else {
+                    dialog.setView(mView);
+                }
+            } else if (mViewLayoutResId != 0) {
+                dialog.setView(mViewLayoutResId);
+            }
+
+            /*
+            dialog.setCancelable(mCancelable);
+            dialog.setOnCancelListener(mOnCancelListener);
+            if (mOnKeyListener != null) {
+                dialog.setOnKeyListener(mOnKeyListener);
+            }
+            */
+        }
+
+        private void createListView(final AlertController dialog) {
+            final RecycleListView listView =
+                    (RecycleListView) mInflater.inflate(dialog.mListLayout, null);
+            final ListAdapter adapter;
+
+            if (mIsMultiChoice) {
+                if (mCursor == null) {
+                    adapter = new ArrayAdapter<CharSequence>(
+                            mContext, dialog.mMultiChoiceItemLayout, android.R.id.text1, mItems) {
+                        @Override
+                        public View getView(int position, View convertView, ViewGroup parent) {
+                            View view = super.getView(position, convertView, parent);
+                            if (mCheckedItems != null) {
+                                boolean isItemChecked = mCheckedItems[position];
+                                if (isItemChecked) {
+                                    listView.setItemChecked(position, true);
+                                }
+                            }
+                            return view;
+                        }
+                    };
+                } else {
+                    adapter = new CursorAdapter(mContext, mCursor, false) {
+                        private final int mLabelIndex;
+                        private final int mIsCheckedIndex;
+
+                        {
+                            final Cursor cursor = getCursor();
+                            mLabelIndex = cursor.getColumnIndexOrThrow(mLabelColumn);
+                            mIsCheckedIndex = cursor.getColumnIndexOrThrow(mIsCheckedColumn);
+                        }
+
+                        @Override
+                        public void bindView(View view, Context context, Cursor cursor) {
+                            CheckedTextView text = (CheckedTextView) view.findViewById(android.R.id.text1);
+                            text.setText(cursor.getString(mLabelIndex));
+                            listView.setItemChecked(
+                                    cursor.getPosition(),
+                                    cursor.getInt(mIsCheckedIndex) == 1);
+                        }
+
+                        @Override
+                        public View newView(Context context, Cursor cursor, ViewGroup parent) {
+                            return mInflater.inflate(dialog.mMultiChoiceItemLayout,
+                                    parent, false);
+                        }
+
+                    };
+                }
+            } else {
+                final int layout;
+                if (mIsSingleChoice) {
+                    layout = dialog.mSingleChoiceItemLayout;
+                } else {
+                    layout = dialog.mListItemLayout;
+                }
+
+                if (mCursor != null) {
+                    adapter = new SimpleCursorAdapter(mContext, layout, mCursor,
+                            new String[] { mLabelColumn }, new int[] { android.R.id.text1 });
+                } else if (mAdapter != null) {
+                    adapter = mAdapter;
+                } else {
+                    adapter = new CheckedItemAdapter(mContext, layout, android.R.id.text1, mItems);
+                }
+            }
+
+            if (mOnPrepareListViewListener != null) {
+                mOnPrepareListViewListener.onPrepareListView(listView);
+            }
+
+            /* Don't directly set the adapter on the ListView as we might
+             * want to add a footer to the ListView later.
+             */
+            dialog.mAdapter = adapter;
+            dialog.mCheckedItem = mCheckedItem;
+
+            if (mOnClickListener != null) {
+                listView.setOnItemClickListener(new OnItemClickListener() {
+                    @Override
+                    public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
+                        mOnClickListener.onClick(dialog.mDialogInterface, position);
+                        if (!mIsSingleChoice) {
+                            dialog.mDialogInterface.dismiss();
+                        }
+                    }
+                });
+            } else if (mOnCheckboxClickListener != null) {
+                listView.setOnItemClickListener(new OnItemClickListener() {
+                    @Override
+                    public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
+                        if (mCheckedItems != null) {
+                            mCheckedItems[position] = listView.isItemChecked(position);
+                        }
+                        mOnCheckboxClickListener.onClick(
+                                dialog.mDialogInterface, position, listView.isItemChecked(position));
+                    }
+                });
+            }
+
+            // Attach a given OnItemSelectedListener to the ListView
+            if (mOnItemSelectedListener != null) {
+                listView.setOnItemSelectedListener(mOnItemSelectedListener);
+            }
+
+            if (mIsSingleChoice) {
+                listView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
+            } else if (mIsMultiChoice) {
+                listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
+            }
+            listView.mRecycleOnMeasure = mRecycleOnMeasure;
+            dialog.mListView = listView;
+        }
+    }
+
+    private static class CheckedItemAdapter extends ArrayAdapter<CharSequence> {
+        public CheckedItemAdapter(Context context, int resource, int textViewResourceId,
+                CharSequence[] objects) {
+            super(context, resource, textViewResourceId, objects);
+        }
+
+        @Override
+        public boolean hasStableIds() {
+            return true;
+        }
+
+        @Override
+        public long getItemId(int position) {
+            return position;
+        }
+    }
+}
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/AlertDialogLayout.java b/packages/PackageInstaller/src/com/android/packageinstaller/AlertDialogLayout.java
new file mode 100644
index 0000000..40fc406
--- /dev/null
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/AlertDialogLayout.java
@@ -0,0 +1,363 @@
+/*
+ * Copyright (C) 2016 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.packageinstaller;
+
+import android.compat.annotation.UnsupportedAppUsage;
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.view.Gravity;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.LinearLayout;
+
+import androidx.annotation.AttrRes;
+import androidx.annotation.Nullable;
+import androidx.annotation.StyleRes;
+
+import com.android.packageinstaller.R;
+
+/**
+ * Special implementation of linear layout that's capable of laying out alert
+ * dialog components.
+ * <p>
+ * A dialog consists of up to three panels. All panels are optional, and a
+ * dialog may contain only a single panel. The panels are laid out according
+ * to the following guidelines:
+ * <ul>
+ *     <li>topPanel: exactly wrap_content</li>
+ *     <li>contentPanel OR customPanel: at most fill_parent, first priority for
+ *         extra space</li>
+ *     <li>buttonPanel: at least minHeight, at most wrap_content, second
+ *         priority for extra space</li>
+ * </ul>
+ */
+public class AlertDialogLayout extends LinearLayout {
+
+    public AlertDialogLayout(@Nullable Context context) {
+        super(context);
+    }
+
+    @UnsupportedAppUsage
+    public AlertDialogLayout(@Nullable Context context, @Nullable AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public AlertDialogLayout(@Nullable Context context, @Nullable AttributeSet attrs,
+            @AttrRes int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+    }
+
+    public AlertDialogLayout(@Nullable Context context, @Nullable AttributeSet attrs,
+            @AttrRes int defStyleAttr, @StyleRes int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        if (!tryOnMeasure(widthMeasureSpec, heightMeasureSpec)) {
+            // Failed to perform custom measurement, let superclass handle it.
+            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+        }
+    }
+
+    private boolean tryOnMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        View topPanel = null;
+        View buttonPanel = null;
+        View middlePanel = null;
+
+        final int count = getChildCount();
+        for (int i = 0; i < count; i++) {
+            final View child = getChildAt(i);
+            if (child.getVisibility() == View.GONE) {
+                continue;
+            }
+
+            final int id = child.getId();
+            switch (id) {
+                case R.id.topPanel:
+                    topPanel = child;
+                    break;
+                case R.id.buttonPanel:
+                    buttonPanel = child;
+                    break;
+                case R.id.contentPanel:
+                case R.id.customPanel:
+                    if (middlePanel != null) {
+                        // Both the content and custom are visible. Abort!
+                        return false;
+                    }
+                    middlePanel = child;
+                    break;
+                default:
+                    // Unknown top-level child. Abort!
+                    return false;
+            }
+        }
+
+        final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
+        final int heightSize = MeasureSpec.getSize(heightMeasureSpec);
+        final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
+
+        int childState = 0;
+        int usedHeight = getPaddingTop() + getPaddingBottom();
+
+        if (topPanel != null) {
+            topPanel.measure(widthMeasureSpec, MeasureSpec.UNSPECIFIED);
+
+            usedHeight += topPanel.getMeasuredHeight();
+            childState = combineMeasuredStates(childState, topPanel.getMeasuredState());
+        }
+
+        int buttonHeight = 0;
+        int buttonWantsHeight = 0;
+        if (buttonPanel != null) {
+            buttonPanel.measure(widthMeasureSpec, MeasureSpec.UNSPECIFIED);
+            buttonHeight = resolveMinimumHeight(buttonPanel);
+            buttonWantsHeight = buttonPanel.getMeasuredHeight() - buttonHeight;
+
+            usedHeight += buttonHeight;
+            childState = combineMeasuredStates(childState, buttonPanel.getMeasuredState());
+        }
+
+        int middleHeight = 0;
+        if (middlePanel != null) {
+            final int childHeightSpec;
+            if (heightMode == MeasureSpec.UNSPECIFIED) {
+                childHeightSpec = MeasureSpec.UNSPECIFIED;
+            } else {
+                childHeightSpec = MeasureSpec.makeMeasureSpec(
+                        Math.max(0, heightSize - usedHeight), heightMode);
+            }
+
+            middlePanel.measure(widthMeasureSpec, childHeightSpec);
+            middleHeight = middlePanel.getMeasuredHeight();
+
+            usedHeight += middleHeight;
+            childState = combineMeasuredStates(childState, middlePanel.getMeasuredState());
+        }
+
+        int remainingHeight = heightSize - usedHeight;
+
+        // Time for the "real" button measure pass. If we have remaining space,
+        // make the button pane bigger up to its target height. Otherwise,
+        // just remeasure the button at whatever height it needs.
+        if (buttonPanel != null) {
+            usedHeight -= buttonHeight;
+
+            final int heightToGive = Math.min(remainingHeight, buttonWantsHeight);
+            if (heightToGive > 0) {
+                remainingHeight -= heightToGive;
+                buttonHeight += heightToGive;
+            }
+
+            final int childHeightSpec = MeasureSpec.makeMeasureSpec(
+                    buttonHeight, MeasureSpec.EXACTLY);
+            buttonPanel.measure(widthMeasureSpec, childHeightSpec);
+
+            usedHeight += buttonPanel.getMeasuredHeight();
+            childState = combineMeasuredStates(childState, buttonPanel.getMeasuredState());
+        }
+
+        // If we still have remaining space, make the middle pane bigger up
+        // to the maximum height.
+        if (middlePanel != null && remainingHeight > 0) {
+            usedHeight -= middleHeight;
+
+            final int heightToGive = remainingHeight;
+            remainingHeight -= heightToGive;
+            middleHeight += heightToGive;
+
+            // Pass the same height mode as we're using for the dialog itself.
+            // If it's EXACTLY, then the middle pane MUST use the entire
+            // height.
+            final int childHeightSpec = MeasureSpec.makeMeasureSpec(
+                    middleHeight, heightMode);
+            middlePanel.measure(widthMeasureSpec, childHeightSpec);
+
+            usedHeight += middlePanel.getMeasuredHeight();
+            childState = combineMeasuredStates(childState, middlePanel.getMeasuredState());
+        }
+
+        // Compute desired width as maximum child width.
+        int maxWidth = 0;
+        for (int i = 0; i < count; i++) {
+            final View child = getChildAt(i);
+            if (child.getVisibility() != View.GONE) {
+                maxWidth = Math.max(maxWidth, child.getMeasuredWidth());
+            }
+        }
+
+        maxWidth += getPaddingLeft() + getPaddingRight();
+
+        final int widthSizeAndState = resolveSizeAndState(maxWidth, widthMeasureSpec, childState);
+        final int heightSizeAndState = resolveSizeAndState(usedHeight, heightMeasureSpec, 0);
+        setMeasuredDimension(widthSizeAndState, heightSizeAndState);
+
+        // If the children weren't already measured EXACTLY, we need to run
+        // another measure pass to for MATCH_PARENT widths.
+        if (widthMode != MeasureSpec.EXACTLY) {
+            forceUniformWidth(count, heightMeasureSpec);
+        }
+
+        return true;
+    }
+
+    /**
+     * Remeasures child views to exactly match the layout's measured width.
+     *
+     * @param count the number of child views
+     * @param heightMeasureSpec the original height measure spec
+     */
+    private void forceUniformWidth(int count, int heightMeasureSpec) {
+        // Pretend that the linear layout has an exact size.
+        final int uniformMeasureSpec = MeasureSpec.makeMeasureSpec(
+                getMeasuredWidth(), MeasureSpec.EXACTLY);
+
+        for (int i = 0; i < count; i++) {
+            final View child = getChildAt(i);
+            if (child.getVisibility() != GONE) {
+                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+                if (lp.width == LayoutParams.MATCH_PARENT) {
+                    // Temporarily force children to reuse their old measured
+                    // height.
+                    final int oldHeight = lp.height;
+                    lp.height = child.getMeasuredHeight();
+
+                    // Remeasure with new dimensions.
+                    measureChildWithMargins(child, uniformMeasureSpec, 0, heightMeasureSpec, 0);
+                    lp.height = oldHeight;
+                }
+            }
+        }
+    }
+
+    /**
+     * Attempts to resolve the minimum height of a view.
+     * <p>
+     * If the view doesn't have a minimum height set and only contains a single
+     * child, attempts to resolve the minimum height of the child view.
+     *
+     * @param v the view whose minimum height to resolve
+     * @return the minimum height
+     */
+    private int resolveMinimumHeight(View v) {
+        final int minHeight = v.getMinimumHeight();
+        if (minHeight > 0) {
+            return minHeight;
+        }
+
+        if (v instanceof ViewGroup) {
+            final ViewGroup vg = (ViewGroup) v;
+            if (vg.getChildCount() == 1) {
+                return resolveMinimumHeight(vg.getChildAt(0));
+            }
+        }
+
+        return 0;
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+        final int paddingLeft = getPaddingLeft();
+        final int paddingRight = getPaddingRight();
+        final int paddingTop = getPaddingTop();
+
+        // Where right end of child should go
+        final int width = right - left;
+        final int childRight = width - paddingRight;
+
+        // Space available for child
+        final int childSpace = width - paddingLeft - paddingRight;
+
+        final int totalLength = getMeasuredHeight();
+        final int count = getChildCount();
+        final int gravity = getGravity();
+        final int majorGravity = gravity & Gravity.VERTICAL_GRAVITY_MASK;
+        final int minorGravity = gravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK;
+
+        int childTop;
+        switch (majorGravity) {
+            case Gravity.BOTTOM:
+                // totalLength contains the padding already
+                childTop = paddingTop + bottom - top - totalLength;
+                break;
+
+            // totalLength contains the padding already
+            case Gravity.CENTER_VERTICAL:
+                childTop = paddingTop + (bottom - top - totalLength) / 2;
+                break;
+
+            case Gravity.TOP:
+            default:
+                childTop = paddingTop;
+                break;
+        }
+
+        final Drawable dividerDrawable = getDividerDrawable();
+        final int dividerHeight = dividerDrawable == null ?
+                0 : dividerDrawable.getIntrinsicHeight();
+
+        for (int i = 0; i < count; i++) {
+            final View child = getChildAt(i);
+            if (child != null && child.getVisibility() != GONE) {
+                final int childWidth = child.getMeasuredWidth();
+                final int childHeight = child.getMeasuredHeight();
+
+                final LayoutParams lp =
+                        (LayoutParams) child.getLayoutParams();
+
+                int layoutGravity = lp.gravity;
+                if (layoutGravity < 0) {
+                    layoutGravity = minorGravity;
+                }
+                final int layoutDirection = getLayoutDirection();
+                final int absoluteGravity = Gravity.getAbsoluteGravity(
+                        layoutGravity, layoutDirection);
+
+                final int childLeft;
+                switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
+                    case Gravity.CENTER_HORIZONTAL:
+                        childLeft = paddingLeft + ((childSpace - childWidth) / 2)
+                                + lp.leftMargin - lp.rightMargin;
+                        break;
+
+                    case Gravity.RIGHT:
+                        childLeft = childRight - childWidth - lp.rightMargin;
+                        break;
+
+                    case Gravity.LEFT:
+                    default:
+                        childLeft = paddingLeft + lp.leftMargin;
+                        break;
+                }
+
+                if (hasDividerBeforeChildAt(i)) {
+                    childTop += dividerHeight;
+                }
+
+                childTop += lp.topMargin;
+                setChildFrame(child, childLeft, childTop, childWidth, childHeight);
+                childTop += childHeight + lp.bottomMargin;
+            }
+        }
+    }
+
+    private void setChildFrame(View child, int left, int top, int width, int height) {
+        child.layout(left, top, left + width, top + height);
+    }
+}
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/ButtonBarLayout.java b/packages/PackageInstaller/src/com/android/packageinstaller/ButtonBarLayout.java
new file mode 100644
index 0000000..826c076
--- /dev/null
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/ButtonBarLayout.java
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2015 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.packageinstaller;
+
+import android.compat.annotation.UnsupportedAppUsage;
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.util.AttributeSet;
+import android.view.Gravity;
+import android.view.View;
+import android.widget.LinearLayout;
+
+import com.android.packageinstaller.R;
+
+/**
+ * An extension of LinearLayout that automatically switches to vertical
+ * orientation when it can't fit its child views horizontally.
+ */
+public class ButtonBarLayout extends LinearLayout {
+    /** Amount of the second button to "peek" above the fold when stacked. */
+    private static final int PEEK_BUTTON_DP = 16;
+
+    /** Whether the current configuration allows stacking. */
+    private boolean mAllowStacking;
+
+    private int mLastWidthSize = -1;
+
+    private int mMinimumHeight = 0;
+
+    @UnsupportedAppUsage
+    public ButtonBarLayout(Context context, AttributeSet attrs) {
+        super(context, attrs);
+
+        final TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.ButtonBarLayout);
+        mAllowStacking = ta.getBoolean(R.styleable.ButtonBarLayout_allowStacking, true);
+        ta.recycle();
+    }
+
+    public void setAllowStacking(boolean allowStacking) {
+        if (mAllowStacking != allowStacking) {
+            mAllowStacking = allowStacking;
+            if (!mAllowStacking && getOrientation() == LinearLayout.VERTICAL) {
+                setStacked(false);
+            }
+            requestLayout();
+        }
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        final int widthSize = MeasureSpec.getSize(widthMeasureSpec);
+
+        if (mAllowStacking) {
+            if (widthSize > mLastWidthSize && isStacked()) {
+                // We're being measured wider this time, try un-stacking.
+                setStacked(false);
+            }
+
+            mLastWidthSize = widthSize;
+        }
+
+        boolean needsRemeasure = false;
+
+        // If we're not stacked, make sure the measure spec is AT_MOST rather
+        // than EXACTLY. This ensures that we'll still get TOO_SMALL so that we
+        // know to stack the buttons.
+        final int initialWidthMeasureSpec;
+        if (!isStacked() && MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY) {
+            initialWidthMeasureSpec = MeasureSpec.makeMeasureSpec(widthSize, MeasureSpec.AT_MOST);
+
+            // We'll need to remeasure again to fill excess space.
+            needsRemeasure = true;
+        } else {
+            initialWidthMeasureSpec = widthMeasureSpec;
+        }
+
+        super.onMeasure(initialWidthMeasureSpec, heightMeasureSpec);
+
+        if (mAllowStacking && !isStacked()) {
+            final int measuredWidth = getMeasuredWidthAndState();
+            final int measuredWidthState = measuredWidth & MEASURED_STATE_MASK;
+            if (measuredWidthState == MEASURED_STATE_TOO_SMALL) {
+                setStacked(true);
+
+                // Measure again in the new orientation.
+                needsRemeasure = true;
+            }
+        }
+
+        if (needsRemeasure) {
+            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+        }
+
+        // Compute minimum height such that, when stacked, some portion of the
+        // second button is visible.
+        int minHeight = 0;
+        final int firstVisible = getNextVisibleChildIndex(0);
+        if (firstVisible >= 0) {
+            final View firstButton = getChildAt(firstVisible);
+            final LayoutParams firstParams = (LayoutParams) firstButton.getLayoutParams();
+            minHeight += getPaddingTop() + firstButton.getMeasuredHeight()
+                    + firstParams.topMargin + firstParams.bottomMargin;
+            if (isStacked()) {
+                final int secondVisible = getNextVisibleChildIndex(firstVisible + 1);
+                if (secondVisible >= 0) {
+                    minHeight += getChildAt(secondVisible).getPaddingTop()
+                            + PEEK_BUTTON_DP * getResources().getDisplayMetrics().density;
+                }
+            } else {
+                minHeight += getPaddingBottom();
+            }
+        }
+
+        if (getMinimumHeight() != minHeight) {
+            setMinimumHeight(minHeight);
+        }
+    }
+
+    private int getNextVisibleChildIndex(int index) {
+        for (int i = index, count = getChildCount(); i < count; i++) {
+            if (getChildAt(i).getVisibility() == View.VISIBLE) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
+    @Override
+    public int getMinimumHeight() {
+        return Math.max(mMinimumHeight, super.getMinimumHeight());
+    }
+
+    private void setStacked(boolean stacked) {
+        setOrientation(stacked ? LinearLayout.VERTICAL : LinearLayout.HORIZONTAL);
+        setGravity(stacked ? Gravity.END : Gravity.BOTTOM);
+
+        final View spacer = findViewById(R.id.spacer);
+        if (spacer != null) {
+            spacer.setVisibility(stacked ? View.GONE : View.INVISIBLE);
+        }
+
+        // Reverse the child order. This is specific to the Material button
+        // bar's layout XML and will probably not generalize.
+        final int childCount = getChildCount();
+        for (int i = childCount - 2; i >= 0; i--) {
+            bringChildToFront(getChildAt(i));
+        }
+    }
+
+    private boolean isStacked() {
+        return getOrientation() == LinearLayout.VERTICAL;
+    }
+}
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/DialogTitle.java b/packages/PackageInstaller/src/com/android/packageinstaller/DialogTitle.java
new file mode 100644
index 0000000..921a904
--- /dev/null
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/DialogTitle.java
@@ -0,0 +1,80 @@
+/* 
+ * Copyright (C) 2008 Google Inc.
+ *
+ * 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.packageinstaller;
+
+import android.compat.annotation.UnsupportedAppUsage;
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.text.Layout;
+import android.util.AttributeSet;
+import android.util.TypedValue;
+import android.widget.TextView;
+
+import com.android.packageinstaller.R;
+/**
+ * Used by dialogs to change the font size and number of lines to try to fit
+ * the text to the available space.
+ */
+public class DialogTitle extends TextView {
+
+    public DialogTitle(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+    }
+
+    public DialogTitle(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+    }
+
+    @UnsupportedAppUsage
+    public DialogTitle(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public DialogTitle(Context context) {
+        super(context);
+    }
+    
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+
+        final Layout layout = getLayout();
+        if (layout != null) {
+            final int lineCount = layout.getLineCount();
+            if (lineCount > 0) {
+                final int ellipsisCount = layout.getEllipsisCount(lineCount - 1);
+                if (ellipsisCount > 0) {
+                    setSingleLine(false);
+                    setMaxLines(2);
+
+                    final TypedArray a = getContext().obtainStyledAttributes(null,
+                            R.styleable.TextAppearance, android.R.attr.textAppearanceMedium,
+                            android.R.style.TextAppearance_Medium);
+                    final int textSize = a.getDimensionPixelSize(
+                            R.styleable.TextAppearance_textSize, 0);
+                    if (textSize != 0) {
+                        // textSize is already expressed in pixels
+                        setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize);
+                    }
+                    a.recycle();
+
+                    super.onMeasure(widthMeasureSpec, heightMeasureSpec);      
+                }
+            }
+        }
+    }
+}
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/MicroAlertController.java b/packages/PackageInstaller/src/com/android/packageinstaller/MicroAlertController.java
new file mode 100644
index 0000000..0d77f35
--- /dev/null
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/MicroAlertController.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2016 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.packageinstaller;
+
+import android.content.Context;
+import android.content.DialogInterface;
+import android.view.Gravity;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.Window;
+import android.widget.FrameLayout;
+import android.widget.ScrollView;
+import android.widget.TextView;
+
+
+public class MicroAlertController extends AlertController {
+    public MicroAlertController(Context context, DialogInterface di, Window window) {
+        super(context, di, window);
+    }
+
+    @Override
+    protected void setupContent(ViewGroup contentPanel) {
+        // Special case for small screen - the scroll view is higher in hierarchy
+        mScrollView = (ScrollView) mWindow.findViewById(R.id.scrollView);
+
+        // Special case for users that only want to display a String
+        mMessageView = (TextView) contentPanel.findViewById(R.id.message);
+        if (mMessageView == null) {
+            return;
+        }
+
+        if (mMessage != null) {
+            mMessageView.setText(mMessage);
+        } else {
+            // no message, remove associated views
+            mMessageView.setVisibility(View.GONE);
+            contentPanel.removeView(mMessageView);
+
+            if (mListView != null) {
+                // has ListView, swap scrollView with ListView
+
+                // move topPanel into top of scrollParent
+                View topPanel = mScrollView.findViewById(R.id.topPanel);
+                ((ViewGroup) topPanel.getParent()).removeView(topPanel);
+                FrameLayout.LayoutParams topParams =
+                        new FrameLayout.LayoutParams(topPanel.getLayoutParams());
+                topParams.gravity = Gravity.TOP;
+                topPanel.setLayoutParams(topParams);
+
+                // move buttonPanel into bottom of scrollParent
+                View buttonPanel = mScrollView.findViewById(R.id.buttonPanel);
+                ((ViewGroup) buttonPanel.getParent()).removeView(buttonPanel);
+                FrameLayout.LayoutParams buttonParams =
+                        new FrameLayout.LayoutParams(buttonPanel.getLayoutParams());
+                buttonParams.gravity = Gravity.BOTTOM;
+                buttonPanel.setLayoutParams(buttonParams);
+
+                // remove scrollview
+                final ViewGroup scrollParent = (ViewGroup) mScrollView.getParent();
+                final int childIndex = scrollParent.indexOfChild(mScrollView);
+                scrollParent.removeViewAt(childIndex);
+
+                // add list view
+                scrollParent.addView(mListView,
+                        new ViewGroup.LayoutParams(
+                                ViewGroup.LayoutParams.MATCH_PARENT,
+                                ViewGroup.LayoutParams.MATCH_PARENT));
+
+                // add top and button panel
+                scrollParent.addView(topPanel);
+                scrollParent.addView(buttonPanel);
+            } else {
+                // no content, just hide everything
+                contentPanel.setVisibility(View.GONE);
+            }
+        }
+    }
+
+    @Override
+    protected void setupTitle(ViewGroup topPanel) {
+        super.setupTitle(topPanel);
+        if (topPanel.getVisibility() == View.GONE) {
+            topPanel.setVisibility(View.INVISIBLE);
+        }
+    }
+
+    @Override
+    protected void setupButtons(ViewGroup buttonPanel) {
+        super.setupButtons(buttonPanel);
+        if (buttonPanel.getVisibility() == View.GONE) {
+            buttonPanel.setVisibility(View.INVISIBLE);
+        }
+    }
+}