Improve gesture handling
Change-Id: Ib1e18274480b6bb681bd06f3130f9b9ea198ea98
diff --git a/res/layout-land/camera_controls.xml b/res/layout-land/camera_controls.xml
index 96f593a..432ae9e 100644
--- a/res/layout-land/camera_controls.xml
+++ b/res/layout-land/camera_controls.xml
@@ -21,6 +21,7 @@
<View
android:id="@+id/blocker"
+ android:clickable="true"
android:layout_height="match_parent"
android:layout_width="@dimen/switcher_size"
android:layout_gravity="right" />
diff --git a/res/layout-port/camera_controls.xml b/res/layout-port/camera_controls.xml
index ebbdf26..7dd66e4 100644
--- a/res/layout-port/camera_controls.xml
+++ b/res/layout-port/camera_controls.xml
@@ -21,6 +21,7 @@
<View
android:id="@+id/blocker"
+ android:clickable="true"
android:layout_width="match_parent"
android:layout_height="@dimen/switcher_size"
android:layout_gravity="bottom" />
diff --git a/src/com/android/camera/NewPhotoModule.java b/src/com/android/camera/NewPhotoModule.java
index 3cb9733..e5d922a 100644
--- a/src/com/android/camera/NewPhotoModule.java
+++ b/src/com/android/camera/NewPhotoModule.java
@@ -906,7 +906,6 @@
switch (state) {
case PhotoController.PREVIEW_STOPPED:
case PhotoController.SNAPSHOT_IN_PROGRESS:
- case PhotoController.FOCUSING:
case PhotoController.SWITCHING_CAMERA:
mUI.enableGestures(false);
break;
diff --git a/src/com/android/camera/NewPhotoUI.java b/src/com/android/camera/NewPhotoUI.java
index 1a14cf5..caf3d5a 100644
--- a/src/com/android/camera/NewPhotoUI.java
+++ b/src/com/android/camera/NewPhotoUI.java
@@ -61,11 +61,9 @@
public class NewPhotoUI implements PieListener,
NewPreviewGestures.SingleTapListener,
- NewPreviewGestures.CancelEventListener,
FocusUI, TextureView.SurfaceTextureListener,
LocationManager.Listener,
- FaceDetectionListener,
- NewPreviewGestures.SwipeListener {
+ FaceDetectionListener {
private static final String TAG = "CAM_UI";
private static final int UPDATE_TRANSFORM_MATRIX = 1;
@@ -290,23 +288,10 @@
if (mGestures == null) {
// this will handle gesture disambiguation and dispatching
- mGestures = new NewPreviewGestures(mActivity, this, mZoomRenderer, mPieRenderer,
- this);
- mGestures.setCancelEventListener(this);
+ mGestures = new NewPreviewGestures(mActivity, this, mZoomRenderer, mPieRenderer);
+ mRenderOverlay.setGestures(mGestures);
}
- mGestures.clearTouchReceivers();
mGestures.setRenderOverlay(mRenderOverlay);
- mGestures.addTouchReceiver(mMenuButton);
- mGestures.addTouchReceiver(mBlocker);
- // make sure to add touch targets for image capture
- if (mController.isImageCaptureIntent()) {
- if (mReviewCancelButton != null) {
- mGestures.addTouchReceiver(mReviewCancelButton);
- }
- if (mReviewDoneButton != null) {
- mGestures.addTouchReceiver(mReviewDoneButton);
- }
- }
mRenderOverlay.requestLayout();
initializeZoom(params);
@@ -468,11 +453,6 @@
return true;
}
- @Override
- public void onTouchEventCancelled(MotionEvent cancelEvent) {
- mRootView.dispatchTouchEvent(cancelEvent);
- }
-
public void enableGestures(boolean enable) {
if (mGestures != null) {
mGestures.setEnabled(enable);
@@ -797,10 +777,4 @@
mFaceView.setFaces(faces);
}
- @Override
- public void onSwipe(int direction) {
- if (direction == PreviewGestures.DIR_UP) {
- openMenu();
- }
- }
}
diff --git a/src/com/android/camera/NewPreviewGestures.java b/src/com/android/camera/NewPreviewGestures.java
index 2718e55..39c4be6 100644
--- a/src/com/android/camera/NewPreviewGestures.java
+++ b/src/com/android/camera/NewPreviewGestures.java
@@ -19,11 +19,13 @@
import android.os.Handler;
import android.os.Message;
import android.util.Log;
+import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.View;
import android.view.ViewConfiguration;
+import com.android.camera.PreviewGestures.SingleTapListener;
import com.android.camera.PreviewGestures.SwipeListener;
import com.android.camera.ui.PieRenderer;
import com.android.camera.ui.RenderOverlay;
@@ -33,6 +35,10 @@
import java.util.ArrayList;
import java.util.List;
+/* NewPreviewGestures disambiguates touch events received on RenderOverlay
+ * and dispatch them to the proper recipient (i.e. zoom renderer or pie renderer).
+ * Touch events on CameraControls will be handled by framework.
+ * */
public class NewPreviewGestures
implements ScaleGestureDetector.OnScaleGestureListener {
@@ -54,29 +60,60 @@
private NewCameraActivity mActivity;
private SingleTapListener mTapListener;
- private CancelEventListener mCancelEventListener;
private RenderOverlay mOverlay;
private PieRenderer mPie;
private ZoomRenderer mZoom;
private MotionEvent mDown;
private MotionEvent mCurrent;
private ScaleGestureDetector mScale;
- private List<View> mReceivers;
private int mMode;
private int mSlop;
private int mTapTimeout;
private boolean mEnabled;
private boolean mZoomOnly;
private int mOrientation;
- private int[] mLocation;
- private SwipeListener mSwipeListener;
+ private GestureDetector mGestureDetector;
+
+ private GestureDetector.SimpleOnGestureListener mGestureListener = new GestureDetector.SimpleOnGestureListener() {
+ @Override
+ public void onLongPress (MotionEvent e) {
+ // Open pie
+ if (mPie != null && !mPie.showsItems()) {
+ openPie();
+ }
+ }
+
+ @Override
+ public boolean onSingleTapUp (MotionEvent e) {
+ // Tap to focus when pie is not open
+ if (mPie == null || !mPie.showsItems()) {
+ mTapListener.onSingleTapUp(null, (int) e.getX(), (int) e.getY());
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public boolean onScroll (MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
+ if (mMode == MODE_ZOOM) return false;
+ int deltaX = (int) (e1.getX() - e2.getX());
+ int deltaY = (int) (e1.getY() - e2.getY());
+ if (deltaY > 2 * deltaX && deltaY > -2 * deltaX) {
+ // Open pie on swipe up
+ if (mPie != null && !mPie.showsItems()) {
+ openPie();
+ return true;
+ }
+ }
+ return false;
+ }
+ };
private Handler mHandler = new Handler() {
public void handleMessage(Message msg) {
if (msg.what == MSG_PIE) {
mMode = MODE_PIE;
openPie();
- cancelActivityTouchHandling(mDown);
}
}
};
@@ -85,16 +122,8 @@
public void onSingleTapUp(View v, int x, int y);
}
- public interface CancelEventListener {
- public void onTouchEventCancelled(MotionEvent cancelEvent);
- }
-
- interface SwipeListener {
- public void onSwipe(int direction);
- }
-
public NewPreviewGestures(NewCameraActivity ctx, SingleTapListener tapListener,
- ZoomRenderer zoom, PieRenderer pie, SwipeListener swipe) {
+ ZoomRenderer zoom, PieRenderer pie) {
mActivity = ctx;
mTapListener = tapListener;
mPie = pie;
@@ -104,12 +133,7 @@
mSlop = (int) ctx.getResources().getDimension(R.dimen.pie_touch_slop);
mTapTimeout = ViewConfiguration.getTapTimeout();
mEnabled = true;
- mLocation = new int[2];
- mSwipeListener = swipe;
- }
-
- public void setCancelEventListener(CancelEventListener listener) {
- mCancelEventListener = listener;
+ mGestureDetector = new GestureDetector(mGestureListener);
}
public void setRenderOverlay(RenderOverlay overlay) {
@@ -122,26 +146,14 @@
public void setEnabled(boolean enabled) {
mEnabled = enabled;
- if (!enabled) {
- cancelPie();
- }
}
public void setZoomOnly(boolean zoom) {
mZoomOnly = zoom;
}
- public void addTouchReceiver(View v) {
- if (mReceivers == null) {
- mReceivers = new ArrayList<View>();
- }
- mReceivers.add(v);
- }
-
- public void clearTouchReceivers() {
- if (mReceivers != null) {
- mReceivers.clear();
- }
+ public boolean isEnabled() {
+ return mEnabled;
}
public boolean dispatchTouch(MotionEvent m) {
@@ -150,121 +162,28 @@
}
mCurrent = m;
if (MotionEvent.ACTION_DOWN == m.getActionMasked()) {
- if (checkReceivers(m)) {
- mMode = MODE_MODULE;
- return false;
- } else {
- mMode = MODE_ALL;
- mDown = MotionEvent.obtain(m);
- if (mPie != null && mPie.showsItems()) {
- mMode = MODE_PIE;
- return sendToPie(m);
- }
- if (mPie != null && !mZoomOnly) {
- mHandler.sendEmptyMessageDelayed(MSG_PIE, TIMEOUT_PIE);
- }
- if (mZoom != null) {
- mScale.onTouchEvent(m);
- }
- // make sure this is ok
- return false;
- }
- } else if (mMode == MODE_NONE) {
- return false;
- } else if (mMode == MODE_SWIPE) {
- if (MotionEvent.ACTION_UP == m.getActionMasked()) {
- mSwipeListener.onSwipe(getSwipeDirection(m));
- }
- return true;
- } else if (mMode == MODE_PIE) {
- if (MotionEvent.ACTION_POINTER_DOWN == m.getActionMasked()) {
- sendToPie(makeCancelEvent(m));
- if (mZoom != null) {
- onScaleBegin(mScale);
- }
- } else {
- return sendToPie(m);
- }
- return true;
- } else if (mMode == MODE_ZOOM) {
- mScale.onTouchEvent(m);
- if (!mScale.isInProgress() && MotionEvent.ACTION_POINTER_UP == m.getActionMasked()) {
- mMode = MODE_NONE;
- onScaleEnd(mScale);
- }
- return true;
- } else if (mMode == MODE_MODULE) {
- return false;
- } else {
- // didn't receive down event previously;
- // assume module wasn't initialzed and ignore this event.
- if (mDown == null) {
- return true;
- }
- if (MotionEvent.ACTION_POINTER_DOWN == m.getActionMasked()) {
- if (!mZoomOnly) {
- cancelPie();
- sendToPie(makeCancelEvent(m));
- }
- if (mZoom != null) {
- mScale.onTouchEvent(m);
- onScaleBegin(mScale);
- }
- } else if ((mMode == MODE_ZOOM) && !mScale.isInProgress()
- && MotionEvent.ACTION_POINTER_UP == m.getActionMasked()) {
- // user initiated and stopped zoom gesture without zooming
- mScale.onTouchEvent(m);
- onScaleEnd(mScale);
- }
- // not zoom or pie mode and no timeout yet
- if (mZoom != null) {
- boolean res = mScale.onTouchEvent(m);
- if (mScale.isInProgress()) {
- cancelPie();
- cancelActivityTouchHandling(m);
- return res;
- }
- }
- if (MotionEvent.ACTION_UP == m.getActionMasked()) {
- cancelPie();
- cancelActivityTouchHandling(m);
- // must have been tap
- if (m.getEventTime() - mDown.getEventTime() < mTapTimeout) {
- mTapListener.onSingleTapUp(null,
- (int) mDown.getX() - mOverlay.getWindowPositionX(),
- (int) mDown.getY() - mOverlay.getWindowPositionY());
- return true;
- } else {
- return false;
- }
- } else if (MotionEvent.ACTION_MOVE == m.getActionMasked()) {
- if ((Math.abs(m.getX() - mDown.getX()) > mSlop)
- || Math.abs(m.getY() - mDown.getY()) > mSlop) {
- // moved too far and no timeout yet, no focus or pie
- cancelPie();
- int dir = getSwipeDirection(m);
- if (dir == DIR_LEFT) {
- mMode = MODE_MODULE;
- return false;
- } else {
- cancelActivityTouchHandling(m);
- mMode = MODE_NONE;
- }
- }
- }
- return false;
+ mMode = MODE_NONE;
+ mDown = MotionEvent.obtain(m);
}
- }
- private boolean checkReceivers(MotionEvent m) {
- if (mReceivers != null) {
- for (View receiver : mReceivers) {
- if (isInside(m, receiver)) {
- return true;
- }
+ // If pie is open, redirects all the touch events to pie.
+ if (mPie != null && mPie.isOpen()) {
+ return sendToPie(m);
+ }
+
+ // If pie is not open, send touch events to gesture detector and scale
+ // listener to recognize the gesture.
+ mGestureDetector.onTouchEvent(m);
+ if (mZoom != null) {
+ mScale.onTouchEvent(m);
+ if (MotionEvent.ACTION_POINTER_DOWN == m.getActionMasked()) {
+ mMode = MODE_ZOOM;
+ mZoom.onScaleBegin(mScale);
+ } else if (MotionEvent.ACTION_POINTER_UP == m.getActionMasked()) {
+ mZoom.onScaleEnd(mScale);
}
}
- return false;
+ return true;
}
// left tests for finger moving right to left
@@ -295,19 +214,6 @@
return DIR_UP;
}
- private boolean isInside(MotionEvent evt, View v) {
- v.getLocationInWindow(mLocation);
- return (v.getVisibility() == View.VISIBLE
- && evt.getX() >= mLocation[0] && evt.getX() < mLocation[0] + v.getWidth()
- && evt.getY() >= mLocation[1] && evt.getY() < mLocation[1] + v.getHeight());
- }
-
- public void cancelActivityTouchHandling(MotionEvent m) {
- if (mCancelEventListener != null) {
- mCancelEventListener.onTouchEventCancelled(makeCancelEvent(m));
- }
- }
-
private MotionEvent makeCancelEvent(MotionEvent m) {
MotionEvent c = MotionEvent.obtain(m);
c.setAction(MotionEvent.ACTION_CANCEL);
@@ -315,21 +221,16 @@
}
private void openPie() {
- mDown.offsetLocation(-mOverlay.getWindowPositionX(),
- -mOverlay.getWindowPositionY());
+ mGestureDetector.onTouchEvent(makeCancelEvent(mDown));
+ mScale.onTouchEvent(makeCancelEvent(mDown));
mOverlay.directDispatchTouch(mDown, mPie);
}
- private void cancelPie() {
- mHandler.removeMessages(MSG_PIE);
- }
-
private boolean sendToPie(MotionEvent m) {
- m.offsetLocation(-mOverlay.getWindowPositionX(),
- -mOverlay.getWindowPositionY());
return mOverlay.directDispatchTouch(m, mPie);
}
+ // OnScaleGestureListener implementation
@Override
public boolean onScale(ScaleGestureDetector detector) {
return mZoom.onScale(detector);
@@ -337,22 +238,17 @@
@Override
public boolean onScaleBegin(ScaleGestureDetector detector) {
- if (mMode != MODE_ZOOM) {
+ if (mPie == null || !mPie.isOpen()) {
mMode = MODE_ZOOM;
- cancelActivityTouchHandling(mCurrent);
- }
- if (mCurrent.getActionMasked() != MotionEvent.ACTION_MOVE) {
+ mGestureDetector.onTouchEvent(makeCancelEvent(mCurrent));
return mZoom.onScaleBegin(detector);
- } else {
- return true;
}
+ return false;
}
@Override
public void onScaleEnd(ScaleGestureDetector detector) {
- if (mCurrent.getActionMasked() != MotionEvent.ACTION_MOVE) {
- mZoom.onScaleEnd(detector);
- }
+ mZoom.onScaleEnd(detector);
}
}
diff --git a/src/com/android/camera/NewVideoUI.java b/src/com/android/camera/NewVideoUI.java
index a14dae3..71ab669 100644
--- a/src/com/android/camera/NewVideoUI.java
+++ b/src/com/android/camera/NewVideoUI.java
@@ -55,8 +55,7 @@
public class NewVideoUI implements PieRenderer.PieListener,
NewPreviewGestures.SingleTapListener,
- NewPreviewGestures.SwipeListener, SurfaceTextureListener,
- SurfaceHolder.Callback {
+ SurfaceTextureListener, SurfaceHolder.Callback {
private final static String TAG = "CAM_VideoUI";
private static final int UPDATE_TRANSFORM_MATRIX = 1;
// module fields
@@ -359,23 +358,10 @@
}
mRenderOverlay.addRenderer(mZoomRenderer);
if (mGestures == null) {
- mGestures = new NewPreviewGestures(mActivity, this, mZoomRenderer, mPieRenderer, this);
+ mGestures = new NewPreviewGestures(mActivity, this, mZoomRenderer, mPieRenderer);
+ mRenderOverlay.setGestures(mGestures);
}
mGestures.setRenderOverlay(mRenderOverlay);
- mGestures.clearTouchReceivers();
- mGestures.addTouchReceiver(mMenuButton);
- mGestures.addTouchReceiver(mBlocker);
- if (mController.isVideoCaptureIntent()) {
- if (mReviewCancelButton != null) {
- mGestures.addTouchReceiver(mReviewCancelButton);
- }
- if (mReviewDoneButton != null) {
- mGestures.addTouchReceiver(mReviewDoneButton);
- }
- if (mReviewPlayButton != null) {
- mGestures.addTouchReceiver(mReviewPlayButton);
- }
- }
}
public void setPrefChangedListener(OnPreferenceChangedListener listener) {
@@ -660,13 +646,6 @@
}
}
- @Override
- public void onSwipe(int direction) {
- if (direction == PreviewGestures.DIR_UP) {
- openMenu();
- }
- }
-
public SurfaceTexture getSurfaceTexture() {
synchronized (mLock) {
if (mSurfaceTexture == null) {
diff --git a/src/com/android/camera/ui/FilmStripView.java b/src/com/android/camera/ui/FilmStripView.java
index 286d6e3..f6b7589 100644
--- a/src/com/android/camera/ui/FilmStripView.java
+++ b/src/com/android/camera/ui/FilmStripView.java
@@ -16,6 +16,8 @@
package com.android.camera.ui;
+import com.android.gallery3d.R;
+
import android.animation.Animator;
import android.animation.TimeInterpolator;
import android.animation.ValueAnimator;
@@ -41,6 +43,8 @@
private static final int DURATION_GEOMETRY_ADJUST = 200;
private static final float FILM_STRIP_SCALE = 0.6f;
private static final float MAX_SCALE = 1f;
+ // Only check for intercepting touch events within first 500ms
+ private static final int SWIPE_TIME_OUT = 500;
private Context mContext;
private FilmStripGestureRecognizer mGestureRecognizer;
@@ -56,9 +60,11 @@
private Listener mListener;
+ private MotionEvent mDown;
+ private boolean mCheckToIntercept = true;
private View mCameraView;
private ImageData mCameraData;
-
+ private int mSlop;
private TimeInterpolator mViewAnimInterpolator;
// This is used to resolve the misalignment problem when the device
@@ -253,6 +259,7 @@
mViewAnimInterpolator = new LinearInterpolator();
mGestureRecognizer =
new FilmStripGestureRecognizer(context, new MyGestureReceiver());
+ mSlop = (int) getContext().getResources().getDimension(R.dimen.pie_touch_slop);
}
public Controller getController() {
@@ -750,8 +757,28 @@
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
- if (isInCameraFullscreen()) return false;
- return true;
+ if (ev.getActionMasked() == MotionEvent.ACTION_DOWN) {
+ mCheckToIntercept = true;
+ mDown = MotionEvent.obtain(ev);
+ return false;
+ } else if (ev.getActionMasked() == MotionEvent.ACTION_POINTER_DOWN) {
+ // Do not intercept touch once child is in zoom mode
+ mCheckToIntercept = false;
+ return false;
+ } else {
+ if (!mCheckToIntercept) return false;
+ if (ev.getEventTime() - ev.getDownTime() > SWIPE_TIME_OUT) return false;
+ int deltaX = (int) (ev.getX() - mDown.getX());
+ int deltaY = (int) (ev.getY() - mDown.getY());
+ if (ev.getActionMasked() == MotionEvent.ACTION_MOVE
+ && deltaX < mSlop * (-1)) {
+ // intercept left swipe
+ if (Math.abs(deltaX) >= Math.abs(deltaY) * 2) {
+ return true;
+ }
+ }
+ }
+ return false;
}
@Override
diff --git a/src/com/android/camera/ui/NewCameraRootView.java b/src/com/android/camera/ui/NewCameraRootView.java
index a50e41a..abb77b8 100644
--- a/src/com/android/camera/ui/NewCameraRootView.java
+++ b/src/com/android/camera/ui/NewCameraRootView.java
@@ -23,6 +23,7 @@
import android.os.Debug;
import android.util.AttributeSet;
import android.view.Gravity;
+import android.view.MotionEvent;
import android.view.View;
import android.widget.FrameLayout;
@@ -131,4 +132,15 @@
}
}
}
+
+ @Override
+ public boolean dispatchTouchEvent(MotionEvent ev) {
+ //TODO: This scale check is temporary, should be removed once full screen notification
+ // is implemented
+ if (((View) getParent()).getScaleX() == 1.0f) {
+ return super.dispatchTouchEvent(ev);
+ } else {
+ return false;
+ }
+ }
}
diff --git a/src/com/android/camera/ui/PieMenuButton.java b/src/com/android/camera/ui/PieMenuButton.java
index e571931..0e23226 100644
--- a/src/com/android/camera/ui/PieMenuButton.java
+++ b/src/com/android/camera/ui/PieMenuButton.java
@@ -36,6 +36,7 @@
@Override
public boolean onTouchEvent(MotionEvent event) {
+ boolean handled = super.onTouchEvent(event);
if (MotionEvent.ACTION_UP == event.getAction() && mPressed) {
// Perform a customized click as soon as the ACTION_UP event
// is received. The reason for doing this is that Framework
@@ -45,7 +46,7 @@
mReadyToClick = true;
performClick();
}
- return super.onTouchEvent(event);
+ return handled;
}
@Override
diff --git a/src/com/android/camera/ui/PieRenderer.java b/src/com/android/camera/ui/PieRenderer.java
index edae2be..834dc4b 100644
--- a/src/com/android/camera/ui/PieRenderer.java
+++ b/src/com/android/camera/ui/PieRenderer.java
@@ -303,6 +303,10 @@
mHandler.sendEmptyMessage(show ? MSG_OPEN : MSG_CLOSE);
}
+ public boolean isOpen() {
+ return mState == STATE_PIE && isVisible();
+ }
+
private void fadeIn() {
mFadeIn = new LinearAnimation(0, 1);
mFadeIn.setDuration(PIE_FADE_IN_DURATION);
diff --git a/src/com/android/camera/ui/RenderOverlay.java b/src/com/android/camera/ui/RenderOverlay.java
index ba25915..0bda10a 100644
--- a/src/com/android/camera/ui/RenderOverlay.java
+++ b/src/com/android/camera/ui/RenderOverlay.java
@@ -23,6 +23,8 @@
import android.view.View;
import android.widget.FrameLayout;
+import com.android.camera.NewPreviewGestures;
+
import java.util.ArrayList;
import java.util.List;
@@ -42,7 +44,7 @@
private RenderView mRenderView;
private List<Renderer> mClients;
-
+ private NewPreviewGestures mGestures;
// reverse list of touch clients
private List<Renderer> mTouchClients;
private int[] mPosition = new int[2];
@@ -57,6 +59,10 @@
setWillNotDraw(false);
}
+ public void setGestures(NewPreviewGestures gestures) {
+ mGestures = gestures;
+ }
+
public void addRenderer(Renderer renderer) {
mClients.add(renderer);
renderer.setOverlay(this);
@@ -83,12 +89,13 @@
@Override
public boolean dispatchTouchEvent(MotionEvent m) {
- return false;
+ if (mGestures != null) mGestures.dispatchTouch(m);
+ return true;
}
public boolean directDispatchTouch(MotionEvent m, Renderer target) {
mRenderView.setTouchTarget(target);
- boolean res = super.dispatchTouchEvent(m);
+ boolean res = mRenderView.dispatchTouchEvent(m);
mRenderView.setTouchTarget(null);
return res;
}
@@ -123,7 +130,8 @@
}
@Override
- public boolean onTouchEvent(MotionEvent evt) {
+ public boolean dispatchTouchEvent(MotionEvent evt) {
+
if (mTouchTarget != null) {
return mTouchTarget.onTouchEvent(evt);
}