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

Commit 4ccfe1a5 authored by Joanne Chung's avatar Joanne Chung Committed by Android (Google) Code Review
Browse files

Merge changes I73bdec96,I1f2add3e,I2e704432

* changes:
  Handle touch focus when clicking toolbar window transparent area
  The client implementation for remote selection bar
  The service implementatoin of selection toolbar
parents cfa26cb2 b0040b03
Loading
Loading
Loading
Loading
+92 −8
Original line number Diff line number Diff line
@@ -16,12 +16,21 @@

package android.service.selectiontoolbar;

import android.util.Log;
import static android.view.selectiontoolbar.SelectionToolbarManager.ERROR_DO_NOT_ALLOW_MULTIPLE_TOOL_BAR;
import static android.view.selectiontoolbar.SelectionToolbarManager.NO_TOOLBAR_ID;

import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
import android.view.selectiontoolbar.ShowInfo;

import java.util.UUID;

/**
 * The default implementation of {@link SelectionToolbarRenderService}.
 *
 * <p><b>NOTE:<b/> The requests are handled on the service main thread.
 *
 *  @hide
 */
// TODO(b/214122495): fix class not found then move to system service folder
@@ -29,22 +38,97 @@ public final class DefaultSelectionToolbarRenderService extends SelectionToolbar

    private static final String TAG = "DefaultSelectionToolbarRenderService";

    // TODO(b/215497659): handle remove if the client process dies.
    // Only show one toolbar, dismiss the old ones and remove from cache
    private final SparseArray<Pair<Long, RemoteSelectionToolbar>> mToolbarCache =
            new SparseArray<>();

    /**
     * Only allow one package to create one toolbar.
     */
    private boolean canShowToolbar(int uid, ShowInfo showInfo) {
        if (showInfo.getWidgetToken() != NO_TOOLBAR_ID) {
            return true;
        }
        return mToolbarCache.indexOfKey(uid) < 0;
    }

    @Override
    public void onShow(ShowInfo showInfo,
    public void onShow(int callingUid, ShowInfo showInfo,
            SelectionToolbarRenderService.RemoteCallbackWrapper callbackWrapper) {
        // TODO: Add implementation
        Log.w(TAG, "onShow()");
        if (!canShowToolbar(callingUid, showInfo)) {
            Slog.e(TAG, "Do not allow multiple toolbar for the app.");
            callbackWrapper.onError(ERROR_DO_NOT_ALLOW_MULTIPLE_TOOL_BAR);
            return;
        }
        long widgetToken = showInfo.getWidgetToken() == NO_TOOLBAR_ID
                ? UUID.randomUUID().getMostSignificantBits()
                : showInfo.getWidgetToken();

        if (mToolbarCache.indexOfKey(callingUid) < 0) {
            RemoteSelectionToolbar toolbar = new RemoteSelectionToolbar(this,
                    widgetToken, showInfo.getHostInputToken(),
                    callbackWrapper, this::transferTouch);
            mToolbarCache.put(callingUid, new Pair<>(widgetToken, toolbar));
        }
        Slog.v(TAG, "onShow() for " + widgetToken);
        Pair<Long, RemoteSelectionToolbar> toolbarPair = mToolbarCache.get(callingUid);
        if (toolbarPair.first == widgetToken) {
            toolbarPair.second.show(showInfo);
        } else {
            Slog.w(TAG, "onShow() for unknown " + widgetToken);
        }
    }

    @Override
    public void onHide(long widgetToken) {
        // TODO: Add implementation
        Log.w(TAG, "onHide()");
        RemoteSelectionToolbar toolbar = getRemoteSelectionToolbarByTokenLocked(widgetToken);
        if (toolbar != null) {
            Slog.v(TAG, "onHide() for " + widgetToken);
            toolbar.hide(widgetToken);
        }
    }

    @Override
    public void onDismiss(long widgetToken) {
        // TODO: Add implementation
        Log.w(TAG, "onDismiss()");
        RemoteSelectionToolbar toolbar = getRemoteSelectionToolbarByTokenLocked(widgetToken);
        if (toolbar != null) {
            Slog.v(TAG, "onDismiss() for " + widgetToken);
            toolbar.dismiss(widgetToken);
            removeRemoteSelectionToolbarByTokenLocked(widgetToken);
        }
    }

    @Override
    public void onToolbarShowTimeout(int callingUid) {
        Slog.w(TAG, "onToolbarShowTimeout for callingUid = " + callingUid);
        Pair<Long, RemoteSelectionToolbar> toolbarPair = mToolbarCache.get(callingUid);
        if (toolbarPair != null) {
            RemoteSelectionToolbar remoteToolbar = toolbarPair.second;
            remoteToolbar.dismiss(toolbarPair.first);
            remoteToolbar.onToolbarShowTimeout();
            mToolbarCache.remove(callingUid);
        }
    }

    private RemoteSelectionToolbar getRemoteSelectionToolbarByTokenLocked(long widgetToken) {
        for (int i = 0; i < mToolbarCache.size(); i++) {
            Pair<Long, RemoteSelectionToolbar> toolbarPair = mToolbarCache.valueAt(i);
            if (toolbarPair.first == widgetToken) {
                return toolbarPair.second;
            }
        }
        return null;
    }

    private void removeRemoteSelectionToolbarByTokenLocked(long widgetToken) {
        for (int i = 0; i < mToolbarCache.size(); i++) {
            Pair<Long, RemoteSelectionToolbar> toolbarPair = mToolbarCache.valueAt(i);
            if (toolbarPair.first == widgetToken) {
                mToolbarCache.remove(mToolbarCache.keyAt(i));
                return;
            }
        }
    }
}
+78 −0
Original line number Diff line number Diff line
/*
 * 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.
 */

package android.service.selectiontoolbar;

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Rect;
import android.os.IBinder;
import android.util.Log;
import android.view.MotionEvent;
import android.widget.LinearLayout;

/**
 * This class is the root view for the selection toolbar. It is responsible for
 * detecting the click on the item and to also transfer input focus to the application.
 *
 * @hide
 */
@SuppressLint("ViewConstructor")
public class FloatingToolbarRoot extends LinearLayout {

    private static final boolean DEBUG = false;
    private static final String TAG = "FloatingToolbarRoot";

    private final IBinder mTargetInputToken;
    private final SelectionToolbarRenderService.TransferTouchListener mTransferTouchListener;
    private Rect mContentRect;

    public FloatingToolbarRoot(Context context, IBinder targetInputToken,
            SelectionToolbarRenderService.TransferTouchListener transferTouchListener) {
        super(context);
        mTargetInputToken = targetInputToken;
        mTransferTouchListener = transferTouchListener;
        setFocusable(false);
    }

    /**
     * Sets the Rect that shows the selection toolbar content.
     */
    public void setContentRect(Rect contentRect) {
        mContentRect = contentRect;
    }

    @Override
    @SuppressLint("ClickableViewAccessibility")
    public boolean dispatchTouchEvent(MotionEvent event) {
        if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
            int downX = (int) event.getX();
            int downY = (int) event.getY();
            if (DEBUG) {
                Log.d(TAG, "downX=" + downX + " downY=" + downY);
            }
            // TODO(b/215497659): Check FLAG_WINDOW_IS_PARTIALLY_OBSCURED
            if (!mContentRect.contains(downX, downY)) {
                if (DEBUG) {
                    Log.d(TAG, "Transfer touch focus to application.");
                }
                mTransferTouchListener.onTransferTouch(getViewRootImpl().getInputToken(),
                        mTargetInputToken);
            }
        }
        return super.dispatchTouchEvent(event);
    }
}
+3 −2
Original line number Diff line number Diff line
@@ -25,7 +25,8 @@ import android.view.selectiontoolbar.ShowInfo;
 * @hide
 */
oneway interface ISelectionToolbarRenderService {
    void onShow(in ShowInfo showInfo, in ISelectionToolbarCallback callback);
    void onConnected(in IBinder callback);
    void onShow(int callingUid, in ShowInfo showInfo, in ISelectionToolbarCallback callback);
    void onHide(long widgetToken);
    void onDismiss(long widgetToken);
    void onDismiss(int callingUid, long widgetToken);
}
+9 −3
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 The Android Open Source Project
 * 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.
@@ -14,9 +14,15 @@
 * limitations under the License.
 */

package android.view.selectiontoolbar;
package android.service.selectiontoolbar;

import android.os.IBinder;

/**
 * The interface from the SelectionToolbarRenderService to the system.
 *
 * @hide
 */
parcelable SelectionContext;
oneway interface ISelectionToolbarRenderServiceCallback {
    void transferTouch(in IBinder source, in IBinder target);
}
+208 −453

File changed.

Preview size limit exceeded, changes collapsed.

Loading