Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9199155a authored by Svetoslav Ganov's avatar Svetoslav Ganov
Browse files

Make the permission request dialog's layout robust

The old implementation was relying on a fixed window size
where the content is positioned by a custom layout manager.
It is possible however that subsequent permissions requests
do not fit in the window as its size is computed based on
the content of the first permissions request. There were
also cases where the content is chopped after a rotation
as the dialog size width was not re-evaluated while it should
be. Further, animation from one permission request state
to another was not properly done resulting in content
being chopped off in some cases.

The current approach is to have a dialog width for the
content activity but the height is as tall as the screen
allowing us to fit arbitrary large permission request
content. Also we are resetting the fixed width on a
configuration change so the dialog is robust to adjust
size as needed.

bug:24679384
bug:25755378

Change-Id: I4d23f81d8e59ce23bf9a27155ebb5ec6e2e6752c
(cherry picked from commit c6dc4bb52b07886346b02b326c5c32a8299ed73e)
parent 6e1457c7
Loading
Loading
Loading
Loading
+54 −51
Original line number Diff line number Diff line
@@ -17,26 +17,36 @@
<com.android.packageinstaller.permission.ui.ManualLayoutFrame
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" >
    android:layout_height="fill_parent"
    android:clipChildren="false">

    <LinearLayout
        android:id="@+id/dialog_container"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:paddingTop="24dip"
        android:paddingBottom="8dip"
        android:paddingStart="22dip"
        android:paddingEnd="16dip"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical">

        <FrameLayout
            android:id="@+id/desc_container"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" >
            android:layout_height="wrap_content"
            android:paddingTop="24dip"
            android:paddingStart="22dip"
            android:paddingEnd="16dip"
            android:background="?android:attr/colorBackgroundFloating">
            <include
                layout="@layout/permission_description" />
        </FrameLayout>

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            android:paddingBottom="8dip"
            android:paddingStart="22dip"
            android:paddingEnd="16dip"
            android:background="?android:attr/colorBackgroundFloating">

            <CheckBox
                android:id="@+id/do_not_ask_checkbox"
                android:layout_width="fill_parent"
@@ -50,7 +60,7 @@
            <com.android.packageinstaller.permission.ui.ButtonBarLayout
                android:id="@+id/button_group"
                android:layout_width="match_parent"
            android:layout_height="match_parent"
                android:layout_height="wrap_content"
                android:orientation="horizontal"
                android:paddingStart="2dip"
                android:paddingTop="16dip">
@@ -59,7 +69,6 @@
                    android:id="@+id/current_page_text"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                android:layout_gravity="start|bottom"
                    android:paddingTop="4dp"
                    android:paddingBottom="4dp"
                    android:paddingEnd="12dp"
@@ -77,12 +86,6 @@
                    android:visibility="invisible" >
                </Space>

            <LinearLayout
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="end"
                android:orientation="horizontal" >

                <Button
                    android:id="@+id/permission_deny_button"
                    android:layout_width="wrap_content"
@@ -100,10 +103,10 @@
                    android:text="@string/grant_dialog_button_allow" >
                </Button>

            </LinearLayout>

            </com.android.packageinstaller.permission.ui.ButtonBarLayout>

        </LinearLayout>

    </LinearLayout>

</com.android.packageinstaller.permission.ui.ManualLayoutFrame>
+3 −0
Original line number Diff line number Diff line
@@ -23,6 +23,9 @@

    <style name="GrantPermissions"
           parent="@android:style/Theme.DeviceDefault.Light.Dialog.NoActionBar">
        <item name="*android:windowFixedHeightMajor">100%</item>
        <item name="*android:windowFixedHeightMinor">100%</item>
        <item name="android:windowBackground">@android:color/transparent</item>
    </style>

</resources>
+17 −1
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@ import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.PermissionInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Typeface;
import android.graphics.drawable.Icon;
@@ -44,8 +45,8 @@ import com.android.packageinstaller.R;
import com.android.packageinstaller.permission.model.AppPermissionGroup;
import com.android.packageinstaller.permission.model.AppPermissions;
import com.android.packageinstaller.permission.model.Permission;
import com.android.packageinstaller.permission.ui.handheld.GrantPermissionsViewHandlerImpl;
import com.android.packageinstaller.permission.utils.SafetyNetLogger;
import com.android.packageinstaller.permission.utils.Utils;

import java.util.ArrayList;
import java.util.LinkedHashMap;
@@ -175,6 +176,21 @@ public class GrantPermissionsActivity extends OverlayTouchActivity
        }
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        // We need to relayout the window as dialog width may be
        // different in landscape vs portrait which affect the min
        // window height needed to show all content. We have to
        // re-add the window to force it to be resized if needed.
        View decor = getWindow().getDecorView();
        getWindowManager().removeViewImmediate(decor);
        getWindowManager().addView(decor, decor.getLayoutParams());
        if (mViewHandler instanceof GrantPermissionsViewHandlerImpl) {
            ((GrantPermissionsViewHandlerImpl) mViewHandler).onConfigurationChanged();
        }
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        View rootView = getWindow().getDecorView();
+29 −31
Original line number Diff line number Diff line
@@ -18,58 +18,56 @@ package com.android.packageinstaller.permission.ui;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.widget.FrameLayout;
import android.view.ViewGroup;

/**
 * Allows one standard layout pass, but afterwards holds getMeasuredHeight constant,
 * however still allows drawing larger at the size needed by its children.  This allows
 * a dialog to tell the window the height is constant (with keeps its position constant)
 * but allows the view to grow downwards for animation.
 */
public class ManualLayoutFrame extends FrameLayout {

    private int mDesiredHeight;
    private int mHeight;
public class ManualLayoutFrame extends ViewGroup {
    private int mContentBottom;
    private int mWidth;

    private View mOffsetView;

    public ManualLayoutFrame(Context context, AttributeSet attrs) {
        super(context, attrs);
        setClipChildren(false);
        setClipToPadding(false);
    }

    public int getLayoutHeight() {
        return mDesiredHeight;
    public void onConfigurationChanged() {
        mContentBottom = 0;
        mWidth = 0;
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        if (mWidth != 0) {
            // Keep the width constant to avoid weirdness.
            int newWidth = mWidth;
            final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
            switch (widthMode) {
                case MeasureSpec.AT_MOST: {
                    newWidth = Math.min(mWidth, MeasureSpec.getSize(widthMeasureSpec));
                } break;
                case MeasureSpec.EXACTLY: {
                    newWidth = MeasureSpec.getSize(widthMeasureSpec);
                } break;
            }
            if (newWidth != mWidth) {
                mWidth = newWidth;
            }
            widthMeasureSpec = MeasureSpec.makeMeasureSpec(mWidth, MeasureSpec.EXACTLY);
        }
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        mDesiredHeight = getMeasuredHeight();
        if (mHeight == 0 && mDesiredHeight != 0) {
            // Record the first non-zero width and height, this will be the height henceforth.
            mHeight = mDesiredHeight;
        if (mWidth == 0) {
            mWidth = getMeasuredWidth();
        }
        if (mHeight != 0) {
            // Always report the same height
            setMeasuredDimension(getMeasuredWidth(), mHeight);
        }

        measureChild(getChildAt(0), widthMeasureSpec, heightMeasureSpec);
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        if (mDesiredHeight != 0) {
            // Draw at height we expect to be.
            setBottom(getTop() + mDesiredHeight);
            bottom = top + mDesiredHeight;
        View content = getChildAt(0);
        if (mContentBottom == 0) {
            mContentBottom = (getMeasuredHeight() + content.getMeasuredHeight()) / 2;
        }
        super.onLayout(changed, left, top, right, bottom);
        final int contentLeft = (getMeasuredWidth() - content.getMeasuredWidth()) / 2;
        final int contentTop = mContentBottom - content.getMeasuredHeight();
        final int contentRight = contentLeft + content.getMeasuredWidth();
        content.layout(contentLeft, contentTop, contentRight, mContentBottom);
    }
}
+105 −211

File changed.

Preview size limit exceeded, changes collapsed.