Merge "[AWARE] Remove Publish/Subscribe Count configuration" am: 5d81b9d67d am: 9bc8e05da2 am: 342a27e7f7
am: b36a9e0eb5
Change-Id: I0c4f93b03a73e169da7250b1cf7e5cc1269d4f07
diff --git a/api/current.txt b/api/current.txt
index 2ed183e..e4720d2 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -41077,9 +41077,9 @@
public static final class FontConfig.Font implements android.os.Parcelable {
method public int describeContents();
method public android.text.FontConfig.Axis[] getAxes();
- method public android.os.ParcelFileDescriptor getFd();
method public java.lang.String getFontName();
method public int getTtcIndex();
+ method public android.net.Uri getUri();
method public int getWeight();
method public boolean isItalic();
method public void writeToParcel(android.os.Parcel, int);
diff --git a/api/system-current.txt b/api/system-current.txt
index 9718b9b..0588855 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -44531,9 +44531,9 @@
public static final class FontConfig.Font implements android.os.Parcelable {
method public int describeContents();
method public android.text.FontConfig.Axis[] getAxes();
- method public android.os.ParcelFileDescriptor getFd();
method public java.lang.String getFontName();
method public int getTtcIndex();
+ method public android.net.Uri getUri();
method public int getWeight();
method public boolean isItalic();
method public void writeToParcel(android.os.Parcel, int);
diff --git a/api/test-current.txt b/api/test-current.txt
index cfbb7be..dc72d73 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -41284,9 +41284,9 @@
public static final class FontConfig.Font implements android.os.Parcelable {
method public int describeContents();
method public android.text.FontConfig.Axis[] getAxes();
- method public android.os.ParcelFileDescriptor getFd();
method public java.lang.String getFontName();
method public int getTtcIndex();
+ method public android.net.Uri getUri();
method public int getWeight();
method public boolean isItalic();
method public void writeToParcel(android.os.Parcel, int);
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index bace226..147b5d0 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -2740,6 +2740,10 @@
return true;
}
return false;
+ } else if (keyCode == KeyEvent.KEYCODE_TAB) {
+ // Don't consume TAB here since it's used for navigation. Arrow keys
+ // aren't considered "typing keys" so they already won't get consumed.
+ return false;
} else {
// Common code for DEFAULT_KEYS_DIALER & DEFAULT_KEYS_SEARCH_*
boolean clearSpannable = false;
diff --git a/core/java/android/companion/BluetoothDeviceFilterUtils.java b/core/java/android/companion/BluetoothDeviceFilterUtils.java
index 8a316f1..3665d1b 100644
--- a/core/java/android/companion/BluetoothDeviceFilterUtils.java
+++ b/core/java/android/companion/BluetoothDeviceFilterUtils.java
@@ -37,7 +37,7 @@
private BluetoothDeviceFilterUtils() {}
private static final boolean DEBUG = false;
- private static final String LOG_TAG = "BluetoothDeviceFilterUtil";
+ private static final String LOG_TAG = "BluetoothDeviceFilterUtils";
@Nullable
static String patternToString(@Nullable Pattern p) {
@@ -50,8 +50,10 @@
}
static boolean matches(ScanFilter filter, BluetoothDevice device) {
- return matchesAddress(filter.getDeviceAddress(), device)
+ boolean result = matchesAddress(filter.getDeviceAddress(), device)
&& matchesServiceUuid(filter.getServiceUuid(), filter.getServiceUuidMask(), device);
+ if (DEBUG) debugLogMatchResult(result, device, filter);
+ return result;
}
static boolean matchesAddress(String deviceAddress, BluetoothDevice device) {
diff --git a/core/java/android/companion/BluetoothLEDeviceFilter.java b/core/java/android/companion/BluetoothLEDeviceFilter.java
index 0444775..5a1b29d 100644
--- a/core/java/android/companion/BluetoothLEDeviceFilter.java
+++ b/core/java/android/companion/BluetoothLEDeviceFilter.java
@@ -31,6 +31,7 @@
import android.os.Parcel;
import android.provider.OneTimeUseBuilder;
import android.text.TextUtils;
+import android.util.Log;
import com.android.internal.util.BitUtils;
import com.android.internal.util.ObjectUtils;
@@ -47,6 +48,9 @@
*/
public final class BluetoothLEDeviceFilter implements DeviceFilter<ScanResult> {
+ private static final boolean DEBUG = false;
+ private static final String LOG_TAG = "BluetoothLEDeviceFilter";
+
private static final int RENAME_PREFIX_LENGTH_LIMIT = 10;
private final Pattern mNamePattern;
@@ -145,9 +149,13 @@
/** @hide */
@Override
public boolean matches(ScanResult device) {
- return matches(device.getDevice())
- && BitUtils.maskedEquals(device.getScanRecord().getBytes(),
- mRawDataFilter, mRawDataFilterMask);
+ boolean result = matches(device.getDevice())
+ && (mRawDataFilter == null
+ || BitUtils.maskedEquals(device.getScanRecord().getBytes(),
+ mRawDataFilter, mRawDataFilterMask));
+ if (DEBUG) Log.i(LOG_TAG, "matches(this = " + this + ", device = " + device +
+ ") -> " + result);
+ return result;
}
private boolean matches(BluetoothDevice device) {
diff --git a/core/java/android/hardware/camera2/params/StreamConfigurationMap.java b/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
index dbe1394..00e047d 100644
--- a/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
+++ b/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
@@ -1112,6 +1112,8 @@
return ImageFormat.DEPTH_POINT_CLOUD;
case HAL_PIXEL_FORMAT_Y16:
return ImageFormat.DEPTH16;
+ case HAL_PIXEL_FORMAT_RAW16:
+ return ImageFormat.RAW_DEPTH;
case ImageFormat.JPEG:
throw new IllegalArgumentException(
"ImageFormat.JPEG is an unknown internal format");
@@ -1179,6 +1181,8 @@
return HAL_PIXEL_FORMAT_BLOB;
case ImageFormat.DEPTH16:
return HAL_PIXEL_FORMAT_Y16;
+ case ImageFormat.RAW_DEPTH:
+ return HAL_PIXEL_FORMAT_RAW16;
default:
return format;
}
@@ -1220,6 +1224,7 @@
return HAL_DATASPACE_V0_JFIF;
case ImageFormat.DEPTH_POINT_CLOUD:
case ImageFormat.DEPTH16:
+ case ImageFormat.RAW_DEPTH:
return HAL_DATASPACE_DEPTH;
default:
return HAL_DATASPACE_UNKNOWN;
@@ -1609,6 +1614,8 @@
return "DEPTH16";
case ImageFormat.DEPTH_POINT_CLOUD:
return "DEPTH_POINT_CLOUD";
+ case ImageFormat.RAW_DEPTH:
+ return "RAW_DEPTH";
case ImageFormat.PRIVATE:
return "PRIVATE";
default:
diff --git a/core/java/android/hardware/radio/RadioManager.java b/core/java/android/hardware/radio/RadioManager.java
index 14bb923..58c3d24 100644
--- a/core/java/android/hardware/radio/RadioManager.java
+++ b/core/java/android/hardware/radio/RadioManager.java
@@ -196,6 +196,19 @@
return mIsCaptureSupported;
}
+ /**
+ * {@code true} if the module supports background scanning. At the given time it may not
+ * be available though, see {@link RadioTuner#startBackgroundScan()}.
+ *
+ * @return {@code true} if background scanning is supported (not necessary available
+ * at a given time), {@code false} otherwise.
+ *
+ * @hide FutureFeature
+ */
+ public boolean isBackgroundScanningSupported() {
+ return false;
+ }
+
/** List of descriptors for all bands supported by this module.
* @return an array of {@link BandDescriptor}.
*/
diff --git a/core/java/android/hardware/radio/RadioModule.java b/core/java/android/hardware/radio/RadioModule.java
index 8964893..033403a 100644
--- a/core/java/android/hardware/radio/RadioModule.java
+++ b/core/java/android/hardware/radio/RadioModule.java
@@ -79,6 +79,8 @@
public native int getProgramInformation(RadioManager.ProgramInfo[] info);
+ public native boolean startBackgroundScan();
+
public native @NonNull List<RadioManager.ProgramInfo> getProgramList(@Nullable String filter);
public native boolean isAntennaConnected();
diff --git a/core/java/android/hardware/radio/RadioTuner.java b/core/java/android/hardware/radio/RadioTuner.java
index c8034eb..1159d7d 100644
--- a/core/java/android/hardware/radio/RadioTuner.java
+++ b/core/java/android/hardware/radio/RadioTuner.java
@@ -212,6 +212,23 @@
public abstract int getProgramInformation(RadioManager.ProgramInfo[] info);
/**
+ * Initiates a background scan to update internally cached program list.
+ *
+ * It may not be necessary to initiate the scan explicitly - the scan MAY be performed on boot.
+ *
+ * The operation is asynchronous and {@link Callback} backgroundScanComplete or onError will
+ * be called if the return value of this call was {@code true}. As result of this call
+ * programListChanged may be triggered (if the scanned list differs).
+ *
+ * @return {@code true} if the scan was properly scheduled, {@code false} if the scan feature
+ * is unavailable; ie. temporarily due to ongoing foreground playback in single-tuner device
+ * or permanently if the feature is not supported
+ * (see ModuleProperties#isBackgroundScanningSupported()).
+ * @hide FutureFeature
+ */
+ public abstract boolean startBackgroundScan();
+
+ /**
* Get the list of discovered radio stations.
*
* To get the full list, set filter to null or empty string. Otherwise, client application
@@ -219,7 +236,8 @@
*
* @param filter vendor-specific selector for radio stations.
* @return a list of radio stations.
- * @throws IllegalStateException if the scan is in progress or has not been started.
+ * @throws IllegalStateException if the scan is in progress or has not been started,
+ * startBackgroundScan() call may fix it.
* @throws IllegalArgumentException if the filter argument is not valid.
* @hide FutureFeature
*/
@@ -317,6 +335,32 @@
* with control set to {@code true}.
*/
public void onControlChanged(boolean control) {}
+
+ /**
+ * onBackgroundScanAvailabilityChange() is called when background scan
+ * feature becomes available or not.
+ *
+ * @param isAvailable true, if the tuner turned temporarily background-
+ * capable, false in the other case.
+ * @hide FutureFeature
+ */
+ public void onBackgroundScanAvailabilityChange(boolean isAvailable) {}
+
+ /**
+ * Called when a background scan completes successfully.
+ *
+ * @hide FutureFeature
+ */
+ public void onBackgroundScanComplete() {}
+
+ /**
+ * Called when available program list changed.
+ *
+ * Use getProgramList() to get the actual list.
+ *
+ * @hide FutureFeature
+ */
+ public void onProgramListChanged() {}
}
}
diff --git a/core/java/android/text/FontConfig.java b/core/java/android/text/FontConfig.java
index 70f9bdd..14d3ad7 100644
--- a/core/java/android/text/FontConfig.java
+++ b/core/java/android/text/FontConfig.java
@@ -22,13 +22,11 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.graphics.FontListParser;
+import android.net.Uri;
import android.os.Parcel;
-import android.os.ParcelFileDescriptor;
import android.os.Parcelable;
-import java.io.IOException;
import java.lang.annotation.Retention;
-import java.util.Arrays;
/**
@@ -44,20 +42,6 @@
}
/**
- * For duplicating file descriptors.
- *
- * Note that this copy constructor can not be usable for deep copy.
- * @hide
- */
- public FontConfig(@NonNull FontConfig config) {
- mFamilies = new Family[config.mFamilies.length];
- for (int i = 0; i < config.mFamilies.length; ++i) {
- mFamilies[i] = new Family(config.mFamilies[i]);
- }
- mAliases = Arrays.copyOf(config.mAliases, config.mAliases.length);
- }
-
- /**
* Returns the ordered list of families included in the system fonts.
*/
public @NonNull Family[] getFamilies() {
@@ -174,7 +158,7 @@
private final @NonNull Axis[] mAxes;
private final int mWeight;
private final boolean mIsItalic;
- private @Nullable ParcelFileDescriptor mFd;
+ private Uri mUri;
/**
* @hide
@@ -186,29 +170,6 @@
mAxes = axes;
mWeight = weight;
mIsItalic = isItalic;
- mFd = null;
- }
-
- /**
- * This is for duplicating FileDescriptors.
- *
- * Note that this copy ctor doesn't deep copy the members.
- *
- * @hide
- */
- public Font(Font origin) {
- mFontName = origin.mFontName;
- mTtcIndex = origin.mTtcIndex;
- mAxes = origin.mAxes;
- mWeight = origin.mWeight;
- mIsItalic = origin.mIsItalic;
- if (origin.mFd != null) {
- try {
- mFd = origin.mFd.dup();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
}
/**
@@ -247,17 +208,20 @@
}
/**
- * Returns a file descriptor to access the specified font. This should be closed after use.
+ * Returns the content uri associated to this font.
+ *
+ * You can reach to the font contents by calling {@link
+ * android.content.ContentResolver#openInputStream}.
*/
- public @Nullable ParcelFileDescriptor getFd() {
- return mFd;
+ public @Nullable Uri getUri() {
+ return mUri;
}
/**
* @hide
*/
- public void setFd(@NonNull ParcelFileDescriptor fd) {
- mFd = fd;
+ public void setUri(@NonNull Uri uri) {
+ mUri = uri;
}
/**
@@ -269,11 +233,7 @@
mAxes = in.createTypedArray(Axis.CREATOR);
mWeight = in.readInt();
mIsItalic = in.readInt() == 1;
- if (in.readInt() == 1) { /* has FD */
- mFd = ParcelFileDescriptor.CREATOR.createFromParcel(in);
- } else {
- mFd = null;
- }
+ mUri = in.readTypedObject(Uri.CREATOR);
}
@Override
@@ -283,10 +243,7 @@
out.writeTypedArray(mAxes, flag);
out.writeInt(mWeight);
out.writeInt(mIsItalic ? 1 : 0);
- out.writeInt(mFd == null ? 0 : 1);
- if (mFd != null) {
- mFd.writeToParcel(out, flag);
- }
+ out.writeTypedObject(mUri, flag);
}
@Override
@@ -425,22 +382,6 @@
}
/**
- * For duplicating file descriptor underlying Font object.
- *
- * This copy constructor is not for deep copying.
- * @hide
- */
- public Family(Family origin) {
- mName = origin.mName;
- mLanguage = origin.mLanguage;
- mVariant = origin.mVariant;
- mFonts = new Font[origin.mFonts.length];
- for (int i = 0; i < origin.mFonts.length; ++i) {
- mFonts[i] = new Font(origin.mFonts[i]);
- }
- }
-
- /**
* Returns the name given by the system to this font family.
*/
public @Nullable String getName() {
diff --git a/core/java/android/view/FocusFinder.java b/core/java/android/view/FocusFinder.java
index 61c9201..ae1ee42 100644
--- a/core/java/android/view/FocusFinder.java
+++ b/core/java/android/view/FocusFinder.java
@@ -18,6 +18,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.content.pm.PackageManager;
import android.graphics.Rect;
import android.util.ArrayMap;
import android.util.SparseArray;
@@ -88,8 +89,9 @@
private View findNextFocus(ViewGroup root, View focused, Rect focusedRect, int direction) {
View next = null;
+ ViewGroup effectiveRoot = getEffectiveRoot(root, focused);
if (focused != null) {
- next = findNextUserSpecifiedFocus(root, focused, direction);
+ next = findNextUserSpecifiedFocus(effectiveRoot, focused, direction);
}
if (next != null) {
return next;
@@ -97,9 +99,9 @@
ArrayList<View> focusables = mTempList;
try {
focusables.clear();
- root.addFocusables(focusables, direction);
+ effectiveRoot.addFocusables(focusables, direction);
if (!focusables.isEmpty()) {
- next = findNextFocus(root, focused, focusedRect, direction, focusables);
+ next = findNextFocus(effectiveRoot, focused, focusedRect, direction, focusables);
}
} finally {
focusables.clear();
@@ -108,6 +110,35 @@
}
/**
+ * Returns the "effective" root of a view. The "effective" root is the closest ancestor
+ * within-which focus should cycle.
+ * <p>
+ * For example: normal focus navigation would stay within a ViewGroup marked as
+ * touchscreenBlocksFocus and keyboardNavigationCluster until a cluster-jump out.
+ * @return the "effective" root of {@param focused}
+ */
+ private ViewGroup getEffectiveRoot(ViewGroup root, View focused) {
+ if (focused == null) {
+ return root;
+ }
+ ViewParent effective = focused.getParent();
+ do {
+ if (effective == root) {
+ return root;
+ }
+ ViewGroup vg = (ViewGroup) effective;
+ if (vg.getTouchscreenBlocksFocus()
+ && focused.getContext().getPackageManager().hasSystemFeature(
+ PackageManager.FEATURE_TOUCHSCREEN)
+ && vg.isKeyboardNavigationCluster()) {
+ return vg;
+ }
+ effective = effective.getParent();
+ } while (effective != null);
+ return root;
+ }
+
+ /**
* Find the root of the next keyboard navigation cluster after the current one.
* @param root The view tree to look inside. Cannot be null
* @param currentCluster The starting point of the search. Null means the default cluster
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 3f52a9d..e924f77 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -61,6 +61,7 @@
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.hardware.display.DisplayManagerGlobal;
+import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
@@ -4170,14 +4171,14 @@
/**
* When this flag is used with {@link #DRAG_FLAG_GLOBAL}, the drag recipient will be able to
* request read access to the content URI(s) contained in the {@link ClipData} object.
- * @see android.content.Intent.FLAG_GRANT_READ_URI_PERMISSION
+ * @see android.content.Intent#FLAG_GRANT_READ_URI_PERMISSION
*/
public static final int DRAG_FLAG_GLOBAL_URI_READ = Intent.FLAG_GRANT_READ_URI_PERMISSION;
/**
* When this flag is used with {@link #DRAG_FLAG_GLOBAL}, the drag recipient will be able to
* request write access to the content URI(s) contained in the {@link ClipData} object.
- * @see android.content.Intent.FLAG_GRANT_WRITE_URI_PERMISSION
+ * @see android.content.Intent#FLAG_GRANT_WRITE_URI_PERMISSION
*/
public static final int DRAG_FLAG_GLOBAL_URI_WRITE = Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
@@ -4185,8 +4186,8 @@
* When this flag is used with {@link #DRAG_FLAG_GLOBAL_URI_READ} and/or {@link
* #DRAG_FLAG_GLOBAL_URI_WRITE}, the URI permission grant can be persisted across device
* reboots until explicitly revoked with
- * {@link android.content.Context#revokeUriPermission(Uri,int) Context.revokeUriPermission}.
- * @see android.content.Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION
+ * {@link android.content.Context#revokeUriPermission(Uri, int)} Context.revokeUriPermission}.
+ * @see android.content.Intent#FLAG_GRANT_PERSISTABLE_URI_PERMISSION
*/
public static final int DRAG_FLAG_GLOBAL_PERSISTABLE_URI_PERMISSION =
Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION;
@@ -4195,7 +4196,7 @@
* When this flag is used with {@link #DRAG_FLAG_GLOBAL_URI_READ} and/or {@link
* #DRAG_FLAG_GLOBAL_URI_WRITE}, the URI permission grant applies to any URI that is a prefix
* match against the original granted URI.
- * @see android.content.Intent.FLAG_GRANT_PREFIX_URI_PERMISSION
+ * @see android.content.Intent#FLAG_GRANT_PREFIX_URI_PERMISSION
*/
public static final int DRAG_FLAG_GLOBAL_PREFIX_URI_PERMISSION =
Intent.FLAG_GRANT_PREFIX_URI_PERMISSION;
@@ -7895,7 +7896,7 @@
* @param arguments A {@link Bundle} holding any arguments relevant for this request. May be
* {@code null} if the service provided no arguments.
*
- * @see AccessibilityNodeInfo#setExtraAvailableData
+ * @see AccessibilityNodeInfo#setAvailableExtraData(List)
*/
public void addExtraDataToAccessibilityNodeInfo(
@NonNull AccessibilityNodeInfo info, @NonNull String extraDataKey,
@@ -9839,7 +9840,7 @@
* Focus gets restored for a view hierarchy when the root of the hierarchy gets added to a
* window or serves as a target of cluster navigation.
*
- * @see #restoreDefaultFocus(int)
+ * @see #restoreDefaultFocus()
*
* @return {@code true} if this view is the default-focus view, {@code false} otherwise
* @attr ref android.R.styleable#View_focusedByDefault
@@ -9859,7 +9860,7 @@
* @param isFocusedByDefault {@code true} to set this view as the default-focus view,
* {@code false} otherwise.
*
- * @see #restoreDefaultFocus(int)
+ * @see #restoreDefaultFocus()
*
* @attr ref android.R.styleable#View_focusedByDefault
*/
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 7921938..c250226 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -1190,7 +1190,8 @@
final int focusableCount = views.size();
final int descendantFocusability = getDescendantFocusability();
- final boolean focusSelf = (isFocusableInTouchMode() || !shouldBlockFocusForTouchscreen());
+ final boolean blockFocusForTouchscreen = shouldBlockFocusForTouchscreen();
+ final boolean focusSelf = (isFocusableInTouchMode() || !blockFocusForTouchscreen);
if (descendantFocusability == FOCUS_BLOCK_DESCENDANTS) {
if (focusSelf) {
@@ -1199,7 +1200,7 @@
return;
}
- if (shouldBlockFocusForTouchscreen()) {
+ if (blockFocusForTouchscreen) {
focusableMode |= FOCUSABLES_TOUCH_MODE;
}
@@ -1234,7 +1235,19 @@
public void addKeyboardNavigationClusters(Collection<View> views, int direction) {
final int focusableCount = views.size();
- super.addKeyboardNavigationClusters(views, direction);
+ if (isKeyboardNavigationCluster()) {
+ // Cluster-navigation can enter a touchscreenBlocksFocus cluster, so temporarily
+ // disable touchscreenBlocksFocus to evaluate whether it contains focusables.
+ final boolean blockedFocus = getTouchscreenBlocksFocus();
+ try {
+ setTouchscreenBlocksFocusNoRefocus(false);
+ super.addKeyboardNavigationClusters(views, direction);
+ } finally {
+ setTouchscreenBlocksFocusNoRefocus(blockedFocus);
+ }
+ } else {
+ super.addKeyboardNavigationClusters(views, direction);
+ }
if (focusableCount != views.size()) {
// No need to look for groups inside a group.
@@ -1280,6 +1293,14 @@
}
}
+ private void setTouchscreenBlocksFocusNoRefocus(boolean touchscreenBlocksFocus) {
+ if (touchscreenBlocksFocus) {
+ mGroupFlags |= FLAG_TOUCHSCREEN_BLOCKS_FOCUS;
+ } else {
+ mGroupFlags &= ~FLAG_TOUCHSCREEN_BLOCKS_FOCUS;
+ }
+ }
+
/**
* Check whether this ViewGroup should ignore focus requests for itself and its children.
*/
@@ -1288,8 +1309,12 @@
}
boolean shouldBlockFocusForTouchscreen() {
+ // There is a special case for keyboard-navigation clusters. We allow cluster navigation
+ // to jump into blockFocusForTouchscreen ViewGroups which are clusters. Once in the
+ // cluster, focus is free to move around within it.
return getTouchscreenBlocksFocus() &&
- mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN);
+ mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN)
+ && (!hasFocus() || !isKeyboardNavigationCluster());
}
@Override
@@ -3175,6 +3200,21 @@
@TestApi
@Override
public boolean restoreFocusInCluster(@FocusRealDirection int direction) {
+ // Allow cluster-navigation to enter touchscreenBlocksFocus ViewGroups.
+ if (isKeyboardNavigationCluster()) {
+ final boolean blockedFocus = getTouchscreenBlocksFocus();
+ try {
+ setTouchscreenBlocksFocusNoRefocus(false);
+ return restoreFocusInClusterInternal(direction);
+ } finally {
+ setTouchscreenBlocksFocusNoRefocus(blockedFocus);
+ }
+ } else {
+ return restoreFocusInClusterInternal(direction);
+ }
+ }
+
+ private boolean restoreFocusInClusterInternal(@FocusRealDirection int direction) {
if (mFocusedInCluster != null && !mFocusedInCluster.isKeyboardNavigationCluster()
&& getDescendantFocusability() != FOCUS_BLOCK_DESCENDANTS
&& (mFocusedInCluster.mViewFlags & VISIBILITY_MASK) == VISIBLE
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 1937187..99b91bd 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -6873,9 +6873,11 @@
mTransientStateViews.put(position, scrap);
} else {
// Otherwise, we'll have to remove the view and start over.
+ clearScrapForRebind(scrap);
getSkippedScrap().add(scrap);
}
} else {
+ clearScrapForRebind(scrap);
if (mViewTypeCount == 1) {
mCurrentScrap.add(scrap);
} else {
@@ -7098,12 +7100,12 @@
}
} else if (params.scrappedFromPosition == position) {
final View scrap = scrapViews.remove(i);
- clearAccessibilityFromScrap(scrap);
+ clearScrapForRebind(scrap);
return scrap;
}
}
final View scrap = scrapViews.remove(size - 1);
- clearAccessibilityFromScrap(scrap);
+ clearScrapForRebind(scrap);
return scrap;
} else {
return null;
@@ -7117,7 +7119,7 @@
}
}
- private void clearAccessibilityFromScrap(View view) {
+ private void clearScrapForRebind(View view) {
view.clearAccessibilityFocus();
view.setAccessibilityDelegate(null);
}
diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java
index 1c0c4ef..12e35a1 100644
--- a/core/java/android/widget/ListView.java
+++ b/core/java/android/widget/ListView.java
@@ -1639,7 +1639,7 @@
final View focusChild = getAccessibilityFocusedChild(focusHost);
if (focusChild != null) {
if (!dataChanged || isDirectChildHeaderOrFooter(focusChild)
- || focusChild.hasTransientState() || mAdapterHasStableIds) {
+ || (focusChild.hasTransientState() && mAdapterHasStableIds)) {
// The views won't be changing, so try to maintain
// focus on the current host and virtual view.
accessibilityFocusLayoutRestoreView = focusHost;
diff --git a/core/java/android/widget/Toolbar.java b/core/java/android/widget/Toolbar.java
index 2eb50e0..bf3085d 100644
--- a/core/java/android/widget/Toolbar.java
+++ b/core/java/android/widget/Toolbar.java
@@ -343,6 +343,9 @@
final ViewGroup vgParent = (ViewGroup) parent;
if (vgParent.isKeyboardNavigationCluster()) {
setKeyboardNavigationCluster(false);
+ if (vgParent.getTouchscreenBlocksFocus()) {
+ setTouchscreenBlocksFocus(false);
+ }
break;
}
parent = vgParent.getParent();
diff --git a/core/java/com/android/internal/app/ToolbarActionBar.java b/core/java/com/android/internal/app/ToolbarActionBar.java
index 7ce5fc3..b3904f4 100644
--- a/core/java/com/android/internal/app/ToolbarActionBar.java
+++ b/core/java/com/android/internal/app/ToolbarActionBar.java
@@ -477,12 +477,9 @@
final KeyCharacterMap kmap = KeyCharacterMap.load(
event != null ? event.getDeviceId() : KeyCharacterMap.VIRTUAL_KEYBOARD);
menu.setQwertyMode(kmap.getKeyboardType() != KeyCharacterMap.NUMERIC);
- menu.performShortcut(keyCode, event, 0);
+ return menu.performShortcut(keyCode, event, 0);
}
- // This action bar always returns true for handling keyboard shortcuts.
- // This will block the window from preparing a temporary panel to handle
- // keyboard shortcuts.
- return true;
+ return false;
}
@Override
@@ -525,6 +522,17 @@
}
return result;
}
+
+ @Override
+ public View onCreatePanelView(int featureId) {
+ if (featureId == Window.FEATURE_OPTIONS_PANEL) {
+ // This gets called by PhoneWindow.preparePanel. Since this already manages
+ // its own panel, we return a dummy view here to prevent PhoneWindow from
+ // preparing a default one.
+ return new View(mDecorToolbar.getContext());
+ }
+ return super.onCreatePanelView(featureId);
+ }
}
private final class ActionMenuPresenterCallback implements MenuPresenter.Callback {
diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp
index 713287e..8a7d1cf 100644
--- a/core/jni/android_view_Surface.cpp
+++ b/core/jni/android_view_Surface.cpp
@@ -135,6 +135,7 @@
case PublicFormat::DEPTH16:
return HAL_PIXEL_FORMAT_Y16;
case PublicFormat::RAW_SENSOR:
+ case PublicFormat::RAW_DEPTH:
return HAL_PIXEL_FORMAT_RAW16;
default:
// Most formats map 1:1
@@ -149,6 +150,7 @@
return HAL_DATASPACE_V0_JFIF;
case PublicFormat::DEPTH_POINT_CLOUD:
case PublicFormat::DEPTH16:
+ case PublicFormat::RAW_DEPTH:
return HAL_DATASPACE_DEPTH;
case PublicFormat::RAW_SENSOR:
case PublicFormat::RAW_PRIVATE:
@@ -182,8 +184,12 @@
// Enums overlap in both name and value
return static_cast<PublicFormat>(format);
case HAL_PIXEL_FORMAT_RAW16:
- // Name differs, though value is the same
- return PublicFormat::RAW_SENSOR;
+ switch (dataSpace) {
+ case HAL_DATASPACE_DEPTH:
+ return PublicFormat::RAW_DEPTH;
+ default:
+ return PublicFormat::RAW_SENSOR;
+ }
case HAL_PIXEL_FORMAT_RAW_OPAQUE:
// Name differs, though value is the same
return PublicFormat::RAW_PRIVATE;
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index 6fbf49b..066ce68 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -167,7 +167,7 @@
buffer->getHeight(),
buffer->getPixelFormat(),
buffer->getUsage(),
- (void*)buffer.get());
+ (jlong)buffer.get());
}
static jobject nativeScreenshotBitmap(JNIEnv* env, jclass clazz,
diff --git a/core/jni/include/android_runtime/android_view_Surface.h b/core/jni/include/android_runtime/android_view_Surface.h
index 3f1bdff..d27c5a3 100644
--- a/core/jni/include/android_runtime/android_view_Surface.h
+++ b/core/jni/include/android_runtime/android_view_Surface.h
@@ -53,6 +53,7 @@
RGBA_1010102 = 0x2b,
JPEG = 0x100,
DEPTH_POINT_CLOUD = 0x101,
+ RAW_DEPTH = 0x1002, // @hide
YV12 = 0x32315659,
Y8 = 0x20203859, // @hide
Y16 = 0x20363159, // @hide
diff --git a/core/res/res/layout/screen_action_bar.xml b/core/res/res/layout/screen_action_bar.xml
index edcbb2b..4c1d6cb 100644
--- a/core/res/res/layout/screen_action_bar.xml
+++ b/core/res/res/layout/screen_action_bar.xml
@@ -35,6 +35,7 @@
android:layout_alignParentTop="true"
style="?attr/actionBarStyle"
android:transitionName="android:action_bar"
+ android:touchscreenBlocksFocus="true"
android:keyboardNavigationCluster="true"
android:gravity="top">
<com.android.internal.widget.ActionBarView
@@ -54,6 +55,7 @@
android:layout_height="wrap_content"
style="?attr/actionBarSplitStyle"
android:visibility="gone"
+ android:touchscreenBlocksFocus="true"
android:keyboardNavigationCluster="true"
android:gravity="center"/>
</com.android.internal.widget.ActionBarOverlayLayout>
diff --git a/core/res/res/layout/screen_toolbar.xml b/core/res/res/layout/screen_toolbar.xml
index 0bec8c4..ded2527 100644
--- a/core/res/res/layout/screen_toolbar.xml
+++ b/core/res/res/layout/screen_toolbar.xml
@@ -35,6 +35,7 @@
android:layout_alignParentTop="true"
style="?attr/actionBarStyle"
android:transitionName="android:action_bar"
+ android:touchscreenBlocksFocus="true"
android:keyboardNavigationCluster="true"
android:gravity="top">
<Toolbar
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index 25873d2..7dac18d 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -1249,6 +1249,7 @@
<item name="collapseContentDescription">@string/toolbar_collapse_description</item>
<item name="contentInsetStart">16dp</item>
<item name="contentInsetStartWithNavigation">@dimen/action_bar_content_inset_with_nav</item>
+ <item name="touchscreenBlocksFocus">true</item>
<item name="keyboardNavigationCluster">true</item>
</style>
diff --git a/graphics/java/android/graphics/FontListParser.java b/graphics/java/android/graphics/FontListParser.java
index b78df34..ff9f11d 100644
--- a/graphics/java/android/graphics/FontListParser.java
+++ b/graphics/java/android/graphics/FontListParser.java
@@ -189,9 +189,8 @@
skip(parser);
}
}
- String fullFilename = "/system/fonts/" +
- FILENAME_WHITESPACE_PATTERN.matcher(filename).replaceAll("");
- return new FontConfig.Font(fullFilename, index,
+ String sanitizedName = FILENAME_WHITESPACE_PATTERN.matcher(filename).replaceAll("");
+ return new FontConfig.Font(sanitizedName, index,
axes.toArray(new FontConfig.Axis[axes.size()]), weight, isItalic);
}
diff --git a/graphics/java/android/graphics/ImageFormat.java b/graphics/java/android/graphics/ImageFormat.java
index a226e85..e3527e3 100644
--- a/graphics/java/android/graphics/ImageFormat.java
+++ b/graphics/java/android/graphics/ImageFormat.java
@@ -662,6 +662,15 @@
public static final int DEPTH_POINT_CLOUD = 0x101;
/**
+ * Unprocessed implementation-dependent raw
+ * depth measurements, opaque with 16 bit
+ * samples.
+ *
+ * @hide
+ */
+ public static final int RAW_DEPTH = 0x1002;
+
+ /**
* Android private opaque image format.
* <p>
* The choices of the actual format and pixel data layout are entirely up to
@@ -723,6 +732,7 @@
return 24;
case FLEX_RGBA_8888:
return 32;
+ case RAW_DEPTH:
case RAW_SENSOR:
return 16;
case RAW10:
@@ -765,6 +775,7 @@
case DEPTH16:
case DEPTH_POINT_CLOUD:
case PRIVATE:
+ case RAW_DEPTH:
return true;
}
diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java
index 228d950..8c3a2e8 100644
--- a/graphics/java/android/graphics/Typeface.java
+++ b/graphics/java/android/graphics/Typeface.java
@@ -1003,21 +1003,22 @@
Map<String, ByteBuffer> bufferForPath) {
FontFamily fontFamily = new FontFamily(family.getLanguage(), family.getVariant());
for (FontConfig.Font font : family.getFonts()) {
- ByteBuffer fontBuffer = bufferForPath.get(font.getFontName());
+ String fullPathName = "/system/fonts/" + font.getFontName();
+ ByteBuffer fontBuffer = bufferForPath.get(fullPathName);
if (fontBuffer == null) {
- try (FileInputStream file = new FileInputStream(font.getFontName())) {
+ try (FileInputStream file = new FileInputStream(fullPathName)) {
FileChannel fileChannel = file.getChannel();
long fontSize = fileChannel.size();
fontBuffer = fileChannel.map(FileChannel.MapMode.READ_ONLY, 0, fontSize);
- bufferForPath.put(font.getFontName(), fontBuffer);
+ bufferForPath.put(fullPathName, fontBuffer);
} catch (IOException e) {
- Log.e(TAG, "Error mapping font file " + font.getFontName());
+ Log.e(TAG, "Error mapping font file " + fullPathName);
continue;
}
}
if (!fontFamily.addFontFromBuffer(fontBuffer, font.getTtcIndex(), font.getAxes(),
font.getWeight(), font.isItalic() ? Builder.ITALIC : Builder.NORMAL)) {
- Log.e(TAG, "Error creating font " + font.getFontName() + "#" + font.getTtcIndex());
+ Log.e(TAG, "Error creating font " + fullPathName + "#" + font.getTtcIndex());
}
}
fontFamily.freeze();
diff --git a/libs/hwui/VectorDrawable.cpp b/libs/hwui/VectorDrawable.cpp
index 8823a92..f6b2912 100644
--- a/libs/hwui/VectorDrawable.cpp
+++ b/libs/hwui/VectorDrawable.cpp
@@ -491,6 +491,36 @@
return *mCache.bitmap;
}
+void Tree::updateCache(sk_sp<SkSurface> surface) {
+ if (surface.get()) {
+ mCache.surface = surface;
+ }
+ if (surface.get() || mCache.dirty) {
+ SkSurface* vdSurface = mCache.surface.get();
+ SkCanvas* canvas = vdSurface->getCanvas();
+ float scaleX = vdSurface->width() / mProperties.getViewportWidth();
+ float scaleY = vdSurface->height() / mProperties.getViewportHeight();
+ SkAutoCanvasRestore acr(canvas, true);
+ canvas->clear(SK_ColorTRANSPARENT);
+ canvas->scale(scaleX, scaleY);
+ mRootNode->draw(canvas, false);
+ mCache.dirty = false;
+ canvas->flush();
+ }
+}
+
+void Tree::draw(SkCanvas* canvas) {
+ /*
+ * TODO address the following...
+ *
+ * 1) figure out how to set path's as volatile during animation
+ * 2) if mRoot->getPaint() != null either promote to layer (during
+ * animation) or cache in SkSurface (for static content)
+ */
+ canvas->drawImageRect(mCache.surface->makeImageSnapshot().get(),
+ mutateProperties()->getBounds(), getPaint());
+}
+
void Tree::updateBitmapCache(Bitmap& bitmap, bool useStagingData) {
SkBitmap outCache;
bitmap.getSkBitmap(&outCache);
diff --git a/libs/hwui/VectorDrawable.h b/libs/hwui/VectorDrawable.h
index 729a4dd..22cfe29 100644
--- a/libs/hwui/VectorDrawable.h
+++ b/libs/hwui/VectorDrawable.h
@@ -31,6 +31,7 @@
#include <SkPathMeasure.h>
#include <SkRect.h>
#include <SkShader.h>
+#include <SkSurface.h>
#include <cutils/compiler.h>
#include <stddef.h>
@@ -677,15 +678,37 @@
// This should only be called from animations on RT
TreeProperties* mutateProperties() { return &mProperties; }
+ // called from RT only
+ const TreeProperties& properties() const { return mProperties; }
+
// This should always be called from RT.
void markDirty() { mCache.dirty = true; }
bool isDirty() const { return mCache.dirty; }
bool getPropertyChangeWillBeConsumed() const { return mWillBeConsumed; }
void setPropertyChangeWillBeConsumed(bool willBeConsumed) { mWillBeConsumed = willBeConsumed; }
+ // Returns true if VD cache surface is big enough. This should always be called from RT and it
+ // works with Skia pipelines only.
+ bool canReuseSurface() {
+ SkSurface* surface = mCache.surface.get();
+ return surface && surface->width() >= mProperties.getScaledWidth()
+ && surface->height() >= mProperties.getScaledHeight();
+ }
+
+ // Draws VD cache into a canvas. This should always be called from RT and it works with Skia
+ // pipelines only.
+ void draw(SkCanvas* canvas);
+
+ // Draws VD into a GPU backed surface. If canReuseSurface returns false, then "surface" must
+ // contain a new surface. This should always be called from RT and it works with Skia pipelines
+ // only.
+ void updateCache(sk_sp<SkSurface> surface);
+
private:
struct Cache {
- sk_sp<Bitmap> bitmap;
+ sk_sp<Bitmap> bitmap; //used by HWUI pipeline and software
+ //TODO: use surface instead of bitmap when drawing in software canvas
+ sk_sp<SkSurface> surface; //used only by Skia pipelines
bool dirty = true;
};
diff --git a/libs/hwui/pipeline/skia/SkiaDisplayList.cpp b/libs/hwui/pipeline/skia/SkiaDisplayList.cpp
index 496f7ba..3ddc09f 100644
--- a/libs/hwui/pipeline/skia/SkiaDisplayList.cpp
+++ b/libs/hwui/pipeline/skia/SkiaDisplayList.cpp
@@ -19,6 +19,7 @@
#include "renderthread/CanvasContext.h"
#include "VectorDrawable.h"
#include "DumpOpsCanvas.h"
+#include "SkiaPipeline.h"
#include <SkImagePriv.h>
@@ -92,6 +93,8 @@
// If any vector drawable in the display list needs update, damage the node.
if (vectorDrawable->isDirty()) {
isDirty = true;
+ static_cast<SkiaPipeline*>(info.canvasContext.getRenderPipeline())
+ ->getVectorDrawables()->push_back(vectorDrawable);
}
vectorDrawable->setPropertyChangeWillBeConsumed(true);
}
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.cpp b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
index 10c1865..75f1adc 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
@@ -25,6 +25,7 @@
#include <SkPictureRecorder.h>
#include <SkPixelSerializer.h>
#include <SkStream.h>
+#include "VectorDrawable.h"
#include <unistd.h>
@@ -40,7 +41,9 @@
Vector3 SkiaPipeline::mLightCenter = {FLT_MIN, FLT_MIN, FLT_MIN};
-SkiaPipeline::SkiaPipeline(RenderThread& thread) : mRenderThread(thread) { }
+SkiaPipeline::SkiaPipeline(RenderThread& thread) : mRenderThread(thread) {
+ mVectorDrawables.reserve(30);
+}
TaskManager* SkiaPipeline::getTaskManager() {
return &mTaskManager;
@@ -74,6 +77,7 @@
const BakedOpRenderer::LightInfo& lightInfo) {
updateLighting(lightGeometry, lightInfo);
ATRACE_NAME("draw layers");
+ renderVectorDrawableCache();
renderLayersImpl(*layerUpdateQueue, opaque);
layerUpdateQueue->clear();
}
@@ -176,10 +180,35 @@
}
};
+void SkiaPipeline::renderVectorDrawableCache() {
+ //render VectorDrawables into offscreen buffers
+ for (auto vd : mVectorDrawables) {
+ sk_sp<SkSurface> surface;
+ if (!vd->canReuseSurface()) {
+#ifndef ANDROID_ENABLE_LINEAR_BLENDING
+ sk_sp<SkColorSpace> colorSpace = nullptr;
+#else
+ sk_sp<SkColorSpace> colorSpace = SkColorSpace::MakeSRGB();
+#endif
+ int scaledWidth = SkScalarCeilToInt(vd->properties().getScaledWidth());
+ int scaledHeight = SkScalarCeilToInt(vd->properties().getScaledHeight());
+ SkImageInfo info = SkImageInfo::MakeN32(scaledWidth, scaledHeight,
+ kPremul_SkAlphaType, colorSpace);
+ SkASSERT(mRenderThread.getGrContext() != nullptr);
+ surface = SkSurface::MakeRenderTarget(mRenderThread.getGrContext(), SkBudgeted::kYes,
+ info);
+ }
+ vd->updateCache(surface);
+ }
+ mVectorDrawables.clear();
+}
+
void SkiaPipeline::renderFrame(const LayerUpdateQueue& layers, const SkRect& clip,
const std::vector<sp<RenderNode>>& nodes, bool opaque, const Rect &contentDrawBounds,
sk_sp<SkSurface> surface) {
+ renderVectorDrawableCache();
+
// draw all layers up front
renderLayersImpl(layers, opaque);
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.h b/libs/hwui/pipeline/skia/SkiaPipeline.h
index c58fedf..6f5e719 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.h
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.h
@@ -49,6 +49,8 @@
const std::vector< sp<RenderNode> >& nodes, bool opaque, const Rect &contentDrawBounds,
sk_sp<SkSurface> surface);
+ std::vector<VectorDrawableRoot*>* getVectorDrawables() { return &mVectorDrawables; }
+
static void destroyLayer(RenderNode* node);
static void prepareToDraw(const renderthread::RenderThread& thread, Bitmap* bitmap);
@@ -119,8 +121,18 @@
const std::vector< sp<RenderNode> >& nodes, const Rect &contentDrawBounds,
sk_sp<SkSurface>);
+ /**
+ * Render mVectorDrawables into offscreen buffers.
+ */
+ void renderVectorDrawableCache();
+
TaskManager mTaskManager;
std::vector<sk_sp<SkImage>> mPinnedImages;
+
+ /**
+ * populated by prepareTree with dirty VDs
+ */
+ std::vector<VectorDrawableRoot*> mVectorDrawables;
static float mLightRadius;
static uint8_t mAmbientShadowAlpha;
static uint8_t mSpotShadowAlpha;
diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
index 559d268..27edc25 100644
--- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
+++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
@@ -126,22 +126,7 @@
return SkRect::MakeLargest();
}
virtual void onDraw(SkCanvas* canvas) override {
- Bitmap& hwuiBitmap = mRoot->getBitmapUpdateIfDirty();
- SkBitmap bitmap;
- hwuiBitmap.getSkBitmap(&bitmap);
- SkPaint* paint = mRoot->getPaint();
- canvas->drawBitmapRect(bitmap, mRoot->mutateProperties()->getBounds(), paint);
- /*
- * TODO we can draw this directly but need to address the following...
- *
- * 1) Add drawDirect(SkCanvas*) to VectorDrawableRoot
- * 2) fix VectorDrawable.cpp's Path::draw to not make a temporary path
- * so that we don't break caching
- * 3) figure out how to set path's as volatile during animation
- * 4) if mRoot->getPaint() != null either promote to layer (during
- * animation) or cache in SkSurface (for static content)
- *
- */
+ mRoot->draw(canvas);
}
private:
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index 738c091..33eda96 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -194,6 +194,8 @@
void waitOnFences();
+ IRenderPipeline* getRenderPipeline() { return mRenderPipeline.get(); }
+
private:
CanvasContext(RenderThread& thread, bool translucent, RenderNode* rootRenderNode,
IContextFactory* contextFactory, std::unique_ptr<IRenderPipeline> renderPipeline);
diff --git a/libs/hwui/tests/unit/SkiaBehaviorTests.cpp b/libs/hwui/tests/unit/SkiaBehaviorTests.cpp
index 7ae58a6..e15f5d9 100644
--- a/libs/hwui/tests/unit/SkiaBehaviorTests.cpp
+++ b/libs/hwui/tests/unit/SkiaBehaviorTests.cpp
@@ -17,6 +17,7 @@
#include "tests/common/TestUtils.h"
#include <gtest/gtest.h>
+#include <SkBlurDrawLooper.h>
#include <SkColorMatrixFilter.h>
#include <SkColorSpace.h>
#include <SkImagePriv.h>
@@ -95,3 +96,16 @@
sk_sp<SkColorSpace> sRGB2 = SkColorSpace::MakeSRGB();
ASSERT_EQ(sRGB1.get(), sRGB2.get());
}
+
+TEST(SkiaBehavior, blurDrawLooper) {
+ sk_sp<SkDrawLooper> looper = SkBlurDrawLooper::Make(SK_ColorRED, 5.0f, 3.0f, 4.0f);
+
+ SkDrawLooper::BlurShadowRec blur;
+ bool success = looper->asABlurShadow(&blur);
+ ASSERT_TRUE(success);
+
+ ASSERT_EQ(SK_ColorRED, blur.fColor);
+ ASSERT_EQ(5.0f, blur.fSigma);
+ ASSERT_EQ(3.0f, blur.fOffset.fX);
+ ASSERT_EQ(4.0f, blur.fOffset.fY);
+}
diff --git a/media/java/android/media/ImageUtils.java b/media/java/android/media/ImageUtils.java
index abf6b20..2a0e04e 100644
--- a/media/java/android/media/ImageUtils.java
+++ b/media/java/android/media/ImageUtils.java
@@ -62,6 +62,7 @@
case ImageFormat.RAW12:
case ImageFormat.DEPTH16:
case ImageFormat.DEPTH_POINT_CLOUD:
+ case ImageFormat.RAW_DEPTH:
return 1;
case ImageFormat.PRIVATE:
return 0;
@@ -103,6 +104,10 @@
throw new IllegalArgumentException(
"Copy of RAW_OPAQUE format has not been implemented");
}
+ if (src.getFormat() == ImageFormat.RAW_DEPTH) {
+ throw new IllegalArgumentException(
+ "Copy of RAW_DEPTH format has not been implemented");
+ }
if (!(dst.getOwner() instanceof ImageWriter)) {
throw new IllegalArgumentException("Destination image is not from ImageWriter. Only"
+ " the images from ImageWriter are writable");
@@ -206,6 +211,7 @@
case PixelFormat.RGB_565:
case ImageFormat.YUY2:
case ImageFormat.Y16:
+ case ImageFormat.RAW_DEPTH:
case ImageFormat.RAW_SENSOR:
case ImageFormat.RAW_PRIVATE: // round estimate, real size is unknown
case ImageFormat.DEPTH16:
@@ -253,6 +259,7 @@
case ImageFormat.RAW_SENSOR:
case ImageFormat.RAW10:
case ImageFormat.RAW12:
+ case ImageFormat.RAW_DEPTH:
return new Size(image.getWidth(), image.getHeight());
case ImageFormat.PRIVATE:
return new Size(0, 0);
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java
index 1b6aca1..227d804 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java
@@ -110,6 +110,11 @@
private final ScanCallback mBLEScanCallback = new ScanCallback() {
@Override
public void onScanResult(int callbackType, ScanResult result) {
+ if (DEBUG) {
+ Log.i(LOG_TAG,
+ "BLE.onScanResult(callbackType = " + callbackType + ", result = " + result
+ + ")");
+ }
final DeviceFilterPair<ScanResult> deviceFilterPair
= DeviceFilterPair.findMatch(result, mBLEFilters);
if (deviceFilterPair == null) return;
@@ -126,6 +131,10 @@
private BroadcastReceiver mBluetoothDeviceFoundBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
+ if (DEBUG) {
+ Log.i(LOG_TAG,
+ "BL.onReceive(context = " + context + ", intent = " + intent + ")");
+ }
final BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
final DeviceFilterPair<BluetoothDevice> deviceFilterPair
= DeviceFilterPair.findMatch(device, mBluetoothFilters);
@@ -191,7 +200,10 @@
mBLEScanFilters = CollectionUtils.map(mBLEFilters, BluetoothLEDeviceFilter::getScanFilter);
reset();
- }
+ } else if (DEBUG) Log.i(LOG_TAG, "startDiscovery: duplicate request: " + request);
+
+
+
if (!ArrayUtils.isEmpty(mDevicesFound)) {
onReadyToShowUI();
}
@@ -221,6 +233,7 @@
}
private void reset() {
+ if (DEBUG) Log.i(LOG_TAG, "reset()");
mDevicesFound.clear();
mSelectedDevice = null;
mDevicesAdapter.notifyDataSetChanged();
@@ -369,8 +382,15 @@
public static <T extends Parcelable> DeviceFilterPair<T> findMatch(
T dev, @Nullable List<? extends DeviceFilter<T>> filters) {
if (isEmpty(filters)) return new DeviceFilterPair<>(dev, null);
- final DeviceFilter<T> matchingFilter = CollectionUtils.find(filters, (f) -> f.matches(dev));
- return matchingFilter != null ? new DeviceFilterPair<>(dev, matchingFilter) : null;
+ final DeviceFilter<T> matchingFilter
+ = CollectionUtils.find(filters, f -> f.matches(dev));
+
+ DeviceFilterPair<T> result = matchingFilter != null
+ ? new DeviceFilterPair<>(dev, matchingFilter)
+ : null;
+ if (DEBUG) Log.i(LOG_TAG, "findMatch(dev = " + dev + ", filters = " + filters +
+ ") -> " + result);
+ return result;
}
public String getDisplayName() {
diff --git a/packages/PrintSpooler/src/com/android/printspooler/model/RemotePrintDocument.java b/packages/PrintSpooler/src/com/android/printspooler/model/RemotePrintDocument.java
index 187e35a..f11a9cd 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/model/RemotePrintDocument.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/model/RemotePrintDocument.java
@@ -113,12 +113,14 @@
}
// Notify we are done.
mState = STATE_UPDATED;
+ mDocumentInfo.updated = true;
notifyUpdateCompleted();
}
}
} else {
// We always notify after a write.
mState = STATE_UPDATED;
+ mDocumentInfo.updated = true;
notifyUpdateCompleted();
}
runPendingCommand();
@@ -229,6 +231,7 @@
mDocumentInfo, oldAttributes, attributes, preview, mCommandResultCallback);
scheduleCommand(command);
+ mDocumentInfo.updated = false;
mState = STATE_UPDATING;
// If no layout in progress and we don't have all pages - schedule a write.
} else if ((!(mCurrentCommand instanceof LayoutCommand)
@@ -249,6 +252,7 @@
mDocumentInfo.fileProvider, mCommandResultCallback);
scheduleCommand(command);
+ mDocumentInfo.updated = false;
mState = STATE_UPDATING;
} else {
willUpdate = false;
@@ -396,7 +400,7 @@
private void notifyUpdateFailed(CharSequence error) {
if (DEBUG) {
- Log.i(LOG_TAG, "[CALLING] onUpdateCompleted()");
+ Log.i(LOG_TAG, "[CALLING] notifyUpdateFailed()");
}
mUpdateCallbacks.onUpdateFailed(error);
}
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
index f6df995..4cce166 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
@@ -491,8 +491,6 @@
setState(STATE_UPDATE_FAILED);
- updateOptionsUi();
-
mPrintedDocument.kill(message);
}
@@ -502,7 +500,6 @@
&& canUpdateDocument() && updateDocument(true)) {
ensurePreviewUiShown();
setState(STATE_CONFIGURING);
- updateOptionsUi();
}
}
@@ -579,7 +576,6 @@
updatePrintPreviewController(document.changed);
setState(STATE_CONFIGURING);
- updateOptionsUi();
} break;
}
}
@@ -600,8 +596,6 @@
}
setState(STATE_UPDATE_FAILED);
-
- updateOptionsUi();
}
@Override
@@ -734,7 +728,6 @@
updateOptionsUi();
} else {
setState(STATE_CREATE_FILE_FAILED);
- updateOptionsUi();
// Calling finish here does not invoke lifecycle callbacks but we
// update the print job in onPause if finishing, hence post a message.
mDestinationSpinner.post(new Runnable() {
@@ -958,12 +951,14 @@
Log.i(LOG_TAG, "[state]" + state);
}
mState = state;
+ updateOptionsUi();
}
} else {
if (DEBUG) {
Log.i(LOG_TAG, "[state]" + state);
}
mState = state;
+ updateOptionsUi();
}
}
@@ -1230,6 +1225,7 @@
final boolean willUpdate = mPrintedDocument.update(mPrintJob.getAttributes(),
pages, preview);
+ updateOptionsUi();
if (willUpdate && !mPrintedDocument.hasLaidOutPages()) {
// When the update is done we update the print preview.
@@ -1254,7 +1250,6 @@
private void cancelPrint() {
setState(STATE_PRINT_CANCELED);
- updateOptionsUi();
mPrintedDocument.cancel(true);
doFinish();
}
@@ -1274,7 +1269,6 @@
private void confirmPrint() {
setState(STATE_PRINT_CONFIRMED);
- updateOptionsUi();
addCurrentPrinterToHistory();
setUserPrinted();
@@ -1629,6 +1623,8 @@
// Always update the summary.
updateSummary();
+ mDestinationSpinner.setEnabled(!isFinalState(mState));
+
if (mState == STATE_PRINT_CONFIRMED
|| mState == STATE_PRINT_COMPLETED
|| mState == STATE_PRINT_CANCELED
@@ -1636,9 +1632,6 @@
|| mState == STATE_CREATE_FILE_FAILED
|| mState == STATE_PRINTER_UNAVAILABLE
|| mState == STATE_UPDATE_SLOW) {
- if (mState != STATE_PRINTER_UNAVAILABLE) {
- mDestinationSpinner.setEnabled(false);
- }
disableOptionsUi(isFinalState(mState));
return;
}
@@ -1927,7 +1920,7 @@
mPrintButton.setImageResource(R.drawable.ic_menu_savetopdf);
mPrintButton.setContentDescription(getString(R.string.savetopdf_button));
}
- if (!mPrintedDocument.getDocumentInfo().laidout
+ if (!mPrintedDocument.getDocumentInfo().updated
||(mRangeOptionsSpinner.getSelectedItemPosition() == 1
&& (TextUtils.isEmpty(mPageRangeEditText.getText()) || hasErrors()))
|| (mRangeOptionsSpinner.getSelectedItemPosition() == 0
@@ -2048,7 +2041,6 @@
updateDocument(false);
}
ensurePreviewUiShown();
- updateOptionsUi();
}
}
@@ -2058,7 +2050,6 @@
mPrintedDocument.cancel(false);
ensureErrorUiShown(getString(R.string.print_error_printer_unavailable),
PrintErrorFragment.ACTION_NONE);
- updateOptionsUi();
}
}
@@ -3038,7 +3029,6 @@
if (mState == STATE_UPDATE_SLOW) {
setState(STATE_UPDATE_SLOW);
ensureProgressUiShown();
- updateOptionsUi();
return;
} else if (mPosted) {
@@ -3080,7 +3070,6 @@
mPreviousState = mState;
setState(STATE_UPDATE_SLOW);
ensureProgressUiShown();
- updateOptionsUi();
}
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/SuggestionParser.java b/packages/SettingsLib/src/com/android/settingslib/SuggestionParser.java
index 4b0ab59..b54d7e20 100644
--- a/packages/SettingsLib/src/com/android/settingslib/SuggestionParser.java
+++ b/packages/SettingsLib/src/com/android/settingslib/SuggestionParser.java
@@ -106,11 +106,11 @@
public SuggestionParser(
Context context, SharedPreferences sharedPrefs, int orderXml, String smartDismissControl) {
- mContext = context;
- mSuggestionList = (List<SuggestionCategory>) new SuggestionOrderInflater(mContext)
- .parse(orderXml);
- mSharedPrefs = sharedPrefs;
- mSmartDismissControl = smartDismissControl;
+ this(
+ context,
+ sharedPrefs,
+ (List<SuggestionCategory>) new SuggestionOrderInflater(context).parse(orderXml),
+ smartDismissControl);
}
public SuggestionParser(Context context, SharedPreferences sharedPrefs, int orderXml) {
@@ -118,12 +118,15 @@
}
@VisibleForTesting
- public SuggestionParser(Context context, SharedPreferences sharedPrefs) {
+ public SuggestionParser(
+ Context context,
+ SharedPreferences sharedPrefs,
+ List<SuggestionCategory> suggestionList,
+ String smartDismissControl) {
mContext = context;
- mSuggestionList = new ArrayList<SuggestionCategory>();
+ mSuggestionList = suggestionList;
mSharedPrefs = sharedPrefs;
- mSmartDismissControl = DEFAULT_SMART_DISMISS_CONTROL;
- Log.wtf(TAG, "Only use this constructor for testing");
+ mSmartDismissControl = smartDismissControl;
}
public List<Tile> getSuggestions() {
@@ -134,7 +137,19 @@
List<Tile> suggestions = new ArrayList<>();
final int N = mSuggestionList.size();
for (int i = 0; i < N; i++) {
- readSuggestions(mSuggestionList.get(i), suggestions, isSmartSuggestionEnabled);
+ final SuggestionCategory category = mSuggestionList.get(i);
+ if (category.exclusive) {
+ // If suggestions from an exclusive category are present, parsing is stopped
+ // and only suggestions from that category are displayed. Note that subsequent
+ // exclusive categories are also ignored.
+ List<Tile> exclusiveSuggestions = new ArrayList<>();
+ readSuggestions(category, exclusiveSuggestions, isSmartSuggestionEnabled);
+ if (!exclusiveSuggestions.isEmpty()) {
+ return exclusiveSuggestions;
+ }
+ } else {
+ readSuggestions(category, suggestions, isSmartSuggestionEnabled);
+ }
}
return suggestions;
}
@@ -368,6 +383,7 @@
public String category;
public String pkg;
public boolean multiple;
+ public boolean exclusive;
}
private static class SuggestionOrderInflater {
@@ -377,6 +393,7 @@
private static final String ATTR_CATEGORY = "category";
private static final String ATTR_PACKAGE = "package";
private static final String ATTR_MULTIPLE = "multiple";
+ private static final String ATTR_EXCLUSIVE = "exclusive";
private final Context mContext;
@@ -451,6 +468,9 @@
category.pkg = attrs.getAttributeValue(null, ATTR_PACKAGE);
String multiple = attrs.getAttributeValue(null, ATTR_MULTIPLE);
category.multiple = !TextUtils.isEmpty(multiple) && Boolean.parseBoolean(multiple);
+ String exclusive = attrs.getAttributeValue(null, ATTR_EXCLUSIVE);
+ category.exclusive =
+ !TextUtils.isEmpty(exclusive) && Boolean.parseBoolean(exclusive);
return category;
} else {
throw new IllegalArgumentException("Unknown item " + name);
diff --git a/packages/SettingsLib/tests/robotests/res/xml/suggestion_ordering.xml b/packages/SettingsLib/tests/robotests/res/xml/suggestion_ordering.xml
index 1eeafba..0e2ce3b 100644
--- a/packages/SettingsLib/tests/robotests/res/xml/suggestion_ordering.xml
+++ b/packages/SettingsLib/tests/robotests/res/xml/suggestion_ordering.xml
@@ -15,6 +15,8 @@
-->
<optional-steps>
+ <step category="com.android.settings.suggested.category.DEFERRED_SETUP"
+ exclusive="true" />
<step category="com.android.settings.suggested.category.LOCK_SCREEN" />
<step category="com.android.settings.suggested.category.EMAIL" />
<step category="com.android.settings.suggested.category.PARTNER_ACCOUNT"
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/SuggestionParserTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/SuggestionParserTest.java
index 7729dec..d534180 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/SuggestionParserTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/SuggestionParserTest.java
@@ -16,11 +16,12 @@
package com.android.settingslib;
+import static com.google.common.truth.Truth.assertThat;
+
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
-import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.os.Bundle;
import android.preference.PreferenceManager;
@@ -31,59 +32,59 @@
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
+import org.robolectric.res.ResourceLoader;
+import org.robolectric.res.builder.DefaultPackageManager;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
-import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyInt;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.when;
-
@RunWith(SettingLibRobolectricTestRunner.class)
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
public class SuggestionParserTest {
- @Mock
- private PackageManager mPackageManager;
private Context mContext;
private SuggestionParser mSuggestionParser;
- private SuggestionParser.SuggestionCategory mSuggestioCategory;
+ private SuggestionParser.SuggestionCategory mMultipleCategory;
+ private SuggestionParser.SuggestionCategory mExclusiveCategory;
private List<Tile> mSuggestionsBeforeDismiss;
private List<Tile> mSuggestionsAfterDismiss;
private SharedPreferences mPrefs;
private Tile mSuggestion;
- private List<ResolveInfo> mInfo;
@Before
public void setUp() {
- MockitoAnnotations.initMocks(this);
- mContext = spy(RuntimeEnvironment.application);
- when(mContext.getPackageManager()).thenReturn(mPackageManager);
+ RuntimeEnvironment.setRobolectricPackageManager(
+ new TestPackageManager(RuntimeEnvironment.getAppResourceLoader()));
+ mContext = RuntimeEnvironment.application;
mPrefs = PreferenceManager.getDefaultSharedPreferences(mContext);
mSuggestion = new Tile();
mSuggestion.intent = new Intent("action");
mSuggestion.intent.setComponent(new ComponentName("pkg", "cls"));
mSuggestion.metaData = new Bundle();
+ mMultipleCategory = new SuggestionParser.SuggestionCategory();
+ mMultipleCategory.category = "category1";
+ mMultipleCategory.multiple = true;
+ mExclusiveCategory = new SuggestionParser.SuggestionCategory();
+ mExclusiveCategory.category = "category2";
+ mExclusiveCategory.exclusive = true;
mSuggestionParser = new SuggestionParser(
- mContext, mPrefs, R.xml.suggestion_ordering, "0,0");
- mSuggestioCategory = new SuggestionParser.SuggestionCategory();
- mSuggestioCategory.category = "category1";
- mSuggestioCategory.multiple = true;
- mInfo = new ArrayList<>();
+ mContext, mPrefs, Arrays.asList(mMultipleCategory, mExclusiveCategory), "0,0");
+
ResolveInfo info1 = TileUtilsTest.newInfo(true, "category1");
info1.activityInfo.packageName = "pkg";
ResolveInfo info2 = TileUtilsTest.newInfo(true, "category1");
info2.activityInfo.packageName = "pkg2";
- mInfo.add(info1);
- mInfo.add(info2);
- when(mPackageManager.queryIntentActivitiesAsUser(
- any(Intent.class), anyInt(), anyInt())).thenReturn(mInfo);
+ ResolveInfo info3 = TileUtilsTest.newInfo(true, "category2");
+ info3.activityInfo.packageName = "pkg3";
+
+ Intent intent1 = new Intent(Intent.ACTION_MAIN).addCategory("category1");
+ Intent intent2 = new Intent(Intent.ACTION_MAIN).addCategory("category2");
+ RuntimeEnvironment.getRobolectricPackageManager().addResolveInfoForIntent(intent1, info1);
+ RuntimeEnvironment.getRobolectricPackageManager().addResolveInfoForIntent(intent1, info2);
+ RuntimeEnvironment.getRobolectricPackageManager().addResolveInfoForIntent(intent2, info3);
}
@Test
@@ -99,30 +100,64 @@
@Test
public void testGetSuggestions_withoutSmartSuggestions() {
readAndDismissSuggestion(false);
- mSuggestionParser.readSuggestions(mSuggestioCategory, mSuggestionsAfterDismiss, false);
- assertThat(mSuggestionsBeforeDismiss.size()).isEqualTo(2);
- assertThat(mSuggestionsAfterDismiss.size()).isEqualTo(1);
+ mSuggestionParser.readSuggestions(mMultipleCategory, mSuggestionsAfterDismiss, false);
+ assertThat(mSuggestionsBeforeDismiss).hasSize(2);
+ assertThat(mSuggestionsAfterDismiss).hasSize(1);
assertThat(mSuggestionsBeforeDismiss.get(1)).isEqualTo(mSuggestionsAfterDismiss.get(0));
}
@Test
public void testGetSuggestions_withSmartSuggestions() {
readAndDismissSuggestion(true);
- assertThat(mSuggestionsBeforeDismiss.size()).isEqualTo(2);
- assertThat(mSuggestionsAfterDismiss.size()).isEqualTo(2);
+ assertThat(mSuggestionsBeforeDismiss).hasSize(2);
+ assertThat(mSuggestionsAfterDismiss).hasSize(2);
assertThat(mSuggestionsBeforeDismiss).isEqualTo(mSuggestionsAfterDismiss);
}
+ @Test
+ public void testGetSuggestion_exclusiveNotAvailable() {
+ RuntimeEnvironment.getRobolectricPackageManager().removeResolveInfosForIntent(
+ new Intent(Intent.ACTION_MAIN).addCategory("category2"),
+ "pkg3");
+
+ // If exclusive item is not available, the other categories should be shown
+ final List<Tile> suggestions = mSuggestionParser.getSuggestions();
+ assertThat(suggestions).hasSize(2);
+ assertThat(suggestions.get(0).category).isEqualTo("category1");
+ assertThat(suggestions.get(1).category).isEqualTo("category1");
+ }
+
+ @Test
+ public void testGetSuggestions_exclusive() {
+ final List<Tile> suggestions = mSuggestionParser.getSuggestions();
+ assertThat(suggestions).hasSize(1);
+ assertThat(suggestions.get(0).category).isEqualTo("category2");
+ }
+
private void readAndDismissSuggestion(boolean isSmartSuggestionEnabled) {
- mSuggestionsBeforeDismiss = new ArrayList<Tile>();
- mSuggestionsAfterDismiss = new ArrayList<Tile>();
+ mSuggestionsBeforeDismiss = new ArrayList<>();
+ mSuggestionsAfterDismiss = new ArrayList<>();
mSuggestionParser.readSuggestions(
- mSuggestioCategory, mSuggestionsBeforeDismiss, isSmartSuggestionEnabled);
- if (mSuggestionParser.dismissSuggestion(
- mSuggestionsBeforeDismiss.get(0), isSmartSuggestionEnabled)) {
- mInfo.remove(0);
+ mMultipleCategory, mSuggestionsBeforeDismiss, isSmartSuggestionEnabled);
+ final Tile suggestion = mSuggestionsBeforeDismiss.get(0);
+ if (mSuggestionParser.dismissSuggestion(suggestion, isSmartSuggestionEnabled)) {
+ RuntimeEnvironment.getRobolectricPackageManager().removeResolveInfosForIntent(
+ new Intent(Intent.ACTION_MAIN).addCategory(suggestion.category),
+ suggestion.intent.getComponent().getPackageName());
}
mSuggestionParser.readSuggestions(
- mSuggestioCategory, mSuggestionsAfterDismiss, isSmartSuggestionEnabled);
+ mMultipleCategory, mSuggestionsAfterDismiss, isSmartSuggestionEnabled);
+ }
+
+ private static class TestPackageManager extends DefaultPackageManager {
+
+ TestPackageManager(ResourceLoader appResourceLoader) {
+ super(appResourceLoader);
+ }
+
+ @Override
+ public List<ResolveInfo> queryIntentActivitiesAsUser(Intent intent, int flags, int userId) {
+ return super.queryIntentActivities(intent, flags);
+ }
}
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java
index 2d3c4a7..dfbe43b 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java
@@ -16,11 +16,22 @@
package com.android.settingslib.drawer;
-import android.app.ActivityManager;
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.argThat;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
-import android.content.IContentProvider;
+import static org.mockito.Mockito.when;
+
+import android.app.ActivityManager;
import android.content.ContentResolver;
import android.content.Context;
+import android.content.IContentProvider;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
@@ -40,34 +51,23 @@
import com.android.settingslib.SuggestionParser;
import com.android.settingslib.TestConfig;
-import com.android.settingslib.drawer.TileUtilsTest;
-import static org.mockito.Mockito.atLeastOnce;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
import org.mockito.ArgumentMatcher;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-import org.robolectric.shadows.ShadowApplication;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
import java.util.Map;
-import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyInt;
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Matchers.argThat;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.when;
-import org.mockito.ArgumentCaptor;
-
@RunWith(RobolectricTestRunner.class)
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
@@ -179,7 +179,11 @@
false /* checkCategory */);
assertThat(outTiles.size()).isEqualTo(1);
- SuggestionParser parser = new SuggestionParser(mContext, null);
+ SuggestionParser parser = new SuggestionParser(
+ mContext,
+ null,
+ Collections.emptyList(),
+ "0,10");
parser.filterSuggestions(outTiles, 0, false);
assertThat(outTiles.size()).isEqualTo(0);
}
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index f15475c..6a75470 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -209,9 +209,12 @@
<!-- Set to true to enable the user switcher on the keyguard. -->
<bool name="config_keyguardUserSwitcher">false</bool>
- <!-- Doze: does this device support STATE_DOZE and STATE_DOZE_SUSPEND? -->
+ <!-- Doze: does this device support STATE_DOZE? -->
<bool name="doze_display_state_supported">false</bool>
+ <!-- Doze: does this device support STATE_DOZE_SUSPEND? -->
+ <bool name="doze_suspend_display_state_supported">false</bool>
+
<!-- Doze: should the significant motion sensor be used as a pulse signal? -->
<bool name="doze_pulse_on_significant_motion">false</bool>
diff --git a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
index 9a4179f..6571294 100644
--- a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
+++ b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
@@ -405,17 +405,17 @@
}
} else {
drawWallpaperWithCanvas(sh, availw, availh, xPixels, yPixels);
+ if (FIXED_SIZED_SURFACE) {
+ // If the surface is fixed-size, we should only need to
+ // draw it once and then we'll let the window manager
+ // position it appropriately. As such, we no longer needed
+ // the loaded bitmap. Yay!
+ // hw-accelerated renderer retains bitmap for faster rotation
+ unloadWallpaper(false /* forgetSize */);
+ }
}
} finally {
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
- if (FIXED_SIZED_SURFACE && !mIsHwAccelerated) {
- // If the surface is fixed-size, we should only need to
- // draw it once and then we'll let the window manager
- // position it appropriately. As such, we no longer needed
- // the loaded bitmap. Yay!
- // hw-accelerated renderer retains bitmap for faster rotation
- unloadWallpaper(false /* forgetSize */);
- }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
index ba8e54a..4d8323b 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
@@ -50,7 +50,8 @@
WakeLock wakeLock = WakeLock.createPartial(context, "Doze");
DozeMachine machine = new DozeMachine(
- DozeScreenStatePreventingAdapter.wrapIfNeeded(dozeService, params),
+ DozeSuspendScreenStatePreventingAdapter.wrapIfNeeded(
+ DozeScreenStatePreventingAdapter.wrapIfNeeded(dozeService, params), params),
config,
wakeLock);
machine.setParts(new DozeMachine.Part[]{
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java b/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java
index f27521e..f498410 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java
@@ -87,8 +87,9 @@
case DOZE:
return Display.STATE_OFF;
case DOZE_PULSING:
+ return Display.STATE_DOZE;
case DOZE_AOD:
- return Display.STATE_DOZE; // TODO: use STATE_ON if appropriate.
+ return Display.STATE_DOZE_SUSPEND;
default:
return Display.STATE_UNKNOWN;
}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeSuspendScreenStatePreventingAdapter.java b/packages/SystemUI/src/com/android/systemui/doze/DozeSuspendScreenStatePreventingAdapter.java
new file mode 100644
index 0000000..1e06797
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeSuspendScreenStatePreventingAdapter.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2017 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.doze;
+
+import android.support.annotation.VisibleForTesting;
+import android.view.Display;
+
+import com.android.systemui.statusbar.phone.DozeParameters;
+
+/**
+ * Prevents usage of doze screen states on devices that don't support them.
+ */
+public class DozeSuspendScreenStatePreventingAdapter implements DozeMachine.Service {
+
+ private final DozeMachine.Service mInner;
+
+ @VisibleForTesting
+ DozeSuspendScreenStatePreventingAdapter(DozeMachine.Service inner) {
+ mInner = inner;
+ }
+
+ @Override
+ public void finish() {
+ mInner.finish();
+ }
+
+ @Override
+ public void setDozeScreenState(int state) {
+ if (state == Display.STATE_DOZE_SUSPEND) {
+ state = Display.STATE_DOZE;
+ }
+ mInner.setDozeScreenState(state);
+ }
+
+ @Override
+ public void requestWakeUp() {
+ mInner.requestWakeUp();
+ }
+
+ /**
+ * If the device supports the doze display state, return {@code inner}. Otherwise
+ * return a new instance of {@link DozeSuspendScreenStatePreventingAdapter} wrapping {@code inner}.
+ */
+ public static DozeMachine.Service wrapIfNeeded(DozeMachine.Service inner,
+ DozeParameters params) {
+ return isNeeded(params) ? new DozeSuspendScreenStatePreventingAdapter(inner) : inner;
+ }
+
+ private static boolean isNeeded(DozeParameters params) {
+ return !params.getDozeSuspendDisplayStateSupported();
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
index ebda2e8..ec80745 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
@@ -45,14 +45,12 @@
import android.os.Messenger;
import android.os.RemoteException;
import android.util.Log;
-import android.util.Pair;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.WindowManager.LayoutParams;
-import android.view.accessibility.AccessibilityManager;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
@@ -61,6 +59,7 @@
import com.android.systemui.R;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
/**
@@ -128,8 +127,9 @@
break;
case MESSAGE_UPDATE_ACTIONS: {
final Bundle data = (Bundle) msg.obj;
- setActions(data.getParcelable(EXTRA_STACK_BOUNDS),
- ((ParceledListSlice) data.getParcelable(EXTRA_ACTIONS)).getList());
+ final ParceledListSlice actions = data.getParcelable(EXTRA_ACTIONS);
+ setActions(data.getParcelable(EXTRA_STACK_BOUNDS), actions != null
+ ? actions.getList() : Collections.EMPTY_LIST);
break;
}
case MESSAGE_UPDATE_DISMISS_FRACTION: {
@@ -260,6 +260,7 @@
}
notifyMenuVisibility(true);
updateExpandButtonFromBounds(stackBounds, movementBounds);
+ setDecorViewVisibility(true);
mMenuContainerAnimator = ObjectAnimator.ofFloat(mMenuContainer, View.ALPHA,
mMenuContainer.getAlpha(), 1f);
mMenuContainerAnimator.setInterpolator(Interpolators.ALPHA_IN);
@@ -300,9 +301,7 @@
if (animationFinishedRunnable != null) {
animationFinishedRunnable.run();
}
- if (getSystemService(AccessibilityManager.class).isEnabled()) {
- finish();
- }
+ setDecorViewVisibility(false);
}
});
mMenuContainerAnimator.addUpdateListener(mMenuBgUpdateListener);
@@ -411,6 +410,7 @@
}
private void updateDismissFraction(float fraction) {
+ setDecorViewVisibility(true);
int alpha;
if (mMenuVisible) {
mMenuContainer.setAlpha(1-fraction);
@@ -497,4 +497,16 @@
v.removeCallbacks(mFinishRunnable);
v.postDelayed(mFinishRunnable, delay);
}
+
+ /**
+ * Sets the visibility of the root view of the window to disable drawing and touches for the
+ * activity. This differs from {@link Activity#setVisible(boolean)} in that it does not set
+ * the internal mVisibleFromClient state.
+ */
+ private void setDecorViewVisibility(boolean visible) {
+ final View decorView = getWindow().getDecorView();
+ if (decorView != null) {
+ decorView.setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
index 7b2e997..2a9de41 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
@@ -80,6 +80,10 @@
return getBoolean("doze.display.supported", R.bool.doze_display_state_supported);
}
+ public boolean getDozeSuspendDisplayStateSupported() {
+ return mContext.getResources().getBoolean(R.bool.doze_suspend_display_state_supported);
+ }
+
public int getPulseDuration(boolean pickup) {
return getPulseInDuration(pickup) + getPulseVisibleDuration() + getPulseOutDuration();
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java
index cdbde5e..5771b28 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java
@@ -228,7 +228,7 @@
mMachine.requestState(DOZE_AOD);
- assertEquals(Display.STATE_DOZE, mServiceFake.screenState);
+ assertEquals(Display.STATE_DOZE_SUSPEND, mServiceFake.screenState);
}
@Test
@@ -258,7 +258,7 @@
mMachine.requestState(DOZE_AOD);
mMachine.requestState(DOZE_REQUEST_PULSE);
- assertEquals(Display.STATE_DOZE, mServiceFake.screenState);
+ assertEquals(Display.STATE_DOZE_SUSPEND, mServiceFake.screenState);
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSuspendScreenStatePreventingAdapterTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSuspendScreenStatePreventingAdapterTest.java
new file mode 100644
index 0000000..2e3df2c
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSuspendScreenStatePreventingAdapterTest.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2017 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.doze;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertSame;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.support.test.filters.SmallTest;
+import android.view.Display;
+
+import com.android.systemui.statusbar.phone.DozeParameters;
+
+import org.junit.Before;
+import org.junit.Test;
+
+@SmallTest
+public class DozeSuspendScreenStatePreventingAdapterTest {
+
+ private DozeMachine.Service mInner;
+ private DozeSuspendScreenStatePreventingAdapter mWrapper;
+
+ @Before
+ public void setup() throws Exception {
+ mInner = mock(DozeMachine.Service.class);
+ mWrapper = new DozeSuspendScreenStatePreventingAdapter(mInner);
+ }
+
+ @Test
+ public void forwards_finish() throws Exception {
+ mWrapper.finish();
+ verify(mInner).finish();
+ }
+
+ @Test
+ public void forwards_setDozeScreenState_on() throws Exception {
+ mWrapper.setDozeScreenState(Display.STATE_ON);
+ verify(mInner).setDozeScreenState(Display.STATE_ON);
+ }
+
+ @Test
+ public void forwards_setDozeScreenState_off() throws Exception {
+ mWrapper.setDozeScreenState(Display.STATE_OFF);
+ verify(mInner).setDozeScreenState(Display.STATE_OFF);
+ }
+
+ @Test
+ public void forwards_setDozeScreenState_doze() throws Exception {
+ mWrapper.setDozeScreenState(Display.STATE_DOZE);
+ verify(mInner).setDozeScreenState(Display.STATE_DOZE);
+ }
+
+ @Test
+ public void forwards_setDozeScreenState_doze_suspend() throws Exception {
+ mWrapper.setDozeScreenState(Display.STATE_DOZE_SUSPEND);
+ verify(mInner).setDozeScreenState(Display.STATE_DOZE);
+ }
+
+ @Test
+ public void forwards_requestWakeUp() throws Exception {
+ mWrapper.requestWakeUp();
+ verify(mInner).requestWakeUp();
+ }
+
+ @Test
+ public void wrapIfNeeded_needed() throws Exception {
+ DozeParameters params = mock(DozeParameters.class);
+ when(params.getDozeSuspendDisplayStateSupported()).thenReturn(false);
+
+ assertEquals(DozeSuspendScreenStatePreventingAdapter.class,
+ DozeSuspendScreenStatePreventingAdapter.wrapIfNeeded(mInner, params).getClass());
+ }
+
+ @Test
+ public void wrapIfNeeded_not_needed() throws Exception {
+ DozeParameters params = mock(DozeParameters.class);
+ when(params.getDozeSuspendDisplayStateSupported()).thenReturn(true);
+
+ assertSame(mInner, DozeSuspendScreenStatePreventingAdapter.wrapIfNeeded(mInner, params));
+ }
+}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/FontManagerService.java b/services/core/java/com/android/server/FontManagerService.java
index 55a945a..f172647 100644
--- a/services/core/java/com/android/server/FontManagerService.java
+++ b/services/core/java/com/android/server/FontManagerService.java
@@ -18,6 +18,7 @@
import android.content.Context;
import android.graphics.FontListParser;
+import android.net.Uri;
import android.os.ParcelFileDescriptor;
import android.text.FontConfig;
import android.util.Slog;
@@ -34,6 +35,7 @@
public class FontManagerService extends IFontManager.Stub {
private static final String TAG = "FontManagerService";
private static final String FONTS_CONFIG = "/system/etc/fonts.xml";
+ private static final String SYSTEM_FONT_DIR = "/system/fonts/";
@GuardedBy("mLock")
private FontConfig mConfig;
@@ -63,28 +65,22 @@
public FontConfig getSystemFonts() {
synchronized (mLock) {
if (mConfig != null) {
- return new FontConfig(mConfig);
+ return mConfig;
}
- FontConfig config = loadFromSystem();
- if (config == null) {
+ mConfig = loadFromSystem();
+ if (mConfig == null) {
return null;
}
- for (FontConfig.Family family : config.getFamilies()) {
+ for (FontConfig.Family family : mConfig.getFamilies()) {
for (FontConfig.Font font : family.getFonts()) {
- File fontFile = new File(font.getFontName());
- try {
- font.setFd(ParcelFileDescriptor.open(
- fontFile, ParcelFileDescriptor.MODE_READ_ONLY));
- } catch (IOException e) {
- Slog.e(TAG, "Error opening font file " + font.getFontName(), e);
- }
+ File fontFile = new File(SYSTEM_FONT_DIR, font.getFontName());
+ font.setUri(Uri.fromFile(fontFile));
}
}
- mConfig = config;
- return new FontConfig(mConfig);
+ return mConfig;
}
}
diff --git a/tools/layoutlib/.gitignore b/tools/layoutlib/.gitignore
index 819103d..a2b0c33 100644
--- a/tools/layoutlib/.gitignore
+++ b/tools/layoutlib/.gitignore
@@ -2,3 +2,4 @@
/.idea/workspace.xml
/out
/bridge/out
+/.idea/kotlinc.xml
\ No newline at end of file
diff --git a/tools/layoutlib/bridge/src/android/content/res/Resources_Delegate.java b/tools/layoutlib/bridge/src/android/content/res/Resources_Delegate.java
index e3bc34b..c20ee12 100644
--- a/tools/layoutlib/bridge/src/android/content/res/Resources_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/content/res/Resources_Delegate.java
@@ -33,7 +33,6 @@
import com.android.layoutlib.bridge.util.NinePatchInputStream;
import com.android.ninepatch.NinePatch;
import com.android.resources.ResourceType;
-import com.android.resources.ResourceUrl;
import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
import com.android.util.Pair;
@@ -60,8 +59,6 @@
import java.io.InputStream;
import java.util.Iterator;
-import static com.android.SdkConstants.ANDROID_NS_NAME;
-
@SuppressWarnings("deprecation")
public class Resources_Delegate {
@@ -140,8 +137,8 @@
if (value == null) {
// Unable to resolve the attribute, just leave the unresolved value
- value = new ResourceValue(ResourceUrl.create(resourceInfo.getFirst(), attributeName,
- platformResFlag_out[0]), attributeName);
+ value = new ResourceValue(resourceInfo.getFirst(), attributeName, attributeName,
+ platformResFlag_out[0]);
}
return Pair.of(attributeName, value);
}
@@ -681,7 +678,7 @@
String packageName;
if (resourceInfo != null) {
if (platformOut[0]) {
- packageName = ANDROID_NS_NAME;
+ packageName = SdkConstants.ANDROID_NS_NAME;
} else {
packageName = resources.mContext.getPackageName();
packageName = packageName == null ? SdkConstants.APP_PREFIX : packageName;
@@ -699,7 +696,7 @@
Pair<ResourceType, String> resourceInfo = getResourceInfo(resources, resid, platformOut);
if (resourceInfo != null) {
if (platformOut[0]) {
- return ANDROID_NS_NAME;
+ return SdkConstants.ANDROID_NS_NAME;
}
String packageName = resources.mContext.getPackageName();
return packageName == null ? SdkConstants.APP_PREFIX : packageName;
diff --git a/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java
index e118889..80e3bad 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java
@@ -233,7 +233,8 @@
Map<String, ByteBuffer> bufferForPath) {
FontFamily fontFamily = new FontFamily(family.getLanguage(), family.getVariant());
for (FontConfig.Font font : family.getFonts()) {
- FontFamily_Delegate.addFont(fontFamily.mBuilderPtr, font.getFontName(),
+ String fullPathName = "/system/fonts/" + font.getFontName();
+ FontFamily_Delegate.addFont(fontFamily.mBuilderPtr, fullPathName,
font.getWeight(), font.isItalic());
}
fontFamily.freeze();
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
index 2e14974..93fd005 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
@@ -52,7 +52,6 @@
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Arrays;
-import java.util.Comparator;
import java.util.EnumMap;
import java.util.EnumSet;
import java.util.HashMap;
@@ -62,7 +61,6 @@
import libcore.io.MemoryMappedFile_Delegate;
import static com.android.ide.common.rendering.api.Result.Status.ERROR_UNKNOWN;
-import static com.android.ide.common.rendering.api.Result.Status.SUCCESS;
/**
* Main entry point of the LayoutLib Bridge.
@@ -90,19 +88,14 @@
/**
* Maps from id to resource type/name. This is for com.android.internal.R
*/
- private final static Map<Integer, Pair<ResourceType, String>> sRMap =
- new HashMap<Integer, Pair<ResourceType, String>>();
+ @SuppressWarnings("deprecation")
+ private final static Map<Integer, Pair<ResourceType, String>> sRMap = new HashMap<>();
/**
- * Same as sRMap except for int[] instead of int resources. This is for android.R only.
- */
- private final static Map<IntArray, String> sRArrayMap = new HashMap<IntArray, String>(384);
- /**
* Reverse map compared to sRMap, resource type -> (resource name -> id).
* This is for com.android.internal.R.
*/
- private final static Map<ResourceType, Map<String, Integer>> sRevRMap =
- new EnumMap<ResourceType, Map<String,Integer>>(ResourceType.class);
+ private final static Map<ResourceType, Map<String, Integer>> sRevRMap = new EnumMap<>(ResourceType.class);
// framework resources are defined as 0x01XX#### where XX is the resource type (layout,
// drawable, etc...). Using FF as the type allows for 255 resource types before we get a
@@ -111,56 +104,19 @@
private final static DynamicIdMap sDynamicIds = new DynamicIdMap(DYNAMIC_ID_SEED_START);
private final static Map<Object, Map<String, SoftReference<Bitmap>>> sProjectBitmapCache =
- new HashMap<Object, Map<String, SoftReference<Bitmap>>>();
+ new HashMap<>();
private final static Map<Object, Map<String, SoftReference<NinePatchChunk>>> sProject9PatchCache =
- new HashMap<Object, Map<String, SoftReference<NinePatchChunk>>>();
- private final static Map<String, SoftReference<Bitmap>> sFrameworkBitmapCache =
- new HashMap<String, SoftReference<Bitmap>>();
+ new HashMap<>();
+
+ private final static Map<String, SoftReference<Bitmap>> sFrameworkBitmapCache = new HashMap<>();
private final static Map<String, SoftReference<NinePatchChunk>> sFramework9PatchCache =
- new HashMap<String, SoftReference<NinePatchChunk>>();
+ new HashMap<>();
private static Map<String, Map<String, Integer>> sEnumValueMap;
private static Map<String, String> sPlatformProperties;
/**
- * int[] wrapper to use as keys in maps.
- */
- private final static class IntArray {
- private int[] mArray;
-
- private IntArray() {
- // do nothing
- }
-
- private IntArray(int[] a) {
- mArray = a;
- }
-
- private void set(int[] a) {
- mArray = a;
- }
-
- @Override
- public int hashCode() {
- return Arrays.hashCode(mArray);
- }
-
- @Override
- public boolean equals(Object obj) {
- if (this == obj) return true;
- if (obj == null) return false;
- if (getClass() != obj.getClass()) return false;
-
- IntArray other = (IntArray) obj;
- return Arrays.equals(mArray, other.mArray);
- }
- }
-
- /** Instance of IntArrayWrapper to be reused in {@link #resolveResourceId(int[])}. */
- private final static IntArray sIntArrayWrapper = new IntArray();
-
- /**
* A default log than prints to stdout/stderr.
*/
private final static LayoutLog sDefaultLog = new LayoutLog() {
@@ -192,6 +148,7 @@
return com.android.ide.common.rendering.api.Bridge.API_CURRENT;
}
+ @SuppressWarnings("deprecation")
@Override
@Deprecated
public EnumSet<Capability> getCapabilities() {
@@ -272,11 +229,11 @@
case STRING:
case STYLE:
// Slightly less than thousand entries in each.
- fullMap = new HashMap<String, Integer>(1280);
+ fullMap = new HashMap<>(1280);
// no break.
default:
if (fullMap == null) {
- fullMap = new HashMap<String, Integer>();
+ fullMap = new HashMap<>();
}
sRevRMap.put(resType, fullMap);
}
@@ -288,13 +245,9 @@
continue;
}
Class<?> type = f.getType();
- if (type.isArray()) {
- // if the object is an int[] we put it in sRArrayMap using an IntArray
- // wrapper that properly implements equals and hashcode for the array
- // objects, as required by the map contract.
- sRArrayMap.put(new IntArray((int[]) f.get(null)), f.getName());
- } else {
+ if (!type.isArray()) {
Integer value = (Integer) f.get(null);
+ //noinspection deprecation
sRMap.put(value, Pair.of(resType, f.getName()));
fullMap.put(f.getName(), value);
}
@@ -332,32 +285,29 @@
// values, we try and find them from the styleables.
// There were 1500 elements in this map at M timeframe.
- Map<String, Integer> revRAttrMap = new HashMap<String, Integer>(2048);
+ Map<String, Integer> revRAttrMap = new HashMap<>(2048);
sRevRMap.put(ResourceType.ATTR, revRAttrMap);
// There were 2000 elements in this map at M timeframe.
- Map<String, Integer> revRStyleableMap = new HashMap<String, Integer>(3072);
+ Map<String, Integer> revRStyleableMap = new HashMap<>(3072);
sRevRMap.put(ResourceType.STYLEABLE, revRStyleableMap);
Class<?> c = com.android.internal.R.styleable.class;
Field[] fields = c.getDeclaredFields();
// Sort the fields to bring all arrays to the beginning, so that indices into the array are
// able to refer back to the arrays (i.e. no forward references).
- Arrays.sort(fields, new Comparator<Field>() {
- @Override
- public int compare(Field o1, Field o2) {
- if (o1 == o2) {
- return 0;
- }
- Class<?> t1 = o1.getType();
- Class<?> t2 = o2.getType();
- if (t1.isArray() && !t2.isArray()) {
- return -1;
- } else if (t2.isArray() && !t1.isArray()) {
- return 1;
- }
- return o1.getName().compareTo(o2.getName());
+ Arrays.sort(fields, (o1, o2) -> {
+ if (o1 == o2) {
+ return 0;
}
+ Class<?> t1 = o1.getType();
+ Class<?> t2 = o2.getType();
+ if (t1.isArray() && !t2.isArray()) {
+ return -1;
+ } else if (t2.isArray() && !t1.isArray()) {
+ return 1;
+ }
+ return o1.getName().compareTo(o2.getName());
});
- Map<String, int[]> styleables = new HashMap<String, int[]>();
+ Map<String, int[]> styleables = new HashMap<>();
for (Field field : fields) {
if (!isValidRField(field)) {
// Only consider public static fields that are int or int[].
@@ -367,7 +317,6 @@
String name = field.getName();
if (field.getType().isArray()) {
int[] styleableValue = (int[]) field.get(null);
- sRArrayMap.put(new IntArray(styleableValue), name);
styleables.put(name, styleableValue);
continue;
}
@@ -389,9 +338,11 @@
if (arrayValue != null) {
String attrName = name.substring(arrayName.length() + 1);
int attrValue = arrayValue[index];
+ //noinspection deprecation
sRMap.put(attrValue, Pair.of(ResourceType.ATTR, attrName));
revRAttrMap.put(attrName, attrValue);
}
+ //noinspection deprecation
sRMap.put(index, Pair.of(ResourceType.STYLEABLE, name));
revRStyleableMap.put(name, index);
}
@@ -422,7 +373,7 @@
@Override
public RenderSession createSession(SessionParams params) {
try {
- Result lastResult = SUCCESS.createResult();
+ Result lastResult;
RenderSessionImpl scene = new RenderSessionImpl(params);
try {
prepareThread();
@@ -456,7 +407,7 @@
@Override
public Result renderDrawable(DrawableParams params) {
try {
- Result lastResult = SUCCESS.createResult();
+ Result lastResult;
RenderDrawable action = new RenderDrawable(params);
try {
prepareThread();
@@ -581,26 +532,16 @@
* @return a Pair containing the resource type and name, or null if the id
* does not match any resource.
*/
+ @SuppressWarnings("deprecation")
public static Pair<ResourceType, String> resolveResourceId(int value) {
Pair<ResourceType, String> pair = sRMap.get(value);
if (pair == null) {
pair = sDynamicIds.resolveId(value);
- if (pair == null) {
- //System.out.println(String.format("Missing id: %1$08X (%1$d)", value));
- }
}
return pair;
}
/**
- * Returns the name of a framework resource whose value is an int array.
- */
- public static String resolveResourceId(int[] array) {
- sIntArrayWrapper.set(array);
- return sRArrayMap.get(sIntArrayWrapper);
- }
-
- /**
* Returns the integer id of a framework resource, from a given resource type and resource name.
* <p/>
* If no resource is found, it creates a dynamic id for the resource.
@@ -674,16 +615,12 @@
*/
public static void setCachedBitmap(String value, Bitmap bmp, Object projectKey) {
if (projectKey != null) {
- Map<String, SoftReference<Bitmap>> map = sProjectBitmapCache.get(projectKey);
+ Map<String, SoftReference<Bitmap>> map =
+ sProjectBitmapCache.computeIfAbsent(projectKey, k -> new HashMap<>());
- if (map == null) {
- map = new HashMap<String, SoftReference<Bitmap>>();
- sProjectBitmapCache.put(projectKey, map);
- }
-
- map.put(value, new SoftReference<Bitmap>(bmp));
+ map.put(value, new SoftReference<>(bmp));
} else {
- sFrameworkBitmapCache.put(value, new SoftReference<Bitmap>(bmp));
+ sFrameworkBitmapCache.put(value, new SoftReference<>(bmp));
}
}
@@ -722,16 +659,12 @@
*/
public static void setCached9Patch(String value, NinePatchChunk ninePatch, Object projectKey) {
if (projectKey != null) {
- Map<String, SoftReference<NinePatchChunk>> map = sProject9PatchCache.get(projectKey);
+ Map<String, SoftReference<NinePatchChunk>> map =
+ sProject9PatchCache.computeIfAbsent(projectKey, k -> new HashMap<>());
- if (map == null) {
- map = new HashMap<String, SoftReference<NinePatchChunk>>();
- sProject9PatchCache.put(projectKey, map);
- }
-
- map.put(value, new SoftReference<NinePatchChunk>(ninePatch));
+ map.put(value, new SoftReference<>(ninePatch));
} else {
- sFramework9PatchCache.put(value, new SoftReference<NinePatchChunk>(ninePatch));
+ sFramework9PatchCache.put(value, new SoftReference<>(ninePatch));
}
}
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
index 4f88232..4573f7a 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
@@ -31,7 +31,6 @@
import com.android.layoutlib.bridge.impl.ParserFactory;
import com.android.layoutlib.bridge.impl.Stack;
import com.android.resources.ResourceType;
-import com.android.resources.ResourceUrl;
import com.android.util.Pair;
import com.android.util.PropertiesMap;
import com.android.util.PropertiesMap.Property;
@@ -87,6 +86,7 @@
import android.view.BridgeInflater;
import android.view.Display;
import android.view.DisplayAdjustments;
+import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
@@ -107,7 +107,6 @@
import java.util.Map;
import static android.os._Original_Build.VERSION_CODES.JELLY_BEAN_MR1;
-import static com.android.SdkConstants.ANDROID_NS_NAME;
import static com.android.layoutlib.bridge.android.RenderParamsFlags.FLAG_KEY_APPLICATION_PACKAGE;
/**
@@ -122,23 +121,20 @@
static {
FRAMEWORK_PATCHED_VALUES.put("animateFirstView", new ResourceValue(
- ResourceUrl.create(ANDROID_NS_NAME, ResourceType.BOOL, "animateFirstView"),
- "false"));
- FRAMEWORK_PATCHED_VALUES.put("animateLayoutChanges", new ResourceValue(
- ResourceUrl.create(ANDROID_NS_NAME, ResourceType.BOOL, "animateLayoutChanges"),
- "false"));
+ ResourceType.BOOL, "animateFirstView", "false", false));
+ FRAMEWORK_PATCHED_VALUES.put("animateLayoutChanges",
+ new ResourceValue(ResourceType.BOOL, "animateLayoutChanges", "false", false));
- FRAMEWORK_REPLACE_VALUES.put("textEditSuggestionItemLayout", new ResourceValue(
- ResourceUrl.create(ANDROID_NS_NAME, ResourceType.LAYOUT,
- "textEditSuggestionItemLayout"), "text_edit_suggestion_item"));
- FRAMEWORK_REPLACE_VALUES.put("textEditSuggestionContainerLayout", new ResourceValue(
- ResourceUrl.create(ANDROID_NS_NAME, ResourceType.LAYOUT,
- "textEditSuggestionContainerLayout"), "text_edit_suggestion_container"));
- FRAMEWORK_REPLACE_VALUES.put("textEditSuggestionHighlightStyle", new ResourceValue(
- ResourceUrl.create(ANDROID_NS_NAME, ResourceType.STYLE,
- "textEditSuggestionHighlightStyle"),
- "TextAppearance.Holo.SuggestionHighlight"));
+ FRAMEWORK_REPLACE_VALUES.put("textEditSuggestionItemLayout",
+ new ResourceValue(ResourceType.LAYOUT, "textEditSuggestionItemLayout",
+ "text_edit_suggestion_item", true));
+ FRAMEWORK_REPLACE_VALUES.put("textEditSuggestionContainerLayout",
+ new ResourceValue(ResourceType.LAYOUT, "textEditSuggestionContainerLayout",
+ "text_edit_suggestion_container", true));
+ FRAMEWORK_REPLACE_VALUES.put("textEditSuggestionHighlightStyle",
+ new ResourceValue(ResourceType.STYLE, "textEditSuggestionHighlightStyle",
+ "TextAppearance.Holo.SuggestionHighlight", true));
}
@@ -971,9 +967,7 @@
// there is a value in the XML, but we need to resolve it in case it's
// referencing another resource or a theme value.
ta.bridgeSetValue(index, attrName, frameworkAttr,
- mRenderResources.resolveResValue(new ResourceValue(
- ResourceUrl.create(ResourceType.STRING, attrName,
- isPlatformFile), value)));
+ mRenderResources.resolveValue(null, attrName, value, isPlatformFile));
}
}
}
diff --git a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/RenderTestBase.java b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/RenderTestBase.java
index 00dddee..8739b7f 100644
--- a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/RenderTestBase.java
+++ b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/RenderTestBase.java
@@ -311,7 +311,6 @@
sFrameworkRepo = null;
sProjectResources = null;
sLogger = null;
- sBridge.dispose();
sBridge = null;
TestUtils.gc();
@@ -329,7 +328,6 @@
RenderSession session = sBridge.createSession(params);
try {
-
if (frameTimeNanos != -1) {
session.setElapsedFrameTimeNanos(frameTimeNanos);
}
@@ -338,11 +336,13 @@
getLogger().error(session.getResult().getException(),
session.getResult().getErrorMessage());
}
- // Render the session with a timeout of 50s.
- Result renderResult = session.render(50000);
- if (!renderResult.isSuccess()) {
- getLogger().error(session.getResult().getException(),
- session.getResult().getErrorMessage());
+ else {
+ // Render the session with a timeout of 50s.
+ Result renderResult = session.render(50000);
+ if (!renderResult.isSuccess()) {
+ getLogger().error(session.getResult().getException(),
+ session.getResult().getErrorMessage());
+ }
}
return RenderResult.getFromSession(session);