Merge "Add 'pm' operation to set a package's app-linking state" into mnc-dev
diff --git a/api/current.txt b/api/current.txt
index 21ca33c..79d5ea0 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -28898,6 +28898,7 @@
method public java.lang.String getCallingPackage();
method public int getCallingUid();
method public android.os.Bundle getExtras();
+ method public boolean isActive();
}
public abstract class VoiceInteractionSessionService extends android.app.Service {
diff --git a/api/system-current.txt b/api/system-current.txt
index bbff8c0..0af72d5 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -31050,6 +31050,7 @@
method public java.lang.String getCallingPackage();
method public int getCallingUid();
method public android.os.Bundle getExtras();
+ method public boolean isActive();
}
public abstract class VoiceInteractionSessionService extends android.app.Service {
diff --git a/core/java/android/content/res/DrawableCache.java b/core/java/android/content/res/DrawableCache.java
index fc70bc60..ba00134 100644
--- a/core/java/android/content/res/DrawableCache.java
+++ b/core/java/android/content/res/DrawableCache.java
@@ -52,6 +52,6 @@
@Override
public boolean shouldInvalidateEntry(Drawable.ConstantState entry, int configChanges) {
- return false;
+ return Configuration.needNewResources(configChanges, entry.getChangingConfigurations());
}
}
diff --git a/core/java/android/inputmethodservice/ExtractEditText.java b/core/java/android/inputmethodservice/ExtractEditText.java
index b039fc7..a2c1d18 100644
--- a/core/java/android/inputmethodservice/ExtractEditText.java
+++ b/core/java/android/inputmethodservice/ExtractEditText.java
@@ -103,8 +103,12 @@
}
@Override public boolean onTextContextMenuItem(int id) {
- // Select all shouldn't be handled by the original edit text, but by the extracted one.
- if (id != android.R.id.selectAll && mIME != null && mIME.onExtractTextContextMenuItem(id)) {
+ // Select all and Replace text shouldn't be handled by the original edit text, but by the
+ // extracted one.
+ if (id == android.R.id.selectAll || id == android.R.id.replaceText) {
+ return super.onTextContextMenuItem(id);
+ }
+ if (mIME != null && mIME.onExtractTextContextMenuItem(id)) {
// Mode was started on Extracted, needs to be stopped here.
// Cut will change the text, which stops selection mode.
if (id == android.R.id.copy || id == android.R.id.paste) stopTextActionMode();
diff --git a/core/java/android/service/voice/VoiceInteractionSession.java b/core/java/android/service/voice/VoiceInteractionSession.java
index a3ccbd3..f08e93c 100644
--- a/core/java/android/service/voice/VoiceInteractionSession.java
+++ b/core/java/android/service/voice/VoiceInteractionSession.java
@@ -322,6 +322,22 @@
return mExtras;
}
+ /**
+ * Check whether this request is currently active. A request becomes inactive after
+ * calling {@link #cancel} or a final result method that completes the request. After
+ * this point, further interactions with the request will result in
+ * {@link java.lang.IllegalStateException} errors; you should not catch these errors,
+ * but can use this method if you need to determine the state of the request. Returns
+ * true if the request is still active.
+ */
+ public boolean isActive() {
+ VoiceInteractionSession session = mSession.get();
+ if (session == null) {
+ return false;
+ }
+ return session.isRequestActive(mInterface.asBinder());
+ }
+
void finishRequest() {
VoiceInteractionSession session = mSession.get();
if (session == null) {
@@ -338,6 +354,7 @@
/**
* Ask the app to cancel this current request.
+ * This also finishes the request (it is no longer active).
*/
public void cancel() {
try {
@@ -389,6 +406,7 @@
* in a call to
* {@link android.app.VoiceInteractor.ConfirmationRequest#onConfirmationResult
* VoiceInteractor.ConfirmationRequest.onConfirmationResult}.
+ * This finishes the request (it is no longer active).
*/
public void sendConfirmationResult(boolean confirmed, Bundle result) {
try {
@@ -475,6 +493,7 @@
* and resulting in a call to
* {@link android.app.VoiceInteractor.PickOptionRequest#onPickOptionResult
* VoiceInteractor.PickOptionRequest.onPickOptionResult} with false for finished.
+ * This finishes the request (it is no longer active).
*/
public void sendPickOptionResult(
VoiceInteractor.PickOptionRequest.Option[] selections, Bundle result) {
@@ -522,6 +541,7 @@
* in a call to
* {@link android.app.VoiceInteractor.CompleteVoiceRequest#onCompleteResult
* VoiceInteractor.CompleteVoiceRequest.onCompleteResult}.
+ * This finishes the request (it is no longer active).
*/
public void sendCompleteResult(Bundle result) {
try {
@@ -570,7 +590,8 @@
* Report that the voice interactor has finished aborting the voice operation, resulting
* in a call to
* {@link android.app.VoiceInteractor.AbortVoiceRequest#onAbortResult
- * VoiceInteractor.AbortVoiceRequest.onAbortResult}.
+ * VoiceInteractor.AbortVoiceRequest.onAbortResult}. This finishes the request (it
+ * is no longer active).
*/
public void sendAbortResult(Bundle result) {
try {
@@ -630,6 +651,7 @@
* Report the final result of the request, completing the request and resulting in a call to
* {@link android.app.VoiceInteractor.CommandRequest#onCommandResult
* VoiceInteractor.CommandRequest.onCommandResult} with true for isCompleted.
+ * This finishes the request (it is no longer active).
*/
public void sendResult(Bundle result) {
sendCommandResult(true, result);
@@ -820,7 +842,15 @@
}
void addRequest(Request req) {
- mActiveRequests.put(req.mInterface.asBinder(), req);
+ synchronized (this) {
+ mActiveRequests.put(req.mInterface.asBinder(), req);
+ }
+ }
+
+ boolean isRequestActive(IBinder reqInterface) {
+ synchronized (this) {
+ return mActiveRequests.containsKey(reqInterface);
+ }
}
Request removeRequest(IBinder reqInterface) {
diff --git a/core/java/android/text/BidiFormatter.java b/core/java/android/text/BidiFormatter.java
index 7ea9da1..5c088cd 100644
--- a/core/java/android/text/BidiFormatter.java
+++ b/core/java/android/text/BidiFormatter.java
@@ -173,7 +173,7 @@
/**
* Specifies whether the BidiFormatter to be built should also "reset" directionality before
- * a string being bidi-wrapped, not just after it. The default is false.
+ * a string being bidi-wrapped, not just after it. The default is true.
*/
public Builder stereoReset(boolean stereoReset) {
if (stereoReset) {
@@ -363,12 +363,13 @@
* If {@code isolate}, directionally isolates the string so that it does not garble its
* surroundings. Currently, this is done by "resetting" the directionality after the string by
* appending a trailing Unicode bidi mark matching the context directionality (LRM or RLM) when
- * either the overall directionality or the exit directionality of the string is opposite to that
- * of the context. If the formatter was built using {@link Builder#stereoReset(boolean)} and
- * passing "true" as an argument, also prepends a Unicode bidi mark matching the context
- * directionality when either the overall directionality or the entry directionality of the
- * string is opposite to that of the context. Note that as opposed to the overall
- * directionality, the entry and exit directionalities are determined from the string itself.
+ * either the overall directionality or the exit directionality of the string is opposite to
+ * that of the context. Unless the formatter was built using
+ * {@link Builder#stereoReset(boolean)} with a {@code false} argument, also prepends a Unicode
+ * bidi mark matching the context directionality when either the overall directionality or the
+ * entry directionality of the string is opposite to that of the context. Note that as opposed
+ * to the overall directionality, the entry and exit directionalities are determined from the
+ * string itself.
* <p>
* Does *not* do HTML-escaping.
*
diff --git a/core/java/android/text/TextLine.java b/core/java/android/text/TextLine.java
index 605b91d..39e8694 100644
--- a/core/java/android/text/TextLine.java
+++ b/core/java/android/text/TextLine.java
@@ -741,11 +741,11 @@
if (needWidth || (c != null && (wp.bgColor != 0 || wp.underlineColor != 0 || runIsRtl))) {
if (mCharsValid) {
- ret = wp.getRunAdvance(mChars, start, contextEnd, contextStart, contextEnd,
+ ret = wp.getRunAdvance(mChars, start, end, contextStart, contextEnd,
runIsRtl, end);
} else {
int delta = mStart;
- ret = wp.getRunAdvance(mText, delta + start, delta + contextEnd,
+ ret = wp.getRunAdvance(mText, delta + start, delta + end,
delta + contextStart, delta + contextEnd, runIsRtl, delta + end);
}
}
diff --git a/core/java/android/text/format/Formatter.java b/core/java/android/text/format/Formatter.java
index 82689b9..b5068b2 100644
--- a/core/java/android/text/format/Formatter.java
+++ b/core/java/android/text/format/Formatter.java
@@ -16,12 +16,18 @@
package android.text.format;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
import android.content.res.Resources;
+import android.text.BidiFormatter;
+import android.text.TextUtils;
+import android.view.View;
import android.net.NetworkUtils;
import android.net.TrafficStats;
+import java.util.Locale;
+
/**
* Utility class to aid in formatting common values that are not covered
* by the {@link java.util.Formatter} class in {@link java.util}
@@ -46,8 +52,23 @@
}
}
+ /* Wraps the source string in bidi formatting characters in RTL locales */
+ private static String bidiWrap(@NonNull Context context, String source) {
+ final Locale locale = context.getResources().getConfiguration().locale;
+ if (TextUtils.getLayoutDirectionFromLocale(locale) == View.LAYOUT_DIRECTION_RTL) {
+ return BidiFormatter.getInstance(true /* RTL*/).unicodeWrap(source);
+ } else {
+ return source;
+ }
+ }
+
/**
- * Formats a content size to be in the form of bytes, kilobytes, megabytes, etc
+ * Formats a content size to be in the form of bytes, kilobytes, megabytes, etc.
+ *
+ * If the context has a right-to-left locale, the returned string is wrapped in bidi formatting
+ * characters to make sure it's displayed correctly if inserted inside a right-to-left string.
+ * (This is useful in cases where the unit strings, like "MB", are left-to-right, but the
+ * locale is right-to-left.)
*
* @param context Context to use to load the localized units
* @param sizeBytes size value to be formatted, in bytes
@@ -58,8 +79,8 @@
return "";
}
final BytesResult res = formatBytes(context.getResources(), sizeBytes, 0);
- return context.getString(com.android.internal.R.string.fileSizeSuffix,
- res.value, res.units);
+ return bidiWrap(context, context.getString(com.android.internal.R.string.fileSizeSuffix,
+ res.value, res.units));
}
/**
@@ -71,8 +92,8 @@
return "";
}
final BytesResult res = formatBytes(context.getResources(), sizeBytes, FLAG_SHORTER);
- return context.getString(com.android.internal.R.string.fileSizeSuffix,
- res.value, res.units);
+ return bidiWrap(context, context.getString(com.android.internal.R.string.fileSizeSuffix,
+ res.value, res.units));
}
/** {@hide} */
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index b2b98db..ed858e7 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -1556,13 +1556,6 @@
if (accessibilityId == getAccessibilityViewId()) {
return this;
}
- // If the data changed the children are invalid since the data model changed.
- // Hence, we pretend they do not exist. After a layout the children will sync
- // with the model at which point we notify that the accessibility state changed,
- // so a service will be able to re-fetch the views.
- if (mDataChanged) {
- return null;
- }
return super.findViewByAccessibilityIdTraversal(accessibilityId);
}
@@ -2409,18 +2402,6 @@
class ListItemAccessibilityDelegate extends AccessibilityDelegate {
@Override
- public AccessibilityNodeInfo createAccessibilityNodeInfo(View host) {
- // If the data changed the children are invalid since the data model changed.
- // Hence, we pretend they do not exist. After a layout the children will sync
- // with the model at which point we notify that the accessibility state changed,
- // so a service will be able to re-fetch the views.
- if (mDataChanged) {
- return null;
- }
- return super.createAccessibilityNodeInfo(host);
- }
-
- @Override
public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
super.onInitializeAccessibilityNodeInfo(host, info);
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index d897f49..15d13ae 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -3225,7 +3225,8 @@
}
private void updateReplaceItem(Menu menu) {
- boolean canReplace = mTextView.isSuggestionsEnabled() && shouldOfferToShowSuggestions();
+ boolean canReplace = mTextView.isSuggestionsEnabled() && shouldOfferToShowSuggestions()
+ && !(mTextView.isInExtractedMode() && mTextView.hasSelection());
boolean replaceItemExists = menu.findItem(TextView.ID_REPLACE) != null;
if (canReplace && !replaceItemExists) {
menu.add(Menu.NONE, TextView.ID_REPLACE, MENU_ITEM_ORDER_REPLACE,
diff --git a/core/java/com/android/internal/app/AssistUtils.java b/core/java/com/android/internal/app/AssistUtils.java
index ff989bd..0910daf 100644
--- a/core/java/com/android/internal/app/AssistUtils.java
+++ b/core/java/com/android/internal/app/AssistUtils.java
@@ -49,8 +49,10 @@
public boolean showSessionForActiveService(Bundle args, int sourceFlags,
IVoiceInteractionSessionShowCallback showCallback, IBinder activityToken) {
try {
- return mVoiceInteractionManagerService.showSessionForActiveService(args, sourceFlags,
- showCallback, activityToken);
+ if (mVoiceInteractionManagerService != null) {
+ return mVoiceInteractionManagerService.showSessionForActiveService(args,
+ sourceFlags, showCallback, activityToken);
+ }
} catch (RemoteException e) {
Log.w(TAG, "Failed to call showSessionForActiveService", e);
}
@@ -59,7 +61,9 @@
public void launchVoiceAssistFromKeyguard() {
try {
- mVoiceInteractionManagerService.launchVoiceAssistFromKeyguard();
+ if (mVoiceInteractionManagerService != null) {
+ mVoiceInteractionManagerService.launchVoiceAssistFromKeyguard();
+ }
} catch (RemoteException e) {
Log.w(TAG, "Failed to call launchVoiceAssistFromKeyguard", e);
}
@@ -87,7 +91,11 @@
public ComponentName getActiveServiceComponentName() {
try {
- return mVoiceInteractionManagerService.getActiveServiceComponentName();
+ if (mVoiceInteractionManagerService != null) {
+ return mVoiceInteractionManagerService.getActiveServiceComponentName();
+ } else {
+ return null;
+ }
} catch (RemoteException e) {
Log.w(TAG, "Failed to call getActiveServiceComponentName", e);
return null;
@@ -106,7 +114,9 @@
public void hideCurrentSession() {
try {
- mVoiceInteractionManagerService.hideCurrentSession();
+ if (mVoiceInteractionManagerService != null) {
+ mVoiceInteractionManagerService.hideCurrentSession();
+ }
} catch (RemoteException e) {
Log.w(TAG, "Failed to call hideCurrentSession", e);
}
diff --git a/core/res/res/layout/time_picker_header_material.xml b/core/res/res/layout/time_picker_header_material.xml
index 3f5e300..3c3a8a8 100644
--- a/core/res/res/layout/time_picker_header_material.xml
+++ b/core/res/res/layout/time_picker_header_material.xml
@@ -22,7 +22,9 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
- android:padding="@dimen/timepicker_separator_padding">
+ android:padding="@dimen/timepicker_separator_padding"
+ android:paddingStart="16dp"
+ android:paddingEnd="16dp">
<!-- The hour should always be to the left of the separator,
regardless of the current locale's layout direction. -->
@@ -68,14 +70,14 @@
android:layout_height="wrap_content"
android:layout_toRightOf="@+id/minutes"
android:layout_alignBaseline="@+id/minutes"
+ android:paddingStart="8dp"
+ android:paddingEnd="8dp"
android:orientation="vertical"
android:baselineAlignedChildIndex="1">
<CheckedTextView
android:id="@+id/am_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:paddingStart="@dimen/timepicker_ampm_horizontal_padding"
- android:paddingEnd="@dimen/timepicker_ampm_horizontal_padding"
android:paddingTop="@dimen/timepicker_am_top_padding"
android:textAppearance="@style/TextAppearance.Material.TimePicker.AmPmLabel"
android:lines="1"
@@ -84,8 +86,6 @@
android:id="@+id/pm_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:paddingStart="@dimen/timepicker_ampm_horizontal_padding"
- android:paddingEnd="@dimen/timepicker_ampm_horizontal_padding"
android:paddingTop="@dimen/timepicker_pm_top_padding"
android:textAppearance="@style/TextAppearance.Material.TimePicker.AmPmLabel"
android:lines="1"
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index a855f2f..06b6389 100755
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2261,4 +2261,12 @@
<!-- How long history of previous vibrations should be kept for the dumpsys. -->
<integer name="config_previousVibrationsDumpLimit">20</integer>
+
+ <!-- Number of retries Cell Data should attempt for a given error code before
+ restarting the modem.
+ Error codes not listed will not lead to modem restarts.
+ Array of "code#,retry#" -->
+ <string-array name="config_cell_retries_per_error_code">
+ </string-array>
+
</resources>
diff --git a/core/res/res/values/dimens_material.xml b/core/res/res/values/dimens_material.xml
index b980777..558afa7 100644
--- a/core/res/res/values/dimens_material.xml
+++ b/core/res/res/values/dimens_material.xml
@@ -127,7 +127,7 @@
<!-- Text size for the time picker header HH:MM label. This value is large
enough that we don't need to use scaled pixels, dp is fine. -->
<dimen name="timepicker_time_label_size">60dp</dimen>
- <dimen name="timepicker_ampm_label_size">16sp</dimen>
+ <dimen name="timepicker_ampm_label_size">16dp</dimen>
<dimen name="timepicker_ampm_horizontal_padding">16dp</dimen>
<dimen name="timepicker_am_top_padding">4dp</dimen>
<dimen name="timepicker_pm_top_padding">4dp</dimen>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 3695cf6..f590ebe 100755
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2311,4 +2311,6 @@
<java-symbol type="bool" name="allow_stacked_button_bar" />
<java-symbol type="bool" name="config_eap_sim_based_auth_supported" />
+
+ <java-symbol type="array" name="config_cell_retries_per_error_code" />
</resources>
diff --git a/media/java/android/media/IRingtonePlayer.aidl b/media/java/android/media/IRingtonePlayer.aidl
index aa5fde3..8091421 100644
--- a/media/java/android/media/IRingtonePlayer.aidl
+++ b/media/java/android/media/IRingtonePlayer.aidl
@@ -33,4 +33,7 @@
/** Used for Notification sound playback. */
void playAsync(in Uri uri, in UserHandle user, boolean looping, in AudioAttributes aa);
void stopAsync();
+
+ /** Return the title of the media. */
+ String getTitle(in Uri uri);
}
diff --git a/media/java/android/media/Ringtone.java b/media/java/android/media/Ringtone.java
index faeebe6..9e9d602 100644
--- a/media/java/android/media/Ringtone.java
+++ b/media/java/android/media/Ringtone.java
@@ -27,6 +27,7 @@
import android.os.RemoteException;
import android.provider.MediaStore;
import android.provider.Settings;
+import android.provider.MediaStore.MediaColumns;
import android.util.Log;
import java.io.IOException;
@@ -50,6 +51,8 @@
MediaStore.Audio.Media.DATA,
MediaStore.Audio.Media.TITLE
};
+ /** Selection that limits query results to just audio files */
+ private static final String MEDIA_SELECTION = MediaColumns.MIME_TYPE + " LIKE 'audio/%'";
// keep references on active Ringtones until stopped or completion listener called.
private static final ArrayList<Ringtone> sActiveRingtones = new ArrayList<Ringtone>();
@@ -193,11 +196,14 @@
*/
public String getTitle(Context context) {
if (mTitle != null) return mTitle;
- return mTitle = getTitle(context, mUri, true);
+ return mTitle = getTitle(context, mUri, true /*followSettingsUri*/, mAllowRemote);
}
- private static String getTitle(Context context, Uri uri, boolean followSettingsUri) {
- Cursor cursor = null;
+ /**
+ * @hide
+ */
+ public static String getTitle(
+ Context context, Uri uri, boolean followSettingsUri, boolean allowRemote) {
ContentResolver res = context.getContentResolver();
String title = null;
@@ -209,31 +215,45 @@
if (followSettingsUri) {
Uri actualUri = RingtoneManager.getActualDefaultRingtoneUri(context,
RingtoneManager.getDefaultType(uri));
- String actualTitle = getTitle(context, actualUri, false);
+ String actualTitle = getTitle(
+ context, actualUri, false /*followSettingsUri*/, allowRemote);
title = context
.getString(com.android.internal.R.string.ringtone_default_with_actual,
actualTitle);
}
} else {
+ Cursor cursor = null;
try {
if (MediaStore.AUTHORITY.equals(authority)) {
- cursor = res.query(uri, MEDIA_COLUMNS, null, null, null);
+ final String mediaSelection = allowRemote ? null : MEDIA_SELECTION;
+ cursor = res.query(uri, MEDIA_COLUMNS, mediaSelection, null, null);
+ if (cursor != null && cursor.getCount() == 1) {
+ cursor.moveToFirst();
+ return cursor.getString(2);
+ }
+ // missing cursor is handled below
}
} catch (SecurityException e) {
- // missing cursor is handled below
- }
-
- try {
- if (cursor != null && cursor.getCount() == 1) {
- cursor.moveToFirst();
- return cursor.getString(2);
- } else {
- title = uri.getLastPathSegment();
+ IRingtonePlayer mRemotePlayer = null;
+ if (allowRemote) {
+ AudioManager audioManager =
+ (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
+ mRemotePlayer = audioManager.getRingtonePlayer();
+ }
+ if (mRemotePlayer != null) {
+ try {
+ title = mRemotePlayer.getTitle(uri);
+ } catch (RemoteException re) {
+ }
}
} finally {
if (cursor != null) {
cursor.close();
}
+ cursor = null;
+ }
+ if (title == null) {
+ title = uri.getLastPathSegment();
}
}
}
diff --git a/media/java/android/media/tv/TvInputService.java b/media/java/android/media/tv/TvInputService.java
index 35037bb..86e8560 100644
--- a/media/java/android/media/tv/TvInputService.java
+++ b/media/java/android/media/tv/TvInputService.java
@@ -385,13 +385,14 @@
trackIdSet.clear();
// TODO: Validate the track list.
+ final List<TvTrackInfo> tracksCopy = new ArrayList<>(tracks);
executeOrPostRunnable(new Runnable() {
@Override
public void run() {
try {
if (DEBUG) Log.d(TAG, "notifyTracksChanged");
if (mSessionCallback != null) {
- mSessionCallback.onTracksChanged(tracks);
+ mSessionCallback.onTracksChanged(tracksCopy);
}
} catch (RemoteException e) {
Log.w(TAG, "error in notifyTracksChanged", e);
diff --git a/packages/SystemUI/res/layout/status_bar_notification_keyguard_overflow.xml b/packages/SystemUI/res/layout/status_bar_notification_keyguard_overflow.xml
index 4526af5..f699fce 100644
--- a/packages/SystemUI/res/layout/status_bar_notification_keyguard_overflow.xml
+++ b/packages/SystemUI/res/layout/status_bar_notification_keyguard_overflow.xml
@@ -31,7 +31,7 @@
android:layout_height="match_parent"
/>
- <LinearLayout
+ <com.android.keyguard.AlphaOptimizedLinearLayout
android:id="@+id/content"
android:layout_width="match_parent"
android:layout_height="match_parent">
@@ -63,6 +63,6 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
- </LinearLayout>
+ </com.android.keyguard.AlphaOptimizedLinearLayout>
</com.android.systemui.statusbar.NotificationOverflowContainer>
diff --git a/packages/SystemUI/src/com/android/systemui/DejankUtils.java b/packages/SystemUI/src/com/android/systemui/DejankUtils.java
new file mode 100644
index 0000000..fc98ec4
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/DejankUtils.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2015 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 com.android.systemui;
+
+import android.os.Handler;
+import android.os.Looper;
+import android.os.StrictMode;
+import android.view.Choreographer;
+
+import java.util.ArrayList;
+
+/**
+ * Utility class for methods used to dejank the UI.
+ */
+public class DejankUtils {
+
+ private static final Choreographer sChoreographer = Choreographer.getInstance();
+ private static final Handler sHandler = new Handler();
+
+ private static final ArrayList<Runnable> sPendingRunnables = new ArrayList<>();
+
+ private static final Runnable sAnimationCallbackRunnable = new Runnable() {
+ @Override
+ public void run() {
+ for (int i = 0; i < sPendingRunnables.size(); i++) {
+ sHandler.post(sPendingRunnables.get(i));
+ }
+ sPendingRunnables.clear();
+ }
+ };
+
+ /**
+ * Executes {@code r} after performTraversals. Use this do to CPU heavy work for which the
+ * timing is not critical for animation. The work is then scheduled at the same time
+ * RenderThread is doing its thing, leading to better parallelization.
+ *
+ * <p>Needs to be called from the main thread.
+ */
+ public static void postAfterTraversal(Runnable r) {
+ throwIfNotCalledOnMainThread();
+ sPendingRunnables.add(r);
+ postAnimationCallback();
+ }
+
+ /**
+ * Removes a previously scheduled runnable.
+ *
+ * <p>Needs to be called from the main thread.
+ */
+ public static void removeCallbacks(Runnable r) {
+ throwIfNotCalledOnMainThread();
+ sPendingRunnables.remove(r);
+ sHandler.removeCallbacks(r);
+ }
+
+ private static void postAnimationCallback() {
+ sChoreographer.postCallback(Choreographer.CALLBACK_ANIMATION, sAnimationCallbackRunnable,
+ null);
+ }
+
+ private static void throwIfNotCalledOnMainThread() {
+ if (!Looper.getMainLooper().isCurrentThread()) {
+ throw new IllegalStateException("should be called from the main thread.");
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java b/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java
index e9a256c..fe876d7 100644
--- a/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java
+++ b/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java
@@ -171,6 +171,13 @@
}
mAsyncPlayer.stop();
}
+
+ @Override
+ public String getTitle(Uri uri) {
+ final UserHandle user = Binder.getCallingUserHandle();
+ return Ringtone.getTitle(getContextForUser(user), uri,
+ false /*followSettingsUri*/, false /*allowRemote*/);
+ }
};
private Context getContextForUser(UserHandle user) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
index ddde106..7b83e6a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
@@ -23,10 +23,9 @@
import com.android.internal.logging.MetricsLogger;
import com.android.systemui.Prefs;
import com.android.systemui.R;
-import com.android.systemui.qs.UsageTracker;
import com.android.systemui.qs.QSTile;
+import com.android.systemui.qs.UsageTracker;
import com.android.systemui.statusbar.policy.HotspotController;
-import com.android.systemui.statusbar.policy.KeyguardMonitor;
/** Quick settings tile: Hotspot **/
public class HotspotTile extends QSTile<QSTile.BooleanState> {
@@ -37,14 +36,12 @@
private final HotspotController mController;
private final Callback mCallback = new Callback();
private final UsageTracker mUsageTracker;
- private final KeyguardMonitor mKeyguard;
public HotspotTile(Host host) {
super(host);
mController = host.getHotspotController();
mUsageTracker = newUsageTracker(host.getContext());
mUsageTracker.setListening(true);
- mKeyguard = host.getKeyguardMonitor();
}
@Override
@@ -97,7 +94,7 @@
if (arg instanceof Boolean) {
state.value = (boolean) arg;
} else {
- mController.isHotspotEnabled();
+ state.value = mController.isHotspotEnabled();
}
state.icon = state.visible && state.value ? mEnable : mDisable;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
index 7cde44c..403af70 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
@@ -656,12 +656,14 @@
}
private void setContentAlpha(float contentAlpha) {
- int layerType = contentAlpha == 0.0f || contentAlpha == 1.0f ? LAYER_TYPE_NONE
- : LAYER_TYPE_HARDWARE;
View contentView = getContentView();
- int currentLayerType = contentView.getLayerType();
- if (currentLayerType != layerType) {
- contentView.setLayerType(layerType, null);
+ if (contentView.hasOverlappingRendering()) {
+ int layerType = contentAlpha == 0.0f || contentAlpha == 1.0f ? LAYER_TYPE_NONE
+ : LAYER_TYPE_HARDWARE;
+ int currentLayerType = contentView.getLayerType();
+ if (currentLayerType != layerType) {
+ contentView.setLayerType(layerType, null);
+ }
}
contentView.setAlpha(contentAlpha);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
index a7afec4..e9b2c61 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
@@ -29,6 +29,7 @@
import com.android.keyguard.KeyguardSecurityView;
import com.android.keyguard.R;
import com.android.keyguard.ViewMediatorCallback;
+import com.android.systemui.DejankUtils;
import static com.android.keyguard.KeyguardHostView.OnDismissAction;
import static com.android.keyguard.KeyguardSecurityModel.SecurityMode;
@@ -46,7 +47,6 @@
private KeyguardHostView mKeyguardView;
private ViewGroup mRoot;
private boolean mShowingSoon;
- private Choreographer mChoreographer = Choreographer.getInstance();
private int mBouncerPromptReason;
public KeyguardBouncer(Context context, ViewMediatorCallback callback,
@@ -70,16 +70,13 @@
return;
}
- mBouncerPromptReason = mCallback.getBouncerPromptReason();
-
// Try to dismiss the Keyguard. If no security pattern is set, this will dismiss the whole
// Keyguard. If we need to authenticate, show the bouncer.
if (!mKeyguardView.dismiss()) {
mShowingSoon = true;
// Split up the work over multiple frames.
- mChoreographer.postCallbackDelayed(Choreographer.CALLBACK_ANIMATION, mShowRunnable,
- null, 16);
+ DejankUtils.postAfterTraversal(mShowRunnable);
}
}
@@ -107,7 +104,7 @@
}
private void cancelShowRunnable() {
- mChoreographer.removeCallbacks(Choreographer.CALLBACK_ANIMATION, mShowRunnable, null);
+ DejankUtils.removeCallbacks(mShowRunnable);
mShowingSoon = false;
}
@@ -165,6 +162,7 @@
if (wasInitialized) {
mKeyguardView.showPrimarySecurityScreen();
}
+ mBouncerPromptReason = mCallback.getBouncerPromptReason();
}
private void ensureView() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index f40f5016..416fb36 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -40,6 +40,7 @@
import android.view.Surface;
import android.view.View;
import android.view.ViewGroup;
+import android.view.ViewRootImpl;
import android.view.WindowManager;
import android.view.inputmethod.InputMethodManager;
import android.widget.FrameLayout;
@@ -184,6 +185,15 @@
mBarTransitions = new NavigationBarTransitions(this);
}
+ @Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ ViewRootImpl root = getViewRootImpl();
+ if (root != null) {
+ root.setDrawDuringWindowsAnimating(true);
+ }
+ }
+
public BarTransitions getBarTransitions() {
return mBarTransitions;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index f0927a8..2248905 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -2677,6 +2677,9 @@
if (mBluetoothController != null) {
mBluetoothController.dump(fd, pw, args);
}
+ if (mHotspotController != null) {
+ mHotspotController.dump(fd, pw, args);
+ }
if (mCastController != null) {
mCastController.dump(fd, pw, args);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
index 6d04b28..c0887ca 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
@@ -24,6 +24,7 @@
import android.view.View;
import android.view.accessibility.AccessibilityEvent;
+import com.android.systemui.DejankUtils;
import com.android.systemui.EventLogTags;
import com.android.systemui.R;
@@ -117,12 +118,12 @@
public void onAllPanelsCollapsed() {
super.onAllPanelsCollapsed();
// Close the status bar in the next frame so we can show the end of the animation.
- postOnAnimation(mHideExpandedRunnable);
+ DejankUtils.postAfterTraversal(mHideExpandedRunnable);
mLastFullyOpenedPanel = null;
}
public void removePendingHideExpandedRunnables() {
- removeCallbacks(mHideExpandedRunnable);
+ DejankUtils.removeCallbacks(mHideExpandedRunnable);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java
index 1e3bc4d..41aeac9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java
@@ -17,7 +17,6 @@
package com.android.systemui.statusbar.policy;
import android.content.BroadcastReceiver;
-import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
@@ -27,6 +26,8 @@
import com.android.settingslib.TetherUtil;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
import java.util.ArrayList;
public class HotspotControllerImpl implements HotspotController {
@@ -43,11 +44,32 @@
private final ArrayList<Callback> mCallbacks = new ArrayList<Callback>();
private final Receiver mReceiver = new Receiver();
private final Context mContext;
- private final WifiManager mWifiManager;
+
+ private int mHotspotState;
public HotspotControllerImpl(Context context) {
mContext = context;
- mWifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
+ }
+
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ pw.println("HotspotController state:");
+ pw.print(" mHotspotEnabled="); pw.println(stateToString(mHotspotState));
+ }
+
+ private static String stateToString(int hotspotState) {
+ switch (hotspotState) {
+ case WifiManager.WIFI_AP_STATE_DISABLED:
+ return "DISABLED";
+ case WifiManager.WIFI_AP_STATE_DISABLING:
+ return "DISABLING";
+ case WifiManager.WIFI_AP_STATE_ENABLED:
+ return "ENABLED";
+ case WifiManager.WIFI_AP_STATE_ENABLING:
+ return "ENABLING";
+ case WifiManager.WIFI_AP_STATE_FAILED:
+ return "FAILED";
+ }
+ return null;
}
public void addCallback(Callback callback) {
@@ -66,7 +88,7 @@
@Override
public boolean isHotspotEnabled() {
- return mWifiManager.getWifiApState() == WifiManager.WIFI_AP_STATE_ENABLED;
+ return mHotspotState == WifiManager.WIFI_AP_STATE_ENABLED;
}
@Override
@@ -76,7 +98,6 @@
@Override
public void setHotspotEnabled(boolean enabled) {
- final ContentResolver cr = mContext.getContentResolver();
// Call provisioning app which is called when enabling Tethering from Settings
if (enabled && TetherUtil.isProvisioningNeeded(mContext)) {
mContext.startServiceAsUser(TETHER_SERVICE_INTENT, UserHandle.CURRENT);
@@ -113,7 +134,8 @@
if (DEBUG) Log.d(TAG, "onReceive " + intent.getAction());
int state = intent.getIntExtra(
WifiManager.EXTRA_WIFI_AP_STATE, WifiManager.WIFI_AP_STATE_FAILED);
- fireCallback(WifiManager.WIFI_AP_STATE_ENABLED == state);
+ mHotspotState = state;
+ fireCallback(mHotspotState == WifiManager.WIFI_AP_STATE_ENABLED);
}
}
}
diff --git a/rs/java/android/renderscript/ScriptIntrinsicBlend.java b/rs/java/android/renderscript/ScriptIntrinsicBlend.java
index 906e0f6..6b09bb7 100644
--- a/rs/java/android/renderscript/ScriptIntrinsicBlend.java
+++ b/rs/java/android/renderscript/ScriptIntrinsicBlend.java
@@ -360,6 +360,8 @@
/**
* dst = dst.rgb * src.a + (1.0 - dst.a) * src.rgb
* dst.a = src.a
+ * Note: Before API 23, the alpha channel was not correctly set.
+ * Please use with caution when targeting older APIs.
*
* @param ain The source buffer
* @param aout The destination buffer
@@ -371,6 +373,8 @@
/**
* dst = dst.rgb * src.a + (1.0 - dst.a) * src.rgb
* dst.a = src.a
+ * Note: Before API 23, the alpha channel was not correctly set.
+ * Please use with caution when targeting older APIs.
*
* @param ain The source buffer
* @param aout The destination buffer
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index a270974..cb294fd 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -534,9 +534,10 @@
account.type);
throw new SecurityException(msg);
}
- UserAccounts accounts = getUserAccountsForCaller();
+ int userId = UserHandle.getCallingUserId();
long identityToken = clearCallingIdentity();
try {
+ UserAccounts accounts = getUserAccounts(userId);
return readPasswordInternal(accounts, account);
} finally {
restoreCallingIdentity(identityToken);
@@ -572,9 +573,10 @@
+ ", pid " + Binder.getCallingPid());
}
if (account == null) throw new IllegalArgumentException("account is null");
- UserAccounts accounts = getUserAccountsForCaller();
+ int userId = UserHandle.getCallingUserId();
long identityToken = clearCallingIdentity();
try {
+ UserAccounts accounts = getUserAccounts(userId);
return readPreviousNameInternal(accounts, account);
} finally {
restoreCallingIdentity(identityToken);
@@ -632,9 +634,10 @@
account.type);
throw new SecurityException(msg);
}
- UserAccounts accounts = getUserAccountsForCaller();
+ int userId = UserHandle.getCallingUserId();
long identityToken = clearCallingIdentity();
try {
+ UserAccounts accounts = getUserAccounts(userId);
return readUserDataInternal(accounts, account, key);
} finally {
restoreCallingIdentity(identityToken);
@@ -709,11 +712,12 @@
* a limited user.
*/
- UserAccounts accounts = getUserAccountsForCaller();
// fails if the account already exists
int uid = getCallingUid();
+ int userId = UserHandle.getCallingUserId();
long identityToken = clearCallingIdentity();
try {
+ UserAccounts accounts = getUserAccounts(userId);
return addAccountInternal(accounts, account, password, extras, false, uid);
} finally {
restoreCallingIdentity(identityToken);
@@ -801,6 +805,13 @@
if (!canUserModifyAccounts(userId) || !canUserModifyAccountsForType(userId, account.type)) {
return false;
}
+ int user = UserHandle.getCallingUserId();
+ long identityToken = clearCallingIdentity();
+ try {
+ UserAccounts accounts = getUserAccounts(user);
+ } finally {
+ restoreCallingIdentity(identityToken);
+ }
return updateLastAuthenticatedTime(account);
}
@@ -975,9 +986,10 @@
if (account == null) throw new IllegalArgumentException("account is null");
if (features == null) throw new IllegalArgumentException("features is null");
checkReadAccountsPermitted(callingUid, account.type);
- UserAccounts accounts = getUserAccountsForCaller();
+ int userId = UserHandle.getCallingUserId();
long identityToken = clearCallingIdentity();
try {
+ UserAccounts accounts = getUserAccounts(userId);
new TestFeaturesSession(accounts, response, account, features).bind();
} finally {
restoreCallingIdentity(identityToken);
@@ -1057,9 +1069,10 @@
accountToRename.type);
throw new SecurityException(msg);
}
- UserAccounts accounts = getUserAccountsForCaller();
+ int userId = UserHandle.getCallingUserId();
long identityToken = clearCallingIdentity();
try {
+ UserAccounts accounts = getUserAccounts(userId);
Account resultingAccount = renameAccountInternal(accounts, accountToRename, newName);
Bundle result = new Bundle();
result.putString(AccountManager.KEY_ACCOUNT_NAME, resultingAccount.name);
@@ -1206,7 +1219,6 @@
throw new SecurityException(msg);
}
- UserAccounts accounts = getUserAccounts(userId);
if (!canUserModifyAccounts(userId)) {
try {
response.onError(AccountManager.ERROR_CODE_USER_RESTRICTED,
@@ -1227,6 +1239,7 @@
UserHandle user = new UserHandle(userId);
long identityToken = clearCallingIdentity();
+ UserAccounts accounts = getUserAccounts(userId);
cancelNotification(getSigninRequiredNotificationId(accounts, account), user);
synchronized(accounts.credentialsPermissionNotificationIds) {
for (Pair<Pair<Account, String>, Integer> pair:
@@ -1381,9 +1394,10 @@
}
if (accountType == null) throw new IllegalArgumentException("accountType is null");
if (authToken == null) throw new IllegalArgumentException("authToken is null");
- UserAccounts accounts = getUserAccountsForCaller();
+ int userId = UserHandle.getCallingUserId();
long identityToken = clearCallingIdentity();
try {
+ UserAccounts accounts = getUserAccounts(userId);
synchronized (accounts.cacheLock) {
final SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
db.beginTransaction();
@@ -1517,9 +1531,10 @@
account.type);
throw new SecurityException(msg);
}
- UserAccounts accounts = getUserAccountsForCaller();
+ int userId = UserHandle.getCallingUserId();
long identityToken = clearCallingIdentity();
try {
+ UserAccounts accounts = getUserAccounts(userId);
return readAuthTokenInternal(accounts, account, authTokenType);
} finally {
restoreCallingIdentity(identityToken);
@@ -1544,9 +1559,10 @@
account.type);
throw new SecurityException(msg);
}
- UserAccounts accounts = getUserAccountsForCaller();
+ int userId = UserHandle.getCallingUserId();
long identityToken = clearCallingIdentity();
try {
+ UserAccounts accounts = getUserAccounts(userId);
saveAuthTokenToDatabase(accounts, account, authTokenType, authToken);
} finally {
restoreCallingIdentity(identityToken);
@@ -1569,9 +1585,10 @@
account.type);
throw new SecurityException(msg);
}
- UserAccounts accounts = getUserAccountsForCaller();
+ int userId = UserHandle.getCallingUserId();
long identityToken = clearCallingIdentity();
try {
+ UserAccounts accounts = getUserAccounts(userId);
setPasswordInternal(accounts, account, password, callingUid);
} finally {
restoreCallingIdentity(identityToken);
@@ -1632,9 +1649,10 @@
account.type);
throw new SecurityException(msg);
}
- UserAccounts accounts = getUserAccountsForCaller();
+ int userId = UserHandle.getCallingUserId();
long identityToken = clearCallingIdentity();
try {
+ UserAccounts accounts = getUserAccounts(userId);
setPasswordInternal(accounts, account, null, callingUid);
} finally {
restoreCallingIdentity(identityToken);
@@ -1659,9 +1677,10 @@
account.type);
throw new SecurityException(msg);
}
- UserAccounts accounts = getUserAccountsForCaller();
+ int userId = UserHandle.getCallingUserId();
long identityToken = clearCallingIdentity();
try {
+ UserAccounts accounts = getUserAccounts(userId);
setUserdataInternal(accounts, account, key, value);
} finally {
restoreCallingIdentity(identityToken);
@@ -1734,9 +1753,10 @@
if (callingUid != Process.SYSTEM_UID) {
throw new SecurityException("can only call from system");
}
- UserAccounts accounts = getUserAccounts(UserHandle.getUserId(callingUid));
+ int userId = UserHandle.getUserId(callingUid);
long identityToken = clearCallingIdentity();
try {
+ UserAccounts accounts = getUserAccounts(userId);
new Session(accounts, response, accountType, false /* expectActivityLaunch */,
false /* stripAuthTokenFromResult */, null /* accountName */,
false /* authDetailsRequired */) {
@@ -1803,11 +1823,17 @@
Slog.w(TAG, "Failed to report error back to the client." + e);
return;
}
-
- final UserAccounts accounts = getUserAccountsForCaller();
+ int userId = UserHandle.getCallingUserId();
+ long ident = Binder.clearCallingIdentity();
+ final UserAccounts accounts;
final RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> authenticatorInfo;
- authenticatorInfo = mAuthenticatorCache.getServiceInfo(
- AuthenticatorDescription.newKey(account.type), accounts.userId);
+ try {
+ accounts = getUserAccounts(userId);
+ authenticatorInfo = mAuthenticatorCache.getServiceInfo(
+ AuthenticatorDescription.newKey(account.type), accounts.userId);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
final boolean customTokens =
authenticatorInfo != null && authenticatorInfo.type.customTokens;
@@ -1820,7 +1846,7 @@
// Get the calling package. We will use it for the purpose of caching.
final String callerPkg = loginOptions.getString(AccountManager.KEY_ANDROID_PACKAGE_NAME);
List<String> callerOwnedPackageNames;
- long ident = Binder.clearCallingIdentity();
+ ident = Binder.clearCallingIdentity();
try {
callerOwnedPackageNames = Arrays.asList(mPackageManager.getPackagesForUid(callerUid));
} finally {
@@ -2108,17 +2134,18 @@
return;
}
- UserAccounts accounts = getUserAccountsForCaller();
final int pid = Binder.getCallingPid();
final int uid = Binder.getCallingUid();
final Bundle options = (optionsIn == null) ? new Bundle() : optionsIn;
options.putInt(AccountManager.KEY_CALLER_UID, uid);
options.putInt(AccountManager.KEY_CALLER_PID, pid);
- logRecord(accounts, DebugDbHelper.ACTION_CALLED_ACCOUNT_ADD, TABLE_ACCOUNTS);
-
+ int usrId = UserHandle.getCallingUserId();
long identityToken = clearCallingIdentity();
try {
+ UserAccounts accounts = getUserAccounts(usrId);
+ logRecordWithUid(
+ accounts, DebugDbHelper.ACTION_CALLED_ACCOUNT_ADD, TABLE_ACCOUNTS, uid);
new Session(accounts, response, accountType, expectActivityLaunch,
true /* stripAuthTokenFromResult */, null /* accountName */,
false /* authDetailsRequired */, true /* updateLastAuthenticationTime */) {
@@ -2190,17 +2217,17 @@
return;
}
- UserAccounts accounts = getUserAccounts(userId);
final int pid = Binder.getCallingPid();
final int uid = Binder.getCallingUid();
final Bundle options = (optionsIn == null) ? new Bundle() : optionsIn;
options.putInt(AccountManager.KEY_CALLER_UID, uid);
options.putInt(AccountManager.KEY_CALLER_PID, pid);
- logRecord(accounts, DebugDbHelper.ACTION_CALLED_ACCOUNT_ADD, TABLE_ACCOUNTS);
-
long identityToken = clearCallingIdentity();
try {
+ UserAccounts accounts = getUserAccounts(userId);
+ logRecordWithUid(
+ accounts, DebugDbHelper.ACTION_CALLED_ACCOUNT_ADD, TABLE_ACCOUNTS, userId);
new Session(accounts, response, accountType, expectActivityLaunch,
true /* stripAuthTokenFromResult */, null /* accountName */,
false /* authDetailsRequired */, true /* updateLastAuthenticationTime */) {
@@ -2262,9 +2289,9 @@
}
if (response == null) throw new IllegalArgumentException("response is null");
if (account == null) throw new IllegalArgumentException("account is null");
- UserAccounts accounts = getUserAccounts(userId);
long identityToken = clearCallingIdentity();
try {
+ UserAccounts accounts = getUserAccounts(userId);
new Session(accounts, response, account.type, expectActivityLaunch,
true /* stripAuthTokenFromResult */, account.name,
true /* authDetailsRequired */, true /* updateLastAuthenticatedTime */) {
@@ -2298,9 +2325,10 @@
if (response == null) throw new IllegalArgumentException("response is null");
if (account == null) throw new IllegalArgumentException("account is null");
if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
- UserAccounts accounts = getUserAccountsForCaller();
+ int userId = UserHandle.getCallingUserId();
long identityToken = clearCallingIdentity();
try {
+ UserAccounts accounts = getUserAccounts(userId);
new Session(accounts, response, account.type, expectActivityLaunch,
true /* stripAuthTokenFromResult */, account.name,
false /* authDetailsRequired */, true /* updateLastCredentialTime */) {
@@ -2342,9 +2370,10 @@
accountType);
throw new SecurityException(msg);
}
- UserAccounts accounts = getUserAccountsForCaller();
+ int userId = UserHandle.getCallingUserId();
long identityToken = clearCallingIdentity();
try {
+ UserAccounts accounts = getUserAccounts(userId);
new Session(accounts, response, accountType, expectActivityLaunch,
true /* stripAuthTokenFromResult */, null /* accountName */,
false /* authDetailsRequired */) {
@@ -2468,13 +2497,13 @@
* @hide
*/
public Account[] getAccounts(int userId) {
- UserAccounts accounts = getUserAccounts(userId);
int callingUid = Binder.getCallingUid();
if (!isReadAccountsPermitted(callingUid, null)) {
return new Account[0];
}
long identityToken = clearCallingIdentity();
try {
+ UserAccounts accounts = getUserAccounts(userId);
synchronized (accounts.cacheLock) {
return getAccountsFromCacheLocked(accounts, null, callingUid, null);
}
@@ -2720,9 +2749,10 @@
}
return;
}
- UserAccounts userAccounts = getUserAccountsForCaller();
+ int userId = UserHandle.getCallingUserId();
long identityToken = clearCallingIdentity();
try {
+ UserAccounts userAccounts = getUserAccounts(userId);
if (features == null || features.length == 0) {
Account[] accounts;
synchronized (userAccounts.cacheLock) {
@@ -3227,6 +3257,11 @@
logRecord(db, action, tableName, -1, accounts);
}
+ private void logRecordWithUid(UserAccounts accounts, String action, String tableName, int uid) {
+ SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
+ logRecord(db, action, tableName, -1, accounts, uid);
+ }
+
/*
* This function receives an opened writable database.
*/
diff --git a/services/core/java/com/android/server/am/RecentTasks.java b/services/core/java/com/android/server/am/RecentTasks.java
index 9f11def..6ee1650 100644
--- a/services/core/java/com/android/server/am/RecentTasks.java
+++ b/services/core/java/com/android/server/am/RecentTasks.java
@@ -446,13 +446,23 @@
if (i > MAX_RECENT_BITMAPS) {
tr.freeLastThumbnail();
}
- if (task.realActivity == null || tr.realActivity == null ||
- !task.realActivity.equals(tr.realActivity)) {
+ final boolean sameAffinity =
+ task.affinity != null && task.affinity.equals(tr.affinity);
+ final boolean trIsDocument = tr.intent != null && tr.intent.isDocument();
+ final boolean bothDocuments = document && trIsDocument;
+ if (!sameAffinity && !bothDocuments) {
+ // Not the same affinity and not documents. Move along...
continue;
}
- final boolean trIsDocument = tr.intent != null && tr.intent.isDocument();
- if (document && trIsDocument) {
- // These are the same document activity (not necessarily the same doc).
+
+ if (bothDocuments) {
+ // Do these documents belong to the same activity?
+ final boolean sameActivity = task.realActivity != null
+ && tr.realActivity != null
+ && task.realActivity.equals(tr.realActivity);
+ if (!sameActivity) {
+ continue;
+ }
if (maxRecents > 0) {
--maxRecents;
continue;
diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java
index 569a0fc..f92f631 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecord.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecord.java
@@ -241,19 +241,10 @@
flags &= ~AudioManager.FLAG_PLAY_SOUND;
}
if (mVolumeType == PlaybackInfo.PLAYBACK_TYPE_LOCAL) {
- int stream = AudioAttributes.toLegacyStreamType(mAudioAttrs);
// Adjust the volume with a handler not to be blocked by other system service.
- if (useSuggested) {
- if (AudioSystem.isStreamActive(stream, 0)) {
- postAdjustSuggestedStreamVolume(stream, direction, flags, packageName, uid);
- } else {
- flags |= previousFlagPlaySound;
- postAdjustSuggestedStreamVolume(AudioManager.USE_DEFAULT_STREAM_TYPE, direction,
- flags, packageName, uid);
- }
- } else {
- postAdjustStreamVolume(stream, direction, flags, packageName, uid);
- }
+ int stream = AudioAttributes.toLegacyStreamType(mAudioAttrs);
+ postAdjustLocalVolume(stream, direction, flags, packageName, uid, useSuggested,
+ previousFlagPlaySound);
} else {
if (mVolumeControlType == VolumeProvider.VOLUME_CONTROL_FIXED) {
// Nothing to do, the volume cannot be changed
@@ -459,24 +450,25 @@
return mPackageName + "/" + mTag;
}
- private void postAdjustSuggestedStreamVolume(final int streamType, final int direction,
- final int flags, final String callingPackage, final int uid) {
+ private void postAdjustLocalVolume(final int stream, final int direction, final int flags,
+ final String packageName, final int uid, final boolean useSuggested,
+ final int previousFlagPlaySound) {
mHandler.post(new Runnable() {
@Override
public void run() {
- mAudioManagerInternal.adjustSuggestedStreamVolumeForUid(streamType, direction,
- flags, callingPackage, uid);
- }
- });
- }
-
- private void postAdjustStreamVolume(final int streamType, final int direction, final int flags,
- final String callingPackage, final int uid) {
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- mAudioManagerInternal.adjustStreamVolumeForUid(streamType, direction, flags,
- callingPackage, uid);
+ if (useSuggested) {
+ if (AudioSystem.isStreamActive(stream, 0)) {
+ mAudioManagerInternal.adjustSuggestedStreamVolumeForUid(stream, direction,
+ flags, packageName, uid);
+ } else {
+ mAudioManagerInternal.adjustSuggestedStreamVolumeForUid(
+ AudioManager.USE_DEFAULT_STREAM_TYPE, direction,
+ flags | previousFlagPlaySound, packageName, uid);
+ }
+ } else {
+ mAudioManagerInternal.adjustStreamVolumeForUid(stream, direction, flags,
+ packageName, uid);
+ }
}
});
}
@@ -1067,23 +1059,22 @@
@Override
public ParcelableVolumeInfo getVolumeAttributes() {
+ int volumeType;
+ AudioAttributes attributes;
synchronized (mLock) {
- int type;
- int max;
- int current;
if (mVolumeType == PlaybackInfo.PLAYBACK_TYPE_REMOTE) {
- type = mVolumeControlType;
- max = mMaxVolume;
- current = mOptimisticVolume != -1 ? mOptimisticVolume
- : mCurrentVolume;
- } else {
- int stream = AudioAttributes.toLegacyStreamType(mAudioAttrs);
- type = VolumeProvider.VOLUME_CONTROL_ABSOLUTE;
- max = mAudioManager.getStreamMaxVolume(stream);
- current = mAudioManager.getStreamVolume(stream);
+ int current = mOptimisticVolume != -1 ? mOptimisticVolume : mCurrentVolume;
+ return new ParcelableVolumeInfo(
+ mVolumeType, mAudioAttrs, mVolumeControlType, mMaxVolume, current);
}
- return new ParcelableVolumeInfo(mVolumeType, mAudioAttrs, type, max, current);
+ volumeType = mVolumeType;
+ attributes = mAudioAttrs;
}
+ int stream = AudioAttributes.toLegacyStreamType(attributes);
+ int max = mAudioManager.getStreamMaxVolume(stream);
+ int current = mAudioManager.getStreamVolume(stream);
+ return new ParcelableVolumeInfo(
+ volumeType, attributes, VolumeProvider.VOLUME_CONTROL_ABSOLUTE, max, current);
}
@Override
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index c763315..c139389 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -12275,6 +12275,20 @@
// We did an in-place move, so dex is ready to roll
scanFlags |= SCAN_NO_DEX;
scanFlags |= SCAN_MOVE;
+
+ synchronized (mPackages) {
+ final PackageSetting ps = mSettings.mPackages.get(pkgName);
+ if (ps == null) {
+ res.setError(INSTALL_FAILED_INTERNAL_ERROR,
+ "Missing settings for moved package " + pkgName);
+ }
+
+ // We moved the entire application as-is, so bring over the
+ // previously derived ABI information.
+ pkg.applicationInfo.primaryCpuAbi = ps.primaryCpuAbiString;
+ pkg.applicationInfo.secondaryCpuAbi = ps.secondaryCpuAbiString;
+ }
+
} else if (!forwardLocked && !pkg.applicationInfo.isExternalAsec()) {
// Enable SCAN_NO_DEX flag to skip dexopt at a later stage
scanFlags |= SCAN_NO_DEX;
diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java
index 51df31f..a5344b4 100644
--- a/services/core/java/com/android/server/tv/TvInputManagerService.java
+++ b/services/core/java/com/android/server/tv/TvInputManagerService.java
@@ -133,7 +133,7 @@
mTvInputHardwareManager = new TvInputHardwareManager(context, new HardwareListener());
synchronized (mLock) {
- mUserStates.put(mCurrentUserId, new UserState(mContext, mCurrentUserId));
+ getOrCreateUserStateLocked(mCurrentUserId);
}
}
@@ -222,7 +222,7 @@
@Override
public void onPackageRemoved(String packageName, int uid) {
synchronized (mLock) {
- UserState userState = getUserStateLocked(getChangingUserId());
+ UserState userState = getOrCreateUserStateLocked(getChangingUserId());
if (!userState.packageSet.contains(packageName)) {
// Not a TV input package.
return;
@@ -281,7 +281,7 @@
}
private void buildTvInputListLocked(int userId, String[] updatedPackages) {
- UserState userState = getUserStateLocked(userId);
+ UserState userState = getOrCreateUserStateLocked(userId);
userState.packageSet.clear();
if (DEBUG) Slog.d(TAG, "buildTvInputList");
@@ -368,7 +368,7 @@
}
private void buildTvContentRatingSystemListLocked(int userId) {
- UserState userState = getUserStateLocked(userId);
+ UserState userState = getOrCreateUserStateLocked(userId);
userState.contentRatingSystemList.clear();
final PackageManager pm = mContext.getPackageManager();
@@ -402,11 +402,7 @@
clearSessionAndServiceStatesLocked(mUserStates.get(mCurrentUserId));
mCurrentUserId = userId;
- UserState userState = mUserStates.get(userId);
- if (userState == null) {
- userState = new UserState(mContext, userId);
- mUserStates.put(userId, userState);
- }
+ getOrCreateUserStateLocked(userId);
buildTvInputListLocked(userId, null);
buildTvContentRatingSystemListLocked(userId);
mWatchLogHandler.obtainMessage(WatchLogHandler.MSG_SWITCH_CONTENT_RESOLVER,
@@ -473,16 +469,17 @@
return context.getContentResolver();
}
- private UserState getUserStateLocked(int userId) {
+ private UserState getOrCreateUserStateLocked(int userId) {
UserState userState = mUserStates.get(userId);
if (userState == null) {
- throw new IllegalStateException("User state not found for user ID " + userId);
+ userState = new UserState(mContext, userId);
+ mUserStates.put(userId, userState);
}
return userState;
}
private ServiceState getServiceStateLocked(ComponentName component, int userId) {
- UserState userState = getUserStateLocked(userId);
+ UserState userState = getOrCreateUserStateLocked(userId);
ServiceState serviceState = userState.serviceStateMap.get(component);
if (serviceState == null) {
throw new IllegalStateException("Service state not found for " + component + " (userId="
@@ -492,7 +489,7 @@
}
private SessionState getSessionStateLocked(IBinder sessionToken, int callingUid, int userId) {
- UserState userState = getUserStateLocked(userId);
+ UserState userState = getOrCreateUserStateLocked(userId);
SessionState sessionState = userState.sessionStateMap.get(sessionToken);
if (sessionState == null) {
throw new SessionNotFoundException("Session state not found for token " + sessionToken);
@@ -530,7 +527,7 @@
}
private void updateServiceConnectionLocked(ComponentName component, int userId) {
- UserState userState = getUserStateLocked(userId);
+ UserState userState = getOrCreateUserStateLocked(userId);
ServiceState serviceState = userState.serviceStateMap.get(component);
if (serviceState == null) {
return;
@@ -574,7 +571,7 @@
private void abortPendingCreateSessionRequestsLocked(ServiceState serviceState,
String inputId, int userId) {
// Let clients know the create session requests are failed.
- UserState userState = getUserStateLocked(userId);
+ UserState userState = getOrCreateUserStateLocked(userId);
List<SessionState> sessionsToAbort = new ArrayList<>();
for (IBinder sessionToken : serviceState.sessionTokens) {
SessionState sessionState = userState.sessionStateMap.get(sessionToken);
@@ -593,7 +590,7 @@
private void createSessionInternalLocked(ITvInputService service, IBinder sessionToken,
int userId) {
- UserState userState = getUserStateLocked(userId);
+ UserState userState = getOrCreateUserStateLocked(userId);
SessionState sessionState = userState.sessionStateMap.get(sessionToken);
if (DEBUG) {
Slog.d(TAG, "createSessionInternalLocked(inputId=" + sessionState.info.getId() + ")");
@@ -629,7 +626,7 @@
try {
sessionState = getSessionStateLocked(sessionToken, callingUid, userId);
if (sessionState.session != null) {
- UserState userState = getUserStateLocked(userId);
+ UserState userState = getOrCreateUserStateLocked(userId);
if (sessionToken == userState.mainSessionToken) {
setMainLocked(sessionToken, false, callingUid, userId);
}
@@ -646,7 +643,7 @@
}
private void removeSessionStateLocked(IBinder sessionToken, int userId) {
- UserState userState = getUserStateLocked(userId);
+ UserState userState = getOrCreateUserStateLocked(userId);
if (sessionToken == userState.mainSessionToken) {
if (DEBUG) {
Slog.d(TAG, "mainSessionToken=null");
@@ -768,7 +765,7 @@
}
private void setStateLocked(String inputId, int state, int userId) {
- UserState userState = getUserStateLocked(userId);
+ UserState userState = getOrCreateUserStateLocked(userId);
TvInputState inputState = userState.inputMap.get(inputId);
ServiceState serviceState = userState.serviceStateMap.get(inputState.info.getComponent());
int oldState = inputState.state;
@@ -791,7 +788,7 @@
final long identity = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
- UserState userState = getUserStateLocked(resolvedUserId);
+ UserState userState = getOrCreateUserStateLocked(resolvedUserId);
List<TvInputInfo> inputList = new ArrayList<>();
for (TvInputState state : userState.inputMap.values()) {
inputList.add(state.info);
@@ -810,7 +807,7 @@
final long identity = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
- UserState userState = getUserStateLocked(resolvedUserId);
+ UserState userState = getOrCreateUserStateLocked(resolvedUserId);
TvInputState state = userState.inputMap.get(inputId);
return state == null ? null : state.info;
}
@@ -826,7 +823,7 @@
final long identity = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
- UserState userState = getUserStateLocked(resolvedUserId);
+ UserState userState = getOrCreateUserStateLocked(resolvedUserId);
TvInputState state = userState.inputMap.get(inputId);
return state == null ? INPUT_STATE_CONNECTED : state.state;
}
@@ -842,7 +839,7 @@
final long identity = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
- UserState userState = getUserStateLocked(resolvedUserId);
+ UserState userState = getOrCreateUserStateLocked(resolvedUserId);
return userState.contentRatingSystemList;
}
} finally {
@@ -857,7 +854,7 @@
final long identity = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
- final UserState userState = getUserStateLocked(resolvedUserId);
+ final UserState userState = getOrCreateUserStateLocked(resolvedUserId);
userState.callbackSet.add(callback);
try {
callback.asBinder().linkToDeath(new IBinder.DeathRecipient() {
@@ -886,7 +883,7 @@
final long identity = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
- UserState userState = getUserStateLocked(resolvedUserId);
+ UserState userState = getOrCreateUserStateLocked(resolvedUserId);
userState.callbackSet.remove(callback);
}
} finally {
@@ -901,7 +898,7 @@
final long identity = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
- UserState userState = getUserStateLocked(resolvedUserId);
+ UserState userState = getOrCreateUserStateLocked(resolvedUserId);
return userState.persistentDataStore.isParentalControlsEnabled();
}
} finally {
@@ -917,7 +914,7 @@
final long identity = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
- UserState userState = getUserStateLocked(resolvedUserId);
+ UserState userState = getOrCreateUserStateLocked(resolvedUserId);
userState.persistentDataStore.setParentalControlsEnabled(enabled);
}
} finally {
@@ -932,7 +929,7 @@
final long identity = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
- UserState userState = getUserStateLocked(resolvedUserId);
+ UserState userState = getOrCreateUserStateLocked(resolvedUserId);
return userState.persistentDataStore.isRatingBlocked(
TvContentRating.unflattenFromString(rating));
}
@@ -948,7 +945,7 @@
final long identity = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
- UserState userState = getUserStateLocked(resolvedUserId);
+ UserState userState = getOrCreateUserStateLocked(resolvedUserId);
List<String> ratings = new ArrayList<>();
for (TvContentRating rating
: userState.persistentDataStore.getBlockedRatings()) {
@@ -969,7 +966,7 @@
final long identity = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
- UserState userState = getUserStateLocked(resolvedUserId);
+ UserState userState = getOrCreateUserStateLocked(resolvedUserId);
userState.persistentDataStore.addBlockedRating(
TvContentRating.unflattenFromString(rating));
}
@@ -986,7 +983,7 @@
final long identity = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
- UserState userState = getUserStateLocked(resolvedUserId);
+ UserState userState = getOrCreateUserStateLocked(resolvedUserId);
userState.persistentDataStore.removeBlockedRating(
TvContentRating.unflattenFromString(rating));
}
@@ -1013,7 +1010,7 @@
final long identity = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
- UserState userState = getUserStateLocked(resolvedUserId);
+ UserState userState = getOrCreateUserStateLocked(resolvedUserId);
TvInputState inputState = userState.inputMap.get(inputId);
if (inputState == null) {
Slog.w(TAG, "Failed to find input state for inputId=" + inputId);
@@ -1084,7 +1081,7 @@
final long identity = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
- UserState userState = getUserStateLocked(resolvedUserId);
+ UserState userState = getOrCreateUserStateLocked(resolvedUserId);
if (userState.mainSessionToken == sessionToken) {
return;
}
@@ -1211,7 +1208,7 @@
return;
}
- UserState userState = getUserStateLocked(resolvedUserId);
+ UserState userState = getOrCreateUserStateLocked(resolvedUserId);
SessionState sessionState = userState.sessionStateMap.get(sessionToken);
// Log the start of watch.
@@ -1639,7 +1636,7 @@
try {
String hardwareInputId = null;
synchronized (mLock) {
- UserState userState = getUserStateLocked(resolvedUserId);
+ UserState userState = getOrCreateUserStateLocked(resolvedUserId);
if (userState.inputMap.get(inputId) == null) {
Slog.e(TAG, "input not found for " + inputId);
return false;
@@ -1669,7 +1666,7 @@
userId, "isSingleSessionActive");
try {
synchronized (mLock) {
- UserState userState = getUserStateLocked(resolvedUserId);
+ UserState userState = getOrCreateUserStateLocked(resolvedUserId);
if (userState.sessionStateMap.size() == 1) {
return true;
} else if (userState.sessionStateMap.size() == 2) {
@@ -1710,7 +1707,7 @@
for (int i = 0; i < mUserStates.size(); i++) {
int userId = mUserStates.keyAt(i);
- UserState userState = getUserStateLocked(userId);
+ UserState userState = getOrCreateUserStateLocked(userId);
pw.println("UserState (" + userId + "):");
pw.increaseIndent();
@@ -1864,7 +1861,7 @@
@Override
public void binderDied() {
synchronized (mLock) {
- UserState userState = getUserStateLocked(userId);
+ UserState userState = getOrCreateUserStateLocked(userId);
// DO NOT remove the client state of clientStateMap in this method. It will be
// removed in releaseSessionLocked().
ClientState clientState = userState.clientStateMap.get(clientToken);
@@ -1945,7 +1942,7 @@
}
}
// If there are any other sessions based on this session, they should be released.
- UserState userState = getUserStateLocked(userId);
+ UserState userState = getOrCreateUserStateLocked(userId);
for (SessionState sessionState : userState.sessionStateMap.values()) {
if (sessionToken == sessionState.hardwareSessionToken) {
releaseSessionLocked(sessionState.sessionToken, Process.SYSTEM_UID,
@@ -1977,7 +1974,7 @@
Slog.d(TAG, "onServiceConnected(component=" + component + ")");
}
synchronized (mLock) {
- UserState userState = getUserStateLocked(mUserId);
+ UserState userState = getOrCreateUserStateLocked(mUserId);
ServiceState serviceState = userState.serviceStateMap.get(mComponent);
serviceState.service = ITvInputService.Stub.asInterface(service);
@@ -2038,7 +2035,7 @@
+ mComponent + " (expected), " + component + " (actual).");
}
synchronized (mLock) {
- UserState userState = getUserStateLocked(mUserId);
+ UserState userState = getOrCreateUserStateLocked(mUserId);
ServiceState serviceState = userState.serviceStateMap.get(mComponent);
if (serviceState != null) {
serviceState.reconnecting = true;
@@ -2163,7 +2160,7 @@
}
IBinder clientToken = mSessionState.client.asBinder();
- UserState userState = getUserStateLocked(mSessionState.userId);
+ UserState userState = getOrCreateUserStateLocked(mSessionState.userId);
ClientState clientState = userState.clientStateMap.get(clientToken);
if (clientState == null) {
clientState = new ClientState(clientToken, mSessionState.userId);
@@ -2509,7 +2506,7 @@
@Override
public void onHardwareDeviceAdded(TvInputHardwareInfo info) {
synchronized (mLock) {
- UserState userState = getUserStateLocked(mCurrentUserId);
+ UserState userState = getOrCreateUserStateLocked(mCurrentUserId);
// Broadcast the event to all hardware inputs.
for (ServiceState serviceState : userState.serviceStateMap.values()) {
if (!serviceState.isHardware || serviceState.service == null) continue;
@@ -2525,7 +2522,7 @@
@Override
public void onHardwareDeviceRemoved(TvInputHardwareInfo info) {
synchronized (mLock) {
- UserState userState = getUserStateLocked(mCurrentUserId);
+ UserState userState = getOrCreateUserStateLocked(mCurrentUserId);
// Broadcast the event to all hardware inputs.
for (ServiceState serviceState : userState.serviceStateMap.values()) {
if (!serviceState.isHardware || serviceState.service == null) continue;
@@ -2541,7 +2538,7 @@
@Override
public void onHdmiDeviceAdded(HdmiDeviceInfo deviceInfo) {
synchronized (mLock) {
- UserState userState = getUserStateLocked(mCurrentUserId);
+ UserState userState = getOrCreateUserStateLocked(mCurrentUserId);
// Broadcast the event to all hardware inputs.
for (ServiceState serviceState : userState.serviceStateMap.values()) {
if (!serviceState.isHardware || serviceState.service == null) continue;
@@ -2557,7 +2554,7 @@
@Override
public void onHdmiDeviceRemoved(HdmiDeviceInfo deviceInfo) {
synchronized (mLock) {
- UserState userState = getUserStateLocked(mCurrentUserId);
+ UserState userState = getOrCreateUserStateLocked(mCurrentUserId);
// Broadcast the event to all hardware inputs.
for (ServiceState serviceState : userState.serviceStateMap.values()) {
if (!serviceState.isHardware || serviceState.service == null) continue;
diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java
index 7630178..85a9624 100644
--- a/services/core/java/com/android/server/wm/WindowAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowAnimator.java
@@ -500,7 +500,13 @@
mPostKeyguardExitAnimation.getStartOffset(),
mPostKeyguardExitAnimation.getDuration());
mKeyguardGoingAway = false;
- } else if (mPostKeyguardExitAnimation.hasEnded()) {
+ }
+ // mPostKeyguardExitAnimation might either be ended normally, cancelled, or "orphaned",
+ // meaning that the window it was running on was removed. We check for hasEnded() for
+ // ended normally and cancelled case, and check the time for the "orphaned" case.
+ else if (mPostKeyguardExitAnimation.hasEnded()
+ || mCurrentTime - mPostKeyguardExitAnimation.getStartTime()
+ > mPostKeyguardExitAnimation.getDuration()) {
// Done with the animation, reset.
if (DEBUG_KEYGUARD) Slog.v(TAG, "Done with Keyguard exit animations.");
mPostKeyguardExitAnimation = null;
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index 653cbd8..1787b91 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -122,6 +122,8 @@
// Request is cancelled if host does not configure device within 10 seconds.
private static final int ACCESSORY_REQUEST_TIMEOUT = 10 * 1000;
+ private static final String BOOT_MODE_PROPERTY = "ro.bootmode";
+
private UsbHandler mHandler;
private boolean mBootCompleted;
@@ -468,6 +470,7 @@
functions = getDefaultFunctions();
}
functions = applyAdbFunction(functions);
+ functions = applyOemOverrideFunction(functions);
functions = applyUserRestrictions(functions);
if (!mCurrentFunctions.equals(functions) || !mCurrentFunctionsApplied
@@ -888,6 +891,24 @@
}
}
+ private String applyOemOverrideFunction(String usbFunctions) {
+ if ((usbFunctions == null) || (mOemModeMap == null)) return usbFunctions;
+
+ String bootMode = SystemProperties.get(BOOT_MODE_PROPERTY, "unknown");
+
+ List<Pair<String, String>> overrides = mOemModeMap.get(bootMode);
+ if (overrides != null) {
+ for (Pair<String, String> pair: overrides) {
+ if (pair.first.equals(usbFunctions)) {
+ Slog.d(TAG, "OEM USB override: " + pair.first + " ==> " + pair.second);
+ return pair.second;
+ }
+ }
+ }
+ // return passed in functions as is.
+ return usbFunctions;
+ }
+
public void allowUsbDebugging(boolean alwaysAllow, String publicKey) {
if (mDebuggingManager != null) {
mDebuggingManager.allowUsbDebugging(alwaysAllow, publicKey);
diff --git a/tests/AccessibilityEventsLogger/Android.mk b/tests/AccessibilityEventsLogger/Android.mk
new file mode 100644
index 0000000..52bc579
--- /dev/null
+++ b/tests/AccessibilityEventsLogger/Android.mk
@@ -0,0 +1,13 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_PACKAGE_NAME := AccessibilityEventsLogger
+LOCAL_CERTIFICATE := platform
+
+LOCAL_PROGUARD_ENABLED := disabled
+
+include $(BUILD_PACKAGE)
diff --git a/tests/AccessibilityEventsLogger/AndroidManifest.xml b/tests/AccessibilityEventsLogger/AndroidManifest.xml
new file mode 100644
index 0000000..d86769f
--- /dev/null
+++ b/tests/AccessibilityEventsLogger/AndroidManifest.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2015 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ package="com.android.tests.accessibilityeventlogger"
+ android:versionCode="1"
+ android:versionName="0.0" >
+
+ <uses-sdk
+ android:minSdkVersion="18"
+ android:targetSdkVersion="18" />
+
+ <application
+ android:allowBackup="true"
+ android:enabled="true"
+ android:label="@string/app_name" >
+
+ <service
+ android:name=".AELogger"
+ android:enabled="true"
+ android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"
+ android:configChanges="locale" >
+ <intent-filter>
+ <action android:name="android.accessibilityservice.AccessibilityService"/>
+
+ <category android:name="android.accessibilityservice.category.FEEDBACK_GENERIC"/>
+ <category android:name="android.accessibilityservice.category.FEEDBACK_VISUAL"/>
+ <category android:name="android.accessibilityservice.category.FEEDBACK_AUDIBLE"/>
+ </intent-filter>
+
+ <meta-data
+ android:name="android.accessibilityservice"
+ android:resource="@xml/accessibilityservice" />
+ </service>
+ </application>
+</manifest>
diff --git a/tests/AccessibilityEventsLogger/res/values/strings.xml b/tests/AccessibilityEventsLogger/res/values/strings.xml
new file mode 100644
index 0000000..353f912
--- /dev/null
+++ b/tests/AccessibilityEventsLogger/res/values/strings.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2015 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.
+-->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- CHAR LIMIT=none -->
+ <string name="app_name">
+ Accessibility Event Logger
+ </string>
+
+ <!-- CHAR LIMIT=none -->
+ <string name="service_description">
+ Debugging service
+ </string>
+</resources>
diff --git a/tests/AccessibilityEventsLogger/res/xml/accessibilityservice.xml b/tests/AccessibilityEventsLogger/res/xml/accessibilityservice.xml
new file mode 100644
index 0000000..69ecd61
--- /dev/null
+++ b/tests/AccessibilityEventsLogger/res/xml/accessibilityservice.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2015 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.
+-->
+
+<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
+ android:accessibilityEventTypes="typeAllMask"
+ android:accessibilityFeedbackType="feedbackGeneric|feedbackVisual|feedbackAudible"
+ android:canRetrieveWindowContent="true"
+ android:accessibilityFlags="flagDefault"
+ android:description="@string/service_description"
+ android:notificationTimeout="0" />
diff --git a/tests/AccessibilityEventsLogger/src/com/android/tests/accessibilityeventslogger/AELogger.java b/tests/AccessibilityEventsLogger/src/com/android/tests/accessibilityeventslogger/AELogger.java
new file mode 100644
index 0000000..27d8eb9
--- /dev/null
+++ b/tests/AccessibilityEventsLogger/src/com/android/tests/accessibilityeventslogger/AELogger.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2015 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 com.android.tests.accessibilityeventslogger;
+
+import android.accessibilityservice.AccessibilityService;
+import android.accessibilityservice.AccessibilityServiceInfo;
+import android.util.Log;
+import android.view.accessibility.AccessibilityEvent;
+import android.widget.Toast;
+
+import java.util.Locale;
+
+public class AELogger extends AccessibilityService {
+ private static final String TAG = AELogger.class.getCanonicalName();
+
+ private static final int TOAST_EVENT_TYPES =
+ AccessibilityEvent.TYPE_VIEW_CLICKED | AccessibilityEvent.TYPE_VIEW_LONG_CLICKED;
+
+ @Override
+ public void onServiceConnected() {
+ super.onServiceConnected();
+ Log.v(TAG, "Service connected.");
+ }
+
+
+ @Override
+ public void onInterrupt() {
+ // Do nothing
+ }
+
+ @Override
+ public void onAccessibilityEvent(AccessibilityEvent event) {
+ final String eventClass = event.getClassName().toString();
+ final String eventText = String.valueOf(event.getText()).toLowerCase(Locale.getDefault());
+ final String eventType = AccessibilityEvent.eventTypeToString(event.getEventType());
+
+ Log.d(TAG, String.format(
+ "typ=%s cls=%s pkg=%s txt=%s dsc=%s",
+ eventType,
+ eventClass,
+ event.getPackageName(),
+ eventText,
+ event.getContentDescription()
+ ));
+
+ // Show selected event types
+ if (0 != (TOAST_EVENT_TYPES & event.getEventType())) {
+ final Toast toast = Toast.makeText(this,
+ eventType + ": " + eventClass, Toast.LENGTH_SHORT);
+ toast.show();
+ }
+ }
+}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
index 23df3f1..6a9d5dd6 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
@@ -526,6 +526,11 @@
if (neededWidth > measuredWidth) {
mMeasuredScreenWidth += neededWidth - measuredWidth;
}
+ if (mMeasuredScreenWidth < measuredWidth) {
+ // If the screen width is less than the exact measured width,
+ // expand to match.
+ mMeasuredScreenWidth = measuredWidth;
+ }
}
if (renderingMode.isVertExpand()) {
@@ -534,6 +539,11 @@
if (neededHeight > measuredHeight) {
mMeasuredScreenHeight += neededHeight - measuredHeight;
}
+ if (mMeasuredScreenHeight < measuredHeight) {
+ // If the screen height is less than the exact measured height,
+ // expand to match.
+ mMeasuredScreenHeight = measuredHeight;
+ }
}
}
}
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$layout.class b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$layout.class
index e172b2d..6c351da 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$layout.class
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R$layout.class
Binary files differ
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R.class b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R.class
index d5b81c4..6d7c719 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R.class
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/build/intermediates/classes/debug/com/android/layoutlib/test/myapplication/R.class
Binary files differ
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/expand_horz_layout.png b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/expand_horz_layout.png
new file mode 100644
index 0000000..92eb3e1
--- /dev/null
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/expand_horz_layout.png
Binary files differ
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/expand_vert_layout.png b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/expand_vert_layout.png
new file mode 100644
index 0000000..81755ce
--- /dev/null
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/expand_vert_layout.png
Binary files differ
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/layout/expand_horz_layout.xml b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/layout/expand_horz_layout.xml
new file mode 100644
index 0000000..2c66b7f
--- /dev/null
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/layout/expand_horz_layout.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:padding="16dp"
+ android:orientation="horizontal"
+ android:background="#AAAAAA"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
+
+ <include layout="@layout/expand_layout"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content" />
+
+</LinearLayout>
+
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/layout/expand_layout.xml b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/layout/expand_layout.xml
new file mode 100644
index 0000000..a255da7
--- /dev/null
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/layout/expand_layout.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<merge xmlns:android="http://schemas.android.com/apk/res/android">
+ <TextView
+ android:background="#FF0000"
+ android:textSize="200sp"
+ android:layout_width="200dp"
+ android:layout_height="200dp" />
+ <TextView
+ android:background="#00FF00"
+ android:textSize="200sp"
+ android:layout_width="200dp"
+ android:layout_height="200dp" />
+ <TextView
+ android:background="#0000FF"
+ android:textSize="200sp"
+ android:layout_width="200dp"
+ android:layout_height="200dp" />
+ <TextView
+ android:background="#FF00FF"
+ android:textSize="200sp"
+ android:layout_width="200dp"
+ android:layout_height="200dp" />
+ <TextView
+ android:background="#00FFFF"
+ android:textSize="200sp"
+ android:layout_width="200dp"
+ android:layout_height="200dp" />
+</merge>
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/layout/expand_vert_layout.xml b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/layout/expand_vert_layout.xml
new file mode 100644
index 0000000..5319654
--- /dev/null
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/src/main/res/layout/expand_vert_layout.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:padding="16dp"
+ android:orientation="vertical"
+ android:background="#AAAAAA"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
+
+ <include layout="@layout/expand_layout"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content" />
+
+</LinearLayout>
+
diff --git a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java
index 272a2b8..b2909c9 100644
--- a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java
+++ b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java
@@ -31,6 +31,8 @@
import com.android.layoutlib.bridge.intensive.setup.ConfigGenerator;
import com.android.layoutlib.bridge.intensive.setup.LayoutLibTestCallback;
import com.android.layoutlib.bridge.intensive.setup.LayoutPullParser;
+import com.android.resources.Density;
+import com.android.resources.Navigation;
import com.android.utils.ILogger;
import org.junit.AfterClass;
@@ -310,21 +312,52 @@
sBridge = null;
}
+ /** Test expand_layout.xml */
+ @Test
+ public void testExpand() throws ClassNotFoundException {
+ // Create the layout pull parser.
+ LayoutPullParser parser = new LayoutPullParser(APP_TEST_RES + "/layout/" +
+ "expand_vert_layout.xml");
+ // Create LayoutLibCallback.
+ LayoutLibTestCallback layoutLibCallback = new LayoutLibTestCallback(getLogger());
+ layoutLibCallback.initResources();
+
+ ConfigGenerator customConfigGenerator = new ConfigGenerator()
+ .setScreenWidth(300)
+ .setScreenHeight(20)
+ .setDensity(Density.XHIGH)
+ .setNavigation(Navigation.NONAV);
+
+ SessionParams params = getSessionParams(parser, customConfigGenerator,
+ layoutLibCallback, "Theme.Material.NoActionBar.Fullscreen", RenderingMode.V_SCROLL,
+ 22);
+
+ renderAndVerify(params, "expand_vert_layout.png");
+
+ customConfigGenerator = new ConfigGenerator()
+ .setScreenWidth(20)
+ .setScreenHeight(300)
+ .setDensity(Density.XHIGH)
+ .setNavigation(Navigation.NONAV);
+ parser = new LayoutPullParser(APP_TEST_RES + "/layout/" +
+ "expand_horz_layout.xml");
+ params = getSessionParams(parser, customConfigGenerator,
+ layoutLibCallback, "Theme.Material.NoActionBar.Fullscreen", RenderingMode
+ .H_SCROLL, 22);
+
+ renderAndVerify(params, "expand_horz_layout.png");
+ }
+
/**
* Create a new rendering session and test that rendering given layout on nexus 5
* doesn't throw any exceptions and matches the provided image.
*/
- private void renderAndVerify(String layoutFileName, String goldenFileName)
+ private void renderAndVerify(SessionParams params, String goldenFileName)
throws ClassNotFoundException {
- // Create the layout pull parser.
- LayoutPullParser parser = new LayoutPullParser(APP_TEST_RES + "/layout/" + layoutFileName);
- // Create LayoutLibCallback.
- LayoutLibTestCallback layoutLibCallback = new LayoutLibTestCallback(getLogger());
- layoutLibCallback.initResources();
// TODO: Set up action bar handler properly to test menu rendering.
// Create session params.
- SessionParams params = getSessionParams(parser, ConfigGenerator.NEXUS_5, layoutLibCallback);
RenderSession session = sBridge.createSession(params);
+
if (!session.getResult().isSuccess()) {
getLogger().error(session.getResult().getException(),
session.getResult().getErrorMessage());
@@ -344,25 +377,44 @@
}
/**
+ * Create a new rendering session and test that rendering given layout on nexus 5
+ * doesn't throw any exceptions and matches the provided image.
+ */
+ private void renderAndVerify(String layoutFileName, String goldenFileName)
+ throws ClassNotFoundException {
+ // Create the layout pull parser.
+ LayoutPullParser parser = new LayoutPullParser(APP_TEST_RES + "/layout/" + layoutFileName);
+ // Create LayoutLibCallback.
+ LayoutLibTestCallback layoutLibCallback = new LayoutLibTestCallback(getLogger());
+ layoutLibCallback.initResources();
+ // TODO: Set up action bar handler properly to test menu rendering.
+ // Create session params.
+ SessionParams params = getSessionParams(parser, ConfigGenerator.NEXUS_5,
+ layoutLibCallback, "Theme.Material.Light.DarkActionBar", RenderingMode.NORMAL, 22);
+ renderAndVerify(params, goldenFileName);
+ }
+
+ /**
* Uses Theme.Material and Target sdk version as 22.
*/
private SessionParams getSessionParams(LayoutPullParser layoutParser,
- ConfigGenerator configGenerator, LayoutLibTestCallback layoutLibCallback) {
+ ConfigGenerator configGenerator, LayoutLibTestCallback layoutLibCallback,
+ String themeName, RenderingMode renderingMode, int targetSdk) {
FolderConfiguration config = configGenerator.getFolderConfig();
ResourceResolver resourceResolver =
ResourceResolver.create(sProjectResources.getConfiguredResources(config),
sFrameworkRepo.getConfiguredResources(config),
- "AppTheme", true);
+ themeName, true);
return new SessionParams(
layoutParser,
- RenderingMode.NORMAL,
+ renderingMode,
null /*used for caching*/,
configGenerator.getHardwareConfig(),
resourceResolver,
layoutLibCallback,
0,
- 22, // TODO: Make it more configurable to run tests for various versions.
+ targetSdk,
getLayoutLog());
}