NekoX/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/FloatingActionMode.java

327 lines
12 KiB
Java

/*
* Copyright (C) 2015 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 org.telegram.ui.ActionBar;
import android.accounts.AccountManager;
import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.Point;
import android.graphics.Rect;
import android.view.ActionMode;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.ViewParent;
import android.view.WindowManager;
import android.widget.PopupMenu;
import android.widget.PopupWindow;
import org.telegram.messenger.AccountInstance;
import org.telegram.messenger.AndroidUtilities;
import org.telegram.messenger.NotificationCenter;
import org.telegram.messenger.UserConfig;
import java.util.Arrays;
@TargetApi(23)
public final class FloatingActionMode extends ActionMode {
private static final int MAX_HIDE_DURATION = 3000;
private static final int MOVING_HIDE_DELAY = 50;
private final Context mContext;
private final ActionMode.Callback2 mCallback;
private final Menu mMenu;
private final Rect mContentRect;
private final Rect mContentRectOnScreen;
private final Rect mPreviousContentRectOnScreen;
private final int[] mViewPositionOnScreen;
private final int[] mPreviousViewPositionOnScreen;
private final int[] mRootViewPositionOnScreen;
private final Rect mViewRectOnScreen;
private final Rect mPreviousViewRectOnScreen;
private final Rect mScreenRect;
private final View mOriginatingView;
private final Point mDisplaySize;
private final int mBottomAllowance;
private final Runnable mMovingOff = new Runnable() {
public void run() {
if (isViewStillActive()) {
mFloatingToolbarVisibilityHelper.setMoving(false);
mFloatingToolbarVisibilityHelper.updateToolbarVisibility();
}
}
};
private final Runnable mHideOff = new Runnable() {
public void run() {
if (isViewStillActive()) {
mFloatingToolbarVisibilityHelper.setHideRequested(false);
mFloatingToolbarVisibilityHelper.updateToolbarVisibility();
}
}
};
private FloatingToolbar mFloatingToolbar;
private FloatingToolbarVisibilityHelper mFloatingToolbarVisibilityHelper;
public FloatingActionMode(Context context, ActionMode.Callback2 callback, View originatingView, FloatingToolbar floatingToolbar) {
mContext = context;
mCallback = callback;
PopupMenu p = new PopupMenu(context, null);
mMenu = p.getMenu();
setType(ActionMode.TYPE_FLOATING);
p.setOnMenuItemClickListener(menuItem -> mCallback.onActionItemClicked(FloatingActionMode.this, menuItem));
mContentRect = new Rect();
mContentRectOnScreen = new Rect();
mPreviousContentRectOnScreen = new Rect();
mViewPositionOnScreen = new int[2];
mPreviousViewPositionOnScreen = new int[2];
mRootViewPositionOnScreen = new int[2];
mViewRectOnScreen = new Rect();
mPreviousViewRectOnScreen = new Rect();
mScreenRect = new Rect();
mOriginatingView = originatingView;
mOriginatingView.getLocationOnScreen(mViewPositionOnScreen);
mBottomAllowance = AndroidUtilities.dp(20);
mDisplaySize = new Point();
setFloatingToolbar(floatingToolbar);
}
private void setFloatingToolbar(FloatingToolbar floatingToolbar) {
mFloatingToolbar = floatingToolbar.setMenu(mMenu).setOnMenuItemClickListener(item -> mCallback.onActionItemClicked(FloatingActionMode.this, item));
mFloatingToolbarVisibilityHelper = new FloatingToolbarVisibilityHelper(mFloatingToolbar);
mFloatingToolbarVisibilityHelper.activate();
}
@Override
public void setTitle(CharSequence title) {
}
@Override
public void setTitle(int resId) {
}
@Override
public void setSubtitle(CharSequence subtitle) {
}
@Override
public void setSubtitle(int resId) {
}
@Override
public void setCustomView(View view) {
}
@Override
public void invalidate() {
mCallback.onPrepareActionMode(this, mMenu);
invalidateContentRect();
}
@Override
public void invalidateContentRect() {
mCallback.onGetContentRect(this, mOriginatingView, mContentRect);
if (mContentRect.left == 0 && mContentRect.right == 0) {
mContentRect.left = 1;
mContentRect.right = 1;
}
repositionToolbar();
}
public void updateViewLocationInWindow() {
mOriginatingView.getLocationOnScreen(mViewPositionOnScreen);
mOriginatingView.getRootView().getLocationOnScreen(mRootViewPositionOnScreen);
mOriginatingView.getGlobalVisibleRect(mViewRectOnScreen);
mViewRectOnScreen.offset(mRootViewPositionOnScreen[0], mRootViewPositionOnScreen[1]);
if (!Arrays.equals(mViewPositionOnScreen, mPreviousViewPositionOnScreen) || !mViewRectOnScreen.equals(mPreviousViewRectOnScreen)) {
repositionToolbar();
mPreviousViewPositionOnScreen[0] = mViewPositionOnScreen[0];
mPreviousViewPositionOnScreen[1] = mViewPositionOnScreen[1];
mPreviousViewRectOnScreen.set(mViewRectOnScreen);
}
}
private void repositionToolbar() {
mContentRectOnScreen.set(mContentRect);
final ViewParent parent = mOriginatingView.getParent();
if (parent instanceof ViewGroup) {
parent.getChildVisibleRect(mOriginatingView, mContentRectOnScreen, null);
mContentRectOnScreen.offset(mRootViewPositionOnScreen[0], mRootViewPositionOnScreen[1]);
} else {
mContentRectOnScreen.offset(mViewPositionOnScreen[0], mViewPositionOnScreen[1]);
}
if (isContentRectWithinBounds()) {
mFloatingToolbarVisibilityHelper.setOutOfBounds(false);
mContentRectOnScreen.set(Math.max(mContentRectOnScreen.left, mViewRectOnScreen.left), Math.max(mContentRectOnScreen.top, mViewRectOnScreen.top), Math.min(mContentRectOnScreen.right, mViewRectOnScreen.right), Math.min(mContentRectOnScreen.bottom, mViewRectOnScreen.bottom + mBottomAllowance));
if (!mContentRectOnScreen.equals(mPreviousContentRectOnScreen)) {
mOriginatingView.removeCallbacks(mMovingOff);
mFloatingToolbarVisibilityHelper.setMoving(true);
mOriginatingView.postDelayed(mMovingOff, MOVING_HIDE_DELAY);
mFloatingToolbar.setContentRect(mContentRectOnScreen);
mFloatingToolbar.updateLayout();
}
} else {
mFloatingToolbarVisibilityHelper.setOutOfBounds(true);
mContentRectOnScreen.setEmpty();
}
mFloatingToolbarVisibilityHelper.updateToolbarVisibility();
mPreviousContentRectOnScreen.set(mContentRectOnScreen);
}
private boolean isContentRectWithinBounds() {
mContext.getSystemService(WindowManager.class).getDefaultDisplay().getRealSize(mDisplaySize);
mScreenRect.set(0, 0, mDisplaySize.x, mDisplaySize.y);
return intersectsClosed(mContentRectOnScreen, mScreenRect) && intersectsClosed(mContentRectOnScreen, mViewRectOnScreen);
}
private static boolean intersectsClosed(Rect a, Rect b) {
return a.left <= b.right && b.left <= a.right && a.top <= b.bottom && b.top <= a.bottom;
}
@Override
public void hide(long duration) {
if (duration == ActionMode.DEFAULT_HIDE_DURATION) {
duration = ViewConfiguration.getDefaultActionModeHideDuration();
}
duration = Math.min(MAX_HIDE_DURATION, duration);
mOriginatingView.removeCallbacks(mHideOff);
if (duration <= 0) {
mHideOff.run();
} else {
mFloatingToolbarVisibilityHelper.setHideRequested(true);
mFloatingToolbarVisibilityHelper.updateToolbarVisibility();
mOriginatingView.postDelayed(mHideOff, duration);
}
}
public void setOutsideTouchable(boolean outsideTouchable, PopupWindow.OnDismissListener onDismiss) {
mFloatingToolbar.setOutsideTouchable(outsideTouchable, onDismiss);
}
@Override
public void onWindowFocusChanged(boolean hasWindowFocus) {
mFloatingToolbarVisibilityHelper.setWindowFocused(hasWindowFocus);
mFloatingToolbarVisibilityHelper.updateToolbarVisibility();
}
@Override
public void finish() {
reset();
mCallback.onDestroyActionMode(this);
}
@Override
public Menu getMenu() {
return mMenu;
}
@Override
public CharSequence getTitle() {
return null;
}
@Override
public CharSequence getSubtitle() {
return null;
}
@Override
public View getCustomView() {
return null;
}
@Override
public MenuInflater getMenuInflater() {
return new MenuInflater(mContext);
}
private void reset() {
mFloatingToolbar.dismiss();
mFloatingToolbarVisibilityHelper.deactivate();
mOriginatingView.removeCallbacks(mMovingOff);
mOriginatingView.removeCallbacks(mHideOff);
}
private boolean isViewStillActive() {
return mOriginatingView.getWindowVisibility() == View.VISIBLE && mOriginatingView.isShown();
}
private static final class FloatingToolbarVisibilityHelper {
private static final long MIN_SHOW_DURATION_FOR_MOVE_HIDE = 500;
private final FloatingToolbar mToolbar;
private boolean mHideRequested;
private boolean mMoving;
private boolean mOutOfBounds;
private boolean mWindowFocused = true;
private boolean mActive;
private long mLastShowTime;
public FloatingToolbarVisibilityHelper(FloatingToolbar toolbar) {
mToolbar = toolbar;
}
public void activate() {
mHideRequested = false;
mMoving = false;
mOutOfBounds = false;
mWindowFocused = true;
mActive = true;
}
public void deactivate() {
mActive = false;
mToolbar.dismiss();
}
public void setHideRequested(boolean hide) {
mHideRequested = hide;
}
public void setMoving(boolean moving) {
final boolean showingLongEnough = System.currentTimeMillis() - mLastShowTime > MIN_SHOW_DURATION_FOR_MOVE_HIDE;
if (!moving || showingLongEnough) {
mMoving = moving;
}
}
public void setOutOfBounds(boolean outOfBounds) {
mOutOfBounds = outOfBounds;
}
public void setWindowFocused(boolean windowFocused) {
mWindowFocused = windowFocused;
}
public void updateToolbarVisibility() {
if (!mActive) {
return;
}
if (mHideRequested || mMoving || mOutOfBounds || !mWindowFocused) {
mToolbar.hide();
} else {
mToolbar.show();
mLastShowTime = System.currentTimeMillis();
}
}
}
}