Update lock screen user switcher on settings update and re-create view stub after disabling multi-user
NotificationPanelViewController inflates user switcher view stub after enabling multi-user and removes user switcher view after disabling this setting. After enabling it again it crashed when trying to inflate view stub as the view was removed. Fixed by re-inserting view stub after disabling user switcher. Another issue was that user switcher is not updated immediately after changing the multi-user setting and after switching displays. Fixed by adding settings observer and listening for screen size changes in the controller. Test: atest com.android.systemui.statusbar.phone.NotificationPanelViewTest Fixes: 186728895 Change-Id: I1957abf952aff938406f4cabf4c83cd2977099e8
This commit is contained in:
@@ -27,6 +27,7 @@ class ConfigurationControllerImpl(context: Context) : ConfigurationController {
|
||||
private val listeners: MutableList<ConfigurationController.ConfigurationListener> = ArrayList()
|
||||
private val lastConfig = Configuration()
|
||||
private var density: Int = 0
|
||||
private var smallestScreenWidth: Int = 0
|
||||
private var fontScale: Float = 0.toFloat()
|
||||
private val inCarMode: Boolean
|
||||
private var uiMode: Int = 0
|
||||
@@ -38,6 +39,7 @@ class ConfigurationControllerImpl(context: Context) : ConfigurationController {
|
||||
this.context = context
|
||||
fontScale = currentConfig.fontScale
|
||||
density = currentConfig.densityDpi
|
||||
smallestScreenWidth = currentConfig.smallestScreenWidthDp
|
||||
inCarMode = currentConfig.uiMode and Configuration.UI_MODE_TYPE_MASK ==
|
||||
Configuration.UI_MODE_TYPE_CAR
|
||||
uiMode = currentConfig.uiMode and Configuration.UI_MODE_NIGHT_MASK
|
||||
@@ -72,6 +74,14 @@ class ConfigurationControllerImpl(context: Context) : ConfigurationController {
|
||||
this.fontScale = fontScale
|
||||
}
|
||||
|
||||
val smallestScreenWidth = newConfig.smallestScreenWidthDp
|
||||
if (smallestScreenWidth != this.smallestScreenWidth) {
|
||||
this.smallestScreenWidth = smallestScreenWidth
|
||||
listeners.filterForEach({ this.listeners.contains(it) }) {
|
||||
it.onSmallestScreenWidthChanged()
|
||||
}
|
||||
}
|
||||
|
||||
val localeList = newConfig.locales
|
||||
if (localeList != this.localeList) {
|
||||
this.localeList = localeList
|
||||
|
||||
@@ -36,9 +36,11 @@ import android.animation.ValueAnimator;
|
||||
import android.app.ActivityManager;
|
||||
import android.app.Fragment;
|
||||
import android.app.StatusBarManager;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.content.res.Configuration;
|
||||
import android.content.res.Resources;
|
||||
import android.database.ContentObserver;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.ColorFilter;
|
||||
@@ -50,10 +52,12 @@ import android.graphics.Region;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.hardware.biometrics.BiometricSourceType;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.PowerManager;
|
||||
import android.os.SystemClock;
|
||||
import android.os.UserManager;
|
||||
import android.os.VibrationEffect;
|
||||
import android.provider.Settings;
|
||||
import android.util.Log;
|
||||
import android.util.MathUtils;
|
||||
import android.view.LayoutInflater;
|
||||
@@ -210,6 +214,8 @@ public class NotificationPanelViewController extends PanelViewController {
|
||||
new MyOnHeadsUpChangedListener();
|
||||
private final HeightListener mHeightListener = new HeightListener();
|
||||
private final ConfigurationListener mConfigurationListener = new ConfigurationListener();
|
||||
private final SettingsChangeObserver mSettingsChangeObserver;
|
||||
|
||||
@VisibleForTesting final StatusBarStateListener mStatusBarStateListener =
|
||||
new StatusBarStateListener();
|
||||
private final BiometricUnlockController mBiometricUnlockController;
|
||||
@@ -594,6 +600,8 @@ public class NotificationPanelViewController extends PanelViewController {
|
||||
private int mScreenCornerRadius;
|
||||
private boolean mQSAnimatingHiddenFromCollapsed;
|
||||
|
||||
private final ContentResolver mContentResolver;
|
||||
|
||||
private final Executor mUiExecutor;
|
||||
private final SecureSettings mSecureSettings;
|
||||
|
||||
@@ -635,6 +643,7 @@ public class NotificationPanelViewController extends PanelViewController {
|
||||
@Inject
|
||||
public NotificationPanelViewController(NotificationPanelView view,
|
||||
@Main Resources resources,
|
||||
@Main Handler handler,
|
||||
LayoutInflater layoutInflater,
|
||||
NotificationWakeUpCoordinator coordinator, PulseExpansionHandler pulseExpansionHandler,
|
||||
DynamicPrivacyController dynamicPrivacyController,
|
||||
@@ -678,6 +687,7 @@ public class NotificationPanelViewController extends PanelViewController {
|
||||
TapAgainViewController tapAgainViewController,
|
||||
NavigationModeController navigationModeController,
|
||||
FragmentService fragmentService,
|
||||
ContentResolver contentResolver,
|
||||
QuickAccessWalletController quickAccessWalletController,
|
||||
@Main Executor uiExecutor,
|
||||
SecureSettings secureSettings,
|
||||
@@ -704,15 +714,12 @@ public class NotificationPanelViewController extends PanelViewController {
|
||||
mKeyguardStatusBarViewComponentFactory = keyguardStatusBarViewComponentFactory;
|
||||
mDepthController = notificationShadeDepthController;
|
||||
mFeatureFlags = featureFlags;
|
||||
mContentResolver = contentResolver;
|
||||
mKeyguardQsUserSwitchComponentFactory = keyguardQsUserSwitchComponentFactory;
|
||||
mKeyguardUserSwitcherComponentFactory = keyguardUserSwitcherComponentFactory;
|
||||
mQSDetailDisplayer = qsDetailDisplayer;
|
||||
mFragmentService = fragmentService;
|
||||
mKeyguardUserSwitcherEnabled = mResources.getBoolean(
|
||||
com.android.internal.R.bool.config_keyguardUserSwitcher);
|
||||
mKeyguardQsUserSwitchEnabled =
|
||||
mKeyguardUserSwitcherEnabled && mResources.getBoolean(
|
||||
R.bool.config_keyguard_user_switch_opens_qs_details);
|
||||
mSettingsChangeObserver = new SettingsChangeObserver(handler);
|
||||
mShouldUseSplitNotificationShade =
|
||||
Utils.shouldUseSplitNotificationShade(mFeatureFlags, mResources);
|
||||
mView.setWillNotDraw(!DEBUG);
|
||||
@@ -795,6 +802,7 @@ public class NotificationPanelViewController extends PanelViewController {
|
||||
}
|
||||
|
||||
mMaxKeyguardNotifications = resources.getInteger(R.integer.keyguard_max_notification_count);
|
||||
updateUserSwitcherFlags();
|
||||
onFinishInflate();
|
||||
}
|
||||
|
||||
@@ -1034,6 +1042,10 @@ public class NotificationPanelViewController extends PanelViewController {
|
||||
view = mLayoutInflater.inflate(layoutId, mView, false);
|
||||
mView.addView(view, index);
|
||||
} else {
|
||||
// Add the stub back so we can re-inflate it again if necessary
|
||||
ViewStub stub = new ViewStub(mView.getContext(), layoutId);
|
||||
stub.setId(stubId);
|
||||
mView.addView(stub, index);
|
||||
view = null;
|
||||
}
|
||||
} else if (enabled) {
|
||||
@@ -1061,6 +1073,7 @@ public class NotificationPanelViewController extends PanelViewController {
|
||||
updateResources();
|
||||
|
||||
// Re-inflate the keyguard user switcher group.
|
||||
updateUserSwitcherFlags();
|
||||
boolean isUserSwitcherEnabled = mUserManager.isUserSwitcherEnabled();
|
||||
boolean showQsUserSwitch = mKeyguardQsUserSwitchEnabled && isUserSwitcherEnabled;
|
||||
boolean showKeyguardUserSwitcher =
|
||||
@@ -3895,6 +3908,26 @@ public class NotificationPanelViewController extends PanelViewController {
|
||||
return false;
|
||||
}
|
||||
|
||||
private void updateUserSwitcherFlags() {
|
||||
mKeyguardUserSwitcherEnabled = mResources.getBoolean(
|
||||
com.android.internal.R.bool.config_keyguardUserSwitcher);
|
||||
mKeyguardQsUserSwitchEnabled =
|
||||
mKeyguardUserSwitcherEnabled && mResources.getBoolean(
|
||||
R.bool.config_keyguard_user_switch_opens_qs_details);
|
||||
}
|
||||
|
||||
private void registerSettingsChangeListener() {
|
||||
mContentResolver.registerContentObserver(
|
||||
Settings.Global.getUriFor(Settings.Global.USER_SWITCHER_ENABLED),
|
||||
/* notifyForDescendants */ false,
|
||||
mSettingsChangeObserver
|
||||
);
|
||||
}
|
||||
|
||||
private void unregisterSettingsChangeListener() {
|
||||
mContentResolver.unregisterContentObserver(mSettingsChangeObserver);
|
||||
}
|
||||
|
||||
private class OnHeightChangedListener implements ExpandableView.OnHeightChangedListener {
|
||||
@Override
|
||||
public void onHeightChanged(ExpandableView view, boolean needsAnimation) {
|
||||
@@ -4215,6 +4248,15 @@ public class NotificationPanelViewController extends PanelViewController {
|
||||
reInflateViews();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSmallestScreenWidthChanged() {
|
||||
if (DEBUG) Log.d(TAG, "onSmallestScreenWidthChanged");
|
||||
|
||||
// Can affect multi-user switcher visibility as it depends on screen size by default:
|
||||
// it is enabled only for devices with large screens (see config_keyguardUserSwitcher)
|
||||
reInflateViews();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOverlayChanged() {
|
||||
if (DEBUG) Log.d(TAG, "onOverlayChanged");
|
||||
@@ -4228,6 +4270,21 @@ public class NotificationPanelViewController extends PanelViewController {
|
||||
}
|
||||
}
|
||||
|
||||
private class SettingsChangeObserver extends ContentObserver {
|
||||
|
||||
SettingsChangeObserver(Handler handler) {
|
||||
super(handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChange(boolean selfChange) {
|
||||
if (DEBUG) Log.d(TAG, "onSettingsChanged");
|
||||
|
||||
// Can affect multi-user switcher visibility
|
||||
reInflateViews();
|
||||
}
|
||||
}
|
||||
|
||||
private class StatusBarStateListener implements StateListener {
|
||||
@Override
|
||||
public void onStateChanged(int statusBarState) {
|
||||
@@ -4343,10 +4400,12 @@ public class NotificationPanelViewController extends PanelViewController {
|
||||
mConfigurationListener.onThemeChanged();
|
||||
mFalsingManager.addTapListener(mFalsingTapListener);
|
||||
mKeyguardIndicationController.init();
|
||||
registerSettingsChangeListener();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewDetachedFromWindow(View v) {
|
||||
unregisterSettingsChangeListener();
|
||||
mFragmentService.getFragmentHostManager(mView)
|
||||
.removeTagListener(QS.TAG, mFragmentListener);
|
||||
mStatusBarStateController.removeCallback(mStatusBarStateListener);
|
||||
|
||||
@@ -33,6 +33,7 @@ public interface ConfigurationController extends CallbackController<Configuratio
|
||||
interface ConfigurationListener {
|
||||
default void onConfigChanged(Configuration newConfig) {}
|
||||
default void onDensityOrFontScaleChanged() {}
|
||||
default void onSmallestScreenWidthChanged() {}
|
||||
default void onOverlayChanged() {}
|
||||
default void onUiModeChanged() {}
|
||||
default void onThemeChanged() {}
|
||||
|
||||
@@ -26,9 +26,12 @@ import static com.android.systemui.statusbar.notification.ViewGroupFadeHelper.re
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyBoolean;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.atLeast;
|
||||
import static org.mockito.Mockito.atLeastOnce;
|
||||
import static org.mockito.Mockito.clearInvocations;
|
||||
import static org.mockito.Mockito.doAnswer;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
@@ -37,9 +40,13 @@ import static org.mockito.Mockito.when;
|
||||
|
||||
import android.annotation.IdRes;
|
||||
import android.app.ActivityManager;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.res.Configuration;
|
||||
import android.content.res.Resources;
|
||||
import android.database.ContentObserver;
|
||||
import android.hardware.biometrics.BiometricSourceType;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.os.PowerManager;
|
||||
import android.os.UserManager;
|
||||
import android.testing.AndroidTestingRunner;
|
||||
@@ -50,6 +57,7 @@ import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.ViewPropertyAnimator;
|
||||
import android.view.ViewStub;
|
||||
import android.view.accessibility.AccessibilityManager;
|
||||
import android.view.accessibility.AccessibilityNodeInfo;
|
||||
|
||||
@@ -60,6 +68,7 @@ import androidx.test.filters.SmallTest;
|
||||
import com.android.internal.logging.MetricsLogger;
|
||||
import com.android.internal.logging.UiEventLogger;
|
||||
import com.android.internal.logging.testing.UiEventLoggerFake;
|
||||
import com.android.internal.util.CollectionUtils;
|
||||
import com.android.internal.util.LatencyTracker;
|
||||
import com.android.keyguard.KeyguardClockSwitch;
|
||||
import com.android.keyguard.KeyguardClockSwitchController;
|
||||
@@ -140,6 +149,7 @@ public class NotificationPanelViewTest extends SysuiTestCase {
|
||||
private KeyguardBottomAreaView mKeyguardBottomArea;
|
||||
@Mock
|
||||
private KeyguardBottomAreaView mQsFrame;
|
||||
private KeyguardStatusView mKeyguardStatusView;
|
||||
@Mock
|
||||
private ViewGroup mBigClockContainer;
|
||||
@Mock
|
||||
@@ -153,6 +163,10 @@ public class NotificationPanelViewTest extends SysuiTestCase {
|
||||
@Mock
|
||||
private KeyguardStatusBarView mKeyguardStatusBar;
|
||||
@Mock
|
||||
private View mUserSwitcherView;
|
||||
@Mock
|
||||
private ViewStub mUserSwitcherStubView;
|
||||
@Mock
|
||||
private HeadsUpTouchHelper.Callback mHeadsUpCallback;
|
||||
@Mock
|
||||
private PanelBar mPanelBar;
|
||||
@@ -204,7 +218,6 @@ public class NotificationPanelViewTest extends SysuiTestCase {
|
||||
@Mock
|
||||
private KeyguardClockSwitch mKeyguardClockSwitch;
|
||||
private PanelViewController.TouchHandler mTouchHandler;
|
||||
@Mock
|
||||
private ConfigurationController mConfigurationController;
|
||||
@Mock
|
||||
private MediaHierarchyManager mMediaHiearchyManager;
|
||||
@@ -265,6 +278,8 @@ public class NotificationPanelViewTest extends SysuiTestCase {
|
||||
@Mock
|
||||
private SecureSettings mSecureSettings;
|
||||
@Mock
|
||||
private ContentResolver mContentResolver;
|
||||
@Mock
|
||||
private TapAgainViewController mTapAgainViewController;
|
||||
@Mock
|
||||
private KeyguardIndicationController mKeyguardIndicationController;
|
||||
@@ -287,6 +302,9 @@ public class NotificationPanelViewTest extends SysuiTestCase {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mStatusBarStateController = new StatusBarStateControllerImpl(mUiEventLogger);
|
||||
|
||||
mKeyguardStatusView = new KeyguardStatusView(mContext);
|
||||
mKeyguardStatusView.setId(R.id.keyguard_status_view);
|
||||
|
||||
when(mAuthController.isUdfpsEnrolled(anyInt())).thenReturn(false);
|
||||
when(mHeadsUpCallback.getContext()).thenReturn(mContext);
|
||||
when(mView.getResources()).thenReturn(mResources);
|
||||
@@ -301,6 +319,9 @@ public class NotificationPanelViewTest extends SysuiTestCase {
|
||||
when(mResources.getDimensionPixelSize(R.dimen.notification_panel_width)).thenReturn(400);
|
||||
when(mView.getContext()).thenReturn(getContext());
|
||||
when(mView.findViewById(R.id.keyguard_header)).thenReturn(mKeyguardStatusBar);
|
||||
when(mView.findViewById(R.id.keyguard_user_switcher_view)).thenReturn(mUserSwitcherView);
|
||||
when(mView.findViewById(R.id.keyguard_user_switcher_stub)).thenReturn(
|
||||
mUserSwitcherStubView);
|
||||
when(mView.findViewById(R.id.keyguard_clock_container)).thenReturn(mKeyguardClockSwitch);
|
||||
when(mView.findViewById(R.id.notification_stack_scroller))
|
||||
.thenReturn(mNotificationStackScrollLayout);
|
||||
@@ -320,7 +341,7 @@ public class NotificationPanelViewTest extends SysuiTestCase {
|
||||
mNotificationContainerParent = new NotificationsQuickSettingsContainer(getContext(), null);
|
||||
mNotificationContainerParent.addView(newViewWithId(R.id.qs_frame));
|
||||
mNotificationContainerParent.addView(newViewWithId(R.id.notification_stack_scroller));
|
||||
mNotificationContainerParent.addView(newViewWithId(R.id.keyguard_status_view));
|
||||
mNotificationContainerParent.addView(mKeyguardStatusView);
|
||||
when(mView.findViewById(R.id.notification_container_parent))
|
||||
.thenReturn(mNotificationContainerParent);
|
||||
when(mFragmentService.getFragmentHostManager(mView)).thenReturn(mFragmentHostManager);
|
||||
@@ -348,6 +369,7 @@ public class NotificationPanelViewTest extends SysuiTestCase {
|
||||
mFalsingManager,
|
||||
mLockscreenShadeTransitionController,
|
||||
new FalsingCollectorFake());
|
||||
mConfigurationController = new ConfigurationControllerImpl(mContext);
|
||||
when(mKeyguardStatusViewComponentFactory.build(any()))
|
||||
.thenReturn(mKeyguardStatusViewComponent);
|
||||
when(mKeyguardStatusViewComponent.getKeyguardClockSwitchController())
|
||||
@@ -358,10 +380,16 @@ public class NotificationPanelViewTest extends SysuiTestCase {
|
||||
.thenReturn(mKeyguardStatusBarViewComponent);
|
||||
when(mKeyguardStatusBarViewComponent.getKeyguardStatusBarViewController())
|
||||
.thenReturn(mKeyguardStatusBarViewController);
|
||||
when(mLayoutInflater.inflate(eq(R.layout.keyguard_status_view), any(), anyBoolean()))
|
||||
.thenReturn(mKeyguardStatusView);
|
||||
when(mLayoutInflater.inflate(eq(R.layout.keyguard_bottom_area), any(), anyBoolean()))
|
||||
.thenReturn(mKeyguardBottomArea);
|
||||
|
||||
reset(mView);
|
||||
|
||||
mNotificationPanelViewController = new NotificationPanelViewController(mView,
|
||||
mResources,
|
||||
new Handler(Looper.getMainLooper()),
|
||||
mLayoutInflater,
|
||||
coordinator, expansionHandler, mDynamicPrivacyController, mKeyguardBypassController,
|
||||
mFalsingManager, new FalsingCollectorFake(),
|
||||
@@ -395,6 +423,7 @@ public class NotificationPanelViewTest extends SysuiTestCase {
|
||||
mTapAgainViewController,
|
||||
mNavigationModeController,
|
||||
mFragmentService,
|
||||
mContentResolver,
|
||||
mQuickAccessWalletController,
|
||||
new FakeExecutor(new FakeSystemClock()),
|
||||
mSecureSettings,
|
||||
@@ -548,6 +577,38 @@ public class NotificationPanelViewTest extends SysuiTestCase {
|
||||
.isEqualTo(R.id.qs_edge_guideline);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDisableUserSwitcherAfterEnabling_returnsViewStubToTheViewHierarchy() {
|
||||
givenViewAttached();
|
||||
when(mResources.getBoolean(
|
||||
com.android.internal.R.bool.config_keyguardUserSwitcher)).thenReturn(true);
|
||||
updateMultiUserSetting(true);
|
||||
clearInvocations(mView);
|
||||
|
||||
updateMultiUserSetting(false);
|
||||
|
||||
ArgumentCaptor<View> captor = ArgumentCaptor.forClass(View.class);
|
||||
verify(mView, atLeastOnce()).addView(captor.capture(), anyInt());
|
||||
final View userSwitcherStub = CollectionUtils.find(captor.getAllValues(),
|
||||
view -> view.getId() == R.id.keyguard_user_switcher_stub);
|
||||
assertThat(userSwitcherStub).isNotNull();
|
||||
assertThat(userSwitcherStub).isInstanceOf(ViewStub.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testChangeSmallestScreenWidthAndUserSwitchEnabled_inflatesUserSwitchView() {
|
||||
givenViewAttached();
|
||||
when(mView.findViewById(R.id.keyguard_user_switcher_view)).thenReturn(null);
|
||||
updateSmallestScreenWidth(300);
|
||||
when(mResources.getBoolean(
|
||||
com.android.internal.R.bool.config_keyguardUserSwitcher)).thenReturn(true);
|
||||
when(mUserManager.isUserSwitcherEnabled()).thenReturn(true);
|
||||
|
||||
updateSmallestScreenWidth(800);
|
||||
|
||||
verify(mUserSwitcherStubView).inflate();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSplitShadeLayout_isAlignedToGuideline() {
|
||||
enableSplitShade();
|
||||
@@ -682,6 +743,12 @@ public class NotificationPanelViewTest extends SysuiTestCase {
|
||||
return mFalsingManager.getTapListeners().get(0);
|
||||
}
|
||||
|
||||
private void givenViewAttached() {
|
||||
for (View.OnAttachStateChangeListener listener : mOnAttachStateChangeListeners) {
|
||||
listener.onViewAttachedToWindow(mView);
|
||||
}
|
||||
}
|
||||
|
||||
private View newViewWithId(int id) {
|
||||
View view = new View(mContext);
|
||||
view.setId(id);
|
||||
@@ -704,6 +771,21 @@ public class NotificationPanelViewTest extends SysuiTestCase {
|
||||
mNotificationPanelViewController.updateResources();
|
||||
}
|
||||
|
||||
private void updateMultiUserSetting(boolean enabled) {
|
||||
when(mUserManager.isUserSwitcherEnabled()).thenReturn(enabled);
|
||||
final ArgumentCaptor<ContentObserver> observerCaptor =
|
||||
ArgumentCaptor.forClass(ContentObserver.class);
|
||||
verify(mContentResolver)
|
||||
.registerContentObserver(any(), anyBoolean(), observerCaptor.capture());
|
||||
observerCaptor.getValue().onChange(/* selfChange */ false);
|
||||
}
|
||||
|
||||
private void updateSmallestScreenWidth(int smallestScreenWidthDp) {
|
||||
Configuration configuration = new Configuration();
|
||||
configuration.smallestScreenWidthDp = smallestScreenWidthDp;
|
||||
mConfigurationController.onConfigurationChanged(configuration);
|
||||
}
|
||||
|
||||
private void onTouchEvent(MotionEvent ev) {
|
||||
mTouchHandler.onTouch(mView, ev);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user