summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--api/current.txt14
-rw-r--r--api/system-current.txt14
-rw-r--r--cmds/bootanimation/Android.mk2
-rw-r--r--cmds/bootanimation/bootanim.rc6
-rw-r--r--core/java/android/content/RestrictionEntry.java2
-rw-r--r--core/java/android/content/pm/ActivityInfo.java47
-rw-r--r--core/java/android/content/pm/PackageParser.java42
-rw-r--r--core/java/android/text/TextUtils.java15
-rw-r--r--core/java/android/text/format/Formatter.java9
-rw-r--r--core/java/android/view/DisplayListCanvas.java15
-rw-r--r--core/java/android/view/HardwareLayer.java4
-rw-r--r--core/java/android/view/TextureView.java28
-rw-r--r--core/java/android/view/View.java15
-rw-r--r--core/java/com/android/internal/policy/PhoneWindow.java6
-rw-r--r--core/jni/android/graphics/Path.cpp3
-rw-r--r--core/jni/android_view_DisplayListCanvas.cpp6
-rw-r--r--core/jni/android_view_HardwareLayer.cpp8
-rw-r--r--core/res/AndroidManifest.xml40
-rw-r--r--core/res/res/drawable/scrollbar_handle_material.xml7
-rw-r--r--core/res/res/values/attrs_manifest.xml14
-rw-r--r--core/tests/coretests/src/android/animation/ValueAnimatorTests.java60
-rw-r--r--core/tests/coretests/src/android/text/format/FormatterTest.java20
-rw-r--r--core/tests/coretests/src/android/widget/TextViewTest.java37
-rw-r--r--docs/html/training/wearables/watch-faces/index.jd2
-rw-r--r--docs/html/training/wearables/watch-faces/interacting.jd4
-rw-r--r--graphics/java/android/graphics/Path.java4
-rw-r--r--graphics/java/android/graphics/drawable/RippleDrawable.java3
-rw-r--r--libs/hwui/CanvasState.cpp9
-rw-r--r--libs/hwui/ClipArea.cpp84
-rw-r--r--libs/hwui/ClipArea.h45
-rw-r--r--libs/hwui/DisplayListCanvas.cpp4
-rw-r--r--libs/hwui/DisplayListCanvas.h2
-rw-r--r--libs/hwui/DisplayListOp.h10
-rw-r--r--libs/hwui/OpenGLRenderer.cpp8
-rwxr-xr-xlibs/hwui/OpenGLRenderer.h3
-rw-r--r--libs/hwui/ProgramCache.cpp9
-rw-r--r--libs/hwui/RenderNode.cpp2
-rw-r--r--libs/hwui/Snapshot.cpp14
-rw-r--r--libs/hwui/Snapshot.h9
-rw-r--r--media/java/android/mtp/MtpObjectInfo.java2
-rw-r--r--media/jni/android_mtp_MtpDevice.cpp22
-rw-r--r--packages/DocumentsUI/res/layout/item_doc_grid.xml4
-rw-r--r--packages/DocumentsUI/res/layout/item_loading_grid.xml4
-rw-r--r--packages/DocumentsUI/res/layout/item_message_grid.xml4
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/BandSelectMatrix.java645
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java6
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java3
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java31
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java4
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/DocumentClipper.java12
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/FilteringCursorWrapper.java2
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/GridItem.java51
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/IconUtils.java4
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/MultiSelectManager.java2
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/ProviderExecutor.java6
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/QuickViewIntentBuilder.java2
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/RecentLoader.java14
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java5
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/RootsCache.java18
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java8
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/SectionedListAdapter.java4
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/Shared.java24
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/StandaloneActivity.java2
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/UriDerivativeLoader.java20
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/model/DocumentInfo.java1
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/model/DurableUtils.java2
-rw-r--r--packages/DocumentsUI/tests/src/com/android/documentsui/BandSelectMatrixTest.java277
-rw-r--r--packages/DocumentsUI/tests/src/com/android/documentsui/RootsCacheTest.java3
-rw-r--r--packages/DocumentsUI/tests/src/com/android/documentsui/StubProvider.java4
-rw-r--r--packages/DocumentsUI/tests/src/com/android/documentsui/UnitTests.java1
-rw-r--r--packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocument.java35
-rw-r--r--packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java20
-rw-r--r--packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java19
-rw-r--r--packages/MtpDocumentsProvider/tests/src/com/android/mtp/DocumentLoaderTest.java3
-rw-r--r--packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java9
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/TetherUtil.java24
-rw-r--r--services/backup/java/com/android/server/backup/BackupManagerService.java46
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java4
-rw-r--r--services/core/java/com/android/server/wm/DragState.java3
-rw-r--r--services/core/java/com/android/server/wm/InputMonitor.java3
-rw-r--r--services/core/java/com/android/server/wm/WallpaperController.java354
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java558
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java37
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java12
-rw-r--r--telephony/java/android/telephony/CarrierConfigManager.java8
85 files changed, 2164 insertions, 784 deletions
diff --git a/api/current.txt b/api/current.txt
index acc9c4b11024..b1e80dd2a672 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -8881,6 +8881,7 @@ package android.content.pm {
field public int configChanges;
field public int documentLaunchMode;
field public int flags;
+ field public android.content.pm.ActivityInfo.InitialLayout initialLayout;
field public int launchMode;
field public int maxRecents;
field public java.lang.String parentActivityName;
@@ -8894,6 +8895,15 @@ package android.content.pm {
field public int uiOptions;
}
+ public static final class ActivityInfo.InitialLayout {
+ ctor public ActivityInfo.InitialLayout(int, float, int, float, int);
+ field public final int gravity;
+ field public final int height;
+ field public final float heightFraction;
+ field public final int width;
+ field public final float widthFraction;
+ }
+
public class ApplicationInfo extends android.content.pm.PackageItemInfo implements android.os.Parcelable {
ctor public ApplicationInfo();
ctor public ApplicationInfo(android.content.pm.ApplicationInfo);
@@ -18136,7 +18146,7 @@ package android.mtp {
method public final int getThumbPixWidth();
}
- public class MtpObjectInfo.Builder {
+ public static class MtpObjectInfo.Builder {
ctor public MtpObjectInfo.Builder();
ctor public MtpObjectInfo.Builder(android.mtp.MtpObjectInfo);
method public android.mtp.MtpObjectInfo build();
@@ -32512,7 +32522,7 @@ package android.text {
method public static int getLayoutDirectionFromLocale(java.util.Locale);
method public static int getOffsetAfter(java.lang.CharSequence, int);
method public static int getOffsetBefore(java.lang.CharSequence, int);
- method public static java.lang.CharSequence getReverse(java.lang.CharSequence, int, int);
+ method public static deprecated java.lang.CharSequence getReverse(java.lang.CharSequence, int, int);
method public static int getTrimmedLength(java.lang.CharSequence);
method public static java.lang.String htmlEncode(java.lang.String);
method public static int indexOf(java.lang.CharSequence, char);
diff --git a/api/system-current.txt b/api/system-current.txt
index 955fb07e20a7..fe7c6dac610e 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -9139,6 +9139,7 @@ package android.content.pm {
field public int configChanges;
field public int documentLaunchMode;
field public int flags;
+ field public android.content.pm.ActivityInfo.InitialLayout initialLayout;
field public int launchMode;
field public int maxRecents;
field public java.lang.String parentActivityName;
@@ -9152,6 +9153,15 @@ package android.content.pm {
field public int uiOptions;
}
+ public static final class ActivityInfo.InitialLayout {
+ ctor public ActivityInfo.InitialLayout(int, float, int, float, int);
+ field public final int gravity;
+ field public final int height;
+ field public final float heightFraction;
+ field public final int width;
+ field public final float widthFraction;
+ }
+
public class ApplicationInfo extends android.content.pm.PackageItemInfo implements android.os.Parcelable {
ctor public ApplicationInfo();
ctor public ApplicationInfo(android.content.pm.ApplicationInfo);
@@ -19649,7 +19659,7 @@ package android.mtp {
method public final int getThumbPixWidth();
}
- public class MtpObjectInfo.Builder {
+ public static class MtpObjectInfo.Builder {
ctor public MtpObjectInfo.Builder();
ctor public MtpObjectInfo.Builder(android.mtp.MtpObjectInfo);
method public android.mtp.MtpObjectInfo build();
@@ -34845,7 +34855,7 @@ package android.text {
method public static int getLayoutDirectionFromLocale(java.util.Locale);
method public static int getOffsetAfter(java.lang.CharSequence, int);
method public static int getOffsetBefore(java.lang.CharSequence, int);
- method public static java.lang.CharSequence getReverse(java.lang.CharSequence, int, int);
+ method public static deprecated java.lang.CharSequence getReverse(java.lang.CharSequence, int, int);
method public static int getTrimmedLength(java.lang.CharSequence);
method public static java.lang.String htmlEncode(java.lang.String);
method public static int indexOf(java.lang.CharSequence, char);
diff --git a/cmds/bootanimation/Android.mk b/cmds/bootanimation/Android.mk
index 2ee586f2c3ca..7c8842ca0231 100644
--- a/cmds/bootanimation/Android.mk
+++ b/cmds/bootanimation/Android.mk
@@ -27,6 +27,8 @@ LOCAL_SHARED_LIBRARIES := \
LOCAL_MODULE:= bootanimation
+LOCAL_INIT_RC := bootanim.rc
+
ifdef TARGET_32_BIT_SURFACEFLINGER
LOCAL_32_BIT_ONLY := true
endif
diff --git a/cmds/bootanimation/bootanim.rc b/cmds/bootanimation/bootanim.rc
new file mode 100644
index 000000000000..ee0d0b8c042f
--- /dev/null
+++ b/cmds/bootanimation/bootanim.rc
@@ -0,0 +1,6 @@
+service bootanim /system/bin/bootanimation
+ class core
+ user graphics
+ group graphics audio
+ disabled
+ oneshot
diff --git a/core/java/android/content/RestrictionEntry.java b/core/java/android/content/RestrictionEntry.java
index ab049ecbed95..0473475c1a77 100644
--- a/core/java/android/content/RestrictionEntry.java
+++ b/core/java/android/content/RestrictionEntry.java
@@ -456,7 +456,7 @@ public class RestrictionEntry implements Parcelable {
if (o == this) return true;
if (!(o instanceof RestrictionEntry)) return false;
final RestrictionEntry other = (RestrictionEntry) o;
- if (mType != other.mType || mKey.equals(other.mKey)) {
+ if (mType != other.mType || !mKey.equals(other.mKey)) {
return false;
}
if (mCurrentValues == null && other.mCurrentValues == null
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index 43cc63b4a3c8..876fbf55765c 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -698,6 +698,8 @@ public class ActivityInfo extends ComponentInfo
*/
public int lockTaskLaunchMode;
+ public InitialLayout initialLayout;
+
public ActivityInfo() {
}
@@ -763,9 +765,14 @@ public class ActivityInfo extends ComponentInfo
}
pw.println(prefix + "resizeable=" + resizeable + " lockTaskLaunchMode="
+ lockTaskLaunchModeToString(lockTaskLaunchMode));
+ if (initialLayout != null) {
+ pw.println(prefix + "initialLayout=" + initialLayout.width + "|"
+ + initialLayout.widthFraction + ", " + initialLayout.height + "|"
+ + initialLayout.heightFraction + ", " + initialLayout.gravity);
+ }
super.dumpBack(pw, prefix);
}
-
+
public String toString() {
return "ActivityInfo{"
+ Integer.toHexString(System.identityHashCode(this))
@@ -793,6 +800,16 @@ public class ActivityInfo extends ComponentInfo
dest.writeInt(maxRecents);
dest.writeInt(resizeable ? 1 : 0);
dest.writeInt(lockTaskLaunchMode);
+ if (initialLayout != null) {
+ dest.writeInt(1);
+ dest.writeInt(initialLayout.width);
+ dest.writeFloat(initialLayout.widthFraction);
+ dest.writeInt(initialLayout.height);
+ dest.writeFloat(initialLayout.heightFraction);
+ dest.writeInt(initialLayout.gravity);
+ } else {
+ dest.writeInt(0);
+ }
}
public static final Parcelable.Creator<ActivityInfo> CREATOR
@@ -822,5 +839,33 @@ public class ActivityInfo extends ComponentInfo
maxRecents = source.readInt();
resizeable = (source.readInt() == 1);
lockTaskLaunchMode = source.readInt();
+ if (source.readInt() == 1) {
+ initialLayout = new InitialLayout(source);
+ }
+ }
+
+ public static final class InitialLayout {
+ public InitialLayout(int width, float widthFraction, int height, float heightFraction,
+ int gravity) {
+ this.width = width;
+ this.widthFraction = widthFraction;
+ this.height = height;
+ this.heightFraction = heightFraction;
+ this.gravity = gravity;
+ }
+
+ InitialLayout(Parcel source) {
+ width = source.readInt();
+ widthFraction = source.readFloat();
+ height = source.readInt();
+ heightFraction = source.readFloat();
+ gravity = source.readInt();
+ }
+
+ public final int width;
+ public final float widthFraction;
+ public final int height;
+ public final float heightFraction;
+ public final int gravity;
}
}
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 924df1b39cb8..6443667ab1db 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -50,6 +50,7 @@ import android.util.Log;
import android.util.Pair;
import android.util.Slog;
import android.util.TypedValue;
+import android.view.Gravity;
import com.android.internal.R;
import com.android.internal.util.ArrayUtils;
@@ -3260,10 +3261,12 @@ public class PackageParser {
owner.preferredActivityFilters.add(intent);
}
} else if (parser.getName().equals("meta-data")) {
- if ((a.metaData=parseMetaData(res, parser, attrs, a.metaData,
+ if ((a.metaData = parseMetaData(res, parser, attrs, a.metaData,
outError)) == null) {
return null;
}
+ } else if (!receiver && parser.getName().equals("initial-layout")) {
+ parseInitialLayout(res, attrs, a);
} else {
if (!RIGID_PARSER) {
Slog.w(TAG, "Problem in package " + mArchiveSourcePath + ":");
@@ -3296,6 +3299,43 @@ public class PackageParser {
return a;
}
+ private void parseInitialLayout(Resources res, AttributeSet attrs, Activity a) {
+ TypedArray sw = res.obtainAttributes(attrs,
+ com.android.internal.R.styleable.AndroidManifestInitialLayout);
+ int width = -1;
+ float widthFraction = -1f;
+ int height = -1;
+ float heightFraction = -1f;
+ final int widthType = sw.getType(
+ com.android.internal.R.styleable.AndroidManifestInitialLayout_activity_width);
+ if (widthType == TypedValue.TYPE_FRACTION) {
+ widthFraction = sw.getFraction(
+ com.android.internal.R.styleable.AndroidManifestInitialLayout_activity_width,
+ 1, 1, -1);
+ } else if (widthType == TypedValue.TYPE_DIMENSION) {
+ width = sw.getDimensionPixelSize(
+ com.android.internal.R.styleable.AndroidManifestInitialLayout_activity_width,
+ -1);
+ }
+ final int heightType = sw.getType(
+ com.android.internal.R.styleable.AndroidManifestInitialLayout_activity_height);
+ if (heightType == TypedValue.TYPE_FRACTION) {
+ heightFraction = sw.getFraction(
+ com.android.internal.R.styleable.AndroidManifestInitialLayout_activity_height,
+ 1, 1, -1);
+ } else if (heightType == TypedValue.TYPE_DIMENSION) {
+ height = sw.getDimensionPixelSize(
+ com.android.internal.R.styleable.AndroidManifestInitialLayout_activity_height,
+ -1);
+ }
+ int gravity = sw.getInt(
+ com.android.internal.R.styleable.AndroidManifestInitialLayout_gravity,
+ Gravity.CENTER);
+ sw.recycle();
+ a.info.initialLayout = new ActivityInfo.InitialLayout(width, widthFraction,
+ height, heightFraction, gravity);
+ }
+
private Activity parseActivityAlias(Package owner, Resources res,
XmlPullParser parser, AttributeSet attrs, int flags, String[] outError)
throws XmlPullParserException, IOException {
diff --git a/core/java/android/text/TextUtils.java b/core/java/android/text/TextUtils.java
index 4d8a7d00ba89..49cb8e2c0e72 100644
--- a/core/java/android/text/TextUtils.java
+++ b/core/java/android/text/TextUtils.java
@@ -462,7 +462,7 @@ public class TextUtils {
/**
* Returns the length that the specified CharSequence would have if
- * spaces and control characters were trimmed from the start and end,
+ * spaces and ASCII control characters were trimmed from the start and end,
* as by {@link String#trim}.
*/
public static int getTrimmedLength(CharSequence s) {
@@ -505,7 +505,13 @@ public class TextUtils {
return false;
}
- // XXX currently this only reverses chars, not spans
+ /*
+ * @deprecated
+ * Do not use. This function only reverses individual {@code char}s and not their associated
+ * spans. It doesn't support surrogate pairs (that correspond to non-BMP code points),
+ * combining sequences or conjuncts either.
+ */
+ @Deprecated
public static CharSequence getReverse(CharSequence source,
int start, int end) {
return new Reverser(source, start, end);
@@ -1470,8 +1476,9 @@ public class TextUtils {
*/
public static boolean isDigitsOnly(CharSequence str) {
final int len = str.length();
- for (int i = 0; i < len; i++) {
- if (!Character.isDigit(str.charAt(i))) {
+ for (int cp, i = 0; i < len; i += Character.charCount(cp)) {
+ cp = Character.codePointAt(str, i);
+ if (!Character.isDigit(cp)) {
return false;
}
}
diff --git a/core/java/android/text/format/Formatter.java b/core/java/android/text/format/Formatter.java
index a53da0955f0c..9f5dfa695174 100644
--- a/core/java/android/text/format/Formatter.java
+++ b/core/java/android/text/format/Formatter.java
@@ -98,7 +98,8 @@ public final class Formatter {
/** {@hide} */
public static BytesResult formatBytes(Resources res, long sizeBytes, int flags) {
- float result = sizeBytes;
+ final boolean isNegative = (sizeBytes < 0);
+ float result = isNegative ? -sizeBytes : sizeBytes;
int suffix = com.android.internal.R.string.byteShort;
long mult = 1;
if (result > 900) {
@@ -154,9 +155,13 @@ public final class Formatter {
roundFormat = "%.2f";
}
}
+
+ if (isNegative) {
+ result = -result;
+ }
final String roundedString = String.format(roundFormat, result);
- // Note this might overflow if result >= Long.MAX_VALUE / 100, but that's like 80PB so
+ // Note this might overflow if abs(result) >= Long.MAX_VALUE / 100, but that's like 80PB so
// it's okay (for now)...
final long roundedBytes =
(flags & FLAG_CALCULATE_ROUNDED) == 0 ? 0
diff --git a/core/java/android/view/DisplayListCanvas.java b/core/java/android/view/DisplayListCanvas.java
index 948cec71d819..080ed9ae1841 100644
--- a/core/java/android/view/DisplayListCanvas.java
+++ b/core/java/android/view/DisplayListCanvas.java
@@ -20,12 +20,7 @@ import android.annotation.NonNull;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.CanvasProperty;
-import android.graphics.NinePatch;
import android.graphics.Paint;
-import android.graphics.Path;
-import android.graphics.Picture;
-import android.graphics.Rect;
-import android.graphics.RectF;
import android.util.Pools.SynchronizedPool;
/**
@@ -206,16 +201,12 @@ public class DisplayListCanvas extends Canvas {
* Draws the specified layer onto this canvas.
*
* @param layer The layer to composite on this canvas
- * @param x The left coordinate of the layer
- * @param y The top coordinate of the layer
- * @param paint The paint used to draw the layer
*/
- void drawHardwareLayer(HardwareLayer layer, float x, float y, Paint paint) {
- layer.setLayerPaint(paint);
- nDrawLayer(mNativeCanvasWrapper, layer.getLayerHandle(), x, y);
+ void drawHardwareLayer(HardwareLayer layer) {
+ nDrawLayer(mNativeCanvasWrapper, layer.getLayerHandle());
}
- private static native void nDrawLayer(long renderer, long layer, float x, float y);
+ private static native void nDrawLayer(long renderer, long layer);
///////////////////////////////////////////////////////////////////////////
// Drawing
diff --git a/core/java/android/view/HardwareLayer.java b/core/java/android/view/HardwareLayer.java
index 65ae8a649241..692ca7ba99cf 100644
--- a/core/java/android/view/HardwareLayer.java
+++ b/core/java/android/view/HardwareLayer.java
@@ -150,8 +150,4 @@ final class HardwareLayer {
private static native void nSetSurfaceTexture(long layerUpdater,
SurfaceTexture surface, boolean isAlreadyAttached);
private static native void nUpdateSurfaceTexture(long layerUpdater);
- private static native void nUpdateRenderLayer(long layerUpdater, long displayList,
- int left, int top, int right, int bottom);
-
- private static native int nGetTexName(long layerUpdater);
}
diff --git a/core/java/android/view/TextureView.java b/core/java/android/view/TextureView.java
index 197ea09e2d60..6b60be9c91b5 100644
--- a/core/java/android/view/TextureView.java
+++ b/core/java/android/view/TextureView.java
@@ -319,11 +319,25 @@ public class TextureView extends View {
*/
@Override
public final void draw(Canvas canvas) {
- // NOTE: Maintain this carefully (see View.java)
+ // NOTE: Maintain this carefully (see View#draw)
mPrivateFlags = (mPrivateFlags & ~PFLAG_DIRTY_MASK) | PFLAG_DRAWN;
- applyUpdate();
- applyTransformMatrix();
+ /* Simplify drawing to guarantee the layer is the only thing drawn - so e.g. no background,
+ scrolling, or fading edges. This guarantees all drawing is in the layer, so drawing
+ properties (alpha, layer paint) affect all of the content of a TextureView. */
+
+ if (canvas.isHardwareAccelerated()) {
+ DisplayListCanvas displayListCanvas = (DisplayListCanvas) canvas;
+
+ HardwareLayer layer = getHardwareLayer();
+ if (layer != null) {
+ applyUpdate();
+ applyTransformMatrix();
+
+ mLayer.setLayerPaint(mLayerPaint); // ensure layer paint is up to date
+ displayListCanvas.drawHardwareLayer(layer);
+ }
+ }
}
/**
@@ -359,12 +373,7 @@ public class TextureView extends View {
invalidate(true);
}
- @Override
HardwareLayer getHardwareLayer() {
- // NOTE: Maintain these two lines very carefully (see View.java)
- mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID;
- mPrivateFlags &= ~PFLAG_DIRTY_MASK;
-
if (mLayer == null) {
if (mAttachInfo == null || mAttachInfo.mHardwareRenderer == null) {
return null;
@@ -402,9 +411,6 @@ public class TextureView extends View {
mSurface.setDefaultBufferSize(getWidth(), getHeight());
}
- applyUpdate();
- applyTransformMatrix();
-
return mLayer;
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index a4925184f181..b17f88fc7497 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -15002,16 +15002,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
/**
- * If this View draws with a HardwareLayer, returns it.
- * Otherwise returns null
- *
- * TODO: Only TextureView uses this, can we eliminate it?
- */
- HardwareLayer getHardwareLayer() {
- return null;
- }
-
- /**
* Destroys all hardware rendering resources. This method is invoked
* when the system needs to reclaim resources. Upon execution of this
* method, you should free any OpenGL resources created by the view.
@@ -15161,10 +15151,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
canvas.setHighContrastText(mAttachInfo.mHighContrastText);
try {
- final HardwareLayer layer = getHardwareLayer();
- if (layer != null && layer.isValid()) {
- canvas.drawHardwareLayer(layer, 0, 0, mLayerPaint);
- } else if (layerType == LAYER_TYPE_SOFTWARE) {
+ if (layerType == LAYER_TYPE_SOFTWARE) {
buildDrawingCache(true);
Bitmap cache = getDrawingCache(true);
if (cache != null) {
diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java
index be26c2479d92..55e23b14b7d0 100644
--- a/core/java/com/android/internal/policy/PhoneWindow.java
+++ b/core/java/com/android/internal/policy/PhoneWindow.java
@@ -20,6 +20,7 @@ import static android.app.ActivityManager.FIRST_DYNAMIC_STACK_ID;
import static android.app.ActivityManager.FREEFORM_WORKSPACE_STACK_ID;
import static android.app.ActivityManager.FULLSCREEN_WORKSPACE_STACK_ID;
import static android.app.ActivityManager.HOME_STACK_ID;
+import static android.app.ActivityManager.INVALID_STACK_ID;
import static android.view.View.MeasureSpec.AT_MOST;
import static android.view.View.MeasureSpec.EXACTLY;
import static android.view.View.MeasureSpec.getMode;
@@ -5250,7 +5251,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
* @return Returns the workspace stack id which contains this window.
**/
private int getWorkspaceId() {
- int workspaceId = FULLSCREEN_WORKSPACE_STACK_ID;
+ int workspaceId = INVALID_STACK_ID;
WindowControllerCallback callback = getWindowControllerCallback();
if (callback != null) {
try {
@@ -5259,6 +5260,9 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
Log.e(TAG, "Failed to get the workspace ID of a PhoneWindow.");
}
}
+ if (workspaceId == INVALID_STACK_ID) {
+ return FULLSCREEN_WORKSPACE_STACK_ID;
+ }
return workspaceId;
}
diff --git a/core/jni/android/graphics/Path.cpp b/core/jni/android/graphics/Path.cpp
index f7b5dc24cea1..dbd7c89805ab 100644
--- a/core/jni/android/graphics/Path.cpp
+++ b/core/jni/android/graphics/Path.cpp
@@ -519,6 +519,9 @@ static JNINativeMethod methods[] = {
int register_android_graphics_Path(JNIEnv* env) {
return RegisterMethodsOrDie(env, "android/graphics/Path", methods, NELEM(methods));
+
+ static_assert(0 == SkPath::kCW_Direction, "direction_mismatch");
+ static_assert(1 == SkPath::kCCW_Direction, "direction_mismatch");
}
}
diff --git a/core/jni/android_view_DisplayListCanvas.cpp b/core/jni/android_view_DisplayListCanvas.cpp
index 3833325631c7..9c1d6b17608b 100644
--- a/core/jni/android_view_DisplayListCanvas.cpp
+++ b/core/jni/android_view_DisplayListCanvas.cpp
@@ -139,10 +139,10 @@ static void android_view_DisplayListCanvas_drawRenderNode(JNIEnv* env,
// ----------------------------------------------------------------------------
static void android_view_DisplayListCanvas_drawLayer(JNIEnv* env, jobject clazz,
- jlong rendererPtr, jlong layerPtr, jfloat x, jfloat y) {
+ jlong rendererPtr, jlong layerPtr) {
DisplayListCanvas* renderer = reinterpret_cast<DisplayListCanvas*>(rendererPtr);
DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerPtr);
- renderer->drawLayer(layer, x, y);
+ renderer->drawLayer(layer);
}
// ----------------------------------------------------------------------------
@@ -192,7 +192,7 @@ static JNINativeMethod gMethods[] = {
{ "nCreateDisplayListCanvas", "(II)J", (void*) android_view_DisplayListCanvas_createDisplayListCanvas },
{ "nResetDisplayListCanvas", "(JII)V", (void*) android_view_DisplayListCanvas_resetDisplayListCanvas },
- { "nDrawLayer", "(JJFF)V", (void*) android_view_DisplayListCanvas_drawLayer },
+ { "nDrawLayer", "(JJ)V", (void*) android_view_DisplayListCanvas_drawLayer },
{ "nGetMaximumTextureWidth", "()I", (void*) android_view_DisplayListCanvas_getMaxTextureWidth },
{ "nGetMaximumTextureHeight", "()I", (void*) android_view_DisplayListCanvas_getMaxTextureHeight },
diff --git a/core/jni/android_view_HardwareLayer.cpp b/core/jni/android_view_HardwareLayer.cpp
index 9e49afb45790..36ba892b51c4 100644
--- a/core/jni/android_view_HardwareLayer.cpp
+++ b/core/jni/android_view_HardwareLayer.cpp
@@ -79,12 +79,6 @@ static void android_view_HardwareLayer_updateSurfaceTexture(JNIEnv* env, jobject
layer->updateTexImage();
}
-static jint android_view_HardwareLayer_getTexName(JNIEnv* env, jobject clazz,
- jlong layerUpdaterPtr) {
- DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerUpdaterPtr);
- return layer->backingLayer()->getTextureId();
-}
-
// ----------------------------------------------------------------------------
// JNI Glue
// ----------------------------------------------------------------------------
@@ -98,8 +92,6 @@ static JNINativeMethod gMethods[] = {
{ "nSetSurfaceTexture", "(JLandroid/graphics/SurfaceTexture;Z)V",
(void*) android_view_HardwareLayer_setSurfaceTexture },
{ "nUpdateSurfaceTexture", "(J)V", (void*) android_view_HardwareLayer_updateSurfaceTexture },
-
- { "nGetTexName", "(J)I", (void*) android_view_HardwareLayer_getTexName },
};
int register_android_view_HardwareLayer(JNIEnv* env) {
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 2fcce675bb37..fefd5a7abba3 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -786,6 +786,46 @@
android:protectionLevel="normal"
android:permissionFlags="hidden"/>
+ <!-- @hide We need to keep this around for backwards compatibility -->
+ <permission android:name="android.permission.WRITE_SMS"
+ android:protectionLevel="normal"
+ android:permissionFlags="hidden"/>
+
+ <!-- @hide We need to keep this around for backwards compatibility -->
+ <permission android:name="com.android.browser.permission.READ_HISTORY_BOOKMARKS"
+ android:protectionLevel="normal"
+ android:permissionFlags="hidden"/>
+
+ <!-- @hide We need to keep this around for backwards compatibility -->
+ <permission android:name="com.android.browser.permission.WRITE_HISTORY_BOOKMARKS"
+ android:protectionLevel="normal"
+ android:permissionFlags="hidden"/>
+
+ <!-- @hide We need to keep this around for backwards compatibility -->
+ <permission android:name="android.permission.AUTHENTICATE_ACCOUNTS"
+ android:protectionLevel="normal"
+ android:permissionFlags="hidden"/>
+
+ <!-- @hide We need to keep this around for backwards compatibility -->
+ <permission android:name="android.permission.MANAGE_ACCOUNTS"
+ android:protectionLevel="normal"
+ android:permissionFlags="hidden"/>
+
+ <!-- @hide We need to keep this around for backwards compatibility -->
+ <permission android:name="android.permission.USE_CREDENTIALS"
+ android:protectionLevel="normal"
+ android:permissionFlags="hidden"/>
+
+ <!-- @hide We need to keep this around for backwards compatibility -->
+ <permission android:name="android.permission.SUBSCRIBED_FEEDS_READ"
+ android:protectionLevel="normal"
+ android:permissionFlags="hidden"/>
+
+ <!-- @hide We need to keep this around for backwards compatibility -->
+ <permission android:name="android.permission.SUBSCRIBED_FEEDS_WRITE"
+ android:protectionLevel="normal"
+ android:permissionFlags="hidden"/>
+
<!-- ====================================================================== -->
<!-- INSTALL PERMISSIONS -->
<!-- ====================================================================== -->
diff --git a/core/res/res/drawable/scrollbar_handle_material.xml b/core/res/res/drawable/scrollbar_handle_material.xml
index 56fececcc2c2..33efbbac8690 100644
--- a/core/res/res/drawable/scrollbar_handle_material.xml
+++ b/core/res/res/drawable/scrollbar_handle_material.xml
@@ -17,6 +17,9 @@
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:tint="?attr/colorControlNormal"
android:shape="rectangle">
- <solid android:color="#84ffffff" />
- <size android:width="4dp" />
+ <solid
+ android:color="#84ffffff" />
+ <size
+ android:width="4dp"
+ android:height="4dp" />
</shape>
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 1a45b3ac75b3..74fd1eccd4db 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -2195,4 +2195,18 @@
<attr name="name" />
</declare-styleable>
+ <!-- <code>initial-layout</code> tag allows configuring the initial layout for the activity
+ within multi-window environment. -->
+ <declare-styleable name="AndroidManifestInitialLayout" parent="AndroidManifestActivity">
+ <!-- Initial width of the activity. Can be either a fixed value or fraction, in which case
+ the width will be constructed as a fraction of the total available width. -->
+ <attr name="activity_width" format="dimension|fraction" />
+ <!-- Initial height of the activity. Can be either a fixed value or fraction, in which case
+ the height will be constructed as a fraction of the total available height. -->
+ <attr name="activity_height" format="dimension|fraction" />
+ <!-- Where to initially position the activity inside the available space. Uses constants
+ defined in {@link android.view.Gravity}. -->
+ <attr name="gravity" />
+ </declare-styleable>
+
</resources>
diff --git a/core/tests/coretests/src/android/animation/ValueAnimatorTests.java b/core/tests/coretests/src/android/animation/ValueAnimatorTests.java
index f3b81377bd07..03ae9dc3f510 100644
--- a/core/tests/coretests/src/android/animation/ValueAnimatorTests.java
+++ b/core/tests/coretests/src/android/animation/ValueAnimatorTests.java
@@ -19,6 +19,8 @@ import android.os.SystemClock;
import android.test.ActivityInstrumentationTestCase2;
import android.test.suitebuilder.annotation.SmallTest;
+import static android.test.MoreAsserts.assertNotEqual;
+
public class ValueAnimatorTests extends ActivityInstrumentationTestCase2<BasicAnimatorActivity> {
private ValueAnimator a1;
private ValueAnimator a2;
@@ -27,6 +29,11 @@ public class ValueAnimatorTests extends ActivityInstrumentationTestCase2<BasicAn
private final static long TOLERANCE = 100; // ms
private final static long POLL_INTERVAL = 100; // ms
+ private final static float A1_START_VALUE = 0f;
+ private final static float A1_END_VALUE = 1f;
+ private final static int A2_START_VALUE = 100;
+ private final static int A2_END_VALUE = 200;
+
public ValueAnimatorTests() {
super(BasicAnimatorActivity.class);
}
@@ -34,8 +41,8 @@ public class ValueAnimatorTests extends ActivityInstrumentationTestCase2<BasicAn
@Override
public void setUp() throws Exception {
super.setUp();
- a1 = ValueAnimator.ofFloat(0, 1f).setDuration(300);
- a2 = ValueAnimator.ofInt(100, 200).setDuration(500);
+ a1 = ValueAnimator.ofFloat(A1_START_VALUE, A1_END_VALUE).setDuration(300);
+ a2 = ValueAnimator.ofInt(A2_START_VALUE, A2_END_VALUE).setDuration(500);
}
@Override
@@ -379,6 +386,55 @@ public class ValueAnimatorTests extends ActivityInstrumentationTestCase2<BasicAn
assertTrue(Math.abs(entireSpan - frameDelta) < TOLERANCE);
}
+ @SmallTest
+ public void testEndValue() throws Throwable {
+ final MyListener l1 = new MyListener();
+ a1.addListener(l1);
+
+ final MyListener l2 = new MyListener();
+ a2.addListener(l2);
+
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ a1.start();
+ a2.start();
+ }
+ });
+
+ Thread.sleep(POLL_INTERVAL);
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ // Animation has started but not finished, check animated values against end values
+ assertFalse(l1.endCalled);
+ assertFalse(l2.endCalled);
+ assertNotEqual(A1_END_VALUE, a1.getAnimatedValue());
+ assertNotEqual(A1_END_VALUE, a2.getAnimatedValue());
+
+ // Force a2 to end.
+ a2.end();
+ }
+ });
+
+ Thread.sleep(a1.getTotalDuration());
+
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ assertFalse(l1.cancelCalled);
+ assertTrue(l1.endCalled);
+ assertFalse(l2.cancelCalled);
+ assertTrue(l2.endCalled);
+
+ // By now a1 should have finished normally and a2 has skipped to the end, check
+ // their end values.
+ assertEquals(A1_END_VALUE, ((Float) (a1.getAnimatedValue())).floatValue());
+ assertEquals(A2_END_VALUE, ((Integer) (a2.getAnimatedValue())).intValue());
+ }
+ });
+ }
+
class MyUpdateListener implements ValueAnimator.AnimatorUpdateListener {
boolean wasRunning = false;
long firstRunningFrameTime = -1;
diff --git a/core/tests/coretests/src/android/text/format/FormatterTest.java b/core/tests/coretests/src/android/text/format/FormatterTest.java
index d2e2131c2da0..be6e7ea5965e 100644
--- a/core/tests/coretests/src/android/text/format/FormatterTest.java
+++ b/core/tests/coretests/src/android/text/format/FormatterTest.java
@@ -56,14 +56,14 @@ public class FormatterTest extends AndroidTestCase {
public void testFormatBytes() {
setLocale(Locale.ENGLISH);
- checkFormatBytes(0, true, "0.00", 0);
- checkFormatBytes(0, false, "0.00", 0);
+ checkFormatBytes(0, true, "0", 0);
+ checkFormatBytes(0, false, "0", 0);
- checkFormatBytes(1, true, "1.0", 1);
- checkFormatBytes(1, false, "1.00", 1);
+ checkFormatBytes(1, true, "1", 1);
+ checkFormatBytes(1, false, "1", 1);
checkFormatBytes(12, true, "12", 12);
- checkFormatBytes(12, false, "12.00", 12);
+ checkFormatBytes(12, false, "12", 12);
checkFormatBytes(123, true, "123", 123);
checkFormatBytes(123, false, "123", 123);
@@ -80,13 +80,15 @@ public class FormatterTest extends AndroidTestCase {
checkFormatBytes(9123000, true, "8.7", 9122611);
checkFormatBytes(9123000, false, "8.70", 9122611);
- // The method doesn't really support negative values, but apparently people pass -1...
- checkFormatBytes(-1, true, "-1.00", -1);
- checkFormatBytes(-1, false, "-1.00", -1);
+ checkFormatBytes(-1, true, "-1", -1);
+ checkFormatBytes(-1, false, "-1", -1);
+
+ checkFormatBytes(-912, true, "-0.89", -911);
+ checkFormatBytes(-912, false, "-0.89", -911);
// Missing FLAG_CALCULATE_ROUNDED case.
BytesResult r = Formatter.formatBytes(getContext().getResources(), 1, 0);
- assertEquals("1.00", r.value);
+ assertEquals("1", r.value);
assertEquals(0, r.roundedBytes); // Didn't pass FLAG_CALCULATE_ROUNDED
// Make sure it works on different locales.
diff --git a/core/tests/coretests/src/android/widget/TextViewTest.java b/core/tests/coretests/src/android/widget/TextViewTest.java
index 0b94f8b2c57a..49d9115319e8 100644
--- a/core/tests/coretests/src/android/widget/TextViewTest.java
+++ b/core/tests/coretests/src/android/widget/TextViewTest.java
@@ -18,7 +18,7 @@ package android.widget;
import android.app.Activity;
import android.content.Intent;
-import android.test.AndroidTestCase;
+import android.test.ActivityInstrumentationTestCase2;
import android.test.suitebuilder.annotation.SmallTest;
import android.text.GetChars;
import android.text.Selection;
@@ -27,11 +27,15 @@ import android.text.Spannable;
/**
* TextViewTest tests {@link TextView}.
*/
-public class TextViewTest extends AndroidTestCase {
+public class TextViewTest extends ActivityInstrumentationTestCase2<TextViewActivity> {
+
+ public TextViewTest() {
+ super(TextViewActivity.class);
+ }
@SmallTest
public void testArray() throws Exception {
- TextView tv = new TextView(mContext);
+ TextView tv = new TextView(getActivity());
char[] c = new char[] { 'H', 'e', 'l', 'l', 'o', ' ',
'W', 'o', 'r', 'l', 'd', '!' };
@@ -59,25 +63,34 @@ public class TextViewTest extends AndroidTestCase {
assertEquals('\0', c2[5]);
}
+ @SmallTest
public void testProcessTextActivityResultNonEditable() {
- TextView tv = new TextView(mContext);
+ final TextView tv = new TextView(getActivity());
CharSequence originalText = "This is some text.";
tv.setText(originalText, TextView.BufferType.SPANNABLE);
assertEquals(originalText, tv.getText().toString());
tv.setTextIsSelectable(true);
Selection.setSelection((Spannable) tv.getText(), 0, tv.getText().length());
- CharSequence newText = "Text is replaced.";
- Intent data = new Intent();
- data.putExtra(Intent.EXTRA_PROCESS_TEXT, newText);
- tv.onActivityResult(TextView.PROCESS_TEXT_REQUEST_CODE, Activity.RESULT_OK, data);
+ // We need to run this in the UI thread, as it will create a Toast.
+ getActivity().runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ CharSequence newText = "Text is replaced.";
+ Intent data = new Intent();
+ data.putExtra(Intent.EXTRA_PROCESS_TEXT, newText);
+ tv.onActivityResult(TextView.PROCESS_TEXT_REQUEST_CODE, Activity.RESULT_OK, data);
+ }
+ });
+ getInstrumentation().waitForIdleSync();
// This is a TextView, which can't be modified. Hence no change should have been made.
assertEquals(originalText, tv.getText().toString());
}
+ @SmallTest
public void testProcessTextActivityResultEditable() {
- EditText tv = new EditText(mContext);
+ EditText tv = new EditText(getActivity());
CharSequence originalText = "This is some text.";
tv.setText(originalText, TextView.BufferType.SPANNABLE);
assertEquals(originalText, tv.getText().toString());
@@ -92,8 +105,9 @@ public class TextViewTest extends AndroidTestCase {
assertEquals(newText, tv.getText().toString());
}
+ @SmallTest
public void testProcessTextActivityResultCancel() {
- EditText tv = new EditText(mContext);
+ EditText tv = new EditText(getActivity());
CharSequence originalText = "This is some text.";
tv.setText(originalText, TextView.BufferType.SPANNABLE);
assertEquals(originalText, tv.getText().toString());
@@ -108,8 +122,9 @@ public class TextViewTest extends AndroidTestCase {
assertEquals(originalText, tv.getText().toString());
}
+ @SmallTest
public void testProcessTextActivityNoData() {
- EditText tv = new EditText(mContext);
+ EditText tv = new EditText(getActivity());
CharSequence originalText = "This is some text.";
tv.setText(originalText, TextView.BufferType.SPANNABLE);
assertEquals(originalText, tv.getText().toString());
diff --git a/docs/html/training/wearables/watch-faces/index.jd b/docs/html/training/wearables/watch-faces/index.jd
index b54463684033..a329fda071bc 100644
--- a/docs/html/training/wearables/watch-faces/index.jd
+++ b/docs/html/training/wearables/watch-faces/index.jd
@@ -66,7 +66,7 @@ Drawing Watch Faces</a></dt>
Showing Information in Watch Faces</a></dt>
<dd>Learn how to incorporate contextual information into your watch face.</dd>
<dt><a href="{@docRoot}training/wearables/watch-faces/interacting.html">
-Making Your Watch Face Interactive </a></dt>
+Creating Interactive Watch Faces</a></dt>
<dd>Learn how to enable the user to interact with your watch face.</dd>
<dt><a href="{@docRoot}training/wearables/watch-faces/configuration.html">
Providing Configuration Activities</a></dt>
diff --git a/docs/html/training/wearables/watch-faces/interacting.jd b/docs/html/training/wearables/watch-faces/interacting.jd
index 4f2486cf416f..5a44fdeeb300 100644
--- a/docs/html/training/wearables/watch-faces/interacting.jd
+++ b/docs/html/training/wearables/watch-faces/interacting.jd
@@ -62,10 +62,10 @@ implementation.</p>
reserves gestures such as drag and long-press for system UI elements.
Therefore, the system does not send raw touch events to the watch face. Instead, the system forwards specific commands to the
<a href="{@docRoot}reference/android/support/wearable/watchface/WatchFaceService.Engine.html#onTapCommand(int, int, int, long)">
-method.
+onTapCommand()</a> method.
<p>The system sends the first command,
-<a href="{@docRoot}reference/android/support/wearable/watchface/WatchFaceService.html#TAP_TYPE_TOUCH"</a>
+<a href="{@docRoot}reference/android/support/wearable/watchface/WatchFaceService.html#TAP_TYPE_TOUCH">
{@code TAP_TYPE_TOUCH}</a>, when the user initially touches the
screen. This event lets you provide visual feedback to the user on touch. Your app should not
launch a UI when this event triggers. Launching a UI prevents drag events from opening the app
diff --git a/graphics/java/android/graphics/Path.java b/graphics/java/android/graphics/Path.java
index 0e9823d1661f..91e704a901cb 100644
--- a/graphics/java/android/graphics/Path.java
+++ b/graphics/java/android/graphics/Path.java
@@ -486,9 +486,9 @@ public class Path {
*/
public enum Direction {
/** clockwise */
- CW (1), // must match enum in SkPath.h
+ CW (0), // must match enum in SkPath.h
/** counter-clockwise */
- CCW (2); // must match enum in SkPath.h
+ CCW (1); // must match enum in SkPath.h
Direction(int ni) {
nativeInt = ni;
diff --git a/graphics/java/android/graphics/drawable/RippleDrawable.java b/graphics/java/android/graphics/drawable/RippleDrawable.java
index 32f6a895f35d..464f3de5d29b 100644
--- a/graphics/java/android/graphics/drawable/RippleDrawable.java
+++ b/graphics/java/android/graphics/drawable/RippleDrawable.java
@@ -855,7 +855,8 @@ public class RippleDrawable extends LayerDrawable {
// Position the shader to account for canvas translation.
if (mMaskShader != null) {
- mMaskMatrix.setTranslate(-x, -y);
+ final Rect bounds = getBounds();
+ mMaskMatrix.setTranslate(bounds.left - x, bounds.top - y);
mMaskShader.setLocalMatrix(mMaskMatrix);
}
diff --git a/libs/hwui/CanvasState.cpp b/libs/hwui/CanvasState.cpp
index 54fb5f233fce..e307ad91885f 100644
--- a/libs/hwui/CanvasState.cpp
+++ b/libs/hwui/CanvasState.cpp
@@ -155,17 +155,20 @@ void CanvasState::concatMatrix(const Matrix4& matrix) {
///////////////////////////////////////////////////////////////////////////////
bool CanvasState::clipRect(float left, float top, float right, float bottom, SkRegion::Op op) {
- mDirtyClip |= mSnapshot->clip(left, top, right, bottom, op);
+ mSnapshot->clip(left, top, right, bottom, op);
+ mDirtyClip = true;
return !mSnapshot->clipIsEmpty();
}
bool CanvasState::clipPath(const SkPath* path, SkRegion::Op op) {
- mDirtyClip |= mSnapshot->clipPath(*path, op);
+ mSnapshot->clipPath(*path, op);
+ mDirtyClip = true;
return !mSnapshot->clipIsEmpty();
}
bool CanvasState::clipRegion(const SkRegion* region, SkRegion::Op op) {
- mDirtyClip |= mSnapshot->clipRegionTransformed(*region, op);
+ mSnapshot->clipRegionTransformed(*region, op);
+ mDirtyClip = true;
return !mSnapshot->clipIsEmpty();
}
diff --git a/libs/hwui/ClipArea.cpp b/libs/hwui/ClipArea.cpp
index b1a68447fc21..8e7efb4e35d6 100644
--- a/libs/hwui/ClipArea.cpp
+++ b/libs/hwui/ClipArea.cpp
@@ -32,9 +32,7 @@ static bool intersect(Rect& r, const Rect& r2) {
}
static void handlePoint(Rect& transformedBounds, const Matrix4& transform, float x, float y) {
- Vertex v;
- v.x = x;
- v.y = y;
+ Vertex v = {x, y};
transform.mapPoint(v.x, v.y);
transformedBounds.expandToCoverVertex(v.x, v.y);
}
@@ -187,7 +185,7 @@ SkRegion RectangleList::convertToRegion(const SkRegion& clip) const {
*/
ClipArea::ClipArea()
- : mMode(kModeRectangle) {
+ : mMode(Mode::Rectangle) {
}
/*
@@ -200,45 +198,46 @@ void ClipArea::setViewportDimensions(int width, int height) {
}
void ClipArea::setEmpty() {
- mMode = kModeRectangle;
+ mMode = Mode::Rectangle;
mClipRect.setEmpty();
mClipRegion.setEmpty();
mRectangleList.setEmpty();
}
void ClipArea::setClip(float left, float top, float right, float bottom) {
- mMode = kModeRectangle;
+ mMode = Mode::Rectangle;
mClipRect.set(left, top, right, bottom);
mClipRegion.setEmpty();
}
-bool ClipArea::clipRectWithTransform(float left, float top, float right,
+void ClipArea::clipRectWithTransform(float left, float top, float right,
float bottom, const mat4* transform, SkRegion::Op op) {
Rect r(left, top, right, bottom);
- return clipRectWithTransform(r, transform, op);
+ clipRectWithTransform(r, transform, op);
}
-bool ClipArea::clipRectWithTransform(const Rect& r, const mat4* transform,
+void ClipArea::clipRectWithTransform(const Rect& r, const mat4* transform,
SkRegion::Op op) {
switch (mMode) {
- case kModeRectangle:
- return rectangleModeClipRectWithTransform(r, transform, op);
- case kModeRectangleList:
- return rectangleListModeClipRectWithTransform(r, transform, op);
- case kModeRegion:
- return regionModeClipRectWithTransform(r, transform, op);
+ case Mode::Rectangle:
+ rectangleModeClipRectWithTransform(r, transform, op);
+ break;
+ case Mode::RectangleList:
+ rectangleListModeClipRectWithTransform(r, transform, op);
+ break;
+ case Mode::Region:
+ regionModeClipRectWithTransform(r, transform, op);
+ break;
}
- return false;
}
-bool ClipArea::clipRegion(const SkRegion& region, SkRegion::Op op) {
+void ClipArea::clipRegion(const SkRegion& region, SkRegion::Op op) {
enterRegionMode();
mClipRegion.op(region, op);
onClipRegionUpdated();
- return true;
}
-bool ClipArea::clipPathWithTransform(const SkPath& path, const mat4* transform,
+void ClipArea::clipPathWithTransform(const SkPath& path, const mat4* transform,
SkRegion::Op op) {
SkMatrix skTransform;
transform->copyTo(skTransform);
@@ -246,7 +245,7 @@ bool ClipArea::clipPathWithTransform(const SkPath& path, const mat4* transform,
path.transform(skTransform, &transformed);
SkRegion region;
regionFromPath(transformed, region);
- return clipRegion(region, op);
+ clipRegion(region, op);
}
/*
@@ -257,19 +256,20 @@ void ClipArea::enterRectangleMode() {
// Entering rectangle mode discards any
// existing clipping information from the other modes.
// The only way this occurs is by a clip setting operation.
- mMode = kModeRectangle;
+ mMode = Mode::Rectangle;
}
-bool ClipArea::rectangleModeClipRectWithTransform(const Rect& r,
+void ClipArea::rectangleModeClipRectWithTransform(const Rect& r,
const mat4* transform, SkRegion::Op op) {
if (op == SkRegion::kReplace_Op && transform->rectToRect()) {
mClipRect = r;
transform->mapRect(mClipRect);
- return true;
+ return;
} else if (op != SkRegion::kIntersect_Op) {
enterRegionMode();
- return regionModeClipRectWithTransform(r, transform, op);
+ regionModeClipRectWithTransform(r, transform, op);
+ return;
}
if (transform->rectToRect()) {
@@ -279,19 +279,18 @@ bool ClipArea::rectangleModeClipRectWithTransform(const Rect& r,
if (!hasIntersection) {
mClipRect.setEmpty();
}
- return true;
+ return;
}
enterRectangleListMode();
- return rectangleListModeClipRectWithTransform(r, transform, op);
+ rectangleListModeClipRectWithTransform(r, transform, op);
}
-bool ClipArea::rectangleModeClipRectWithTransform(float left, float top,
+void ClipArea::rectangleModeClipRectWithTransform(float left, float top,
float right, float bottom, const mat4* transform, SkRegion::Op op) {
Rect r(left, top, right, bottom);
- bool result = rectangleModeClipRectWithTransform(r, transform, op);
+ rectangleModeClipRectWithTransform(r, transform, op);
mClipRect = mRectangleList.calculateBounds();
- return result;
}
/*
@@ -302,25 +301,24 @@ void ClipArea::enterRectangleListMode() {
// Is is only legal to enter rectangle list mode from
// rectangle mode, since rectangle list mode cannot represent
// all clip areas that can be represented by a region.
- ALOG_ASSERT(mMode == kModeRectangle);
- mMode = kModeRectangleList;
+ ALOG_ASSERT(mMode == Mode::Rectangle);
+ mMode = Mode::RectangleList;
mRectangleList.set(mClipRect, Matrix4::identity());
}
-bool ClipArea::rectangleListModeClipRectWithTransform(const Rect& r,
+void ClipArea::rectangleListModeClipRectWithTransform(const Rect& r,
const mat4* transform, SkRegion::Op op) {
if (op != SkRegion::kIntersect_Op
|| !mRectangleList.intersectWith(r, *transform)) {
enterRegionMode();
- return regionModeClipRectWithTransform(r, transform, op);
+ regionModeClipRectWithTransform(r, transform, op);
}
- return true;
}
-bool ClipArea::rectangleListModeClipRectWithTransform(float left, float top,
+void ClipArea::rectangleListModeClipRectWithTransform(float left, float top,
float right, float bottom, const mat4* transform, SkRegion::Op op) {
Rect r(left, top, right, bottom);
- return rectangleListModeClipRectWithTransform(r, transform, op);
+ rectangleListModeClipRectWithTransform(r, transform, op);
}
/*
@@ -329,9 +327,9 @@ bool ClipArea::rectangleListModeClipRectWithTransform(float left, float top,
void ClipArea::enterRegionMode() {
Mode oldMode = mMode;
- mMode = kModeRegion;
- if (oldMode != kModeRegion) {
- if (oldMode == kModeRectangle) {
+ mMode = Mode::Region;
+ if (oldMode != Mode::Region) {
+ if (oldMode == Mode::Rectangle) {
mClipRegion.setRect(mClipRect.left, mClipRect.top,
mClipRect.right, mClipRect.bottom);
} else {
@@ -341,20 +339,18 @@ void ClipArea::enterRegionMode() {
}
}
-bool ClipArea::regionModeClipRectWithTransform(const Rect& r,
+void ClipArea::regionModeClipRectWithTransform(const Rect& r,
const mat4* transform, SkRegion::Op op) {
SkPath transformedRect = pathFromTransformedRectangle(r, *transform);
SkRegion transformedRectRegion;
regionFromPath(transformedRect, transformedRectRegion);
mClipRegion.op(transformedRectRegion, op);
onClipRegionUpdated();
- return true;
}
-bool ClipArea::regionModeClipRectWithTransform(float left, float top,
+void ClipArea::regionModeClipRectWithTransform(float left, float top,
float right, float bottom, const mat4* transform, SkRegion::Op op) {
- return regionModeClipRectWithTransform(Rect(left, top, right, bottom),
- transform, op);
+ regionModeClipRectWithTransform(Rect(left, top, right, bottom), transform, op);
}
void ClipArea::onClipRegionUpdated() {
diff --git a/libs/hwui/ClipArea.h b/libs/hwui/ClipArea.h
index 51ef27b4e9cc..38fefe5ab097 100644
--- a/libs/hwui/ClipArea.h
+++ b/libs/hwui/ClipArea.h
@@ -80,6 +80,13 @@ private:
};
class ClipArea {
+private:
+ enum class Mode {
+ Rectangle,
+ Region,
+ RectangleList
+ };
+
public:
ClipArea();
@@ -91,12 +98,12 @@ public:
void setEmpty();
void setClip(float left, float top, float right, float bottom);
- bool clipRectWithTransform(float left, float top, float right, float bottom,
- const mat4* transform, SkRegion::Op op = SkRegion::kIntersect_Op);
- bool clipRectWithTransform(const Rect& r, const mat4* transform,
- SkRegion::Op op = SkRegion::kIntersect_Op);
- bool clipRegion(const SkRegion& region, SkRegion::Op op = SkRegion::kIntersect_Op);
- bool clipPathWithTransform(const SkPath& path, const mat4* transform,
+ void clipRectWithTransform(float left, float top, float right, float bottom,
+ const mat4* transform, SkRegion::Op op);
+ void clipRectWithTransform(const Rect& r, const mat4* transform,
+ SkRegion::Op op);
+ void clipRegion(const SkRegion& region, SkRegion::Op op);
+ void clipPathWithTransform(const SkPath& path, const mat4* transform,
SkRegion::Op op);
const Rect& getClipRect() const {
@@ -112,41 +119,39 @@ public:
}
bool isRegion() const {
- return kModeRegion == mMode;
+ return Mode::Region == mMode;
}
bool isSimple() const {
- return mMode == kModeRectangle;
+ return mMode == Mode::Rectangle;
}
bool isRectangleList() const {
- return mMode == kModeRectangleList;
+ return mMode == Mode::RectangleList;
}
private:
void enterRectangleMode();
- bool rectangleModeClipRectWithTransform(const Rect& r, const mat4* transform, SkRegion::Op op);
- bool rectangleModeClipRectWithTransform(float left, float top, float right,
+ void rectangleModeClipRectWithTransform(const Rect& r, const mat4* transform, SkRegion::Op op);
+ void rectangleModeClipRectWithTransform(float left, float top, float right,
float bottom, const mat4* transform, SkRegion::Op op);
void enterRectangleListMode();
- bool rectangleListModeClipRectWithTransform(float left, float top,
+ void rectangleListModeClipRectWithTransform(float left, float top,
float right, float bottom, const mat4* transform, SkRegion::Op op);
- bool rectangleListModeClipRectWithTransform(const Rect& r,
+ void rectangleListModeClipRectWithTransform(const Rect& r,
const mat4* transform, SkRegion::Op op);
void enterRegionModeFromRectangleMode();
void enterRegionModeFromRectangleListMode();
void enterRegionMode();
- bool regionModeClipRectWithTransform(const Rect& r, const mat4* transform,
+ void regionModeClipRectWithTransform(const Rect& r, const mat4* transform,
SkRegion::Op op);
- bool regionModeClipRectWithTransform(float left, float top, float right,
+ void regionModeClipRectWithTransform(float left, float top, float right,
float bottom, const mat4* transform, SkRegion::Op op);
void ensureClipRegion();
void onClipRegionUpdated();
- bool clipRegionOp(float left, float top, float right, float bottom,
- SkRegion::Op op);
SkRegion createViewportRegion() {
return SkRegion(mViewportBounds.toSkIRect());
@@ -158,12 +163,6 @@ private:
pathAsRegion.setPath(path, createViewportRegion());
}
- enum Mode {
- kModeRectangle,
- kModeRegion,
- kModeRectangleList
- };
-
Mode mMode;
Rect mViewportBounds;
Rect mClipRect;
diff --git a/libs/hwui/DisplayListCanvas.cpp b/libs/hwui/DisplayListCanvas.cpp
index bb149fe09d69..506bfad08c1b 100644
--- a/libs/hwui/DisplayListCanvas.cpp
+++ b/libs/hwui/DisplayListCanvas.cpp
@@ -216,11 +216,11 @@ void DisplayListCanvas::drawRenderNode(RenderNode* renderNode) {
addRenderNodeOp(op);
}
-void DisplayListCanvas::drawLayer(DeferredLayerUpdater* layerHandle, float x, float y) {
+void DisplayListCanvas::drawLayer(DeferredLayerUpdater* layerHandle) {
// We ref the DeferredLayerUpdater due to its thread-safe ref-counting
// semantics.
mDisplayListData->ref(layerHandle);
- addDrawOp(new (alloc()) DrawLayerOp(layerHandle->backingLayer(), x, y));
+ addDrawOp(new (alloc()) DrawLayerOp(layerHandle->backingLayer()));
}
void DisplayListCanvas::drawBitmap(const SkBitmap* bitmap, const SkPaint* paint) {
diff --git a/libs/hwui/DisplayListCanvas.h b/libs/hwui/DisplayListCanvas.h
index f29e835c4858..392bb3e5d85f 100644
--- a/libs/hwui/DisplayListCanvas.h
+++ b/libs/hwui/DisplayListCanvas.h
@@ -91,7 +91,7 @@ public:
// ----------------------------------------------------------------------------
// HWUI Canvas draw operations - special
// ----------------------------------------------------------------------------
- void drawLayer(DeferredLayerUpdater* layerHandle, float x, float y);
+ void drawLayer(DeferredLayerUpdater* layerHandle);
void drawRenderNode(RenderNode* renderNode);
// TODO: rename for consistency
diff --git a/libs/hwui/DisplayListOp.h b/libs/hwui/DisplayListOp.h
index 8bb892f8e9d4..14126a9e31a7 100644
--- a/libs/hwui/DisplayListOp.h
+++ b/libs/hwui/DisplayListOp.h
@@ -1524,23 +1524,21 @@ private:
class DrawLayerOp : public DrawOp {
public:
- DrawLayerOp(Layer* layer, float x, float y)
- : DrawOp(nullptr), mLayer(layer), mX(x), mY(y) {}
+ DrawLayerOp(Layer* layer)
+ : DrawOp(nullptr), mLayer(layer) {}
virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override {
- renderer.drawLayer(mLayer, mX, mY);
+ renderer.drawLayer(mLayer);
}
virtual void output(int level, uint32_t logFlags) const override {
- OP_LOG("Draw Layer %p at %f %f", mLayer, mX, mY);
+ OP_LOG("Draw Layer %p", mLayer);
}
virtual const char* name() override { return "DrawLayer"; }
private:
Layer* mLayer;
- float mX;
- float mY;
};
}; // namespace uirenderer
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index b35c0179193a..5692d7e120ff 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -2268,7 +2268,7 @@ void OpenGLRenderer::drawPath(const SkPath* path, const SkPaint* paint) {
mDirty = true;
}
-void OpenGLRenderer::drawLayer(Layer* layer, float x, float y) {
+void OpenGLRenderer::drawLayer(Layer* layer) {
if (!layer) {
return;
}
@@ -2284,7 +2284,7 @@ void OpenGLRenderer::drawLayer(Layer* layer, float x, float y) {
bool clipRequired = false;
const bool rejected = mState.calculateQuickRejectForScissor(
- x, y, x + layer->layer.getWidth(), y + layer->layer.getHeight(),
+ 0, 0, layer->layer.getWidth(), layer->layer.getHeight(),
&clipRequired, nullptr, false);
if (rejected) {
@@ -2313,7 +2313,7 @@ void OpenGLRenderer::drawLayer(Layer* layer, float x, float y) {
.setMeshTexturedIndexedQuads(layer->mesh, layer->meshElementCount)
.setFillLayer(layer->getTexture(), layer->getColorFilter(), getLayerAlpha(layer), layer->getMode(), Blend::ModeOrderSwap::NoSwap)
.setTransform(*currentSnapshot(), TransformFlags::None)
- .setModelViewOffsetRectSnap(x, y, Rect(0, 0, layer->layer.getWidth(), layer->layer.getHeight()))
+ .setModelViewOffsetRectSnap(0, 0, Rect(0, 0, layer->layer.getWidth(), layer->layer.getHeight()))
.build();
DRAW_DOUBLE_STENCIL_IF(!layer->hasDrawnSinceUpdate, renderGlop(glop));
#if DEBUG_LAYERS_AS_REGIONS
@@ -2326,7 +2326,7 @@ void OpenGLRenderer::drawLayer(Layer* layer, float x, float y) {
SkPaint paint;
paint.setColor(0x7f00ff00);
- drawColorRect(x, y, x + layer->layer.getWidth(), y + layer->layer.getHeight(), &paint);
+ drawColorRect(0, 0, layer->layer.getWidth(), layer->layer.getHeight(), &paint);
}
}
layer->hasDrawnSinceUpdate = true;
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index 45662a77cfdd..af85e8c72619 100755
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -35,6 +35,7 @@
#include <SkBitmap.h>
#include <SkCanvas.h>
#include <SkColorFilter.h>
+#include <SkDrawLooper.h>
#include <SkMatrix.h>
#include <SkPaint.h>
#include <SkRegion.h>
@@ -187,7 +188,7 @@ public:
const SkPaint* paint, int flags);
void drawRenderNode(RenderNode* displayList, Rect& dirty, int32_t replayFlags = 1);
- void drawLayer(Layer* layer, float x, float y);
+ void drawLayer(Layer* layer);
void drawBitmap(const SkBitmap* bitmap, const SkPaint* paint);
void drawBitmaps(const SkBitmap* bitmap, AssetAtlas::Entry* entry, int bitmapCount,
TextureVertex* vertices, bool pureTranslate, const Rect& bounds, const SkPaint* paint);
diff --git a/libs/hwui/ProgramCache.cpp b/libs/hwui/ProgramCache.cpp
index 1ac368f423b8..b25a4ac9558d 100644
--- a/libs/hwui/ProgramCache.cpp
+++ b/libs/hwui/ProgramCache.cpp
@@ -38,7 +38,8 @@ namespace uirenderer {
// Vertex shaders snippets
///////////////////////////////////////////////////////////////////////////////
-const char* gVS_Header_Attributes =
+const char* gVS_Header_Start =
+ "#version 100\n"
"attribute vec4 position;\n";
const char* gVS_Header_Attributes_TexCoords =
"attribute vec2 texCoords;\n";
@@ -132,6 +133,8 @@ const char* gVS_Footer =
// Fragment shaders snippets
///////////////////////////////////////////////////////////////////////////////
+const char* gFS_Header_Start =
+ "#version 100\n";
const char* gFS_Header_Extension_FramebufferFetch =
"#extension GL_NV_shader_framebuffer_fetch : enable\n\n";
const char* gFS_Header_Extension_ExternalTexture =
@@ -457,7 +460,7 @@ static inline size_t gradientIndex(const ProgramDescription& description) {
String8 ProgramCache::generateVertexShader(const ProgramDescription& description) {
// Add attributes
- String8 shader(gVS_Header_Attributes);
+ String8 shader(gVS_Header_Start);
if (description.hasTexture || description.hasExternalTexture) {
shader.append(gVS_Header_Attributes_TexCoords);
}
@@ -543,7 +546,7 @@ static bool shaderOp(const ProgramDescription& description, String8& shader,
}
String8 ProgramCache::generateFragmentShader(const ProgramDescription& description) {
- String8 shader;
+ String8 shader(gFS_Header_Start);
const bool blendFramebuffer = description.framebufferMode >= SkXfermode::kPlus_Mode;
if (blendFramebuffer) {
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index 1414fd541909..7d09c0beaf2a 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -875,7 +875,7 @@ void RenderNode::issueOperations(OpenGLRenderer& renderer, T& handler) {
renderer.setBaseTransform(initialTransform);
if (drawLayer) {
- handler(new (alloc) DrawLayerOp(mLayer, 0, 0),
+ handler(new (alloc) DrawLayerOp(mLayer),
renderer.getSaveCount() - 1, properties().getClipToBounds());
} else {
const int saveCountOffset = renderer.getSaveCount() - 1;
diff --git a/libs/hwui/Snapshot.cpp b/libs/hwui/Snapshot.cpp
index ca19a423e5c8..4d60b8dd0e7c 100644
--- a/libs/hwui/Snapshot.cpp
+++ b/libs/hwui/Snapshot.cpp
@@ -83,24 +83,24 @@ Snapshot::Snapshot(const sp<Snapshot>& s, int saveFlags)
// Clipping
///////////////////////////////////////////////////////////////////////////////
-bool Snapshot::clipRegionTransformed(const SkRegion& region, SkRegion::Op op) {
+void Snapshot::clipRegionTransformed(const SkRegion& region, SkRegion::Op op) {
flags |= Snapshot::kFlagClipSet;
- return mClipArea->clipRegion(region, op);
+ mClipArea->clipRegion(region, op);
}
-bool Snapshot::clip(float left, float top, float right, float bottom, SkRegion::Op op) {
+void Snapshot::clip(float left, float top, float right, float bottom, SkRegion::Op op) {
flags |= Snapshot::kFlagClipSet;
- return mClipArea->clipRectWithTransform(left, top, right, bottom, transform, op);
+ mClipArea->clipRectWithTransform(left, top, right, bottom, transform, op);
}
-bool Snapshot::clipPath(const SkPath& path, SkRegion::Op op) {
+void Snapshot::clipPath(const SkPath& path, SkRegion::Op op) {
flags |= Snapshot::kFlagClipSet;
- return mClipArea->clipPathWithTransform(path, transform, op);
+ mClipArea->clipPathWithTransform(path, transform, op);
}
void Snapshot::setClip(float left, float top, float right, float bottom) {
- mClipArea->setClip(left, top, right, bottom);
flags |= Snapshot::kFlagClipSet;
+ mClipArea->setClip(left, top, right, bottom);
}
bool Snapshot::hasPerspectiveTransform() const {
diff --git a/libs/hwui/Snapshot.h b/libs/hwui/Snapshot.h
index af6ad727da85..cf8f11c80058 100644
--- a/libs/hwui/Snapshot.h
+++ b/libs/hwui/Snapshot.h
@@ -124,26 +124,25 @@ public:
* the specified operation. The specified rectangle is transformed
* by this snapshot's trasnformation.
*/
- bool clip(float left, float top, float right, float bottom,
- SkRegion::Op op = SkRegion::kIntersect_Op);
+ void clip(float left, float top, float right, float bottom, SkRegion::Op op);
/**
* Modifies the current clip with the new clip rectangle and
* the specified operation. The specified rectangle is considered
* already transformed.
*/
- bool clipTransformed(const Rect& r, SkRegion::Op op = SkRegion::kIntersect_Op);
+ void clipTransformed(const Rect& r, SkRegion::Op op = SkRegion::kIntersect_Op);
/**
* Modifies the current clip with the specified region and operation.
* The specified region is considered already transformed.
*/
- bool clipRegionTransformed(const SkRegion& region, SkRegion::Op op);
+ void clipRegionTransformed(const SkRegion& region, SkRegion::Op op);
/**
* Modifies the current clip with the specified path and operation.
*/
- bool clipPath(const SkPath& path, SkRegion::Op op);
+ void clipPath(const SkPath& path, SkRegion::Op op);
/**
* Sets the current clip.
diff --git a/media/java/android/mtp/MtpObjectInfo.java b/media/java/android/mtp/MtpObjectInfo.java
index d2824b556315..f79d52ee8c56 100644
--- a/media/java/android/mtp/MtpObjectInfo.java
+++ b/media/java/android/mtp/MtpObjectInfo.java
@@ -256,7 +256,7 @@ public final class MtpObjectInfo {
/**
* Builds a new object info instance.
*/
- public class Builder {
+ public static class Builder {
private MtpObjectInfo mObjectInfo;
public Builder() {
diff --git a/media/jni/android_mtp_MtpDevice.cpp b/media/jni/android_mtp_MtpDevice.cpp
index ad804f32fd9f..9dd3861177e9 100644
--- a/media/jni/android_mtp_MtpDevice.cpp
+++ b/media/jni/android_mtp_MtpDevice.cpp
@@ -430,12 +430,14 @@ static jobject
android_mtp_MtpDevice_send_object_info(JNIEnv *env, jobject thiz, jobject info)
{
MtpDevice* device = get_device_from_object(env, thiz);
- if (!device)
+ if (!device) {
return JNI_FALSE;
+ }
// Updating existing objects is not supported.
- if (env->GetIntField(info, field_objectInfo_handle) != -1)
+ if (env->GetIntField(info, field_objectInfo_handle) != -1) {
return JNI_FALSE;
+ }
MtpObjectInfo* object_info = new MtpObjectInfo(-1);
object_info->mStorageID = env->GetIntField(info, field_objectInfo_storageId);
@@ -456,17 +458,21 @@ android_mtp_MtpDevice_send_object_info(JNIEnv *env, jobject thiz, jobject info)
object_info->mSequenceNumber = env->GetIntField(info, field_objectInfo_sequenceNumber);
jstring name_jstring = (jstring) env->GetObjectField(info, field_objectInfo_name);
- const char* name_string = env->GetStringUTFChars(name_jstring, NULL);
- object_info->mName = strdup(name_string);
- env->ReleaseStringUTFChars(name_jstring, name_string);
+ if (name_jstring != NULL) {
+ const char* name_string = env->GetStringUTFChars(name_jstring, NULL);
+ object_info->mName = strdup(name_string);
+ env->ReleaseStringUTFChars(name_jstring, name_string);
+ }
object_info->mDateCreated = env->GetLongField(info, field_objectInfo_dateCreated) / 1000LL;
object_info->mDateModified = env->GetLongField(info, field_objectInfo_dateModified) / 1000LL;
jstring keywords_jstring = (jstring) env->GetObjectField(info, field_objectInfo_keywords);
- const char* keywords_string = env->GetStringUTFChars(keywords_jstring, NULL);
- object_info->mKeywords = strdup(keywords_string);
- env->ReleaseStringUTFChars(keywords_jstring, keywords_string);
+ if (keywords_jstring != NULL) {
+ const char* keywords_string = env->GetStringUTFChars(keywords_jstring, NULL);
+ object_info->mKeywords = strdup(keywords_string);
+ env->ReleaseStringUTFChars(keywords_jstring, keywords_string);
+ }
int object_handle = device->sendObjectInfo(object_info);
if (object_handle == -1) {
diff --git a/packages/DocumentsUI/res/layout/item_doc_grid.xml b/packages/DocumentsUI/res/layout/item_doc_grid.xml
index 1001e105bcd0..71e618bf4314 100644
--- a/packages/DocumentsUI/res/layout/item_doc_grid.xml
+++ b/packages/DocumentsUI/res/layout/item_doc_grid.xml
@@ -14,7 +14,7 @@
limitations under the License.
-->
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<com.android.documentsui.GridItem xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="@dimen/grid_item_height"
android:layout_margin="@dimen/grid_item_margin"
@@ -140,4 +140,4 @@
android:contentDescription="@null"
android:duplicateParentState="true" />
-</FrameLayout>
+</com.android.documentsui.GridItem>
diff --git a/packages/DocumentsUI/res/layout/item_loading_grid.xml b/packages/DocumentsUI/res/layout/item_loading_grid.xml
index 005a111beabd..147dfd449724 100644
--- a/packages/DocumentsUI/res/layout/item_loading_grid.xml
+++ b/packages/DocumentsUI/res/layout/item_loading_grid.xml
@@ -14,7 +14,7 @@
limitations under the License.
-->
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<com.android.documentsui.GridItem xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="@dimen/grid_height"
android:orientation="horizontal">
@@ -26,4 +26,4 @@
android:indeterminate="true"
style="?android:attr/progressBarStyle" />
-</FrameLayout>
+</com.android.documentsui.GridItem>
diff --git a/packages/DocumentsUI/res/layout/item_message_grid.xml b/packages/DocumentsUI/res/layout/item_message_grid.xml
index 385563df64f6..45d61a506bb5 100644
--- a/packages/DocumentsUI/res/layout/item_message_grid.xml
+++ b/packages/DocumentsUI/res/layout/item_message_grid.xml
@@ -14,7 +14,7 @@
limitations under the License.
-->
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<com.android.documentsui.GridItem xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="@dimen/grid_height"
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
@@ -48,4 +48,4 @@
</LinearLayout>
-</FrameLayout>
+</com.android.documentsui.GridItem>
diff --git a/packages/DocumentsUI/src/com/android/documentsui/BandSelectMatrix.java b/packages/DocumentsUI/src/com/android/documentsui/BandSelectMatrix.java
new file mode 100644
index 000000000000..f2590592c52a
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/BandSelectMatrix.java
@@ -0,0 +1,645 @@
+/*
+ * Copyright (C) 2013 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.documentsui;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import com.google.common.base.Preconditions;
+
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.support.annotation.Nullable;
+import android.support.v7.widget.GridLayoutManager;
+import android.support.v7.widget.RecyclerView;
+import android.support.v7.widget.RecyclerView.LayoutManager;
+import android.support.v7.widget.RecyclerView.OnScrollListener;
+import android.util.SparseBooleanArray;
+import android.view.View;
+
+/**
+ * Provides a band selection item model for views within a RecyclerView. This class queries the
+ * RecyclerView to determine where its items are placed; then, once band selection is underway, it
+ * alerts listeners of which items are covered by the selections.
+ */
+public final class BandSelectMatrix extends RecyclerView.OnScrollListener {
+
+ private final RecyclerViewHelper mHelper;
+ private final List<OnSelectionChangedListener> mOnSelectionChangedListeners = new ArrayList<>();
+
+ // Map from the x-value of the left side of an item to an ordered list of metadata of all items
+ // whose x-values are the same. The list is ordered by the y-values of the items in the column.
+ // For example, if the first column of the view starts at an x-value of 5, mColumns.get(5) would
+ // return a list of all items in that column, with the top-most item first in the list and the
+ // bottom-most item last in the list.
+ private final Map<Integer, List<ItemData>> mColumns = new HashMap<>();
+
+ // List of limits along the x-axis. For example, if the view has two columns, this list will
+ // have two elements, each of which lists the lower- and upper-limits of the x-values of the
+ // view items. This list is sorted from furthest left to furthest right.
+ private final List<Limits> mXLimitsList = new ArrayList<>();
+
+ // Like mXLimitsList, but for y-coordinates. Note that this list only contains items which have
+ // been in the viewport. Thus, limits which exist in an area of the view to which the view has
+ // not scrolled are not present in the list.
+ private final List<Limits> mYLimitsList = new ArrayList<>();
+
+ // The adapter positions which have been recorded so far.
+ private final SparseBooleanArray mRecordedPositions = new SparseBooleanArray();
+
+ // Array passed to registered OnSelectionChangedListeners. One array is created and reused
+ // throughout the lifetime of the object.
+ private final SparseBooleanArray mSelectionForListeners = new SparseBooleanArray();
+
+ // The current pointer (in absolute positioning from the top of the view).
+ private Point mPointer = null;
+
+ // The bounds of the band selection.
+ private RelativePoint mRelativeOrigin;
+ private RelativePoint mRelativePointer;
+
+ BandSelectMatrix(RecyclerViewHelper helper) {
+ mHelper = helper;
+ mHelper.addOnScrollListener(this);
+ }
+
+ BandSelectMatrix(RecyclerView rv) {
+ this(new RuntimeRecyclerViewHelper(rv));
+ }
+
+ /**
+ * Stops listening to the view's scrolls. Call this function before discarding a
+ * BandSelecMatrix object to prevent memory leaks.
+ */
+ void stopListening() {
+ mHelper.removeOnScrollListener(this);
+ }
+
+ /**
+ * Start a band select operation at the given point.
+ * @param relativeOrigin The origin of the band select operation, relative to the viewport.
+ * For example, if the view is scrolled to the bottom, the top-left of the viewport would
+ * have a relative origin of (0, 0), even though its absolute point has a higher y-value.
+ */
+ void startSelection(Point relativeOrigin) {
+ Point absoluteOrigin = mHelper.createAbsolutePoint(relativeOrigin);
+ mPointer = new Point(absoluteOrigin.x, absoluteOrigin.y);
+
+ processVisibleChildren();
+ mRelativeOrigin = new RelativePoint(absoluteOrigin);
+ mRelativePointer = new RelativePoint(mPointer);
+ computeCurrentSelection();
+ notifyListeners();
+ }
+
+ /**
+ * Resizes the selection by adjusting the pointer (i.e., the corner of the selection opposite
+ * the origin.
+ * @param relativePointer The pointer (opposite of the origin) of the band select operation,
+ * relative to the viewport. For example, if the view is scrolled to the bottom, the
+ * top-left of the viewport would have a relative origin of (0, 0), even though its absolute
+ * point has a higher y-value.
+ */
+ void resizeSelection(Point relativePointer) {
+ mPointer = mHelper.createAbsolutePoint(relativePointer);
+ handlePointerMoved();
+ }
+
+ @Override
+ public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
+ if (mPointer == null) {
+ return;
+ }
+
+ mPointer.x += dx;
+ mPointer.y += dy;
+ processVisibleChildren();
+ handlePointerMoved();
+ }
+
+ /**
+ * Queries the view for all children and records their location metadata.
+ */
+ private void processVisibleChildren() {
+ for (int i = 0; i < mHelper.getVisibleChildCount(); i++) {
+ int adapterPosition = mHelper.getAdapterPositionAt(i);
+ if (!mRecordedPositions.get(adapterPosition)) {
+ mRecordedPositions.put(adapterPosition, true);
+ captureItemLayoutData(mHelper.getAbsoluteRectForChildViewAt(i), adapterPosition);
+ }
+ }
+ }
+
+ /**
+ * Updates the limits lists and column map with the given item metadata.
+ * @param absoluteChildRect The absolute rectangle for the child view being processed.
+ * @param adapterPosition The position of the child view being processed.
+ */
+ private void captureItemLayoutData(Rect absoluteChildRect, int adapterPosition) {
+ if (mXLimitsList.size() != mHelper.getNumColumns()) {
+ // If not all x-limits have been recorded, record this one.
+ recordLimits(
+ mXLimitsList, new Limits(absoluteChildRect.left, absoluteChildRect.right));
+ }
+
+ if (mYLimitsList.size() != mHelper.getNumRows()) {
+ // If not all y-limits have been recorded, record this one.
+ recordLimits(
+ mYLimitsList, new Limits(absoluteChildRect.top, absoluteChildRect.bottom));
+ }
+
+ List<ItemData> columnList = mColumns.get(absoluteChildRect.left);
+ if (columnList == null) {
+ columnList = new ArrayList<ItemData>();
+ mColumns.put(absoluteChildRect.left, columnList);
+ }
+ recordItemData(
+ columnList, new ItemData(adapterPosition, absoluteChildRect.top));
+ }
+
+ /**
+ * Ensures limits exists within the sorted list limitsList, and adds it to the list if it does
+ * not exist.
+ */
+ private static void recordLimits(List<Limits> limitsList, Limits limits) {
+ int index = Collections.binarySearch(limitsList, limits);
+ if (index < 0) {
+ limitsList.add(~index, limits);
+ }
+ }
+
+ /**
+ * Ensures itemData exists within the sorted list itemDataList, and adds it to the list if it
+ * does not exist.
+ */
+ private static void recordItemData(List<ItemData> itemDataList, ItemData itemData) {
+ int index = Collections.binarySearch(itemDataList, itemData);
+ if (index < 0) {
+ itemDataList.add(~index, itemData);
+ }
+ }
+
+ /**
+ * Handles a moved pointer; this function determines whether the pointer movement resulted in a
+ * selection change and, if it has, notifies listeners of this change.
+ */
+ private void handlePointerMoved() {
+ RelativePoint old = mRelativePointer;
+ mRelativePointer = new RelativePoint(mPointer);
+ if (old != null && mRelativePointer.equals(old)) {
+ return;
+ }
+
+ computeCurrentSelection();
+ notifyListeners();
+ }
+
+ /**
+ * Computes the currently-selected items.
+ */
+ private void computeCurrentSelection() {
+ Rect selectionRect = mRelativePointer.computeBounds(mRelativeOrigin);
+ computePositionsCoveredByRect(selectionRect);
+ }
+
+ /**
+ * Notifies all listeners of a selection change. Note that this function simply passes
+ * mSelectionForListeners, so computeCurrentSelection() should be called before this function.
+ */
+ private void notifyListeners() {
+ for (OnSelectionChangedListener listener : mOnSelectionChangedListeners) {
+ listener.onSelectionChanged(mSelectionForListeners);
+ }
+ }
+
+ /**
+ * @param rect Rectangle including all covered items.
+ */
+ private void computePositionsCoveredByRect(@Nullable Rect rect) {
+ mSelectionForListeners.clear();
+ if (rect == null) {
+ // If there is no bounding rectangle, there are no items selected, so just return early.
+ return;
+ }
+
+ int columnIndex = Collections.binarySearch(mXLimitsList, new Limits(rect.left, rect.left));
+ Preconditions.checkState(columnIndex >= 0);
+
+ for (; columnIndex < mXLimitsList.size() &&
+ mXLimitsList.get(columnIndex).lowerLimit <= rect.right; columnIndex++) {
+ List<ItemData> positions =
+ mColumns.get(mXLimitsList.get(columnIndex).lowerLimit);
+ int rowIndex = Collections.binarySearch(positions, new ItemData(0, rect.top));
+ if (rowIndex < 0) {
+ // If band select occurs after the last item in a row with fewer items than columns,
+ // go to the next column. This situation occurs in the last row of the grid when the
+ // total number of items is not a multiple of the number of columns (e.g., when 10
+ // items exist in a grid with 4 columns).
+ continue;
+ }
+
+ for (; rowIndex < positions.size() &&
+ positions.get(rowIndex).offset <= rect.bottom; rowIndex++) {
+ mSelectionForListeners.append(positions.get(rowIndex).position, true);
+ }
+ }
+ }
+
+ /**
+ * Provides functionality for interfacing with the view. In practice, RecyclerViewMatrixHelper
+ * should be used; this interface exists solely for the purpose of decoupling the view from
+ * this class so that the view can be mocked out for tests.
+ */
+ interface RecyclerViewHelper {
+ public void addOnScrollListener(RecyclerView.OnScrollListener listener);
+ public void removeOnScrollListener(RecyclerView.OnScrollListener listener);
+ public Point createAbsolutePoint(Point relativePoint);
+ public int getVisibleChildCount();
+ public int getTotalChildCount();
+ public int getNumColumns();
+ public int getNumRows();
+ public int getAdapterPositionAt(int index);
+ public Rect getAbsoluteRectForChildViewAt(int index);
+ }
+
+ /**
+ * Concrete MatrixHelper implementation for use within the Files app.
+ */
+ static class RuntimeRecyclerViewHelper implements RecyclerViewHelper {
+ private final RecyclerView mRecyclerView;
+
+ RuntimeRecyclerViewHelper(RecyclerView rv) {
+ mRecyclerView = rv;
+ }
+
+ @Override
+ public int getAdapterPositionAt(int index) {
+ View child = mRecyclerView.getChildAt(index);
+ return mRecyclerView.getChildViewHolder(child).getAdapterPosition();
+ }
+
+ @Override
+ public void addOnScrollListener(OnScrollListener listener) {
+ mRecyclerView.addOnScrollListener(listener);
+ }
+
+ @Override
+ public void removeOnScrollListener(OnScrollListener listener) {
+ mRecyclerView.removeOnScrollListener(listener);
+ }
+
+ @Override
+ public Point createAbsolutePoint(Point relativePoint) {
+ return new Point(relativePoint.x + mRecyclerView.computeHorizontalScrollOffset(),
+ relativePoint.y + mRecyclerView.computeVerticalScrollOffset());
+ }
+
+ @Override
+ public Rect getAbsoluteRectForChildViewAt(int index) {
+ final View child = mRecyclerView.getChildAt(index);
+ final Rect childRect = new Rect();
+ child.getHitRect(childRect);
+ childRect.left += mRecyclerView.computeHorizontalScrollOffset();
+ childRect.right += mRecyclerView.computeHorizontalScrollOffset();
+ childRect.top += mRecyclerView.computeVerticalScrollOffset();
+ childRect.bottom += mRecyclerView.computeVerticalScrollOffset();
+ return childRect;
+ }
+
+ @Override
+ public int getVisibleChildCount() {
+ return mRecyclerView.getChildCount();
+ }
+
+ @Override
+ public int getTotalChildCount() {
+ return mRecyclerView.getAdapter().getItemCount();
+ }
+
+ @Override
+ public int getNumColumns() {
+ LayoutManager layoutManager = mRecyclerView.getLayoutManager();
+ if (layoutManager instanceof GridLayoutManager) {
+ return ((GridLayoutManager) layoutManager).getSpanCount();
+ }
+
+ // Otherwise, it is a list with 1 column.
+ return 1;
+ }
+
+ @Override
+ public int getNumRows() {
+ int numFullColumns = getTotalChildCount() / getNumColumns();
+ boolean hasPartiallyFullColumn = getTotalChildCount() % getNumColumns() != 0;
+ return numFullColumns + (hasPartiallyFullColumn ? 1 : 0);
+ }
+ }
+
+ /**
+ * Listener for changes in which items have been band selected.
+ */
+ interface OnSelectionChangedListener {
+ public void onSelectionChanged(SparseBooleanArray updatedSelection);
+ }
+
+ void addOnSelectionChangedListener(OnSelectionChangedListener listener) {
+ mOnSelectionChangedListeners.add(listener);
+ }
+
+ void removeOnSelectionChangedListener(OnSelectionChangedListener listener) {
+ mOnSelectionChangedListeners.remove(listener);
+ }
+
+ /**
+ * Metadata for an item in the view, consisting of the adapter position and the offset from the
+ * top of the view (in pixels). Stored in the mColumns map to model the item grid.
+ */
+ private static class ItemData implements Comparable<ItemData> {
+ int position;
+ int offset;
+
+ ItemData(int position, int offset) {
+ this.position = position;
+ this.offset = offset;
+ }
+
+ @Override
+ public int compareTo(ItemData other) {
+ // The list of columns is sorted via the offset from the top, so PositionMetadata
+ // objects with lower y-values are befor those with higher y-values.
+ return offset - other.offset;
+ }
+ }
+
+ /**
+ * Limits of a view item. For example, if an item's left side is at x-value 5 and its right side
+ * is at x-value 10, the limits would be from 5 to 10. Used to record the left- and right sides
+ * of item columns and the top- and bottom sides of item rows so that it can be determined
+ * whether the pointer is located within the bounds of an item.
+ */
+ private static class Limits implements Comparable<Limits> {
+ int lowerLimit;
+ int upperLimit;
+
+ Limits(int lowerLimit, int upperLimit) {
+ this.lowerLimit = lowerLimit;
+ this.upperLimit = upperLimit;
+ }
+
+ @Override
+ public int compareTo(Limits other) {
+ return lowerLimit - other.lowerLimit;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (!(other instanceof Limits)) {
+ return false;
+ }
+
+ return ((Limits) other).lowerLimit == lowerLimit &&
+ ((Limits) other).upperLimit == upperLimit;
+ }
+ }
+
+ /**
+ * The location of a coordinate relative to items. This class represents a general area of the
+ * view as it relates to band selection rather than an explicit point. For example, two
+ * different points within an item are considered to have the same "location" because band
+ * selection originating within the item would select the same items no matter which point
+ * was used. Same goes for points between items as well as those at the very beginning or end
+ * of the view.
+ *
+ * Tracking a coordinate (e.g., an x-value) as a CoordinateLocation instead of as an int has the
+ * advantage of tying the value to the Limits of items along that axis. This allows easy
+ * selection of items within those Limits as opposed to a search through every item to see if a
+ * given coordinate value falls within those Limits.
+ */
+ private static class RelativeCoordinate
+ implements Comparable<RelativeCoordinate> {
+ /**
+ * Location describing points after the last known item.
+ */
+ static final int AFTER_LAST_ITEM = 0;
+
+ /**
+ * Location describing points before the first known item.
+ */
+ static final int BEFORE_FIRST_ITEM = 1;
+
+ /**
+ * Location describing points between two items.
+ */
+ static final int BETWEEN_TWO_ITEMS = 2;
+
+ /**
+ * Location describing points within the limits of one item.
+ */
+ static final int WITHIN_LIMITS = 3;
+
+ /**
+ * The type of this coordinate, which is one of AFTER_LAST_ITEM, BEFORE_FIRST_ITEM,
+ * BETWEEN_TWO_ITEMS, or WITHIN_LIMITS.
+ */
+ final int type;
+
+ /**
+ * The limits before the coordinate; only populated when type == WITHIN_LIMITS or type ==
+ * BETWEEN_TWO_ITEMS.
+ */
+ Limits limitsBeforeCoordinate;
+
+ /**
+ * The limits after the coordinate; only populated when type == BETWEEN_TWO_ITEMS.
+ */
+ Limits limitsAfterCoordinate;
+
+ // Limits of the first known item; only populated when type == BEFORE_FIRST_ITEM.
+ Limits mFirstKnownItem;
+ // Limits of the last known item; only populated when type == AFTER_LAST_ITEM.
+ Limits mLastKnownItem;
+
+ /**
+ * @param limitsList The sorted limits list for the coordinate type. If this
+ * CoordinateLocation is an x-value, mXLimitsList should be passed; otherwise,
+ * mYLimitsList should be pased.
+ * @param value The coordinate value.
+ */
+ RelativeCoordinate(List<Limits> limitsList, int value) {
+ Limits dummyLimits = new Limits(value, value);
+ int index = Collections.binarySearch(limitsList, dummyLimits);
+
+ if (index >= 0) {
+ this.type = WITHIN_LIMITS;
+ this.limitsBeforeCoordinate = limitsList.get(index);
+ } else if (~index == 0) {
+ this.type = BEFORE_FIRST_ITEM;
+ this.mFirstKnownItem = limitsList.get(0);
+ } else if (~index == limitsList.size()) {
+ Limits lastLimits = limitsList.get(limitsList.size() - 1);
+ if (lastLimits.lowerLimit <= value && value <= lastLimits.upperLimit) {
+ this.type = WITHIN_LIMITS;
+ this.limitsBeforeCoordinate = lastLimits;
+ } else {
+ this.type = AFTER_LAST_ITEM;
+ this.mLastKnownItem = lastLimits;
+ }
+ } else {
+ Limits limitsBeforeIndex = limitsList.get(~index - 1);
+ if (limitsBeforeIndex.lowerLimit <= value && value <= limitsBeforeIndex.upperLimit) {
+ this.type = WITHIN_LIMITS;
+ this.limitsBeforeCoordinate = limitsList.get(~index - 1);
+ } else {
+ this.type = BETWEEN_TWO_ITEMS;
+ this.limitsBeforeCoordinate = limitsList.get(~index - 1);
+ this.limitsAfterCoordinate = limitsList.get(~index);
+ }
+ }
+ }
+
+ int toComparisonValue() {
+ if (type == BEFORE_FIRST_ITEM) {
+ return mFirstKnownItem.lowerLimit - 1;
+ } else if (type == AFTER_LAST_ITEM) {
+ return mLastKnownItem.upperLimit + 1;
+ } else if (type == BETWEEN_TWO_ITEMS) {
+ return limitsBeforeCoordinate.upperLimit + 1;
+ } else {
+ return limitsBeforeCoordinate.lowerLimit;
+ }
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (!(other instanceof RelativeCoordinate)) {
+ return false;
+ }
+
+ RelativeCoordinate otherCoordinate = (RelativeCoordinate) other;
+ return toComparisonValue() == otherCoordinate.toComparisonValue();
+ }
+
+ @Override
+ public int compareTo(RelativeCoordinate other) {
+ return toComparisonValue() - other.toComparisonValue();
+ }
+ }
+
+ /**
+ * The location of a point relative to the Limits of nearby items; consists of both an x- and
+ * y-RelativeCoordinateLocation.
+ */
+ private class RelativePoint {
+ final RelativeCoordinate xLocation;
+ final RelativeCoordinate yLocation;
+
+ RelativePoint(Point point) {
+ this.xLocation = new RelativeCoordinate(mXLimitsList, point.x);
+ this.yLocation = new RelativeCoordinate(mYLimitsList, point.y);
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (!(other instanceof RelativePoint)) {
+ return false;
+ }
+
+ RelativePoint otherPoint = (RelativePoint) other;
+ return xLocation.equals(otherPoint.xLocation) && yLocation.equals(otherPoint.yLocation);
+ }
+
+ /**
+ * Generates a rectangle which contains the items selected by the two points.
+ * @param other The other PointLocation. A rectangle will be formed between "this" and
+ * "other".
+ * @return The rectangle, or null if no items were selected.
+ */
+ Rect computeBounds(RelativePoint other) {
+ if (!areItemsCoveredBySelection(mRelativePointer, mRelativeOrigin)) {
+ return null;
+ }
+
+ RelativeCoordinate minXLocation =
+ xLocation.compareTo(other.xLocation) < 0 ? xLocation : other.xLocation;
+ RelativeCoordinate maxXLocation =
+ minXLocation == xLocation ? other.xLocation : xLocation;
+ RelativeCoordinate minYLocation =
+ yLocation.compareTo(other.yLocation) < 0 ? yLocation : other.yLocation;
+ RelativeCoordinate maxYLocation =
+ minYLocation == yLocation ? other.yLocation : yLocation;
+
+ Rect rect = new Rect();
+ rect.left = getCoordinateValue(minXLocation, mXLimitsList, true);
+ rect.right = getCoordinateValue(maxXLocation, mXLimitsList, false);
+ rect.top = getCoordinateValue(minYLocation, mYLimitsList, true);
+ rect.bottom = getCoordinateValue(maxYLocation, mYLimitsList, false);
+ return rect;
+ }
+
+ int getCoordinateValue(RelativeCoordinate coordinate,
+ List<Limits> limitsList, boolean isStartOfRange) {
+ switch (coordinate.type) {
+ case RelativeCoordinate.BEFORE_FIRST_ITEM:
+ return limitsList.get(0).lowerLimit;
+ case RelativeCoordinate.AFTER_LAST_ITEM:
+ return limitsList.get(limitsList.size() - 1).upperLimit;
+ case RelativeCoordinate.BETWEEN_TWO_ITEMS:
+ if (isStartOfRange) {
+ return coordinate.limitsAfterCoordinate.lowerLimit;
+ } else {
+ return coordinate.limitsBeforeCoordinate.upperLimit;
+ }
+ case RelativeCoordinate.WITHIN_LIMITS:
+ return coordinate.limitsBeforeCoordinate.lowerLimit;
+ }
+
+ throw new RuntimeException("Invalid coordinate value.");
+ }
+ }
+
+ private static boolean areItemsCoveredBySelection(
+ RelativePoint first, RelativePoint second) {
+ return doesCoordinateLocationCoverItems(first.xLocation, second.xLocation) &&
+ doesCoordinateLocationCoverItems(first.yLocation, second.yLocation);
+ }
+
+ private static boolean doesCoordinateLocationCoverItems(
+ RelativeCoordinate pointerCoordinate,
+ RelativeCoordinate originCoordinate) {
+ if (pointerCoordinate.type == RelativeCoordinate.BEFORE_FIRST_ITEM &&
+ originCoordinate.type == RelativeCoordinate.BEFORE_FIRST_ITEM) {
+ return false;
+ }
+
+ if (pointerCoordinate.type == RelativeCoordinate.AFTER_LAST_ITEM &&
+ originCoordinate.type == RelativeCoordinate.AFTER_LAST_ITEM) {
+ return false;
+ }
+
+ if (pointerCoordinate.type == RelativeCoordinate.BETWEEN_TWO_ITEMS &&
+ originCoordinate.type == RelativeCoordinate.BETWEEN_TWO_ITEMS &&
+ pointerCoordinate.limitsBeforeCoordinate.equals(originCoordinate) &&
+ pointerCoordinate.limitsAfterCoordinate.equals(originCoordinate)) {
+ return false;
+ }
+
+ return true;
+ }
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
index 9b8d84723c03..a804e9a5ca19 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
@@ -22,7 +22,6 @@ import static com.android.documentsui.DirectoryFragment.ANIM_SIDE;
import static com.android.documentsui.DirectoryFragment.ANIM_UP;
import static com.android.internal.util.Preconditions.checkArgument;
-import android.annotation.Nullable;
import android.app.Activity;
import android.app.Fragment;
import android.content.Intent;
@@ -38,6 +37,7 @@ import android.os.Parcel;
import android.os.Parcelable;
import android.provider.DocumentsContract;
import android.provider.DocumentsContract.Root;
+import android.support.annotation.Nullable;
import android.util.Log;
import android.util.SparseArray;
import android.view.LayoutInflater;
@@ -60,8 +60,6 @@ import com.android.documentsui.model.DocumentStack;
import com.android.documentsui.model.DurableUtils;
import com.android.documentsui.model.RootInfo;
-import com.google.common.collect.Maps;
-
import libcore.io.IoUtils;
import java.io.FileNotFoundException;
@@ -371,7 +369,7 @@ abstract class BaseActivity extends Activity {
public String currentSearch;
/** Instance state for every shown directory */
- public HashMap<String, SparseArray<Parcelable>> dirState = Maps.newHashMap();
+ public HashMap<String, SparseArray<Parcelable>> dirState = new HashMap<>();
/** Currently copying file */
public List<DocumentInfo> selectedDocumentsForCopy = new ArrayList<DocumentInfo>();
diff --git a/packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java
index f9275951b9df..e408e6eb821d 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java
@@ -16,7 +16,7 @@
package com.android.documentsui;
-import static com.android.documentsui.DocumentsActivity.TAG;
+import static com.android.documentsui.Shared.TAG;
import android.app.AlertDialog;
import android.app.Dialog;
@@ -36,7 +36,6 @@ import android.util.Log;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
-import android.view.inputmethod.EditorInfo;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.TextView.OnEditorActionListener;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
index 5223d760e96d..704e60781dd5 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
@@ -24,14 +24,13 @@ import static com.android.documentsui.BaseActivity.State.MODE_GRID;
import static com.android.documentsui.BaseActivity.State.MODE_LIST;
import static com.android.documentsui.BaseActivity.State.MODE_UNKNOWN;
import static com.android.documentsui.BaseActivity.State.SORT_ORDER_UNKNOWN;
-import static com.android.documentsui.DocumentsActivity.TAG;
+import static com.android.documentsui.Shared.TAG;
import static com.android.documentsui.model.DocumentInfo.getCursorInt;
import static com.android.documentsui.model.DocumentInfo.getCursorLong;
import static com.android.documentsui.model.DocumentInfo.getCursorString;
import static com.android.internal.util.Preconditions.checkNotNull;
import static com.android.internal.util.Preconditions.checkState;
-import android.annotation.NonNull;
import android.app.Activity;
import android.app.ActivityManager;
import android.app.Fragment;
@@ -98,7 +97,7 @@ import com.android.documentsui.model.DocumentStack;
import com.android.documentsui.model.RootInfo;
import com.android.internal.util.Preconditions;
-import com.google.android.collect.Lists;
+import com.google.common.collect.Lists;
import java.util.ArrayList;
import java.util.Collections;
@@ -235,8 +234,7 @@ public class DirectoryFragment extends Fragment {
public void onLayoutChange(
View v, int left, int top, int right, int bottom, int oldLeft,
int oldTop, int oldRight, int oldBottom) {
- int thumbSize = getResources().getDimensionPixelSize(R.dimen.grid_width);
- mColumnCount = pickColumnCount(thumbSize);
+ mColumnCount = calculateColumnCount();
if (mGridLayout != null) {
mGridLayout.setSpanCount(mColumnCount);
}
@@ -535,8 +533,6 @@ public class DirectoryFragment extends Fragment {
updateLayout(state.derivedMode);
- final int thumbSize = getResources().getDimensionPixelSize(R.dimen.icon_size);
- mThumbSize = new Point(thumbSize, thumbSize);
mRecView.setAdapter(mAdapter);
}
@@ -573,13 +569,15 @@ public class DirectoryFragment extends Fragment {
mThumbSize = new Point(thumbSize, thumbSize);
}
- private int pickColumnCount(final int thumbSize) {
- int itemPadding =
- getResources().getDimensionPixelSize(R.dimen.grid_item_margin);
+ private int calculateColumnCount() {
+ int cellWidth = getResources().getDimensionPixelSize(R.dimen.grid_width);
+ int cellMargin = 2 * getResources().getDimensionPixelSize(R.dimen.grid_item_margin);
int viewPadding = mRecView.getPaddingLeft() + mRecView.getPaddingRight();
+
checkState(mRecView.getWidth() > 0);
int columnCount = Math.max(1,
- (mRecView.getWidth() - viewPadding) / (thumbSize + itemPadding));
+ (mRecView.getWidth() - viewPadding) / (cellWidth + cellMargin));
+
return columnCount;
}
@@ -753,7 +751,7 @@ public class DirectoryFragment extends Fragment {
Intent intent;
// Filter out directories - those can't be shared.
- List<DocumentInfo> docsForSend = Lists.newArrayList();
+ List<DocumentInfo> docsForSend = new ArrayList<>();
for (DocumentInfo doc: docs) {
if (!Document.MIME_TYPE_DIR.equals(doc.mimeType)) {
docsForSend.add(doc);
@@ -774,8 +772,8 @@ public class DirectoryFragment extends Fragment {
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.addCategory(Intent.CATEGORY_DEFAULT);
- final ArrayList<String> mimeTypes = Lists.newArrayList();
- final ArrayList<Uri> uris = Lists.newArrayList();
+ final ArrayList<String> mimeTypes = new ArrayList<>();
+ final ArrayList<Uri> uris = new ArrayList<>();
for (DocumentInfo doc : docsForSend) {
mimeTypes.add(doc.mimeType);
uris.add(doc.derivedUri);
@@ -956,7 +954,7 @@ public class DirectoryFragment extends Fragment {
private final Context mContext;
private final LayoutInflater mInflater;
// TODO: Bring back support for footers.
- private final List<Footer> mFooters = Lists.newArrayList();
+ private final List<Footer> mFooters = new ArrayList<>();
private Cursor mCursor;
private int mCursorCount;
@@ -1330,7 +1328,7 @@ public class DirectoryFragment extends Fragment {
return MimePredicate.mimeMatches(state.acceptMimes, docMimeType);
}
- private @NonNull List<DocumentInfo> getSelectedDocuments() {
+ private List<DocumentInfo> getSelectedDocuments() {
Selection sel = mSelectionManager.getSelection(new Selection());
return getItemsAsDocuments(sel);
}
@@ -1570,6 +1568,7 @@ public class DirectoryFragment extends Fragment {
final Cursor cursor = mAdapter.getItem(position);
checkNotNull(cursor, "Cursor cannot be null.");
final DocumentInfo doc = DocumentInfo.fromDirectoryCursor(cursor);
+
return Lists.newArrayList(doc);
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java
index a8a61d28c222..0edb2413b0ca 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java
@@ -16,12 +16,12 @@
package com.android.documentsui;
-import static com.android.documentsui.DocumentsActivity.TAG;
import static com.android.documentsui.BaseActivity.State.MODE_UNKNOWN;
import static com.android.documentsui.BaseActivity.State.SORT_ORDER_DISPLAY_NAME;
import static com.android.documentsui.BaseActivity.State.SORT_ORDER_LAST_MODIFIED;
import static com.android.documentsui.BaseActivity.State.SORT_ORDER_SIZE;
import static com.android.documentsui.BaseActivity.State.SORT_ORDER_UNKNOWN;
+import static com.android.documentsui.Shared.TAG;
import static com.android.documentsui.model.DocumentInfo.getCursorInt;
import android.content.AsyncTaskLoader;
@@ -31,8 +31,6 @@ import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.os.CancellationSignal;
-import android.os.Handler;
-import android.os.Looper;
import android.os.OperationCanceledException;
import android.os.RemoteException;
import android.provider.DocumentsContract;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DocumentClipper.java b/packages/DocumentsUI/src/com/android/documentsui/DocumentClipper.java
index 237057570d49..6ba07fbbaf6a 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DocumentClipper.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DocumentClipper.java
@@ -16,8 +16,6 @@
package com.android.documentsui;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.ContentProviderClient;
@@ -26,15 +24,15 @@ import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.provider.DocumentsContract;
+import android.support.annotation.Nullable;
import android.util.Log;
import com.android.documentsui.model.DocumentInfo;
import com.android.internal.util.Preconditions;
-import com.google.android.collect.Lists;
-
import libcore.io.IoUtils;
+import java.util.ArrayList;
import java.util.List;
/**
@@ -78,7 +76,7 @@ final class DocumentClipper {
* Returns a list of Documents as decoded from Clipboard primary clipdata.
* This should be run from inside an AsyncTask.
*/
- public @NonNull List<DocumentInfo> getClippedDocuments() {
+ public List<DocumentInfo> getClippedDocuments() {
return getDocumentsFromClipData(mClipboard.getPrimaryClip());
}
@@ -86,9 +84,9 @@ final class DocumentClipper {
* Returns a list of Documents as decoded in clipData.
* This should be run from inside an AsyncTask.
*/
- public @NonNull List<DocumentInfo> getDocumentsFromClipData(ClipData clipData) {
+ public List<DocumentInfo> getDocumentsFromClipData(ClipData clipData) {
Preconditions.checkNotNull(clipData);
- final List<DocumentInfo> srcDocs = Lists.newArrayList();
+ final List<DocumentInfo> srcDocs = new ArrayList<>();
int count = clipData.getItemCount();
if (count == 0) {
diff --git a/packages/DocumentsUI/src/com/android/documentsui/FilteringCursorWrapper.java b/packages/DocumentsUI/src/com/android/documentsui/FilteringCursorWrapper.java
index 1cbc221e1057..17a1161f7c25 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/FilteringCursorWrapper.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/FilteringCursorWrapper.java
@@ -16,7 +16,7 @@
package com.android.documentsui;
-import static com.android.documentsui.DocumentsActivity.TAG;
+import static com.android.documentsui.Shared.TAG;
import static com.android.documentsui.model.DocumentInfo.getCursorLong;
import static com.android.documentsui.model.DocumentInfo.getCursorString;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/GridItem.java b/packages/DocumentsUI/src/com/android/documentsui/GridItem.java
new file mode 100644
index 000000000000..990dca70f9c6
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/GridItem.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.documentsui;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.widget.FrameLayout;
+
+/**
+ * A FrameLayout subclass used by DirectoryFragment. Ensures that the resulting grid item is always
+ * square.
+ */
+public class GridItem extends FrameLayout {
+ public GridItem(Context context) {
+ super(context);
+ }
+
+ public GridItem(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public GridItem(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ }
+
+ @Override
+ public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ // Grid layout uses item width to figure out the number of columns, then dynamically fits
+ // rows into the view. The upshot of this is that changing the item width will mess up the
+ // grid layout - so to make the items square, throw out the height and use the width for
+ // both dimensions. The grid layout will correctly adjust the row height.
+ //
+ // Note that this code will need to be changed if the layout manager's orientation is
+ // changed from VERTICAL to HORIZONTAL.
+ super.onMeasure(widthMeasureSpec, widthMeasureSpec);
+ }
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/IconUtils.java b/packages/DocumentsUI/src/com/android/documentsui/IconUtils.java
index b43fedf3d1fb..99592659a7fb 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/IconUtils.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/IconUtils.java
@@ -23,13 +23,11 @@ import android.graphics.drawable.Drawable;
import android.provider.DocumentsContract.Document;
import android.util.TypedValue;
-import com.google.android.collect.Maps;
-
import java.util.HashMap;
public class IconUtils {
- private static HashMap<String, Integer> sMimeIcons = Maps.newHashMap();
+ private static HashMap<String, Integer> sMimeIcons = new HashMap<>();
private static void add(String mimeType, int resId) {
if (sMimeIcons.put(mimeType, resId) != null) {
diff --git a/packages/DocumentsUI/src/com/android/documentsui/MultiSelectManager.java b/packages/DocumentsUI/src/com/android/documentsui/MultiSelectManager.java
index 02edd0c87448..f87fe4ccfa46 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/MultiSelectManager.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/MultiSelectManager.java
@@ -31,7 +31,7 @@ import android.view.GestureDetector.OnGestureListener;
import android.view.MotionEvent;
import android.view.View;
-import com.google.common.annotations.VisibleForTesting;
+import android.support.annotation.VisibleForTesting;
import java.util.ArrayList;
import java.util.List;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/ProviderExecutor.java b/packages/DocumentsUI/src/com/android/documentsui/ProviderExecutor.java
index f94aebd50d61..b0e332faa3fc 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/ProviderExecutor.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/ProviderExecutor.java
@@ -20,8 +20,6 @@ import android.os.AsyncTask;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.Preconditions;
-import com.google.android.collect.Lists;
-import com.google.android.collect.Maps;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
@@ -32,7 +30,7 @@ import java.util.concurrent.LinkedBlockingQueue;
public class ProviderExecutor extends Thread implements Executor {
@GuardedBy("sExecutors")
- private static HashMap<String, ProviderExecutor> sExecutors = Maps.newHashMap();
+ private static HashMap<String, ProviderExecutor> sExecutors = new HashMap<>();
public static ProviderExecutor forAuthority(String authority) {
synchronized (sExecutors) {
@@ -53,7 +51,7 @@ public class ProviderExecutor extends Thread implements Executor {
private final LinkedBlockingQueue<Runnable> mQueue = new LinkedBlockingQueue<Runnable>();
- private final ArrayList<WeakReference<Preemptable>> mPreemptable = Lists.newArrayList();
+ private final ArrayList<WeakReference<Preemptable>> mPreemptable = new ArrayList<>();
private void preempt() {
synchronized (mPreemptable) {
diff --git a/packages/DocumentsUI/src/com/android/documentsui/QuickViewIntentBuilder.java b/packages/DocumentsUI/src/com/android/documentsui/QuickViewIntentBuilder.java
index 878c4c217588..4685c41fc2b6 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/QuickViewIntentBuilder.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/QuickViewIntentBuilder.java
@@ -18,7 +18,6 @@ package com.android.documentsui;
import static com.android.documentsui.model.DocumentInfo.getCursorString;
-import android.annotation.Nullable;
import android.content.ClipData;
import android.content.ClipDescription;
import android.content.ComponentName;
@@ -28,6 +27,7 @@ import android.database.Cursor;
import android.net.Uri;
import android.provider.DocumentsContract;
import android.provider.DocumentsContract.Document;
+import android.support.annotation.Nullable;
import android.util.Log;
import com.android.documentsui.BaseActivity.DocumentContext;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RecentLoader.java b/packages/DocumentsUI/src/com/android/documentsui/RecentLoader.java
index f5908c55cfa2..1a7095a054c3 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RecentLoader.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RecentLoader.java
@@ -16,8 +16,8 @@
package com.android.documentsui;
-import static com.android.documentsui.DocumentsActivity.TAG;
import static com.android.documentsui.BaseActivity.State.SORT_ORDER_LAST_MODIFIED;
+import static com.android.documentsui.Shared.TAG;
import android.app.ActivityManager;
import android.content.AsyncTaskLoader;
@@ -36,14 +36,14 @@ import android.util.Log;
import com.android.documentsui.BaseActivity.State;
import com.android.documentsui.model.RootInfo;
-import com.google.android.collect.Maps;
-import com.google.common.collect.Lists;
+
import com.google.common.util.concurrent.AbstractFuture;
import libcore.io.IoUtils;
import java.io.Closeable;
import java.io.IOException;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
@@ -53,7 +53,7 @@ import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
public class RecentLoader extends AsyncTaskLoader<DirectoryResult> {
- private static final boolean LOGD = true;
+ private static final boolean DEBUG = false;
// TODO: clean up cursor ownership so background thread doesn't traverse
// previously returned cursors for filtering/sorting; this currently races
@@ -81,7 +81,7 @@ public class RecentLoader extends AsyncTaskLoader<DirectoryResult> {
private final RootsCache mRoots;
private final State mState;
- private final HashMap<RootInfo, RecentTask> mTasks = Maps.newHashMap();
+ private final HashMap<RootInfo, RecentTask> mTasks = new HashMap<>();
private final int mSortOrder = State.SORT_ORDER_LAST_MODIFIED;
@@ -196,7 +196,7 @@ public class RecentLoader extends AsyncTaskLoader<DirectoryResult> {
// Collect all finished tasks
boolean allDone = true;
- List<Cursor> cursors = Lists.newArrayList();
+ List<Cursor> cursors = new ArrayList<>();
for (RecentTask task : mTasks.values()) {
if (task.isDone()) {
try {
@@ -221,7 +221,7 @@ public class RecentLoader extends AsyncTaskLoader<DirectoryResult> {
}
}
- if (LOGD) {
+ if (DEBUG) {
Log.d(TAG, "Found " + cursors.size() + " of " + mTasks.size() + " recent queries done");
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java b/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java
index e11d7d967961..662822ee35d3 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java
@@ -16,7 +16,7 @@
package com.android.documentsui;
-import static com.android.documentsui.DocumentsActivity.TAG;
+import static com.android.documentsui.Shared.TAG;
import android.app.Fragment;
import android.app.FragmentManager;
@@ -50,7 +50,6 @@ import com.android.documentsui.RecentsProvider.RecentColumns;
import com.android.documentsui.model.DocumentStack;
import com.android.documentsui.model.DurableUtils;
import com.android.documentsui.model.RootInfo;
-import com.google.android.collect.Lists;
import libcore.io.IoUtils;
@@ -157,7 +156,7 @@ public class RecentsCreateFragment extends Fragment {
@Override
public List<DocumentStack> loadInBackground(Uri uri, CancellationSignal signal) {
final Collection<RootInfo> matchingRoots = mRoots.getMatchingRootsBlocking(mState);
- final ArrayList<DocumentStack> result = Lists.newArrayList();
+ final ArrayList<DocumentStack> result = new ArrayList<>();
final ContentResolver resolver = getContext().getContentResolver();
final Cursor cursor = resolver.query(
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java b/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
index fbcb938692af..05f7d8dd11e3 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
@@ -16,7 +16,7 @@
package com.android.documentsui;
-import static com.android.documentsui.DocumentsActivity.TAG;
+import static com.android.documentsui.Shared.TAG;
import android.content.ContentProviderClient;
import android.content.ContentResolver;
@@ -39,14 +39,14 @@ import android.util.Log;
import com.android.documentsui.BaseActivity.State;
import com.android.documentsui.model.RootInfo;
import com.android.internal.annotations.GuardedBy;
-import com.android.internal.annotations.VisibleForTesting;
-import com.google.android.collect.Lists;
-import com.google.android.collect.Sets;
+import android.support.annotation.VisibleForTesting;
+
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap;
import libcore.io.IoUtils;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
@@ -74,10 +74,10 @@ public class RootsCache {
@GuardedBy("mLock")
private Multimap<String, RootInfo> mRoots = ArrayListMultimap.create();
@GuardedBy("mLock")
- private HashSet<String> mStoppedAuthorities = Sets.newHashSet();
+ private HashSet<String> mStoppedAuthorities = new HashSet<>();
@GuardedBy("mObservedAuthorities")
- private final HashSet<String> mObservedAuthorities = Sets.newHashSet();
+ private final HashSet<String> mObservedAuthorities = new HashSet<>();
public RootsCache(Context context) {
mContext = context;
@@ -159,7 +159,7 @@ public class RootsCache {
private final String mFilterPackage;
private final Multimap<String, RootInfo> mTaskRoots = ArrayListMultimap.create();
- private final HashSet<String> mTaskStoppedAuthorities = Sets.newHashSet();
+ private final HashSet<String> mTaskStoppedAuthorities = new HashSet<>();
/**
* Update all roots.
@@ -251,7 +251,7 @@ public class RootsCache {
}
}
- final List<RootInfo> roots = Lists.newArrayList();
+ final List<RootInfo> roots = new ArrayList<>();
final Uri rootsUri = DocumentsContract.buildRootsUri(authority);
ContentProviderClient client = null;
@@ -350,7 +350,7 @@ public class RootsCache {
@VisibleForTesting
static List<RootInfo> getMatchingRoots(Collection<RootInfo> roots, State state) {
- final List<RootInfo> matching = Lists.newArrayList();
+ final List<RootInfo> matching = new ArrayList<>();
for (RootInfo root : roots) {
final boolean supportsCreate = (root.flags & Root.FLAG_SUPPORTS_CREATE) != 0;
final boolean supportsIsChild = (root.flags & Root.FLAG_SUPPORTS_IS_CHILD) != 0;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java b/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
index fd67a77254a6..c02184b72b2f 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
@@ -44,8 +44,8 @@ import android.widget.TextView;
import com.android.documentsui.BaseActivity.State;
import com.android.documentsui.model.DocumentInfo;
import com.android.documentsui.model.RootInfo;
-import com.google.common.collect.Lists;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
@@ -293,8 +293,8 @@ public class RootsFragment extends Fragment {
RootItem audio = null;
RootItem downloads = null;
- final List<RootInfo> clouds = Lists.newArrayList();
- final List<RootInfo> locals = Lists.newArrayList();
+ final List<RootInfo> clouds = new ArrayList<>();
+ final List<RootInfo> locals = new ArrayList<>();
for (RootInfo root : roots) {
if (root.isRecents()) {
@@ -338,7 +338,7 @@ public class RootsFragment extends Fragment {
final List<ResolveInfo> infos = pm.queryIntentActivities(
includeApps, PackageManager.MATCH_DEFAULT_ONLY);
- final List<AppItem> apps = Lists.newArrayList();
+ final List<AppItem> apps = new ArrayList<>();
// Omit ourselves from the list
for (ResolveInfo info : infos) {
diff --git a/packages/DocumentsUI/src/com/android/documentsui/SectionedListAdapter.java b/packages/DocumentsUI/src/com/android/documentsui/SectionedListAdapter.java
index 088e3fa70d43..ae959f91dec0 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/SectionedListAdapter.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/SectionedListAdapter.java
@@ -22,8 +22,6 @@ import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.ListAdapter;
-import com.google.android.collect.Lists;
-
import java.util.ArrayList;
/**
@@ -31,7 +29,7 @@ import java.util.ArrayList;
* provide a header, and correctly handling item types across child adapters.
*/
public class SectionedListAdapter extends BaseAdapter {
- private ArrayList<SectionAdapter> mSections = Lists.newArrayList();
+ private ArrayList<SectionAdapter> mSections = new ArrayList<>();
public interface SectionAdapter extends ListAdapter {
public View getHeaderView(View convertView, ViewGroup parent);
diff --git a/packages/DocumentsUI/src/com/android/documentsui/Shared.java b/packages/DocumentsUI/src/com/android/documentsui/Shared.java
new file mode 100644
index 000000000000..b414ee3269d8
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/Shared.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.documentsui;
+
+/**
+ * @hide
+ */
+public final class Shared {
+ public static final String TAG = "Documents";
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/StandaloneActivity.java b/packages/DocumentsUI/src/com/android/documentsui/StandaloneActivity.java
index a935a0053429..7ca3954036bc 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/StandaloneActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/StandaloneActivity.java
@@ -20,7 +20,6 @@ import static com.android.documentsui.DirectoryFragment.ANIM_DOWN;
import static com.android.documentsui.DirectoryFragment.ANIM_NONE;
import static com.android.documentsui.DirectoryFragment.ANIM_UP;
-import android.annotation.Nullable;
import android.app.Activity;
import android.app.FragmentManager;
import android.content.ActivityNotFoundException;
@@ -33,6 +32,7 @@ import android.net.Uri;
import android.os.Bundle;
import android.provider.DocumentsContract;
import android.provider.DocumentsContract.Root;
+import android.support.annotation.Nullable;
import android.util.Log;
import android.view.KeyEvent;
import android.view.Menu;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/UriDerivativeLoader.java b/packages/DocumentsUI/src/com/android/documentsui/UriDerivativeLoader.java
index 1a5bb0c099a8..7bb662c72cf5 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/UriDerivativeLoader.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/UriDerivativeLoader.java
@@ -27,16 +27,16 @@ import android.os.OperationCanceledException;
* changes while started, manages {@link CancellationSignal}, and caches
* returned results.
*/
-public abstract class UriDerivativeLoader<P, R> extends AsyncTaskLoader<R> {
+public abstract class UriDerivativeLoader<Param, Res> extends AsyncTaskLoader<Res> {
final ForceLoadContentObserver mObserver;
- private final P mParam;
+ private final Param mParam;
- private R mResult;
+ private Res mResult;
private CancellationSignal mCancellationSignal;
@Override
- public final R loadInBackground() {
+ public final Res loadInBackground() {
synchronized (this) {
if (isLoadInBackgroundCanceled()) {
throw new OperationCanceledException();
@@ -52,7 +52,7 @@ public abstract class UriDerivativeLoader<P, R> extends AsyncTaskLoader<R> {
}
}
- public abstract R loadInBackground(P param, CancellationSignal signal);
+ public abstract Res loadInBackground(Param param, CancellationSignal signal);
@Override
public void cancelLoadInBackground() {
@@ -66,12 +66,12 @@ public abstract class UriDerivativeLoader<P, R> extends AsyncTaskLoader<R> {
}
@Override
- public void deliverResult(R result) {
+ public void deliverResult(Res result) {
if (isReset()) {
closeQuietly(result);
return;
}
- R oldResult = mResult;
+ Res oldResult = mResult;
mResult = result;
if (isStarted()) {
@@ -83,7 +83,7 @@ public abstract class UriDerivativeLoader<P, R> extends AsyncTaskLoader<R> {
}
}
- public UriDerivativeLoader(Context context, P param) {
+ public UriDerivativeLoader(Context context, Param param) {
super(context);
mObserver = new ForceLoadContentObserver();
mParam = param;
@@ -105,7 +105,7 @@ public abstract class UriDerivativeLoader<P, R> extends AsyncTaskLoader<R> {
}
@Override
- public void onCanceled(R result) {
+ public void onCanceled(Res result) {
closeQuietly(result);
}
@@ -122,7 +122,7 @@ public abstract class UriDerivativeLoader<P, R> extends AsyncTaskLoader<R> {
getContext().getContentResolver().unregisterContentObserver(mObserver);
}
- private void closeQuietly(R result) {
+ private void closeQuietly(Res result) {
if (result instanceof AutoCloseable) {
try {
((AutoCloseable) result).close();
diff --git a/packages/DocumentsUI/src/com/android/documentsui/model/DocumentInfo.java b/packages/DocumentsUI/src/com/android/documentsui/model/DocumentInfo.java
index 5d5f2ebabf2e..cc981e1eaaad 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/model/DocumentInfo.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/model/DocumentInfo.java
@@ -24,7 +24,6 @@ import android.os.Parcel;
import android.os.Parcelable;
import android.provider.DocumentsContract;
import android.provider.DocumentsContract.Document;
-import android.provider.DocumentsContract.Root;
import android.provider.DocumentsProvider;
import android.text.TextUtils;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/model/DurableUtils.java b/packages/DocumentsUI/src/com/android/documentsui/model/DurableUtils.java
index 2a29cbc23d0c..e21dd4930678 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/model/DurableUtils.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/model/DurableUtils.java
@@ -16,7 +16,7 @@
package com.android.documentsui.model;
-import static com.android.documentsui.DocumentsActivity.TAG;
+import static com.android.documentsui.Shared.TAG;
import android.os.BadParcelableException;
import android.os.Parcel;
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/BandSelectMatrixTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/BandSelectMatrixTest.java
new file mode 100644
index 000000000000..f15a6430388c
--- /dev/null
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/BandSelectMatrixTest.java
@@ -0,0 +1,277 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.documentsui;
+
+import static org.junit.Assert.*;
+
+import com.android.documentsui.BandSelectMatrix;
+
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.support.v7.widget.RecyclerView.OnScrollListener;
+import android.util.SparseBooleanArray;
+
+import org.junit.After;
+import org.junit.Test;
+
+public class BandSelectMatrixTest {
+
+ private static final int VIEW_PADDING_PX = 5;
+ private static final int CHILD_VIEW_EDGE_PX = 100;
+ private static final int VIEWPORT_HEIGHT = 500;
+
+ private static BandSelectMatrix matrix;
+ private static TestHelper helper;
+ private static SparseBooleanArray lastSelection;
+ private static int viewWidth;
+
+ private static void setUp(int numChildren, int numColumns) {
+ helper = new TestHelper(numChildren, numColumns);
+ viewWidth = VIEW_PADDING_PX + numColumns * (VIEW_PADDING_PX + CHILD_VIEW_EDGE_PX);
+ matrix = new BandSelectMatrix(helper);
+ matrix.addOnSelectionChangedListener(new BandSelectMatrix.OnSelectionChangedListener() {
+
+ @Override
+ public void onSelectionChanged(SparseBooleanArray updatedSelection) {
+ lastSelection = updatedSelection;
+ }
+ });
+ }
+
+ @After
+ public void tearDown() {
+ matrix = null;
+ helper = null;
+ lastSelection = null;
+ }
+
+ @Test
+ public void testSelectionLeftOfItems() {
+ setUp(20, 5);
+ matrix.startSelection(new Point(0, 10));
+ matrix.resizeSelection(new Point(1, 11));
+ assertSelected(new int[0]);
+ }
+
+ @Test
+ public void testSelectionRightOfItems() {
+ setUp(20, 4);
+ matrix.startSelection(new Point(viewWidth - 1, 10));
+ matrix.resizeSelection(new Point(viewWidth - 2, 11));
+ assertSelected(new int[0]);
+ }
+
+ @Test
+ public void testSelectionAboveItems() {
+ setUp(20, 4);
+ matrix.startSelection(new Point(10, 0));
+ matrix.resizeSelection(new Point(11, 1));
+ assertSelected(new int[0]);
+ }
+
+ @Test
+ public void testSelectionBelowItems() {
+ setUp(5, 4);
+ matrix.startSelection(new Point(10, VIEWPORT_HEIGHT - 1));
+ matrix.resizeSelection(new Point(11, VIEWPORT_HEIGHT - 2));
+ assertSelected(new int[0]);
+ }
+
+ @Test
+ public void testVerticalSelectionBetweenItems() {
+ setUp(20, 4);
+ matrix.startSelection(new Point(106, 0));
+ matrix.resizeSelection(new Point(107, 200));
+ assertSelected(new int[0]);
+ }
+
+ @Test
+ public void testHorizontalSelectionBetweenItems() {
+ setUp(20, 4);
+ matrix.startSelection(new Point(0, 105));
+ matrix.resizeSelection(new Point(200, 106));
+ assertSelected(new int[0]);
+ }
+
+ @Test
+ public void testGrowingAndShrinkingSelection() {
+ setUp(20, 4);
+ matrix.startSelection(new Point(0, 0));
+ matrix.resizeSelection(new Point(5, 5));
+ assertSelected(new int[] {0});
+ matrix.resizeSelection(new Point(109, 109));
+ assertSelected(new int[] {0});
+ matrix.resizeSelection(new Point(110, 109));
+ assertSelected(new int[] {0, 1});
+ matrix.resizeSelection(new Point(110, 110));
+ assertSelected(new int[] {0, 1, 4, 5});
+ matrix.resizeSelection(new Point(214, 214));
+ assertSelected(new int[] {0, 1, 4, 5});
+ matrix.resizeSelection(new Point(215, 214));
+ assertSelected(new int[] {0, 1, 2, 4, 5, 6});
+ matrix.resizeSelection(new Point(214, 214));
+ assertSelected(new int[] {0, 1, 4, 5});
+ matrix.resizeSelection(new Point(110, 110));
+ assertSelected(new int[] {0, 1, 4, 5});
+ matrix.resizeSelection(new Point(110, 109));
+ assertSelected(new int[] {0, 1});
+ matrix.resizeSelection(new Point(109, 109));
+ assertSelected(new int[] {0});
+ matrix.resizeSelection(new Point(5, 5));
+ assertSelected(new int[] {0});
+ matrix.resizeSelection(new Point(0, 0));
+ assertSelected(new int[0]);
+ }
+
+ @Test
+ public void testSelectionMovingAroundOrigin() {
+ setUp(16, 4);
+ matrix.startSelection(new Point(210, 210));
+ matrix.resizeSelection(new Point(viewWidth - 1, 0));
+ assertSelected(new int[] {2, 3, 6, 7});
+ matrix.resizeSelection(new Point(0, 0));
+ assertSelected(new int[] {0, 1, 4, 5});
+ matrix.resizeSelection(new Point(0, 420));
+ assertSelected(new int[] {8, 9, 12, 13});
+ matrix.resizeSelection(new Point(viewWidth - 1, 420));
+ assertSelected(new int[] {10, 11, 14, 15});
+ }
+
+ @Test
+ public void testScrollingBandSelect() {
+ setUp(40, 4);
+ matrix.startSelection(new Point(0, 0));
+ matrix.resizeSelection(new Point(100, VIEWPORT_HEIGHT - 1));
+ assertSelected(new int[] {0, 4, 8, 12, 16});
+ scroll(CHILD_VIEW_EDGE_PX);
+ assertSelected(new int[] {0, 4, 8, 12, 16, 20});
+ matrix.resizeSelection(new Point(200, VIEWPORT_HEIGHT - 1));
+ assertSelected(new int[] {0, 1, 4, 5, 8, 9, 12, 13, 16, 17, 20, 21});
+ scroll(CHILD_VIEW_EDGE_PX);
+ assertSelected(new int[] {0, 1, 4, 5, 8, 9, 12, 13, 16, 17, 20, 21, 24, 25});
+ scroll(-2 * CHILD_VIEW_EDGE_PX);
+ assertSelected(new int[] {0, 1, 4, 5, 8, 9, 12, 13, 16, 17});
+ matrix.resizeSelection(new Point(100, VIEWPORT_HEIGHT - 1));
+ assertSelected(new int[] {0, 4, 8, 12, 16});
+ }
+
+ private static void assertSelected(int[] selectedPositions) {
+ assertEquals(selectedPositions.length, lastSelection.size());
+ for (int position : selectedPositions) {
+ assertTrue(lastSelection.get(position));
+ }
+ }
+
+ private static void scroll(int dy) {
+ assertTrue(helper.verticalOffset + VIEWPORT_HEIGHT + dy <= helper.getTotalHeight());
+ helper.verticalOffset += dy;
+ matrix.onScrolled(null, 0, dy);
+ }
+
+ private static final class TestHelper implements BandSelectMatrix.RecyclerViewHelper {
+
+ public int horizontalOffset = 0;
+ public int verticalOffset = 0;
+ private final int mNumColumns;
+ private final int mNumRows;
+ private final int mNumChildren;
+
+ public TestHelper(int numChildren, int numColumns) {
+ mNumChildren = numChildren;
+ mNumColumns = numColumns;
+ mNumRows = (int) Math.ceil((double) numChildren / mNumColumns);
+ }
+
+ private int getTotalHeight() {
+ return CHILD_VIEW_EDGE_PX * mNumRows + VIEW_PADDING_PX * (mNumRows + 1);
+ }
+
+ private int getFirstVisibleRowIndex() {
+ return verticalOffset / (CHILD_VIEW_EDGE_PX + VIEW_PADDING_PX);
+ }
+
+ private int getLastVisibleRowIndex() {
+ int lastVisibleRowUncapped =
+ (VIEWPORT_HEIGHT + verticalOffset - 1) / (CHILD_VIEW_EDGE_PX + VIEW_PADDING_PX);
+ return Math.min(lastVisibleRowUncapped, mNumRows - 1);
+ }
+
+ private int getNumItemsInRow(int index) {
+ assertTrue(index >= 0 && index < mNumRows);
+ if (index == mNumRows - 1 && mNumChildren % mNumColumns != 0) {
+ return mNumChildren % mNumColumns;
+ }
+
+ return mNumColumns;
+ }
+
+ @Override
+ public void addOnScrollListener(OnScrollListener listener) {}
+
+ @Override
+ public void removeOnScrollListener(OnScrollListener listener) {}
+
+ @Override
+ public Point createAbsolutePoint(Point relativePoint) {
+ return new Point(
+ relativePoint.x + horizontalOffset, relativePoint.y + verticalOffset);
+ }
+
+ @Override
+ public int getVisibleChildCount() {
+ int childCount = 0;
+ for (int i = getFirstVisibleRowIndex(); i <= getLastVisibleRowIndex(); i++) {
+ childCount += getNumItemsInRow(i);
+ }
+ return childCount;
+ }
+
+ @Override
+ public int getAdapterPositionAt(int index) {
+ return index + mNumColumns * (getFirstVisibleRowIndex());
+ }
+
+ @Override
+ public Rect getAbsoluteRectForChildViewAt(int index) {
+ int adapterPosition = getAdapterPositionAt(index);
+ int rowIndex = adapterPosition / mNumColumns;
+ int columnIndex = adapterPosition % mNumColumns;
+
+ Rect rect = new Rect();
+ rect.top = VIEW_PADDING_PX + rowIndex * (CHILD_VIEW_EDGE_PX + VIEW_PADDING_PX);
+ rect.bottom = rect.top + CHILD_VIEW_EDGE_PX - 1;
+ rect.left = VIEW_PADDING_PX + columnIndex * (CHILD_VIEW_EDGE_PX + VIEW_PADDING_PX);
+ rect.right = rect.left + CHILD_VIEW_EDGE_PX - 1;
+ return rect;
+ }
+
+ @Override
+ public int getTotalChildCount() {
+ return mNumChildren;
+ }
+
+ @Override
+ public int getNumColumns() {
+ return mNumColumns;
+ }
+
+ @Override
+ public int getNumRows() {
+ return mNumRows;
+ }
+ }
+}
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/RootsCacheTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/RootsCacheTest.java
index 8c5bac15442d..132570674b48 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/RootsCacheTest.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/RootsCacheTest.java
@@ -21,7 +21,8 @@ import android.test.suitebuilder.annotation.SmallTest;
import com.android.documentsui.BaseActivity.State;
import com.android.documentsui.model.RootInfo;
-import com.google.android.collect.Lists;
+
+import com.google.common.collect.Lists;
import java.util.List;
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/StubProvider.java b/packages/DocumentsUI/tests/src/com/android/documentsui/StubProvider.java
index c2f176221f4b..6a2e03a3b809 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/StubProvider.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/StubProvider.java
@@ -36,8 +36,6 @@ import android.provider.DocumentsProvider;
import android.support.annotation.VisibleForTesting;
import android.util.Log;
-import com.google.android.collect.Maps;
-
import libcore.io.IoUtils;
import java.io.File;
@@ -101,7 +99,7 @@ public class StubProvider extends DocumentsProvider {
});
}
// Create new roots.
- mRoots = Maps.newHashMap();
+ mRoots = new HashMap<>();
for (String rootId : rootIds) {
final RootInfo rootInfo = new RootInfo(rootId, getSize(rootId));
mRoots.put(rootId, rootInfo);
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/UnitTests.java b/packages/DocumentsUI/tests/src/com/android/documentsui/UnitTests.java
index 4ffe799119ec..055327090eb4 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/UnitTests.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/UnitTests.java
@@ -22,6 +22,7 @@ import org.junit.runners.Suite.SuiteClasses;
@RunWith(Suite.class)
@SuiteClasses({
+ BandSelectMatrixTest.class,
MultiSelectManager_SelectionTest.class,
MultiSelectManagerTest.class
})
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocument.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocument.java
index 98775b36f796..7126694bc4a5 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocument.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocument.java
@@ -32,6 +32,7 @@ class MtpDocument {
private final Date mDateModified;
private final int mSize;
private final int mThumbSize;
+ private final boolean mReadOnly;
/**
* Constructor for root document.
@@ -40,9 +41,10 @@ class MtpDocument {
this(DUMMY_HANDLE_FOR_ROOT,
0x3001, // Directory.
root.mDescription,
- null, // Unknown,
+ null, // Unknown name.
(int) Math.min(root.mMaxCapacity - root.mFreeSpace, Integer.MAX_VALUE),
- 0);
+ 0, // Total size.
+ true); // Writable.
}
MtpDocument(MtpObjectInfo objectInfo) {
@@ -51,7 +53,8 @@ class MtpDocument {
objectInfo.getName(),
objectInfo.getDateModified() != 0 ? new Date(objectInfo.getDateModified()) : null,
objectInfo.getCompressedSize(),
- objectInfo.getThumbCompressedSize());
+ objectInfo.getThumbCompressedSize(),
+ objectInfo.getProtectionStatus() != 0);
}
MtpDocument(int objectHandle,
@@ -59,13 +62,15 @@ class MtpDocument {
String name,
Date dateModified,
int size,
- int thumbSize) {
+ int thumbSize,
+ boolean readOnly) {
this.mObjectHandle = objectHandle;
this.mFormat = format;
this.mName = name;
this.mDateModified = dateModified;
this.mSize = size;
this.mThumbSize = thumbSize;
+ this.mReadOnly = readOnly;
}
void addToCursor(Identifier rootIdentifier, MatrixCursor.RowBuilder builder) {
@@ -82,7 +87,7 @@ class MtpDocument {
builder.add(Document.COLUMN_DOCUMENT_ID, identifier.toDocumentId());
builder.add(Document.COLUMN_DISPLAY_NAME, mName);
- builder.add(Document.COLUMN_MIME_TYPE, getMimeType());
+ builder.add(Document.COLUMN_MIME_TYPE, formatTypeToMimeType(mFormat));
builder.add(
Document.COLUMN_LAST_MODIFIED,
mDateModified != null ? mDateModified.getTime() : null);
@@ -90,9 +95,9 @@ class MtpDocument {
builder.add(Document.COLUMN_SIZE, mSize);
}
- private String getMimeType() {
+ static String formatTypeToMimeType(int format) {
// TODO: Add complete list of mime types.
- switch (mFormat) {
+ switch (format) {
case 0x3001:
return DocumentsContract.Document.MIME_TYPE_DIR;
case 0x3009:
@@ -100,7 +105,21 @@ class MtpDocument {
case 0x3801:
return "image/jpeg";
default:
- return "";
+ return "application/octet-stream";
+ }
+ }
+
+ static int mimeTypeToFormatType(String mimeType) {
+ // TODO: Add complete list of mime types.
+ switch (mimeType.toLowerCase()) {
+ case Document.MIME_TYPE_DIR:
+ return 0x3001;
+ case "audio/mp3":
+ return 0x3009;
+ case "image/jpeg":
+ return 0x3801;
+ default:
+ return 0x3000; // Undefined object.
}
}
}
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
index 61b9fc53b98f..031cc074672a 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
@@ -96,7 +96,7 @@ public class MtpDocumentsProvider extends DocumentsProvider {
final Identifier rootIdentifier = new Identifier(root.mDeviceId, root.mStorageId);
final MatrixCursor.RowBuilder builder = cursor.newRow();
builder.add(Root.COLUMN_ROOT_ID, rootIdentifier.toRootId());
- builder.add(Root.COLUMN_FLAGS, Root.FLAG_SUPPORTS_IS_CHILD);
+ builder.add(Root.COLUMN_FLAGS, Root.FLAG_SUPPORTS_IS_CHILD | Root.FLAG_SUPPORTS_CREATE);
builder.add(Root.COLUMN_TITLE, root.mDescription);
builder.add(
Root.COLUMN_DOCUMENT_ID,
@@ -214,6 +214,24 @@ public class MtpDocumentsProvider extends DocumentsProvider {
mDocumentLoader.clearCache();
}
+ @Override
+ public String createDocument(String parentDocumentId, String mimeType, String displayName)
+ throws FileNotFoundException {
+ try {
+ final Identifier parentId = Identifier.createFromDocumentId(parentDocumentId);
+ final int objectHandle = mMtpManager.createDocument(
+ parentId.mDeviceId, parentId.mStorageId, parentId.mObjectHandle, mimeType,
+ displayName);
+ final String documentId = new Identifier(parentId.mDeviceId, parentId.mStorageId,
+ objectHandle).toDocumentId();
+ notifyChildDocumentsChange(parentDocumentId);
+ return documentId;
+ } catch (IOException error) {
+ Log.e(TAG, error.getMessage());
+ throw new FileNotFoundException(error.getMessage());
+ }
+ }
+
void openDevice(int deviceId) throws IOException {
mMtpManager.openDevice(deviceId);
mRootScanner.scanNow();
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java
index 3afc173fcc52..27ba794d3883 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java
@@ -21,7 +21,10 @@ import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbDeviceConnection;
import android.hardware.usb.UsbManager;
import android.mtp.MtpDevice;
+import android.mtp.MtpObjectInfo;
import android.os.ParcelFileDescriptor;
+import android.provider.DocumentsContract.Document;
+import android.provider.DocumentsContract;
import android.util.SparseArray;
import java.io.FileNotFoundException;
@@ -134,6 +137,22 @@ class MtpManager {
}
}
+ synchronized int createDocument(int deviceId, int storageId, int parentObjectHandle,
+ String mimeType, String name) throws IOException {
+ final MtpDevice device = getDevice(deviceId);
+ final MtpObjectInfo objectInfo = new MtpObjectInfo.Builder()
+ .setName(name)
+ .setStorageId(storageId)
+ .setParent(parentObjectHandle)
+ .setFormat(MtpDocument.mimeTypeToFormatType(mimeType))
+ .build();
+ final MtpObjectInfo result = device.sendObjectInfo(objectInfo);
+ if (result == null) {
+ throw new IOException("Failed to create a document");
+ }
+ return result.getObjectHandle();
+ }
+
synchronized int getParent(int deviceId, int objectHandle) throws IOException {
final MtpDevice device = getDevice(deviceId);
final int result = (int) device.getParent(objectHandle);
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/DocumentLoaderTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/DocumentLoaderTest.java
index 55041478f105..1e015bdc78d5 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/DocumentLoaderTest.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/DocumentLoaderTest.java
@@ -91,7 +91,8 @@ public class DocumentLoaderTest extends AndroidTestCase {
"file" + objectHandle,
new Date(),
1024,
- 0 /* thumbnail size */));
+ 0 /* thumbnail size */,
+ false /* not read only */));
}
manager.setObjectHandles(0, 0, MtpManager.OBJECT_HANDLE_ROOT_CHILDREN, childDocuments);
}
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java
index c1da59f5cb43..f06e2ffacf9a 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java
@@ -210,7 +210,8 @@ public class MtpDocumentsProviderTest extends AndroidTestCase {
"image.jpg" /* display name */,
new Date(1422716400000L) /* modified date */,
1024 * 1024 * 5 /* file size */,
- 1024 * 50 /* thumbnail size */));
+ 1024 * 50 /* thumbnail size */,
+ true /* read only */));
final Cursor cursor = mProvider.queryDocument("0_1_2", null);
assertEquals(1, cursor.getCount());
@@ -257,7 +258,8 @@ public class MtpDocumentsProviderTest extends AndroidTestCase {
"image.jpg" /* display name */,
new Date(0) /* modified date */,
1024 * 1024 * 5 /* file size */,
- 1024 * 50 /* thumbnail size */));
+ 1024 * 50 /* thumbnail size */,
+ true /* read only */));
final Cursor cursor = mProvider.queryChildDocuments("0_0_0", null, null);
assertEquals(1, cursor.getCount());
@@ -302,7 +304,8 @@ public class MtpDocumentsProviderTest extends AndroidTestCase {
"image.jpg" /* display name */,
new Date(1422716400000L) /* modified date */,
1024 * 1024 * 5 /* file size */,
- 1024 * 50 /* thumbnail size */));
+ 1024 * 50 /* thumbnail size */,
+ false /* not read only */));
mMtpManager.setParent(0, 1, 2);
mProvider.deleteDocument("0_0_1");
assertEquals(1, mResolver.getChangeCount(
diff --git a/packages/SettingsLib/src/com/android/settingslib/TetherUtil.java b/packages/SettingsLib/src/com/android/settingslib/TetherUtil.java
index 096a5c43e12c..f52d75502e7d 100644
--- a/packages/SettingsLib/src/com/android/settingslib/TetherUtil.java
+++ b/packages/SettingsLib/src/com/android/settingslib/TetherUtil.java
@@ -54,29 +54,7 @@ public class TetherUtil {
public static boolean setWifiTethering(boolean enable, Context context) {
final WifiManager wifiManager =
(WifiManager) context.getSystemService(Context.WIFI_SERVICE);
- final ContentResolver cr = context.getContentResolver();
- /**
- * Disable Wifi if enabling tethering
- */
- int wifiState = wifiManager.getWifiState();
- if (enable && ((wifiState == WifiManager.WIFI_STATE_ENABLING) ||
- (wifiState == WifiManager.WIFI_STATE_ENABLED))) {
- wifiManager.setWifiEnabled(false);
- Settings.Global.putInt(cr, Settings.Global.WIFI_SAVED_STATE, 1);
- }
-
- boolean success = wifiManager.setWifiApEnabled(null, enable);
- /**
- * If needed, restore Wifi on tether disable
- */
- if (!enable) {
- int wifiSavedState = Settings.Global.getInt(cr, Settings.Global.WIFI_SAVED_STATE, 0);
- if (wifiSavedState == 1) {
- wifiManager.setWifiEnabled(true);
- Settings.Global.putInt(cr, Settings.Global.WIFI_SAVED_STATE, 0);
- }
- }
- return success;
+ return wifiManager.setWifiApEnabled(null, enable);
}
public static boolean isWifiTetherEnabled(Context context) {
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index 34aeb60a1104..f72474983182 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -401,21 +401,40 @@ public class BackupManagerService {
public boolean isSystemRestore;
public String[] filterSet;
- // Restore a single package
+ /**
+ * Restore a single package; no kill after restore
+ */
RestoreParams(IBackupTransport _transport, String _dirName, IRestoreObserver _obs,
- long _token, PackageInfo _pkg, int _pmToken) {
+ long _token, PackageInfo _pkg) {
transport = _transport;
dirName = _dirName;
observer = _obs;
token = _token;
pkgInfo = _pkg;
- pmToken = _pmToken;
+ pmToken = 0;
isSystemRestore = false;
filterSet = null;
}
- // Restore everything possible. This is the form that Setup Wizard or similar
- // restore UXes use.
+ /**
+ * Restore at install: PM token needed, kill after restore
+ */
+ RestoreParams(IBackupTransport _transport, String _dirName, IRestoreObserver _obs,
+ long _token, String _pkgName, int _pmToken) {
+ transport = _transport;
+ dirName = _dirName;
+ observer = _obs;
+ token = _token;
+ pkgInfo = null;
+ pmToken = _pmToken;
+ isSystemRestore = false;
+ filterSet = new String[] { _pkgName };
+ }
+
+ /**
+ * Restore everything possible. This is the form that Setup Wizard or similar
+ * restore UXes use.
+ */
RestoreParams(IBackupTransport _transport, String _dirName, IRestoreObserver _obs,
long _token) {
transport = _transport;
@@ -428,8 +447,10 @@ public class BackupManagerService {
filterSet = null;
}
- // Restore some set of packages. Leave this one up to the caller to specify
- // whether it's to be considered a system-level restore.
+ /**
+ * Restore some set of packages. Leave this one up to the caller to specify
+ * whether it's to be considered a system-level restore.
+ */
RestoreParams(IBackupTransport _transport, String _dirName, IRestoreObserver _obs,
long _token, String[] _filterSet, boolean _isSystemRestore) {
transport = _transport;
@@ -9137,19 +9158,13 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF
// This can throw and so *must* happen before the wakelock is acquired
String dirName = transport.transportDirName();
- // We can use a synthetic PackageInfo here because:
- // 1. We know it's valid, since the Package Manager supplied the name
- // 2. Only the packageName field will be used by the restore code
- PackageInfo pkg = new PackageInfo();
- pkg.packageName = packageName;
-
mWakelock.acquire();
if (MORE_DEBUG) {
Slog.d(TAG, "Restore at install of " + packageName);
}
Message msg = mBackupHandler.obtainMessage(MSG_RUN_RESTORE);
msg.obj = new RestoreParams(transport, dirName, null,
- restoreSet, pkg, token);
+ restoreSet, packageName, token);
mBackupHandler.sendMessage(msg);
} catch (RemoteException e) {
// Binding to the transport broke; back off and proceed with the installation.
@@ -9528,8 +9543,7 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF
Slog.d(TAG, "restorePackage() : " + packageName);
}
Message msg = mBackupHandler.obtainMessage(MSG_RUN_RESTORE);
- msg.obj = new RestoreParams(mRestoreTransport, dirName,
- observer, token, app, 0);
+ msg.obj = new RestoreParams(mRestoreTransport, dirName, observer, token, app);
mBackupHandler.sendMessage(msg);
} finally {
Binder.restoreCallingIdentity(oldId);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 55a26599a92d..c1b07538c9dc 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -21,6 +21,7 @@ import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
import static android.Manifest.permission.START_TASKS_FROM_RECENTS;
import static android.app.ActivityManager.DOCKED_STACK_ID;
import static android.app.ActivityManager.HOME_STACK_ID;
+import static android.app.ActivityManager.INVALID_STACK_ID;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static com.android.internal.util.XmlUtils.readBooleanAttribute;
import static com.android.internal.util.XmlUtils.readIntAttribute;
@@ -9005,8 +9006,7 @@ public final class ActivityManagerService extends ActivityManagerNative
synchronized (this) {
ActivityStack stack = ActivityRecord.getStackLocked(token);
if (stack == null) {
- throw new IllegalArgumentException(
- "getActivityStackId: No stack for token=" + token);
+ return INVALID_STACK_ID;
}
return stack.mStackId;
}
diff --git a/services/core/java/com/android/server/wm/DragState.java b/services/core/java/com/android/server/wm/DragState.java
index 222945c2f594..e87dcdea77e6 100644
--- a/services/core/java/com/android/server/wm/DragState.java
+++ b/services/core/java/com/android/server/wm/DragState.java
@@ -16,6 +16,7 @@
package com.android.server.wm;
+import static com.android.server.wm.WindowState.BOUNDS_FOR_TOUCH;
import com.android.server.input.InputApplicationHandle;
import com.android.server.input.InputWindowHandle;
import com.android.server.wm.WindowManagerService.DragInputEventReceiver;
@@ -413,7 +414,7 @@ class DragState {
continue;
}
- child.getTaskBounds(mTmpRect);
+ child.getTaskBounds(mTmpRect, !BOUNDS_FOR_TOUCH);
if (!mTmpRect.contains(x, y)) {
// outside of this window's activity stack == don't tell about drags
continue;
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index 65f26c1c0afa..b3244ffb980f 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -16,6 +16,7 @@
package com.android.server.wm;
+import static com.android.server.wm.WindowState.BOUNDS_FOR_TOUCH;
import android.app.ActivityManagerNative;
import android.graphics.Rect;
import android.os.RemoteException;
@@ -177,7 +178,7 @@ final class InputMonitor implements InputManagerService.WindowManagerCallbacks {
if (modal && child.mAppToken != null) {
// Limit the outer touch to the activity stack region.
flags |= WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
- child.getTaskBounds(mTmpRect);
+ child.getTaskBounds(mTmpRect, BOUNDS_FOR_TOUCH);
inputWindowHandle.touchableRegion.set(mTmpRect);
} else {
// Not modal or full screen modal
diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java
index b871d7f0f501..d0962f46ddcf 100644
--- a/services/core/java/com/android/server/wm/WallpaperController.java
+++ b/services/core/java/com/android/server/wm/WallpaperController.java
@@ -16,6 +16,7 @@
package com.android.server.wm;
+import static android.app.ActivityManager.FREEFORM_WORKSPACE_STACK_ID;
import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
@@ -98,6 +99,8 @@ class WallpaperController {
private static final int WALLPAPER_DRAW_TIMEOUT = 2;
private int mWallpaperDrawState = WALLPAPER_DRAW_NORMAL;
+ private final FindWallpaperTargetResult mFindResults = new FindWallpaperTargetResult();
+
public WallpaperController(WindowManagerService service) {
mService = service;
}
@@ -466,39 +469,24 @@ class WallpaperController {
}
}
- boolean adjustWallpaperWindows() {
- mService.mInnerFields.mWallpaperMayChange = false;
- boolean targetChanged = false;
-
- // TODO(multidisplay): Wallpapers on main screen only.
- final DisplayInfo displayInfo = mService.getDefaultDisplayContentLocked().getDisplayInfo();
- final int dw = displayInfo.logicalWidth;
- final int dh = displayInfo.logicalHeight;
+ private void findWallpaperTarget(WindowList windows, FindWallpaperTargetResult result) {
final WindowAnimator winAnimator = mService.mAnimator;
-
- // First find top-most window that has asked to be on top of the
- // wallpaper; all wallpapers go behind it.
- final WindowList windows = mService.getDefaultWindowListLocked();
- int N = windows.size();
+ result.reset();
WindowState w = null;
- WindowState foundW = null;
- int foundI = 0;
- WindowState topCurW = null;
- int topCurI = 0;
int windowDetachedI = -1;
- int i = N;
- while (i > 0) {
- i--;
+ boolean resetTopWallpaper = false;
+ boolean inFreeformSpace = false;
+ for (int i = windows.size() - 1; i >= 0; i--) {
w = windows.get(i);
if ((w.mAttrs.type == TYPE_WALLPAPER)) {
- if (topCurW == null) {
- topCurW = w;
- topCurI = i;
+ if (result.topWallpaper == null || resetTopWallpaper) {
+ result.setTopWallpaper(w, i);
+ resetTopWallpaper = false;
}
continue;
}
- topCurW = null;
+ resetTopWallpaper = true;
if (w != winAnimator.mWindowDetachedWallpaper && w.mAppToken != null) {
// If this window's app token is hidden and not animating,
// it is of no interest to us.
@@ -511,23 +499,24 @@ class WallpaperController {
if (DEBUG_WALLPAPER) Slog.v(TAG, "Win #" + i + " " + w + ": isOnScreen="
+ w.isOnScreen() + " mDrawState=" + w.mWinAnimator.mDrawState);
- // If the app is executing an animation because the keyguard is going away, keep the
- // wallpaper during the animation so it doesn't flicker out.
- final boolean hasWallpaper = (w.mAttrs.flags&FLAG_SHOW_WALLPAPER) != 0
- || (w.mAppToken != null
- && w.mWinAnimator.mKeyguardGoingAwayAnimation);
+ if (!inFreeformSpace) {
+ TaskStack stack = w.getStack();
+ inFreeformSpace = stack != null && stack.mStackId == FREEFORM_WORKSPACE_STACK_ID;
+ }
+
+ // If the app is executing an animation because the keyguard is going away,
+ // keep the wallpaper during the animation so it doesn't flicker out.
+ final boolean hasWallpaper = (w.mAttrs.flags & FLAG_SHOW_WALLPAPER) != 0
+ || (w.mAppToken != null && w.mWinAnimator.mKeyguardGoingAwayAnimation);
if (hasWallpaper && w.isOnScreen()
&& (mWallpaperTarget == w || w.isDrawFinishedLw())) {
- if (DEBUG_WALLPAPER) Slog.v(TAG,
- "Found wallpaper target: #" + i + "=" + w);
- foundW = w;
- foundI = i;
+ if (DEBUG_WALLPAPER) Slog.v(TAG, "Found wallpaper target: #" + i + "=" + w);
+ result.setWallpaperTarget(w, i);
if (w == mWallpaperTarget && w.mWinAnimator.isAnimating()) {
- // The current wallpaper target is animating, so we'll
- // look behind it for another possible target and figure
- // out what is going on below.
- if (DEBUG_WALLPAPER) Slog.v(TAG, "Win " + w
- + ": token animating, looking behind.");
+ // The current wallpaper target is animating, so we'll look behind it for
+ // another possible target and figure out what is going on later.
+ if (DEBUG_WALLPAPER) Slog.v(TAG,
+ "Win " + w + ": token animating, looking behind.");
continue;
}
break;
@@ -536,76 +525,78 @@ class WallpaperController {
}
}
- if (foundW == null && windowDetachedI >= 0) {
+ if (result.wallpaperTarget == null && windowDetachedI >= 0) {
if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG,
- "Found animating detached wallpaper activity: #" + i + "=" + w);
- foundW = w;
- foundI = windowDetachedI;
+ "Found animating detached wallpaper activity: #" + windowDetachedI + "=" + w);
+ result.setWallpaperTarget(w, windowDetachedI);
+ }
+ if (result.wallpaperTarget == null && inFreeformSpace) {
+ // In freeform mode we set the wallpaper as its own target, so we don't need an
+ // additional window to make it visible.
+ result.setWallpaperTarget(result.topWallpaper, result.topWallpaperIndex);
}
+ }
- if (mWallpaperTarget != foundW
- && (mLowerWallpaperTarget == null || mLowerWallpaperTarget != foundW)) {
- if (DEBUG_WALLPAPER_LIGHT) {
- Slog.v(TAG, "New wallpaper target: " + foundW
- + " oldTarget: " + mWallpaperTarget);
- }
+ private boolean updateWallpaperWindowsTarget(
+ WindowList windows, FindWallpaperTargetResult result) {
+
+ boolean targetChanged = false;
+ WindowState wallpaperTarget = result.wallpaperTarget;
+ int wallpaperTargetIndex = result.wallpaperTargetIndex;
+
+ if (mWallpaperTarget != wallpaperTarget
+ && (mLowerWallpaperTarget == null || mLowerWallpaperTarget != wallpaperTarget)) {
+ if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG,
+ "New wallpaper target: " + wallpaperTarget + " oldTarget: " + mWallpaperTarget);
mLowerWallpaperTarget = null;
mUpperWallpaperTarget = null;
WindowState oldW = mWallpaperTarget;
- mWallpaperTarget = foundW;
+ mWallpaperTarget = wallpaperTarget;
targetChanged = true;
- // Now what is happening... if the current and new targets are
- // animating, then we are in our super special mode!
- if (foundW != null && oldW != null) {
+ // Now what is happening... if the current and new targets are animating,
+ // then we are in our super special mode!
+ if (wallpaperTarget != null && oldW != null) {
boolean oldAnim = oldW.isAnimatingLw();
- boolean foundAnim = foundW.isAnimatingLw();
- if (DEBUG_WALLPAPER_LIGHT) {
- Slog.v(TAG, "New animation: " + foundAnim
- + " old animation: " + oldAnim);
- }
+ boolean foundAnim = wallpaperTarget.isAnimatingLw();
+ if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG,
+ "New animation: " + foundAnim + " old animation: " + oldAnim);
if (foundAnim && oldAnim) {
int oldI = windows.indexOf(oldW);
- if (DEBUG_WALLPAPER_LIGHT) {
- Slog.v(TAG, "New i: " + foundI + " old i: " + oldI);
- }
+ if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG,
+ "New i: " + wallpaperTargetIndex + " old i: " + oldI);
if (oldI >= 0) {
- if (DEBUG_WALLPAPER_LIGHT) {
- Slog.v(TAG, "Animating wallpapers: old#" + oldI
- + "=" + oldW + "; new#" + foundI
- + "=" + foundW);
- }
+ if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG,
+ "Animating wallpapers: old#" + oldI + "=" + oldW + "; new#"
+ + wallpaperTargetIndex + "=" + wallpaperTarget);
// Set the new target correctly.
- if (foundW.mAppToken != null && foundW.mAppToken.hiddenRequested) {
- if (DEBUG_WALLPAPER_LIGHT) {
- Slog.v(TAG, "Old wallpaper still the target.");
- }
+ if (wallpaperTarget.mAppToken != null
+ && wallpaperTarget.mAppToken.hiddenRequested) {
+ if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG,
+ "Old wallpaper still the target.");
mWallpaperTarget = oldW;
- foundW = oldW;
- foundI = oldI;
+ wallpaperTarget = oldW;
+ wallpaperTargetIndex = oldI;
}
- // Now set the upper and lower wallpaper targets
- // correctly, and make sure that we are positioning
- // the wallpaper below the lower.
- else if (foundI > oldI) {
+ // Now set the upper and lower wallpaper targets correctly,
+ // and make sure that we are positioning the wallpaper below the lower.
+ else if (wallpaperTargetIndex > oldI) {
// The new target is on top of the old one.
- if (DEBUG_WALLPAPER_LIGHT) {
- Slog.v(TAG, "Found target above old target.");
- }
- mUpperWallpaperTarget = foundW;
+ if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG,
+ "Found target above old target.");
+ mUpperWallpaperTarget = wallpaperTarget;
mLowerWallpaperTarget = oldW;
- foundW = oldW;
- foundI = oldI;
+ wallpaperTarget = oldW;
+ wallpaperTargetIndex = oldI;
} else {
// The new target is below the old one.
- if (DEBUG_WALLPAPER_LIGHT) {
- Slog.v(TAG, "Found target below old target.");
- }
+ if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG,
+ "Found target below old target.");
mUpperWallpaperTarget = oldW;
- mLowerWallpaperTarget = foundW;
+ mLowerWallpaperTarget = wallpaperTarget;
}
}
}
@@ -614,29 +605,36 @@ class WallpaperController {
} else if (mLowerWallpaperTarget != null) {
// Is it time to stop animating?
if (!mLowerWallpaperTarget.isAnimatingLw() || !mUpperWallpaperTarget.isAnimatingLw()) {
- if (DEBUG_WALLPAPER_LIGHT) {
- Slog.v(TAG, "No longer animating wallpaper targets!");
- }
+ if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, "No longer animating wallpaper targets!");
mLowerWallpaperTarget = null;
mUpperWallpaperTarget = null;
- mWallpaperTarget = foundW;
+ mWallpaperTarget = wallpaperTarget;
targetChanged = true;
}
}
- boolean visible = foundW != null;
+ result.setWallpaperTarget(wallpaperTarget, wallpaperTargetIndex);
+ return targetChanged;
+ }
+
+ boolean updateWallpaperWindowsTargetByLayer(
+ WindowList windows, FindWallpaperTargetResult result) {
+
+ WindowState wallpaperTarget = result.wallpaperTarget;
+ int wallpaperTargetIndex = result.wallpaperTargetIndex;
+ boolean visible = wallpaperTarget != null;
+
if (visible) {
- // The window is visible to the compositor... but is it visible
- // to the user? That is what the wallpaper cares about.
- visible = isWallpaperVisible(foundW);
+ // The window is visible to the compositor...but is it visible to the user?
+ // That is what the wallpaper cares about.
+ visible = isWallpaperVisible(wallpaperTarget);
if (DEBUG_WALLPAPER) Slog.v(TAG, "Wallpaper visibility: " + visible);
- // If the wallpaper target is animating, we may need to copy
- // its layer adjustment. Only do this if we are not transfering
- // between two wallpaper targets.
+ // If the wallpaper target is animating, we may need to copy its layer adjustment.
+ // Only do this if we are not transferring between two wallpaper targets.
mWallpaperAnimLayerAdjustment =
- (mLowerWallpaperTarget == null && foundW.mAppToken != null)
- ? foundW.mAppToken.mAppAnimator.animLayerAdjustment : 0;
+ (mLowerWallpaperTarget == null && wallpaperTarget.mAppToken != null)
+ ? wallpaperTarget.mAppToken.mAppAnimator.animLayerAdjustment : 0;
final int maxLayer = (mService.mPolicy.getMaxWallpaperLayer() * TYPE_LAYER_MULTIPLIER)
+ TYPE_LAYER_OFFSET;
@@ -645,52 +643,37 @@ class WallpaperController {
// need to be sure to also be behind any of its attached windows,
// AND any starting window associated with it, AND below the
// maximum layer the policy allows for wallpapers.
- while (foundI > 0) {
- WindowState wb = windows.get(foundI - 1);
+ while (wallpaperTargetIndex > 0) {
+ WindowState wb = windows.get(wallpaperTargetIndex - 1);
if (wb.mBaseLayer < maxLayer &&
- wb.mAttachedWindow != foundW &&
- (foundW.mAttachedWindow == null ||
- wb.mAttachedWindow != foundW.mAttachedWindow) &&
- (wb.mAttrs.type != TYPE_APPLICATION_STARTING ||
- foundW.mToken == null || wb.mToken != foundW.mToken)) {
+ wb.mAttachedWindow != wallpaperTarget &&
+ (wallpaperTarget.mAttachedWindow == null ||
+ wb.mAttachedWindow != wallpaperTarget.mAttachedWindow) &&
+ (wb.mAttrs.type != TYPE_APPLICATION_STARTING
+ || wallpaperTarget.mToken == null
+ || wb.mToken != wallpaperTarget.mToken)) {
// This window is not related to the previous one in any
// interesting way, so stop here.
break;
}
- foundW = wb;
- foundI--;
+ wallpaperTarget = wb;
+ wallpaperTargetIndex--;
}
} else {
if (DEBUG_WALLPAPER) Slog.v(TAG, "No wallpaper target");
}
- if (foundW == null && topCurW != null) {
- // There is no wallpaper target, so it goes at the bottom.
- // We will assume it is the same place as last time, if known.
- foundW = topCurW;
- foundI = topCurI+1;
- } else {
- // Okay i is the position immediately above the wallpaper. Look at
- // what is below it for later.
- foundW = foundI > 0 ? windows.get(foundI - 1) : null;
- }
+ result.setWallpaperTarget(wallpaperTarget, wallpaperTargetIndex);
+ return visible;
+ }
- if (visible) {
- if (mWallpaperTarget.mWallpaperX >= 0) {
- mLastWallpaperX = mWallpaperTarget.mWallpaperX;
- mLastWallpaperXStep = mWallpaperTarget.mWallpaperXStep;
- }
- if (mWallpaperTarget.mWallpaperY >= 0) {
- mLastWallpaperY = mWallpaperTarget.mWallpaperY;
- mLastWallpaperYStep = mWallpaperTarget.mWallpaperYStep;
- }
- if (mWallpaperTarget.mWallpaperDisplayOffsetX != Integer.MIN_VALUE) {
- mLastWallpaperDisplayOffsetX = mWallpaperTarget.mWallpaperDisplayOffsetX;
- }
- if (mWallpaperTarget.mWallpaperDisplayOffsetY != Integer.MIN_VALUE) {
- mLastWallpaperDisplayOffsetY = mWallpaperTarget.mWallpaperDisplayOffsetY;
- }
- }
+ boolean updateWallpaperWindowsPlacement(WindowList windows,
+ WindowState wallpaperTarget, int wallpaperTargetIndex, boolean visible) {
+
+ // TODO(multidisplay): Wallpapers on main screen only.
+ final DisplayInfo displayInfo = mService.getDefaultDisplayContentLocked().getDisplayInfo();
+ final int dw = displayInfo.logicalWidth;
+ final int dh = displayInfo.logicalHeight;
// Start stepping backwards from here, ensuring that our wallpaper windows
// are correctly placed.
@@ -722,41 +705,40 @@ class WallpaperController {
+ wallpaper + " anim layer: " + wallpaper.mWinAnimator.mAnimLayer);
// First, if this window is at the current index, then all is well.
- if (wallpaper == foundW) {
- foundI--;
- foundW = foundI > 0 ? windows.get(foundI - 1) : null;
+ if (wallpaper == wallpaperTarget) {
+ wallpaperTargetIndex--;
+ wallpaperTarget = wallpaperTargetIndex > 0
+ ? windows.get(wallpaperTargetIndex - 1) : null;
continue;
}
// The window didn't match... the current wallpaper window,
- // wherever it is, is in the wrong place, so make sure it is
- // not in the list.
+ // wherever it is, is in the wrong place, so make sure it is not in the list.
int oldIndex = windows.indexOf(wallpaper);
if (oldIndex >= 0) {
- if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG, "Wallpaper removing at "
- + oldIndex + ": " + wallpaper);
+ if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG,
+ "Wallpaper removing at " + oldIndex + ": " + wallpaper);
windows.remove(oldIndex);
mService.mWindowsChanged = true;
- if (oldIndex < foundI) {
- foundI--;
+ if (oldIndex < wallpaperTargetIndex) {
+ wallpaperTargetIndex--;
}
}
// Now stick it in. For apps over wallpaper keep the wallpaper at the bottommost
// layer. For keyguard over wallpaper put the wallpaper under the keyguard.
int insertionIndex = 0;
- if (visible && foundW != null) {
- final int type = foundW.mAttrs.type;
- final int privateFlags = foundW.mAttrs.privateFlags;
+ if (visible && wallpaperTarget != null) {
+ final int type = wallpaperTarget.mAttrs.type;
+ final int privateFlags = wallpaperTarget.mAttrs.privateFlags;
if ((privateFlags & PRIVATE_FLAG_KEYGUARD) != 0
|| type == TYPE_KEYGUARD_SCRIM) {
- insertionIndex = windows.indexOf(foundW);
+ insertionIndex = windows.indexOf(wallpaperTarget);
}
}
- if (DEBUG_WALLPAPER_LIGHT || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) {
- Slog.v(TAG, "Moving wallpaper " + wallpaper
- + " from " + oldIndex + " to " + insertionIndex);
- }
+ if (DEBUG_WALLPAPER_LIGHT || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG,
+ "Moving wallpaper " + wallpaper
+ + " from " + oldIndex + " to " + insertionIndex);
windows.add(insertionIndex, wallpaper);
mService.mWindowsChanged = true;
@@ -764,6 +746,53 @@ class WallpaperController {
}
}
+ return changed;
+ }
+
+ boolean adjustWallpaperWindows() {
+ mService.mInnerFields.mWallpaperMayChange = false;
+
+ final WindowList windows = mService.getDefaultWindowListLocked();
+ // First find top-most window that has asked to be on top of the wallpaper;
+ // all wallpapers go behind it.
+ findWallpaperTarget(windows, mFindResults);
+ final boolean targetChanged = updateWallpaperWindowsTarget(windows, mFindResults);
+ final boolean visible = updateWallpaperWindowsTargetByLayer(windows, mFindResults);
+ WindowState wallpaperTarget = mFindResults.wallpaperTarget;
+ int wallpaperTargetIndex = mFindResults.wallpaperTargetIndex;
+
+ if (wallpaperTarget == null && mFindResults.topWallpaper != null) {
+ // There is no wallpaper target, so it goes at the bottom.
+ // We will assume it is the same place as last time, if known.
+ wallpaperTarget = mFindResults.topWallpaper;
+ wallpaperTargetIndex = mFindResults.topWallpaperIndex + 1;
+ } else {
+ // Okay i is the position immediately above the wallpaper.
+ // Look at what is below it for later.
+ wallpaperTarget = wallpaperTargetIndex > 0
+ ? windows.get(wallpaperTargetIndex - 1) : null;
+ }
+
+ if (visible) {
+ if (mWallpaperTarget.mWallpaperX >= 0) {
+ mLastWallpaperX = mWallpaperTarget.mWallpaperX;
+ mLastWallpaperXStep = mWallpaperTarget.mWallpaperXStep;
+ }
+ if (mWallpaperTarget.mWallpaperY >= 0) {
+ mLastWallpaperY = mWallpaperTarget.mWallpaperY;
+ mLastWallpaperYStep = mWallpaperTarget.mWallpaperYStep;
+ }
+ if (mWallpaperTarget.mWallpaperDisplayOffsetX != Integer.MIN_VALUE) {
+ mLastWallpaperDisplayOffsetX = mWallpaperTarget.mWallpaperDisplayOffsetX;
+ }
+ if (mWallpaperTarget.mWallpaperDisplayOffsetY != Integer.MIN_VALUE) {
+ mLastWallpaperDisplayOffsetY = mWallpaperTarget.mWallpaperDisplayOffsetY;
+ }
+ }
+
+ final boolean changed = updateWallpaperWindowsPlacement(
+ windows, wallpaperTarget, wallpaperTargetIndex, visible);
+
if (targetChanged && DEBUG_WALLPAPER_LIGHT) Slog.d(TAG, "New wallpaper: target="
+ mWallpaperTarget + " lower=" + mLowerWallpaperTarget + " upper="
+ mUpperWallpaperTarget);
@@ -859,4 +888,29 @@ class WallpaperController {
}
}
}
+
+ /** Helper class for storing the results of a wallpaper target find operation. */
+ final private static class FindWallpaperTargetResult {
+ int topWallpaperIndex = 0;
+ WindowState topWallpaper = null;
+ int wallpaperTargetIndex = 0;
+ WindowState wallpaperTarget = null;
+
+ void setTopWallpaper(WindowState win, int index) {
+ topWallpaper = win;
+ topWallpaperIndex = index;
+ }
+
+ void setWallpaperTarget(WindowState win, int index) {
+ wallpaperTarget = win;
+ wallpaperTargetIndex = index;
+ }
+
+ void reset() {
+ topWallpaperIndex = 0;
+ topWallpaper = null;
+ wallpaperTargetIndex = 0;
+ wallpaperTarget = null;
+ }
+ }
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 7e7d009a8675..029609d6d213 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -114,6 +114,7 @@ import android.view.WindowManagerPolicy.PointerEventListener;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
+import static com.android.server.wm.WindowState.BOUNDS_FOR_TOUCH;
import com.android.internal.app.IAssistScreenshotReceiver;
import com.android.internal.app.IBatteryStats;
import com.android.internal.util.FastPrintWriter;
@@ -597,6 +598,7 @@ public class WindowManagerService extends IWindowManager.Stub
final InputManagerService mInputManager;
final DisplayManagerInternal mDisplayManagerInternal;
final DisplayManager mDisplayManager;
+ final Display[] mDisplays;
// Who is holding the screen on.
Session mHoldingScreenOn;
@@ -870,8 +872,8 @@ public class WindowManagerService extends IWindowManager.Stub
mFxSession = new SurfaceSession();
mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
- Display[] displays = mDisplayManager.getDisplays();
- for (Display display : displays) {
+ mDisplays = mDisplayManager.getDisplays();
+ for (Display display : mDisplays) {
createDisplayContentLocked(display);
}
@@ -5633,7 +5635,7 @@ public class WindowManagerService extends IWindowManager.Stub
int right = wf.right - cr.right;
int bottom = wf.bottom - cr.bottom;
frame.union(left, top, right, bottom);
- ws.getTaskBounds(stackBounds);
+ ws.getTaskBounds(stackBounds, !BOUNDS_FOR_TOUCH);
if (!frame.intersect(stackBounds)) {
// Set frame empty if there's no intersection.
frame.setEmpty();
@@ -7003,7 +7005,9 @@ public class WindowManagerService extends IWindowManager.Stub
}
public void displayReady() {
- displayReady(Display.DEFAULT_DISPLAY);
+ for (Display display : mDisplays) {
+ displayReady(display.getDisplayId());
+ }
synchronized(mWindowMap) {
final DisplayContent displayContent = getDefaultDisplayContentLocked();
@@ -8553,312 +8557,322 @@ public class WindowManagerService extends IWindowManager.Stub
* @return bitmap indicating if another pass through layout must be made.
*/
public int handleAppTransitionReadyLocked(WindowList windows) {
- int changes = 0;
- int i;
int appsCount = mOpeningApps.size();
- boolean goodToGo = true;
- if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
- "Checking " + appsCount + " opening apps (frozen="
- + mDisplayFrozen + " timeout="
- + mAppTransition.isTimeout() + ")...");
- if (!mAppTransition.isTimeout()) {
- for (i = 0; i < appsCount && goodToGo; i++) {
- AppWindowToken wtoken = mOpeningApps.valueAt(i);
- if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
- "Check opening app=" + wtoken + ": allDrawn="
- + wtoken.allDrawn + " startingDisplayed="
- + wtoken.startingDisplayed + " startingMoved="
- + wtoken.startingMoved);
- if (!wtoken.allDrawn && !wtoken.startingDisplayed
- && !wtoken.startingMoved) {
- goodToGo = false;
- }
- }
-
- if (goodToGo && mWallpaperControllerLocked.isWallpaperVisible()) {
- goodToGo &= mWallpaperControllerLocked.wallpaperTransitionReady();
- }
+ if (!checkIfTransitionGoodToGo(appsCount)) {
+ return 0;
}
- if (goodToGo) {
- if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "**** GOOD TO GO");
- int transit = mAppTransition.getAppTransition();
- if (mSkipAppTransitionAnimation) {
- transit = AppTransition.TRANSIT_UNSET;
- }
- mSkipAppTransitionAnimation = false;
- mNoAnimationNotifyOnTransitionFinished.clear();
-
- mH.removeMessages(H.APP_TRANSITION_TIMEOUT);
-
- rebuildAppWindowListLocked();
-
- // if wallpaper is animating in or out set oldWallpaper to null else to wallpaper
- final WindowState wallpaperTarget = mWallpaperControllerLocked.getWallpaperTarget();
- final WindowState oldWallpaper = mWallpaperControllerLocked.isWallpaperTargetAnimating()
- ? null : wallpaperTarget;
+ if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "**** GOOD TO GO");
+ int transit = mAppTransition.getAppTransition();
+ if (mSkipAppTransitionAnimation) {
+ transit = AppTransition.TRANSIT_UNSET;
+ }
+ mSkipAppTransitionAnimation = false;
+ mNoAnimationNotifyOnTransitionFinished.clear();
- mInnerFields.mWallpaperMayChange = false;
+ mH.removeMessages(H.APP_TRANSITION_TIMEOUT);
- // The top-most window will supply the layout params,
- // and we will determine it below.
- LayoutParams animLp = null;
- int bestAnimLayer = -1;
- boolean fullscreenAnim = false;
- boolean voiceInteraction = false;
+ rebuildAppWindowListLocked();
- final WindowState lowerWallpaperTarget =
- mWallpaperControllerLocked.getLowerWallpaperTarget();
- final WindowState upperWallpaperTarget =
- mWallpaperControllerLocked.getUpperWallpaperTarget();
+ mInnerFields.mWallpaperMayChange = false;
+
+ // The top-most window will supply the layout params,
+ // and we will determine it below.
+ LayoutParams animLp = null;
+ int bestAnimLayer = -1;
+ boolean fullscreenAnim = false;
+ boolean voiceInteraction = false;
+
+ final WindowState lowerWallpaperTarget =
+ mWallpaperControllerLocked.getLowerWallpaperTarget();
+ final WindowState upperWallpaperTarget =
+ mWallpaperControllerLocked.getUpperWallpaperTarget();
+
+ boolean openingAppHasWallpaper = false;
+ boolean closingAppHasWallpaper = false;
+ final AppWindowToken lowerWallpaperAppToken;
+ final AppWindowToken upperWallpaperAppToken;
+ if (lowerWallpaperTarget == null) {
+ lowerWallpaperAppToken = upperWallpaperAppToken = null;
+ } else {
+ lowerWallpaperAppToken = lowerWallpaperTarget.mAppToken;
+ upperWallpaperAppToken = upperWallpaperTarget.mAppToken;
+ }
- if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
- "New wallpaper target=" + wallpaperTarget
- + ", oldWallpaper=" + oldWallpaper
- + ", lower target=" + lowerWallpaperTarget
- + ", upper target=" + upperWallpaperTarget);
-
- boolean openingAppHasWallpaper = false;
- boolean closingAppHasWallpaper = false;
- final AppWindowToken lowerWallpaperAppToken;
- final AppWindowToken upperWallpaperAppToken;
- if (lowerWallpaperTarget == null) {
- lowerWallpaperAppToken = upperWallpaperAppToken = null;
+ int i;
+ // Do a first pass through the tokens for two
+ // things:
+ // (1) Determine if both the closing and opening
+ // app token sets are wallpaper targets, in which
+ // case special animations are needed
+ // (since the wallpaper needs to stay static
+ // behind them).
+ // (2) Find the layout params of the top-most
+ // application window in the tokens, which is
+ // what will control the animation theme.
+ final int closingAppsCount = mClosingApps.size();
+ appsCount = closingAppsCount + mOpeningApps.size();
+ for (i = 0; i < appsCount; i++) {
+ final AppWindowToken wtoken;
+ if (i < closingAppsCount) {
+ wtoken = mClosingApps.valueAt(i);
+ if (wtoken == lowerWallpaperAppToken || wtoken == upperWallpaperAppToken) {
+ closingAppHasWallpaper = true;
+ }
} else {
- lowerWallpaperAppToken = lowerWallpaperTarget.mAppToken;
- upperWallpaperAppToken = upperWallpaperTarget.mAppToken;
- }
-
- // Do a first pass through the tokens for two
- // things:
- // (1) Determine if both the closing and opening
- // app token sets are wallpaper targets, in which
- // case special animations are needed
- // (since the wallpaper needs to stay static
- // behind them).
- // (2) Find the layout params of the top-most
- // application window in the tokens, which is
- // what will control the animation theme.
- final int closingAppsCount = mClosingApps.size();
- appsCount = closingAppsCount + mOpeningApps.size();
- for (i = 0; i < appsCount; i++) {
- final AppWindowToken wtoken;
- if (i < closingAppsCount) {
- wtoken = mClosingApps.valueAt(i);
- if (wtoken == lowerWallpaperAppToken || wtoken == upperWallpaperAppToken) {
- closingAppHasWallpaper = true;
- }
- } else {
- wtoken = mOpeningApps.valueAt(i - closingAppsCount);
- if (wtoken == lowerWallpaperAppToken || wtoken == upperWallpaperAppToken) {
- openingAppHasWallpaper = true;
- }
+ wtoken = mOpeningApps.valueAt(i - closingAppsCount);
+ if (wtoken == lowerWallpaperAppToken || wtoken == upperWallpaperAppToken) {
+ openingAppHasWallpaper = true;
}
+ }
- voiceInteraction |= wtoken.voiceInteraction;
+ voiceInteraction |= wtoken.voiceInteraction;
- if (wtoken.appFullscreen) {
- WindowState ws = wtoken.findMainWindow();
- if (ws != null) {
+ if (wtoken.appFullscreen) {
+ WindowState ws = wtoken.findMainWindow();
+ if (ws != null) {
+ animLp = ws.mAttrs;
+ bestAnimLayer = ws.mLayer;
+ fullscreenAnim = true;
+ }
+ } else if (!fullscreenAnim) {
+ WindowState ws = wtoken.findMainWindow();
+ if (ws != null) {
+ if (ws.mLayer > bestAnimLayer) {
animLp = ws.mAttrs;
bestAnimLayer = ws.mLayer;
- fullscreenAnim = true;
- }
- } else if (!fullscreenAnim) {
- WindowState ws = wtoken.findMainWindow();
- if (ws != null) {
- if (ws.mLayer > bestAnimLayer) {
- animLp = ws.mAttrs;
- bestAnimLayer = ws.mLayer;
- }
}
}
}
+ }
- mAnimateWallpaperWithTarget = false;
- if (closingAppHasWallpaper && openingAppHasWallpaper) {
- if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Wallpaper animation!");
- switch (transit) {
- case AppTransition.TRANSIT_ACTIVITY_OPEN:
- case AppTransition.TRANSIT_TASK_OPEN:
- case AppTransition.TRANSIT_TASK_TO_FRONT:
- transit = AppTransition.TRANSIT_WALLPAPER_INTRA_OPEN;
- break;
- case AppTransition.TRANSIT_ACTIVITY_CLOSE:
- case AppTransition.TRANSIT_TASK_CLOSE:
- case AppTransition.TRANSIT_TASK_TO_BACK:
- transit = AppTransition.TRANSIT_WALLPAPER_INTRA_CLOSE;
- break;
+ transit = maybeUpdateTransitToWallpaper(transit, openingAppHasWallpaper,
+ closingAppHasWallpaper, lowerWallpaperTarget, upperWallpaperTarget);
+
+ // If all closing windows are obscured, then there is
+ // no need to do an animation. This is the case, for
+ // example, when this transition is being done behind
+ // the lock screen.
+ if (!mPolicy.allowAppAnimationsLw()) {
+ if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
+ "Animations disallowed by keyguard or dream.");
+ animLp = null;
+ }
+
+ processApplicationsAnimatingInPlace(transit);
+
+ AppWindowToken topClosingApp = null;
+ int topClosingLayer = 0;
+ appsCount = mClosingApps.size();
+ for (i = 0; i < appsCount; i++) {
+ AppWindowToken wtoken = mClosingApps.valueAt(i);
+ final AppWindowAnimator appAnimator = wtoken.mAppAnimator;
+ if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Now closing app " + wtoken);
+ appAnimator.clearThumbnail();
+ appAnimator.animation = null;
+ wtoken.inPendingTransaction = false;
+ setTokenVisibilityLocked(wtoken, animLp, false, transit, false, voiceInteraction);
+ wtoken.updateReportedVisibilityLocked();
+ // Force the allDrawn flag, because we want to start
+ // this guy's animations regardless of whether it's
+ // gotten drawn.
+ wtoken.allDrawn = true;
+ wtoken.deferClearAllDrawn = false;
+ // Ensure that apps that are mid-starting are also scheduled to have their
+ // starting windows removed after the animation is complete
+ if (wtoken.startingWindow != null && !wtoken.startingWindow.mExiting) {
+ scheduleRemoveStartingWindowLocked(wtoken);
+ }
+ mAnimator.mAppWindowAnimating |= appAnimator.isAnimating();
+
+ if (animLp != null) {
+ int layer = -1;
+ for (int j = 0; j < wtoken.windows.size(); j++) {
+ WindowState win = wtoken.windows.get(j);
+ if (win.mWinAnimator.mAnimLayer > layer) {
+ layer = win.mWinAnimator.mAnimLayer;
+ }
+ }
+ if (topClosingApp == null || layer > topClosingLayer) {
+ topClosingApp = wtoken;
+ topClosingLayer = layer;
}
- if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
- "New transit: " + AppTransition.appTransitionToString(transit));
- } else if ((oldWallpaper != null) && !mOpeningApps.isEmpty()
- && !mOpeningApps.contains(oldWallpaper.mAppToken)) {
- // We are transitioning from an activity with
- // a wallpaper to one without.
- transit = AppTransition.TRANSIT_WALLPAPER_CLOSE;
- if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
- "New transit away from wallpaper: "
- + AppTransition.appTransitionToString(transit));
- } else if (wallpaperTarget != null && wallpaperTarget.isVisibleLw()) {
- // We are transitioning from an activity without
- // a wallpaper to now showing the wallpaper
- transit = AppTransition.TRANSIT_WALLPAPER_OPEN;
- if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
- "New transit into wallpaper: "
- + AppTransition.appTransitionToString(transit));
- } else {
- mAnimateWallpaperWithTarget = true;
}
+ }
- // If all closing windows are obscured, then there is
- // no need to do an animation. This is the case, for
- // example, when this transition is being done behind
- // the lock screen.
- if (!mPolicy.allowAppAnimationsLw()) {
- if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
- "Animations disallowed by keyguard or dream.");
- animLp = null;
- }
-
- // Process all applications animating in place
- if (transit == AppTransition.TRANSIT_TASK_IN_PLACE) {
- // Find the focused window
- final WindowState win =
- findFocusedWindowLocked(getDefaultDisplayContentLocked());
- if (win != null) {
- final AppWindowToken wtoken = win.mAppToken;
- final AppWindowAnimator appAnimator = wtoken.mAppAnimator;
- if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Now animating app in place " + wtoken);
- appAnimator.clearThumbnail();
- appAnimator.animation = null;
- updateTokenInPlaceLocked(wtoken, transit);
- wtoken.updateReportedVisibilityLocked();
-
- appAnimator.mAllAppWinAnimators.clear();
- final int N = wtoken.allAppWindows.size();
- for (int j = 0; j < N; j++) {
- appAnimator.mAllAppWinAnimators.add(wtoken.allAppWindows.get(j).mWinAnimator);
- }
- mAnimator.mAppWindowAnimating |= appAnimator.isAnimating();
- mAnimator.mAnimating |= appAnimator.showAllWindowsLocked();
- }
- }
-
- AppWindowToken topClosingApp = null;
- int topClosingLayer = 0;
- appsCount = mClosingApps.size();
- for (i = 0; i < appsCount; i++) {
- AppWindowToken wtoken = mClosingApps.valueAt(i);
- final AppWindowAnimator appAnimator = wtoken.mAppAnimator;
- if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Now closing app " + wtoken);
+ AppWindowToken topOpeningApp = null;
+ appsCount = mOpeningApps.size();
+ for (i = 0; i < appsCount; i++) {
+ AppWindowToken wtoken = mOpeningApps.valueAt(i);
+ final AppWindowAnimator appAnimator = wtoken.mAppAnimator;
+ if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Now opening app" + wtoken);
+
+ if (!appAnimator.usingTransferredAnimation) {
appAnimator.clearThumbnail();
appAnimator.animation = null;
- wtoken.inPendingTransaction = false;
- setTokenVisibilityLocked(wtoken, animLp, false, transit, false, voiceInteraction);
- wtoken.updateReportedVisibilityLocked();
- // Force the allDrawn flag, because we want to start
- // this guy's animations regardless of whether it's
- // gotten drawn.
- wtoken.allDrawn = true;
- wtoken.deferClearAllDrawn = false;
- // Ensure that apps that are mid-starting are also scheduled to have their
- // starting windows removed after the animation is complete
- if (wtoken.startingWindow != null && !wtoken.startingWindow.mExiting) {
- scheduleRemoveStartingWindowLocked(wtoken);
- }
- mAnimator.mAppWindowAnimating |= appAnimator.isAnimating();
+ }
+ wtoken.inPendingTransaction = false;
+ if (!setTokenVisibilityLocked(
+ wtoken, animLp, true, transit, false, voiceInteraction)){
+ // This token isn't going to be animating. Add it to the list of tokens to
+ // be notified of app transition complete since the notification will not be
+ // sent be the app window animator.
+ mNoAnimationNotifyOnTransitionFinished.add(wtoken.token);
+ }
+ wtoken.updateReportedVisibilityLocked();
+ wtoken.waitingToShow = false;
- if (animLp != null) {
- int layer = -1;
- for (int j = 0; j < wtoken.windows.size(); j++) {
- WindowState win = wtoken.windows.get(j);
- if (win.mWinAnimator.mAnimLayer > layer) {
- layer = win.mWinAnimator.mAnimLayer;
- }
- }
- if (topClosingApp == null || layer > topClosingLayer) {
- topClosingApp = wtoken;
- topClosingLayer = layer;
+ appAnimator.mAllAppWinAnimators.clear();
+ final int windowsCount = wtoken.allAppWindows.size();
+ for (int j = 0; j < windowsCount; j++) {
+ appAnimator.mAllAppWinAnimators.add(wtoken.allAppWindows.get(j).mWinAnimator);
+ }
+ mAnimator.mAnimating |= appAnimator.showAllWindowsLocked();
+ mAnimator.mAppWindowAnimating |= appAnimator.isAnimating();
+
+ int topOpeningLayer = 0;
+ if (animLp != null) {
+ int layer = -1;
+ for (int j = 0; j < wtoken.windows.size(); j++) {
+ WindowState win = wtoken.windows.get(j);
+ if (win.mWinAnimator.mAnimLayer > layer) {
+ layer = win.mWinAnimator.mAnimLayer;
}
}
+ if (topOpeningApp == null || layer > topOpeningLayer) {
+ topOpeningApp = wtoken;
+ topOpeningLayer = layer;
+ }
}
+ createThumbnailAppAnimator(transit, wtoken, topOpeningLayer, topClosingLayer);
+ }
- AppWindowToken topOpeningApp = null;
- appsCount = mOpeningApps.size();
- for (i = 0; i < appsCount; i++) {
- AppWindowToken wtoken = mOpeningApps.valueAt(i);
- final AppWindowAnimator appAnimator = wtoken.mAppAnimator;
- if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Now opening app" + wtoken);
+ AppWindowAnimator openingAppAnimator = (topOpeningApp == null) ? null :
+ topOpeningApp.mAppAnimator;
+ AppWindowAnimator closingAppAnimator = (topClosingApp == null) ? null :
+ topClosingApp.mAppAnimator;
- if (!appAnimator.usingTransferredAnimation) {
- appAnimator.clearThumbnail();
- appAnimator.animation = null;
- }
- wtoken.inPendingTransaction = false;
- if (!setTokenVisibilityLocked(
- wtoken, animLp, true, transit, false, voiceInteraction)){
- // This token isn't going to be animating. Add it to the list of tokens to
- // be notified of app transition complete since the notification will not be
- // sent be the app window animator.
- mNoAnimationNotifyOnTransitionFinished.add(wtoken.token);
- }
+ mAppTransition.goodToGo(openingAppAnimator, closingAppAnimator);
+ mAppTransition.postAnimationCallback();
+ mAppTransition.clear();
+
+ mOpeningApps.clear();
+ mClosingApps.clear();
+
+ // This has changed the visibility of windows, so perform
+ // a new layout to get them all up-to-date.
+ getDefaultDisplayContentLocked().layoutNeeded = true;
+
+ // TODO(multidisplay): IMEs are only supported on the default display.
+ if (windows == getDefaultWindowListLocked()
+ && !moveInputMethodWindowsIfNeededLocked(true)) {
+ assignLayersLocked(windows);
+ }
+ updateFocusedWindowLocked(UPDATE_FOCUS_PLACING_SURFACES, true /*updateInputWindows*/);
+ mFocusMayChange = false;
+ notifyActivityDrawnForKeyguard();
+ return WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT
+ | WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG;
+
+ }
+
+ private int maybeUpdateTransitToWallpaper(int transit, boolean openingAppHasWallpaper,
+ boolean closingAppHasWallpaper, WindowState lowerWallpaperTarget,
+ WindowState upperWallpaperTarget) {
+ // if wallpaper is animating in or out set oldWallpaper to null else to wallpaper
+ final WindowState wallpaperTarget = mWallpaperControllerLocked.getWallpaperTarget();
+ final WindowState oldWallpaper = mWallpaperControllerLocked.isWallpaperTargetAnimating()
+ ? null : wallpaperTarget;
+ if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
+ "New wallpaper target=" + wallpaperTarget
+ + ", oldWallpaper=" + oldWallpaper
+ + ", lower target=" + lowerWallpaperTarget
+ + ", upper target=" + upperWallpaperTarget);
+ mAnimateWallpaperWithTarget = false;
+ if (closingAppHasWallpaper && openingAppHasWallpaper) {
+ if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Wallpaper animation!");
+ switch (transit) {
+ case AppTransition.TRANSIT_ACTIVITY_OPEN:
+ case AppTransition.TRANSIT_TASK_OPEN:
+ case AppTransition.TRANSIT_TASK_TO_FRONT:
+ transit = AppTransition.TRANSIT_WALLPAPER_INTRA_OPEN;
+ break;
+ case AppTransition.TRANSIT_ACTIVITY_CLOSE:
+ case AppTransition.TRANSIT_TASK_CLOSE:
+ case AppTransition.TRANSIT_TASK_TO_BACK:
+ transit = AppTransition.TRANSIT_WALLPAPER_INTRA_CLOSE;
+ break;
+ }
+ if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
+ "New transit: " + AppTransition.appTransitionToString(transit));
+ } else if ((oldWallpaper != null) && !mOpeningApps.isEmpty()
+ && !mOpeningApps.contains(oldWallpaper.mAppToken)) {
+ // We are transitioning from an activity with
+ // a wallpaper to one without.
+ transit = AppTransition.TRANSIT_WALLPAPER_CLOSE;
+ if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
+ "New transit away from wallpaper: "
+ + AppTransition.appTransitionToString(transit));
+ } else if (wallpaperTarget != null && wallpaperTarget.isVisibleLw()) {
+ // We are transitioning from an activity without
+ // a wallpaper to now showing the wallpaper
+ transit = AppTransition.TRANSIT_WALLPAPER_OPEN;
+ if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
+ "New transit into wallpaper: "
+ + AppTransition.appTransitionToString(transit));
+ } else {
+ mAnimateWallpaperWithTarget = true;
+ }
+ return transit;
+ }
+
+ private void processApplicationsAnimatingInPlace(int transit) {
+ if (transit == AppTransition.TRANSIT_TASK_IN_PLACE) {
+ // Find the focused window
+ final WindowState win =
+ findFocusedWindowLocked(getDefaultDisplayContentLocked());
+ if (win != null) {
+ final AppWindowToken wtoken = win.mAppToken;
+ final AppWindowAnimator appAnimator = wtoken.mAppAnimator;
+ if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Now animating app in place " + wtoken);
+ appAnimator.clearThumbnail();
+ appAnimator.animation = null;
+ updateTokenInPlaceLocked(wtoken, transit);
wtoken.updateReportedVisibilityLocked();
- wtoken.waitingToShow = false;
appAnimator.mAllAppWinAnimators.clear();
- final int windowsCount = wtoken.allAppWindows.size();
- for (int j = 0; j < windowsCount; j++) {
+ final int N = wtoken.allAppWindows.size();
+ for (int j = 0; j < N; j++) {
appAnimator.mAllAppWinAnimators.add(wtoken.allAppWindows.get(j).mWinAnimator);
}
- mAnimator.mAnimating |= appAnimator.showAllWindowsLocked();
mAnimator.mAppWindowAnimating |= appAnimator.isAnimating();
+ mAnimator.mAnimating |= appAnimator.showAllWindowsLocked();
+ }
+ }
+ }
- int topOpeningLayer = 0;
- if (animLp != null) {
- int layer = -1;
- for (int j = 0; j < wtoken.windows.size(); j++) {
- WindowState win = wtoken.windows.get(j);
- if (win.mWinAnimator.mAnimLayer > layer) {
- layer = win.mWinAnimator.mAnimLayer;
- }
- }
- if (topOpeningApp == null || layer > topOpeningLayer) {
- topOpeningApp = wtoken;
- topOpeningLayer = layer;
- }
+ private boolean checkIfTransitionGoodToGo(int appsCount) {
+ if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
+ "Checking " + appsCount + " opening apps (frozen="
+ + mDisplayFrozen + " timeout="
+ + mAppTransition.isTimeout() + ")...");
+ if (!mAppTransition.isTimeout()) {
+ for (int i = 0; i < appsCount; i++) {
+ AppWindowToken wtoken = mOpeningApps.valueAt(i);
+ if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
+ "Check opening app=" + wtoken + ": allDrawn="
+ + wtoken.allDrawn + " startingDisplayed="
+ + wtoken.startingDisplayed + " startingMoved="
+ + wtoken.startingMoved);
+ if (!wtoken.allDrawn && !wtoken.startingDisplayed && !wtoken.startingMoved) {
+ return false;
}
- createThumbnailAppAnimator(transit, wtoken, topOpeningLayer, topClosingLayer);
}
- AppWindowAnimator openingAppAnimator = (topOpeningApp == null) ? null :
- topOpeningApp.mAppAnimator;
- AppWindowAnimator closingAppAnimator = (topClosingApp == null) ? null :
- topClosingApp.mAppAnimator;
-
- mAppTransition.goodToGo(openingAppAnimator, closingAppAnimator);
- mAppTransition.postAnimationCallback();
- mAppTransition.clear();
-
- mOpeningApps.clear();
- mClosingApps.clear();
-
- // This has changed the visibility of windows, so perform
- // a new layout to get them all up-to-date.
- changes |= WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT
- | WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG;
- getDefaultDisplayContentLocked().layoutNeeded = true;
-
- // TODO(multidisplay): IMEs are only supported on the default display.
- if (windows == getDefaultWindowListLocked()
- && !moveInputMethodWindowsIfNeededLocked(true)) {
- assignLayersLocked(windows);
- }
- updateFocusedWindowLocked(UPDATE_FOCUS_PLACING_SURFACES, true /*updateInputWindows*/);
- mFocusMayChange = false;
- notifyActivityDrawnForKeyguard();
+ // If the wallpaper is visible, we need to check it's ready too.
+ return !mWallpaperControllerLocked.isWallpaperVisible() ||
+ mWallpaperControllerLocked.wallpaperTransitionReady();
}
-
- return changes;
+ return true;
}
private void createThumbnailAppAnimator(int transit, AppWindowToken appToken,
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index b56b1f9cadc6..092a6d1ad348 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -80,8 +80,14 @@ final class WindowState implements WindowManagerPolicy.WindowState {
static final String TAG = "WindowState";
// The minimal size of a window within the usable area of the freeform stack.
- static final int MINIMUM_VISIBLE_WIDTH_IN_DP = 48;
- static final int MINIMUM_VISIBLE_HEIGHT_IN_DP = 32;
+ private static final int MINIMUM_VISIBLE_WIDTH_IN_DP = 48;
+ private static final int MINIMUM_VISIBLE_HEIGHT_IN_DP = 32;
+
+ // The thickness of a window resize handle outside the window bounds on the free form workspace
+ // to capture touch events in that area.
+ private static final int RESIZE_HANDLE_WIDTH_IN_DP = 10;
+
+ static final boolean BOUNDS_FOR_TOUCH = true;
final WindowManagerService mService;
final WindowManagerPolicy mPolicy;
@@ -541,9 +547,8 @@ final class WindowState implements WindowManagerPolicy.WindowState {
mHaveFrame = true;
final Task task = mAppToken != null ? getTask() : null;
- final boolean isFreeFormWorkspace = task != null && task.mStack != null &&
- task.mStack.mStackId == FREEFORM_WORKSPACE_STACK_ID;
final boolean nonFullscreenTask = task != null && !task.isFullscreen();
+ final boolean freeformWorkspace = inFreeformWorkspace();
if (nonFullscreenTask) {
task.getBounds(mContainingFrame);
final WindowState imeWin = mService.mInputMethodWindow;
@@ -553,7 +558,7 @@ final class WindowState implements WindowManagerPolicy.WindowState {
mContainingFrame.top -= mContainingFrame.bottom - cf.bottom;
}
- if (isFreeFormWorkspace) {
+ if (freeformWorkspace) {
// In free form mode we have only to set the rectangle if it wasn't set already. No
// need to intersect it with the (visible) "content frame" since it is allowed to
// be outside the visible desktop.
@@ -669,7 +674,7 @@ final class WindowState implements WindowManagerPolicy.WindowState {
// Make sure the content and visible frames are inside of the
// final window frame.
- if (isFreeFormWorkspace && !mFrame.isEmpty()) {
+ if (freeformWorkspace && !mFrame.isEmpty()) {
// Keep the frame out of the blocked system area, limit it in size to the content area
// and make sure that there is always a minimum visible so that the user can drag it
// into a usable area..
@@ -910,10 +915,22 @@ final class WindowState implements WindowManagerPolicy.WindowState {
return mDisplayContent.getHomeStack();
}
- void getTaskBounds(Rect bounds) {
+ /**
+ * Retrieves the bounds for a task.
+ * @param bounds The rect which gets the bounds.
+ * @param forTouch Pass in BOUNDS_FOR_TOUCH to get touch related bounds, otherwise visible
+ * bounds will be returned.
+ */
+ void getTaskBounds(Rect bounds, boolean forTouch) {
final Task task = getTask();
if (task != null) {
task.getBounds(bounds);
+ if (forTouch == BOUNDS_FOR_TOUCH) {
+ if (inFreeformWorkspace()) {
+ final int delta = calculatePixelFromDp(RESIZE_HANDLE_WIDTH_IN_DP);
+ bounds.inset(-delta, -delta);
+ }
+ }
return;
}
bounds.set(mFrame);
@@ -1612,6 +1629,12 @@ final class WindowState implements WindowManagerPolicy.WindowState {
}
}
+ private boolean inFreeformWorkspace() {
+ final Task task = getTask();
+ return task != null && task.mStack != null &&
+ task.mStack.mStackId == FREEFORM_WORKSPACE_STACK_ID;
+ }
+
private int calculatePixelFromDp(int dp) {
final Configuration serviceConfig = mService.mCurConfiguration;
// TODO(multidisplay): Update Dp to that of display stack is on.
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 7fc56ec6c294..471994a05696 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -4994,12 +4994,18 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
IPackageManager pm = AppGlobals.getPackageManager();
long id = Binder.clearCallingIdentity();
try {
- // Removing those that go from the managed profile to the primary user.
+ UserInfo parent = mUserManager.getProfileParent(callingUserId);
+ if (parent == null) {
+ Slog.e(LOG_TAG, "Cannot call clearCrossProfileIntentFilter if there is no "
+ + "parent");
+ return;
+ }
+ // Removing those that go from the managed profile to the parent.
pm.clearCrossProfileIntentFilters(callingUserId, who.getPackageName());
- // And those that go from the primary user to the managed profile.
+ // And those that go from the parent to the managed profile.
// If we want to support multiple managed profiles, we will have to only remove
// those that have callingUserId as their target.
- pm.clearCrossProfileIntentFilters(UserHandle.USER_OWNER, who.getPackageName());
+ pm.clearCrossProfileIntentFilters(parent.id, who.getPackageName());
} catch (RemoteException re) {
// Shouldn't happen
} finally {
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 263c5e9b3ce9..31f1d7fdc61d 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -358,6 +358,13 @@ public class CarrierConfigManager {
public static final String KEY_CDMA_DTMF_TONE_DELAY_INT = "cdma_dtmf_tone_delay_int";
/**
+ * Determines whether conference calls are supported by a carrier. When {@code true},
+ * conference calling is supported, {@code false otherwise}.
+ * @hide
+ */
+ public static final String KEY_SUPPORT_CONFERENCE_CALL_BOOL = "support_conference_call_bool";
+
+ /**
* If this is true, the SIM card (through Customer Service Profile EF file) will be able to
* prevent manual operator selection. If false, this SIM setting will be ignored and manual
* operator selection will always be available. See CPHS4_2.WW6, CPHS B.4.7.1 for more
@@ -457,6 +464,7 @@ public class CarrierConfigManager {
sDefaults.putBoolean(KEY_FORCE_HOME_NETWORK_BOOL, false);
sDefaults.putInt(KEY_IMS_DTMF_TONE_DELAY_INT, 0);
sDefaults.putInt(KEY_CDMA_DTMF_TONE_DELAY_INT, 100);
+ sDefaults.putBoolean(KEY_SUPPORT_CONFERENCE_CALL_BOOL, true);
// MMS defaults
sDefaults.putBoolean(KEY_MMS_ALIAS_ENABLED_BOOL, false);