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

Commit ce92347e authored by Automerger Merge Worker's avatar Automerger Merge Worker
Browse files

Merge "Unify toast presentation code" into rvc-dev am: 9b256a21

Change-Id: I810c0a37d1f63280e11e2d3270032e0c7f45e7f0
parents a438c3b6 9b256a21
Loading
Loading
Loading
Loading
+14 −69
Original line number Diff line number Diff line
@@ -31,9 +31,7 @@ import android.compat.annotation.ChangeId;
import android.compat.annotation.EnabledAfter;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.PixelFormat;
import android.os.Binder;
import android.os.Build;
import android.os.Handler;
@@ -43,11 +41,8 @@ import android.os.Message;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.WindowManager;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;

import com.android.internal.annotations.GuardedBy;
@@ -122,6 +117,7 @@ public class Toast {
    private final Binder mToken;
    private final Context mContext;
    private final Handler mHandler;
    private final ToastPresenter mPresenter;
    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
    final TN mTN;
    @UnsupportedAppUsage
@@ -172,7 +168,8 @@ public class Toast {
        looper = getLooper(looper);
        mHandler = new Handler(looper);
        mCallbacks = new ArrayList<>();
        mTN = new TN(context.getPackageName(), mToken, mCallbacks, looper);
        mPresenter = new ToastPresenter(context, AccessibilityManager.getInstance(context));
        mTN = new TN(mPresenter, context.getPackageName(), mToken, mCallbacks, looper);
        mTN.mY = context.getResources().getDimensionPixelSize(
                com.android.internal.R.dimen.toast_y_offset);
        mTN.mGravity = context.getResources().getInteger(
@@ -504,13 +501,7 @@ public class Toast {
            return result;
        } else {
            Toast result = new Toast(context, looper);

            LayoutInflater inflate = (LayoutInflater)
                    context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            View v = inflate.inflate(com.android.internal.R.layout.transient_notification, null);
            TextView tv = (TextView) v.findViewById(com.android.internal.R.id.message);
            tv.setText(text);

            View v = result.mPresenter.getTextToastView(text);
            result.mNextView = v;
            result.mDuration = duration;

@@ -611,34 +602,20 @@ public class Toast {

        final String mPackageName;
        final Binder mToken;
        private final ToastPresenter mPresenter;

        @GuardedBy("mCallbacks")
        private final List<Callback> mCallbacks;

        static final long SHORT_DURATION_TIMEOUT = 4000;
        static final long LONG_DURATION_TIMEOUT = 7000;

        /**
         * Creates a {@link ITransientNotification} object.
         *
         * The parameter {@code callbacks} is not copied and is accessed with itself as its own
         * lock.
         */
        TN(String packageName, Binder token, List<Callback> callbacks, @Nullable Looper looper) {
            // XXX This should be changed to use a Dialog, with a Theme.Toast
            // defined that sets up the layout params appropriately.
            final WindowManager.LayoutParams params = mParams;
            params.height = WindowManager.LayoutParams.WRAP_CONTENT;
            params.width = WindowManager.LayoutParams.WRAP_CONTENT;
            params.format = PixelFormat.TRANSLUCENT;
            params.windowAnimations = com.android.internal.R.style.Animation_Toast;
            params.type = WindowManager.LayoutParams.TYPE_TOAST;
            params.setFitInsetsIgnoringVisibility(true);
            params.setTitle("Toast");
            params.flags = WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
                    | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                    | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;

        TN(ToastPresenter presenter, String packageName, Binder token, List<Callback> callbacks,
                @Nullable Looper looper) {
            mPresenter = presenter;
            mPackageName = packageName;
            mToken = token;
            mCallbacks = callbacks;
@@ -673,6 +650,8 @@ public class Toast {
                    }
                }
            };

            presenter.startLayoutParams(mParams);
        }

        private List<Callback> getCallbacks() {
@@ -718,30 +697,12 @@ public class Toast {
                handleHide();
                mView = mNextView;
                Context context = mView.getContext().getApplicationContext();
                String packageName = mView.getContext().getOpPackageName();
                if (context == null) {
                    context = mView.getContext();
                }
                mWM = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
                // We can resolve the Gravity here by using the Locale for getting
                // the layout direction
                final Configuration config = mView.getContext().getResources().getConfiguration();
                final int gravity = Gravity.getAbsoluteGravity(mGravity, config.getLayoutDirection());
                mParams.gravity = gravity;
                if ((gravity & Gravity.HORIZONTAL_GRAVITY_MASK) == Gravity.FILL_HORIZONTAL) {
                    mParams.horizontalWeight = 1.0f;
                }
                if ((gravity & Gravity.VERTICAL_GRAVITY_MASK) == Gravity.FILL_VERTICAL) {
                    mParams.verticalWeight = 1.0f;
                }
                mParams.x = mX;
                mParams.y = mY;
                mParams.verticalMargin = mVerticalMargin;
                mParams.horizontalMargin = mHorizontalMargin;
                mParams.packageName = packageName;
                mParams.hideTimeoutMilliseconds = mDuration ==
                    Toast.LENGTH_LONG ? LONG_DURATION_TIMEOUT : SHORT_DURATION_TIMEOUT;
                mParams.token = windowToken;
                mPresenter.adjustLayoutParams(mParams, windowToken, mDuration, mGravity, mX, mY,
                        mHorizontalMargin, mVerticalMargin);
                if (mView.getParent() != null) {
                    if (localLOGV) Log.v(TAG, "REMOVE! " + mView + " in " + this);
                    mWM.removeView(mView);
@@ -753,7 +714,7 @@ public class Toast {
                // invalidated. Let us hedge against that.
                try {
                    mWM.addView(mView, mParams);
                    trySendAccessibilityEvent();
                    mPresenter.trySendAccessibilityEvent(mView, mPackageName);
                    for (Callback callback : getCallbacks()) {
                        callback.onToastShown();
                    }
@@ -763,22 +724,6 @@ public class Toast {
            }
        }

        private void trySendAccessibilityEvent() {
            AccessibilityManager accessibilityManager =
                    AccessibilityManager.getInstance(mView.getContext());
            if (!accessibilityManager.isEnabled()) {
                return;
            }
            // treat toasts as notifications since they are used to
            // announce a transient piece of information to the user
            AccessibilityEvent event = AccessibilityEvent.obtain(
                    AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED);
            event.setClassName(getClass().getName());
            event.setPackageName(mView.getContext().getPackageName());
            mView.dispatchPopulateAccessibilityEvent(event);
            accessibilityManager.sendAccessibilityEvent(event);
        }

        @UnsupportedAppUsage
        public void handleHide() {
            if (localLOGV) Log.v(TAG, "HANDLE HIDE: " + this + " mView=" + mView);
+117 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2020 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 android.widget;

import android.content.Context;
import android.content.res.Configuration;
import android.graphics.PixelFormat;
import android.os.IBinder;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.WindowManager;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;

import com.android.internal.R;

/**
 * Class responsible for toast presentation inside app's process and in system UI.
 *
 * @hide
 */
public class ToastPresenter {
    private static final long SHORT_DURATION_TIMEOUT = 4000;
    private static final long LONG_DURATION_TIMEOUT = 7000;

    private final Context mContext;
    private final AccessibilityManager mAccessibilityManager;

    public ToastPresenter(Context context, AccessibilityManager accessibilityManager) {
        mContext = context;
        mAccessibilityManager = accessibilityManager;
    }

    /**
     * Initializes {@code params} with default values for toasts.
     */
    public void startLayoutParams(WindowManager.LayoutParams params) {
        params.height = WindowManager.LayoutParams.WRAP_CONTENT;
        params.width = WindowManager.LayoutParams.WRAP_CONTENT;
        params.format = PixelFormat.TRANSLUCENT;
        params.windowAnimations = R.style.Animation_Toast;
        params.type = WindowManager.LayoutParams.TYPE_TOAST;
        params.setFitInsetsIgnoringVisibility(true);
        params.setTitle("Toast");
        params.flags = WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
                | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
    }

    /**
     * Customizes {@code params} according to other parameters, ready to be passed to {@link
     * WindowManager#addView(View, ViewGroup.LayoutParams)}.
     */
    public void adjustLayoutParams(WindowManager.LayoutParams params, IBinder windowToken,
            int duration, int gravity, int xOffset, int yOffset, float horizontalMargin,
            float verticalMargin) {
        Configuration config = mContext.getResources().getConfiguration();
        int absGravity = Gravity.getAbsoluteGravity(gravity, config.getLayoutDirection());
        params.gravity = absGravity;
        if ((absGravity & Gravity.HORIZONTAL_GRAVITY_MASK) == Gravity.FILL_HORIZONTAL) {
            params.horizontalWeight = 1.0f;
        }
        if ((absGravity & Gravity.VERTICAL_GRAVITY_MASK) == Gravity.FILL_VERTICAL) {
            params.verticalWeight = 1.0f;
        }
        params.x = xOffset;
        params.y = yOffset;
        params.horizontalMargin = horizontalMargin;
        params.verticalMargin = verticalMargin;
        params.packageName = mContext.getPackageName();
        params.hideTimeoutMilliseconds =
                (duration == Toast.LENGTH_LONG) ? LONG_DURATION_TIMEOUT : SHORT_DURATION_TIMEOUT;
        params.token = windowToken;
    }

    /**
     * Returns the default text toast view for message {@code text}.
     */
    public View getTextToastView(CharSequence text) {
        View view = LayoutInflater.from(mContext).inflate(
                R.layout.transient_notification, null);
        TextView textView = view.findViewById(com.android.internal.R.id.message);
        textView.setText(text);
        return view;
    }

    /**
     * Sends {@link AccessibilityEvent#TYPE_NOTIFICATION_STATE_CHANGED} event if accessibility is
     * enabled.
     */
    public void trySendAccessibilityEvent(View view, String packageName) {
        if (!mAccessibilityManager.isEnabled()) {
            return;
        }
        AccessibilityEvent event = AccessibilityEvent.obtain(
                AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED);
        event.setClassName(Toast.class.getName());
        event.setPackageName(packageName);
        view.dispatchPopulateAccessibilityEvent(event);
        mAccessibilityManager.sendAccessibilityEvent(event);
    }
}
+9 −55
Original line number Diff line number Diff line
@@ -21,21 +21,16 @@ import android.annotation.Nullable;
import android.app.INotificationManager;
import android.app.ITransientNotificationCallback;
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.PixelFormat;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup.LayoutParams;
import android.view.WindowManager;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.ToastPresenter;

import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
@@ -64,6 +59,7 @@ public class ToastUI extends SystemUI implements CommandQueue.Callbacks {
    private final WindowManager mWindowManager;
    private final INotificationManager mNotificationManager;
    private final AccessibilityManager mAccessibilityManager;
    private final ToastPresenter mPresenter;
    private ToastEntry mCurrentToast;

    @Inject
@@ -83,6 +79,7 @@ public class ToastUI extends SystemUI implements CommandQueue.Callbacks {
        mWindowManager = windowManager;
        mNotificationManager = notificationManager;
        mAccessibilityManager = accessibilityManager;
        mPresenter = new ToastPresenter(context, accessibilityManager);
    }

    @Override
@@ -97,7 +94,7 @@ public class ToastUI extends SystemUI implements CommandQueue.Callbacks {
        if (mCurrentToast != null) {
            hideCurrentToast();
        }
        View view = getView(text);
        View view = mPresenter.getTextToastView(text);
        LayoutParams params = getLayoutParams(windowToken, duration);
        mCurrentToast = new ToastEntry(packageName, token, view, windowToken, callback);
        try {
@@ -106,7 +103,7 @@ public class ToastUI extends SystemUI implements CommandQueue.Callbacks {
            Log.w(TAG, "Error while attempting to show toast from " + packageName, e);
            return;
        }
        trySendAccessibilityEvent(view, packageName);
        mPresenter.trySendAccessibilityEvent(view, packageName);
        if (callback != null) {
            try {
                callback.onToastShown();
@@ -148,56 +145,13 @@ public class ToastUI extends SystemUI implements CommandQueue.Callbacks {
        mCurrentToast = null;
    }

    private void trySendAccessibilityEvent(View view, String packageName) {
        if (!mAccessibilityManager.isEnabled()) {
            return;
        }
        AccessibilityEvent event = AccessibilityEvent.obtain(
                AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED);
        event.setClassName(Toast.class.getName());
        event.setPackageName(packageName);
        view.dispatchPopulateAccessibilityEvent(event);
        mAccessibilityManager.sendAccessibilityEvent(event);
    }

    private View getView(CharSequence text) {
        View view = LayoutInflater.from(mContext).inflate(
                R.layout.transient_notification, null);
        TextView textView = view.findViewById(com.android.internal.R.id.message);
        textView.setText(text);
        return view;
    }

    private LayoutParams getLayoutParams(IBinder windowToken, int duration) {
        WindowManager.LayoutParams params = new WindowManager.LayoutParams();
        params.height = WindowManager.LayoutParams.WRAP_CONTENT;
        params.width = WindowManager.LayoutParams.WRAP_CONTENT;
        params.format = PixelFormat.TRANSLUCENT;
        params.windowAnimations = com.android.internal.R.style.Animation_Toast;
        params.type = WindowManager.LayoutParams.TYPE_TOAST;
        params.setTitle("Toast");
        params.flags = WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
                | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
        Configuration config = mContext.getResources().getConfiguration();
        int specificGravity = mContext.getResources().getInteger(
        mPresenter.startLayoutParams(params);
        int gravity = mContext.getResources().getInteger(
                com.android.internal.R.integer.config_toastDefaultGravity);
        int gravity = Gravity.getAbsoluteGravity(specificGravity, config.getLayoutDirection());
        params.gravity = gravity;
        if ((gravity & Gravity.HORIZONTAL_GRAVITY_MASK) == Gravity.FILL_HORIZONTAL) {
            params.horizontalWeight = 1.0f;
        }
        if ((gravity & Gravity.VERTICAL_GRAVITY_MASK) == Gravity.FILL_VERTICAL) {
            params.verticalWeight = 1.0f;
        }
        params.x = 0;
        params.y = mContext.getResources().getDimensionPixelSize(R.dimen.toast_y_offset);
        params.verticalMargin = 0;
        params.horizontalMargin = 0;
        params.packageName = mContext.getPackageName();
        params.hideTimeoutMilliseconds =
                (duration == Toast.LENGTH_LONG) ? DURATION_LONG : DURATION_SHORT;
        params.token = windowToken;
        int yOffset = mContext.getResources().getDimensionPixelSize(R.dimen.toast_y_offset);
        mPresenter.adjustLayoutParams(params, windowToken, duration, gravity, 0, yOffset, 0, 0);
        return params;
    }