Merge "Verfiy global apps with device owner" into mnc-dev
diff --git a/Android.mk b/Android.mk
index 1de3625..121bc8e 100644
--- a/Android.mk
+++ b/Android.mk
@@ -668,7 +668,8 @@
# FRAMEWORKS_BASE_SUBDIRS comes from build/core/pathmap.mk
dirs_to_document := \
$(dirs_to_check_apis) \
- $(addprefix ../../, $(FRAMEWORKS_SUPPORT_JAVA_SRC_DIRS))
+ $(addprefix ../../, $(FRAMEWORKS_DATA_BINDING_JAVA_SRC_DIRS)) \
+ $(addprefix ../../, $(FRAMEWORKS_SUPPORT_JAVA_SRC_DIRS)) \
# These are relative to frameworks/base
html_dirs := \
diff --git a/api/current.txt b/api/current.txt
index df9ea35..ea33eaf 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -28785,11 +28785,13 @@
public class VoiceInteractionService extends android.app.Service {
ctor public VoiceInteractionService();
method public final android.service.voice.AlwaysOnHotwordDetector createAlwaysOnHotwordDetector(java.lang.String, java.util.Locale, android.service.voice.AlwaysOnHotwordDetector.Callback);
+ method public int getDisabledShowContext();
method public static boolean isActiveService(android.content.Context, android.content.ComponentName);
method public android.os.IBinder onBind(android.content.Intent);
method public void onLaunchVoiceAssistFromKeyguard();
method public void onReady();
method public void onShutdown();
+ method public void setDisabledShowContext(int);
method public void showSession(android.os.Bundle, int);
field public static final java.lang.String SERVICE_INTERFACE = "android.service.voice.VoiceInteractionService";
field public static final java.lang.String SERVICE_META_DATA = "android.voice_interaction";
@@ -28801,6 +28803,7 @@
method public void closeSystemDialogs();
method public void finish();
method public android.content.Context getContext();
+ method public int getDisabledShowContext();
method public android.view.LayoutInflater getLayoutInflater();
method public android.app.Dialog getWindow();
method public void hide();
@@ -28832,6 +28835,7 @@
method public void onTaskStarted(android.content.Intent, int);
method public void onTrimMemory(int);
method public void setContentView(android.view.View);
+ method public void setDisabledShowContext(int);
method public void setKeepAwake(boolean);
method public void setTheme(int);
method public void show(android.os.Bundle, int);
diff --git a/api/system-current.txt b/api/system-current.txt
index eb1c431..cbb1bb2 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -30934,11 +30934,13 @@
public class VoiceInteractionService extends android.app.Service {
ctor public VoiceInteractionService();
method public final android.service.voice.AlwaysOnHotwordDetector createAlwaysOnHotwordDetector(java.lang.String, java.util.Locale, android.service.voice.AlwaysOnHotwordDetector.Callback);
+ method public int getDisabledShowContext();
method public static boolean isActiveService(android.content.Context, android.content.ComponentName);
method public android.os.IBinder onBind(android.content.Intent);
method public void onLaunchVoiceAssistFromKeyguard();
method public void onReady();
method public void onShutdown();
+ method public void setDisabledShowContext(int);
method public void showSession(android.os.Bundle, int);
field public static final java.lang.String SERVICE_INTERFACE = "android.service.voice.VoiceInteractionService";
field public static final java.lang.String SERVICE_META_DATA = "android.voice_interaction";
@@ -30950,6 +30952,7 @@
method public void closeSystemDialogs();
method public void finish();
method public android.content.Context getContext();
+ method public int getDisabledShowContext();
method public android.view.LayoutInflater getLayoutInflater();
method public android.app.Dialog getWindow();
method public void hide();
@@ -30981,6 +30984,7 @@
method public void onTaskStarted(android.content.Intent, int);
method public void onTrimMemory(int);
method public void setContentView(android.view.View);
+ method public void setDisabledShowContext(int);
method public void setKeepAwake(boolean);
method public void setTheme(int);
method public void show(android.os.Bundle, int);
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 849253b..08e1696 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -773,7 +773,7 @@
AppOpsManager.MODE_ALLOWED,
AppOpsManager.MODE_ALLOWED,
AppOpsManager.MODE_ALLOWED,
- AppOpsManager.MODE_ALLOWED,
+ AppOpsManager.MODE_DEFAULT, // OP_SYSTEM_ALERT_WINDOW
AppOpsManager.MODE_ALLOWED,
AppOpsManager.MODE_ALLOWED,
AppOpsManager.MODE_ALLOWED,
diff --git a/core/java/android/app/ExitTransitionCoordinator.java b/core/java/android/app/ExitTransitionCoordinator.java
index ad104a4..7fbb99a 100644
--- a/core/java/android/app/ExitTransitionCoordinator.java
+++ b/core/java/android/app/ExitTransitionCoordinator.java
@@ -25,6 +25,7 @@
import android.graphics.RectF;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
+import android.os.Build.VERSION_CODES;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
@@ -238,8 +239,12 @@
if (decorView != null && decorView.getBackground() == null) {
getWindow().setBackgroundDrawable(new ColorDrawable(Color.BLACK));
}
+ final boolean targetsM = decorView == null || decorView.getContext()
+ .getApplicationInfo().targetSdkVersion >= VERSION_CODES.MNC;
+ ArrayList<String> sharedElementNames = targetsM ? mSharedElementNames :
+ mAllSharedElementNames;
ActivityOptions options = ActivityOptions.makeSceneTransitionAnimation(mActivity, this,
- mSharedElementNames, resultCode, data);
+ sharedElementNames, resultCode, data);
mActivity.convertToTranslucent(new Activity.TranslucentConversionListener() {
@Override
public void onTranslucentConversionComplete(boolean drawComplete) {
diff --git a/core/java/android/app/assist/AssistStructure.java b/core/java/android/app/assist/AssistStructure.java
index 9673c98..40126d6 100644
--- a/core/java/android/app/assist/AssistStructure.java
+++ b/core/java/android/app/assist/AssistStructure.java
@@ -812,7 +812,7 @@
* Returns true if assist data has been blocked starting at this node in the hierarchy.
*/
public boolean isAssistBlocked() {
- return (mFlags&ViewNode.FLAGS_ASSIST_BLOCKED) == 0;
+ return (mFlags&ViewNode.FLAGS_ASSIST_BLOCKED) != 0;
}
/**
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 2b75f31..b2cec60 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -860,8 +860,23 @@
final IMountService mountService = IMountService.Stub.asInterface(
ServiceManager.getService("mount"));
try {
- final String packageName = ActivityThread.currentOpPackageName();
+ String packageName = ActivityThread.currentOpPackageName();
+ if (packageName == null) {
+ // Package name can be null if the activity thread is running but the app
+ // hasn't bound yet. In this case we fall back to the first package in the
+ // current UID. This works for runtime permissions as permission state is
+ // per UID and permission realted app ops are updated for all UID packages.
+ String[] packageNames = ActivityThread.getPackageManager().getPackagesForUid(
+ android.os.Process.myUid());
+ if (packageNames == null || packageNames.length <= 0) {
+ return new StorageVolume[0];
+ }
+ packageName = packageNames[0];
+ }
final int uid = ActivityThread.getPackageManager().getPackageUid(packageName, userId);
+ if (uid <= 0) {
+ return new StorageVolume[0];
+ }
return mountService.getVolumeList(uid, packageName);
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
diff --git a/core/java/android/provider/CalendarContract.java b/core/java/android/provider/CalendarContract.java
index d743484..aa22041 100644
--- a/core/java/android/provider/CalendarContract.java
+++ b/core/java/android/provider/CalendarContract.java
@@ -2393,7 +2393,7 @@
intent.setData(ContentUris.withAppendedId(CalendarContract.CONTENT_URI, alarmTime));
intent.putExtra(ALARM_TIME, alarmTime);
PendingIntent pi = PendingIntent.getBroadcast(context, 0, intent, 0);
- manager.setExact(AlarmManager.RTC_WAKEUP, alarmTime, pi);
+ manager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, alarmTime, pi);
}
/**
diff --git a/core/java/android/service/voice/VoiceInteractionService.java b/core/java/android/service/voice/VoiceInteractionService.java
index 549c93e..479c9e2 100644
--- a/core/java/android/service/voice/VoiceInteractionService.java
+++ b/core/java/android/service/voice/VoiceInteractionService.java
@@ -37,7 +37,6 @@
import java.io.PrintWriter;
import java.util.Locale;
-
/**
* Top-level service of the current global voice interactor, which is providing
* support for hotwording, the back-end of a {@link android.app.VoiceInteractor}, etc.
@@ -154,11 +153,39 @@
}
/**
+ * Set contextual options you would always like to have disabled when a session
+ * is shown. The flags may be any combination of
+ * {@link VoiceInteractionSession#SHOW_WITH_ASSIST VoiceInteractionSession.SHOW_WITH_ASSIST} and
+ * {@link VoiceInteractionSession#SHOW_WITH_SCREENSHOT
+ * VoiceInteractionSession.SHOW_WITH_SCREENSHOT}.
+ */
+ public void setDisabledShowContext(int flags) {
+ try {
+ mSystemService.setDisabledShowContext(flags);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Return the value set by {@link #setDisabledShowContext}.
+ */
+ public int getDisabledShowContext() {
+ try {
+ return mSystemService.getDisabledShowContext();
+ } catch (RemoteException e) {
+ return 0;
+ }
+ }
+
+ /**
* Request that the associated {@link android.service.voice.VoiceInteractionSession} be
* shown to the user, starting it if necessary.
* @param args Arbitrary arguments that will be propagated to the session.
* @param flags Indicates additional optional behavior that should be performed. May
- * be {@link VoiceInteractionSession#SHOW_WITH_ASSIST VoiceInteractionSession.SHOW_WITH_ASSIST}
+ * be any combination of
+ * {@link VoiceInteractionSession#SHOW_WITH_ASSIST VoiceInteractionSession.SHOW_WITH_ASSIST} and
+ * {@link VoiceInteractionSession#SHOW_WITH_SCREENSHOT
+ * VoiceInteractionSession.SHOW_WITH_SCREENSHOT}
* to request that the system generate and deliver assist data on the current foreground
* app as part of showing the session UI.
*/
diff --git a/core/java/android/service/voice/VoiceInteractionSession.java b/core/java/android/service/voice/VoiceInteractionSession.java
index e408b36..95f96e8 100644
--- a/core/java/android/service/voice/VoiceInteractionSession.java
+++ b/core/java/android/service/voice/VoiceInteractionSession.java
@@ -650,7 +650,7 @@
class MyCallbacks implements HandlerCaller.Callback, SoftInputWindow.Callback {
@Override
public void executeMessage(Message msg) {
- SomeArgs args;
+ SomeArgs args = null;
switch (msg.what) {
case MSG_START_CONFIRMATION:
if (DEBUG) Log.d(TAG, "onConfirm: req=" + msg.obj);
@@ -676,6 +676,8 @@
args = (SomeArgs)msg.obj;
if (DEBUG) Log.d(TAG, "onGetSupportedCommands: cmds=" + args.arg1);
args.arg1 = onGetSupportedCommands((String[]) args.arg1);
+ args.complete();
+ args = null;
break;
case MSG_CANCEL:
if (DEBUG) Log.d(TAG, "onCancel: req=" + ((Request)msg.obj));
@@ -723,6 +725,9 @@
doHide();
break;
}
+ if (args != null) {
+ args.recycle();
+ }
}
@Override
@@ -908,12 +913,38 @@
}
/**
+ * Equivalent to {@link VoiceInteractionService#setDisabledShowContext
+ * VoiceInteractionService.setDisabledShowContext(int)}.
+ */
+ public void setDisabledShowContext(int flags) {
+ try {
+ mSystemService.setDisabledShowContext(flags);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Equivalent to {@link VoiceInteractionService#getDisabledShowContext
+ * VoiceInteractionService.getDisabledShowContext}.
+ */
+ public int getDisabledShowContext() {
+ try {
+ return mSystemService.getDisabledShowContext();
+ } catch (RemoteException e) {
+ return 0;
+ }
+ }
+
+ /**
* Show the UI for this session. This asks the system to go through the process of showing
* your UI, which will eventually culminate in {@link #onShow}. This is similar to calling
* {@link VoiceInteractionService#showSession VoiceInteractionService.showSession}.
* @param args Arbitrary arguments that will be propagated {@link #onShow}.
* @param flags Indicates additional optional behavior that should be performed. May
- * be {@link VoiceInteractionSession#SHOW_WITH_ASSIST VoiceInteractionSession.SHOW_WITH_ASSIST}
+ * be any combination of
+ * {@link VoiceInteractionSession#SHOW_WITH_ASSIST VoiceInteractionSession.SHOW_WITH_ASSIST} and
+ * {@link VoiceInteractionSession#SHOW_WITH_SCREENSHOT
+ * VoiceInteractionSession.SHOW_WITH_SCREENSHOT}
* to request that the system generate and deliver assist data on the current foreground
* app as part of showing the session UI.
*/
diff --git a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
index 7f54f50..73ad981 100644
--- a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
+++ b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
@@ -37,6 +37,8 @@
void setKeepAwake(IBinder token, boolean keepAwake);
void closeSystemDialogs(IBinder token);
void finish(IBinder token);
+ void setDisabledShowContext(int flags);
+ int getDisabledShowContext();
/**
* Gets the registered Sound model for keyphrase detection for the current user.
diff --git a/core/java/com/android/internal/os/SomeArgs.java b/core/java/com/android/internal/os/SomeArgs.java
index b0d24fd..c05e0d8 100644
--- a/core/java/com/android/internal/os/SomeArgs.java
+++ b/core/java/com/android/internal/os/SomeArgs.java
@@ -73,6 +73,16 @@
}
}
+ public void complete() {
+ synchronized (this) {
+ if (mWaitState != WAIT_WAITING) {
+ throw new IllegalStateException("Not waiting");
+ }
+ mWaitState = WAIT_FINISHED;
+ notifyAll();
+ }
+ }
+
public void recycle() {
if (mInPool) {
throw new IllegalStateException("Already recycled.");
diff --git a/core/java/com/android/internal/widget/FloatingToolbar.java b/core/java/com/android/internal/widget/FloatingToolbar.java
index b3f688b..ca6fe61 100644
--- a/core/java/com/android/internal/widget/FloatingToolbar.java
+++ b/core/java/com/android/internal/widget/FloatingToolbar.java
@@ -285,7 +285,6 @@
private final Context mContext;
private final View mParent;
- private final int[] mParentPositionOnScreen = new int[2];
private final PopupWindow mPopupWindow;
private final ViewGroup mContentContainer;
private final int mMarginHorizontal;
@@ -339,7 +338,8 @@
};
private final Rect mViewPortOnScreen = new Rect();
- private final Point mCoordsOnScreen = new Point();
+ private final Point mCoordsOnWindow = new Point();
+ private final int[] mTmpCoords = new int[2];
private final Rect mTmpRect = new Rect();
private final Region mTouchableRegion = new Region();
@@ -450,13 +450,11 @@
}
refreshCoordinatesAndOverflowDirection(contentRectOnScreen);
preparePopupContent();
- // We need to specify the offset relative to mParent.
+ // We need to specify the position in window coordinates.
// TODO: Consider to use PopupWindow.setLayoutInScreenEnabled(true) so that we can
// specify the popup poision in screen coordinates.
- mParent.getLocationOnScreen(mParentPositionOnScreen);
- final int relativeX = mCoordsOnScreen.x - mParentPositionOnScreen[0];
- final int relativeY = mCoordsOnScreen.y - mParentPositionOnScreen[1];
- mPopupWindow.showAtLocation(mParent, Gravity.NO_GRAVITY, relativeX, relativeY);
+ mPopupWindow.showAtLocation(mParent, Gravity.NO_GRAVITY, mCoordsOnWindow.x,
+ mCoordsOnWindow.y);
setTouchableSurfaceInsetsComputer();
runShowAnimation();
}
@@ -519,13 +517,10 @@
cancelOverflowAnimations();
refreshCoordinatesAndOverflowDirection(contentRectOnScreen);
preparePopupContent();
- // We need to specify the offset relative to mParent.
+ // We need to specify the position in window coordinates.
// TODO: Consider to use PopupWindow.setLayoutInScreenEnabled(true) so that we can
// specify the popup poision in screen coordinates.
- mParent.getLocationOnScreen(mParentPositionOnScreen);
- final int relativeX = mCoordsOnScreen.x - mParentPositionOnScreen[0];
- final int relativeY = mCoordsOnScreen.y - mParentPositionOnScreen[1];
- mPopupWindow.update(relativeX, relativeY, getWidth(), getHeight());
+ mPopupWindow.update(mCoordsOnWindow.x, mCoordsOnWindow.y, getWidth(), getHeight());
}
/**
@@ -624,7 +619,22 @@
mOverflowPanel.setOverflowDirection(mOverflowDirection);
}
- mCoordsOnScreen.set(x, y);
+ // We later specify the location of PopupWindow relative to the attached window.
+ // The idea here is that 1) we can get the location of a View in both window coordinates
+ // and screen coordiantes, where the offset between them should be equal to the window
+ // origin, and 2) we can use an arbitrary for this calculation while calculating the
+ // location of the rootview is supposed to be least expensive.
+ // TODO: Consider to use PopupWindow.setLayoutInScreenEnabled(true) so that we can avoid
+ // the following calculation.
+ mParent.getRootView().getLocationOnScreen(mTmpCoords);
+ int rootViewLeftOnScreen = mTmpCoords[0];
+ int rootViewTopOnScreen = mTmpCoords[1];
+ mParent.getRootView().getLocationInWindow(mTmpCoords);
+ int rootViewLeftOnWindow = mTmpCoords[0];
+ int rootViewTopOnWindow = mTmpCoords[1];
+ int windowLeftOnScreen = rootViewLeftOnScreen - rootViewLeftOnWindow;
+ int windowTopOnScreen = rootViewTopOnScreen - rootViewTopOnWindow;
+ mCoordsOnWindow.set(x - windowLeftOnScreen, y - windowTopOnScreen);
}
private int getToolbarHeightWithVerticalMargin() {
diff --git a/core/java/com/android/internal/widget/IRemoteViewsAdapterConnection.aidl b/core/java/com/android/internal/widget/IRemoteViewsAdapterConnection.aidl
index 7eb2aef..7294124 100644
--- a/core/java/com/android/internal/widget/IRemoteViewsAdapterConnection.aidl
+++ b/core/java/com/android/internal/widget/IRemoteViewsAdapterConnection.aidl
@@ -19,7 +19,7 @@
import android.os.IBinder;
/** {@hide} */
-interface IRemoteViewsAdapterConnection {
+oneway interface IRemoteViewsAdapterConnection {
void onServiceConnected(IBinder service);
void onServiceDisconnected();
}
diff --git a/core/res/res/layout/common_tab_settings.xml b/core/res/res/layout/common_tab_settings.xml
new file mode 100644
index 0000000..d2a4acc
--- /dev/null
+++ b/core/res/res/layout/common_tab_settings.xml
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<TabHost xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@android:id/tabhost"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <LinearLayout
+ android:id="@+id/tabs_container"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+ <HorizontalScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:scrollbars="none"
+ android:fillViewport="true">
+
+ <TabWidget
+ android:id="@android:id/tabs"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ style="?android:attr/tabWidgetStyle" />
+
+ </HorizontalScrollView>
+
+ <!-- give an empty content area to make tabhost happy -->
+ <FrameLayout
+ android:id="@android:id/tabcontent"
+ android:layout_width="0dip"
+ android:layout_height="0dip" />
+
+ <ListView
+ android:id="@android:id/list"
+ android:layout_width="match_parent"
+ android:layout_height="0dip"
+ android:layout_weight="1"
+ android:clipChildren="false"
+ android:clipToPadding="false"
+ android:smoothScrollbar="false" />
+
+ </LinearLayout>
+
+</TabHost>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index d41031c..b330423 100755
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1360,6 +1360,7 @@
<java-symbol type="layout" name="restrictions_pin_setup" />
<java-symbol type="layout" name="immersive_mode_cling" />
<java-symbol type="layout" name="user_switching_dialog" />
+ <java-symbol type="layout" name="common_tab_settings" />
<java-symbol type="anim" name="slide_in_child_bottom" />
<java-symbol type="anim" name="slide_in_right" />
diff --git a/docs/html/distribute/essentials/quality/tv.jd b/docs/html/distribute/essentials/quality/tv.jd
index 20018c3..c7f6fcb 100644
--- a/docs/html/distribute/essentials/quality/tv.jd
+++ b/docs/html/distribute/essentials/quality/tv.jd
@@ -418,9 +418,9 @@
</td>
<td>
<p style="margin-bottom:.5em;">
- If the app continues to play sound after the user has left, the app provides a <em>Now
- Playing</em> card on the home screen recommendation row so users can return to the app to
- control playback.
+ If the app continues to play sound or video after the user has left, the
+ app provides a <em>Now Playing</em> card on the home screen recommendation
+ row so users can return to the app to control playback.
(<a href="{@docRoot}training/tv/playback/now-playing.html">Learn how</a>)
</p>
</td>
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 260fb6f..09f93b8 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -145,7 +145,11 @@
void CanvasContext::makeCurrent() {
// TODO: Figure out why this workaround is needed, see b/13913604
// In the meantime this matches the behavior of GLRenderer, so it is not a regression
- mHaveNewSurface |= mEglManager.makeCurrent(mEglSurface);
+ EGLint error = 0;
+ mHaveNewSurface |= mEglManager.makeCurrent(mEglSurface, &error);
+ if (error) {
+ setSurface(nullptr);
+ }
}
void CanvasContext::processLayerUpdate(DeferredLayerUpdater* layerUpdater) {
diff --git a/libs/hwui/renderthread/EglManager.cpp b/libs/hwui/renderthread/EglManager.cpp
index cb34e00..eb332d5 100644
--- a/libs/hwui/renderthread/EglManager.cpp
+++ b/libs/hwui/renderthread/EglManager.cpp
@@ -217,7 +217,7 @@
mCurrentSurface = EGL_NO_SURFACE;
}
-bool EglManager::makeCurrent(EGLSurface surface) {
+bool EglManager::makeCurrent(EGLSurface surface, EGLint* errOut) {
if (isCurrent(surface)) return false;
if (surface == EGL_NO_SURFACE) {
@@ -225,8 +225,14 @@
surface = mPBufferSurface;
}
if (!eglMakeCurrent(mEglDisplay, surface, surface, mEglContext)) {
- LOG_ALWAYS_FATAL("Failed to make current on surface %p, error=%s",
- (void*)surface, egl_error_str());
+ if (errOut) {
+ *errOut = eglGetError();
+ ALOGW("Failed to make current on surface %p, error=%s",
+ (void*)surface, egl_error_str(*errOut));
+ } else {
+ LOG_ALWAYS_FATAL("Failed to make current on surface %p, error=%s",
+ (void*)surface, egl_error_str());
+ }
}
mCurrentSurface = surface;
return true;
diff --git a/libs/hwui/renderthread/EglManager.h b/libs/hwui/renderthread/EglManager.h
index 8881de6..0a8cfd3 100644
--- a/libs/hwui/renderthread/EglManager.h
+++ b/libs/hwui/renderthread/EglManager.h
@@ -44,7 +44,7 @@
bool isCurrent(EGLSurface surface) { return mCurrentSurface == surface; }
// Returns true if the current surface changed, false if it was already current
- bool makeCurrent(EGLSurface surface);
+ bool makeCurrent(EGLSurface surface, EGLint* errOut = nullptr);
void beginFrame(EGLSurface surface, EGLint* width, EGLint* height);
bool swapBuffers(EGLSurface surface, const SkRect& dirty, EGLint width, EGLint height);
diff --git a/packages/SystemUI/res/layout/qs_detail_item.xml b/packages/SystemUI/res/layout/qs_detail_item.xml
index a519d3f..6facb71 100644
--- a/packages/SystemUI/res/layout/qs_detail_item.xml
+++ b/packages/SystemUI/res/layout/qs_detail_item.xml
@@ -20,6 +20,7 @@
android:minHeight="@dimen/qs_detail_item_height"
android:background="@drawable/btn_borderless_rect"
android:clickable="true"
+ android:focusable="true"
android:gravity="center_vertical"
android:orientation="horizontal" >
@@ -57,6 +58,7 @@
android:layout_width="48dp"
android:layout_height="48dp"
android:clickable="true"
+ android:focusable="true"
android:scaleType="center"
android:src="@drawable/ic_qs_cancel" />
diff --git a/packages/SystemUI/res/layout/status_bar_notification_dismiss_all.xml b/packages/SystemUI/res/layout/status_bar_notification_dismiss_all.xml
index 6a000fd..dc7577a 100644
--- a/packages/SystemUI/res/layout/status_bar_notification_dismiss_all.xml
+++ b/packages/SystemUI/res/layout/status_bar_notification_dismiss_all.xml
@@ -27,6 +27,7 @@
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_gravity="end"
+ android:focusable="true"
android:background="@drawable/ripple_drawable"
android:contentDescription="@string/accessibility_clear_all"/>
</com.android.systemui.statusbar.DismissView>
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
index da1f03e..f7c3c67 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
@@ -478,7 +478,6 @@
}
private void setTint(ImageView v, int tint) {
- v.setImageTintMode(PorterDuff.Mode.SRC_ATOP);
v.setImageTintList(ColorStateList.valueOf(tint));
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 37aa408..1582037 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -10801,6 +10801,8 @@
}
// We are now ready to launch the assist activity.
+ IResultReceiver sendReceiver = null;
+ Bundle sendBundle = null;
synchronized (this) {
buildAssistBundleLocked(pae, extras);
boolean exists = mPendingAssistExtras.remove(pae);
@@ -10809,19 +10811,21 @@
// Timed out.
return;
}
- if (pae.receiver != null) {
+ if ((sendReceiver=pae.receiver) != null) {
// Caller wants result sent back to them.
- Bundle topBundle = new Bundle();
- topBundle.putBundle("data", pae.extras);
- topBundle.putParcelable("structure", pae.structure);
- topBundle.putParcelable("content", pae.content);
- try {
- pae.receiver.send(0, topBundle);
- } catch (RemoteException e) {
- }
- return;
+ sendBundle = new Bundle();
+ sendBundle.putBundle("data", pae.extras);
+ sendBundle.putParcelable("structure", pae.structure);
+ sendBundle.putParcelable("content", pae.content);
}
}
+ if (sendReceiver != null) {
+ try {
+ sendReceiver.send(0, sendBundle);
+ } catch (RemoteException e) {
+ }
+ return;
+ }
long ident = Binder.clearCallingIdentity();
try {
diff --git a/services/core/java/com/android/server/fingerprint/FingerprintService.java b/services/core/java/com/android/server/fingerprint/FingerprintService.java
index a71dfcd..8871e64 100644
--- a/services/core/java/com/android/server/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/fingerprint/FingerprintService.java
@@ -86,6 +86,7 @@
private static final int FINGERPRINT_ACQUIRED_GOOD = 0;
Handler mHandler = new Handler() {
+ @Override
public void handleMessage(android.os.Message msg) {
switch (msg.what) {
case MSG_USER_SWITCHING:
@@ -274,7 +275,7 @@
Slog.w(TAG, "enroll: no fingeprintd!");
return;
}
- stopPendingOperations();
+ stopPendingOperations(true);
mEnrollClient = new ClientMonitor(token, receiver, groupId, restricted);
final int timeout = (int) (ENROLLMENT_TIMEOUT_MS / MS_PER_SEC);
try {
@@ -315,17 +316,23 @@
return 0;
}
- private void stopPendingOperations() {
+ private void stopPendingOperations(boolean initiatedByClient) {
if (mEnrollClient != null) {
- stopEnrollment(mEnrollClient.token, true);
+ stopEnrollment(mEnrollClient.token, initiatedByClient);
}
if (mAuthClient != null) {
- stopAuthentication(mAuthClient.token, true);
+ stopAuthentication(mAuthClient.token, initiatedByClient);
}
// mRemoveClient is allowed to continue
}
- void stopEnrollment(IBinder token, boolean notify) {
+ /**
+ * Stop enrollment in progress and inform client if they initiated it.
+ *
+ * @param token token for client
+ * @param initiatedByClient if this call is the result of client action (e.g. calling cancel)
+ */
+ void stopEnrollment(IBinder token, boolean initiatedByClient) {
IFingerprintDaemon daemon = getFingerprintDaemon();
if (daemon == null) {
Slog.w(TAG, "stopEnrollment: no fingeprintd!");
@@ -333,15 +340,15 @@
}
final ClientMonitor client = mEnrollClient;
if (client == null || client.token != token) return;
- try {
- int result = daemon.cancelEnrollment();
- if (result != 0) {
- Slog.w(TAG, "startEnrollCancel failed, result = " + result);
+ if (initiatedByClient) {
+ try {
+ int result = daemon.cancelEnrollment();
+ if (result != 0) {
+ Slog.w(TAG, "startEnrollCancel failed, result = " + result);
+ }
+ } catch (RemoteException e) {
+ Slog.e(TAG, "stopEnrollment failed", e);
}
- } catch (RemoteException e) {
- Slog.e(TAG, "stopEnrollment failed", e);
- }
- if (notify) {
client.sendError(FingerprintManager.FINGERPRINT_ERROR_CANCELED);
}
removeClient(mEnrollClient);
@@ -354,7 +361,7 @@
Slog.w(TAG, "startAuthentication: no fingeprintd!");
return;
}
- stopPendingOperations();
+ stopPendingOperations(true);
mAuthClient = new ClientMonitor(token, receiver, groupId, restricted);
if (inLockoutMode()) {
Slog.v(TAG, "In lockout mode; disallowing authentication");
@@ -374,7 +381,13 @@
}
}
- void stopAuthentication(IBinder token, boolean notify) {
+ /**
+ * Stop authentication in progress and inform client if they initiated it.
+ *
+ * @param token token for client
+ * @param initiatedByClient if this call is the result of client action (e.g. calling cancel)
+ */
+ void stopAuthentication(IBinder token, boolean initiatedByClient) {
IFingerprintDaemon daemon = getFingerprintDaemon();
if (daemon == null) {
Slog.w(TAG, "stopAuthentication: no fingeprintd!");
@@ -382,15 +395,15 @@
}
final ClientMonitor client = mAuthClient;
if (client == null || client.token != token) return;
- try {
- int result = daemon.cancelAuthentication();
- if (result != 0) {
- Slog.w(TAG, "stopAuthentication failed, result=" + result);
+ if (initiatedByClient) {
+ try {
+ int result = daemon.cancelAuthentication();
+ if (result != 0) {
+ Slog.w(TAG, "stopAuthentication failed, result=" + result);
+ }
+ } catch (RemoteException e) {
+ Slog.e(TAG, "stopAuthentication failed", e);
}
- } catch (RemoteException e) {
- Slog.e(TAG, "stopAuthentication failed", e);
- }
- if (notify) {
client.sendError(FingerprintManager.FINGERPRINT_ERROR_CANCELED);
}
removeClient(mAuthClient);
@@ -486,12 +499,14 @@
receiver = null;
}
+ @Override
public void binderDied() {
token = null;
removeClient(this);
receiver = null;
}
+ @Override
protected void finalize() throws Throwable {
try {
if (token != null) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 7cc857f..7602990 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -801,12 +801,9 @@
}
private static boolean hasValidDomains(ActivityIntentInfo filter) {
- boolean hasHTTPorHTTPS = filter.hasDataScheme(IntentFilter.SCHEME_HTTP) ||
- filter.hasDataScheme(IntentFilter.SCHEME_HTTPS);
- if (!hasHTTPorHTTPS) {
- return false;
- }
- return true;
+ return filter.hasCategory(Intent.CATEGORY_BROWSABLE)
+ && (filter.hasDataScheme(IntentFilter.SCHEME_HTTP) ||
+ filter.hasDataScheme(IntentFilter.SCHEME_HTTPS));
}
private IntentFilterVerifier mIntentFilterVerifier;
@@ -4420,9 +4417,7 @@
synchronized(mPackages) {
CrossProfileDomainInfo xpDomainInfo = getCrossProfileDomainPreferredLpr(
intent, resolvedType, 0, sourceUserId, parent.id);
- return xpDomainInfo != null
- && xpDomainInfo.bestDomainVerificationStatus !=
- INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER;
+ return xpDomainInfo != null;
}
}
return false;
@@ -4579,6 +4574,11 @@
result.bestDomainVerificationStatus);
}
}
+ // Don't consider matches with status NEVER across profiles.
+ if (result != null && result.bestDomainVerificationStatus
+ == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER) {
+ return null;
+ }
return result;
}
@@ -4716,8 +4716,7 @@
} else {
// Browser/generic handling case. If there's a default browser, go straight
// to that (but only if there is no other higher-priority match).
- final String defaultBrowserPackageName = getDefaultBrowserPackageName(
- UserHandle.myUserId());
+ final String defaultBrowserPackageName = getDefaultBrowserPackageName(userId);
int maxMatchPrio = 0;
ResolveInfo defaultBrowserMatch = null;
final int numCandidates = matchAllList.size();
@@ -9929,7 +9928,7 @@
if (packageName != null) {
result |= updateIntentVerificationStatus(packageName,
PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS,
- UserHandle.myUserId());
+ userId);
mDefaultPermissionPolicy.grantDefaultPermissionsToDefaultBrowserLPr(
packageName, userId);
}
@@ -15081,8 +15080,9 @@
}
if (filters != null && filters.size() > 0) {
for (IntentFilter filter : filters) {
- if (filter.hasDataScheme(IntentFilter.SCHEME_HTTP) ||
- filter.hasDataScheme(IntentFilter.SCHEME_HTTPS)) {
+ if (filter.hasCategory(Intent.CATEGORY_BROWSABLE)
+ && (filter.hasDataScheme(IntentFilter.SCHEME_HTTP) ||
+ filter.hasDataScheme(IntentFilter.SCHEME_HTTPS))) {
result.addAll(filter.getHostsList());
}
}
diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java
index 4faf75a..bbdfe31 100644
--- a/services/core/java/com/android/server/pm/PackageSettingBase.java
+++ b/services/core/java/com/android/server/pm/PackageSettingBase.java
@@ -238,6 +238,7 @@
installStatus = base.installStatus;
keySetData = base.keySetData;
verificationInfo = base.verificationInfo;
+ installerPackageName = base.installerPackageName;
}
private PackageUserState modifyUserState(int userId) {
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 978ed51..13e075c 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -126,6 +126,7 @@
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintWriter;
+import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
@@ -1875,21 +1876,33 @@
if (permission != null) {
if (permission == android.Manifest.permission.SYSTEM_ALERT_WINDOW) {
final int callingUid = Binder.getCallingUid();
- // check if this is a system uid first before bothering with
- // obtaining package name
+ // system processes will be automatically allowed privilege to draw
if (callingUid == Process.SYSTEM_UID) {
return WindowManagerGlobal.ADD_OKAY;
}
+ // check if user has enabled this operation. SecurityException will be thrown if
+ // this app has not been allowed by the user
final int mode = mAppOpsManager.checkOp(outAppOp[0], callingUid,
attrs.packageName);
- if (mode == AppOpsManager.MODE_DEFAULT) {
- if (mContext.checkCallingPermission(permission) !=
- PackageManager.PERMISSION_GRANTED) {
+ switch (mode) {
+ case AppOpsManager.MODE_ALLOWED:
+ case AppOpsManager.MODE_IGNORED:
+ // although we return ADD_OKAY for MODE_IGNORED, the added window will
+ // actually be hidden in WindowManagerService
+ return WindowManagerGlobal.ADD_OKAY;
+ case AppOpsManager.MODE_ERRORED:
return WindowManagerGlobal.ADD_PERMISSION_DENIED;
- }
+ default:
+ // in the default mode, we will make a decision here based on
+ // checkCallingPermission()
+ if (mContext.checkCallingPermission(permission) !=
+ PackageManager.PERMISSION_GRANTED) {
+ return WindowManagerGlobal.ADD_PERMISSION_DENIED;
+ } else {
+ return WindowManagerGlobal.ADD_OKAY;
+ }
}
- return WindowManagerGlobal.ADD_OKAY;
}
if (mContext.checkCallingOrSelfPermission(permission)
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 05c111c..c776e8f 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2543,8 +2543,10 @@
win.attach();
mWindowMap.put(client.asBinder(), win);
if (win.mAppOp != AppOpsManager.OP_NONE) {
- if (mAppOps.startOpNoThrow(win.mAppOp, win.getOwningUid(), win.getOwningPackage())
- != AppOpsManager.MODE_ALLOWED) {
+ int startOpResult = mAppOps.startOpNoThrow(win.mAppOp, win.getOwningUid(),
+ win.getOwningPackage());
+ if ((startOpResult != AppOpsManager.MODE_ALLOWED) &&
+ (startOpResult != AppOpsManager.MODE_DEFAULT)) {
win.setAppOpVisibilityLw(false);
}
}
@@ -2728,10 +2730,10 @@
wasVisible = win.isWinVisibleLw();
if (wasVisible) {
- int transit = WindowManagerPolicy.TRANSIT_EXIT;
- if (win.mAttrs.type == TYPE_APPLICATION_STARTING) {
- transit = WindowManagerPolicy.TRANSIT_PREVIEW_DONE;
- }
+ final int transit = (!startingWindow)
+ ? WindowManagerPolicy.TRANSIT_EXIT
+ : WindowManagerPolicy.TRANSIT_PREVIEW_DONE;
+
// Try starting an animation.
if (win.mWinAnimator.applyAnimationLocked(transit, false)) {
win.mExiting = true;
@@ -2743,12 +2745,13 @@
}
}
final AppWindowToken appToken = win.mAppToken;
+ final boolean isAnimating = win.mWinAnimator.isAnimating();
// The starting window is the last window in this app token and it isn't animating.
// Allow it to be removed now as there is no additional window or animation that will
// trigger its removal.
final boolean lastWinStartingNotAnimating = startingWindow && appToken!= null
- && appToken.allAppWindows.size() == 1 && !win.mWinAnimator.isAnimating();
- if (!lastWinStartingNotAnimating && (win.mExiting || win.mWinAnimator.isAnimating())) {
+ && appToken.allAppWindows.size() == 1 && !isAnimating;
+ if (!lastWinStartingNotAnimating && (win.mExiting || isAnimating)) {
// The exit animation is running... wait for it!
win.mExiting = true;
win.mRemoveOnExit = true;
@@ -2899,7 +2902,8 @@
if (win.mAppOp != AppOpsManager.OP_NONE) {
final int mode = mAppOps.checkOpNoThrow(win.mAppOp, win.getOwningUid(),
win.getOwningPackage());
- win.setAppOpVisibilityLw(mode == AppOpsManager.MODE_ALLOWED);
+ win.setAppOpVisibilityLw(mode == AppOpsManager.MODE_ALLOWED ||
+ mode == AppOpsManager.MODE_DEFAULT);
}
}
}
@@ -4524,7 +4528,10 @@
}
wtoken.willBeHidden = false;
- if (wtoken.hidden == visible) {
+ // Allow for state changes and animation to be applied if token is transitioning
+ // visibility state or the token was marked as hidden and is exiting before we had a chance
+ // to play the transition animation.
+ if (wtoken.hidden == visible || (wtoken.hidden && wtoken.mIsExiting)) {
boolean changed = false;
if (DEBUG_APP_TRANSITIONS) Slog.v(
TAG, "Changing app " + wtoken + " hidden=" + wtoken.hidden
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index 36478da..42f879c 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -578,6 +578,44 @@
}
}
+ @Override
+ public void setDisabledShowContext(int flags) {
+ synchronized (this) {
+ if (mImpl == null) {
+ Slog.w(TAG, "setDisabledShowContext without running voice interaction service");
+ return;
+ }
+ final int callingPid = Binder.getCallingPid();
+ final int callingUid = Binder.getCallingUid();
+ final long caller = Binder.clearCallingIdentity();
+ try {
+ mImpl.setDisabledShowContextLocked(callingPid, callingUid, flags);
+ } finally {
+ Binder.restoreCallingIdentity(caller);
+ }
+ }
+
+ }
+
+ @Override
+ public int getDisabledShowContext() {
+ synchronized (this) {
+ if (mImpl == null) {
+ Slog.w(TAG, "getDisabledShowContext without running voice interaction service");
+ return 0;
+ }
+ final int callingPid = Binder.getCallingPid();
+ final int callingUid = Binder.getCallingUid();
+ final long caller = Binder.clearCallingIdentity();
+ try {
+ return mImpl.getDisabledShowContextLocked(callingPid, callingUid);
+ } finally {
+ Binder.restoreCallingIdentity(caller);
+ }
+ }
+
+ }
+
//----------------- Model management APIs --------------------------------//
@Override
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
index e5faf4d..7409f99 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
@@ -65,6 +65,7 @@
IVoiceInteractionService mService;
VoiceInteractionSessionConnection mActiveSession;
+ int mDisabledShowContext;
final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@Override
@@ -146,7 +147,7 @@
mActiveSession = new VoiceInteractionSessionConnection(mLock, mSessionComponentName,
mUser, mContext, this, mInfo.getServiceInfo().applicationInfo.uid, mHandler);
}
- return mActiveSession.showLocked(args, flags, showCallback);
+ return mActiveSession.showLocked(args, flags, mDisabledShowContext, showCallback);
}
public boolean hideSessionLocked() {
@@ -222,6 +223,24 @@
mActiveSession = null;
}
+ public void setDisabledShowContextLocked(int callingPid, int callingUid, int flags) {
+ int activeUid = mInfo.getServiceInfo().applicationInfo.uid;
+ if (callingUid != activeUid) {
+ throw new SecurityException("Calling uid " + callingUid
+ + " does not match active uid " + activeUid);
+ }
+ mDisabledShowContext = flags;
+ }
+
+ public int getDisabledShowContextLocked(int callingPid, int callingUid) {
+ int activeUid = mInfo.getServiceInfo().applicationInfo.uid;
+ if (callingUid != activeUid) {
+ throw new SecurityException("Calling uid " + callingUid
+ + " does not match active uid " + activeUid);
+ }
+ return mDisabledShowContext;
+ }
+
public void dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args) {
if (!mValid) {
pw.print(" NOT VALID: ");
@@ -235,6 +254,10 @@
pw.print(" mComponent="); pw.println(mComponent.flattenToShortString());
pw.print(" Session service="); pw.println(mInfo.getSessionService());
pw.print(" Settings activity="); pw.println(mInfo.getSettingsActivity());
+ if (mDisabledShowContext != 0) {
+ pw.print(" mDisabledShowContext=");
+ pw.println(Integer.toHexString(mDisabledShowContext));
+ }
pw.print(" mBound="); pw.print(mBound); pw.print(" mService="); pw.println(mService);
if (mActiveSession != null) {
pw.println(" Active session:");
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
index bd043ac..dfdd639 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
@@ -183,7 +183,7 @@
}
}
- public boolean showLocked(Bundle args, int flags,
+ public boolean showLocked(Bundle args, int flags, int disabledContext,
IVoiceInteractionSessionShowCallback showCallback) {
if (mBound) {
if (!mFullyBound) {
@@ -200,15 +200,17 @@
}
boolean structureEnabled = Settings.Secure.getIntForUser(mContext.getContentResolver(),
Settings.Secure.ASSIST_STRUCTURE_ENABLED, 1, mUser) != 0
- && isScreenCaptureAllowed;
+ && isScreenCaptureAllowed
+ && (disabledContext&VoiceInteractionSession.SHOW_WITH_ASSIST) == 0;
boolean screenshotEnabled = Settings.Secure.getIntForUser(mContext.getContentResolver(),
Settings.Secure.ASSIST_SCREENSHOT_ENABLED, 1, mUser) != 0
- && isScreenCaptureAllowed;
+ && isScreenCaptureAllowed
+ && (disabledContext&VoiceInteractionSession.SHOW_WITH_SCREENSHOT) == 0;
mShowArgs = args;
mShowFlags = flags;
mHaveAssistData = false;
boolean needDisclosure = false;
- if ((flags& VoiceInteractionSession.SHOW_WITH_ASSIST) != 0) {
+ if ((flags&VoiceInteractionSession.SHOW_WITH_ASSIST) != 0) {
if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ASSIST_STRUCTURE, mCallingUid,
mSessionComponentName.getPackageName()) == AppOpsManager.MODE_ALLOWED
&& structureEnabled) {
@@ -226,7 +228,7 @@
mAssistData = null;
}
mHaveScreenshot = false;
- if ((flags& VoiceInteractionSession.SHOW_WITH_SCREENSHOT) != 0) {
+ if ((flags&VoiceInteractionSession.SHOW_WITH_SCREENSHOT) != 0) {
if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ASSIST_SCREENSHOT, mCallingUid,
mSessionComponentName.getPackageName()) == AppOpsManager.MODE_ALLOWED
&& screenshotEnabled) {
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index f4a6064..32b7383 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -21,12 +21,15 @@
import android.annotation.SdkConstant.SdkConstantType;
import android.content.Context;
import android.content.Intent;
+import android.content.res.Configuration;
+import android.content.res.Resources;
import android.net.Uri;
import android.telephony.Rlog;
import android.os.Handler;
import android.os.Message;
import android.os.ServiceManager;
import android.os.RemoteException;
+import android.util.DisplayMetrics;
import com.android.internal.telephony.ISub;
import com.android.internal.telephony.IOnSubscriptionsChangedListener;
@@ -248,6 +251,78 @@
public static final String MNC = "mnc";
/**
+ * TelephonyProvider column name for extreme threat in CB settings
+ * @hide
+ */
+ public static final String CB_EXTREME_THREAT_ALERT = "enable_cmas_extreme_threat_alerts";
+
+ /**
+ * TelephonyProvider column name for severe threat in CB settings
+ *@hide
+ */
+ public static final String CB_SEVERE_THREAT_ALERT = "enable_cmas_severe_threat_alerts";
+
+ /**
+ * TelephonyProvider column name for amber alert in CB settings
+ *@hide
+ */
+ public static final String CB_AMBER_ALERT = "enable_cmas_amber_alerts";
+
+ /**
+ * TelephonyProvider column name for emergency alert in CB settings
+ *@hide
+ */
+ public static final String CB_EMERGENCY_ALERT = "enable_emergency_alerts";
+
+ /**
+ * TelephonyProvider column name for alert sound duration in CB settings
+ *@hide
+ */
+ public static final String CB_ALERT_SOUND_DURATION = "alert_sound_duration";
+
+ /**
+ * TelephonyProvider column name for alert reminder interval in CB settings
+ *@hide
+ */
+ public static final String CB_ALERT_REMINDER_INTERVAL = "alert_reminder_interval";
+
+ /**
+ * TelephonyProvider column name for enabling vibrate in CB settings
+ *@hide
+ */
+ public static final String CB_ALERT_VIBRATE = "enable_alert_vibrate";
+
+ /**
+ * TelephonyProvider column name for enabling alert speech in CB settings
+ *@hide
+ */
+ public static final String CB_ALERT_SPEECH = "enable_alert_speech";
+
+ /**
+ * TelephonyProvider column name for ETWS test alert in CB settings
+ *@hide
+ */
+ public static final String CB_ETWS_TEST_ALERT = "enable_etws_test_alerts";
+
+ /**
+ * TelephonyProvider column name for enable channel50 alert in CB settings
+ *@hide
+ */
+ public static final String CB_CHANNEL_50_ALERT = "enable_channel_50_alerts";
+
+ /**
+ * TelephonyProvider column name for CMAS test alert in CB settings
+ *@hide
+ */
+ public static final String CB_CMAS_TEST_ALERT= "enable_cmas_test_alerts";
+
+ /**
+ * TelephonyProvider column name for Opt out dialog in CB settings
+ *@hide
+ */
+ public static final String CB_OPT_OUT_DIALOG = "show_cmas_opt_out_dialog";
+
+ /**
* Broadcast Action: The user has changed one of the default subs related to
* data, phone calls, or sms</p>
*
@@ -1137,6 +1212,112 @@
}
/**
+ * Store properties associated with SubscriptionInfo in database
+ * @param subId Subscription Id of Subscription
+ * @param propKey Column name in database associated with SubscriptionInfo
+ * @param propValue Value to store in DB for particular subId & column name
+ * @hide
+ */
+ public static void setSubscriptionProperty(int subId, String propKey, String propValue) {
+ try {
+ ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ if (iSub != null) {
+ iSub.setSubscriptionProperty(subId, propKey, propValue);
+ }
+ } catch (RemoteException ex) {
+ // ignore it
+ }
+ }
+
+ /**
+ * Store properties associated with SubscriptionInfo in database
+ * @param subId Subscription Id of Subscription
+ * @param propKey Column name in SubscriptionInfo database
+ * @return Value associated with subId and propKey column in database
+ * @hide
+ */
+ private static String getSubscriptionProperty(int subId, String propKey,
+ Context context) {
+ String resultValue = null;
+ try {
+ ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ if (iSub != null) {
+ resultValue = iSub.getSubscriptionProperty(subId, propKey,
+ context.getOpPackageName());
+ }
+ } catch (RemoteException ex) {
+ // ignore it
+ }
+ return resultValue;
+ }
+
+ /**
+ * Returns boolean value corresponding to query result.
+ * @param subId Subscription Id of Subscription
+ * @param propKey Column name in SubscriptionInfo database
+ * @param defValue Default boolean value to be returned
+ * @return boolean result value to be returned
+ * @hide
+ */
+ public static boolean getBooleanSubscriptionProperty(int subId, String propKey,
+ boolean defValue, Context context) {
+ String result = getSubscriptionProperty(subId, propKey, context);
+ if (result != null) {
+ try {
+ return Integer.parseInt(result) == 1;
+ } catch (NumberFormatException err) {
+ logd("getBooleanSubscriptionProperty NumberFormat exception");
+ }
+ }
+ return defValue;
+ }
+
+ /**
+ * Returns integer value corresponding to query result.
+ * @param subId Subscription Id of Subscription
+ * @param propKey Column name in SubscriptionInfo database
+ * @param defValue Default integer value to be returned
+ * @return integer result value to be returned
+ * @hide
+ */
+ public static int getIntegerSubscriptionProperty(int subId, String propKey, int defValue,
+ Context context) {
+ String result = getSubscriptionProperty(subId, propKey, context);
+ if (result != null) {
+ try {
+ return Integer.parseInt(result);
+ } catch (NumberFormatException err) {
+ logd("getBooleanSubscriptionProperty NumberFormat exception");
+ }
+ }
+ return defValue;
+ }
+
+ /**
+ * Returns the resources associated with Subscription.
+ * @param context Context object
+ * @param subId Subscription Id of Subscription who's resources are required
+ * @return Resources associated with Subscription.
+ * @hide
+ */
+ public static Resources getResourcesForSubId(Context context, int subId) {
+ final SubscriptionInfo subInfo =
+ SubscriptionManager.from(context).getActiveSubscriptionInfo(subId);
+
+ Configuration config = context.getResources().getConfiguration();
+ Configuration newConfig = new Configuration();
+ newConfig.setTo(config);
+ if (subInfo != null) {
+ newConfig.mcc = subInfo.getMcc();
+ newConfig.mnc = subInfo.getMnc();
+ }
+ DisplayMetrics metrics = context.getResources().getDisplayMetrics();
+ DisplayMetrics newMetrics = new DisplayMetrics();
+ newMetrics.setTo(metrics);
+ return new Resources(context.getResources().getAssets(), newMetrics, newConfig);
+ }
+
+ /**
* @return true if the sub ID is active. i.e. The sub ID corresponds to a known subscription
* and the SIM providing the subscription is present in a slot and in "LOADED" state.
* @hide
diff --git a/telephony/java/com/android/internal/telephony/ISub.aidl b/telephony/java/com/android/internal/telephony/ISub.aidl
index 0555121..f6aef08 100755
--- a/telephony/java/com/android/internal/telephony/ISub.aidl
+++ b/telephony/java/com/android/internal/telephony/ISub.aidl
@@ -172,6 +172,10 @@
int[] getActiveSubIdList();
+ void setSubscriptionProperty(int subId, String propKey, String propValue);
+
+ String getSubscriptionProperty(int subId, String propKey, String callingPackage);
+
/**
* Get the SIM state for the slot idx
* @return SIM state as the ordinal of IccCardConstants.State
diff --git a/tests/VoiceInteraction/res/layout/voice_interaction_session.xml b/tests/VoiceInteraction/res/layout/voice_interaction_session.xml
index 610f30b..dc4e31b 100644
--- a/tests/VoiceInteraction/res/layout/voice_interaction_session.xml
+++ b/tests/VoiceInteraction/res/layout/voice_interaction_session.xml
@@ -31,33 +31,56 @@
android:layout_height="match_parent"
android:fitsSystemWindows="true">
- <LinearLayout android:id="@+id/top_content"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_gravity="top"
- android:orientation="horizontal"
- android:background="#ffffffff"
- android:elevation="8dp"
- >
- <ImageView android:id="@+id/screenshot"
- android:layout_width="wrap_content"
- android:layout_height="46dp"
- android:adjustViewBounds="true" />
- <View android:layout_width="0dp"
- android:layout_height="0dp"
- android:layout_weight="1" />
- <Button android:id="@+id/do_tree"
- android:layout_width="wrap_content"
+ <LinearLayout
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:text="@string/tree" />
- <Button android:id="@+id/do_text"
- android:layout_width="wrap_content"
+ android:layout_gravity="top"
+ android:orientation="vertical"
+ android:background="#ffffffff"
+ android:elevation="8dp"
+ >
+ <LinearLayout android:id="@+id/top_content"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:text="@string/text" />
- <Button android:id="@+id/start"
- android:layout_width="wrap_content"
+ android:orientation="horizontal"
+ >
+ <ImageView android:id="@+id/screenshot"
+ android:layout_width="wrap_content"
+ android:layout_height="46dp"
+ android:adjustViewBounds="true" />
+ <View android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:layout_weight="1" />
+ <CheckBox android:id="@+id/show_options"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+ <Button android:id="@+id/do_tree"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/tree" />
+ <Button android:id="@+id/do_text"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/text" />
+ <Button android:id="@+id/start"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/start" />
+ </LinearLayout>
+ <LinearLayout android:id="@+id/options"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:text="@string/start" />
+ android:orientation="vertical"
+ >
+ <CheckBox android:id="@+id/disallow_structure"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Disallow context" />
+ <CheckBox android:id="@+id/disallow_screenshot"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Disallow screenshot" />
+ </LinearLayout>
</LinearLayout>
<LinearLayout android:id="@+id/bottom_content"
diff --git a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java
index a6585ba..8796c9f 100644
--- a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java
+++ b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java
@@ -29,6 +29,7 @@
import android.util.Log;
import android.view.View;
import android.widget.Button;
+import android.widget.CheckBox;
import android.widget.ImageView;
import android.widget.TextView;
@@ -45,6 +46,10 @@
Button mTreeButton;
Button mTextButton;
Button mStartButton;
+ CheckBox mOptionsCheck;
+ View mOptionsContainer;
+ CheckBox mDisallowAssist;
+ CheckBox mDisallowScreenshot;
ImageView mScreenshot;
ImageView mFullScreenshot;
Button mConfirmButton;
@@ -122,15 +127,34 @@
mScreenshot = (ImageView)mContentView.findViewById(R.id.screenshot);
mScreenshot.setOnClickListener(this);
mFullScreenshot = (ImageView)mContentView.findViewById(R.id.full_screenshot);
+ mOptionsCheck = (CheckBox)mContentView.findViewById(R.id.show_options);
+ mOptionsCheck.setOnClickListener(this);
+ mOptionsContainer = mContentView.findViewById(R.id.options);
+ mDisallowAssist = (CheckBox)mContentView.findViewById(R.id.disallow_structure);
+ mDisallowAssist.setOnClickListener(this);
+ mDisallowScreenshot = (CheckBox)mContentView.findViewById(R.id.disallow_screenshot);
+ mDisallowScreenshot.setOnClickListener(this);
mConfirmButton = (Button)mContentView.findViewById(R.id.confirm);
mConfirmButton.setOnClickListener(this);
mCompleteButton = (Button)mContentView.findViewById(R.id.complete);
mCompleteButton.setOnClickListener(this);
mAbortButton = (Button)mContentView.findViewById(R.id.abort);
mAbortButton.setOnClickListener(this);
+ refreshOptions();
return mContentView;
}
+ void refreshOptions() {
+ if (mOptionsCheck.isChecked()) {
+ mOptionsContainer.setVisibility(View.VISIBLE);
+ int flags = getDisabledShowContext();
+ mDisallowAssist.setChecked((flags & SHOW_WITH_ASSIST) != 0);
+ mDisallowScreenshot.setChecked((flags & SHOW_WITH_SCREENSHOT) != 0);
+ } else {
+ mOptionsContainer.setVisibility(View.GONE);
+ }
+ }
+
public void onHandleAssist(Bundle assistBundle) {
}
@@ -202,6 +226,24 @@
if (mAssistVisualizer != null) {
mAssistVisualizer.logText();
}
+ } else if (v == mOptionsCheck) {
+ refreshOptions();
+ } else if (v == mDisallowAssist) {
+ int flags = getDisabledShowContext();
+ if (mDisallowAssist.isChecked()) {
+ flags |= SHOW_WITH_ASSIST;
+ } else {
+ flags &= ~SHOW_WITH_ASSIST;
+ }
+ setDisabledShowContext(flags);
+ } else if (v == mDisallowScreenshot) {
+ int flags = getDisabledShowContext();
+ if (mDisallowScreenshot.isChecked()) {
+ flags |= SHOW_WITH_SCREENSHOT;
+ } else {
+ flags &= ~SHOW_WITH_SCREENSHOT;
+ }
+ setDisabledShowContext(flags);
} else if (v == mStartButton) {
mState = STATE_LAUNCHING;
updateState();
diff --git a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/TestInteractionActivity.java b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/TestInteractionActivity.java
index 2487e1ca..b0d6b39 100644
--- a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/TestInteractionActivity.java
+++ b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/TestInteractionActivity.java
@@ -103,6 +103,14 @@
}
};
mInteractor.submitRequest(mCurrentRequest, REQUEST_CONFIRM);
+ String[] cmds = new String[] {
+ "com.android.test.voiceinteraction.COMMAND",
+ "com.example.foo.bar"
+ };
+ boolean sup[] = mInteractor.supportsCommands(cmds);
+ for (int i=0; i<cmds.length; i++) {
+ mLog.append(cmds[i] + ": " + (sup[i] ? "SUPPORTED" : "NOT SUPPORTED") + "\n");
+ }
} else {
Log.i(TAG, "Restarting with active confirmation: " + mCurrentRequest);
}
diff --git a/tools/layoutlib/bridge/src/android/view/BridgeInflater.java b/tools/layoutlib/bridge/src/android/view/BridgeInflater.java
index 20b6e41..1e33e3a 100644
--- a/tools/layoutlib/bridge/src/android/view/BridgeInflater.java
+++ b/tools/layoutlib/bridge/src/android/view/BridgeInflater.java
@@ -25,6 +25,7 @@
import com.android.layoutlib.bridge.BridgeConstants;
import com.android.layoutlib.bridge.android.BridgeContext;
import com.android.layoutlib.bridge.android.BridgeXmlBlockParser;
+import com.android.layoutlib.bridge.android.support.DrawerLayoutUtil;
import com.android.layoutlib.bridge.android.support.RecyclerViewUtil;
import com.android.layoutlib.bridge.impl.ParserFactory;
import com.android.layoutlib.bridge.util.ReflectionUtils;
@@ -33,10 +34,13 @@
import org.xmlpull.v1.XmlPullParser;
+import android.annotation.NonNull;
import android.content.Context;
import android.util.AttributeSet;
import java.io.File;
+import java.util.HashMap;
+import java.util.Map;
import static com.android.layoutlib.bridge.android.BridgeContext.getBaseContext;
@@ -48,6 +52,7 @@
private final LayoutlibCallback mLayoutlibCallback;
private boolean mIsInMerge = false;
private ResourceReference mResourceReference;
+ private Map<View, String> mOpenDrawerLayouts;
/**
* List of class prefixes which are tried first by default.
@@ -256,7 +261,14 @@
resourceId = 0;
}
RecyclerViewUtil.setAdapter(view, bc, mLayoutlibCallback, resourceId);
+ } else if (ReflectionUtils.isInstanceOf(view, DrawerLayoutUtil.CN_DRAWER_LAYOUT)) {
+ String attrVal = attrs.getAttributeValue(BridgeConstants.NS_TOOLS_URI,
+ BridgeConstants.ATTR_OPEN_DRAWER);
+ if (attrVal != null) {
+ getDrawerLayoutMap().put(view, attrVal);
+ }
}
+
}
}
@@ -312,4 +324,28 @@
return viewKey;
}
+
+ public void postInflateProcess(View view) {
+ if (mOpenDrawerLayouts != null) {
+ String gravity = mOpenDrawerLayouts.get(view);
+ if (gravity != null) {
+ DrawerLayoutUtil.openDrawer(view, gravity);
+ }
+ mOpenDrawerLayouts.remove(view);
+ }
+ }
+
+ @NonNull
+ private Map<View, String> getDrawerLayoutMap() {
+ if (mOpenDrawerLayouts == null) {
+ mOpenDrawerLayouts = new HashMap<View, String>(4);
+ }
+ return mOpenDrawerLayouts;
+ }
+
+ public void onDoneInflation() {
+ if (mOpenDrawerLayouts != null) {
+ mOpenDrawerLayouts.clear();
+ }
+ }
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeConstants.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeConstants.java
index 661c08b9..6228766 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeConstants.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeConstants.java
@@ -50,6 +50,9 @@
public final static String FILL_PARENT = "fill_parent";
public final static String WRAP_CONTENT = "wrap_content";
+ // Should be kept in sync with LayoutMetadata.KEY_LV_ITEM in tools/adt/idea
/** Attribute in the tools namespace used to specify layout manager for RecyclerView. */
- public static final String ATTR_LIST_ITEM = "list_item";
+ @SuppressWarnings("SpellCheckingInspection")
+ public static final String ATTR_LIST_ITEM = "listitem";
+ public static final String ATTR_OPEN_DRAWER = "openDrawer";
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/support/DrawerLayoutUtil.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/support/DrawerLayoutUtil.java
new file mode 100644
index 0000000..40d3811
--- /dev/null
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/support/DrawerLayoutUtil.java
@@ -0,0 +1,63 @@
+/*
+ * 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.layoutlib.bridge.android.support;
+
+import com.android.ide.common.rendering.api.LayoutLog;
+import com.android.layoutlib.bridge.Bridge;
+import com.android.layoutlib.bridge.util.ReflectionUtils.ReflectionException;
+
+import android.annotation.Nullable;
+import android.view.View;
+
+import static android.view.Gravity.END;
+import static android.view.Gravity.LEFT;
+import static android.view.Gravity.RIGHT;
+import static android.view.Gravity.START;
+import static com.android.layoutlib.bridge.util.ReflectionUtils.getCause;
+import static com.android.layoutlib.bridge.util.ReflectionUtils.getMethod;
+import static com.android.layoutlib.bridge.util.ReflectionUtils.invoke;
+
+public class DrawerLayoutUtil {
+
+ public static final String CN_DRAWER_LAYOUT = "android.support.v4.widget.DrawerLayout";
+
+ public static void openDrawer(View drawerLayout, @Nullable String drawerGravity) {
+ int gravity = -1;
+ if ("left".equals(drawerGravity)) {
+ gravity = LEFT;
+ } else if ("right".equals(drawerGravity)) {
+ gravity = RIGHT;
+ } else if ("start".equals(drawerGravity)) {
+ gravity = START;
+ } else if ("end".equals(drawerGravity)) {
+ gravity = END;
+ }
+ if (gravity > 0) {
+ openDrawer(drawerLayout, gravity);
+ }
+ }
+
+ private static void openDrawer(View drawerLayout, int gravity) {
+ try {
+ invoke(getMethod(drawerLayout.getClass(), "openDrawer", int.class), drawerLayout,
+ gravity);
+ } catch (ReflectionException e) {
+ Bridge.getLog().error(LayoutLog.TAG_BROKEN, "Unable to open navigation drawer",
+ getCause(e), null);
+ }
+ }
+}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/support/RecyclerViewUtil.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/support/RecyclerViewUtil.java
index 4182cd9..d14c80b 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/support/RecyclerViewUtil.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/support/RecyclerViewUtil.java
@@ -21,6 +21,7 @@
import com.android.layoutlib.bridge.Bridge;
import com.android.layoutlib.bridge.android.BridgeContext;
import com.android.layoutlib.bridge.android.RenderParamsFlags;
+import com.android.layoutlib.bridge.util.ReflectionUtils;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -30,6 +31,7 @@
import java.lang.reflect.Method;
import static com.android.layoutlib.bridge.util.ReflectionUtils.ReflectionException;
+import static com.android.layoutlib.bridge.util.ReflectionUtils.getCause;
import static com.android.layoutlib.bridge.util.ReflectionUtils.getMethod;
import static com.android.layoutlib.bridge.util.ReflectionUtils.invoke;
@@ -70,11 +72,6 @@
}
}
- private static Throwable getCause(Throwable throwable) {
- Throwable cause = throwable.getCause();
- return cause == null ? throwable : cause;
- }
-
private static void setLayoutManager(@NonNull View recyclerView, @NonNull BridgeContext context,
@NonNull LayoutlibCallback callback) throws ReflectionException {
if (getLayoutManager(recyclerView) == null) {
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 72e97ad..23df3f1 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
@@ -423,6 +423,7 @@
// post-inflate process. For now this supports TabHost/TabWidget
postInflateProcess(view, params.getLayoutlibCallback(), isPreference ? view : null);
+ mInflater.onDoneInflation();
setActiveToolbar(view, context, params);
@@ -1342,6 +1343,7 @@
}
}
} else if (view instanceof ViewGroup) {
+ mInflater.postInflateProcess(view);
ViewGroup group = (ViewGroup) view;
final int count = group.getChildCount();
for (int c = 0; c < count; c++) {
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/util/ReflectionUtils.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/util/ReflectionUtils.java
index b78b613..7ce27b6 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/util/ReflectionUtils.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/util/ReflectionUtils.java
@@ -27,7 +27,7 @@
*/
public class ReflectionUtils {
- @Nullable
+ @NonNull
public static Method getMethod(@NonNull Class<?> clazz, @NonNull String name,
@Nullable Class<?>... params) throws ReflectionException {
try {
@@ -67,6 +67,12 @@
return false;
}
+ @NonNull
+ public static Throwable getCause(@NonNull Throwable throwable) {
+ Throwable cause = throwable.getCause();
+ return cause == null ? throwable : cause;
+ }
+
/**
* Wraps all reflection related exceptions. Created since ReflectiveOperationException was
* introduced in 1.7 and we are still on 1.6