diff options
Diffstat (limited to 'core/java/android')
-rw-r--r-- | core/java/android/app/ActionBar.java | 21 | ||||
-rw-r--r-- | core/java/android/app/Activity.java | 27 | ||||
-rw-r--r-- | core/java/android/app/ContextImpl.java | 7 | ||||
-rw-r--r-- | core/java/android/hardware/hdmi/HdmiCecClient.java | 38 | ||||
-rw-r--r-- | core/java/android/hardware/hdmi/HdmiCecManager.java | 10 | ||||
-rw-r--r-- | core/java/android/hardware/hdmi/HdmiCecMessage.java | 39 | ||||
-rw-r--r-- | core/java/android/hardware/hdmi/HdmiPlaybackClient.java | 2 | ||||
-rw-r--r-- | core/java/android/preference/SeekBarVolumizer.java | 91 | ||||
-rw-r--r-- | core/java/android/tv/ITvInputClient.aidl | 3 | ||||
-rw-r--r-- | core/java/android/tv/ITvInputSessionCallback.aidl | 3 | ||||
-rw-r--r-- | core/java/android/tv/TvInputManager.java | 66 | ||||
-rw-r--r-- | core/java/android/tv/TvInputService.java | 65 | ||||
-rw-r--r-- | core/java/android/tv/TvView.java | 19 | ||||
-rw-r--r-- | core/java/android/view/RenderNodeAnimator.java | 16 | ||||
-rw-r--r-- | core/java/android/widget/AbsListView.java | 35 | ||||
-rw-r--r-- | core/java/android/widget/ActionMenuView.java | 7 | ||||
-rw-r--r-- | core/java/android/widget/Toolbar.java | 168 |
17 files changed, 483 insertions, 134 deletions
diff --git a/core/java/android/app/ActionBar.java b/core/java/android/app/ActionBar.java index f05f4c7..d4c4318 100644 --- a/core/java/android/app/ActionBar.java +++ b/core/java/android/app/ActionBar.java @@ -26,6 +26,7 @@ import android.graphics.drawable.Drawable; import android.util.AttributeSet; import android.view.ActionMode; import android.view.Gravity; +import android.view.KeyEvent; import android.view.View; import android.view.ViewDebug; import android.view.ViewGroup; @@ -1013,6 +1014,26 @@ public abstract class ActionBar { return null; } + /** @hide */ + public boolean openOptionsMenu() { + return false; + } + + /** @hide */ + public boolean invalidateOptionsMenu() { + return false; + } + + /** @hide */ + public boolean onMenuKeyEvent(KeyEvent event) { + return false; + } + + /** @hide */ + public boolean collapseActionView() { + return false; + } + /** * Listener interface for ActionBar navigation events. * diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index 5257430..23b5f29 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -2075,15 +2075,16 @@ public class Activity extends ContextThemeWrapper * <p>In order to use a Toolbar within the Activity's window content the application * must not request the window feature {@link Window#FEATURE_ACTION_BAR FEATURE_ACTION_BAR}.</p> * - * @param actionBar Toolbar to set as the Activity's action bar + * @param toolbar Toolbar to set as the Activity's action bar */ - public void setActionBar(@Nullable Toolbar actionBar) { + public void setActionBar(@Nullable Toolbar toolbar) { if (getActionBar() instanceof WindowDecorActionBar) { throw new IllegalStateException("This Activity already has an action bar supplied " + "by the window decor. Do not request Window.FEATURE_ACTION_BAR and set " + "android:windowActionBar to false in your theme to use a Toolbar instead."); } - mActionBar = new ToolbarActionBar(actionBar); + mActionBar = new ToolbarActionBar(toolbar, getTitle(), this); + mActionBar.invalidateOptionsMenu(); } /** @@ -2449,6 +2450,10 @@ public class Activity extends ContextThemeWrapper * but you can override this to do whatever you want. */ public void onBackPressed() { + if (mActionBar != null && mActionBar.collapseActionView()) { + return; + } + if (!mFragments.popBackStackImmediate()) { finishAfterTransition(); } @@ -2660,6 +2665,14 @@ public class Activity extends ContextThemeWrapper */ public boolean dispatchKeyEvent(KeyEvent event) { onUserInteraction(); + + // Let action bars open menus in response to the menu key prioritized over + // the window handling it + if (event.getKeyCode() == KeyEvent.KEYCODE_MENU && + mActionBar != null && mActionBar.onMenuKeyEvent(event)) { + return true; + } + Window win = getWindow(); if (win.superDispatchKeyEvent(event)) { return true; @@ -2907,7 +2920,9 @@ public class Activity extends ContextThemeWrapper * time it needs to be displayed. */ public void invalidateOptionsMenu() { - mWindow.invalidatePanelMenu(Window.FEATURE_OPTIONS_PANEL); + if (mActionBar == null || !mActionBar.invalidateOptionsMenu()) { + mWindow.invalidatePanelMenu(Window.FEATURE_OPTIONS_PANEL); + } } /** @@ -3117,7 +3132,9 @@ public class Activity extends ContextThemeWrapper * open, this method does nothing. */ public void openOptionsMenu() { - mWindow.openPanel(Window.FEATURE_OPTIONS_PANEL, null); + if (mActionBar == null || !mActionBar.openOptionsMenu()) { + mWindow.openPanel(Window.FEATURE_OPTIONS_PANEL, null); + } } /** diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index 8ffa6fe..e66534b 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -58,7 +58,9 @@ import android.hardware.ISerialManager; import android.hardware.SerialManager; import android.hardware.SystemSensorManager; import android.hardware.hdmi.HdmiCecManager; +import android.hardware.hdmi.HdmiControlManager; import android.hardware.hdmi.IHdmiCecService; +import android.hardware.hdmi.IHdmiControlService; import android.hardware.camera2.CameraManager; import android.hardware.display.DisplayManager; import android.hardware.input.InputManager; @@ -388,6 +390,11 @@ class ContextImpl extends Context { return new HdmiCecManager(IHdmiCecService.Stub.asInterface(b)); }}); + registerService(HDMI_CONTROL_SERVICE, new StaticServiceFetcher() { + public Object createStaticService() { + IBinder b = ServiceManager.getService(HDMI_CONTROL_SERVICE); + return new HdmiControlManager(IHdmiControlService.Stub.asInterface(b)); + }}); registerService(CLIPBOARD_SERVICE, new ServiceFetcher() { public Object createService(ContextImpl ctx) { diff --git a/core/java/android/hardware/hdmi/HdmiCecClient.java b/core/java/android/hardware/hdmi/HdmiCecClient.java index cd86cd8..dcb3624 100644 --- a/core/java/android/hardware/hdmi/HdmiCecClient.java +++ b/core/java/android/hardware/hdmi/HdmiCecClient.java @@ -69,44 +69,28 @@ public final class HdmiCecClient { * Send <Active Source> message. */ public void sendActiveSource() { - try { - mService.sendActiveSource(mBinder); - } catch (RemoteException e) { - Log.e(TAG, "sendActiveSource threw exception ", e); - } + Log.w(TAG, "In transition to HdmiControlManager. Will not work."); } /** * Send <Inactive Source> message. */ public void sendInactiveSource() { - try { - mService.sendInactiveSource(mBinder); - } catch (RemoteException e) { - Log.e(TAG, "sendInactiveSource threw exception ", e); - } + Log.w(TAG, "In transition to HdmiControlManager. Will not work."); } /** * Send <Text View On> message. */ public void sendTextViewOn() { - try { - mService.sendTextViewOn(mBinder); - } catch (RemoteException e) { - Log.e(TAG, "sendTextViewOn threw exception ", e); - } + Log.w(TAG, "In transition to HdmiControlManager. Will not work."); } /** * Send <Image View On> message. */ public void sendImageViewOn() { - try { - mService.sendImageViewOn(mBinder); - } catch (RemoteException e) { - Log.e(TAG, "sendImageViewOn threw exception ", e); - } + Log.w(TAG, "In transition to HdmiControlManager. Will not work."); } /** @@ -116,11 +100,7 @@ public final class HdmiCecClient { * {@link HdmiCec#ADDR_TV}. */ public void sendGiveDevicePowerStatus(int address) { - try { - mService.sendGiveDevicePowerStatus(mBinder, address); - } catch (RemoteException e) { - Log.e(TAG, "sendGiveDevicePowerStatus threw exception ", e); - } + Log.w(TAG, "In transition to HdmiControlManager. Will not work."); } /** @@ -133,11 +113,7 @@ public final class HdmiCecClient { * @return true if TV is on; otherwise false. */ public boolean isTvOn() { - try { - return mService.isTvOn(mBinder); - } catch (RemoteException e) { - Log.e(TAG, "isTvOn threw exception ", e); - } - return false; + Log.w(TAG, "In transition to HdmiControlManager. Will not work."); + return true; } } diff --git a/core/java/android/hardware/hdmi/HdmiCecManager.java b/core/java/android/hardware/hdmi/HdmiCecManager.java index 10b058c..03c46d8 100644 --- a/core/java/android/hardware/hdmi/HdmiCecManager.java +++ b/core/java/android/hardware/hdmi/HdmiCecManager.java @@ -45,15 +45,7 @@ public final class HdmiCecManager { * @return {@link HdmiCecClient} instance. {@code null} on failure. */ public HdmiCecClient getClient(int type, HdmiCecClient.Listener listener) { - if (mService == null) { - return null; - } - try { - IBinder b = mService.allocateLogicalDevice(type, getListenerWrapper(listener)); - return HdmiCecClient.create(mService, b); - } catch (RemoteException e) { - return null; - } + return HdmiCecClient.create(mService, null); } private IHdmiCecListener getListenerWrapper(final HdmiCecClient.Listener listener) { diff --git a/core/java/android/hardware/hdmi/HdmiCecMessage.java b/core/java/android/hardware/hdmi/HdmiCecMessage.java index ddaf870..62fa279 100644 --- a/core/java/android/hardware/hdmi/HdmiCecMessage.java +++ b/core/java/android/hardware/hdmi/HdmiCecMessage.java @@ -46,7 +46,7 @@ public final class HdmiCecMessage implements Parcelable { public HdmiCecMessage(int source, int destination, int opcode, byte[] params) { mSource = source; mDestination = destination; - mOpcode = opcode; + mOpcode = opcode & 0xFF; mParams = Arrays.copyOf(params, params.length); } @@ -123,6 +123,7 @@ public final class HdmiCecMessage implements Parcelable { * @param p HdmiCecMessage object to read the Rating from * @return a new HdmiCecMessage created from the data in the parcel */ + @Override public HdmiCecMessage createFromParcel(Parcel p) { int source = p.readInt(); int destination = p.readInt(); @@ -131,6 +132,7 @@ public final class HdmiCecMessage implements Parcelable { p.readByteArray(params); return new HdmiCecMessage(source, destination, opcode, params); } + @Override public HdmiCecMessage[] newArray(int size) { return new HdmiCecMessage[size]; } @@ -139,11 +141,40 @@ public final class HdmiCecMessage implements Parcelable { @Override public String toString() { StringBuffer s = new StringBuffer(); - s.append(String.format("src: %d dst: %d op: %2X params: ", mSource, mDestination, mOpcode)); - for (byte data : mParams) { - s.append(String.format("%02X ", data)); + s.append(String.format("<%s> src: %d, dst: %d", + opcodeToString(mOpcode), mSource, mDestination)); + if (mParams.length > 0) { + s.append(", params:"); + for (byte data : mParams) { + s.append(String.format(" %02X", data)); + } } return s.toString(); } + + private static String opcodeToString(int opcode) { + switch (opcode) { + case HdmiCec.MESSAGE_FEATURE_ABORT: + return "Feature Abort"; + case HdmiCec.MESSAGE_CEC_VERSION: + return "CEC Version"; + case HdmiCec.MESSAGE_REQUEST_ARC_INITIATION: + return "Request ARC Initiation"; + case HdmiCec.MESSAGE_REQUEST_ARC_TERMINATION: + return "Request ARC Termination"; + case HdmiCec.MESSAGE_REPORT_ARC_INITIATED: + return "Report ARC Initiated"; + case HdmiCec.MESSAGE_REPORT_ARC_TERMINATED: + return "Report ARC Terminated"; + case HdmiCec.MESSAGE_TEXT_VIEW_ON: + return "Text View On"; + case HdmiCec.MESSAGE_ACTIVE_SOURCE: + return "Active Source"; + case HdmiCec.MESSAGE_GIVE_DEVICE_POWER_STATUS: + return "Give Device Power Status"; + default: + return String.format("Opcode: %02X", opcode); + } + } } diff --git a/core/java/android/hardware/hdmi/HdmiPlaybackClient.java b/core/java/android/hardware/hdmi/HdmiPlaybackClient.java index 83da29a..f0bd237 100644 --- a/core/java/android/hardware/hdmi/HdmiPlaybackClient.java +++ b/core/java/android/hardware/hdmi/HdmiPlaybackClient.java @@ -90,7 +90,7 @@ public final class HdmiPlaybackClient { public void queryDisplayStatus(DisplayStatusCallback callback) { // TODO: PendingResult. try { - mService.oneTouchPlay(getCallbackWrapper(callback)); + mService.queryDisplayStatus(getCallbackWrapper(callback)); } catch (RemoteException e) { Log.e(TAG, "queryDisplayStatus threw exception ", e); } diff --git a/core/java/android/preference/SeekBarVolumizer.java b/core/java/android/preference/SeekBarVolumizer.java index 5e005d0..d66fc0f 100644 --- a/core/java/android/preference/SeekBarVolumizer.java +++ b/core/java/android/preference/SeekBarVolumizer.java @@ -16,7 +16,10 @@ package android.preference; +import android.content.BroadcastReceiver; import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; import android.database.ContentObserver; import android.media.AudioManager; import android.media.Ringtone; @@ -45,11 +48,14 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba private final Context mContext; private final Handler mHandler; + private final H mUiHandler = new H(); private final Callback mCallback; private final Uri mDefaultUri; private final AudioManager mAudioManager; private final int mStreamType; private final int mMaxStreamVolume; + private final Receiver mReceiver = new Receiver(); + private final Observer mVolumeObserver; private int mOriginalStreamVolume; private Ringtone mRingtone; @@ -63,17 +69,6 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba private static final int MSG_INIT_SAMPLE = 3; private static final int CHECK_RINGTONE_PLAYBACK_DELAY_MS = 1000; - private ContentObserver mVolumeObserver = new ContentObserver(new Handler()) { - @Override - public void onChange(boolean selfChange) { - super.onChange(selfChange); - if (mSeekBar != null && mAudioManager != null) { - int volume = mAudioManager.getStreamVolume(mStreamType); - mSeekBar.setProgress(volume); - } - } - }; - public SeekBarVolumizer(Context context, int streamType, Uri defaultUri, Callback callback) { mContext = context; @@ -85,10 +80,11 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba mHandler = new Handler(thread.getLooper(), this); mCallback = callback; mOriginalStreamVolume = mAudioManager.getStreamVolume(mStreamType); + mVolumeObserver = new Observer(mHandler); mContext.getContentResolver().registerContentObserver( System.getUriFor(System.VOLUME_SETTINGS[mStreamType]), false, mVolumeObserver); - + mReceiver.setListening(true); if (defaultUri == null) { if (mStreamType == AudioManager.STREAM_RING) { defaultUri = Settings.System.DEFAULT_RINGTONE_URI; @@ -103,6 +99,9 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba } public void setSeekBar(SeekBar seekBar) { + if (mSeekBar != null) { + mSeekBar.setOnSeekBarChangeListener(null); + } mSeekBar = seekBar; mSeekBar.setOnSeekBarChangeListener(null); mSeekBar.setMax(mMaxStreamVolume); @@ -150,7 +149,11 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba mCallback.onSampleStarting(this); } if (mRingtone != null) { - mRingtone.play(); + try { + mRingtone.play(); + } catch (Throwable e) { + Log.w(TAG, "Error playing ringtone, stream " + mStreamType, e); + } } } } @@ -172,6 +175,8 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba postStopSample(); mContext.getContentResolver().unregisterContentObserver(mVolumeObserver); mSeekBar.setOnSeekBarChangeListener(null); + mReceiver.setListening(false); + mHandler.getLooper().quitSafely(); } public void revertVolume() { @@ -252,4 +257,62 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba postSetVolume(mLastProgress); } } -}
\ No newline at end of file + + private final class H extends Handler { + private static final int UPDATE_SLIDER = 1; + + @Override + public void handleMessage(Message msg) { + if (msg.what == UPDATE_SLIDER) { + if (mSeekBar != null) { + mSeekBar.setProgress(msg.arg1); + mLastProgress = mSeekBar.getProgress(); + } + } + } + + public void postUpdateSlider(int volume) { + obtainMessage(UPDATE_SLIDER, volume, 0).sendToTarget(); + } + } + + private final class Observer extends ContentObserver { + public Observer(Handler handler) { + super(handler); + } + + @Override + public void onChange(boolean selfChange) { + super.onChange(selfChange); + if (mSeekBar != null && mAudioManager != null) { + final int volume = mAudioManager.getStreamVolume(mStreamType); + mUiHandler.postUpdateSlider(volume); + } + } + } + + private final class Receiver extends BroadcastReceiver { + private boolean mListening; + + public void setListening(boolean listening) { + if (mListening == listening) return; + mListening = listening; + if (listening) { + final IntentFilter filter = new IntentFilter(AudioManager.VOLUME_CHANGED_ACTION); + mContext.registerReceiver(this, filter); + } else { + mContext.unregisterReceiver(this); + } + } + + @Override + public void onReceive(Context context, Intent intent) { + if (!AudioManager.VOLUME_CHANGED_ACTION.equals(intent.getAction())) return; + final int streamType = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, -1); + final int streamValue = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, -1); + if (mSeekBar != null && streamType == mStreamType && streamValue != -1) { + mUiHandler.postUpdateSlider(streamValue); + } + } + } +} diff --git a/core/java/android/tv/ITvInputClient.aidl b/core/java/android/tv/ITvInputClient.aidl index ac83356..ef89c68 100644 --- a/core/java/android/tv/ITvInputClient.aidl +++ b/core/java/android/tv/ITvInputClient.aidl @@ -17,6 +17,7 @@ package android.tv; import android.content.ComponentName; +import android.os.Bundle; import android.tv.ITvInputSession; import android.view.InputChannel; @@ -29,4 +30,6 @@ oneway interface ITvInputClient { void onSessionCreated(in String inputId, IBinder token, in InputChannel channel, int seq); void onAvailabilityChanged(in String inputId, boolean isAvailable); void onSessionReleased(int seq); + void onSessionEvent(in String name, in Bundle args, int seq); + void onVideoSizeChanged(int width, int height, int seq); } diff --git a/core/java/android/tv/ITvInputSessionCallback.aidl b/core/java/android/tv/ITvInputSessionCallback.aidl index a2bd0d7..e27b8bf 100644 --- a/core/java/android/tv/ITvInputSessionCallback.aidl +++ b/core/java/android/tv/ITvInputSessionCallback.aidl @@ -16,6 +16,7 @@ package android.tv; +import android.os.Bundle; import android.tv.ITvInputSession; /** @@ -25,4 +26,6 @@ import android.tv.ITvInputSession; */ oneway interface ITvInputSessionCallback { void onSessionCreated(ITvInputSession session); + void onSessionEvent(in String name, in Bundle args); + void onVideoSizeChanged(int width, int height); } diff --git a/core/java/android/tv/TvInputManager.java b/core/java/android/tv/TvInputManager.java index dfa84f8..d0c2ca6 100644 --- a/core/java/android/tv/TvInputManager.java +++ b/core/java/android/tv/TvInputManager.java @@ -18,6 +18,7 @@ package android.tv; import android.graphics.Rect; import android.net.Uri; +import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.Looper; @@ -85,6 +86,29 @@ public final class TvInputManager { */ public void onSessionReleased(Session session) { } + + /** + * This is called at the beginning of the playback of a channel and later when the size of + * the video has been changed. + * + * @param session A {@link TvInputManager.Session} associated with this callback + * @param width the width of the video + * @param height the height of the video + * @hide + */ + public void onVideoSizeChanged(Session session, int width, int height) { + } + + /** + * This is called when a custom event has been sent from this session. + * + * @param session A {@link TvInputManager.Session} associated with this callback + * @param eventType The type of the event. + * @param eventArgs Optional arguments of the event. + * @hide + */ + public void onSessionEvent(Session session, String eventType, Bundle eventArgs) { + } } private static final class SessionCallbackRecord { @@ -116,6 +140,24 @@ public final class TvInputManager { } }); } + + public void postVideoSizeChanged(final int width, final int height) { + mHandler.post(new Runnable() { + @Override + public void run() { + mSessionCallback.onVideoSizeChanged(mSession, width, height); + } + }); + } + + public void postSessionEvent(final String eventType, final Bundle eventArgs) { + mHandler.post(new Runnable() { + @Override + public void run() { + mSessionCallback.onSessionEvent(mSession, eventType, eventArgs); + } + }); + } } /** @@ -196,6 +238,30 @@ public final class TvInputManager { } @Override + public void onVideoSizeChanged(int width, int height, int seq) { + synchronized (mSessionCallbackRecordMap) { + SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq); + if (record == null) { + Log.e(TAG, "Callback not found for seq " + seq); + return; + } + record.postVideoSizeChanged(width, height); + } + } + + @Override + public void onSessionEvent(String eventType, Bundle eventArgs, int seq) { + synchronized (mSessionCallbackRecordMap) { + SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq); + if (record == null) { + Log.e(TAG, "Callback not found for seq " + seq); + return; + } + record.postSessionEvent(eventType, eventArgs); + } + } + + @Override public void onAvailabilityChanged(String inputId, boolean isAvailable) { synchronized (mTvInputListenerRecordsMap) { List<TvInputListenerRecord> records = mTvInputListenerRecordsMap.get(inputId); diff --git a/core/java/android/tv/TvInputService.java b/core/java/android/tv/TvInputService.java index cb0142f..03d24db 100644 --- a/core/java/android/tv/TvInputService.java +++ b/core/java/android/tv/TvInputService.java @@ -23,6 +23,7 @@ import android.content.Intent; import android.graphics.PixelFormat; import android.graphics.Rect; import android.net.Uri; +import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.Message; @@ -156,6 +157,7 @@ public abstract class TvInputService extends Service { private boolean mOverlayViewEnabled; private IBinder mWindowToken; private Rect mOverlayFrame; + private ITvInputSessionCallback mSessionCallback; public TvInputSessionImpl() { mWindowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE); @@ -188,6 +190,52 @@ public abstract class TvInputService extends Service { } /** + * Dispatches an event to the application using this session. + * + * @param eventType The type of the event. + * @param eventArgs Optional arguments of the event. + * @hide + */ + public void dispatchSessionEvent(final String eventType, final Bundle eventArgs) { + if (eventType == null) { + throw new IllegalArgumentException("eventType should not be null."); + } + mHandler.post(new Runnable() { + @Override + public void run() { + try { + if (DEBUG) Log.d(TAG, "dispatchSessionEvent(" + eventType + ")"); + mSessionCallback.onSessionEvent(eventType, eventArgs); + } catch (RemoteException e) { + Log.w(TAG, "error in sending event (event=" + eventType + ")"); + } + } + }); + } + + /** + * Sends the change on the size of the video. This is expected to be called at the + * beginning of the playback and later when the size has been changed. + * + * @param width The width of the video. + * @param height The height of the video. + * @hide + */ + public void dispatchVideoSizeChanged(final int width, final int height) { + mHandler.post(new Runnable() { + @Override + public void run() { + try { + if (DEBUG) Log.d(TAG, "dispatchVideoSizeChanged"); + mSessionCallback.onVideoSizeChanged(width, height); + } catch (RemoteException e) { + Log.w(TAG, "error in dispatchVideoSizeChanged"); + } + } + }); + } + + /** * Called when the session is released. */ public abstract void onRelease(); @@ -394,9 +442,7 @@ public abstract class TvInputService extends Service { mWindowManager.removeView(mOverlayView); mOverlayView = null; } - if (DEBUG) { - Log.d(TAG, "create overlay view(" + frame + ")"); - } + if (DEBUG) Log.d(TAG, "create overlay view(" + frame + ")"); mWindowToken = windowToken; mOverlayFrame = frame; if (!mOverlayViewEnabled) { @@ -431,9 +477,7 @@ public abstract class TvInputService extends Service { * @param frame A new position of the overlay view. */ void relayoutOverlayView(Rect frame) { - if (DEBUG) { - Log.d(TAG, "relayout overlay view(" + frame + ")"); - } + if (DEBUG) Log.d(TAG, "relayoutOverlayView(" + frame + ")"); mOverlayFrame = frame; if (!mOverlayViewEnabled || mOverlayView == null) { return; @@ -449,9 +493,7 @@ public abstract class TvInputService extends Service { * Removes the current overlay view. */ void removeOverlayView(boolean clearWindowToken) { - if (DEBUG) { - Log.d(TAG, "remove overlay view(" + mOverlayView + ")"); - } + if (DEBUG) Log.d(TAG, "removeOverlayView(" + mOverlayView + ")"); if (clearWindowToken) { mWindowToken = null; mOverlayFrame = null; @@ -498,6 +540,10 @@ public abstract class TvInputService extends Service { mOverlayView.getViewRootImpl().dispatchInputEvent(event, receiver); return Session.DISPATCH_IN_PROGRESS; } + + private void setSessionCallback(ITvInputSessionCallback callback) { + mSessionCallback = callback; + } } private final class ServiceHandler extends Handler { @@ -517,6 +563,7 @@ public abstract class TvInputService extends Service { // Failed to create a session. cb.onSessionCreated(null); } else { + sessionImpl.setSessionCallback(cb); ITvInputSession stub = new ITvInputSessionWrapper(TvInputService.this, sessionImpl, channel); cb.onSessionCreated(stub); diff --git a/core/java/android/tv/TvView.java b/core/java/android/tv/TvView.java index 59b6386..2d31701 100644 --- a/core/java/android/tv/TvView.java +++ b/core/java/android/tv/TvView.java @@ -18,6 +18,7 @@ package android.tv; import android.content.Context; import android.graphics.Rect; +import android.os.Bundle; import android.os.Handler; import android.text.TextUtils; import android.tv.TvInputManager.Session; @@ -379,5 +380,23 @@ public class TvView extends SurfaceView { mExternalCallback.onSessionReleased(session); } } + + @Override + public void onVideoSizeChanged(Session session, int width, int height) { + if (DEBUG) { + Log.d(TAG, "onVideoSizeChanged(" + width + ", " + height + ")"); + } + if (mExternalCallback != null) { + mExternalCallback.onVideoSizeChanged(session, width, height); + } + } + + @Override + public void onSessionEvent(TvInputManager.Session session, String eventType, + Bundle eventArgs) { + if (mExternalCallback != null) { + mExternalCallback.onSessionEvent(session, eventType, eventArgs); + } + } } } diff --git a/core/java/android/view/RenderNodeAnimator.java b/core/java/android/view/RenderNodeAnimator.java index e918119..4979059 100644 --- a/core/java/android/view/RenderNodeAnimator.java +++ b/core/java/android/view/RenderNodeAnimator.java @@ -219,6 +219,15 @@ public final class RenderNodeAnimator extends Animator { return mTarget; } + /** + * WARNING: May only be called once!!! + * TODO: Fix above -_- + */ + public void setStartValue(float startValue) { + checkMutable(); + nSetStartValue(mNativePtr.get(), startValue); + } + @Override public void setStartDelay(long startDelay) { checkMutable(); @@ -282,11 +291,12 @@ public final class RenderNodeAnimator extends Animator { } private static native long nCreateAnimator(WeakReference<RenderNodeAnimator> weakThis, - int property, float deltaValue); + int property, float finalValue); private static native long nCreateCanvasPropertyFloatAnimator(WeakReference<RenderNodeAnimator> weakThis, - long canvasProperty, float deltaValue); + long canvasProperty, float finalValue); private static native long nCreateCanvasPropertyPaintAnimator(WeakReference<RenderNodeAnimator> weakThis, - long canvasProperty, int paintField, float deltaValue); + long canvasProperty, int paintField, float finalValue); + private static native void nSetStartValue(long nativePtr, float startValue); private static native void nSetDuration(long nativePtr, long duration); private static native long nGetDuration(long nativePtr); private static native void nSetStartDelay(long nativePtr, long startDelay); diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java index c9eb130..9a46052 100644 --- a/core/java/android/widget/AbsListView.java +++ b/core/java/android/widget/AbsListView.java @@ -2495,17 +2495,25 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te } /** - * Positions the selector in a way that mimics keyboard focus. If the - * selector drawable supports hotspots, this manages the focus hotspot. + * Positions the selector in a way that mimics keyboard focus. */ void positionSelectorLikeFocus(int position, View sel) { + // If we're changing position, update the visibility since the selector + // is technically being detached from the previous selection. + final Drawable selector = mSelector; + final boolean manageState = selector != null && mSelectorPosition != position + && position != INVALID_POSITION; + if (manageState) { + selector.setVisible(false, false); + } + positionSelector(position, sel); - final Drawable selector = mSelector; - if (selector != null && position != INVALID_POSITION) { + if (manageState) { final Rect bounds = mSelectorRect; final float x = bounds.exactCenterX(); final float y = bounds.exactCenterY(); + selector.setVisible(getVisibility() == VISIBLE, false); selector.setHotspot(x, y); } } @@ -2520,8 +2528,18 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te if (sel instanceof SelectionBoundsAdjuster) { ((SelectionBoundsAdjuster)sel).adjustListItemSelectionBounds(selectorRect); } - positionSelector(selectorRect.left, selectorRect.top, selectorRect.right, - selectorRect.bottom); + + // Adjust for selection padding. + selectorRect.left -= mSelectionLeftPadding; + selectorRect.top -= mSelectionTopPadding; + selectorRect.right += mSelectionRightPadding; + selectorRect.bottom += mSelectionBottomPadding; + + // Update the selector drawable. + final Drawable selector = mSelector; + if (selector != null) { + selector.setBounds(selectorRect); + } final boolean isChildViewEnabled = mIsChildViewEnabled; if (sel.isEnabled() != isChildViewEnabled) { @@ -2532,11 +2550,6 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te } } - private void positionSelector(int l, int t, int r, int b) { - mSelectorRect.set(l - mSelectionLeftPadding, t - mSelectionTopPadding, r - + mSelectionRightPadding, b + mSelectionBottomPadding); - } - @Override protected void dispatchDraw(Canvas canvas) { int saveCount = 0; diff --git a/core/java/android/widget/ActionMenuView.java b/core/java/android/widget/ActionMenuView.java index a9a5eae..acee592 100644 --- a/core/java/android/widget/ActionMenuView.java +++ b/core/java/android/widget/ActionMenuView.java @@ -570,9 +570,9 @@ public class ActionMenuView extends LinearLayout implements MenuBuilder.ItemInvo mMenu = new MenuBuilder(context); mMenu.setCallback(new MenuBuilderCallback()); mPresenter = new ActionMenuPresenter(context); - mPresenter.setMenuView(this); mPresenter.setCallback(new ActionMenuPresenterCallback()); mMenu.addMenuPresenter(mPresenter); + mPresenter.setMenuView(this); } return mMenu; @@ -652,6 +652,11 @@ public class ActionMenuView extends LinearLayout implements MenuBuilder.ItemInvo return false; } + /** @hide */ + public void setExpandedActionViewsExclusive(boolean exclusive) { + mPresenter.setExpandedActionViewsExclusive(exclusive); + } + /** * Interface responsible for receiving menu item click events if the items themselves * do not have individual item click listeners. diff --git a/core/java/android/widget/Toolbar.java b/core/java/android/widget/Toolbar.java index f35ca27..419c582 100644 --- a/core/java/android/widget/Toolbar.java +++ b/core/java/android/widget/Toolbar.java @@ -127,6 +127,8 @@ public class Toolbar extends ViewGroup { // Clear me after use. private final ArrayList<View> mTempViews = new ArrayList<View>(); + private final int[] mTempMargins = new int[2]; + private OnMenuItemClickListener mOnMenuItemClickListener; private final ActionMenuView.OnMenuItemClickListener mMenuViewItemClickListener = @@ -220,7 +222,7 @@ public class Toolbar extends ViewGroup { final CharSequence subtitle = a.getText(R.styleable.Toolbar_subtitle); if (!TextUtils.isEmpty(subtitle)) { - setSubtitle(title); + setSubtitle(subtitle); } a.recycle(); } @@ -703,10 +705,23 @@ public class Toolbar extends ViewGroup { * @return The toolbar's Menu */ public Menu getMenu() { - ensureMenuView(); + ensureMenu(); return mMenuView.getMenu(); } + private void ensureMenu() { + ensureMenuView(); + if (mMenuView.peekMenu() == null) { + // Initialize a new menu for the first time. + final MenuBuilder menu = (MenuBuilder) mMenuView.getMenu(); + if (mExpandedMenuPresenter == null) { + mExpandedMenuPresenter = new ExpandedActionViewMenuPresenter(); + } + mMenuView.setExpandedActionViewsExclusive(true); + menu.addMenuPresenter(mExpandedMenuPresenter); + } + } + private void ensureMenuView() { if (mMenuView == null) { mMenuView = new ActionMenuView(getContext()); @@ -928,12 +943,49 @@ public class Toolbar extends ViewGroup { child.measure(childWidthSpec, childHeightSpec); } + /** + * Returns the width + uncollapsed margins + */ + private int measureChildCollapseMargins(View child, + int parentWidthMeasureSpec, int widthUsed, + int parentHeightMeasureSpec, int heightUsed, int[] collapsingMargins) { + final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams(); + + final int leftDiff = lp.leftMargin - collapsingMargins[0]; + final int rightDiff = lp.rightMargin - collapsingMargins[1]; + final int leftMargin = Math.max(0, leftDiff); + final int rightMargin = Math.max(0, rightDiff); + final int hMargins = leftMargin + rightMargin; + collapsingMargins[0] = Math.max(0, -leftDiff); + collapsingMargins[1] = Math.max(0, -rightDiff); + + final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec, + mPaddingLeft + mPaddingRight + hMargins + widthUsed, lp.width); + final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec, + mPaddingTop + mPaddingBottom + lp.topMargin + lp.bottomMargin + + heightUsed, lp.height); + + child.measure(childWidthMeasureSpec, childHeightMeasureSpec); + return child.getMeasuredWidth() + hMargins; + } + @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int width = 0; int height = 0; int childState = 0; + final int[] collapsingMargins = mTempMargins; + final int marginStartIndex; + final int marginEndIndex; + if (isLayoutRtl()) { + marginStartIndex = 1; + marginEndIndex = 0; + } else { + marginStartIndex = 0; + marginEndIndex = 1; + } + // System views measure first. int navWidth = 0; @@ -956,7 +1008,9 @@ public class Toolbar extends ViewGroup { childState = combineMeasuredStates(childState, mCollapseButtonView.getMeasuredState()); } - width += Math.max(getContentInsetStart(), navWidth); + final int contentInsetStart = getContentInsetStart(); + width += Math.max(contentInsetStart, navWidth); + collapsingMargins[marginStartIndex] = Math.max(0, contentInsetStart - navWidth); int menuWidth = 0; if (shouldLayout(mMenuView)) { @@ -968,21 +1022,21 @@ public class Toolbar extends ViewGroup { childState = combineMeasuredStates(childState, mMenuView.getMeasuredState()); } - width += Math.max(getContentInsetEnd(), menuWidth); + final int contentInsetEnd = getContentInsetEnd(); + width += Math.max(contentInsetEnd, menuWidth); + collapsingMargins[marginEndIndex] = Math.max(0, contentInsetEnd - menuWidth); if (shouldLayout(mExpandedActionView)) { - measureChildWithMargins(mExpandedActionView, widthMeasureSpec, width, - heightMeasureSpec, 0); - width += mExpandedActionView.getMeasuredWidth() + - getHorizontalMargins(mExpandedActionView); + width += measureChildCollapseMargins(mExpandedActionView, widthMeasureSpec, width, + heightMeasureSpec, 0, collapsingMargins); height = Math.max(height, mExpandedActionView.getMeasuredHeight() + getVerticalMargins(mExpandedActionView)); childState = combineMeasuredStates(childState, mExpandedActionView.getMeasuredState()); } if (shouldLayout(mLogoView)) { - measureChildWithMargins(mLogoView, widthMeasureSpec, width, heightMeasureSpec, 0); - width += mLogoView.getMeasuredWidth() + getHorizontalMargins(mLogoView); + width += measureChildCollapseMargins(mLogoView, widthMeasureSpec, width, + heightMeasureSpec, 0, collapsingMargins); height = Math.max(height, mLogoView.getMeasuredHeight() + getVerticalMargins(mLogoView)); childState = combineMeasuredStates(childState, mLogoView.getMeasuredState()); @@ -993,17 +1047,18 @@ public class Toolbar extends ViewGroup { final int titleVertMargins = mTitleMarginTop + mTitleMarginBottom; final int titleHorizMargins = mTitleMarginStart + mTitleMarginEnd; if (shouldLayout(mTitleTextView)) { - measureChildWithMargins(mTitleTextView, widthMeasureSpec, width + titleHorizMargins, - heightMeasureSpec, titleVertMargins); + titleWidth = measureChildCollapseMargins(mTitleTextView, widthMeasureSpec, + width + titleHorizMargins, heightMeasureSpec, titleVertMargins, + collapsingMargins); titleWidth = mTitleTextView.getMeasuredWidth() + getHorizontalMargins(mTitleTextView); titleHeight = mTitleTextView.getMeasuredHeight() + getVerticalMargins(mTitleTextView); childState = combineMeasuredStates(childState, mTitleTextView.getMeasuredState()); } if (shouldLayout(mSubtitleTextView)) { - measureChildWithMargins(mSubtitleTextView, widthMeasureSpec, width + titleHorizMargins, - heightMeasureSpec, titleHeight + titleVertMargins); - titleWidth = Math.max(titleWidth, mSubtitleTextView.getMeasuredWidth() + - getHorizontalMargins(mSubtitleTextView)); + titleWidth = Math.max(titleWidth, measureChildCollapseMargins(mSubtitleTextView, + widthMeasureSpec, width + titleHorizMargins, + heightMeasureSpec, titleHeight + titleVertMargins, + collapsingMargins)); titleHeight += mSubtitleTextView.getMeasuredHeight() + getVerticalMargins(mSubtitleTextView); childState = combineMeasuredStates(childState, mSubtitleTextView.getMeasuredState()); @@ -1021,8 +1076,8 @@ public class Toolbar extends ViewGroup { continue; } - measureChildWithMargins(child, widthMeasureSpec, width, heightMeasureSpec, 0); - width += child.getMeasuredWidth() + getHorizontalMargins(child); + width += measureChildCollapseMargins(child, widthMeasureSpec, width, + heightMeasureSpec, 0, collapsingMargins); height = Math.max(height, child.getMeasuredHeight() + getVerticalMargins(child)); childState = combineMeasuredStates(childState, child.getMeasuredState()); } @@ -1053,46 +1108,51 @@ public class Toolbar extends ViewGroup { int left = paddingLeft; int right = width - paddingRight; + final int[] collapsingMargins = mTempMargins; + collapsingMargins[0] = collapsingMargins[1] = 0; + if (shouldLayout(mNavButtonView)) { if (isRtl) { - right = layoutChildRight(mNavButtonView, right); + right = layoutChildRight(mNavButtonView, right, collapsingMargins); } else { - left = layoutChildLeft(mNavButtonView, left); + left = layoutChildLeft(mNavButtonView, left, collapsingMargins); } } if (shouldLayout(mCollapseButtonView)) { if (isRtl) { - right = layoutChildRight(mCollapseButtonView, right); + right = layoutChildRight(mCollapseButtonView, right, collapsingMargins); } else { - left = layoutChildLeft(mCollapseButtonView, left); + left = layoutChildLeft(mCollapseButtonView, left, collapsingMargins); } } if (shouldLayout(mMenuView)) { if (isRtl) { - left = layoutChildLeft(mMenuView, left); + left = layoutChildLeft(mMenuView, left, collapsingMargins); } else { - right = layoutChildRight(mMenuView, right); + right = layoutChildRight(mMenuView, right, collapsingMargins); } } + collapsingMargins[0] = Math.max(0, getContentInsetLeft() - left); + collapsingMargins[1] = Math.max(0, getContentInsetRight() - (width - paddingRight - right)); left = Math.max(left, getContentInsetLeft()); right = Math.min(right, width - paddingRight - getContentInsetRight()); if (shouldLayout(mExpandedActionView)) { if (isRtl) { - right = layoutChildRight(mExpandedActionView, right); + right = layoutChildRight(mExpandedActionView, right, collapsingMargins); } else { - left = layoutChildLeft(mExpandedActionView, left); + left = layoutChildLeft(mExpandedActionView, left, collapsingMargins); } } if (shouldLayout(mLogoView)) { if (isRtl) { - right = layoutChildRight(mLogoView, right); + right = layoutChildRight(mLogoView, right, collapsingMargins); } else { - left = layoutChildLeft(mLogoView, left); + left = layoutChildLeft(mLogoView, left, collapsingMargins); } } @@ -1141,48 +1201,52 @@ public class Toolbar extends ViewGroup { break; } if (isRtl) { + final int rd = mTitleMarginStart - collapsingMargins[1]; + right -= Math.max(0, rd); + collapsingMargins[1] = Math.max(0, -rd); int titleRight = right; int subtitleRight = right; + if (layoutTitle) { final LayoutParams lp = (LayoutParams) mTitleTextView.getLayoutParams(); - titleRight -= lp.rightMargin + mTitleMarginStart; final int titleLeft = titleRight - mTitleTextView.getMeasuredWidth(); final int titleBottom = titleTop + mTitleTextView.getMeasuredHeight(); mTitleTextView.layout(titleLeft, titleTop, titleRight, titleBottom); - titleRight = titleLeft - lp.leftMargin - mTitleMarginEnd; + titleRight = titleLeft - mTitleMarginEnd; titleTop = titleBottom + lp.bottomMargin; } if (layoutSubtitle) { final LayoutParams lp = (LayoutParams) mSubtitleTextView.getLayoutParams(); - subtitleRight -= lp.rightMargin + mTitleMarginStart; titleTop += lp.topMargin; final int subtitleLeft = subtitleRight - mSubtitleTextView.getMeasuredWidth(); final int subtitleBottom = titleTop + mSubtitleTextView.getMeasuredHeight(); mSubtitleTextView.layout(subtitleLeft, titleTop, subtitleRight, subtitleBottom); - subtitleRight = subtitleRight - lp.leftMargin - mTitleMarginEnd; + subtitleRight = subtitleRight - mTitleMarginEnd; titleTop = subtitleBottom + lp.bottomMargin; } right = Math.max(titleRight, subtitleRight); } else { + final int ld = mTitleMarginStart - collapsingMargins[0]; + left += Math.max(0, ld); + collapsingMargins[0] = Math.max(0, -ld); int titleLeft = left; int subtitleLeft = left; + if (layoutTitle) { final LayoutParams lp = (LayoutParams) mTitleTextView.getLayoutParams(); - titleLeft += lp.leftMargin + mTitleMarginStart; final int titleRight = titleLeft + mTitleTextView.getMeasuredWidth(); final int titleBottom = titleTop + mTitleTextView.getMeasuredHeight(); mTitleTextView.layout(titleLeft, titleTop, titleRight, titleBottom); - titleLeft = titleRight + lp.rightMargin + mTitleMarginEnd; + titleLeft = titleRight + mTitleMarginEnd; titleTop = titleBottom + lp.bottomMargin; } if (layoutSubtitle) { final LayoutParams lp = (LayoutParams) mSubtitleTextView.getLayoutParams(); - subtitleLeft += lp.leftMargin + mTitleMarginStart; titleTop += lp.topMargin; final int subtitleRight = subtitleLeft + mSubtitleTextView.getMeasuredWidth(); final int subtitleBottom = titleTop + mSubtitleTextView.getMeasuredHeight(); mSubtitleTextView.layout(subtitleLeft, titleTop, subtitleRight, subtitleBottom); - subtitleLeft = subtitleRight + lp.rightMargin + mTitleMarginEnd; + subtitleLeft = subtitleRight + mTitleMarginEnd; titleTop = subtitleBottom + lp.bottomMargin; } left = Math.max(titleLeft, subtitleLeft); @@ -1195,19 +1259,19 @@ public class Toolbar extends ViewGroup { addCustomViewsWithGravity(mTempViews, Gravity.LEFT); final int leftViewsCount = mTempViews.size(); for (int i = 0; i < leftViewsCount; i++) { - left = layoutChildLeft(mTempViews.get(i), left); + left = layoutChildLeft(mTempViews.get(i), left, collapsingMargins); } addCustomViewsWithGravity(mTempViews, Gravity.RIGHT); final int rightViewsCount = mTempViews.size(); for (int i = 0; i < rightViewsCount; i++) { - right = layoutChildRight(mTempViews.get(i), right); + right = layoutChildRight(mTempViews.get(i), right, collapsingMargins); } // Centered views try to center with respect to the whole bar, but views pinned // to the left or right can push the mass of centered views to one side or the other. addCustomViewsWithGravity(mTempViews, Gravity.CENTER_HORIZONTAL); - final int centerViewsWidth = getViewListMeasuredWidth(mTempViews); + final int centerViewsWidth = getViewListMeasuredWidth(mTempViews, collapsingMargins); final int parentCenter = paddingLeft + (width - paddingLeft - paddingRight) / 2; final int halfCenterViewsWidth = centerViewsWidth / 2; int centerLeft = parentCenter - halfCenterViewsWidth; @@ -1220,25 +1284,35 @@ public class Toolbar extends ViewGroup { final int centerViewsCount = mTempViews.size(); for (int i = 0; i < centerViewsCount; i++) { - centerLeft = layoutChildLeft(mTempViews.get(i), centerLeft); + centerLeft = layoutChildLeft(mTempViews.get(i), centerLeft, collapsingMargins); } mTempViews.clear(); } - private int getViewListMeasuredWidth(List<View> views) { + private int getViewListMeasuredWidth(List<View> views, int[] collapsingMargins) { + int collapseLeft = collapsingMargins[0]; + int collapseRight = collapsingMargins[1]; int width = 0; final int count = views.size(); for (int i = 0; i < count; i++) { final View v = views.get(i); final LayoutParams lp = (LayoutParams) v.getLayoutParams(); - width += lp.leftMargin + v.getMeasuredWidth() + lp.rightMargin; + final int l = lp.leftMargin - collapseLeft; + final int r = lp.rightMargin - collapseRight; + final int leftMargin = Math.max(0, l); + final int rightMargin = Math.max(0, r); + collapseLeft = Math.max(0, -l); + collapseRight = Math.max(0, -r); + width += leftMargin + v.getMeasuredWidth() + rightMargin; } return width; } - private int layoutChildLeft(View child, int left) { + private int layoutChildLeft(View child, int left, int[] collapsingMargins) { final LayoutParams lp = (LayoutParams) child.getLayoutParams(); - left += lp.leftMargin; + final int l = lp.leftMargin - collapsingMargins[0]; + left += Math.max(0, l); + collapsingMargins[0] = Math.max(0, -l); final int top = getChildTop(child); final int childWidth = child.getMeasuredWidth(); child.layout(left, top, left + childWidth, top + child.getMeasuredHeight()); @@ -1246,9 +1320,11 @@ public class Toolbar extends ViewGroup { return left; } - private int layoutChildRight(View child, int right) { + private int layoutChildRight(View child, int right, int[] collapsingMargins) { final LayoutParams lp = (LayoutParams) child.getLayoutParams(); - right -= lp.rightMargin; + final int r = lp.rightMargin - collapsingMargins[1]; + right -= Math.max(0, r); + collapsingMargins[1] = Math.max(0, -r); final int top = getChildTop(child); final int childWidth = child.getMeasuredWidth(); child.layout(right - childWidth, top, right, top + child.getMeasuredHeight()); |