Fix request role dialog buttons missing with too many items.

The "don't ask again" check box was added as a custom view to the
alert dialog, and because we were using the list view in content panel
at the same time, AlertDialogLayout refuses to handle layout with its
special logic when both panels are used, and causes list view to take
up all the space with no space left for button bar. This can happen
for any device in landscape mode if there are a lot of candidate apps.

This CL uses a custom list view inside the custom view added to the
alert dialog, so that AlertController will hide the content
panel. This way AlertDialogLayout will only see the custom panel and
layout properly.

Fixes: 135549535
Test: manual && atest RoleManagerTest
Change-Id: I9e376279f10e8258f531ab27349c8cfb80d6f575
diff --git a/res/layout/request_role_view.xml b/res/layout/request_role_view.xml
index f0b86df..44430a5 100644
--- a/res/layout/request_role_view.xml
+++ b/res/layout/request_role_view.xml
@@ -16,12 +16,16 @@
   ~ limitations under the License.
   -->
 
-<FrameLayout
+<LinearLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
     style="@style/RequestRoleView">
 
+    <ListView
+        android:id="@+id/list"
+        style="@style/RequestRoleViewListView" />
+
     <CheckBox
         android:id="@+id/dont_ask_again"
         android:text="@string/request_role_dont_ask_again"
         style="@style/RequestRoleViewCheckbox" />
-</FrameLayout>
+</LinearLayout>
diff --git a/res/values/overlayable.xml b/res/values/overlayable.xml
index 82708ed..6d0dda5 100644
--- a/res/values/overlayable.xml
+++ b/res/values/overlayable.xml
@@ -164,6 +164,7 @@
 
             <!-- START REQUEST ROLE DIALOG VIEW -->
             <item type="style" name="RequestRoleView" />
+            <item type="style" name="RequestRoleViewListView" />
             <item type="style" name="RequestRoleViewCheckbox" />
             <!-- END REQUEST ROLE DIALOG VIEW -->
 
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 6469cbd..5516dbe 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -711,15 +711,26 @@
     <style name="RequestRoleView">
         <item name="android:layout_width">match_parent</item>
         <item name="android:layout_height">wrap_content</item>
-        <item name="android:paddingStart">?android:dialogPreferredPadding</item>
-        <item name="android:paddingEnd">?android:dialogPreferredPadding</item>
-        <item name="android:clipChildren">false</item>
-        <item name="android:clipToPadding">false</item>
+        <!-- @android:dimen/dialog_title_divider_material -->
+        <item name="android:paddingTop">8dp</item>
+        <item name="android:orientation">vertical</item>
+    </style>
+
+    <style name="RequestRoleViewListView">
+        <item name="android:layout_width">match_parent</item>
+        <item name="android:layout_height">0dp</item>
+        <item name="android:layout_weight">1</item>
+        <item name="android:cacheColorHint">@null</item>
+        <item name="android:divider">?android:listDividerAlertDialog</item>
+        <item name="android:overScrollMode">ifContentScrolls</item>
+        <item name="android:scrollIndicators">top|bottom</item>
     </style>
 
     <style name="RequestRoleViewCheckbox">
         <item name="android:layout_width">match_parent</item>
         <item name="android:layout_height">wrap_content</item>
+        <item name="android:layout_marginStart">?android:dialogPreferredPadding</item>
+        <item name="android:layout_marginEnd">?android:dialogPreferredPadding</item>
         <item name="android:minHeight">?android:listPreferredItemHeightSmall</item>
         <item name="android:paddingStart">16dp</item>
         <item name="android:textAppearance">@style/android:TextAppearance.Material.Subhead</item>
diff --git a/src/com/android/packageinstaller/role/ui/RequestRoleFragment.java b/src/com/android/packageinstaller/role/ui/RequestRoleFragment.java
index 55ea3dd..7991a2f 100644
--- a/src/com/android/packageinstaller/role/ui/RequestRoleFragment.java
+++ b/src/com/android/packageinstaller/role/ui/RequestRoleFragment.java
@@ -76,7 +76,9 @@
 
     private Role mRole;
 
+    private ListView mListView;
     private Adapter mAdapter;
+    @Nullable
     private CheckBox mDontAskAgainCheck;
 
     private RequestRoleViewModel mViewModel;
@@ -145,20 +147,27 @@
 
         LayoutInflater inflater = LayoutInflater.from(context);
         View titleLayout = inflater.inflate(R.layout.request_role_title, null);
-        ImageView iconImage = titleLayout.findViewById(R.id.icon);
+        ImageView iconImage = titleLayout.requireViewById(R.id.icon);
         iconImage.setImageDrawable(icon);
-        TextView titleText = titleLayout.findViewById(R.id.title);
+        TextView titleText = titleLayout.requireViewById(R.id.title);
         titleText.setText(title);
 
-        mAdapter = new Adapter(mRole);
+        View viewLayout = inflater.inflate(R.layout.request_role_view, null);
+        mListView = viewLayout.requireViewById(R.id.list);
+        mListView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
+        mListView.setOnItemClickListener((parent, view, position, id) -> onItemClicked(position));
+        mAdapter = new Adapter(mListView, mRole);
         if (savedInstanceState != null) {
             mAdapter.onRestoreInstanceState(savedInstanceState);
         }
+        mListView.setAdapter(mAdapter);
 
-        View viewLayout = null;
-        if (UserDeniedManager.getInstance(context).isDeniedOnce(mRoleName, mPackageName)) {
-            viewLayout = inflater.inflate(R.layout.request_role_view, null);
-            mDontAskAgainCheck = viewLayout.findViewById(R.id.dont_ask_again);
+        CheckBox dontAskAgainCheck = viewLayout.requireViewById(R.id.dont_ask_again);
+        boolean isDeniedOnce = UserDeniedManager.getInstance(context).isDeniedOnce(mRoleName,
+                mPackageName);
+        dontAskAgainCheck.setVisibility(isDeniedOnce ? View.VISIBLE : View.GONE);
+        if (isDeniedOnce) {
+            mDontAskAgainCheck = dontAskAgainCheck;
             mDontAskAgainCheck.setOnClickListener(view -> updateUi());
             if (savedInstanceState != null) {
                 boolean dontAskAgain = savedInstanceState.getBoolean(STATE_DONT_ASK_AGAIN);
@@ -169,8 +178,6 @@
 
         AlertDialog dialog = builder
                 .setCustomTitle(titleLayout)
-                .setSingleChoiceItems(mAdapter, AdapterView.INVALID_POSITION, (dialog2, which) ->
-                        onItemClicked(which))
                 .setView(viewLayout)
                 // Set the positive button listener later to avoid the automatic dismiss behavior.
                 .setPositiveButton(R.string.request_role_set_as_default, null)
@@ -216,8 +223,6 @@
         };
         mPackageRemovalMonitor.register();
 
-        mAdapter.setListView(getDialog().getListView());
-
         // Postponed to onStart() so that the list view in dialog is created.
         mViewModel = ViewModelProviders.of(this, new RequestRoleViewModel.Factory(mRole,
                 requireActivity().getApplication())).get(RequestRoleViewModel.class);
@@ -333,12 +338,12 @@
     }
 
     private void updateUi() {
-        AlertDialog dialog = getDialog();
         boolean enabled = mViewModel.getManageRoleHolderStateLiveData().getValue()
                 == ManageRoleHolderStateLiveData.STATE_IDLE;
-        dialog.getListView().setEnabled(enabled);
+        mListView.setEnabled(enabled);
         boolean dontAskAgain = mDontAskAgainCheck != null && mDontAskAgainCheck.isChecked();
         mAdapter.setDontAskAgain(dontAskAgain);
+        AlertDialog dialog = getDialog();
         dialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(enabled && (dontAskAgain
                 || !mAdapter.isHolderApplicationChecked()));
         dialog.getButton(AlertDialog.BUTTON_NEGATIVE).setEnabled(enabled);
@@ -465,6 +470,9 @@
         private static final int LAYOUT_TRANSITION_DURATION_MILLIS = 150;
 
         @NonNull
+        private final ListView mListView;
+
+        @NonNull
         private final Role mRole;
 
         // We'll use a null to represent the "None" item.
@@ -474,8 +482,6 @@
 
         private boolean mHasHolderApplication;
 
-        private ListView mListView;
-
         private boolean mDontAskAgain;
 
         // If user has ever clicked an item to mark it as checked, we no longer automatically mark
@@ -487,7 +493,8 @@
         @Nullable
         private String mPendingUserCheckedPackageName;
 
-        Adapter(@NonNull Role role) {
+        Adapter(@NonNull ListView listView, @NonNull Role role) {
+            mListView = listView;
             mRole = role;
         }
 
@@ -506,10 +513,6 @@
             }
         }
 
-        public void setListView(@NonNull ListView listView) {
-            mListView = listView;
-        }
-
         public void setDontAskAgain(boolean dontAskAgain) {
             if (mDontAskAgain == dontAskAgain) {
                 return;
@@ -732,11 +735,10 @@
             public final TextView subtitleText;
 
             ViewHolder(@NonNull View view) {
-                iconImage = Objects.requireNonNull(view.findViewById(R.id.icon));
-                titleAndSubtitleLayout = Objects.requireNonNull(view.findViewById(
-                        R.id.title_and_subtitle));
-                titleText = Objects.requireNonNull(view.findViewById(R.id.title));
-                subtitleText = Objects.requireNonNull(view.findViewById(R.id.subtitle));
+                iconImage = view.requireViewById(R.id.icon);
+                titleAndSubtitleLayout = view.requireViewById(R.id.title_and_subtitle);
+                titleText = view.requireViewById(R.id.title);
+                subtitleText = view.requireViewById(R.id.subtitle);
             }
         }
     }