summaryrefslogtreecommitdiffstats
path: root/core/java/android
diff options
context:
space:
mode:
Diffstat (limited to 'core/java/android')
-rw-r--r--core/java/android/bluetooth/le/BluetoothLeScanner.java5
-rw-r--r--core/java/android/content/Intent.java52
-rw-r--r--core/java/android/hardware/hdmi/HdmiClient.java10
-rw-r--r--core/java/android/hardware/hdmi/HdmiControlManager.java29
-rw-r--r--core/java/android/hardware/hdmi/HdmiTvClient.java18
-rw-r--r--core/java/android/hardware/hdmi/IHdmiControlService.aidl1
-rw-r--r--core/java/android/hardware/hdmi/IHdmiVendorCommandListener.aidl3
-rw-r--r--core/java/android/preference/ListPreference.java4
-rw-r--r--core/java/android/preference/SeekBarVolumizer.java7
-rw-r--r--core/java/android/preference/VolumePreference.java2
-rw-r--r--core/java/android/view/Surface.java123
-rw-r--r--core/java/android/view/ViewGroup.java11
-rw-r--r--core/java/android/view/WindowManager.java9
-rw-r--r--core/java/android/widget/TimePickerSpinnerDelegate.java47
14 files changed, 266 insertions, 55 deletions
diff --git a/core/java/android/bluetooth/le/BluetoothLeScanner.java b/core/java/android/bluetooth/le/BluetoothLeScanner.java
index a57c3ca..93ea299 100644
--- a/core/java/android/bluetooth/le/BluetoothLeScanner.java
+++ b/core/java/android/bluetooth/le/BluetoothLeScanner.java
@@ -51,6 +51,7 @@ public final class BluetoothLeScanner {
private static final String TAG = "BluetoothLeScanner";
private static final boolean DBG = true;
+ private static final boolean VDBG = false;
private final IBluetoothManager mBluetoothManager;
private final Handler mHandler;
@@ -317,7 +318,7 @@ public final class BluetoothLeScanner {
*/
@Override
public void onScanResult(final ScanResult scanResult) {
- if (DBG) Log.d(TAG, "onScanResult() - " + scanResult.toString());
+ if (VDBG) Log.d(TAG, "onScanResult() - " + scanResult.toString());
// Check null in case the scan has been stopped
synchronized (this) {
@@ -346,7 +347,7 @@ public final class BluetoothLeScanner {
@Override
public void onFoundOrLost(final boolean onFound, final ScanResult scanResult) {
- if (DBG) {
+ if (VDBG) {
Log.d(TAG, "onFoundOrLost() - onFound = " + onFound +
" " + scanResult.toString());
}
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index af6f181..7676e4b 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -876,12 +876,44 @@ public class Intent implements Parcelable, Cloneable {
* related methods.
*/
public static Intent createChooser(Intent target, CharSequence title) {
+ return createChooser(target, title, null);
+ }
+
+ /**
+ * Convenience function for creating a {@link #ACTION_CHOOSER} Intent.
+ *
+ * <p>Builds a new {@link #ACTION_CHOOSER} Intent that wraps the given
+ * target intent, also optionally supplying a title. If the target
+ * intent has specified {@link #FLAG_GRANT_READ_URI_PERMISSION} or
+ * {@link #FLAG_GRANT_WRITE_URI_PERMISSION}, then these flags will also be
+ * set in the returned chooser intent, with its ClipData set appropriately:
+ * either a direct reflection of {@link #getClipData()} if that is non-null,
+ * or a new ClipData built from {@link #getData()}.</p>
+ *
+ * <p>The caller may optionally supply an {@link IntentSender} to receive a callback
+ * when the user makes a choice. This can be useful if the calling application wants
+ * to remember the last chosen target and surface it as a more prominent or one-touch
+ * affordance elsewhere in the UI for next time.</p>
+ *
+ * @param target The Intent that the user will be selecting an activity
+ * to perform.
+ * @param title Optional title that will be displayed in the chooser.
+ * @param sender Optional IntentSender to be called when a choice is made.
+ * @return Return a new Intent object that you can hand to
+ * {@link Context#startActivity(Intent) Context.startActivity()} and
+ * related methods.
+ */
+ public static Intent createChooser(Intent target, CharSequence title, IntentSender sender) {
Intent intent = new Intent(ACTION_CHOOSER);
intent.putExtra(EXTRA_INTENT, target);
if (title != null) {
intent.putExtra(EXTRA_TITLE, title);
}
+ if (sender != null) {
+ intent.putExtra(EXTRA_CHOSEN_COMPONENT_INTENT_SENDER, sender);
+ }
+
// Migrate any clip data and flags from target.
int permFlags = target.getFlags() & (FLAG_GRANT_READ_URI_PERMISSION
| FLAG_GRANT_WRITE_URI_PERMISSION | FLAG_GRANT_PERSISTABLE_URI_PERMISSION
@@ -3140,6 +3172,26 @@ public class Intent implements Parcelable, Cloneable {
"android.intent.extra.REPLACEMENT_EXTRAS";
/**
+ * An {@link IntentSender} that will be notified if a user successfully chooses a target
+ * component to handle an action in an {@link #ACTION_CHOOSER} activity. The IntentSender
+ * will have the extra {@link #EXTRA_CHOSEN_COMPONENT} appended to it containing the
+ * {@link ComponentName} of the chosen component.
+ *
+ * <p>In some situations this callback may never come, for example if the user abandons
+ * the chooser, switches to another task or any number of other reasons. Apps should not
+ * be written assuming that this callback will always occur.</p>
+ */
+ public static final String EXTRA_CHOSEN_COMPONENT_INTENT_SENDER =
+ "android.intent.extra.CHOSEN_COMPONENT_INTENT_SENDER";
+
+ /**
+ * The {@link ComponentName} chosen by the user to complete an action.
+ *
+ * @see #EXTRA_CHOSEN_COMPONENT_INTENT_SENDER
+ */
+ public static final String EXTRA_CHOSEN_COMPONENT = "android.intent.extra.CHOSEN_COMPONENT";
+
+ /**
* A {@link android.view.KeyEvent} object containing the event that
* triggered the creation of the Intent it is in.
*/
diff --git a/core/java/android/hardware/hdmi/HdmiClient.java b/core/java/android/hardware/hdmi/HdmiClient.java
index aba90e4..c2b9846 100644
--- a/core/java/android/hardware/hdmi/HdmiClient.java
+++ b/core/java/android/hardware/hdmi/HdmiClient.java
@@ -3,7 +3,6 @@ package android.hardware.hdmi;
import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.hardware.hdmi.HdmiControlManager.VendorCommandListener;
-import android.hardware.hdmi.IHdmiVendorCommandListener;
import android.os.RemoteException;
import android.util.Log;
@@ -91,8 +90,13 @@ public abstract class HdmiClient {
final VendorCommandListener listener) {
return new IHdmiVendorCommandListener.Stub() {
@Override
- public void onReceived(int srcAddress, byte[] params, boolean hasVendorId) {
- listener.onReceived(srcAddress, params, hasVendorId);
+ public void onReceived(int srcAddress, int destAddress, byte[] params,
+ boolean hasVendorId) {
+ listener.onReceived(srcAddress, destAddress, params, hasVendorId);
+ }
+ @Override
+ public void onControlStateChanged(boolean enabled, int reason) {
+ listener.onControlStateChanged(enabled, reason);
}
};
}
diff --git a/core/java/android/hardware/hdmi/HdmiControlManager.java b/core/java/android/hardware/hdmi/HdmiControlManager.java
index 30f3576..ff2ba1e 100644
--- a/core/java/android/hardware/hdmi/HdmiControlManager.java
+++ b/core/java/android/hardware/hdmi/HdmiControlManager.java
@@ -236,6 +236,15 @@ public final class HdmiControlManager {
/** Clear timer error - CEC is disabled. */
public static final int CLEAR_TIMER_STATUS_CEC_DISABLE = 0xA2;
+ /** The HdmiControlService is started. */
+ public static final int CONTROL_STATE_CHANGED_REASON_START = 0;
+ /** The state of HdmiControlService is changed by changing of settings. */
+ public static final int CONTROL_STATE_CHANGED_REASON_SETTING = 1;
+ /** The HdmiControlService is enabled to wake up. */
+ public static final int CONTROL_STATE_CHANGED_REASON_WAKEUP = 2;
+ /** The HdmiControlService will be disabled to standby. */
+ public static final int CONTROL_STATE_CHANGED_REASON_STANDBY = 3;
+
// True if we have a logical device of type playback hosted in the system.
private final boolean mHasPlaybackDevice;
// True if we have a logical device of type TV hosted in the system.
@@ -339,11 +348,29 @@ public final class HdmiControlManager {
* Called when a vendor command is received.
*
* @param srcAddress source logical address
+ * @param destAddress destination logical address
* @param params vendor-specific parameters
* @param hasVendorId {@code true} if the command is &lt;Vendor Command
* With ID&gt;. The first 3 bytes of params is vendor id.
*/
- void onReceived(int srcAddress, byte[] params, boolean hasVendorId);
+ void onReceived(int srcAddress, int destAddress, byte[] params, boolean hasVendorId);
+
+ /**
+ * The callback is called:
+ * <ul>
+ * <li> before HdmiControlService is disabled.
+ * <li> after HdmiControlService is enabled and the local address is assigned.
+ * </ul>
+ * The client shouldn't hold the thread too long since this is a blocking call.
+ *
+ * @param enabled {@code true} if HdmiControlService is enabled.
+ * @param reason the reason code why the state of HdmiControlService is changed.
+ * @see #CONTROL_STATE_CHANGED_REASON_START
+ * @see #CONTROL_STATE_CHANGED_REASON_SETTING
+ * @see #CONTROL_STATE_CHANGED_REASON_WAKEUP
+ * @see #CONTROL_STATE_CHANGED_REASON_STANDBY
+ */
+ void onControlStateChanged(boolean enabled, int reason);
}
/**
diff --git a/core/java/android/hardware/hdmi/HdmiTvClient.java b/core/java/android/hardware/hdmi/HdmiTvClient.java
index 9d92fd9..683d04b 100644
--- a/core/java/android/hardware/hdmi/HdmiTvClient.java
+++ b/core/java/android/hardware/hdmi/HdmiTvClient.java
@@ -22,6 +22,9 @@ import android.hardware.hdmi.HdmiTimerRecordSources.TimerRecordSource;
import android.os.RemoteException;
import android.util.Log;
+import java.util.Collections;
+import java.util.List;
+
import libcore.util.EmptyArray;
/**
@@ -150,6 +153,21 @@ public final class HdmiTvClient extends HdmiClient {
}
/**
+ * Returns all the CEC devices connected to TV.
+ *
+ * @return list of {@link HdmiDeviceInfo} for connected CEC devices.
+ * Empty list is returned if there is none.
+ */
+ public List<HdmiDeviceInfo> getDeviceList() {
+ try {
+ return mService.getDeviceList();
+ } catch (RemoteException e) {
+ Log.e("TAG", "Failed to call getDeviceList():", e);
+ return Collections.<HdmiDeviceInfo>emptyList();
+ }
+ }
+
+ /**
* Set system audio volume
*
* @param oldIndex current volume index
diff --git a/core/java/android/hardware/hdmi/IHdmiControlService.aidl b/core/java/android/hardware/hdmi/IHdmiControlService.aidl
index 4866a9a..c1e924e 100644
--- a/core/java/android/hardware/hdmi/IHdmiControlService.aidl
+++ b/core/java/android/hardware/hdmi/IHdmiControlService.aidl
@@ -59,6 +59,7 @@ interface IHdmiControlService {
void setSystemAudioMute(boolean mute);
void setInputChangeListener(IHdmiInputChangeListener listener);
List<HdmiDeviceInfo> getInputDevices();
+ List<HdmiDeviceInfo> getDeviceList();
void sendVendorCommand(int deviceType, int targetAddress, in byte[] params,
boolean hasVendorId);
void addVendorCommandListener(IHdmiVendorCommandListener listener, int deviceType);
diff --git a/core/java/android/hardware/hdmi/IHdmiVendorCommandListener.aidl b/core/java/android/hardware/hdmi/IHdmiVendorCommandListener.aidl
index 55cc925..a16e878 100644
--- a/core/java/android/hardware/hdmi/IHdmiVendorCommandListener.aidl
+++ b/core/java/android/hardware/hdmi/IHdmiVendorCommandListener.aidl
@@ -23,5 +23,6 @@ package android.hardware.hdmi;
* @hide
*/
oneway interface IHdmiVendorCommandListener {
- void onReceived(int logicalAddress, in byte[] operands, boolean hasVendorId);
+ void onReceived(int logicalAddress, int destAddress, in byte[] operands, boolean hasVendorId);
+ void onControlStateChanged(boolean enabled, int reason);
}
diff --git a/core/java/android/preference/ListPreference.java b/core/java/android/preference/ListPreference.java
index 8081a54..9482a72 100644
--- a/core/java/android/preference/ListPreference.java
+++ b/core/java/android/preference/ListPreference.java
@@ -162,10 +162,10 @@ public class ListPreference extends DialogPreference {
@Override
public CharSequence getSummary() {
final CharSequence entry = getEntry();
- if (mSummary == null || entry == null) {
+ if (mSummary == null) {
return super.getSummary();
} else {
- return String.format(mSummary, entry);
+ return String.format(mSummary, entry == null ? "" : entry);
}
}
diff --git a/core/java/android/preference/SeekBarVolumizer.java b/core/java/android/preference/SeekBarVolumizer.java
index a680b51..3130b64 100644
--- a/core/java/android/preference/SeekBarVolumizer.java
+++ b/core/java/android/preference/SeekBarVolumizer.java
@@ -130,6 +130,7 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba
}
private void postStartSample() {
+ if (mHandler == null) return;
mHandler.removeMessages(MSG_START_SAMPLE);
mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_START_SAMPLE),
isSamplePlaying() ? CHECK_RINGTONE_PLAYBACK_DELAY_MS : 0);
@@ -150,7 +151,8 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba
}
}
- void postStopSample() {
+ private void postStopSample() {
+ if (mHandler == null) return;
// remove pending delayed start messages
mHandler.removeMessages(MSG_START_SAMPLE);
mHandler.removeMessages(MSG_STOP_SAMPLE);
@@ -200,7 +202,8 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba
postSetVolume(progress);
}
- void postSetVolume(int progress) {
+ private void postSetVolume(int progress) {
+ if (mHandler == null) return;
// Do the volume changing separately to give responsive UI
mLastProgress = progress;
mHandler.removeMessages(MSG_SET_STREAM_VOLUME);
diff --git a/core/java/android/preference/VolumePreference.java b/core/java/android/preference/VolumePreference.java
index 86d96f2..0d4c0b6 100644
--- a/core/java/android/preference/VolumePreference.java
+++ b/core/java/android/preference/VolumePreference.java
@@ -117,7 +117,7 @@ public class VolumePreference extends SeekBarDialogPreference implements
public void onActivityStop() {
if (mSeekBarVolumizer != null) {
- mSeekBarVolumizer.postStopSample();
+ mSeekBarVolumizer.stopSample();
}
}
diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java
index 3770b8a..132e25c 100644
--- a/core/java/android/view/Surface.java
+++ b/core/java/android/view/Surface.java
@@ -87,6 +87,8 @@ public class Surface implements Parcelable {
// non compatibility mode.
private Matrix mCompatibleMatrix;
+ private HwuiContext mHwuiContext;
+
/** @hide */
@IntDef({ROTATION_0, ROTATION_90, ROTATION_180, ROTATION_270})
@Retention(RetentionPolicy.SOURCE)
@@ -171,6 +173,10 @@ public class Surface implements Parcelable {
nativeRelease(mNativeObject);
setNativeObjectLocked(0);
}
+ if (mHwuiContext != null) {
+ mHwuiContext.destroy();
+ mHwuiContext = null;
+ }
}
}
@@ -264,27 +270,60 @@ public class Surface implements Parcelable {
* @param canvas The canvas previously obtained from {@link #lockCanvas}.
*/
public void unlockCanvasAndPost(Canvas canvas) {
+ synchronized (mLock) {
+ checkNotReleasedLocked();
+
+ if (mHwuiContext != null) {
+ mHwuiContext.unlockAndPost(canvas);
+ } else {
+ unlockSwCanvasAndPost(canvas);
+ }
+ }
+ }
+
+ private void unlockSwCanvasAndPost(Canvas canvas) {
if (canvas != mCanvas) {
throw new IllegalArgumentException("canvas object must be the same instance that "
+ "was previously returned by lockCanvas");
}
+ if (mNativeObject != mLockedObject) {
+ Log.w(TAG, "WARNING: Surface's mNativeObject (0x" +
+ Long.toHexString(mNativeObject) + ") != mLockedObject (0x" +
+ Long.toHexString(mLockedObject) +")");
+ }
+ if (mLockedObject == 0) {
+ throw new IllegalStateException("Surface was not locked");
+ }
+ try {
+ nativeUnlockCanvasAndPost(mLockedObject, canvas);
+ } finally {
+ nativeRelease(mLockedObject);
+ mLockedObject = 0;
+ }
+ }
+ /**
+ * Gets a {@link Canvas} for drawing into this surface.
+ *
+ * After drawing into the provided {@link Canvas}, the caller must
+ * invoke {@link #unlockCanvasAndPost} to post the new contents to the surface.
+ *
+ * Unlike {@link #lockCanvas(Rect)} this will return a hardware-accelerated
+ * canvas. See the <a href="{@docRoot}guide/topics/graphics/hardware-accel.html#unsupported">
+ * unsupported drawing operations</a> for a list of what is and isn't
+ * supported in a hardware-accelerated canvas.
+ *
+ * @return A canvas for drawing into the surface.
+ *
+ * @throws IllegalStateException If the canvas cannot be locked.
+ */
+ public Canvas lockHardwareCanvas() {
synchronized (mLock) {
checkNotReleasedLocked();
- if (mNativeObject != mLockedObject) {
- Log.w(TAG, "WARNING: Surface's mNativeObject (0x" +
- Long.toHexString(mNativeObject) + ") != mLockedObject (0x" +
- Long.toHexString(mLockedObject) +")");
- }
- if (mLockedObject == 0) {
- throw new IllegalStateException("Surface was not locked");
- }
- try {
- nativeUnlockCanvasAndPost(mLockedObject, canvas);
- } finally {
- nativeRelease(mLockedObject);
- mLockedObject = 0;
+ if (mHwuiContext == null) {
+ mHwuiContext = new HwuiContext();
}
+ return mHwuiContext.lockCanvas();
}
}
@@ -415,6 +454,9 @@ public class Surface implements Parcelable {
}
mNativeObject = ptr;
mGenerationId += 1;
+ if (mHwuiContext != null) {
+ mHwuiContext.updateSurface();
+ }
}
}
@@ -518,4 +560,59 @@ public class Surface implements Parcelable {
mOrigMatrix.set(m);
}
}
+
+ private final class HwuiContext {
+ private final RenderNode mRenderNode;
+ private long mHwuiRenderer;
+ private HardwareCanvas mCanvas;
+
+ HwuiContext() {
+ mRenderNode = RenderNode.create("HwuiCanvas", null);
+ mRenderNode.setClipToBounds(false);
+ mHwuiRenderer = nHwuiCreate(mRenderNode.mNativeRenderNode, mNativeObject);
+ }
+
+ Canvas lockCanvas() {
+ if (mCanvas != null) {
+ throw new IllegalStateException("Surface was already locked!");
+ }
+ mCanvas = mRenderNode.start(0, 0);
+ return mCanvas;
+ }
+
+ void unlockAndPost(Canvas canvas) {
+ if (canvas != mCanvas) {
+ throw new IllegalArgumentException("canvas object must be the same instance that "
+ + "was previously returned by lockCanvas");
+ }
+ mRenderNode.end(mCanvas);
+ mCanvas = null;
+ nHwuiDraw(mHwuiRenderer);
+ }
+
+ void updateSurface() {
+ nHwuiSetSurface(mHwuiRenderer, mNativeObject);
+ }
+
+ void destroy() {
+ if (mHwuiRenderer != 0) {
+ nHwuiDestroy(mHwuiRenderer);
+ mHwuiRenderer = 0;
+ }
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ try {
+ destroy();
+ } finally {
+ super.finalize();
+ }
+ }
+ }
+
+ private static native long nHwuiCreate(long rootNode, long surface);
+ private static native void nHwuiSetSurface(long renderer, long surface);
+ private static native void nHwuiDraw(long renderer);
+ private static native void nHwuiDestroy(long renderer);
}
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 7538dff..134171a 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -4078,9 +4078,10 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
* {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
*/
public void removeView(View view) {
- removeViewInternal(view);
- requestLayout();
- invalidate(true);
+ if (removeViewInternal(view)) {
+ requestLayout();
+ invalidate(true);
+ }
}
/**
@@ -4143,11 +4144,13 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
invalidate(true);
}
- private void removeViewInternal(View view) {
+ private boolean removeViewInternal(View view) {
final int index = indexOfChild(view);
if (index >= 0) {
removeViewInternal(index, view);
+ return true;
}
+ return false;
}
private void removeViewInternal(int index, View view) {
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 47ee52e..75c9ebd 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -523,15 +523,6 @@ public interface WindowManager extends ViewManager {
public static final int TYPE_MAGNIFICATION_OVERLAY = FIRST_SYSTEM_WINDOW+27;
/**
- * Window type: Recents. Same layer as {@link #TYPE_SYSTEM_DIALOG} but only appears on
- * one user's screen.
- * In multiuser systems shows on all users' windows.
- * @hide
- */
- public static final int TYPE_RECENTS_OVERLAY = FIRST_SYSTEM_WINDOW+28;
-
-
- /**
* Window type: keyguard scrim window. Shows if keyguard needs to be restarted.
* In multiuser systems shows on all users' windows.
* @hide
diff --git a/core/java/android/widget/TimePickerSpinnerDelegate.java b/core/java/android/widget/TimePickerSpinnerDelegate.java
index e4342b1..d9c4114 100644
--- a/core/java/android/widget/TimePickerSpinnerDelegate.java
+++ b/core/java/android/widget/TimePickerSpinnerDelegate.java
@@ -105,6 +105,10 @@ class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate im
private String mMinutePickerDescription;
private String mSelectMinutes;
+ // Most recent time announcement values for accessibility.
+ private CharSequence mLastAnnouncedText;
+ private boolean mLastAnnouncedIsHour;
+
private Calendar mTempCalendar;
public TimePickerSpinnerDelegate(TimePicker delegator, Context context, AttributeSet attrs,
@@ -224,11 +228,11 @@ class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate im
// Enable or disable the AM/PM view.
updateHeaderAmPm();
// Update Hour and Minutes
- updateHeaderHour(mInitialHourOfDay, true);
+ updateHeaderHour(mInitialHourOfDay, false);
// Update time separator
updateHeaderSeparator();
// Update Minutes
- updateHeaderMinute(mInitialMinute);
+ updateHeaderMinute(mInitialMinute, false);
// Invalidate everything
mDelegator.invalidate();
}
@@ -293,7 +297,7 @@ class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate im
return;
}
mInitialHourOfDay = currentHour;
- updateHeaderHour(currentHour, true /* accessibility announce */);
+ updateHeaderHour(currentHour, true);
updateHeaderAmPm();
mRadialTimePickerView.setCurrentHour(currentHour);
mRadialTimePickerView.setAmOrPm(mInitialHourOfDay < 12 ? AM : PM);
@@ -329,7 +333,7 @@ class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate im
return;
}
mInitialMinute = currentMinute;
- updateHeaderMinute(currentMinute);
+ updateHeaderMinute(currentMinute, true);
mRadialTimePickerView.setCurrentMinute(currentMinute);
mDelegator.invalidate();
onTimeChanged();
@@ -357,7 +361,7 @@ class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate im
generateLegalTimesTree();
int hour = mRadialTimePickerView.getCurrentHour();
mInitialHourOfDay = hour;
- updateHeaderHour(hour, false /* no accessibility announce */);
+ updateHeaderHour(hour, false);
updateHeaderAmPm();
updateRadialPicker(mRadialTimePickerView.getCurrentItemShowing());
mDelegator.invalidate();
@@ -604,19 +608,17 @@ class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate im
@Override
public void onValueSelected(int pickerIndex, int newValue, boolean autoAdvance) {
if (pickerIndex == HOUR_INDEX) {
- updateHeaderHour(newValue, false);
- String announcement = String.format("%d", newValue);
if (mAllowAutoAdvance && autoAdvance) {
+ updateHeaderHour(newValue, false);
setCurrentItemShowing(MINUTE_INDEX, true, false);
- announcement += ". " + mSelectMinutes;
+ mRadialTimePickerView.announceForAccessibility(newValue + ". " + mSelectMinutes);
} else {
+ updateHeaderHour(newValue, true);
mRadialTimePickerView.setContentDescription(
mHourPickerDescription + ": " + newValue);
}
-
- mRadialTimePickerView.announceForAccessibility(announcement);
} else if (pickerIndex == MINUTE_INDEX){
- updateHeaderMinute(newValue);
+ updateHeaderMinute(newValue, true);
mRadialTimePickerView.setContentDescription(mMinutePickerDescription + ": " + newValue);
} else if (pickerIndex == AMPM_INDEX) {
updateAmPmLabelStates(newValue);
@@ -664,7 +666,16 @@ class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate im
CharSequence text = String.format(format, value);
mHourView.setText(text);
if (announce) {
- mRadialTimePickerView.announceForAccessibility(text);
+ tryAnnounceForAccessibility(text, true);
+ }
+ }
+
+ private void tryAnnounceForAccessibility(CharSequence text, boolean isHour) {
+ if (mLastAnnouncedIsHour != isHour || !text.equals(mLastAnnouncedText)) {
+ // TODO: Find a better solution, potentially live regions?
+ mDelegator.announceForAccessibility(text);
+ mLastAnnouncedText = text;
+ mLastAnnouncedIsHour = isHour;
}
}
@@ -715,13 +726,15 @@ class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate im
return -1;
}
- private void updateHeaderMinute(int value) {
+ private void updateHeaderMinute(int value, boolean announceForAccessibility) {
if (value == 60) {
value = 0;
}
- CharSequence text = String.format(mCurrentLocale, "%02d", value);
- mRadialTimePickerView.announceForAccessibility(text);
+ final CharSequence text = String.format(mCurrentLocale, "%02d", value);
mMinuteView.setText(text);
+ if (announceForAccessibility) {
+ tryAnnounceForAccessibility(text, false);
+ }
}
/**
@@ -921,8 +934,8 @@ class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate im
if (!allowEmptyDisplay && mTypedTimes.isEmpty()) {
int hour = mRadialTimePickerView.getCurrentHour();
int minute = mRadialTimePickerView.getCurrentMinute();
- updateHeaderHour(hour, true);
- updateHeaderMinute(minute);
+ updateHeaderHour(hour, false);
+ updateHeaderMinute(minute, false);
if (!mIs24HourView) {
updateAmPmLabelStates(hour < 12 ? AM : PM);
}