diff options
14 files changed, 153 insertions, 30 deletions
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 @@ public class AppOpsManager { 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/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 @@ data-sortorder="-timestamp" data-cardsizes="9x3" data-maxresults="6"> </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/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 @@ public class SignalClusterView } 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/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 221e925..eb84e18 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 @@ public class PackageManagerService extends IPackageManager.Stub { } 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; @@ -15075,8 +15072,9 @@ public class PackageManagerService extends IPackageManager.Stub { } 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/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.File; 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 @@ public class PhoneWindowManager implements WindowManagerPolicy { 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..bc63c69 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 @@ public class WindowManagerService extends IWindowManager.Stub 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); } } @@ -2899,7 +2901,8 @@ public class WindowManagerService extends IWindowManager.Stub 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); } } } 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.Bridge; 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 com.android.util.Pair; 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 @@ public final class BridgeInflater extends LayoutInflater { 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 @@ public final class BridgeInflater extends LayoutInflater { 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 @@ public final class BridgeInflater extends LayoutInflater { 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 661c08b..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 class BridgeConstants { 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.ide.common.rendering.api.LayoutlibCallback; 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 android.view.View; 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 @@ public class RecyclerViewUtil { } } - 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 @@ public class RenderSessionImpl extends RenderAction<SessionParams> { // 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 @@ public class RenderSessionImpl extends RenderAction<SessionParams> { } } } 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 @@ import java.lang.reflect.Method; */ 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 @@ public class ReflectionUtils { 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 |