summaryrefslogtreecommitdiffstats
path: root/core/java
diff options
context:
space:
mode:
Diffstat (limited to 'core/java')
-rwxr-xr-xcore/java/android/animation/ValueAnimator.java2
-rw-r--r--core/java/android/app/Activity.java5
-rw-r--r--core/java/android/app/ActivityOptions.java12
-rw-r--r--core/java/android/app/ActivityThread.java8
-rw-r--r--core/java/android/net/EthernetDataTracker.java19
-rw-r--r--core/java/android/os/Trace.java1
-rw-r--r--core/java/android/server/BluetoothAdapterStateMachine.java58
-rwxr-xr-xcore/java/android/server/BluetoothService.java12
-rw-r--r--core/java/android/view/Choreographer.java33
-rw-r--r--core/java/android/view/ViewTreeObserver.java206
-rw-r--r--core/java/android/widget/AbsListView.java104
-rw-r--r--core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java103
12 files changed, 449 insertions, 114 deletions
diff --git a/core/java/android/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java
index 326f27c..f3a442a 100755
--- a/core/java/android/animation/ValueAnimator.java
+++ b/core/java/android/animation/ValueAnimator.java
@@ -910,7 +910,7 @@ public class ValueAnimator extends Animator {
animationHandler.mPendingAnimations.add(this);
if (mStartDelay == 0) {
// This sets the initial value of the animation, prior to actually starting it running
- setCurrentPlayTime(getCurrentPlayTime());
+ setCurrentPlayTime(0);
mPlayingState = STOPPED;
mRunning = true;
notifyStartListeners();
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 29d96fe..781eea5 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -2540,11 +2540,10 @@ public class Activity extends ContextThemeWrapper
if (item.getItemId() == android.R.id.home && mActionBar != null &&
(mActionBar.getDisplayOptions() & ActionBar.DISPLAY_HOME_AS_UP) != 0) {
if (mParent == null) {
- onNavigateUp();
+ return onNavigateUp();
} else {
- mParent.onNavigateUpFromChild(this);
+ return mParent.onNavigateUpFromChild(this);
}
- return true;
}
return false;
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index b730581..3d0b7d8 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -147,12 +147,17 @@ public class ActivityOptions {
* activity is scaled from a small originating area of the screen to
* its final full representation.
*
+ * <p>If the Intent this is being used with has not set its
+ * {@link android.content.Intent#setSourceBounds Intent.setSourceBounds},
+ * those bounds will be filled in for you based on the initial
+ * bounds passed in here.
+ *
* @param source The View that the new activity is animating from. This
* defines the coordinate space for <var>startX</var> and <var>startY</var>.
* @param startX The x starting location of the new activity, relative to <var>source</var>.
* @param startY The y starting location of the activity, relative to <var>source</var>.
* @param startWidth The initial width of the new activity.
- * @param startWidth The initial height of the new activity.
+ * @param startHeight The initial height of the new activity.
* @return Returns a new ActivityOptions object that you can use to
* supply these options as the options Bundle when starting an activity.
*/
@@ -175,6 +180,11 @@ public class ActivityOptions {
* is scaled from a given position to the new activity window that is
* being started.
*
+ * <p>If the Intent this is being used with has not set its
+ * {@link android.content.Intent#setSourceBounds Intent.setSourceBounds},
+ * those bounds will be filled in for you based on the initial
+ * thumbnail location and size provided here.
+ *
* @param source The View that this thumbnail is animating from. This
* defines the coordinate space for <var>startX</var> and <var>startY</var>.
* @param thumbnail The bitmap that will be shown as the initial thumbnail
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index b55ee26..314f5c2 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -136,7 +136,7 @@ public final class ActivityThread {
/** @hide */
public static final boolean DEBUG_BROADCAST = false;
private static final boolean DEBUG_RESULTS = false;
- private static final boolean DEBUG_BACKUP = true;
+ private static final boolean DEBUG_BACKUP = false;
private static final boolean DEBUG_CONFIGURATION = false;
private static final boolean DEBUG_SERVICE = false;
private static final boolean DEBUG_MEMORY_TRIM = false;
@@ -1172,10 +1172,10 @@ public final class ActivityThread {
case DUMP_PROVIDER: return "DUMP_PROVIDER";
}
}
- return "(unknown)";
+ return Integer.toString(code);
}
public void handleMessage(Message msg) {
- if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + msg.what);
+ if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
switch (msg.what) {
case LAUNCH_ACTIVITY: {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
@@ -1378,7 +1378,7 @@ public final class ActivityThread {
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
}
- if (DEBUG_MESSAGES) Slog.v(TAG, "<<< done: " + msg.what);
+ if (DEBUG_MESSAGES) Slog.v(TAG, "<<< done: " + codeToString(msg.what));
}
private void maybeSnapshot() {
diff --git a/core/java/android/net/EthernetDataTracker.java b/core/java/android/net/EthernetDataTracker.java
index fb09ba5..28bd289 100644
--- a/core/java/android/net/EthernetDataTracker.java
+++ b/core/java/android/net/EthernetDataTracker.java
@@ -59,6 +59,8 @@ public class EthernetDataTracker implements NetworkStateTracker {
private static String sIfaceMatch = "";
private static String mIface = "";
+ private INetworkManagementService mNMService;
+
private static class InterfaceObserver extends INetworkManagementEventObserver.Stub {
private EthernetDataTracker mTracker;
@@ -117,6 +119,13 @@ public class EthernetDataTracker implements NetworkStateTracker {
mIface = iface;
}
+ // we don't get link status indications unless the iface is up - bring it up
+ try {
+ mNMService.setInterfaceUp(iface);
+ } catch (Exception e) {
+ Log.e(TAG, "Error upping interface " + iface + ": " + e);
+ }
+
mNetworkInfo.setIsAvailable(true);
Message msg = mCsHandler.obtainMessage(EVENT_CONFIGURATION_CHANGED, mNetworkInfo);
msg.sendToTarget();
@@ -199,7 +208,7 @@ public class EthernetDataTracker implements NetworkStateTracker {
// register for notifications from NetworkManagement Service
IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
- INetworkManagementService service = INetworkManagementService.Stub.asInterface(b);
+ mNMService = INetworkManagementService.Stub.asInterface(b);
mInterfaceObserver = new InterfaceObserver(this);
@@ -208,12 +217,12 @@ public class EthernetDataTracker implements NetworkStateTracker {
sIfaceMatch = context.getResources().getString(
com.android.internal.R.string.config_ethernet_iface_regex);
try {
- final String[] ifaces = service.listInterfaces();
+ final String[] ifaces = mNMService.listInterfaces();
for (String iface : ifaces) {
if (iface.matches(sIfaceMatch)) {
mIface = iface;
- service.setInterfaceUp(iface);
- InterfaceConfiguration config = service.getInterfaceConfig(iface);
+ mNMService.setInterfaceUp(iface);
+ InterfaceConfiguration config = mNMService.getInterfaceConfig(iface);
mLinkUp = config.isActive();
if (config != null && mHwAddr == null) {
mHwAddr = config.getHardwareAddress();
@@ -230,7 +239,7 @@ public class EthernetDataTracker implements NetworkStateTracker {
}
try {
- service.registerObserver(mInterfaceObserver);
+ mNMService.registerObserver(mInterfaceObserver);
} catch (RemoteException e) {
Log.e(TAG, "Could not register InterfaceObserver " + e);
}
diff --git a/core/java/android/os/Trace.java b/core/java/android/os/Trace.java
index 05acd63..ac9ee26 100644
--- a/core/java/android/os/Trace.java
+++ b/core/java/android/os/Trace.java
@@ -37,6 +37,7 @@ public final class Trace {
public static final long TRACE_TAG_WINDOW_MANAGER = 1L << 5;
public static final long TRACE_TAG_ACTIVITY_MANAGER = 1L << 6;
public static final long TRACE_TAG_SYNC_MANAGER = 1L << 7;
+ public static final long TRACE_TAG_AUDIO = 1L << 8;
private static final long sEnabledTags = nativeGetEnabledTags();
diff --git a/core/java/android/server/BluetoothAdapterStateMachine.java b/core/java/android/server/BluetoothAdapterStateMachine.java
index f543de9..2a994b2 100644
--- a/core/java/android/server/BluetoothAdapterStateMachine.java
+++ b/core/java/android/server/BluetoothAdapterStateMachine.java
@@ -39,7 +39,7 @@ import java.io.PrintWriter;
* (BluetootOn)<----------------------<-
* | ^ -------------------->- |
* | | | |
- * TURN_OFF | | SCAN_MODE_CHANGED m1 | | USER_TURN_ON
+ * USER_TURN_OFF | | SCAN_MODE_CHANGED m1 | | USER_TURN_ON
* AIRPLANE_MODE_ON | | | |
* V | | |
* (Switching) (PerProcessState)
@@ -121,8 +121,10 @@ final class BluetoothAdapterStateMachine extends StateMachine {
private static final int DEVICES_DISCONNECT_TIMEOUT = 103;
// Prepare Bluetooth timeout happens
private static final int PREPARE_BLUETOOTH_TIMEOUT = 104;
- // Bluetooth Powerdown timeout happens
- private static final int POWER_DOWN_TIMEOUT = 105;
+ // Bluetooth turn off wait timeout happens
+ private static final int TURN_OFF_TIMEOUT = 105;
+ // Bluetooth device power off wait timeout happens
+ private static final int POWER_DOWN_TIMEOUT = 106;
private Context mContext;
private BluetoothService mBluetoothService;
@@ -137,13 +139,17 @@ final class BluetoothAdapterStateMachine extends StateMachine {
// this is the BluetoothAdapter state that reported externally
private int mPublicState;
+ // When turning off, broadcast STATE_OFF in the last HotOff state
+ // This is because we do HotOff -> PowerOff -> HotOff for USER_TURN_OFF
+ private boolean mDelayBroadcastStateOff;
// timeout value waiting for all the devices to be disconnected
private static final int DEVICES_DISCONNECT_TIMEOUT_TIME = 3000;
private static final int PREPARE_BLUETOOTH_TIMEOUT_TIME = 10000;
- private static final int POWER_DOWN_TIMEOUT_TIME = 5000;
+ private static final int TURN_OFF_TIMEOUT_TIME = 5000;
+ private static final int POWER_DOWN_TIMEOUT_TIME = 20;
BluetoothAdapterStateMachine(Context context, BluetoothService bluetoothService,
BluetoothAdapter bluetoothAdapter) {
@@ -168,6 +174,7 @@ final class BluetoothAdapterStateMachine extends StateMachine {
setInitialState(mPowerOff);
mPublicState = BluetoothAdapter.STATE_OFF;
+ mDelayBroadcastStateOff = false;
}
/**
@@ -315,6 +322,10 @@ final class BluetoothAdapterStateMachine extends StateMachine {
case SERVICE_RECORD_LOADED:
removeMessages(PREPARE_BLUETOOTH_TIMEOUT);
transitionTo(mHotOff);
+ if (mDelayBroadcastStateOff) {
+ broadcastState(BluetoothAdapter.STATE_OFF);
+ mDelayBroadcastStateOff = false;
+ }
break;
case PREPARE_BLUETOOTH_TIMEOUT:
Log.e(TAG, "Bluetooth adapter SDP failed to load");
@@ -373,8 +384,17 @@ final class BluetoothAdapterStateMachine extends StateMachine {
case AIRPLANE_MODE_ON:
case TURN_COLD:
shutoffBluetooth();
+ // we cannot go to power off state yet, we need wait for the Bluetooth
+ // device power off. Unfortunately the stack does not give a event back
+ // so we wait a little bit here
+ sendMessageDelayed(POWER_DOWN_TIMEOUT,
+ POWER_DOWN_TIMEOUT_TIME);
+ break;
+ case POWER_DOWN_TIMEOUT:
transitionTo(mPowerOff);
- broadcastState(BluetoothAdapter.STATE_OFF);
+ if (!mDelayBroadcastStateOff) {
+ broadcastState(BluetoothAdapter.STATE_OFF);
+ }
break;
case AIRPLANE_MODE_OFF:
if (getBluetoothPersistedSetting()) {
@@ -402,6 +422,9 @@ final class BluetoothAdapterStateMachine extends StateMachine {
recoverStateMachine(TURN_HOT, null);
}
break;
+ case TURN_HOT:
+ deferMessage(message);
+ break;
default:
return NOT_HANDLED;
}
@@ -436,15 +459,17 @@ final class BluetoothAdapterStateMachine extends StateMachine {
}
break;
case POWER_STATE_CHANGED:
- removeMessages(POWER_DOWN_TIMEOUT);
+ removeMessages(TURN_OFF_TIMEOUT);
if (!((Boolean) message.obj)) {
if (mPublicState == BluetoothAdapter.STATE_TURNING_OFF) {
transitionTo(mHotOff);
- finishSwitchingOff();
+ mBluetoothService.finishDisable();
+ mBluetoothService.cleanupAfterFinishDisable();
deferMessage(obtainMessage(TURN_COLD));
if (mContext.getResources().getBoolean
(com.android.internal.R.bool.config_bluetooth_adapter_quick_switch)) {
deferMessage(obtainMessage(TURN_HOT));
+ mDelayBroadcastStateOff = true;
}
}
} else {
@@ -461,7 +486,7 @@ final class BluetoothAdapterStateMachine extends StateMachine {
case ALL_DEVICES_DISCONNECTED:
removeMessages(DEVICES_DISCONNECT_TIMEOUT);
mBluetoothService.switchConnectable(false);
- sendMessageDelayed(POWER_DOWN_TIMEOUT, POWER_DOWN_TIMEOUT_TIME);
+ sendMessageDelayed(TURN_OFF_TIMEOUT, TURN_OFF_TIMEOUT_TIME);
break;
case DEVICES_DISCONNECT_TIMEOUT:
sendMessage(ALL_DEVICES_DISCONNECTED);
@@ -473,7 +498,7 @@ final class BluetoothAdapterStateMachine extends StateMachine {
deferMessage(obtainMessage(TURN_HOT));
}
break;
- case POWER_DOWN_TIMEOUT:
+ case TURN_OFF_TIMEOUT:
transitionTo(mHotOff);
finishSwitchingOff();
// reset the hardware for error recovery
@@ -536,7 +561,7 @@ final class BluetoothAdapterStateMachine extends StateMachine {
DEVICES_DISCONNECT_TIMEOUT_TIME);
} else {
mBluetoothService.switchConnectable(false);
- sendMessageDelayed(POWER_DOWN_TIMEOUT, POWER_DOWN_TIMEOUT_TIME);
+ sendMessageDelayed(TURN_OFF_TIMEOUT, TURN_OFF_TIMEOUT_TIME);
}
// we turn all the way to PowerOff with AIRPLANE_MODE_ON
@@ -610,13 +635,12 @@ final class BluetoothAdapterStateMachine extends StateMachine {
}
break;
case POWER_STATE_CHANGED:
- removeMessages(POWER_DOWN_TIMEOUT);
+ removeMessages(TURN_OFF_TIMEOUT);
if (!((Boolean) message.obj)) {
transitionTo(mHotOff);
- deferMessage(obtainMessage(TURN_COLD));
- if (mContext.getResources().getBoolean
+ if (!mContext.getResources().getBoolean
(com.android.internal.R.bool.config_bluetooth_adapter_quick_switch)) {
- deferMessage(obtainMessage(TURN_HOT));
+ deferMessage(obtainMessage(TURN_COLD));
}
} else {
if (!isTurningOn) {
@@ -629,7 +653,7 @@ final class BluetoothAdapterStateMachine extends StateMachine {
}
}
break;
- case POWER_DOWN_TIMEOUT:
+ case TURN_OFF_TIMEOUT:
transitionTo(mHotOff);
Log.e(TAG, "Power-down timed out, resetting...");
deferMessage(obtainMessage(TURN_COLD));
@@ -676,12 +700,12 @@ final class BluetoothAdapterStateMachine extends StateMachine {
perProcessCallback(false, (IBluetoothStateChangeCallback)message.obj);
if (mBluetoothService.isApplicationStateChangeTrackerEmpty()) {
mBluetoothService.switchConnectable(false);
- sendMessageDelayed(POWER_DOWN_TIMEOUT, POWER_DOWN_TIMEOUT_TIME);
+ sendMessageDelayed(TURN_OFF_TIMEOUT, TURN_OFF_TIMEOUT_TIME);
}
break;
case AIRPLANE_MODE_ON:
mBluetoothService.switchConnectable(false);
- sendMessageDelayed(POWER_DOWN_TIMEOUT, POWER_DOWN_TIMEOUT_TIME);
+ sendMessageDelayed(TURN_OFF_TIMEOUT, TURN_OFF_TIMEOUT_TIME);
allProcessesCallback(false);
// we turn all the way to PowerOff with AIRPLANE_MODE_ON
deferMessage(obtainMessage(AIRPLANE_MODE_ON));
diff --git a/core/java/android/server/BluetoothService.java b/core/java/android/server/BluetoothService.java
index a420734..3cf207f 100755
--- a/core/java/android/server/BluetoothService.java
+++ b/core/java/android/server/BluetoothService.java
@@ -526,6 +526,12 @@ public class BluetoothService extends IBluetooth.Stub {
return false;
}
switchConnectable(false);
+
+ // Bluetooth stack needs a small delay here before adding
+ // SDP records, otherwise dbus stalls for over 30 seconds 1 out of 50 runs
+ try {
+ Thread.sleep(20);
+ } catch (InterruptedException e) {}
updateSdpRecords();
return true;
}
@@ -593,6 +599,12 @@ public class BluetoothService extends IBluetooth.Stub {
// Add SDP records for profiles maintained by Android userspace
addReservedSdpRecords(uuids);
+ // Bluetooth stack need some a small delay here before adding more
+ // SDP records, otherwise dbus stalls for over 30 seconds 1 out of 50 runs
+ try {
+ Thread.sleep(20);
+ } catch (InterruptedException e) {}
+
if (R.getBoolean(com.android.internal.R.bool.config_bluetooth_default_profiles)) {
// Enable profiles maintained by Bluez userspace.
setBluetoothTetheringNative(true, BluetoothPanProfileHandler.NAP_ROLE,
diff --git a/core/java/android/view/Choreographer.java b/core/java/android/view/Choreographer.java
index b319cd5..825f351 100644
--- a/core/java/android/view/Choreographer.java
+++ b/core/java/android/view/Choreographer.java
@@ -92,6 +92,7 @@ public final class Choreographer {
private boolean mFrameScheduled;
private boolean mCallbacksRunning;
private long mLastFrameTimeNanos;
+ private long mFrameIntervalNanos;
/**
* Callback type: Input callback. Runs first.
@@ -116,6 +117,8 @@ public final class Choreographer {
mHandler = new FrameHandler(looper);
mDisplayEventReceiver = USE_VSYNC ? new FrameDisplayEventReceiver(looper) : null;
mLastFrameTimeNanos = Long.MIN_VALUE;
+ mFrameIntervalNanos = (long)(1000000000 /
+ new Display(Display.DEFAULT_DISPLAY, null).getRefreshRate());
mCallbackQueues = new CallbackQueue[CALLBACK_LAST + 1];
for (int i = 0; i <= CALLBACK_LAST; i++) {
@@ -343,17 +346,37 @@ public final class Choreographer {
}
void doFrame(long timestampNanos, int frame) {
+ final long startNanos;
synchronized (mLock) {
if (!mFrameScheduled) {
return; // no work to do
}
- mFrameScheduled = false;
- mLastFrameTimeNanos = timestampNanos;
- }
- final long startNanos;
- if (DEBUG) {
startNanos = System.nanoTime();
+ final long jitterNanos = startNanos - timestampNanos;
+ if (jitterNanos >= mFrameIntervalNanos) {
+ final long lastFrameOffset = jitterNanos % mFrameIntervalNanos;
+ if (DEBUG) {
+ Log.d(TAG, "Missed vsync by " + (jitterNanos * 0.000001f) + " ms "
+ + "which is more than the frame interval of "
+ + (mFrameIntervalNanos * 0.000001f) + " ms! "
+ + "Setting frame time to " + (lastFrameOffset * 0.000001f)
+ + " ms in the past.");
+ }
+ timestampNanos = startNanos - lastFrameOffset;
+ }
+
+ if (timestampNanos < mLastFrameTimeNanos) {
+ if (DEBUG) {
+ Log.d(TAG, "Frame time appears to be going backwards. May be due to a "
+ + "previously skipped frame. Waiting for next vsync");
+ }
+ scheduleVsyncLocked();
+ return;
+ }
+
+ mFrameScheduled = false;
+ mLastFrameTimeNanos = timestampNanos;
}
doCallbacks(Choreographer.CALLBACK_INPUT);
diff --git a/core/java/android/view/ViewTreeObserver.java b/core/java/android/view/ViewTreeObserver.java
index 1c5d436..6a8a60a 100644
--- a/core/java/android/view/ViewTreeObserver.java
+++ b/core/java/android/view/ViewTreeObserver.java
@@ -20,7 +20,6 @@ import android.graphics.Rect;
import android.graphics.Region;
import java.util.ArrayList;
-import java.util.concurrent.CopyOnWriteArrayList;
/**
* A view tree observer is used to register listeners that can be notified of global
@@ -32,12 +31,12 @@ import java.util.concurrent.CopyOnWriteArrayList;
* for more information.
*/
public final class ViewTreeObserver {
- private CopyOnWriteArrayList<OnGlobalFocusChangeListener> mOnGlobalFocusListeners;
- private CopyOnWriteArrayList<OnGlobalLayoutListener> mOnGlobalLayoutListeners;
- private CopyOnWriteArrayList<OnTouchModeChangeListener> mOnTouchModeChangeListeners;
- private CopyOnWriteArrayList<OnComputeInternalInsetsListener> mOnComputeInternalInsetsListeners;
- private CopyOnWriteArrayList<OnScrollChangedListener> mOnScrollChangedListeners;
- private ArrayList<OnPreDrawListener> mOnPreDrawListeners;
+ private CopyOnWriteArray<OnGlobalFocusChangeListener> mOnGlobalFocusListeners;
+ private CopyOnWriteArray<OnGlobalLayoutListener> mOnGlobalLayoutListeners;
+ private CopyOnWriteArray<OnTouchModeChangeListener> mOnTouchModeChangeListeners;
+ private CopyOnWriteArray<OnComputeInternalInsetsListener> mOnComputeInternalInsetsListeners;
+ private CopyOnWriteArray<OnScrollChangedListener> mOnScrollChangedListeners;
+ private CopyOnWriteArray<OnPreDrawListener> mOnPreDrawListeners;
private ArrayList<OnDrawListener> mOnDrawListeners;
private boolean mAlive = true;
@@ -147,7 +146,7 @@ public final class ViewTreeObserver {
* windows behind it should be placed.
*/
public final Rect contentInsets = new Rect();
-
+
/**
* Offsets from the frame of the window at which windows behind it
* are visible.
@@ -166,13 +165,13 @@ public final class ViewTreeObserver {
* can be touched.
*/
public static final int TOUCHABLE_INSETS_FRAME = 0;
-
+
/**
* Option for {@link #setTouchableInsets(int)}: the area inside of
* the content insets can be touched.
*/
public static final int TOUCHABLE_INSETS_CONTENT = 1;
-
+
/**
* Option for {@link #setTouchableInsets(int)}: the area inside of
* the visible insets can be touched.
@@ -195,7 +194,7 @@ public final class ViewTreeObserver {
}
int mTouchableInsets;
-
+
void reset() {
contentInsets.setEmpty();
visibleInsets.setEmpty();
@@ -231,7 +230,7 @@ public final class ViewTreeObserver {
mTouchableInsets = other.mTouchableInsets;
}
}
-
+
/**
* Interface definition for a callback to be invoked when layout has
* completed and the client can compute its interior insets.
@@ -328,7 +327,7 @@ public final class ViewTreeObserver {
checkIsAlive();
if (mOnGlobalFocusListeners == null) {
- mOnGlobalFocusListeners = new CopyOnWriteArrayList<OnGlobalFocusChangeListener>();
+ mOnGlobalFocusListeners = new CopyOnWriteArray<OnGlobalFocusChangeListener>();
}
mOnGlobalFocusListeners.add(listener);
@@ -363,7 +362,7 @@ public final class ViewTreeObserver {
checkIsAlive();
if (mOnGlobalLayoutListeners == null) {
- mOnGlobalLayoutListeners = new CopyOnWriteArrayList<OnGlobalLayoutListener>();
+ mOnGlobalLayoutListeners = new CopyOnWriteArray<OnGlobalLayoutListener>();
}
mOnGlobalLayoutListeners.add(listener);
@@ -413,7 +412,7 @@ public final class ViewTreeObserver {
checkIsAlive();
if (mOnPreDrawListeners == null) {
- mOnPreDrawListeners = new ArrayList<OnPreDrawListener>();
+ mOnPreDrawListeners = new CopyOnWriteArray<OnPreDrawListener>();
}
mOnPreDrawListeners.add(listener);
@@ -485,7 +484,7 @@ public final class ViewTreeObserver {
checkIsAlive();
if (mOnScrollChangedListeners == null) {
- mOnScrollChangedListeners = new CopyOnWriteArrayList<OnScrollChangedListener>();
+ mOnScrollChangedListeners = new CopyOnWriteArray<OnScrollChangedListener>();
}
mOnScrollChangedListeners.add(listener);
@@ -519,7 +518,7 @@ public final class ViewTreeObserver {
checkIsAlive();
if (mOnTouchModeChangeListeners == null) {
- mOnTouchModeChangeListeners = new CopyOnWriteArrayList<OnTouchModeChangeListener>();
+ mOnTouchModeChangeListeners = new CopyOnWriteArray<OnTouchModeChangeListener>();
}
mOnTouchModeChangeListeners.add(listener);
@@ -558,7 +557,7 @@ public final class ViewTreeObserver {
if (mOnComputeInternalInsetsListeners == null) {
mOnComputeInternalInsetsListeners =
- new CopyOnWriteArrayList<OnComputeInternalInsetsListener>();
+ new CopyOnWriteArray<OnComputeInternalInsetsListener>();
}
mOnComputeInternalInsetsListeners.add(listener);
@@ -622,10 +621,16 @@ public final class ViewTreeObserver {
// perform the dispatching. The iterator is a safe guard against listeners that
// could mutate the list by calling the various add/remove methods. This prevents
// the array from being modified while we iterate it.
- final CopyOnWriteArrayList<OnGlobalFocusChangeListener> listeners = mOnGlobalFocusListeners;
+ final CopyOnWriteArray<OnGlobalFocusChangeListener> listeners = mOnGlobalFocusListeners;
if (listeners != null && listeners.size() > 0) {
- for (OnGlobalFocusChangeListener listener : listeners) {
- listener.onGlobalFocusChanged(oldFocus, newFocus);
+ CopyOnWriteArray.Access<OnGlobalFocusChangeListener> access = listeners.start();
+ try {
+ int count = access.size();
+ for (int i = 0; i < count; i++) {
+ access.get(i).onGlobalFocusChanged(oldFocus, newFocus);
+ }
+ } finally {
+ listeners.end();
}
}
}
@@ -640,10 +645,16 @@ public final class ViewTreeObserver {
// perform the dispatching. The iterator is a safe guard against listeners that
// could mutate the list by calling the various add/remove methods. This prevents
// the array from being modified while we iterate it.
- final CopyOnWriteArrayList<OnGlobalLayoutListener> listeners = mOnGlobalLayoutListeners;
+ final CopyOnWriteArray<OnGlobalLayoutListener> listeners = mOnGlobalLayoutListeners;
if (listeners != null && listeners.size() > 0) {
- for (OnGlobalLayoutListener listener : listeners) {
- listener.onGlobalLayout();
+ CopyOnWriteArray.Access<OnGlobalLayoutListener> access = listeners.start();
+ try {
+ int count = access.size();
+ for (int i = 0; i < count; i++) {
+ access.get(i).onGlobalLayout();
+ }
+ } finally {
+ listeners.end();
}
}
}
@@ -658,17 +669,17 @@ public final class ViewTreeObserver {
*/
@SuppressWarnings("unchecked")
public final boolean dispatchOnPreDraw() {
- // NOTE: we *must* clone the listener list to perform the dispatching.
- // The clone is a safe guard against listeners that
- // could mutate the list by calling the various add/remove methods. This prevents
- // the array from being modified while we process it.
boolean cancelDraw = false;
- if (mOnPreDrawListeners != null && mOnPreDrawListeners.size() > 0) {
- final ArrayList<OnPreDrawListener> listeners =
- (ArrayList<OnPreDrawListener>) mOnPreDrawListeners.clone();
- int numListeners = listeners.size();
- for (int i = 0; i < numListeners; ++i) {
- cancelDraw |= !(listeners.get(i).onPreDraw());
+ final CopyOnWriteArray<OnPreDrawListener> listeners = mOnPreDrawListeners;
+ if (listeners != null && listeners.size() > 0) {
+ CopyOnWriteArray.Access<OnPreDrawListener> access = listeners.start();
+ try {
+ int count = access.size();
+ for (int i = 0; i < count; i++) {
+ cancelDraw |= !(access.get(i).onPreDraw());
+ }
+ } finally {
+ listeners.end();
}
}
return cancelDraw;
@@ -693,11 +704,17 @@ public final class ViewTreeObserver {
* @param inTouchMode True if the touch mode is now enabled, false otherwise.
*/
final void dispatchOnTouchModeChanged(boolean inTouchMode) {
- final CopyOnWriteArrayList<OnTouchModeChangeListener> listeners =
+ final CopyOnWriteArray<OnTouchModeChangeListener> listeners =
mOnTouchModeChangeListeners;
if (listeners != null && listeners.size() > 0) {
- for (OnTouchModeChangeListener listener : listeners) {
- listener.onTouchModeChanged(inTouchMode);
+ CopyOnWriteArray.Access<OnTouchModeChangeListener> access = listeners.start();
+ try {
+ int count = access.size();
+ for (int i = 0; i < count; i++) {
+ access.get(i).onTouchModeChanged(inTouchMode);
+ }
+ } finally {
+ listeners.end();
}
}
}
@@ -710,10 +727,16 @@ public final class ViewTreeObserver {
// perform the dispatching. The iterator is a safe guard against listeners that
// could mutate the list by calling the various add/remove methods. This prevents
// the array from being modified while we iterate it.
- final CopyOnWriteArrayList<OnScrollChangedListener> listeners = mOnScrollChangedListeners;
+ final CopyOnWriteArray<OnScrollChangedListener> listeners = mOnScrollChangedListeners;
if (listeners != null && listeners.size() > 0) {
- for (OnScrollChangedListener listener : listeners) {
- listener.onScrollChanged();
+ CopyOnWriteArray.Access<OnScrollChangedListener> access = listeners.start();
+ try {
+ int count = access.size();
+ for (int i = 0; i < count; i++) {
+ access.get(i).onScrollChanged();
+ }
+ } finally {
+ listeners.end();
}
}
}
@@ -722,11 +745,11 @@ public final class ViewTreeObserver {
* Returns whether there are listeners for computing internal insets.
*/
final boolean hasComputeInternalInsetsListeners() {
- final CopyOnWriteArrayList<OnComputeInternalInsetsListener> listeners =
+ final CopyOnWriteArray<OnComputeInternalInsetsListener> listeners =
mOnComputeInternalInsetsListeners;
return (listeners != null && listeners.size() > 0);
}
-
+
/**
* Calls all listeners to compute the current insets.
*/
@@ -735,12 +758,105 @@ public final class ViewTreeObserver {
// perform the dispatching. The iterator is a safe guard against listeners that
// could mutate the list by calling the various add/remove methods. This prevents
// the array from being modified while we iterate it.
- final CopyOnWriteArrayList<OnComputeInternalInsetsListener> listeners =
+ final CopyOnWriteArray<OnComputeInternalInsetsListener> listeners =
mOnComputeInternalInsetsListeners;
if (listeners != null && listeners.size() > 0) {
- for (OnComputeInternalInsetsListener listener : listeners) {
- listener.onComputeInternalInsets(inoutInfo);
+ CopyOnWriteArray.Access<OnComputeInternalInsetsListener> access = listeners.start();
+ try {
+ int count = access.size();
+ for (int i = 0; i < count; i++) {
+ access.get(i).onComputeInternalInsets(inoutInfo);
+ }
+ } finally {
+ listeners.end();
+ }
+ }
+ }
+
+ /**
+ * Copy on write array. This array is not thread safe, and only one loop can
+ * iterate over this array at any given time. This class avoids allocations
+ * until a concurrent modification happens.
+ *
+ * Usage:
+ *
+ * CopyOnWriteArray.Access<MyData> access = array.start();
+ * try {
+ * for (int i = 0; i < access.size(); i++) {
+ * MyData d = access.get(i);
+ * }
+ * } finally {
+ * access.end();
+ * }
+ */
+ static class CopyOnWriteArray<T> {
+ private ArrayList<T> mData = new ArrayList<T>();
+ private ArrayList<T> mDataCopy;
+
+ private final Access<T> mAccess = new Access<T>();
+
+ private boolean mStart;
+
+ static class Access<T> {
+ private ArrayList<T> mData;
+ private int mSize;
+
+ T get(int index) {
+ return mData.get(index);
}
+
+ int size() {
+ return mSize;
+ }
+ }
+
+ CopyOnWriteArray() {
+ }
+
+ private ArrayList<T> getArray() {
+ if (mStart) {
+ if (mDataCopy == null) mDataCopy = new ArrayList<T>(mData);
+ return mDataCopy;
+ }
+ return mData;
+ }
+
+ Access<T> start() {
+ if (mStart) throw new IllegalStateException("Iteration already started");
+ mStart = true;
+ mDataCopy = null;
+ mAccess.mData = mData;
+ mAccess.mSize = mData.size();
+ return mAccess;
+ }
+
+ void end() {
+ if (!mStart) throw new IllegalStateException("Iteration not started");
+ mStart = false;
+ if (mDataCopy != null) {
+ mData = mDataCopy;
+ }
+ mDataCopy = null;
+ }
+
+ int size() {
+ return getArray().size();
+ }
+
+ void add(T item) {
+ getArray().add(item);
+ }
+
+ void addAll(CopyOnWriteArray<T> array) {
+ getArray().addAll(array.mData);
+ }
+
+ void remove(T item) {
+ getArray().remove(item);
+ }
+
+ void clear() {
+ getArray().clear();
}
}
}
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 449870e..5fe0f5f 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -3985,7 +3985,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
}
class PositionScroller implements Runnable {
- private static final int SCROLL_DURATION = 400;
+ private static final int SCROLL_DURATION = 200;
private static final int MOVE_DOWN_POS = 1;
private static final int MOVE_UP_POS = 2;
@@ -4006,21 +4006,35 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
mExtraScroll = ViewConfiguration.get(mContext).getScaledFadingEdgeLength();
}
- void start(int position) {
+ void start(final int position) {
stop();
+ final int childCount = getChildCount();
+ if (childCount == 0) {
+ // Can't scroll without children.
+ if (mDataChanged) {
+ // But we might have something in a minute.
+ post(new Runnable() {
+ @Override public void run() {
+ start(position);
+ }
+ });
+ }
+ return;
+ }
+
final int firstPos = mFirstPosition;
- final int lastPos = firstPos + getChildCount() - 1;
+ final int lastPos = firstPos + childCount - 1;
int viewTravelCount;
- if (position <= firstPos) {
+ if (position < firstPos) {
viewTravelCount = firstPos - position + 1;
mMode = MOVE_UP_POS;
- } else if (position >= lastPos) {
+ } else if (position > lastPos) {
viewTravelCount = position - lastPos + 1;
mMode = MOVE_DOWN_POS;
} else {
- // Already on screen, nothing to do
+ scrollToVisible(position, INVALID_POSITION, SCROLL_DURATION);
return;
}
@@ -4036,7 +4050,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
postOnAnimation(this);
}
- void start(int position, int boundPosition) {
+ void start(final int position, final int boundPosition) {
stop();
if (boundPosition == INVALID_POSITION) {
@@ -4044,11 +4058,25 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
return;
}
+ final int childCount = getChildCount();
+ if (childCount == 0) {
+ // Can't scroll without children.
+ if (mDataChanged) {
+ // But we might have something in a minute.
+ post(new Runnable() {
+ @Override public void run() {
+ start(position, boundPosition);
+ }
+ });
+ }
+ return;
+ }
+
final int firstPos = mFirstPosition;
- final int lastPos = firstPos + getChildCount() - 1;
+ final int lastPos = firstPos + childCount - 1;
int viewTravelCount;
- if (position <= firstPos) {
+ if (position < firstPos) {
final int boundPosFromLast = lastPos - boundPosition;
if (boundPosFromLast < 1) {
// Moving would shift our bound position off the screen. Abort.
@@ -4064,7 +4092,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
viewTravelCount = posTravel;
mMode = MOVE_UP_POS;
}
- } else if (position >= lastPos) {
+ } else if (position > lastPos) {
final int boundPosFromFirst = boundPosition - firstPos;
if (boundPosFromFirst < 1) {
// Moving would shift our bound position off the screen. Abort.
@@ -4081,7 +4109,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
mMode = MOVE_DOWN_POS;
}
} else {
- // Already on screen, nothing to do
+ scrollToVisible(position, boundPosition, SCROLL_DURATION);
return;
}
@@ -4137,6 +4165,60 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
postOnAnimation(this);
}
+ /**
+ * Scroll such that targetPos is in the visible padded region without scrolling
+ * boundPos out of view. Assumes targetPos is onscreen.
+ */
+ void scrollToVisible(int targetPos, int boundPos, int duration) {
+ final int firstPos = mFirstPosition;
+ final int childCount = getChildCount();
+ final int lastPos = firstPos + childCount - 1;
+ final int paddedTop = mListPadding.top;
+ final int paddedBottom = getHeight() - mListPadding.bottom;
+
+ if (targetPos < firstPos || targetPos > lastPos) {
+ Log.w(TAG, "scrollToVisible called with targetPos " + targetPos +
+ " not visible [" + firstPos + ", " + lastPos + "]");
+ }
+ if (boundPos < firstPos || boundPos > lastPos) {
+ // boundPos doesn't matter, it's already offscreen.
+ boundPos = INVALID_POSITION;
+ }
+
+ final View targetChild = getChildAt(targetPos - firstPos);
+ final int targetTop = targetChild.getTop();
+ final int targetBottom = targetChild.getBottom();
+ int scrollBy = 0;
+
+ if (targetBottom > paddedBottom) {
+ scrollBy = targetBottom - paddedBottom;
+ }
+ if (targetTop < paddedTop) {
+ scrollBy = targetTop - paddedTop;
+ }
+
+ if (scrollBy == 0) {
+ return;
+ }
+
+ if (boundPos >= 0) {
+ final View boundChild = getChildAt(boundPos - firstPos);
+ final int boundTop = boundChild.getTop();
+ final int boundBottom = boundChild.getBottom();
+ final int absScroll = Math.abs(scrollBy);
+
+ if (scrollBy < 0 && boundBottom + absScroll > paddedBottom) {
+ // Don't scroll the bound view off the bottom of the screen.
+ scrollBy = Math.max(0, boundBottom - paddedBottom);
+ } else if (scrollBy > 0 && boundTop - absScroll < paddedTop) {
+ // Don't scroll the bound view off the top of the screen.
+ scrollBy = Math.min(0, boundTop - paddedTop);
+ }
+ }
+
+ smoothScrollBy(scrollBy, duration);
+ }
+
void stop() {
removeCallbacks(this);
}
diff --git a/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java b/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java
index 624dea8..a74ecd3 100644
--- a/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java
+++ b/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java
@@ -32,6 +32,7 @@ import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
+import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.accessibility.AccessibilityEvent;
@@ -99,8 +100,11 @@ public class MultiWaveView extends View {
private float mTapRadius;
private float mWaveCenterX;
private float mWaveCenterY;
- private float mVerticalOffset;
+ private int mMaxTargetHeight;
+ private int mMaxTargetWidth;
private float mHorizontalOffset;
+ private float mVerticalOffset;
+
private float mOuterRadius = 0.0f;
private float mHitRadius = 0.0f;
private float mSnapMargin = 0.0f;
@@ -142,6 +146,9 @@ public class MultiWaveView extends View {
private int mTargetDescriptionsResourceId;
private int mDirectionDescriptionsResourceId;
private boolean mAlwaysTrackFinger;
+ private int mHorizontalInset;
+ private int mVerticalInset;
+ private int mGravity = Gravity.TOP;
public MultiWaveView(Context context) {
this(context, null);
@@ -153,10 +160,9 @@ public class MultiWaveView extends View {
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.MultiWaveView);
mOuterRadius = a.getDimension(R.styleable.MultiWaveView_outerRadius, mOuterRadius);
- mHorizontalOffset = a.getDimension(R.styleable.MultiWaveView_horizontalOffset,
- mHorizontalOffset);
- mVerticalOffset = a.getDimension(R.styleable.MultiWaveView_verticalOffset,
- mVerticalOffset);
+// mHorizontalOffset = a.getDimension(R.styleable.MultiWaveView_horizontalOffset,
+// mHorizontalOffset);
+// mVerticalOffset = a.getDimension(R.styleable.MultiWaveView_verticalOffset, mVerticalOffset);
mHitRadius = a.getDimension(R.styleable.MultiWaveView_hitRadius, mHitRadius);
mSnapMargin = a.getDimension(R.styleable.MultiWaveView_snapMargin, mSnapMargin);
mVibrationDuration = a.getInt(R.styleable.MultiWaveView_vibrationDuration,
@@ -169,6 +175,7 @@ public class MultiWaveView extends View {
mOuterRing = new TargetDrawable(res,
a.peekValue(R.styleable.MultiWaveView_waveDrawable).resourceId);
mAlwaysTrackFinger = a.getBoolean(R.styleable.MultiWaveView_alwaysTrackFinger, false);
+ mGravity = a.getInt(R.styleable.MultiWaveView_gravity, Gravity.TOP);
// Read chevron animation drawables
final int chevrons[] = { R.styleable.MultiWaveView_leftChevronDrawable,
@@ -231,16 +238,16 @@ public class MultiWaveView extends View {
@Override
protected int getSuggestedMinimumWidth() {
- // View should be large enough to contain the background + target drawable on either edge
- return mOuterRing.getWidth()
- + (mTargetDrawables.size() > 0 ? (mTargetDrawables.get(0).getWidth()/2) : 0);
+ // View should be large enough to contain the background + handle and
+ // target drawable on either edge.
+ return mOuterRing.getWidth() + mMaxTargetWidth;
}
@Override
protected int getSuggestedMinimumHeight() {
- // View should be large enough to contain the unlock ring + target drawable on either edge
- return mOuterRing.getHeight()
- + (mTargetDrawables.size() > 0 ? (mTargetDrawables.get(0).getHeight()/2) : 0);
+ // View should be large enough to contain the unlock ring + target and
+ // target drawable on either edge
+ return mOuterRing.getHeight() + mMaxTargetHeight;
}
private int resolveMeasured(int measureSpec, int desired)
@@ -265,9 +272,10 @@ public class MultiWaveView extends View {
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
final int minimumWidth = getSuggestedMinimumWidth();
final int minimumHeight = getSuggestedMinimumHeight();
- int viewWidth = resolveMeasured(widthMeasureSpec, minimumWidth);
- int viewHeight = resolveMeasured(heightMeasureSpec, minimumHeight);
- setMeasuredDimension(viewWidth, viewHeight);
+ int computedWidth = resolveMeasured(widthMeasureSpec, minimumWidth);
+ int computedHeight = resolveMeasured(heightMeasureSpec, minimumHeight);
+ setupGravity((computedWidth - minimumWidth), (computedHeight - minimumHeight));
+ setMeasuredDimension(computedWidth, computedHeight);
}
private void switchToState(int state, float x, float y) {
@@ -521,14 +529,25 @@ public class MultiWaveView extends View {
TypedArray array = res.obtainTypedArray(resourceId);
int count = array.length();
ArrayList<TargetDrawable> targetDrawables = new ArrayList<TargetDrawable>(count);
+ int maxWidth = mHandleDrawable.getWidth();
+ int maxHeight = mHandleDrawable.getHeight();
for (int i = 0; i < count; i++) {
TypedValue value = array.peekValue(i);
- targetDrawables.add(new TargetDrawable(res, value != null ? value.resourceId : 0));
+ TargetDrawable target= new TargetDrawable(res, value != null ? value.resourceId : 0);
+ targetDrawables.add(target);
+ maxWidth = Math.max(maxWidth, target.getWidth());
+ maxHeight = Math.max(maxHeight, target.getHeight());
}
- array.recycle();
mTargetResourceId = resourceId;
mTargetDrawables = targetDrawables;
- updateTargetPositions();
+ if (mMaxTargetWidth != maxWidth || mMaxTargetHeight != maxHeight) {
+ mMaxTargetWidth = maxWidth;
+ mMaxTargetHeight = maxHeight;
+ requestLayout(); // required to resize layout and call updateTargetPositions()
+ } else {
+ updateTargetPositions();
+ }
+ array.recycle();
}
/**
@@ -638,23 +657,27 @@ public class MultiWaveView extends View {
boolean handled = false;
switch (action) {
case MotionEvent.ACTION_DOWN:
+ if (DEBUG) Log.v(TAG, "*** DOWN ***");
handleDown(event);
handled = true;
break;
case MotionEvent.ACTION_MOVE:
+ if (DEBUG) Log.v(TAG, "*** MOVE ***");
handleMove(event);
handled = true;
break;
case MotionEvent.ACTION_UP:
+ if (DEBUG) Log.v(TAG, "*** UP ***");
handleMove(event);
handleUp(event);
handled = true;
break;
case MotionEvent.ACTION_CANCEL:
- handleMove(event);
+ if (DEBUG) Log.v(TAG, "*** CANCEL ***");
+ // handleMove(event);
handleCancel(event);
handled = true;
break;
@@ -795,6 +818,11 @@ public class MultiWaveView extends View {
}
mGrabbedState = newState;
if (mOnTriggerListener != null) {
+ if (newState == OnTriggerListener.NO_HANDLE) {
+ mOnTriggerListener.onReleased(this, OnTriggerListener.CENTER_HANDLE);
+ } else {
+ mOnTriggerListener.onGrabbed(this, OnTriggerListener.CENTER_HANDLE);
+ }
mOnTriggerListener.onGrabbedStateChange(this, mGrabbedState);
}
}
@@ -832,13 +860,45 @@ public class MultiWaveView extends View {
moveHandleTo(centerX, centerY, false);
}
+ private void setupGravity(int dx, int dy) {
+ final int layoutDirection = getResolvedLayoutDirection();
+ final int absoluteGravity = Gravity.getAbsoluteGravity(mGravity, layoutDirection);
+
+ switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
+ case Gravity.LEFT:
+ mHorizontalInset = 0;
+ break;
+ case Gravity.RIGHT:
+ mHorizontalInset = dx;
+ break;
+ case Gravity.CENTER_HORIZONTAL:
+ default:
+ mHorizontalInset = dx / 2;
+ break;
+ }
+ switch (absoluteGravity & Gravity.VERTICAL_GRAVITY_MASK) {
+ case Gravity.TOP:
+ mVerticalInset = 0;
+ break;
+ case Gravity.BOTTOM:
+ mVerticalInset = dy;
+ break;
+ case Gravity.CENTER_VERTICAL:
+ default:
+ mVerticalInset = dy / 2;
+ break;
+ }
+ }
+
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
final int width = right - left;
final int height = bottom - top;
- float newWaveCenterX = mHorizontalOffset + Math.max(width, mOuterRing.getWidth() ) / 2;
- float newWaveCenterY = mVerticalOffset + Math.max(height, mOuterRing.getHeight()) / 2;
+ float newWaveCenterX = mHorizontalOffset + mHorizontalInset
+ + Math.max(width, mMaxTargetWidth + mOuterRing.getWidth()) / 2;
+ float newWaveCenterY = mVerticalOffset + mVerticalInset
+ + Math.max(height, + mMaxTargetHeight + mOuterRing.getHeight()) / 2;
if (newWaveCenterX != mWaveCenterX || newWaveCenterY != mWaveCenterY) {
if (mWaveCenterX == 0 && mWaveCenterY == 0) {
performInitialLayout(newWaveCenterX, newWaveCenterY);
@@ -848,9 +908,8 @@ public class MultiWaveView extends View {
mOuterRing.setX(mWaveCenterX);
mOuterRing.setY(Math.max(mWaveCenterY, mWaveCenterY));
-
- updateTargetPositions();
}
+ updateTargetPositions();
if (DEBUG) dump();
}