summaryrefslogtreecommitdiffstats
path: root/core/java/android
diff options
context:
space:
mode:
Diffstat (limited to 'core/java/android')
-rw-r--r--core/java/android/app/ActivityOptions.java5
-rw-r--r--core/java/android/app/AppOpsManager.java81
-rw-r--r--core/java/android/app/EnterTransitionCoordinator.java33
-rw-r--r--core/java/android/app/ExitTransitionCoordinator.java2
-rw-r--r--core/java/android/app/admin/DevicePolicyManager.java2
-rw-r--r--core/java/android/net/ConnectivityManager.java18
-rw-r--r--core/java/android/os/UserManager.java19
-rw-r--r--core/java/android/service/wallpaper/WallpaperService.java6
-rw-r--r--core/java/android/speech/tts/ITextToSpeechService.aidl13
-rw-r--r--core/java/android/speech/tts/SynthesisRequest.java17
-rw-r--r--core/java/android/speech/tts/TextToSpeech.java229
-rw-r--r--core/java/android/speech/tts/TextToSpeechService.java39
-rw-r--r--core/java/android/view/Choreographer.java2
-rw-r--r--core/java/android/view/IWindow.aidl3
-rw-r--r--core/java/android/view/IWindowSession.aidl2
-rw-r--r--core/java/android/view/RenderNodeAnimator.java41
-rw-r--r--core/java/android/view/RenderNodeAnimatorCompat.java144
-rw-r--r--core/java/android/view/SurfaceView.java6
-rw-r--r--core/java/android/view/View.java7
-rw-r--r--core/java/android/view/ViewPropertyAnimatorRT.java11
-rw-r--r--core/java/android/view/ViewRootImpl.java50
-rw-r--r--core/java/android/view/Window.java21
-rw-r--r--core/java/android/view/WindowInsets.java81
-rw-r--r--core/java/android/view/WindowManagerPolicy.java4
24 files changed, 706 insertions, 130 deletions
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index f9c2c8b..fafa948 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -578,9 +578,9 @@ public class ActivityOptions {
mResultData = null;
mResultCode = 0;
mExitCoordinatorIndex = 0;
+ mAnimationType = otherOptions.mAnimationType;
switch (otherOptions.mAnimationType) {
case ANIM_CUSTOM:
- mAnimationType = otherOptions.mAnimationType;
mCustomEnterResId = otherOptions.mCustomEnterResId;
mCustomExitResId = otherOptions.mCustomExitResId;
mThumbnail = null;
@@ -593,7 +593,6 @@ public class ActivityOptions {
mAnimationStartedListener = otherOptions.mAnimationStartedListener;
break;
case ANIM_SCALE_UP:
- mAnimationType = otherOptions.mAnimationType;
mStartX = otherOptions.mStartX;
mStartY = otherOptions.mStartY;
mStartWidth = otherOptions.mStartWidth;
@@ -608,7 +607,6 @@ public class ActivityOptions {
break;
case ANIM_THUMBNAIL_SCALE_UP:
case ANIM_THUMBNAIL_SCALE_DOWN:
- mAnimationType = otherOptions.mAnimationType;
mThumbnail = otherOptions.mThumbnail;
mStartX = otherOptions.mStartX;
mStartY = otherOptions.mStartY;
@@ -621,7 +619,6 @@ public class ActivityOptions {
mAnimationStartedListener = otherOptions.mAnimationStartedListener;
break;
case ANIM_SCENE_TRANSITION:
- mAnimationType = otherOptions.mAnimationType;
mTransitionReceiver = otherOptions.mTransitionReceiver;
mSharedElementNames = otherOptions.mSharedElementNames;
mIsReturning = otherOptions.mIsReturning;
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index a480219..b7e64a2 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -191,7 +191,9 @@ public class AppOpsManager {
/** @hide */
public static final int OP_MUTE_MICROPHONE = 44;
/** @hide */
- public static final int _NUM_OP = 45;
+ public static final int OP_TOAST_WINDOW = 45;
+ /** @hide */
+ public static final int _NUM_OP = 46;
/** Access to coarse location information. */
public static final String OPSTR_COARSE_LOCATION =
@@ -259,7 +261,8 @@ public class AppOpsManager {
OP_COARSE_LOCATION,
OP_COARSE_LOCATION,
OP_GET_USAGE_STATS,
- OP_MUTE_MICROPHONE
+ OP_MUTE_MICROPHONE,
+ OP_TOAST_WINDOW,
};
/**
@@ -312,6 +315,7 @@ public class AppOpsManager {
OPSTR_MONITOR_HIGH_POWER_LOCATION,
null,
null,
+ null,
};
/**
@@ -364,6 +368,7 @@ public class AppOpsManager {
"MONITOR_HIGH_POWER_LOCATION",
"GET_USAGE_STATS",
"OP_MUTE_MICROPHONE",
+ "TOAST_WINDOW",
};
/**
@@ -416,6 +421,7 @@ public class AppOpsManager {
null, // no permission for high power location monitoring
android.Manifest.permission.PACKAGE_USAGE_STATS,
null, // no permission for muting/unmuting microphone
+ null, // no permission for displaying toasts
};
/**
@@ -448,7 +454,7 @@ public class AppOpsManager {
null, //READ_ICC_SMS
null, //WRITE_ICC_SMS
null, //WRITE_SETTINGS
- null, //SYSTEM_ALERT_WINDOW
+ UserManager.DISALLOW_CREATE_WINDOWS, //SYSTEM_ALERT_WINDOW
null, //ACCESS_NOTIFICATIONS
null, //CAMERA
null, //RECORD_AUDIO
@@ -469,6 +475,60 @@ public class AppOpsManager {
null, //MONITOR_HIGH_POWER_LOCATION
null, //GET_USAGE_STATS
UserManager.DISALLOW_UNMUTE_MICROPHONE, // MUTE_MICROPHONE
+ UserManager.DISALLOW_CREATE_WINDOWS, // TOAST_WINDOW
+ };
+
+ /**
+ * This specifies whether each option should allow the system
+ * (and system ui) to bypass the user restriction when active.
+ */
+ private static boolean[] sOpAllowSystemRestrictionBypass = new boolean[] {
+ false, //COARSE_LOCATION
+ false, //FINE_LOCATION
+ false, //GPS
+ false, //VIBRATE
+ false, //READ_CONTACTS
+ false, //WRITE_CONTACTS
+ false, //READ_CALL_LOG
+ false, //WRITE_CALL_LOG
+ false, //READ_CALENDAR
+ false, //WRITE_CALENDAR
+ false, //WIFI_SCAN
+ false, //POST_NOTIFICATION
+ false, //NEIGHBORING_CELLS
+ false, //CALL_PHONE
+ false, //READ_SMS
+ false, //WRITE_SMS
+ false, //RECEIVE_SMS
+ false, //RECEIVE_EMERGECY_SMS
+ false, //RECEIVE_MMS
+ false, //RECEIVE_WAP_PUSH
+ false, //SEND_SMS
+ false, //READ_ICC_SMS
+ false, //WRITE_ICC_SMS
+ false, //WRITE_SETTINGS
+ true, //SYSTEM_ALERT_WINDOW
+ false, //ACCESS_NOTIFICATIONS
+ false, //CAMERA
+ false, //RECORD_AUDIO
+ false, //PLAY_AUDIO
+ false, //READ_CLIPBOARD
+ false, //WRITE_CLIPBOARD
+ false, //TAKE_MEDIA_BUTTONS
+ false, //TAKE_AUDIO_FOCUS
+ false, //AUDIO_MASTER_VOLUME
+ false, //AUDIO_VOICE_VOLUME
+ false, //AUDIO_RING_VOLUME
+ false, //AUDIO_MEDIA_VOLUME
+ false, //AUDIO_ALARM_VOLUME
+ false, //AUDIO_NOTIFICATION_VOLUME
+ false, //AUDIO_BLUETOOTH_VOLUME
+ false, //WAKE_LOCK
+ false, //MONITOR_LOCATION
+ false, //MONITOR_HIGH_POWER_LOCATION
+ false, //GET_USAGE_STATS
+ false, // MUTE_MICROPHONE
+ true, // TOAST_WINDOW
};
/**
@@ -520,6 +580,7 @@ public class AppOpsManager {
AppOpsManager.MODE_ALLOWED,
AppOpsManager.MODE_IGNORED, // OP_GET_USAGE_STATS
AppOpsManager.MODE_ALLOWED,
+ AppOpsManager.MODE_ALLOWED,
};
/**
@@ -575,6 +636,7 @@ public class AppOpsManager {
false,
false,
false,
+ false,
};
private static HashMap<String, Integer> sOpStrToOp = new HashMap<String, Integer>();
@@ -608,6 +670,10 @@ public class AppOpsManager {
throw new IllegalStateException("sOpRestrictions length " + sOpRestrictions.length
+ " should be " + _NUM_OP);
}
+ if (sOpAllowSystemRestrictionBypass.length != _NUM_OP) {
+ throw new IllegalStateException("sOpAllowSYstemRestrictionsBypass length "
+ + sOpRestrictions.length + " should be " + _NUM_OP);
+ }
for (int i=0; i<_NUM_OP; i++) {
if (sOpToString[i] != null) {
sOpStrToOp.put(sOpToString[i], i);
@@ -649,6 +715,15 @@ public class AppOpsManager {
}
/**
+ * Retrieve whether the op allows the system (and system ui) to
+ * bypass the user restriction.
+ * @hide
+ */
+ public static boolean opAllowSystemBypassRestriction(int op) {
+ return sOpAllowSystemRestrictionBypass[op];
+ }
+
+ /**
* Retrieve the default mode for the operation.
* @hide
*/
diff --git a/core/java/android/app/EnterTransitionCoordinator.java b/core/java/android/app/EnterTransitionCoordinator.java
index a8f6539..5e18d0f 100644
--- a/core/java/android/app/EnterTransitionCoordinator.java
+++ b/core/java/android/app/EnterTransitionCoordinator.java
@@ -57,6 +57,7 @@ class EnterTransitionCoordinator extends ActivityTransitionCoordinator {
private boolean mIsReadyForTransition;
private Bundle mSharedElementsBundle;
private boolean mWasOpaque;
+ private boolean mAreViewsReady;
public EnterTransitionCoordinator(Activity activity, ResultReceiver resultReceiver,
ArrayList<String> sharedElementNames, boolean isReturning) {
@@ -81,18 +82,11 @@ class EnterTransitionCoordinator extends ActivityTransitionCoordinator {
}
public void viewInstancesReady(ArrayList<String> accepted, ArrayList<View> localViews) {
- if (mIsReadyForTransition) {
- return;
- }
- viewsReady(mapSharedElements(accepted, localViews));
+ triggerViewsReady(mapSharedElements(accepted, localViews));
}
public void namedViewsReady(ArrayList<String> accepted, ArrayList<String> localNames) {
- if (mIsReadyForTransition) {
- return;
- }
-
- viewsReady(mapNamedElements(accepted, localNames));
+ triggerViewsReady(mapNamedElements(accepted, localNames));
}
@Override
@@ -118,6 +112,27 @@ class EnterTransitionCoordinator extends ActivityTransitionCoordinator {
}
}
+ private void triggerViewsReady(final ArrayMap<String, View> sharedElements) {
+ if (mAreViewsReady) {
+ return;
+ }
+ mAreViewsReady = true;
+ // Ensure the views have been laid out before capturing the views -- we need the epicenter.
+ if (sharedElements.isEmpty() || !sharedElements.valueAt(0).isLayoutRequested()) {
+ viewsReady(sharedElements);
+ } else {
+ sharedElements.valueAt(0).getViewTreeObserver()
+ .addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
+ @Override
+ public boolean onPreDraw() {
+ sharedElements.valueAt(0).getViewTreeObserver().removeOnPreDrawListener(this);
+ viewsReady(sharedElements);
+ return true;
+ }
+ });
+ }
+ }
+
private ArrayMap<String, View> mapNamedElements(ArrayList<String> accepted,
ArrayList<String> localNames) {
ArrayMap<String, View> sharedElements = new ArrayMap<String, View>();
diff --git a/core/java/android/app/ExitTransitionCoordinator.java b/core/java/android/app/ExitTransitionCoordinator.java
index ba34184..93cba0d 100644
--- a/core/java/android/app/ExitTransitionCoordinator.java
+++ b/core/java/android/app/ExitTransitionCoordinator.java
@@ -123,6 +123,8 @@ class ExitTransitionCoordinator extends ActivityTransitionCoordinator {
startSharedElementExit();
}
});
+ } else {
+ sharedElementTransitionComplete();
}
}
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index d18647a..df51ff5 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -2586,6 +2586,8 @@ public class DevicePolicyManager {
* @param packages The list of packages allowed to enter lock task mode
*
* @see Activity#startLockTask()
+ * @see DeviceAdminReceiver#onLockTaskModeChanged(Context, Intent, boolean, String)
+ * @see UserManager#DISALLOW_CREATE_WINDOWS
*/
public void setLockTaskPackages(String[] packages) throws SecurityException {
if (mService != null) {
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index a8b324a..05e179d 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -2208,15 +2208,15 @@ public class ConnectivityManager {
if (need == null) throw new IllegalArgumentException("null NetworkCapabilities");
try {
incCallbackHandlerRefCount();
- if (action == LISTEN) {
- networkCallback.networkRequest = mService.listenForNetwork(need,
- new Messenger(sCallbackHandler), new Binder());
- } else {
- networkCallback.networkRequest = mService.requestNetwork(need,
- new Messenger(sCallbackHandler), timeoutSec, new Binder(), legacyType);
- }
- if (networkCallback.networkRequest != null) {
- synchronized(sNetworkCallback) {
+ synchronized(sNetworkCallback) {
+ if (action == LISTEN) {
+ networkCallback.networkRequest = mService.listenForNetwork(need,
+ new Messenger(sCallbackHandler), new Binder());
+ } else {
+ networkCallback.networkRequest = mService.requestNetwork(need,
+ new Messenger(sCallbackHandler), timeoutSec, new Binder(), legacyType);
+ }
+ if (networkCallback.networkRequest != null) {
sNetworkCallback.put(networkCallback.networkRequest, networkCallback);
}
}
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index b980e81..a54320f 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -27,6 +27,7 @@ import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.provider.Settings;
import android.util.Log;
+import android.view.WindowManager.LayoutParams;
import com.android.internal.R;
@@ -278,6 +279,24 @@ public class UserManager {
*/
public static final String DISALLOW_TELEPHONY = "no_telephony";
+ /**
+ * Key for user restrictions. Specifies that windows besides app windows should not be
+ * created. This will block the creation of the following types of windows.
+ * <li>{@link LayoutParams#TYPE_TOAST}</li>
+ * <li>{@link LayoutParams#TYPE_PHONE}</li>
+ * <li>{@link LayoutParams#TYPE_PRIORITY_PHONE}</li>
+ * <li>{@link LayoutParams#TYPE_SYSTEM_ALERT}</li>
+ * <li>{@link LayoutParams#TYPE_SYSTEM_ERROR}</li>
+ * <li>{@link LayoutParams#TYPE_SYSTEM_OVERLAY}</li>
+ *
+ * <p>The default value is <code>false</code>.
+ * <p/>
+ * Type: Boolean
+ * @see #setUserRestrictions(Bundle)
+ * @see #getUserRestrictions()
+ */
+ public static final String DISALLOW_CREATE_WINDOWS = "no_create_windows";
+
/** @hide */
public static final int PIN_VERIFICATION_FAILED_INCORRECT = -3;
/** @hide */
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index 03ce4e0..f3c26c8 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -154,6 +154,7 @@ public abstract class WallpaperService extends Service {
final Rect mWinFrame = new Rect();
final Rect mOverscanInsets = new Rect();
final Rect mContentInsets = new Rect();
+ final Rect mStableInsets = new Rect();
final Configuration mConfiguration = new Configuration();
final WindowManager.LayoutParams mLayout
@@ -253,7 +254,8 @@ public abstract class WallpaperService extends Service {
final BaseIWindow mWindow = new BaseIWindow() {
@Override
public void resized(Rect frame, Rect overscanInsets, Rect contentInsets,
- Rect visibleInsets, boolean reportDraw, Configuration newConfig) {
+ Rect visibleInsets, Rect stableInsets, boolean reportDraw,
+ Configuration newConfig) {
Message msg = mCaller.obtainMessageI(MSG_WINDOW_RESIZED,
reportDraw ? 1 : 0);
mCaller.sendMessage(msg);
@@ -628,7 +630,7 @@ public abstract class WallpaperService extends Service {
final int relayoutResult = mSession.relayout(
mWindow, mWindow.mSeq, mLayout, mWidth, mHeight,
View.VISIBLE, 0, mWinFrame, mOverscanInsets, mContentInsets,
- mVisibleInsets, mConfiguration, mSurfaceHolder.mSurface);
+ mVisibleInsets, mStableInsets, mConfiguration, mSurfaceHolder.mSurface);
if (DEBUG) Log.v(TAG, "New surface: " + mSurfaceHolder.mSurface
+ ", frame=" + mWinFrame);
diff --git a/core/java/android/speech/tts/ITextToSpeechService.aidl b/core/java/android/speech/tts/ITextToSpeechService.aidl
index 4d322df..694f25a 100644
--- a/core/java/android/speech/tts/ITextToSpeechService.aidl
+++ b/core/java/android/speech/tts/ITextToSpeechService.aidl
@@ -36,8 +36,10 @@ interface ITextToSpeechService {
* @param text The text to synthesize.
* @param queueMode Determines what to do to requests already in the queue.
* @param param Request parameters.
+ * @param utteranceId Unique identifier of synthesized utterance.
*/
- int speak(in IBinder callingInstance, in String text, in int queueMode, in Bundle params);
+ int speak(in IBinder callingInstance, in CharSequence text, in int queueMode, in Bundle params,
+ String utteranceId);
/**
* Tells the engine to synthesize some speech and write it to a file.
@@ -47,10 +49,11 @@ interface ITextToSpeechService {
* @param text The text to synthesize.
* @param fileDescriptor The file descriptor to write the synthesized audio to. Has to be
writable.
+ * @param utteranceId Unique identifier of synthesized utterance.
* @param param Request parameters.
*/
- int synthesizeToFileDescriptor(in IBinder callingInstance, in String text,
- in ParcelFileDescriptor fileDescriptor, in Bundle params);
+ int synthesizeToFileDescriptor(in IBinder callingInstance, in CharSequence text,
+ in ParcelFileDescriptor fileDescriptor, in Bundle params, String utteranceId);
/**
* Plays an existing audio resource.
@@ -59,9 +62,11 @@ interface ITextToSpeechService {
* TextToSpeech object.
* @param audioUri URI for the audio resource (a file or android.resource URI)
* @param queueMode Determines what to do to requests already in the queue.
+ * @param utteranceId Unique identifier of synthesized utterance.
* @param param Request parameters.
*/
- int playAudio(in IBinder callingInstance, in Uri audioUri, in int queueMode, in Bundle params);
+ int playAudio(in IBinder callingInstance, in Uri audioUri, in int queueMode, in Bundle params,
+ String utteranceId);
/**
* Plays silence.
diff --git a/core/java/android/speech/tts/SynthesisRequest.java b/core/java/android/speech/tts/SynthesisRequest.java
index 12a026b..eaacc06 100644
--- a/core/java/android/speech/tts/SynthesisRequest.java
+++ b/core/java/android/speech/tts/SynthesisRequest.java
@@ -34,7 +34,7 @@ import android.os.Bundle;
* and {@link TextToSpeech#synthesizeToFile}.
*/
public final class SynthesisRequest {
- private final String mText;
+ private final CharSequence mText;
private final Bundle mParams;
private String mLanguage;
private String mCountry;
@@ -49,10 +49,25 @@ public final class SynthesisRequest {
mParams = new Bundle(params);
}
+ public SynthesisRequest(CharSequence text, Bundle params) {
+ mText = text;
+ // Makes a copy of params.
+ mParams = new Bundle(params);
+ }
+
/**
* Gets the text which should be synthesized.
+ * @deprecated As of API level 20, replaced by {@link #getCharSequenceText}.
*/
+ @Deprecated
public String getText() {
+ return mText.toString();
+ }
+
+ /**
+ * Gets the text which should be synthesized.
+ */
+ public CharSequence getCharSequenceText() {
return mText;
}
diff --git a/core/java/android/speech/tts/TextToSpeech.java b/core/java/android/speech/tts/TextToSpeech.java
index 0d2b69b..e1c1767 100644
--- a/core/java/android/speech/tts/TextToSpeech.java
+++ b/core/java/android/speech/tts/TextToSpeech.java
@@ -593,7 +593,7 @@ public class TextToSpeech {
// too.
private final boolean mUseFallback;
private final Map<String, Uri> mEarcons;
- private final Map<String, Uri> mUtterances;
+ private final Map<CharSequence, Uri> mUtterances;
private final Bundle mParams = new Bundle();
private final TtsEngines mEnginesHelper;
private final String mPackageName;
@@ -644,7 +644,7 @@ public class TextToSpeech {
mUseFallback = useFallback;
mEarcons = new HashMap<String, Uri>();
- mUtterances = new HashMap<String, Uri>();
+ mUtterances = new HashMap<CharSequence, Uri>();
mUtteranceProgressListener = null;
mEnginesHelper = new TtsEngines(mContext);
@@ -825,6 +825,40 @@ public class TextToSpeech {
}
/**
+ * Adds a mapping between a CharSequence (may be spanned with TtsSpans) of text
+ * and a sound resource in a package. After a call to this method, subsequent calls to
+ * {@link #speak(String, int, HashMap)} will play the specified sound resource
+ * if it is available, or synthesize the text it is missing.
+ *
+ * @param text
+ * The string of text. Example: <code>"south_south_east"</code>
+ *
+ * @param packagename
+ * Pass the packagename of the application that contains the
+ * resource. If the resource is in your own application (this is
+ * the most common case), then put the packagename of your
+ * application here.<br/>
+ * Example: <b>"com.google.marvin.compass"</b><br/>
+ * The packagename can be found in the AndroidManifest.xml of
+ * your application.
+ * <p>
+ * <code>&lt;manifest xmlns:android=&quot;...&quot;
+ * package=&quot;<b>com.google.marvin.compass</b>&quot;&gt;</code>
+ * </p>
+ *
+ * @param resourceId
+ * Example: <code>R.raw.south_south_east</code>
+ *
+ * @return Code indicating success or failure. See {@link #ERROR} and {@link #SUCCESS}.
+ */
+ public int addSpeech(CharSequence text, String packagename, int resourceId) {
+ synchronized (mStartLock) {
+ mUtterances.put(text, makeResourceUri(packagename, resourceId));
+ return SUCCESS;
+ }
+ }
+
+ /**
* Adds a mapping between a string of text and a sound file. Using this, it
* is possible to add custom pronounciations for a string of text.
* After a call to this method, subsequent calls to {@link #speak(String, int, HashMap)}
@@ -846,6 +880,28 @@ public class TextToSpeech {
}
}
+ /**
+ * Adds a mapping between a CharSequence (may be spanned with TtsSpans and a sound file.
+ * Using this, it is possible to add custom pronounciations for a string of text.
+ * After a call to this method, subsequent calls to {@link #speak(String, int, HashMap)}
+ * will play the specified sound resource if it is available, or synthesize the text it is
+ * missing.
+ *
+ * @param text
+ * The string of text. Example: <code>"south_south_east"</code>
+ * @param filename
+ * The full path to the sound file (for example:
+ * "/sdcard/mysounds/hello.wav")
+ *
+ * @return Code indicating success or failure. See {@link #ERROR} and {@link #SUCCESS}.
+ */
+ public int addSpeech(CharSequence text, String filename) {
+ synchronized (mStartLock) {
+ mUtterances.put(text, Uri.parse(filename));
+ return SUCCESS;
+ }
+ }
+
/**
* Adds a mapping between a string of text and a sound resource in a
@@ -910,7 +966,8 @@ public class TextToSpeech {
}
/**
- * Speaks the string using the specified queuing strategy and speech parameters.
+ * Speaks the text using the specified queuing strategy and speech parameters, the text may
+ * be spanned with TtsSpans.
* This method is asynchronous, i.e. the method just adds the request to the queue of TTS
* requests and then returns. The synthesis might not have finished (or even started!) at the
* time when this method returns. In order to reliably detect errors during synthesis,
@@ -924,32 +981,69 @@ public class TextToSpeech {
* @param params Parameters for the request. Can be null.
* Supported parameter names:
* {@link Engine#KEY_PARAM_STREAM},
- * {@link Engine#KEY_PARAM_UTTERANCE_ID},
* {@link Engine#KEY_PARAM_VOLUME},
* {@link Engine#KEY_PARAM_PAN}.
* Engine specific parameters may be passed in but the parameter keys
* must be prefixed by the name of the engine they are intended for. For example
* the keys "com.svox.pico_foo" and "com.svox.pico:bar" will be passed to the
* engine named "com.svox.pico" if it is being used.
+ * @param utteranceId An unique identifier for this request.
*
* @return {@link #ERROR} or {@link #SUCCESS} of <b>queuing</b> the speak operation.
*/
- public int speak(final String text, final int queueMode, final HashMap<String, String> params) {
+ public int speak(final CharSequence text,
+ final int queueMode,
+ final HashMap<String, String> params,
+ final String utteranceId) {
return runAction(new Action<Integer>() {
@Override
public Integer run(ITextToSpeechService service) throws RemoteException {
Uri utteranceUri = mUtterances.get(text);
if (utteranceUri != null) {
return service.playAudio(getCallerIdentity(), utteranceUri, queueMode,
- getParams(params));
+ getParams(params), utteranceId);
} else {
- return service.speak(getCallerIdentity(), text, queueMode, getParams(params));
+ return service.speak(getCallerIdentity(), text, queueMode, getParams(params),
+ utteranceId);
}
}
}, ERROR, "speak");
}
/**
+ * Speaks the string using the specified queuing strategy and speech parameters.
+ * This method is asynchronous, i.e. the method just adds the request to the queue of TTS
+ * requests and then returns. The synthesis might not have finished (or even started!) at the
+ * time when this method returns. In order to reliably detect errors during synthesis,
+ * we recommend setting an utterance progress listener (see
+ * {@link #setOnUtteranceProgressListener}) and using the
+ * {@link Engine#KEY_PARAM_UTTERANCE_ID} parameter.
+ *
+ * @param text The string of text to be spoken. No longer than
+ * {@link #getMaxSpeechInputLength()} characters.
+ * @param queueMode The queuing strategy to use, {@link #QUEUE_ADD} or {@link #QUEUE_FLUSH}.
+ * @param params Parameters for the request. Can be null.
+ * Supported parameter names:
+ * {@link Engine#KEY_PARAM_STREAM},
+ * {@link Engine#KEY_PARAM_UTTERANCE_ID},
+ * {@link Engine#KEY_PARAM_VOLUME},
+ * {@link Engine#KEY_PARAM_PAN}.
+ * Engine specific parameters may be passed in but the parameter keys
+ * must be prefixed by the name of the engine they are intended for. For example
+ * the keys "com.svox.pico_foo" and "com.svox.pico:bar" will be passed to the
+ * engine named "com.svox.pico" if it is being used.
+ *
+ * @return {@link #ERROR} or {@link #SUCCESS} of <b>queuing</b> the speak operation.
+ * @deprecated As of API level 20, replaced by
+ * {@link #speak(CharSequence, int, HashMap, String)}.
+ */
+ @Deprecated
+ public int speak(final String text, final int queueMode, final HashMap<String, String> params) {
+ return speak(text, queueMode, params,
+ params == null ? null : params.get(Engine.KEY_PARAM_UTTERANCE_ID));
+ }
+
+ /**
* Plays the earcon using the specified queueing mode and parameters.
* The earcon must already have been added with {@link #addEarcon(String, String)} or
* {@link #addEarcon(String, String, int)}.
@@ -965,7 +1059,6 @@ public class TextToSpeech {
* @param params Parameters for the request. Can be null.
* Supported parameter names:
* {@link Engine#KEY_PARAM_STREAM},
- * {@link Engine#KEY_PARAM_UTTERANCE_ID}.
* Engine specific parameters may be passed in but the parameter keys
* must be prefixed by the name of the engine they are intended for. For example
* the keys "com.svox.pico_foo" and "com.svox.pico:bar" will be passed to the
@@ -974,7 +1067,7 @@ public class TextToSpeech {
* @return {@link #ERROR} or {@link #SUCCESS} of <b>queuing</b> the playEarcon operation.
*/
public int playEarcon(final String earcon, final int queueMode,
- final HashMap<String, String> params) {
+ final HashMap<String, String> params, final String utteranceId) {
return runAction(new Action<Integer>() {
@Override
public Integer run(ITextToSpeechService service) throws RemoteException {
@@ -983,12 +1076,45 @@ public class TextToSpeech {
return ERROR;
}
return service.playAudio(getCallerIdentity(), earconUri, queueMode,
- getParams(params));
+ getParams(params), utteranceId);
}
}, ERROR, "playEarcon");
}
/**
+ * Plays the earcon using the specified queueing mode and parameters.
+ * The earcon must already have been added with {@link #addEarcon(String, String)} or
+ * {@link #addEarcon(String, String, int)}.
+ * This method is asynchronous, i.e. the method just adds the request to the queue of TTS
+ * requests and then returns. The synthesis might not have finished (or even started!) at the
+ * time when this method returns. In order to reliably detect errors during synthesis,
+ * we recommend setting an utterance progress listener (see
+ * {@link #setOnUtteranceProgressListener}) and using the
+ * {@link Engine#KEY_PARAM_UTTERANCE_ID} parameter.
+ *
+ * @param earcon The earcon that should be played
+ * @param queueMode {@link #QUEUE_ADD} or {@link #QUEUE_FLUSH}.
+ * @param params Parameters for the request. Can be null.
+ * Supported parameter names:
+ * {@link Engine#KEY_PARAM_STREAM},
+ * {@link Engine#KEY_PARAM_UTTERANCE_ID}.
+ * Engine specific parameters may be passed in but the parameter keys
+ * must be prefixed by the name of the engine they are intended for. For example
+ * the keys "com.svox.pico_foo" and "com.svox.pico:bar" will be passed to the
+ * engine named "com.svox.pico" if it is being used.
+ *
+ * @return {@link #ERROR} or {@link #SUCCESS} of <b>queuing</b> the playEarcon operation.
+ * @deprecated As of API level 20, replaced by
+ * {@link #playEarcon(String, int, HashMap, String)}.
+ */
+ @Deprecated
+ public int playEarcon(final String earcon, final int queueMode,
+ final HashMap<String, String> params) {
+ return playEarcon(earcon, queueMode, params,
+ params == null ? null : params.get(Engine.KEY_PARAM_UTTERANCE_ID));
+ }
+
+ /**
* Plays silence for the specified amount of time using the specified
* queue mode.
* This method is asynchronous, i.e. the method just adds the request to the queue of TTS
@@ -1001,27 +1127,57 @@ public class TextToSpeech {
* @param durationInMs The duration of the silence.
* @param queueMode {@link #QUEUE_ADD} or {@link #QUEUE_FLUSH}.
* @param params Parameters for the request. Can be null.
- * Supported parameter names:
- * {@link Engine#KEY_PARAM_UTTERANCE_ID}.
* Engine specific parameters may be passed in but the parameter keys
* must be prefixed by the name of the engine they are intended for. For example
* the keys "com.svox.pico_foo" and "com.svox.pico:bar" will be passed to the
* engine named "com.svox.pico" if it is being used.
+ * @param utteranceId An unique identifier for this request.
*
* @return {@link #ERROR} or {@link #SUCCESS} of <b>queuing</b> the playSilence operation.
*/
public int playSilence(final long durationInMs, final int queueMode,
- final HashMap<String, String> params) {
+ final HashMap<String, String> params, final String utteranceId) {
return runAction(new Action<Integer>() {
@Override
public Integer run(ITextToSpeechService service) throws RemoteException {
- return service.playSilence(getCallerIdentity(), durationInMs, queueMode,
- params == null ? null : params.get(Engine.KEY_PARAM_UTTERANCE_ID));
+ return service.playSilence(getCallerIdentity(), durationInMs,
+ queueMode, utteranceId);
}
}, ERROR, "playSilence");
}
/**
+ * Plays silence for the specified amount of time using the specified
+ * queue mode.
+ * This method is asynchronous, i.e. the method just adds the request to the queue of TTS
+ * requests and then returns. The synthesis might not have finished (or even started!) at the
+ * time when this method returns. In order to reliably detect errors during synthesis,
+ * we recommend setting an utterance progress listener (see
+ * {@link #setOnUtteranceProgressListener}) and using the
+ * {@link Engine#KEY_PARAM_UTTERANCE_ID} parameter.
+ *
+ * @param durationInMs The duration of the silence.
+ * @param queueMode {@link #QUEUE_ADD} or {@link #QUEUE_FLUSH}.
+ * @param params Parameters for the request. Can be null.
+ * Supported parameter names:
+ * {@link Engine#KEY_PARAM_UTTERANCE_ID}.
+ * Engine specific parameters may be passed in but the parameter keys
+ * must be prefixed by the name of the engine they are intended for. For example
+ * the keys "com.svox.pico_foo" and "com.svox.pico:bar" will be passed to the
+ * engine named "com.svox.pico" if it is being used.
+ *
+ * @return {@link #ERROR} or {@link #SUCCESS} of <b>queuing</b> the playSilence operation.
+ * @deprecated As of API level 20, replaced by
+ * {@link #playSilence(long, int, HashMap, String)}.
+ */
+ @Deprecated
+ public int playSilence(final long durationInMs, final int queueMode,
+ final HashMap<String, String> params) {
+ return playSilence(durationInMs, queueMode, params,
+ params == null ? null : params.get(Engine.KEY_PARAM_UTTERANCE_ID));
+ }
+
+ /**
* Queries the engine for the set of features it supports for a given locale.
* Features can either be framework defined, e.g.
* {@link TextToSpeech.Engine#KEY_FEATURE_NETWORK_SYNTHESIS} or engine specific.
@@ -1294,25 +1450,22 @@ public class TextToSpeech {
* requests and then returns. The synthesis might not have finished (or even started!) at the
* time when this method returns. In order to reliably detect errors during synthesis,
* we recommend setting an utterance progress listener (see
- * {@link #setOnUtteranceProgressListener}) and using the
- * {@link Engine#KEY_PARAM_UTTERANCE_ID} parameter.
+ * {@link #setOnUtteranceProgressListener}).
*
* @param text The text that should be synthesized. No longer than
* {@link #getMaxSpeechInputLength()} characters.
* @param params Parameters for the request. Can be null.
- * Supported parameter names:
- * {@link Engine#KEY_PARAM_UTTERANCE_ID}.
* Engine specific parameters may be passed in but the parameter keys
* must be prefixed by the name of the engine they are intended for. For example
* the keys "com.svox.pico_foo" and "com.svox.pico:bar" will be passed to the
* engine named "com.svox.pico" if it is being used.
* @param filename Absolute file filename to write the generated audio data to.It should be
* something like "/sdcard/myappsounds/mysound.wav".
- *
+ * @param utteranceId An unique identifier for this request.
* @return {@link #ERROR} or {@link #SUCCESS} of <b>queuing</b> the synthesizeToFile operation.
*/
- public int synthesizeToFile(final String text, final HashMap<String, String> params,
- final String filename) {
+ public int synthesizeToFile(final CharSequence text, final HashMap<String, String> params,
+ final String filename, final String utteranceId) {
return runAction(new Action<Integer>() {
@Override
public Integer run(ITextToSpeechService service) throws RemoteException {
@@ -1329,7 +1482,7 @@ public class TextToSpeech {
ParcelFileDescriptor.MODE_CREATE |
ParcelFileDescriptor.MODE_TRUNCATE);
returnValue = service.synthesizeToFileDescriptor(getCallerIdentity(), text,
- fileDescriptor, getParams(params));
+ fileDescriptor, getParams(params), utteranceId);
fileDescriptor.close();
return returnValue;
} catch (FileNotFoundException e) {
@@ -1343,6 +1496,36 @@ public class TextToSpeech {
}, ERROR, "synthesizeToFile");
}
+ /**
+ * Synthesizes the given text to a file using the specified parameters.
+ * This method is asynchronous, i.e. the method just adds the request to the queue of TTS
+ * requests and then returns. The synthesis might not have finished (or even started!) at the
+ * time when this method returns. In order to reliably detect errors during synthesis,
+ * we recommend setting an utterance progress listener (see
+ * {@link #setOnUtteranceProgressListener}) and using the
+ * {@link Engine#KEY_PARAM_UTTERANCE_ID} parameter.
+ *
+ * @param text The text that should be synthesized. No longer than
+ * {@link #getMaxSpeechInputLength()} characters.
+ * @param params Parameters for the request. Can be null.
+ * Supported parameter names:
+ * {@link Engine#KEY_PARAM_UTTERANCE_ID}.
+ * Engine specific parameters may be passed in but the parameter keys
+ * must be prefixed by the name of the engine they are intended for. For example
+ * the keys "com.svox.pico_foo" and "com.svox.pico:bar" will be passed to the
+ * engine named "com.svox.pico" if it is being used.
+ * @param filename Absolute file filename to write the generated audio data to.It should be
+ * something like "/sdcard/myappsounds/mysound.wav".
+ *
+ * @return {@link #ERROR} or {@link #SUCCESS} of <b>queuing</b> the synthesizeToFile operation.
+ * @deprecated As of API level 20, replaced by
+ * {@link #synthesizeToFile(CharSequence, HashMap, String, String)}.
+ */
+ public int synthesizeToFile(final String text, final HashMap<String, String> params,
+ final String filename) {
+ return synthesizeToFile(text, params, filename, params.get(Engine.KEY_PARAM_UTTERANCE_ID));
+ }
+
private Bundle getParams(HashMap<String, String> params) {
if (params != null && !params.isEmpty()) {
Bundle bundle = new Bundle(mParams);
diff --git a/core/java/android/speech/tts/TextToSpeechService.java b/core/java/android/speech/tts/TextToSpeechService.java
index 5a3c5f7..017be93 100644
--- a/core/java/android/speech/tts/TextToSpeechService.java
+++ b/core/java/android/speech/tts/TextToSpeechService.java
@@ -637,11 +637,13 @@ public abstract class TextToSpeechService extends Service {
*/
private abstract class SpeechItemV1 extends UtteranceSpeechItem {
protected final Bundle mParams;
+ protected final String mUtteranceId;
SpeechItemV1(Object callerIdentity, int callerUid, int callerPid,
- Bundle params) {
+ Bundle params, String utteranceId) {
super(callerIdentity, callerUid, callerPid);
mParams = params;
+ mUtteranceId = utteranceId;
}
boolean hasLanguage() {
@@ -658,7 +660,7 @@ public abstract class TextToSpeechService extends Service {
@Override
public String getUtteranceId() {
- return getStringParam(mParams, Engine.KEY_PARAM_UTTERANCE_ID, null);
+ return mUtteranceId;
}
AudioOutputParams getAudioParams() {
@@ -668,7 +670,7 @@ public abstract class TextToSpeechService extends Service {
class SynthesisSpeechItemV1 extends SpeechItemV1 {
// Never null.
- private final String mText;
+ private final CharSequence mText;
private final SynthesisRequest mSynthesisRequest;
private final String[] mDefaultLocale;
// Non null after synthesis has started, and all accesses
@@ -678,8 +680,8 @@ public abstract class TextToSpeechService extends Service {
private final int mCallerUid;
public SynthesisSpeechItemV1(Object callerIdentity, int callerUid, int callerPid,
- Bundle params, String text) {
- super(callerIdentity, callerUid, callerPid, params);
+ Bundle params, String utteranceId, CharSequence text) {
+ super(callerIdentity, callerUid, callerPid, params, utteranceId);
mText = text;
mCallerUid = callerUid;
mSynthesisRequest = new SynthesisRequest(mText, mParams);
@@ -689,7 +691,7 @@ public abstract class TextToSpeechService extends Service {
mPackageName);
}
- public String getText() {
+ public CharSequence getText() {
return mText;
}
@@ -774,8 +776,9 @@ public abstract class TextToSpeechService extends Service {
private final FileOutputStream mFileOutputStream;
public SynthesisToFileOutputStreamSpeechItemV1(Object callerIdentity, int callerUid,
- int callerPid, Bundle params, String text, FileOutputStream fileOutputStream) {
- super(callerIdentity, callerUid, callerPid, params, text);
+ int callerPid, Bundle params, String utteranceId, CharSequence text,
+ FileOutputStream fileOutputStream) {
+ super(callerIdentity, callerUid, callerPid, params, utteranceId, text);
mFileOutputStream = fileOutputStream;
}
@@ -801,8 +804,8 @@ public abstract class TextToSpeechService extends Service {
private final AudioPlaybackQueueItem mItem;
public AudioSpeechItemV1(Object callerIdentity, int callerUid, int callerPid,
- Bundle params, Uri uri) {
- super(callerIdentity, callerUid, callerPid, params);
+ Bundle params, String utteranceId, Uri uri) {
+ super(callerIdentity, callerUid, callerPid, params, utteranceId);
mItem = new AudioPlaybackQueueItem(this, getCallerIdentity(),
TextToSpeechService.this, uri, getAudioParams());
}
@@ -909,19 +912,20 @@ public abstract class TextToSpeechService extends Service {
// they can be used as message objects (which are tested for equality using ==).
private final ITextToSpeechService.Stub mBinder = new ITextToSpeechService.Stub() {
@Override
- public int speak(IBinder caller, String text, int queueMode, Bundle params) {
+ public int speak(IBinder caller, CharSequence text, int queueMode, Bundle params,
+ String utteranceId) {
if (!checkNonNull(caller, text, params)) {
return TextToSpeech.ERROR;
}
SpeechItem item = new SynthesisSpeechItemV1(caller,
- Binder.getCallingUid(), Binder.getCallingPid(), params, text);
+ Binder.getCallingUid(), Binder.getCallingPid(), params, utteranceId, text);
return mSynthHandler.enqueueSpeechItem(queueMode, item);
}
@Override
- public int synthesizeToFileDescriptor(IBinder caller, String text, ParcelFileDescriptor
- fileDescriptor, Bundle params) {
+ public int synthesizeToFileDescriptor(IBinder caller, CharSequence text, ParcelFileDescriptor
+ fileDescriptor, Bundle params, String utteranceId) {
if (!checkNonNull(caller, text, fileDescriptor, params)) {
return TextToSpeech.ERROR;
}
@@ -933,19 +937,20 @@ public abstract class TextToSpeechService extends Service {
fileDescriptor.detachFd());
SpeechItem item = new SynthesisToFileOutputStreamSpeechItemV1(caller,
- Binder.getCallingUid(), Binder.getCallingPid(), params, text,
+ Binder.getCallingUid(), Binder.getCallingPid(), params, utteranceId, text,
new ParcelFileDescriptor.AutoCloseOutputStream(sameFileDescriptor));
return mSynthHandler.enqueueSpeechItem(TextToSpeech.QUEUE_ADD, item);
}
@Override
- public int playAudio(IBinder caller, Uri audioUri, int queueMode, Bundle params) {
+ public int playAudio(IBinder caller, Uri audioUri, int queueMode, Bundle params,
+ String utteranceId) {
if (!checkNonNull(caller, audioUri, params)) {
return TextToSpeech.ERROR;
}
SpeechItem item = new AudioSpeechItemV1(caller,
- Binder.getCallingUid(), Binder.getCallingPid(), params, audioUri);
+ Binder.getCallingUid(), Binder.getCallingPid(), params, utteranceId, audioUri);
return mSynthHandler.enqueueSpeechItem(queueMode, item);
}
diff --git a/core/java/android/view/Choreographer.java b/core/java/android/view/Choreographer.java
index 1066430..f41afcf 100644
--- a/core/java/android/view/Choreographer.java
+++ b/core/java/android/view/Choreographer.java
@@ -431,7 +431,7 @@ public final class Choreographer {
/**
* Gets the time when the current frame started.
* <p>
- * This method provides the time in nanoseconds when the frame started being rendered.
+ * This method provides the time in milliseconds when the frame started being rendered.
* The frame time provides a stable time base for synchronizing animations
* and drawing. It should be used instead of {@link SystemClock#uptimeMillis()}
* or {@link System#nanoTime()} for animations and drawing in the UI. Using the frame
diff --git a/core/java/android/view/IWindow.aidl b/core/java/android/view/IWindow.aidl
index 3670eed..3e7aae0 100644
--- a/core/java/android/view/IWindow.aidl
+++ b/core/java/android/view/IWindow.aidl
@@ -46,7 +46,8 @@ oneway interface IWindow {
void executeCommand(String command, String parameters, in ParcelFileDescriptor descriptor);
void resized(in Rect frame, in Rect overscanInsets, in Rect contentInsets,
- in Rect visibleInsets, boolean reportDraw, in Configuration newConfig);
+ in Rect visibleInsets, in Rect stableInsets, boolean reportDraw,
+ in Configuration newConfig);
void moved(int newX, int newY);
void dispatchAppVisibility(boolean visible);
void dispatchGetNewSurface();
diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl
index fa5bd88..0f3f182 100644
--- a/core/java/android/view/IWindowSession.aidl
+++ b/core/java/android/view/IWindowSession.aidl
@@ -89,7 +89,7 @@ interface IWindowSession {
int relayout(IWindow window, int seq, in WindowManager.LayoutParams attrs,
int requestedWidth, int requestedHeight, int viewVisibility,
int flags, out Rect outFrame, out Rect outOverscanInsets,
- out Rect outContentInsets, out Rect outVisibleInsets,
+ out Rect outContentInsets, out Rect outVisibleInsets, out Rect outStableInsets,
out Configuration outConfig, out Surface outSurface);
/**
diff --git a/core/java/android/view/RenderNodeAnimator.java b/core/java/android/view/RenderNodeAnimator.java
index 1363a5c..4b53c8e 100644
--- a/core/java/android/view/RenderNodeAnimator.java
+++ b/core/java/android/view/RenderNodeAnimator.java
@@ -18,6 +18,7 @@ package android.view;
import android.animation.Animator;
import android.animation.TimeInterpolator;
+import android.animation.ValueAnimator;
import android.graphics.Canvas;
import android.graphics.CanvasProperty;
import android.graphics.Paint;
@@ -34,7 +35,7 @@ import java.util.ArrayList;
/**
* @hide
*/
-public final class RenderNodeAnimator extends Animator {
+public class RenderNodeAnimator extends Animator {
// Keep in sync with enum RenderProperty in Animator.h
public static final int TRANSLATION_X = 0;
public static final int TRANSLATION_Y = 1;
@@ -83,16 +84,23 @@ public final class RenderNodeAnimator extends Animator {
private RenderNode mTarget;
private View mViewTarget;
+ private int mRenderProperty = -1;
+ private float mFinalValue;
private TimeInterpolator mInterpolator;
private boolean mStarted = false;
private boolean mFinished = false;
+ private long mUnscaledDuration = 300;
+ private long mUnscaledStartDelay = 0;
+
public static int mapViewPropertyToRenderProperty(int viewProperty) {
return sViewPropertyAnimatorMap.get(viewProperty);
}
public RenderNodeAnimator(int property, float finalValue) {
+ mRenderProperty = property;
+ mFinalValue = finalValue;
init(nCreateAnimator(new WeakReference<RenderNodeAnimator>(this),
property, finalValue));
}
@@ -156,7 +164,16 @@ public final class RenderNodeAnimator extends Animator {
mStarted = true;
applyInterpolator();
- mTarget.addAnimator(this);
+ nStart(mNativePtr.get());
+
+ // Alpha is a special snowflake that has the canonical value stored
+ // in mTransformationInfo instead of in RenderNode, so we need to update
+ // it with the final value here.
+ if (mRenderProperty == RenderNodeAnimator.ALPHA) {
+ // Don't need null check because ViewPropertyAnimator's
+ // ctor calls ensureTransformationInfo()
+ mViewTarget.mTransformationInfo.mAlpha = mFinalValue;
+ }
final ArrayList<AnimatorListener> listeners = getListeners();
final int numListeners = listeners == null ? 0 : listeners.size();
@@ -201,6 +218,7 @@ public final class RenderNodeAnimator extends Animator {
public void setTarget(View view) {
mViewTarget = view;
mTarget = view.mRenderNode;
+ mTarget.addAnimator(this);
}
public void setTarget(Canvas canvas) {
@@ -213,12 +231,12 @@ public final class RenderNodeAnimator extends Animator {
}
public void setTarget(RenderNode node) {
+ if (mTarget != null) {
+ throw new IllegalStateException("Target already set!");
+ }
mViewTarget = null;
mTarget = node;
- }
-
- public RenderNode getTarget() {
- return mTarget;
+ mTarget.addAnimator(this);
}
public void setStartValue(float startValue) {
@@ -232,12 +250,13 @@ public final class RenderNodeAnimator extends Animator {
if (startDelay < 0) {
throw new IllegalArgumentException("startDelay must be positive; " + startDelay);
}
- nSetStartDelay(mNativePtr.get(), startDelay);
+ mUnscaledStartDelay = startDelay;
+ nSetStartDelay(mNativePtr.get(), (long) (startDelay * ValueAnimator.getDurationScale()));
}
@Override
public long getStartDelay() {
- return nGetStartDelay(mNativePtr.get());
+ return mUnscaledStartDelay;
}
@Override
@@ -246,13 +265,14 @@ public final class RenderNodeAnimator extends Animator {
if (duration < 0) {
throw new IllegalArgumentException("duration must be positive; " + duration);
}
- nSetDuration(mNativePtr.get(), duration);
+ mUnscaledDuration = duration;
+ nSetDuration(mNativePtr.get(), (long) (duration * ValueAnimator.getDurationScale()));
return this;
}
@Override
public long getDuration() {
- return nGetDuration(mNativePtr.get());
+ return mUnscaledDuration;
}
@Override
@@ -307,5 +327,6 @@ public final class RenderNodeAnimator extends Animator {
private static native long nGetStartDelay(long nativePtr);
private static native void nSetInterpolator(long animPtr, long interpolatorPtr);
+ private static native void nStart(long animPtr);
private static native void nCancel(long animPtr);
}
diff --git a/core/java/android/view/RenderNodeAnimatorCompat.java b/core/java/android/view/RenderNodeAnimatorCompat.java
new file mode 100644
index 0000000..151277a
--- /dev/null
+++ b/core/java/android/view/RenderNodeAnimatorCompat.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+import android.animation.ValueAnimator;
+
+import java.util.ArrayList;
+
+/**
+ * This class provides compatibility for things like start listeners &
+ * start delays for use by ViewPropertyAnimator and ObjectAnimator
+ * @hide
+ */
+public class RenderNodeAnimatorCompat extends RenderNodeAnimator {
+
+ private long mUnscaledStartDelay = 0;
+ private long mStartDelay = 0;
+ private long mStartTime;
+ private boolean mCanceled;
+
+ public RenderNodeAnimatorCompat(int property, float finalValue) {
+ super(property, finalValue);
+ }
+
+ @Override
+ public void setStartDelay(long startDelay) {
+ mUnscaledStartDelay = startDelay;
+ mStartDelay = (long) (ValueAnimator.getDurationScale() * startDelay);
+ }
+
+ @Override
+ public long getStartDelay() {
+ return mUnscaledStartDelay;
+ }
+
+ @Override
+ public void start() {
+ if (mStartDelay <= 0) {
+ doStart();
+ } else {
+ getHelper().addDelayedAnimation(this);
+ }
+ }
+
+ private void doStart() {
+ if (!mCanceled) {
+ super.start();
+ }
+ }
+
+ @Override
+ public void cancel() {
+ mCanceled = true;
+ super.cancel();
+ }
+
+ /**
+ * @return true if the animator was started, false if still delayed
+ */
+ private boolean processDelayed(long frameTimeMs) {
+ if (mCanceled) return true;
+
+ if (mStartTime == 0) {
+ mStartTime = frameTimeMs;
+ } else if ((frameTimeMs - mStartTime) >= mStartDelay) {
+ doStart();
+ return true;
+ }
+ return false;
+ }
+
+ private static AnimationHelper getHelper() {
+ AnimationHelper helper = sAnimationHelper.get();
+ if (helper == null) {
+ helper = new AnimationHelper();
+ sAnimationHelper.set(helper);
+ }
+ return helper;
+ }
+
+ private static ThreadLocal<AnimationHelper> sAnimationHelper =
+ new ThreadLocal<AnimationHelper>();
+
+ private static class AnimationHelper implements Runnable {
+
+ private ArrayList<RenderNodeAnimatorCompat> mDelayedAnims = new ArrayList<RenderNodeAnimatorCompat>();
+ private final Choreographer mChoreographer;
+ private boolean mCallbackScheduled;
+
+ public AnimationHelper() {
+ mChoreographer = Choreographer.getInstance();
+ }
+
+ public void addDelayedAnimation(RenderNodeAnimatorCompat animator) {
+ mDelayedAnims.add(animator);
+ scheduleCallback();
+ }
+
+ private void scheduleCallback() {
+ if (!mCallbackScheduled) {
+ mCallbackScheduled = true;
+ mChoreographer.postCallback(Choreographer.CALLBACK_ANIMATION, this, null);
+ }
+ }
+
+ @Override
+ public void run() {
+ long frameTimeMs = mChoreographer.getFrameTime();
+ mCallbackScheduled = false;
+
+ int end = 0;
+ for (int i = 0; i < mDelayedAnims.size(); i++) {
+ RenderNodeAnimatorCompat animator = mDelayedAnims.get(i);
+ if (!animator.processDelayed(frameTimeMs)) {
+ if (end != i) {
+ mDelayedAnims.set(end, animator);
+ }
+ end++;
+ }
+ }
+ while (mDelayedAnims.size() > end) {
+ mDelayedAnims.remove(mDelayedAnims.size() - 1);
+ }
+
+ if (mDelayedAnims.size() > 0) {
+ scheduleCallback();
+ }
+ }
+ }
+}
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 4a2cc1a..a2a4540 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -105,6 +105,7 @@ public class SurfaceView extends View {
final Rect mWinFrame = new Rect();
final Rect mOverscanInsets = new Rect();
final Rect mContentInsets = new Rect();
+ final Rect mStableInsets = new Rect();
final Configuration mConfiguration = new Configuration();
static final int KEEP_SCREEN_ON_MSG = 1;
@@ -518,7 +519,7 @@ public class SurfaceView extends View {
visible ? VISIBLE : GONE,
WindowManagerGlobal.RELAYOUT_DEFER_SURFACE_DESTROY,
mWinFrame, mOverscanInsets, mContentInsets,
- mVisibleInsets, mConfiguration, mNewSurface);
+ mVisibleInsets, mStableInsets, mConfiguration, mNewSurface);
if ((relayoutResult & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) {
mReportDrawNeeded = true;
}
@@ -653,7 +654,8 @@ public class SurfaceView extends View {
@Override
public void resized(Rect frame, Rect overscanInsets, Rect contentInsets,
- Rect visibleInsets, boolean reportDraw, Configuration newConfig) {
+ Rect visibleInsets, Rect stableInsets, boolean reportDraw,
+ Configuration newConfig) {
SurfaceView surfaceView = mSurfaceView.get();
if (surfaceView != null) {
if (DEBUG) Log.v(
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 33b6d6c..3b2e1d1 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -19805,6 +19805,13 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
final Rect mVisibleInsets = new Rect();
/**
+ * For windows that are full-screen but using insets to layout inside
+ * of the screen decorations, these are the current insets for the
+ * stable system windows.
+ */
+ final Rect mStableInsets = new Rect();
+
+ /**
* The internal insets given by this window. This value is
* supplied by the client (through
* {@link ViewTreeObserver.OnComputeInternalInsetsListener}) and will
diff --git a/core/java/android/view/ViewPropertyAnimatorRT.java b/core/java/android/view/ViewPropertyAnimatorRT.java
index 31b360c..20f5182 100644
--- a/core/java/android/view/ViewPropertyAnimatorRT.java
+++ b/core/java/android/view/ViewPropertyAnimatorRT.java
@@ -81,21 +81,14 @@ class ViewPropertyAnimatorRT {
int property = RenderNodeAnimator.mapViewPropertyToRenderProperty(holder.mNameConstant);
final float finalValue = holder.mFromValue + holder.mDeltaValue;
- RenderNodeAnimator animator = new RenderNodeAnimator(property, finalValue);
+ RenderNodeAnimator animator = new RenderNodeAnimatorCompat(property, finalValue);
animator.setStartDelay(startDelay);
animator.setDuration(duration);
animator.setInterpolator(interpolator);
animator.setTarget(mView);
animator.start();
- // Alpha is a special snowflake that has the canonical value stored
- // in mTransformationInfo instead of in RenderNode, so we need to update
- // it with the final value here.
- if (property == RenderNodeAnimator.ALPHA) {
- // Don't need null check because ViewPropertyAnimator's
- // ctor calls ensureTransformationInfo()
- parent.mView.mTransformationInfo.mAlpha = finalValue;
- }
+ mAnimators[property] = animator;
}
parent.mPendingAnimations.clear();
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 3219330..5def940 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -21,7 +21,6 @@ import android.animation.LayoutTransition;
import android.app.ActivityManagerNative;
import android.content.ClipDescription;
import android.content.ComponentCallbacks;
-import android.content.ComponentCallbacks2;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.res.CompatibilityInfo;
@@ -205,7 +204,7 @@ public final class ViewRootImpl implements ViewParent,
/** Set to true while in performTraversals for detecting when die(true) is called from internal
* callbacks such as onMeasure, onPreDraw, onDraw and deferring doDie() until later. */
boolean mIsInTraversal;
- boolean mFitSystemWindowsRequested;
+ boolean mApplyInsetsRequested;
boolean mLayoutRequested;
boolean mFirst;
boolean mReportNextDraw;
@@ -257,11 +256,13 @@ public final class ViewRootImpl implements ViewParent,
final Rect mPendingOverscanInsets = new Rect();
final Rect mPendingVisibleInsets = new Rect();
+ final Rect mPendingStableInsets = new Rect();
final Rect mPendingContentInsets = new Rect();
final ViewTreeObserver.InternalInsetsInfo mLastGivenInsets
= new ViewTreeObserver.InternalInsetsInfo();
- final Rect mFitSystemWindowsInsets = new Rect();
+ final Rect mDispatchContentInsets = new Rect();
+ final Rect mDispatchStableInsets = new Rect();
final Configuration mLastConfiguration = new Configuration();
final Configuration mPendingConfiguration = new Configuration();
@@ -532,6 +533,7 @@ public final class ViewRootImpl implements ViewParent,
}
mPendingOverscanInsets.set(0, 0, 0, 0);
mPendingContentInsets.set(mAttachInfo.mContentInsets);
+ mPendingStableInsets.set(mAttachInfo.mStableInsets);
mPendingVisibleInsets.set(0, 0, 0, 0);
if (DEBUG_LAYOUT) Log.v(TAG, "Added window " + mWindow);
if (res < WindowManagerGlobal.ADD_OKAY) {
@@ -816,7 +818,7 @@ public final class ViewRootImpl implements ViewParent,
@Override
public void requestFitSystemWindows() {
checkThread();
- mFitSystemWindowsRequested = true;
+ mApplyInsetsRequested = true;
scheduleTraversals();
}
@@ -1161,7 +1163,8 @@ public final class ViewRootImpl implements ViewParent,
}
void dispatchApplyInsets(View host) {
- mFitSystemWindowsInsets.set(mAttachInfo.mContentInsets);
+ mDispatchContentInsets.set(mAttachInfo.mContentInsets);
+ mDispatchStableInsets.set(mAttachInfo.mStableInsets);
boolean isRound = false;
if ((mWindowAttributes.flags & WindowManager.LayoutParams.FLAG_LAYOUT_IN_OVERSCAN) != 0
&& mDisplay.getDisplayId() == 0) {
@@ -1171,7 +1174,8 @@ public final class ViewRootImpl implements ViewParent,
com.android.internal.R.bool.config_windowIsRound);
}
host.dispatchApplyWindowInsets(new WindowInsets(
- mFitSystemWindowsInsets, isRound));
+ mDispatchContentInsets, null /* windowDecorInsets */,
+ mDispatchStableInsets, isRound));
}
private void performTraversals() {
@@ -1310,6 +1314,9 @@ public final class ViewRootImpl implements ViewParent,
if (!mPendingContentInsets.equals(mAttachInfo.mContentInsets)) {
insetsChanged = true;
}
+ if (!mPendingStableInsets.equals(mAttachInfo.mStableInsets)) {
+ insetsChanged = true;
+ }
if (!mPendingVisibleInsets.equals(mAttachInfo.mVisibleInsets)) {
mAttachInfo.mVisibleInsets.set(mPendingVisibleInsets);
if (DEBUG_LAYOUT) Log.v(TAG, "Visible insets changing to: "
@@ -1383,8 +1390,8 @@ public final class ViewRootImpl implements ViewParent,
& WindowManager.LayoutParams.FLAG_LAYOUT_IN_OVERSCAN) != 0;
}
- if (mFitSystemWindowsRequested) {
- mFitSystemWindowsRequested = false;
+ if (mApplyInsetsRequested) {
+ mApplyInsetsRequested = false;
mLastOverscanRequested = mAttachInfo.mOverscanRequested;
dispatchApplyInsets(host);
if (mLayoutRequested) {
@@ -1469,6 +1476,7 @@ public final class ViewRootImpl implements ViewParent,
+ " overscan=" + mPendingOverscanInsets.toShortString()
+ " content=" + mPendingContentInsets.toShortString()
+ " visible=" + mPendingVisibleInsets.toShortString()
+ + " visible=" + mPendingStableInsets.toShortString()
+ " surface=" + mSurface);
if (mPendingConfiguration.seq != 0) {
@@ -1484,6 +1492,8 @@ public final class ViewRootImpl implements ViewParent,
mAttachInfo.mContentInsets);
final boolean visibleInsetsChanged = !mPendingVisibleInsets.equals(
mAttachInfo.mVisibleInsets);
+ final boolean stableInsetsChanged = !mPendingStableInsets.equals(
+ mAttachInfo.mStableInsets);
if (contentInsetsChanged) {
if (mWidth > 0 && mHeight > 0 && lp != null &&
((lp.systemUiVisibility|lp.subtreeSystemUiVisibility)
@@ -1558,12 +1568,19 @@ public final class ViewRootImpl implements ViewParent,
// Need to relayout with content insets.
contentInsetsChanged = true;
}
+ if (stableInsetsChanged) {
+ mAttachInfo.mStableInsets.set(mPendingStableInsets);
+ if (DEBUG_LAYOUT) Log.v(TAG, "Decor insets changing to: "
+ + mAttachInfo.mStableInsets);
+ // Need to relayout with content insets.
+ contentInsetsChanged = true;
+ }
if (contentInsetsChanged || mLastSystemUiVisibility !=
- mAttachInfo.mSystemUiVisibility || mFitSystemWindowsRequested
+ mAttachInfo.mSystemUiVisibility || mApplyInsetsRequested
|| mLastOverscanRequested != mAttachInfo.mOverscanRequested) {
mLastSystemUiVisibility = mAttachInfo.mSystemUiVisibility;
mLastOverscanRequested = mAttachInfo.mOverscanRequested;
- mFitSystemWindowsRequested = false;
+ mApplyInsetsRequested = false;
dispatchApplyInsets(host);
}
if (visibleInsetsChanged) {
@@ -3065,6 +3082,7 @@ public final class ViewRootImpl implements ViewParent,
if (mWinFrame.equals(args.arg1)
&& mPendingOverscanInsets.equals(args.arg5)
&& mPendingContentInsets.equals(args.arg2)
+ && mPendingStableInsets.equals(args.arg6)
&& mPendingVisibleInsets.equals(args.arg3)
&& args.arg4 == null) {
break;
@@ -3082,6 +3100,7 @@ public final class ViewRootImpl implements ViewParent,
mWinFrame.set((Rect) args.arg1);
mPendingOverscanInsets.set((Rect) args.arg5);
mPendingContentInsets.set((Rect) args.arg2);
+ mPendingStableInsets.set((Rect) args.arg6);
mPendingVisibleInsets.set((Rect) args.arg3);
args.recycle();
@@ -5167,7 +5186,7 @@ public final class ViewRootImpl implements ViewParent,
(int) (mView.getMeasuredHeight() * appScale + 0.5f),
viewVisibility, insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0,
mWinFrame, mPendingOverscanInsets, mPendingContentInsets, mPendingVisibleInsets,
- mPendingConfiguration, mSurface);
+ mPendingStableInsets, mPendingConfiguration, mSurface);
//Log.d(TAG, "<<<<<< BACK FROM relayout");
if (restore) {
params.restore();
@@ -5178,6 +5197,7 @@ public final class ViewRootImpl implements ViewParent,
mTranslator.translateRectInScreenToAppWindow(mPendingOverscanInsets);
mTranslator.translateRectInScreenToAppWindow(mPendingContentInsets);
mTranslator.translateRectInScreenToAppWindow(mPendingVisibleInsets);
+ mTranslator.translateRectInScreenToAppWindow(mPendingStableInsets);
}
return relayoutResult;
}
@@ -5446,7 +5466,7 @@ public final class ViewRootImpl implements ViewParent,
}
public void dispatchResized(Rect frame, Rect overscanInsets, Rect contentInsets,
- Rect visibleInsets, boolean reportDraw, Configuration newConfig) {
+ Rect visibleInsets, Rect stableInsets, boolean reportDraw, Configuration newConfig) {
if (DEBUG_LAYOUT) Log.v(TAG, "Resizing " + this + ": frame=" + frame.toShortString()
+ " contentInsets=" + contentInsets.toShortString()
+ " visibleInsets=" + visibleInsets.toShortString()
@@ -5465,6 +5485,7 @@ public final class ViewRootImpl implements ViewParent,
args.arg3 = sameProcessCall ? new Rect(visibleInsets) : visibleInsets;
args.arg4 = sameProcessCall && newConfig != null ? new Configuration(newConfig) : newConfig;
args.arg5 = sameProcessCall ? new Rect(overscanInsets) : overscanInsets;
+ args.arg6 = sameProcessCall ? new Rect(stableInsets) : stableInsets;
msg.obj = args;
mHandler.sendMessage(msg);
}
@@ -6292,11 +6313,12 @@ public final class ViewRootImpl implements ViewParent,
@Override
public void resized(Rect frame, Rect overscanInsets, Rect contentInsets,
- Rect visibleInsets, boolean reportDraw, Configuration newConfig) {
+ Rect visibleInsets, Rect stableInsets, boolean reportDraw,
+ Configuration newConfig) {
final ViewRootImpl viewAncestor = mViewAncestor.get();
if (viewAncestor != null) {
viewAncestor.dispatchResized(frame, overscanInsets, contentInsets,
- visibleInsets, reportDraw, newConfig);
+ visibleInsets, stableInsets, reportDraw, newConfig);
}
}
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index 0a44d23..aa71ed8 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -130,7 +130,20 @@ public abstract class Window {
public static final int PROGRESS_SECONDARY_START = 20000;
/** Highest possible value for the secondary progress */
public static final int PROGRESS_SECONDARY_END = 30000;
-
+
+ /**
+ * The transitionName for the status bar background View when a custom background is used.
+ * @see android.view.Window#setStatusBarColor(int)
+ */
+ public static final String STATUS_BAR_BACKGROUND_TRANSITION_NAME = "android:status:background";
+
+ /**
+ * The transitionName for the navigation bar background View when a custom background is used.
+ * @see android.view.Window#setNavigationBarColor(int)
+ */
+ public static final String NAVIGATION_BAR_BACKGROUND_TRANSITION_NAME =
+ "android:navigation:background";
+
/** The default features enabled */
@SuppressWarnings({"PointlessBitwiseExpression"})
protected static final int DEFAULT_FEATURES = (1 << FEATURE_OPTIONS_PANEL) |
@@ -1554,6 +1567,9 @@ public abstract class Window {
* If {@param color} is not opaque, consider setting
* {@link android.view.View#SYSTEM_UI_FLAG_LAYOUT_STABLE} and
* {@link android.view.View#SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN}.
+ * <p>
+ * The transitionName for the view background will be "android:status:background".
+ * </p>
*/
public abstract void setStatusBarColor(int color);
@@ -1573,6 +1589,9 @@ public abstract class Window {
* If {@param color} is not opaque, consider setting
* {@link android.view.View#SYSTEM_UI_FLAG_LAYOUT_STABLE} and
* {@link android.view.View#SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION}.
+ * <p>
+ * The transitionName for the view background will be "android:navigation:background".
+ * </p>
*/
public abstract void setNavigationBarColor(int color);
diff --git a/core/java/android/view/WindowInsets.java b/core/java/android/view/WindowInsets.java
index 1d2f1bf..1832cc3 100644
--- a/core/java/android/view/WindowInsets.java
+++ b/core/java/android/view/WindowInsets.java
@@ -30,13 +30,16 @@ import android.graphics.Rect;
* @see View#onApplyWindowInsets(WindowInsets)
*/
public final class WindowInsets {
+
private Rect mSystemWindowInsets;
private Rect mWindowDecorInsets;
+ private Rect mStableInsets;
private Rect mTempRect;
private boolean mIsRound;
private boolean mSystemWindowInsetsConsumed = false;
private boolean mWindowDecorInsetsConsumed = false;
+ private boolean mStableInsetsConsumed = false;
private static final Rect EMPTY_RECT = new Rect(0, 0, 0, 0);
@@ -49,29 +52,21 @@ public final class WindowInsets {
public static final WindowInsets CONSUMED;
static {
- CONSUMED = new WindowInsets(EMPTY_RECT, EMPTY_RECT);
- CONSUMED.mSystemWindowInsetsConsumed = true;
- CONSUMED.mWindowDecorInsetsConsumed = true;
- }
-
- /** @hide */
- public WindowInsets(Rect systemWindowInsets, Rect windowDecorInsets) {
- this(systemWindowInsets, windowDecorInsets, false);
- }
-
- /** @hide */
- public WindowInsets(Rect systemWindowInsets, boolean isRound) {
- this(systemWindowInsets, null, isRound);
+ CONSUMED = new WindowInsets(null, null, null, false);
}
/** @hide */
- public WindowInsets(Rect systemWindowInsets, Rect windowDecorInsets, boolean isRound) {
+ public WindowInsets(Rect systemWindowInsets, Rect windowDecorInsets, Rect stableInsets,
+ boolean isRound) {
mSystemWindowInsetsConsumed = systemWindowInsets == null;
mSystemWindowInsets = mSystemWindowInsetsConsumed ? EMPTY_RECT : systemWindowInsets;
mWindowDecorInsetsConsumed = windowDecorInsets == null;
mWindowDecorInsets = mWindowDecorInsetsConsumed ? EMPTY_RECT : windowDecorInsets;
+ mStableInsetsConsumed = stableInsets == null;
+ mStableInsets = mStableInsetsConsumed ? EMPTY_RECT : stableInsets;
+
mIsRound = isRound;
}
@@ -83,14 +78,16 @@ public final class WindowInsets {
public WindowInsets(WindowInsets src) {
mSystemWindowInsets = src.mSystemWindowInsets;
mWindowDecorInsets = src.mWindowDecorInsets;
+ mStableInsets = src.mStableInsets;
mSystemWindowInsetsConsumed = src.mSystemWindowInsetsConsumed;
mWindowDecorInsetsConsumed = src.mWindowDecorInsetsConsumed;
+ mStableInsetsConsumed = src.mStableInsetsConsumed;
mIsRound = src.mIsRound;
}
/** @hide */
public WindowInsets(Rect systemWindowInsets) {
- this(systemWindowInsets, null);
+ this(systemWindowInsets, null, null, false);
}
/**
@@ -272,7 +269,7 @@ public final class WindowInsets {
* @hide Pending API
*/
public boolean isConsumed() {
- return mSystemWindowInsetsConsumed && mWindowDecorInsetsConsumed;
+ return mSystemWindowInsetsConsumed && mWindowDecorInsetsConsumed && mStableInsetsConsumed;
}
/**
@@ -381,9 +378,57 @@ public final class WindowInsets {
return result;
}
+ /**
+ * @hide
+ */
+ public int getStableInsetTop() {
+ return mStableInsets.top;
+ }
+
+ /**
+ * @hide
+ */
+ public int getStableInsetLeft() {
+ return mStableInsets.left;
+ }
+
+ /**
+ * @hide
+ */
+ public int getStableInsetRight() {
+ return mStableInsets.right;
+ }
+
+ /**
+ * @hide
+ */
+ public int getStableInsetBottom() {
+ return mStableInsets.bottom;
+ }
+
+ /**
+ * @hide
+ */
+ public boolean hasStableInsets() {
+ return mStableInsets.top != 0 || mStableInsets.left != 0 || mStableInsets.right != 0
+ || mStableInsets.bottom != 0;
+ }
+
+ /**
+ * @hide
+ */
+ public WindowInsets consumeStableInsets() {
+ final WindowInsets result = new WindowInsets(this);
+ result.mStableInsets = EMPTY_RECT;
+ result.mStableInsetsConsumed = true;
+ return result;
+ }
+
@Override
public String toString() {
- return "WindowInsets{systemWindowInsets=" + mSystemWindowInsets + " windowDecorInsets=" +
- mWindowDecorInsets + (isRound() ? "round}" : "}");
+ return "WindowInsets{systemWindowInsets=" + mSystemWindowInsets
+ + " windowDecorInsets=" + mWindowDecorInsets
+ + " stableInsets=" + mStableInsets +
+ (isRound() ? " round}" : "}");
}
}
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index 024600d..ee542a1 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -149,9 +149,11 @@ public interface WindowManagerPolicy {
* are visible.
* @param decorFrame The decor frame specified by policy specific to this window,
* to use for proper cropping during animation.
+ * @param stableFrame The frame around which stable system decoration is positioned.
*/
public void computeFrameLw(Rect parentFrame, Rect displayFrame,
- Rect overlayFrame, Rect contentFrame, Rect visibleFrame, Rect decorFrame);
+ Rect overlayFrame, Rect contentFrame, Rect visibleFrame, Rect decorFrame,
+ Rect stableFrame);
/**
* Retrieve the current frame of the window that has been assigned by