Fields Summary |
---|
private static final String | TAG |
private static final int | ZOOM_CONTROLS_TIMEOUT |
private static final int | ZOOM_CONTROLS_TOUCH_PADDING |
private int | mTouchPaddingScaledSq |
private android.content.Context | mContext |
private android.view.WindowManager | mWindowManager |
private boolean | mAutoDismissControls |
private android.view.View | mOwnerViewThe view that is being zoomed by this zoom controller. |
private int[] | mOwnerViewRawLocationThe location of the owner view on the screen. This is recalculated
each time the zoom controller is shown. |
private FrameLayout | mContainerThe container that is added as a window. |
private android.view.WindowManager.LayoutParams | mContainerLayoutParams |
private int[] | mContainerRawLocation |
private ZoomControls | mControls |
private android.view.View | mTouchTargetViewThe view (or null) that should receive touch events. This will get set if
the touch down hits the container. It will be reset on the touch up. |
private int[] | mTouchTargetWindowLocationThe {@link #mTouchTargetView}'s location in window, set on touch down. |
private boolean | mReleaseTouchListenerOnUpIf the zoom controller is dismissed but the user is still in a touch
interaction, we set this to true. This will ignore all touch events until
up/cancel, and then set the owner's touch listener to null.
Otherwise, the owner view would get mismatched events (i.e., touch move
even though it never got the touch down.) |
private boolean | mIsVisibleWhether the container has been added to the window manager. |
private android.graphics.Rect | mTempRect |
private int[] | mTempIntArray |
private OnZoomListener | mCallback |
private Runnable | mPostedVisibleInitializerWhen showing the zoom, we add the view as a new window. However, there is
logic that needs to know the size of the zoom which is determined after
it's laid out. Therefore, we must post this logic onto the UI thread so
it will be exceuted AFTER the layout. This is the logic. |
private android.content.IntentFilter | mConfigurationChangedFilter |
private android.content.BroadcastReceiver | mConfigurationChangedReceiverNeeded to reposition the zoom controls after configuration changes. |
private static final int | MSG_POST_CONFIGURATION_CHANGEDWhen configuration changes, this is called after the UI thread is idle. |
private static final int | MSG_DISMISS_ZOOM_CONTROLSUsed to delay the zoom controller dismissal. |
private static final int | MSG_POST_SET_VISIBLEIf setVisible(true) is called and the owner view's window token is null,
we delay the setVisible(true) call until it is not null. |
private android.os.Handler | mHandler |
Methods Summary |
---|
private FrameLayout | createContainer()
LayoutParams lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
// Controls are positioned BOTTOM | CENTER with respect to the owner view.
lp.gravity = Gravity.TOP | Gravity.LEFT;
lp.flags = LayoutParams.FLAG_NOT_TOUCHABLE |
LayoutParams.FLAG_NOT_FOCUSABLE |
LayoutParams.FLAG_LAYOUT_NO_LIMITS |
LayoutParams.FLAG_ALT_FOCUSABLE_IM;
lp.height = LayoutParams.WRAP_CONTENT;
lp.width = LayoutParams.FILL_PARENT;
lp.type = LayoutParams.TYPE_APPLICATION_PANEL;
lp.format = PixelFormat.TRANSPARENT;
lp.windowAnimations = com.android.internal.R.style.Animation_ZoomButtons;
mContainerLayoutParams = lp;
FrameLayout container = new Container(mContext);
container.setLayoutParams(lp);
container.setMeasureAllChildren(true);
LayoutInflater inflater = (LayoutInflater) mContext
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(com.android.internal.R.layout.zoom_container, container);
mControls = (ZoomControls) container.findViewById(com.android.internal.R.id.zoomControls);
mControls.setOnZoomInClickListener(new OnClickListener() {
public void onClick(View v) {
dismissControlsDelayed(ZOOM_CONTROLS_TIMEOUT);
if (mCallback != null) mCallback.onZoom(true);
}
});
mControls.setOnZoomOutClickListener(new OnClickListener() {
public void onClick(View v) {
dismissControlsDelayed(ZOOM_CONTROLS_TIMEOUT);
if (mCallback != null) mCallback.onZoom(false);
}
});
return container;
|
private void | dismissControlsDelayed(int delay)
if (mAutoDismissControls) {
mHandler.removeMessages(MSG_DISMISS_ZOOM_CONTROLS);
mHandler.sendEmptyMessageDelayed(MSG_DISMISS_ZOOM_CONTROLS, delay);
}
|
private android.view.View | findViewForTouch(int rawX, int rawY)Returns the View that should receive a touch at the given coordinates.
// Reverse order so the child drawn on top gets first dibs.
int containerCoordsX = rawX - mContainerRawLocation[0];
int containerCoordsY = rawY - mContainerRawLocation[1];
Rect frame = mTempRect;
View closestChild = null;
int closestChildDistanceSq = Integer.MAX_VALUE;
for (int i = mContainer.getChildCount() - 1; i >= 0; i--) {
View child = mContainer.getChildAt(i);
if (child.getVisibility() != View.VISIBLE) {
continue;
}
child.getHitRect(frame);
if (frame.contains(containerCoordsX, containerCoordsY)) {
return child;
}
int distanceX;
if (containerCoordsX >= frame.left && containerCoordsX <= frame.right) {
distanceX = 0;
} else {
distanceX = Math.min(Math.abs(frame.left - containerCoordsX),
Math.abs(containerCoordsX - frame.right));
}
int distanceY;
if (containerCoordsY >= frame.top && containerCoordsY <= frame.bottom) {
distanceY = 0;
} else {
distanceY = Math.min(Math.abs(frame.top - containerCoordsY),
Math.abs(containerCoordsY - frame.bottom));
}
int distanceSq = distanceX * distanceX + distanceY * distanceY;
if ((distanceSq < mTouchPaddingScaledSq) &&
(distanceSq < closestChildDistanceSq)) {
closestChild = child;
closestChildDistanceSq = distanceSq;
}
}
return closestChild;
|
public android.view.ViewGroup | getContainer()Gets the container that is the parent of the zoom controls.
The client can add other views to this container to link them with the
zoom controls.
return mContainer;
|
private android.view.ViewRoot | getOwnerViewRoot()
View rootViewOfOwner = mOwnerView.getRootView();
if (rootViewOfOwner == null) {
return null;
}
ViewParent parentOfRootView = rootViewOfOwner.getParent();
if (parentOfRootView instanceof ViewRoot) {
return (ViewRoot) parentOfRootView;
} else {
return null;
}
|
public android.view.View | getZoomControls()Gets the view for the zoom controls.
return mControls;
|
public boolean | isAutoDismissed()Whether the zoom controls will be automatically dismissed after showing.
return mAutoDismissControls;
|
private boolean | isInterestingKey(int keyCode)
switch (keyCode) {
case KeyEvent.KEYCODE_DPAD_CENTER:
case KeyEvent.KEYCODE_DPAD_UP:
case KeyEvent.KEYCODE_DPAD_DOWN:
case KeyEvent.KEYCODE_DPAD_LEFT:
case KeyEvent.KEYCODE_DPAD_RIGHT:
case KeyEvent.KEYCODE_ENTER:
case KeyEvent.KEYCODE_BACK:
return true;
default:
return false;
}
|
public boolean | isVisible()Whether the zoom controls are visible to the user.
return mIsVisible;
|
private boolean | onContainerKey(android.view.KeyEvent event)
int keyCode = event.getKeyCode();
if (isInterestingKey(keyCode)) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
setVisible(false);
} else {
dismissControlsDelayed(ZOOM_CONTROLS_TIMEOUT);
}
// Let the container handle the key
return false;
} else {
ViewRoot viewRoot = getOwnerViewRoot();
if (viewRoot != null) {
viewRoot.dispatchKey(event);
}
// We gave the key to the owner, don't let the container handle this key
return true;
}
|
private void | onPostConfigurationChanged()
dismissControlsDelayed(ZOOM_CONTROLS_TIMEOUT);
refreshPositioningVariables();
|
public boolean | onTouch(android.view.View v, android.view.MotionEvent event)
int action = event.getAction();
if (mReleaseTouchListenerOnUp) {
// The controls were dismissed but we need to throw away all events until the up
if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
mOwnerView.setOnTouchListener(null);
setTouchTargetView(null);
mReleaseTouchListenerOnUp = false;
}
// Eat this event
return true;
}
dismissControlsDelayed(ZOOM_CONTROLS_TIMEOUT);
View targetView = mTouchTargetView;
switch (action) {
case MotionEvent.ACTION_DOWN:
targetView = findViewForTouch((int) event.getRawX(), (int) event.getRawY());
setTouchTargetView(targetView);
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
setTouchTargetView(null);
break;
}
if (targetView != null) {
// The upperleft corner of the target view in raw coordinates
int targetViewRawX = mContainerRawLocation[0] + mTouchTargetWindowLocation[0];
int targetViewRawY = mContainerRawLocation[1] + mTouchTargetWindowLocation[1];
MotionEvent containerEvent = MotionEvent.obtain(event);
// Convert the motion event into the target view's coordinates (from
// owner view's coordinates)
containerEvent.offsetLocation(mOwnerViewRawLocation[0] - targetViewRawX,
mOwnerViewRawLocation[1] - targetViewRawY);
/* Disallow negative coordinates (which can occur due to
* ZOOM_CONTROLS_TOUCH_PADDING) */
// These are floats because we need to potentially offset away this exact amount
float containerX = containerEvent.getX();
float containerY = containerEvent.getY();
if (containerX < 0 && containerX > -ZOOM_CONTROLS_TOUCH_PADDING) {
containerEvent.offsetLocation(-containerX, 0);
}
if (containerY < 0 && containerY > -ZOOM_CONTROLS_TOUCH_PADDING) {
containerEvent.offsetLocation(0, -containerY);
}
boolean retValue = targetView.dispatchTouchEvent(containerEvent);
containerEvent.recycle();
return retValue;
} else {
return false;
}
|
private void | refreshPositioningVariables()
// Position the zoom controls on the bottom of the owner view.
int ownerHeight = mOwnerView.getHeight();
int ownerWidth = mOwnerView.getWidth();
// The gap between the top of the owner and the top of the container
int containerOwnerYOffset = ownerHeight - mContainer.getHeight();
// Calculate the owner view's bounds
mOwnerView.getLocationOnScreen(mOwnerViewRawLocation);
mContainerRawLocation[0] = mOwnerViewRawLocation[0];
mContainerRawLocation[1] = mOwnerViewRawLocation[1] + containerOwnerYOffset;
int[] ownerViewWindowLoc = mTempIntArray;
mOwnerView.getLocationInWindow(ownerViewWindowLoc);
// lp.x and lp.y should be relative to the owner's window top-left
mContainerLayoutParams.x = ownerViewWindowLoc[0];
mContainerLayoutParams.width = ownerWidth;
mContainerLayoutParams.y = ownerViewWindowLoc[1] + containerOwnerYOffset;
if (mIsVisible) {
mWindowManager.updateViewLayout(mContainer, mContainerLayoutParams);
}
|
public void | setAutoDismissed(boolean autoDismiss)Sets whether the zoom controls will be automatically dismissed after
showing.
if (mAutoDismissControls == autoDismiss) return;
mAutoDismissControls = autoDismiss;
|
public void | setFocusable(boolean focusable)Sets whether the zoom controls should be focusable. If the controls are
focusable, then trackball and arrow key interactions are possible.
Otherwise, only touch interactions are possible.
int oldFlags = mContainerLayoutParams.flags;
if (focusable) {
mContainerLayoutParams.flags &= ~LayoutParams.FLAG_NOT_FOCUSABLE;
} else {
mContainerLayoutParams.flags |= LayoutParams.FLAG_NOT_FOCUSABLE;
}
if ((mContainerLayoutParams.flags != oldFlags) && mIsVisible) {
mWindowManager.updateViewLayout(mContainer, mContainerLayoutParams);
}
|
public void | setOnZoomListener(android.widget.ZoomButtonsController$OnZoomListener listener)Sets the {@link OnZoomListener} listener that receives callbacks to zoom.
mCallback = listener;
|
private void | setTouchTargetView(android.view.View view)
mTouchTargetView = view;
if (view != null) {
view.getLocationInWindow(mTouchTargetWindowLocation);
}
|
public void | setVisible(boolean visible)Sets whether the zoom controls should be visible to the user.
if (visible) {
if (mOwnerView.getWindowToken() == null) {
/*
* We need a window token to show ourselves, maybe the owner's
* window hasn't been created yet but it will have been by the
* time the looper is idle, so post the setVisible(true) call.
*/
if (!mHandler.hasMessages(MSG_POST_SET_VISIBLE)) {
mHandler.sendEmptyMessage(MSG_POST_SET_VISIBLE);
}
return;
}
dismissControlsDelayed(ZOOM_CONTROLS_TIMEOUT);
}
if (mIsVisible == visible) {
return;
}
mIsVisible = visible;
if (visible) {
if (mContainerLayoutParams.token == null) {
mContainerLayoutParams.token = mOwnerView.getWindowToken();
}
mWindowManager.addView(mContainer, mContainerLayoutParams);
if (mPostedVisibleInitializer == null) {
mPostedVisibleInitializer = new Runnable() {
public void run() {
refreshPositioningVariables();
if (mCallback != null) {
mCallback.onVisibilityChanged(true);
}
}
};
}
mHandler.post(mPostedVisibleInitializer);
// Handle configuration changes when visible
mContext.registerReceiver(mConfigurationChangedReceiver, mConfigurationChangedFilter);
// Steal touches events from the owner
mOwnerView.setOnTouchListener(this);
mReleaseTouchListenerOnUp = false;
} else {
// Don't want to steal any more touches
if (mTouchTargetView != null) {
// We are still stealing the touch events for this touch
// sequence, so release the touch listener later
mReleaseTouchListenerOnUp = true;
} else {
mOwnerView.setOnTouchListener(null);
}
// No longer care about configuration changes
mContext.unregisterReceiver(mConfigurationChangedReceiver);
mWindowManager.removeView(mContainer);
mHandler.removeCallbacks(mPostedVisibleInitializer);
if (mCallback != null) {
mCallback.onVisibilityChanged(false);
}
}
|
public void | setZoomInEnabled(boolean enabled)Whether to enable the zoom in control.
mControls.setIsZoomInEnabled(enabled);
|
public void | setZoomOutEnabled(boolean enabled)Whether to enable the zoom out control.
mControls.setIsZoomOutEnabled(enabled);
|
public void | setZoomSpeed(long speed)Sets the delay between zoom callbacks as the user holds a zoom button.
mControls.setZoomSpeed(speed);
|