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

Commit 78056370 authored by Michael Wright's avatar Michael Wright
Browse files

DO NOT MERGE. Truncate and ellipsize app name if too long for dialog.

If the given app name is too long for the permissions dialog, then
it can push the warning that the application will be able to record
the screen below the fold, letting the app basically set its own
dialog message in a way that a user would be difficult to detect as
fraudulant.

Bug: 23345192
Change-Id: If5881ca75d5c155ef5174351d245dbc3abdaa584
parent a1be8b43
Loading
Loading
Loading
Loading
+54 −2
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.graphics.Typeface;
import android.media.projection.MediaProjectionManager;
import android.media.projection.IMediaProjectionManager;
import android.media.projection.IMediaProjection;
@@ -31,9 +32,17 @@ import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.text.BidiFormatter;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.TextPaint;
import android.text.TextUtils;
import android.text.style.StyleSpan;
import android.util.Log;
import android.util.TypedValue;
import android.view.LayoutInflater;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.TextView;
@@ -47,6 +56,8 @@ public class MediaProjectionPermissionActivity extends Activity
        implements DialogInterface.OnClickListener, CheckBox.OnCheckedChangeListener,
        DialogInterface.OnCancelListener {
    private static final String TAG = "MediaProjectionPermissionActivity";
    private static final float MAX_APP_NAME_SIZE_PX = 500f;
    private static final String ELLIPSIS = "\u2026";

    private boolean mPermanentGrant;
    private String mPackageName;
@@ -92,11 +103,49 @@ public class MediaProjectionPermissionActivity extends Activity
            return;
        }

        String appName = aInfo.loadLabel(packageManager).toString();
        TextPaint paint = new TextPaint();
        paint.setTextSize(42);

        String label = aInfo.loadLabel(packageManager).toString();

        // If the label contains new line characters it may push the security
        // message below the fold of the dialog. Labels shouldn't have new line
        // characters anyways, so just truncate the message the first time one
        // is seen.
        final int labelLength = label.length();
        int offset = 0;
        while (offset < labelLength) {
            final int codePoint = label.codePointAt(offset);
            final int type = Character.getType(codePoint);
            if (type == Character.LINE_SEPARATOR
                    || type == Character.CONTROL
                    || type == Character.PARAGRAPH_SEPARATOR) {
                label = label.substring(0, offset) + ELLIPSIS;
                break;
            }
            offset += Character.charCount(codePoint);
        }

        if (label.isEmpty()) {
            label = mPackageName;
        }

        String unsanitizedAppName = TextUtils.ellipsize(label,
                paint, MAX_APP_NAME_SIZE_PX, TextUtils.TruncateAt.END).toString();
        String appName = BidiFormatter.getInstance().unicodeWrap(unsanitizedAppName);

        String actionText = getString(R.string.media_projection_dialog_text, appName);
        SpannableString message = new SpannableString(actionText);

        int appNameIndex = actionText.indexOf(appName);
        if (appNameIndex >= 0) {
            message.setSpan(new StyleSpan(Typeface.BOLD),
                    appNameIndex, appNameIndex + appName.length(), 0);
        }

        mDialog = new AlertDialog.Builder(this)
                .setIcon(aInfo.loadIcon(packageManager))
                .setMessage(getString(R.string.media_projection_dialog_text, appName))
                .setMessage(message)
                .setPositiveButton(R.string.media_projection_action_text, this)
                .setNegativeButton(android.R.string.cancel, this)
                .setView(R.layout.remember_permission_checkbox)
@@ -105,6 +154,9 @@ public class MediaProjectionPermissionActivity extends Activity

        mDialog.create();

        Button btn = mDialog.getButton(DialogInterface.BUTTON_POSITIVE);
        btn.getRootView().setFilterTouchesWhenObscured(true);

        ((CheckBox) mDialog.findViewById(R.id.remember)).setOnCheckedChangeListener(this);
        mDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);