Merge "Hide message / remote input references"
diff --git a/compat/api/current.txt b/compat/api/current.txt
index fabc4aa..37fdd22 100644
--- a/compat/api/current.txt
+++ b/compat/api/current.txt
@@ -1211,6 +1211,7 @@
method public E get(long, E);
method public int indexOfKey(long);
method public int indexOfValue(E);
+ method public boolean isEmpty();
method public long keyAt(int);
method public void put(long, E);
method public void remove(long);
@@ -1312,6 +1313,7 @@
method public E get(int, E);
method public int indexOfKey(int);
method public int indexOfValue(E);
+ method public boolean isEmpty();
method public int keyAt(int);
method public void put(int, E);
method public void remove(int);
diff --git a/compat/src/main/java/android/support/v13/view/DragAndDropPermissionsCompat.java b/compat/src/main/java/android/support/v13/view/DragAndDropPermissionsCompat.java
index 13ed203..5fe61da 100644
--- a/compat/src/main/java/android/support/v13/view/DragAndDropPermissionsCompat.java
+++ b/compat/src/main/java/android/support/v13/view/DragAndDropPermissionsCompat.java
@@ -20,57 +20,16 @@
import android.app.Activity;
import android.os.Build;
-import android.support.annotation.RequiresApi;
+import android.support.annotation.Nullable;
import android.support.annotation.RestrictTo;
import android.view.DragAndDropPermissions;
import android.view.DragEvent;
/**
- * Helper for accessing features in {@link android.view.DragAndDropPermissions}
- * introduced after API level 13 in a backwards compatible fashion.
+ * Helper for accessing features in {@link android.view.DragAndDropPermissions} a backwards
+ * compatible fashion.
*/
public final class DragAndDropPermissionsCompat {
-
- interface DragAndDropPermissionsCompatImpl {
- Object request(Activity activity, DragEvent dragEvent);
- void release(Object dragAndDropPermissions);
- }
-
- static class BaseDragAndDropPermissionsCompatImpl implements DragAndDropPermissionsCompatImpl {
- @Override
- public Object request(Activity activity, DragEvent dragEvent) {
- return null;
- }
-
- @Override
- public void release(Object dragAndDropPermissions) {
- // no-op
- }
- }
-
- @RequiresApi(24)
- static class Api24DragAndDropPermissionsCompatImpl
- extends BaseDragAndDropPermissionsCompatImpl {
- @Override
- public Object request(Activity activity, DragEvent dragEvent) {
- return activity.requestDragAndDropPermissions(dragEvent);
- }
-
- @Override
- public void release(Object dragAndDropPermissions) {
- ((DragAndDropPermissions) dragAndDropPermissions).release();
- }
- }
-
- private static DragAndDropPermissionsCompatImpl IMPL;
- static {
- if (Build.VERSION.SDK_INT >= 24) {
- IMPL = new Api24DragAndDropPermissionsCompatImpl();
- } else {
- IMPL = new BaseDragAndDropPermissionsCompatImpl();
- }
- }
-
private Object mDragAndDropPermissions;
private DragAndDropPermissionsCompat(Object dragAndDropPermissions) {
@@ -79,18 +38,24 @@
/** @hide */
@RestrictTo(LIBRARY_GROUP)
+ @Nullable
public static DragAndDropPermissionsCompat request(Activity activity, DragEvent dragEvent) {
- Object dragAndDropPermissions = IMPL.request(activity, dragEvent);
- if (dragAndDropPermissions != null) {
- return new DragAndDropPermissionsCompat(dragAndDropPermissions);
+ if (Build.VERSION.SDK_INT >= 24) {
+ DragAndDropPermissions dragAndDropPermissions =
+ activity.requestDragAndDropPermissions(dragEvent);
+ if (dragAndDropPermissions != null) {
+ return new DragAndDropPermissionsCompat(dragAndDropPermissions);
+ }
}
return null;
}
- /*
+ /**
* Revoke the permission grant explicitly.
*/
public void release() {
- IMPL.release(mDragAndDropPermissions);
+ if (Build.VERSION.SDK_INT >= 24) {
+ ((DragAndDropPermissions) mDragAndDropPermissions).release();
+ }
}
}
diff --git a/compat/src/main/java/android/support/v13/view/DragStartHelper.java b/compat/src/main/java/android/support/v13/view/DragStartHelper.java
index 85bc2f3..f8aed92 100644
--- a/compat/src/main/java/android/support/v13/view/DragStartHelper.java
+++ b/compat/src/main/java/android/support/v13/view/DragStartHelper.java
@@ -69,8 +69,8 @@
* </pre>
*/
public class DragStartHelper {
- final private View mView;
- final private OnDragStartListener mListener;
+ private final View mView;
+ private final OnDragStartListener mListener;
private int mLastTouchX, mLastTouchY;
private boolean mDragging;
diff --git a/compat/src/main/java/android/support/v13/view/inputmethod/EditorInfoCompat.java b/compat/src/main/java/android/support/v13/view/inputmethod/EditorInfoCompat.java
index 92743c2..309877d 100644
--- a/compat/src/main/java/android/support/v13/view/inputmethod/EditorInfoCompat.java
+++ b/compat/src/main/java/android/support/v13/view/inputmethod/EditorInfoCompat.java
@@ -16,7 +16,6 @@
package android.support.v13.view.inputmethod;
-import android.support.annotation.RequiresApi;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.NonNull;
@@ -24,8 +23,7 @@
import android.view.inputmethod.EditorInfo;
/**
- * Helper for accessing features in {@link EditorInfo} introduced after API level 13 in a backwards
- * compatible fashion.
+ * Helper for accessing features in {@link EditorInfo} in a backwards compatible fashion.
*/
public final class EditorInfoCompat {
@@ -69,63 +67,10 @@
*/
public static final int IME_FLAG_FORCE_ASCII = 0x80000000;
- private interface EditorInfoCompatImpl {
- void setContentMimeTypes(@NonNull EditorInfo editorInfo,
- @Nullable String[] contentMimeTypes);
- @NonNull
- String[] getContentMimeTypes(@NonNull EditorInfo editorInfo);
- }
-
private static final String[] EMPTY_STRING_ARRAY = new String[0];
- private static final class EditorInfoCompatBaseImpl implements EditorInfoCompatImpl {
- private static String CONTENT_MIME_TYPES_KEY =
- "android.support.v13.view.inputmethod.EditorInfoCompat.CONTENT_MIME_TYPES";
-
- @Override
- public void setContentMimeTypes(@NonNull EditorInfo editorInfo,
- @Nullable String[] contentMimeTypes) {
- if (editorInfo.extras == null) {
- editorInfo.extras = new Bundle();
- }
- editorInfo.extras.putStringArray(CONTENT_MIME_TYPES_KEY, contentMimeTypes);
- }
-
- @NonNull
- @Override
- public String[] getContentMimeTypes(@NonNull EditorInfo editorInfo) {
- if (editorInfo.extras == null) {
- return EMPTY_STRING_ARRAY;
- }
- String[] result = editorInfo.extras.getStringArray(CONTENT_MIME_TYPES_KEY);
- return result != null ? result : EMPTY_STRING_ARRAY;
- }
- }
-
- @RequiresApi(25)
- private static final class EditorInfoCompatApi25Impl implements EditorInfoCompatImpl {
- @Override
- public void setContentMimeTypes(@NonNull EditorInfo editorInfo,
- @Nullable String[] contentMimeTypes) {
- editorInfo.contentMimeTypes = contentMimeTypes;
- }
-
- @NonNull
- @Override
- public String[] getContentMimeTypes(@NonNull EditorInfo editorInfo) {
- final String[] result = editorInfo.contentMimeTypes;
- return result != null ? result : EMPTY_STRING_ARRAY;
- }
- }
-
- private static final EditorInfoCompatImpl IMPL;
- static {
- if (Build.VERSION.SDK_INT >= 25) {
- IMPL = new EditorInfoCompatApi25Impl();
- } else {
- IMPL = new EditorInfoCompatBaseImpl();
- }
- }
+ private static final String CONTENT_MIME_TYPES_KEY =
+ "android.support.v13.view.inputmethod.EditorInfoCompat.CONTENT_MIME_TYPES";
/**
* Sets MIME types that can be accepted by the target editor if the IME calls
@@ -140,7 +85,14 @@
*/
public static void setContentMimeTypes(@NonNull EditorInfo editorInfo,
@Nullable String[] contentMimeTypes) {
- IMPL.setContentMimeTypes(editorInfo, contentMimeTypes);
+ if (Build.VERSION.SDK_INT >= 25) {
+ editorInfo.contentMimeTypes = contentMimeTypes;
+ } else {
+ if (editorInfo.extras == null) {
+ editorInfo.extras = new Bundle();
+ }
+ editorInfo.extras.putStringArray(CONTENT_MIME_TYPES_KEY, contentMimeTypes);
+ }
}
/**
@@ -155,7 +107,16 @@
*/
@NonNull
public static String[] getContentMimeTypes(EditorInfo editorInfo) {
- return IMPL.getContentMimeTypes(editorInfo);
+ if (Build.VERSION.SDK_INT >= 25) {
+ final String[] result = editorInfo.contentMimeTypes;
+ return result != null ? result : EMPTY_STRING_ARRAY;
+ } else {
+ if (editorInfo.extras == null) {
+ return EMPTY_STRING_ARRAY;
+ }
+ String[] result = editorInfo.extras.getStringArray(CONTENT_MIME_TYPES_KEY);
+ return result != null ? result : EMPTY_STRING_ARRAY;
+ }
}
}
diff --git a/compat/src/main/java/android/support/v13/view/inputmethod/InputConnectionCompat.java b/compat/src/main/java/android/support/v13/view/inputmethod/InputConnectionCompat.java
index 5999575..d77389b 100644
--- a/compat/src/main/java/android/support/v13/view/inputmethod/InputConnectionCompat.java
+++ b/compat/src/main/java/android/support/v13/view/inputmethod/InputConnectionCompat.java
@@ -16,7 +16,6 @@
package android.support.v13.view.inputmethod;
-import android.support.annotation.RequiresApi;
import android.content.ClipDescription;
import android.net.Uri;
import android.os.Build;
@@ -36,138 +35,50 @@
*/
public final class InputConnectionCompat {
- private interface InputConnectionCompatImpl {
- boolean commitContent(@NonNull InputConnection inputConnection,
- @NonNull InputContentInfoCompat inputContentInfo, int flags, @Nullable Bundle opts);
+ private static final String COMMIT_CONTENT_ACTION =
+ "android.support.v13.view.inputmethod.InputConnectionCompat.COMMIT_CONTENT";
+ private static final String COMMIT_CONTENT_CONTENT_URI_KEY =
+ "android.support.v13.view.inputmethod.InputConnectionCompat.CONTENT_URI";
+ private static final String COMMIT_CONTENT_DESCRIPTION_KEY =
+ "android.support.v13.view.inputmethod.InputConnectionCompat.CONTENT_DESCRIPTION";
+ private static final String COMMIT_CONTENT_LINK_URI_KEY =
+ "android.support.v13.view.inputmethod.InputConnectionCompat.CONTENT_LINK_URI";
+ private static final String COMMIT_CONTENT_OPTS_KEY =
+ "android.support.v13.view.inputmethod.InputConnectionCompat.CONTENT_OPTS";
+ private static final String COMMIT_CONTENT_FLAGS_KEY =
+ "android.support.v13.view.inputmethod.InputConnectionCompat.CONTENT_FLAGS";
+ private static final String COMMIT_CONTENT_RESULT_RECEIVER =
+ "android.support.v13.view.inputmethod.InputConnectionCompat.CONTENT_RESULT_RECEIVER";
- @NonNull
- InputConnection createWrapper(@NonNull InputConnection ic,
- @NonNull EditorInfo editorInfo, @NonNull OnCommitContentListener callback);
- }
-
- static final class InputContentInfoCompatBaseImpl implements InputConnectionCompatImpl {
-
- private static String COMMIT_CONTENT_ACTION =
- "android.support.v13.view.inputmethod.InputConnectionCompat.COMMIT_CONTENT";
- private static String COMMIT_CONTENT_CONTENT_URI_KEY =
- "android.support.v13.view.inputmethod.InputConnectionCompat.CONTENT_URI";
- private static String COMMIT_CONTENT_DESCRIPTION_KEY =
- "android.support.v13.view.inputmethod.InputConnectionCompat.CONTENT_DESCRIPTION";
- private static String COMMIT_CONTENT_LINK_URI_KEY =
- "android.support.v13.view.inputmethod.InputConnectionCompat.CONTENT_LINK_URI";
- private static String COMMIT_CONTENT_OPTS_KEY =
- "android.support.v13.view.inputmethod.InputConnectionCompat.CONTENT_OPTS";
- private static String COMMIT_CONTENT_FLAGS_KEY =
- "android.support.v13.view.inputmethod.InputConnectionCompat.CONTENT_FLAGS";
- private static String COMMIT_CONTENT_RESULT_RECEIVER =
- "android.support.v13.view.inputmethod.InputConnectionCompat.CONTENT_RESULT_RECEIVER";
-
- @Override
- public boolean commitContent(@NonNull InputConnection inputConnection,
- @NonNull InputContentInfoCompat inputContentInfo, int flags,
- @Nullable Bundle opts) {
- final Bundle params = new Bundle();
- params.putParcelable(COMMIT_CONTENT_CONTENT_URI_KEY, inputContentInfo.getContentUri());
- params.putParcelable(COMMIT_CONTENT_DESCRIPTION_KEY, inputContentInfo.getDescription());
- params.putParcelable(COMMIT_CONTENT_LINK_URI_KEY, inputContentInfo.getLinkUri());
- params.putInt(COMMIT_CONTENT_FLAGS_KEY, flags);
- params.putParcelable(COMMIT_CONTENT_OPTS_KEY, opts);
- // TODO: Support COMMIT_CONTENT_RESULT_RECEIVER.
- return inputConnection.performPrivateCommand(COMMIT_CONTENT_ACTION, params);
+ static boolean handlePerformPrivateCommand(
+ @Nullable String action,
+ @NonNull Bundle data,
+ @NonNull OnCommitContentListener onCommitContentListener) {
+ if (!TextUtils.equals(COMMIT_CONTENT_ACTION, action)) {
+ return false;
}
-
- @NonNull
- @Override
- public InputConnection createWrapper(@NonNull InputConnection ic,
- @NonNull EditorInfo editorInfo,
- @NonNull OnCommitContentListener onCommitContentListener) {
- String[] contentMimeTypes = EditorInfoCompat.getContentMimeTypes(editorInfo);
- if (contentMimeTypes.length == 0) {
- return ic;
+ if (data == null) {
+ return false;
+ }
+ ResultReceiver resultReceiver = null;
+ boolean result = false;
+ try {
+ resultReceiver = data.getParcelable(COMMIT_CONTENT_RESULT_RECEIVER);
+ final Uri contentUri = data.getParcelable(COMMIT_CONTENT_CONTENT_URI_KEY);
+ final ClipDescription description = data.getParcelable(
+ COMMIT_CONTENT_DESCRIPTION_KEY);
+ final Uri linkUri = data.getParcelable(COMMIT_CONTENT_LINK_URI_KEY);
+ final int flags = data.getInt(COMMIT_CONTENT_FLAGS_KEY);
+ final Bundle opts = data.getParcelable(COMMIT_CONTENT_OPTS_KEY);
+ final InputContentInfoCompat inputContentInfo =
+ new InputContentInfoCompat(contentUri, description, linkUri);
+ result = onCommitContentListener.onCommitContent(inputContentInfo, flags, opts);
+ } finally {
+ if (resultReceiver != null) {
+ resultReceiver.send(result ? 1 : 0, null);
}
- final OnCommitContentListener listener = onCommitContentListener;
- return new InputConnectionWrapper(ic, false /* mutable */) {
- @Override
- public boolean performPrivateCommand(String action, Bundle data) {
- if (InputContentInfoCompatBaseImpl.handlePerformPrivateCommand(action, data,
- listener)) {
- return true;
- }
- return super.performPrivateCommand(action, data);
- }
- };
}
-
- static boolean handlePerformPrivateCommand(
- @Nullable String action,
- @NonNull Bundle data,
- @NonNull OnCommitContentListener onCommitContentListener) {
- if (!TextUtils.equals(COMMIT_CONTENT_ACTION, action)) {
- return false;
- }
- if (data == null) {
- return false;
- }
- ResultReceiver resultReceiver = null;
- boolean result = false;
- try {
- resultReceiver = data.getParcelable(COMMIT_CONTENT_RESULT_RECEIVER);
- final Uri contentUri = data.getParcelable(COMMIT_CONTENT_CONTENT_URI_KEY);
- final ClipDescription description = data.getParcelable(
- COMMIT_CONTENT_DESCRIPTION_KEY);
- final Uri linkUri = data.getParcelable(COMMIT_CONTENT_LINK_URI_KEY);
- final int flags = data.getInt(COMMIT_CONTENT_FLAGS_KEY);
- final Bundle opts = data.getParcelable(COMMIT_CONTENT_OPTS_KEY);
- final InputContentInfoCompat inputContentInfo =
- new InputContentInfoCompat(contentUri, description, linkUri);
- result = onCommitContentListener.onCommitContent(inputContentInfo, flags, opts);
- } finally {
- if (resultReceiver != null) {
- resultReceiver.send(result ? 1 : 0, null);
- }
- }
- return result;
- }
- }
-
- @RequiresApi(25)
- private static final class InputContentInfoCompatApi25Impl
- implements InputConnectionCompatImpl {
- @Override
- public boolean commitContent(@NonNull InputConnection inputConnection,
- @NonNull InputContentInfoCompat inputContentInfo, int flags,
- @Nullable Bundle opts) {
- return inputConnection.commitContent((InputContentInfo) inputContentInfo.unwrap(),
- flags, opts);
- }
-
- @Nullable
- @Override
- public InputConnection createWrapper(
- @Nullable InputConnection inputConnection, @NonNull EditorInfo editorInfo,
- @Nullable OnCommitContentListener onCommitContentListener) {
- final OnCommitContentListener listener = onCommitContentListener;
- return new InputConnectionWrapper(inputConnection, false /* mutable */) {
- @Override
- public boolean commitContent(InputContentInfo inputContentInfo, int flags,
- Bundle opts) {
- if (listener.onCommitContent(InputContentInfoCompat.wrap(inputContentInfo),
- flags, opts)) {
- return true;
- }
- return super.commitContent(inputContentInfo, flags, opts);
- }
- };
- }
- }
-
- private static final InputConnectionCompatImpl IMPL;
- static {
- if (Build.VERSION.SDK_INT >= 25) {
- IMPL = new InputContentInfoCompatApi25Impl();
- } else {
- IMPL = new InputContentInfoCompatBaseImpl();
- }
+ return result;
}
/**
@@ -196,7 +107,19 @@
return false;
}
- return IMPL.commitContent(inputConnection, inputContentInfo, flags, opts);
+ if (Build.VERSION.SDK_INT >= 25) {
+ return inputConnection.commitContent(
+ (InputContentInfo) inputContentInfo.unwrap(), flags, opts);
+ } else {
+ final Bundle params = new Bundle();
+ params.putParcelable(COMMIT_CONTENT_CONTENT_URI_KEY, inputContentInfo.getContentUri());
+ params.putParcelable(COMMIT_CONTENT_DESCRIPTION_KEY, inputContentInfo.getDescription());
+ params.putParcelable(COMMIT_CONTENT_LINK_URI_KEY, inputContentInfo.getLinkUri());
+ params.putInt(COMMIT_CONTENT_FLAGS_KEY, flags);
+ params.putParcelable(COMMIT_CONTENT_OPTS_KEY, opts);
+ // TODO: Support COMMIT_CONTENT_RESULT_RECEIVER.
+ return inputConnection.performPrivateCommand(COMMIT_CONTENT_ACTION, params);
+ }
}
/**
@@ -276,7 +199,35 @@
if (onCommitContentListener == null) {
throw new IllegalArgumentException("onCommitContentListener must be non-null");
}
- return IMPL.createWrapper(inputConnection, editorInfo, onCommitContentListener);
+ if (Build.VERSION.SDK_INT >= 25) {
+ final OnCommitContentListener listener = onCommitContentListener;
+ return new InputConnectionWrapper(inputConnection, false /* mutable */) {
+ @Override
+ public boolean commitContent(InputContentInfo inputContentInfo, int flags,
+ Bundle opts) {
+ if (listener.onCommitContent(InputContentInfoCompat.wrap(inputContentInfo),
+ flags, opts)) {
+ return true;
+ }
+ return super.commitContent(inputContentInfo, flags, opts);
+ }
+ };
+ } else {
+ String[] contentMimeTypes = EditorInfoCompat.getContentMimeTypes(editorInfo);
+ if (contentMimeTypes.length == 0) {
+ return inputConnection;
+ }
+ final OnCommitContentListener listener = onCommitContentListener;
+ return new InputConnectionWrapper(inputConnection, false /* mutable */) {
+ @Override
+ public boolean performPrivateCommand(String action, Bundle data) {
+ if (InputConnectionCompat.handlePerformPrivateCommand(action, data, listener)) {
+ return true;
+ }
+ return super.performPrivateCommand(action, data);
+ }
+ };
+ }
}
}
diff --git a/compat/src/main/java/android/support/v4/app/ActivityCompat.java b/compat/src/main/java/android/support/v4/app/ActivityCompat.java
index 9d15be1..32355e7 100644
--- a/compat/src/main/java/android/support/v4/app/ActivityCompat.java
+++ b/compat/src/main/java/android/support/v4/app/ActivityCompat.java
@@ -538,6 +538,7 @@
* URIs. {@code null} if no content URIs are associated with the event or if permissions could
* not be granted.
*/
+ @Nullable
public static DragAndDropPermissionsCompat requestDragAndDropPermissions(Activity activity,
DragEvent dragEvent) {
return DragAndDropPermissionsCompat.request(activity, dragEvent);
diff --git a/compat/src/main/java/android/support/v4/util/LongSparseArray.java b/compat/src/main/java/android/support/v4/util/LongSparseArray.java
index 25b6bb9..febb5d5 100644
--- a/compat/src/main/java/android/support/v4/util/LongSparseArray.java
+++ b/compat/src/main/java/android/support/v4/util/LongSparseArray.java
@@ -235,6 +235,14 @@
}
/**
+ * Return true if size() is 0.
+ * @return true if size() is 0.
+ */
+ public boolean isEmpty() {
+ return size() == 0;
+ }
+
+ /**
* Given an index in the range <code>0...size()-1</code>, returns
* the key from the <code>index</code>th key-value mapping that this
* LongSparseArray stores.
diff --git a/compat/src/main/java/android/support/v4/util/SparseArrayCompat.java b/compat/src/main/java/android/support/v4/util/SparseArrayCompat.java
index aedc4ad..5238cf0 100644
--- a/compat/src/main/java/android/support/v4/util/SparseArrayCompat.java
+++ b/compat/src/main/java/android/support/v4/util/SparseArrayCompat.java
@@ -228,6 +228,14 @@
}
/**
+ * Return true if size() is 0.
+ * @return true if size() is 0.
+ */
+ public boolean isEmpty() {
+ return size() == 0;
+ }
+
+ /**
* Given an index in the range <code>0...size()-1</code>, returns
* the key from the <code>index</code>th key-value mapping that this
* SparseArray stores.
diff --git a/compat/tests/java/android/support/v4/util/LongSparseArrayTest.java b/compat/tests/java/android/support/v4/util/LongSparseArrayTest.java
new file mode 100644
index 0000000..663ea48
--- /dev/null
+++ b/compat/tests/java/android/support/v4/util/LongSparseArrayTest.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2018 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 android.support.v4.util;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class LongSparseArrayTest {
+ @Test
+ public void isEmpty() throws Exception {
+ LongSparseArray<String> LongSparseArray = new LongSparseArray<>();
+ assertTrue(LongSparseArray.isEmpty()); // Newly created LongSparseArray should be empty
+
+ // Adding elements should change state from empty to not empty.
+ for (long i = 0L; i < 5L; i++) {
+ LongSparseArray.put(i, Long.toString(i));
+ assertFalse(LongSparseArray.isEmpty());
+ }
+ LongSparseArray.clear();
+ assertTrue(LongSparseArray.isEmpty()); // A cleared LongSparseArray should be empty.
+
+
+ long key1 = 1L, key2 = 2L;
+ String value1 = "some value", value2 = "some other value";
+ LongSparseArray.append(key1, value1);
+ assertFalse(LongSparseArray.isEmpty()); // has 1 element.
+ LongSparseArray.append(key2, value2);
+ assertFalse(LongSparseArray.isEmpty()); // has 2 elements.
+ assertFalse(LongSparseArray.isEmpty()); // consecutive calls should be OK.
+
+ LongSparseArray.remove(key1);
+ assertFalse(LongSparseArray.isEmpty()); // has 1 element.
+ LongSparseArray.remove(key2);
+ assertTrue(LongSparseArray.isEmpty());
+ }
+
+}
diff --git a/compat/tests/java/android/support/v4/util/SparseArrayCompatTest.java b/compat/tests/java/android/support/v4/util/SparseArrayCompatTest.java
new file mode 100644
index 0000000..122c89b
--- /dev/null
+++ b/compat/tests/java/android/support/v4/util/SparseArrayCompatTest.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2018 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 android.support.v4.util;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class SparseArrayCompatTest {
+ @Test
+ public void isEmpty() throws Exception {
+ SparseArrayCompat<String> sparseArrayCompat = new SparseArrayCompat<>();
+ assertTrue(sparseArrayCompat.isEmpty()); // Newly created SparseArrayCompat should be empty
+
+ // Adding elements should change state from empty to not empty.
+ for (int i = 0; i < 5; i++) {
+ sparseArrayCompat.put(i, Integer.toString(i));
+ assertFalse(sparseArrayCompat.isEmpty());
+ }
+ sparseArrayCompat.clear();
+ assertTrue(sparseArrayCompat.isEmpty()); // A cleared SparseArrayCompat should be empty.
+
+
+ int key1 = 1, key2 = 2;
+ String value1 = "some value", value2 = "some other value";
+ sparseArrayCompat.append(key1, value1);
+ assertFalse(sparseArrayCompat.isEmpty()); // has 1 element.
+ sparseArrayCompat.append(key2, value2);
+ assertFalse(sparseArrayCompat.isEmpty()); // has 2 elements.
+ assertFalse(sparseArrayCompat.isEmpty()); // consecutive calls should be OK.
+
+ sparseArrayCompat.remove(key1);
+ assertFalse(sparseArrayCompat.isEmpty()); // has 1 element.
+ sparseArrayCompat.remove(key2);
+ assertTrue(sparseArrayCompat.isEmpty());
+ }
+}
diff --git a/core-utils/java/android/support/v4/content/WakefulBroadcastReceiver.java b/core-utils/java/android/support/v4/content/WakefulBroadcastReceiver.java
index 8ec3eee..78555aa 100644
--- a/core-utils/java/android/support/v4/content/WakefulBroadcastReceiver.java
+++ b/core-utils/java/android/support/v4/content/WakefulBroadcastReceiver.java
@@ -34,6 +34,9 @@
* for you; you must request the {@link android.Manifest.permission#WAKE_LOCK}
* permission to use it.</p>
*
+ * <p>Wakelocks held by this class are reported to tools as
+ * {@code "androidx.core:wake:<component-name>"}.</p>
+ *
* <h3>Example</h3>
*
* <p>A {@link WakefulBroadcastReceiver} uses the method
@@ -103,7 +106,7 @@
PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
- "wake:" + comp.flattenToShortString());
+ "androidx.core:wake:" + comp.flattenToShortString());
wl.setReferenceCounted(false);
wl.acquire(60 * 1000);
sActiveWakeLocks.put(id, wl);
diff --git a/fragment/src/main/java/android/support/v4/app/Fragment.java b/fragment/src/main/java/android/support/v4/app/Fragment.java
index 5b560cd..ce9bc4b 100644
--- a/fragment/src/main/java/android/support/v4/app/Fragment.java
+++ b/fragment/src/main/java/android/support/v4/app/Fragment.java
@@ -575,7 +575,6 @@
/**
* Return the {@link Context} this fragment is currently associated with.
*/
- @Nullable
public Context getContext() {
return mHost == null ? null : mHost.getContext();
}
@@ -585,7 +584,6 @@
* May return {@code null} if the fragment is associated with a {@link Context}
* instead.
*/
- @Nullable
final public FragmentActivity getActivity() {
return mHost == null ? null : (FragmentActivity) mHost.getActivity();
}
@@ -594,7 +592,6 @@
* Return the host object of this fragment. May return {@code null} if the fragment
* isn't currently being hosted.
*/
- @Nullable
final public Object getHost() {
return mHost == null ? null : mHost.onGetHost();
}
@@ -655,7 +652,6 @@
* <p>If this Fragment is a child of another Fragment, the FragmentManager
* returned here will be the parent's {@link #getChildFragmentManager()}.
*/
- @Nullable
final public FragmentManager getFragmentManager() {
return mFragmentManager;
}
diff --git a/graphics/drawable/animated/src/main/java/android/support/graphics/drawable/AnimatorInflaterCompat.java b/graphics/drawable/animated/src/main/java/android/support/graphics/drawable/AnimatorInflaterCompat.java
index cfededb..da522f6 100644
--- a/graphics/drawable/animated/src/main/java/android/support/graphics/drawable/AnimatorInflaterCompat.java
+++ b/graphics/drawable/animated/src/main/java/android/support/graphics/drawable/AnimatorInflaterCompat.java
@@ -463,7 +463,6 @@
// the previously sampled contours' total length.
for (int i = 0; i < numPoints; ++i) {
pathMeasure.getPosTan(currentDistance, position, null);
- pathMeasure.getPosTan(currentDistance, position, null);
mX[i] = position[0];
mY[i] = position[1];
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/parser/SqlParser.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/parser/SqlParser.kt
index c5c5f17..0bd2f49 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/parser/SqlParser.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/parser/SqlParser.kt
@@ -214,7 +214,7 @@
return when (this) {
TEXT -> listOf(env.elementUtils.getTypeElement("java.lang.String").asType())
INTEGER -> withBoxedTypes(env, TypeKind.INT, TypeKind.BYTE, TypeKind.CHAR,
- TypeKind.BOOLEAN, TypeKind.LONG, TypeKind.SHORT)
+ TypeKind.LONG, TypeKind.SHORT)
REAL -> withBoxedTypes(env, TypeKind.DOUBLE, TypeKind.FLOAT)
BLOB -> listOf(typeUtils.getArrayType(
typeUtils.getPrimitiveType(TypeKind.BYTE)))
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/TypeAdapterStore.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/TypeAdapterStore.kt
index 7abad86..62a24ad 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/TypeAdapterStore.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/TypeAdapterStore.kt
@@ -160,7 +160,11 @@
}
val targetTypes = targetTypeMirrorsFor(affinity)
val binder = findTypeConverter(input, targetTypes) ?: return null
- return CompositeAdapter(input, getAllColumnAdapters(binder.to).first(), binder, null)
+ // columnAdapter should not be null but we are receiving errors on crash in `first()` so
+ // this safeguard allows us to dispatch the real problem to the user (e.g. why we couldn't
+ // find the right adapter)
+ val columnAdapter = getAllColumnAdapters(binder.to).firstOrNull() ?: return null
+ return CompositeAdapter(input, columnAdapter, binder, null)
}
/**
diff --git a/room/integration-tests/testapp/src/androidTest/java/android/arch/persistence/room/integration/testapp/dao/UserDao.java b/room/integration-tests/testapp/src/androidTest/java/android/arch/persistence/room/integration/testapp/dao/UserDao.java
index 82a3583..7cb8b60 100644
--- a/room/integration-tests/testapp/src/androidTest/java/android/arch/persistence/room/integration/testapp/dao/UserDao.java
+++ b/room/integration-tests/testapp/src/androidTest/java/android/arch/persistence/room/integration/testapp/dao/UserDao.java
@@ -164,6 +164,12 @@
@Query("SELECT COUNT(*) from user")
public abstract int count();
+ @Query("SELECT mAdmin from User where mId = :uid")
+ public abstract boolean isAdmin(int uid);
+
+ @Query("SELECT mAdmin from User where mId = :uid")
+ public abstract LiveData<Boolean> isAdminLiveData(int uid);
+
public void insertBothByRunnable(final User a, final User b) {
mDatabase.runInTransaction(new Runnable() {
@Override
diff --git a/room/integration-tests/testapp/src/androidTest/java/android/arch/persistence/room/integration/testapp/test/LiveDataQueryTest.java b/room/integration-tests/testapp/src/androidTest/java/android/arch/persistence/room/integration/testapp/test/LiveDataQueryTest.java
index d78411f..d073598 100644
--- a/room/integration-tests/testapp/src/androidTest/java/android/arch/persistence/room/integration/testapp/test/LiveDataQueryTest.java
+++ b/room/integration-tests/testapp/src/androidTest/java/android/arch/persistence/room/integration/testapp/test/LiveDataQueryTest.java
@@ -315,6 +315,24 @@
assertThat(weakLiveData.get(), nullValue());
}
+ @Test
+ public void booleanLiveData() throws ExecutionException, InterruptedException,
+ TimeoutException {
+ User user = TestUtil.createUser(3);
+ user.setAdmin(false);
+ LiveData<Boolean> adminLiveData = mUserDao.isAdminLiveData(3);
+ final TestLifecycleOwner lifecycleOwner = new TestLifecycleOwner();
+ lifecycleOwner.handleEvent(Lifecycle.Event.ON_START);
+ final TestObserver<Boolean> observer = new TestObserver<>();
+ observe(adminLiveData, lifecycleOwner, observer);
+ assertThat(observer.get(), is(nullValue()));
+ mUserDao.insert(user);
+ assertThat(observer.get(), is(false));
+ user.setAdmin(true);
+ mUserDao.insertOrReplace(user);
+ assertThat(observer.get(), is(true));
+ }
+
private void observe(final LiveData liveData, final LifecycleOwner provider,
final Observer observer) throws ExecutionException, InterruptedException {
FutureTask<Void> futureTask = new FutureTask<>(new Callable<Void>() {
diff --git a/room/integration-tests/testapp/src/androidTest/java/android/arch/persistence/room/integration/testapp/test/SimpleEntityReadWriteTest.java b/room/integration-tests/testapp/src/androidTest/java/android/arch/persistence/room/integration/testapp/test/SimpleEntityReadWriteTest.java
index de45ebb..4ca81ad 100644
--- a/room/integration-tests/testapp/src/androidTest/java/android/arch/persistence/room/integration/testapp/test/SimpleEntityReadWriteTest.java
+++ b/room/integration-tests/testapp/src/androidTest/java/android/arch/persistence/room/integration/testapp/test/SimpleEntityReadWriteTest.java
@@ -267,6 +267,18 @@
}
@Test
+ public void returnBoolean() {
+ User user1 = TestUtil.createUser(1);
+ User user2 = TestUtil.createUser(2);
+ user1.setAdmin(true);
+ user2.setAdmin(false);
+ mUserDao.insert(user1);
+ mUserDao.insert(user2);
+ assertThat(mUserDao.isAdmin(1), is(true));
+ assertThat(mUserDao.isAdmin(2), is(false));
+ }
+
+ @Test
public void findByCollateNoCase() {
User user = TestUtil.createUser(3);
user.setCustomField("abc");
diff --git a/room/runtime/src/androidTest/java/android/arch/persistence/room/migration/TableInfoTest.java b/room/runtime/src/androidTest/java/android/arch/persistence/room/migration/TableInfoTest.java
index d88c02f..0eb35f6 100644
--- a/room/runtime/src/androidTest/java/android/arch/persistence/room/migration/TableInfoTest.java
+++ b/room/runtime/src/androidTest/java/android/arch/persistence/room/migration/TableInfoTest.java
@@ -31,6 +31,7 @@
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
+import android.util.Pair;
import org.junit.After;
import org.junit.Test;
@@ -41,6 +42,7 @@
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -209,6 +211,28 @@
));
}
+ @Test
+ public void compatColumnTypes() {
+ // see:https://www.sqlite.org/datatype3.html 3.1
+ List<Pair<String, String>> testCases = Arrays.asList(
+ new Pair<>("TINYINT", "integer"),
+ new Pair<>("VARCHAR", "text"),
+ new Pair<>("DOUBLE", "real"),
+ new Pair<>("BOOLEAN", "numeric"),
+ new Pair<>("FLOATING POINT", "integer")
+ );
+ for (Pair<String, String> testCase : testCases) {
+ mDb = createDatabase(
+ "CREATE TABLE foo (id INTEGER PRIMARY KEY AUTOINCREMENT,"
+ + "name " + testCase.first + ")");
+ TableInfo info = TableInfo.read(mDb, "foo");
+ assertThat(info, is(new TableInfo("foo",
+ toMap(new TableInfo.Column("id", "INTEGER", false, 1),
+ new TableInfo.Column("name", testCase.second, false, 0)),
+ Collections.<TableInfo.ForeignKey>emptySet())));
+ }
+ }
+
private static Map<String, TableInfo.Column> toMap(TableInfo.Column... columns) {
Map<String, TableInfo.Column> result = new HashMap<>();
for (TableInfo.Column column : columns) {
diff --git a/room/runtime/src/main/java/android/arch/persistence/room/util/TableInfo.java b/room/runtime/src/main/java/android/arch/persistence/room/util/TableInfo.java
index a115147..19d9853 100644
--- a/room/runtime/src/main/java/android/arch/persistence/room/util/TableInfo.java
+++ b/room/runtime/src/main/java/android/arch/persistence/room/util/TableInfo.java
@@ -17,6 +17,7 @@
package android.arch.persistence.room.util;
import android.arch.persistence.db.SupportSQLiteDatabase;
+import android.arch.persistence.room.ColumnInfo;
import android.database.Cursor;
import android.os.Build;
import android.support.annotation.NonNull;
@@ -28,6 +29,7 @@
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
+import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
@@ -44,7 +46,8 @@
* @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
-@SuppressWarnings({"WeakerAccess", "unused", "TryFinallyCanBeTryWithResources"})
+@SuppressWarnings({"WeakerAccess", "unused", "TryFinallyCanBeTryWithResources",
+ "SimplifiableIfStatement"})
// if you change this class, you must change TableInfoWriter.kt
public class TableInfo {
/**
@@ -313,6 +316,14 @@
*/
public final String type;
/**
+ * The column type after it is normalized to one of the basic types according to
+ * https://www.sqlite.org/datatype3.html Section 3.1.
+ * <p>
+ * This is the value Room uses for equality check.
+ */
+ @ColumnInfo.SQLiteTypeAffinity
+ public final int affinity;
+ /**
* Whether or not the column can be NULL.
*/
public final boolean notNull;
@@ -337,6 +348,40 @@
this.type = type;
this.notNull = notNull;
this.primaryKeyPosition = primaryKeyPosition;
+ this.affinity = findAffinity(type);
+ }
+
+ /**
+ * Implements https://www.sqlite.org/datatype3.html section 3.1
+ *
+ * @param type The type that was given to the sqlite
+ * @return The normalized type which is one of the 5 known affinities
+ */
+ @ColumnInfo.SQLiteTypeAffinity
+ private static int findAffinity(@Nullable String type) {
+ if (type == null) {
+ return ColumnInfo.BLOB;
+ }
+ String uppercaseType = type.toUpperCase(Locale.US);
+ if (uppercaseType.contains("INT")) {
+ return ColumnInfo.INTEGER;
+ }
+ if (uppercaseType.contains("CHAR")
+ || uppercaseType.contains("CLOB")
+ || uppercaseType.contains("TEXT")) {
+ return ColumnInfo.TEXT;
+ }
+ if (uppercaseType.contains("BLOB")) {
+ return ColumnInfo.BLOB;
+ }
+ if (uppercaseType.contains("REAL")
+ || uppercaseType.contains("FLOA")
+ || uppercaseType.contains("DOUB")) {
+ return ColumnInfo.REAL;
+ }
+ // sqlite returns NUMERIC here but it is like a catch all. We already
+ // have UNDEFINED so it is better to use UNDEFINED for consistency.
+ return ColumnInfo.UNDEFINED;
}
@Override
@@ -354,7 +399,7 @@
if (!name.equals(column.name)) return false;
//noinspection SimplifiableIfStatement
if (notNull != column.notNull) return false;
- return type != null ? type.equalsIgnoreCase(column.type) : column.type == null;
+ return affinity == column.affinity;
}
/**
@@ -369,7 +414,7 @@
@Override
public int hashCode() {
int result = name.hashCode();
- result = 31 * result + (type != null ? type.hashCode() : 0);
+ result = 31 * result + affinity;
result = 31 * result + (notNull ? 1231 : 1237);
result = 31 * result + primaryKeyPosition;
return result;
@@ -380,6 +425,7 @@
return "Column{"
+ "name='" + name + '\''
+ ", type='" + type + '\''
+ + ", affinity='" + affinity + '\''
+ ", notNull=" + notNull
+ ", primaryKeyPosition=" + primaryKeyPosition
+ '}';
@@ -472,7 +518,7 @@
}
@Override
- public int compareTo(ForeignKeyWithSequence o) {
+ public int compareTo(@NonNull ForeignKeyWithSequence o) {
final int idCmp = mId - o.mId;
if (idCmp == 0) {
return mSequence - o.mSequence;
diff --git a/slices/core/src/main/java/androidx/app/slice/core/SliceHints.java b/slices/core/src/main/java/androidx/app/slice/core/SliceHints.java
index 34acf93..c98f1d2 100644
--- a/slices/core/src/main/java/androidx/app/slice/core/SliceHints.java
+++ b/slices/core/src/main/java/androidx/app/slice/core/SliceHints.java
@@ -36,13 +36,29 @@
public static final String SUBTYPE_TOGGLE = "toggle";
/**
+ * Subtype indicating that this content is the maximum value for a slider or progress.
+ */
+ public static final String SUBTYPE_MAX = "max";
+
+ /**
+ * Subtype indicating that this content is the current value for a slider or progress.
+ */
+ public static final String SUBTYPE_PROGRESS = "progress";
+
+ /**
* Key to retrieve an extra added to an intent when a control is changed.
*/
public static final String EXTRA_TOGGLE_STATE = "android.app.slice.extra.TOGGLE_STATE";
/**
+ * Key to retrieve an extra added to an intent when the value of a slider has changed.
+ */
+ public static final String EXTRA_SLIDER_VALUE = "android.app.slice.extra.SLIDER_VALUE";
+
+ /**
* Hint indicating this content should be shown instead of the normal content when the slice
* is in small format
*/
public static final String HINT_SUMMARY = "summary";
+
}
diff --git a/slices/view/src/main/java/androidx/app/slice/widget/RowContent.java b/slices/view/src/main/java/androidx/app/slice/widget/RowContent.java
index fb927ff..0e730a5 100644
--- a/slices/view/src/main/java/androidx/app/slice/widget/RowContent.java
+++ b/slices/view/src/main/java/androidx/app/slice/widget/RowContent.java
@@ -17,8 +17,10 @@
package androidx.app.slice.widget;
import static android.app.slice.Slice.HINT_TITLE;
+import static android.app.slice.Slice.SUBTYPE_SLIDER;
import static android.app.slice.SliceItem.FORMAT_ACTION;
import static android.app.slice.SliceItem.FORMAT_IMAGE;
+import static android.app.slice.SliceItem.FORMAT_INT;
import static android.app.slice.SliceItem.FORMAT_REMOTE_INPUT;
import static android.app.slice.SliceItem.FORMAT_SLICE;
import static android.app.slice.SliceItem.FORMAT_TEXT;
@@ -49,6 +51,7 @@
private SliceItem mSubtitleItem;
private ArrayList<SliceItem> mEndItems = new ArrayList<>();
private boolean mEndItemsContainAction;
+ private SliceItem mSlider;
public RowContent(SliceItem rowSlice, boolean showStartItem) {
populate(rowSlice, showStartItem);
@@ -75,19 +78,22 @@
return false;
}
// Filter anything not viable for displaying in a row
- ArrayList<SliceItem> rowItems = filterInvalidItems(rowSlice.getSlice().getItems());
+ ArrayList<SliceItem> rowItems = filterInvalidItems(rowSlice);
// If we've only got one item that's a slice / action use those items instead
if (rowItems.size() == 1 && (FORMAT_ACTION.equals(rowItems.get(0).getFormat())
|| FORMAT_SLICE.equals(rowItems.get(0).getFormat()))) {
if (isValidRow(rowItems.get(0))) {
rowSlice = rowItems.get(0);
- rowItems = filterInvalidItems(rowSlice.getSlice().getItems());
+ rowItems = filterInvalidItems(rowSlice);
}
}
// Content intent
if (FORMAT_ACTION.equals(rowSlice.getFormat())) {
mContentIntent = rowSlice;
}
+ if (SUBTYPE_SLIDER.equals(rowSlice.getSubType())) {
+ mSlider = rowSlice;
+ }
if (rowItems.size() > 0) {
// Start item
if (isStartType(rowItems.get(0))) {
@@ -135,6 +141,14 @@
}
/**
+ * @return the {@link SliceItem} representing the slider in this row; can be null
+ */
+ @Nullable
+ public SliceItem getSlider() {
+ return mSlider;
+ }
+
+ /**
* @return whether this row has content that is valid to display.
*/
public boolean isValid() {
@@ -178,25 +192,25 @@
/**
* @return whether this is a valid item to use to populate a row of content.
*/
- private static boolean isValidRow(SliceItem item) {
+ private static boolean isValidRow(SliceItem rowSlice) {
// Must be slice or action
- if (FORMAT_SLICE.equals(item.getFormat()) || FORMAT_ACTION.equals(item.getFormat())) {
+ if (FORMAT_SLICE.equals(rowSlice.getFormat())
+ || FORMAT_ACTION.equals(rowSlice.getFormat())) {
// Must have at least one legitimate child
- List<SliceItem> rowItems = item.getSlice().getItems();
+ List<SliceItem> rowItems = rowSlice.getSlice().getItems();
for (int i = 0; i < rowItems.size(); i++) {
- if (isValidRowContent(rowItems.get(i))) {
+ if (isValidRowContent(rowSlice, rowItems.get(i))) {
return true;
}
}
}
- Log.w(TAG, "invalid row content because not a slice or action");
return false;
}
- private static ArrayList<SliceItem> filterInvalidItems(List<SliceItem> items) {
+ private static ArrayList<SliceItem> filterInvalidItems(SliceItem rowSlice) {
ArrayList<SliceItem> filteredList = new ArrayList<>();
- for (SliceItem i : items) {
- if (isValidRowContent(i)) {
+ for (SliceItem i : rowSlice.getSlice().getItems()) {
+ if (isValidRowContent(rowSlice, i)) {
filteredList.add(i);
}
}
@@ -206,7 +220,7 @@
/**
* @return whether this item has valid content to display in a row.
*/
- private static boolean isValidRowContent(SliceItem item) {
+ private static boolean isValidRowContent(SliceItem slice, SliceItem item) {
// TODO -- filter for shortcut once that's in
final String itemFormat = item.getFormat();
// Must be a format that is presentable
@@ -214,7 +228,8 @@
|| FORMAT_IMAGE.equals(itemFormat)
|| FORMAT_TIMESTAMP.equals(itemFormat)
|| FORMAT_REMOTE_INPUT.equals(itemFormat)
- || FORMAT_ACTION.equals(itemFormat);
+ || FORMAT_ACTION.equals(itemFormat)
+ || (FORMAT_INT.equals(itemFormat) && SUBTYPE_SLIDER.equals(slice.getSubType()));
}
/**
diff --git a/slices/view/src/main/java/androidx/app/slice/widget/RowView.java b/slices/view/src/main/java/androidx/app/slice/widget/RowView.java
index 94d16a6..d182dfd 100644
--- a/slices/view/src/main/java/androidx/app/slice/widget/RowView.java
+++ b/slices/view/src/main/java/androidx/app/slice/widget/RowView.java
@@ -20,9 +20,13 @@
import static android.app.slice.Slice.HINT_SELECTED;
import static android.app.slice.SliceItem.FORMAT_ACTION;
import static android.app.slice.SliceItem.FORMAT_IMAGE;
+import static android.app.slice.SliceItem.FORMAT_INT;
import static android.app.slice.SliceItem.FORMAT_TIMESTAMP;
+import static androidx.app.slice.core.SliceHints.EXTRA_SLIDER_VALUE;
import static androidx.app.slice.core.SliceHints.EXTRA_TOGGLE_STATE;
+import static androidx.app.slice.core.SliceHints.SUBTYPE_MAX;
+import static androidx.app.slice.core.SliceHints.SUBTYPE_PROGRESS;
import static androidx.app.slice.core.SliceHints.SUBTYPE_TOGGLE;
import static androidx.app.slice.widget.SliceView.MODE_LARGE;
import static androidx.app.slice.widget.SliceView.MODE_SMALL;
@@ -41,6 +45,8 @@
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
+import android.widget.ProgressBar;
+import android.widget.SeekBar;
import android.widget.Switch;
import android.widget.TextView;
import android.widget.ToggleButton;
@@ -81,6 +87,8 @@
private View mDivider;
private ArrayList<CompoundButton> mToggles = new ArrayList<>();
private LinearLayout mEndContainer;
+ private SeekBar mSeekBar;
+ private ProgressBar mProgressBar;
private int mRowIndex;
private RowContent mRowContent;
@@ -101,6 +109,8 @@
mSecondaryText = (TextView) findViewById(android.R.id.summary);
mDivider = findViewById(R.id.divider);
mEndContainer = (LinearLayout) findViewById(android.R.id.widget_frame);
+ mSeekBar = (SeekBar) findViewById(R.id.seek_bar);
+ mProgressBar = (ProgressBar) findViewById(R.id.progress_bar);
}
@Override
@@ -175,6 +185,12 @@
}
mSecondaryText.setVisibility(subTitle != null ? View.VISIBLE : View.GONE);
+ final SliceItem slider = mRowContent.getSlider();
+ if (slider != null) {
+ addSlider(slider);
+ return;
+ }
+
mRowAction = mRowContent.getContentIntent();
ArrayList<SliceItem> endItems = mRowContent.getEndItems();
if (endItems.isEmpty()) {
@@ -228,6 +244,48 @@
}
}
+ private void addSlider(final SliceItem slider) {
+ final ProgressBar progressBar;
+ if (FORMAT_ACTION.equals(slider.getFormat())) {
+ // Seek bar
+ progressBar = mSeekBar;
+ mSeekBar.setVisibility(View.VISIBLE);
+ SliceItem thumb = SliceQuery.find(slider, FORMAT_IMAGE);
+ if (thumb != null) {
+ mSeekBar.setThumb(thumb.getIcon().loadDrawable(getContext()));
+ }
+ mSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
+ @Override
+ public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
+ try {
+ PendingIntent pi = slider.getAction();
+ Intent i = new Intent().putExtra(EXTRA_SLIDER_VALUE, progress);
+ // TODO: sending this PendingIntent should be rate limited.
+ pi.send(getContext(), 0, i, null, null);
+ } catch (CanceledException e) { }
+ }
+
+ @Override
+ public void onStartTrackingTouch(SeekBar seekBar) { }
+
+ @Override
+ public void onStopTrackingTouch(SeekBar seekBar) { }
+ });
+ } else {
+ // Progress bar
+ progressBar = mProgressBar;
+ mProgressBar.setVisibility(View.VISIBLE);
+ }
+ SliceItem max = SliceQuery.findSubtype(slider, FORMAT_INT, SUBTYPE_MAX);
+ if (max != null) {
+ progressBar.setMax(max.getInt());
+ }
+ SliceItem progress = SliceQuery.findSubtype(slider, FORMAT_INT, SUBTYPE_PROGRESS);
+ if (progress != null) {
+ progressBar.setProgress(progress.getInt());
+ }
+ }
+
/**
* Add a toggle view to container.
*/
@@ -382,5 +440,7 @@
mToggles.clear();
mRowAction = null;
mDivider.setVisibility(View.GONE);
+ mSeekBar.setVisibility(View.GONE);
+ mProgressBar.setVisibility(View.GONE);
}
}
diff --git a/slices/view/src/main/res/layout-v21/abc_slice_small_template.xml b/slices/view/src/main/res/layout-v21/abc_slice_small_template.xml
index 649e39f..7707dae 100644
--- a/slices/view/src/main/res/layout-v21/abc_slice_small_template.xml
+++ b/slices/view/src/main/res/layout-v21/abc_slice_small_template.xml
@@ -56,6 +56,19 @@
android:textColor="?android:attr/textColorSecondary"
android:maxLines="10" />
+ <SeekBar
+ android:id="@+id/seek_bar"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:visibility="gone" />
+
+ <ProgressBar
+ android:id="@+id/progress_bar"
+ style="?android:attr/progressBarStyleHorizontal"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:visibility="gone" />
+
</LinearLayout>
<View
diff --git a/slices/view/src/main/res/layout/abc_slice_small_template.xml b/slices/view/src/main/res/layout/abc_slice_small_template.xml
index e673362..706ded6 100644
--- a/slices/view/src/main/res/layout/abc_slice_small_template.xml
+++ b/slices/view/src/main/res/layout/abc_slice_small_template.xml
@@ -55,6 +55,19 @@
android:textColor="?android:attr/textColorSecondary"
android:maxLines="10" />
+ <SeekBar
+ android:id="@+id/seek_bar"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:visibility="gone" />
+
+ <ProgressBar
+ android:id="@+id/progress_bar"
+ style="?android:attr/progressBarStyleHorizontal"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:visibility="gone" />
+
</LinearLayout>
<View
diff --git a/v7/cardview/Android.mk b/v7/cardview/Android.mk
index 2d9492d..563ea9d 100644
--- a/v7/cardview/Android.mk
+++ b/v7/cardview/Android.mk
@@ -22,6 +22,7 @@
# in their makefiles to include the resources in their package.
include $(CLEAR_VARS)
LOCAL_USE_AAPT2 := true
+LOCAL_AAPT2_ONLY := true
LOCAL_MODULE := android-support-v7-cardview
LOCAL_SDK_VERSION := $(SUPPORT_CURRENT_SDK_VERSION)
LOCAL_SRC_FILES := \
diff --git a/v7/mediarouter/res/values-in/strings.xml b/v7/mediarouter/res/values-in/strings.xml
index e76b3e8..becb41e 100644
--- a/v7/mediarouter/res/values-in/strings.xml
+++ b/v7/mediarouter/res/values-in/strings.xml
@@ -25,7 +25,7 @@
<string name="mr_chooser_title" msgid="414301941546135990">"Transmisikan ke"</string>
<string name="mr_chooser_searching" msgid="6349900579507521956">"Mencari perangkat"</string>
<string name="mr_controller_disconnect" msgid="1227264889412989580">"Putuskan sambungan"</string>
- <string name="mr_controller_stop_casting" msgid="8857886794086583226">"Hentikan cast"</string>
+ <string name="mr_controller_stop_casting" msgid="8857886794086583226">"Hentikan Transmisi"</string>
<string name="mr_controller_close_description" msgid="7333862312480583260">"Tutup"</string>
<string name="mr_controller_play" msgid="683634565969987458">"Putar"</string>
<string name="mr_controller_pause" msgid="5451884435510905406">"Jeda"</string>
diff --git a/v7/preference/res/values/styles.xml b/v7/preference/res/values/styles.xml
index 46351e1..be1797b 100644
--- a/v7/preference/res/values/styles.xml
+++ b/v7/preference/res/values/styles.xml
@@ -84,10 +84,6 @@
<style name="Preference.Material">
<item name="android:layout">@layout/preference_material</item>
- <item name="allowDividerAbove">false</item>
- <item name="allowDividerBelow">true</item>
- <item name="singleLineTitle">false</item>
- <item name="iconSpaceReserved">true</item>
</style>
<style name="Preference.Information.Material">
@@ -98,16 +94,10 @@
<style name="Preference.Category.Material">
<item name="android:layout">@layout/preference_category_material</item>
- <item name="allowDividerAbove">true</item>
- <item name="allowDividerBelow">true</item>
- <item name="iconSpaceReserved">true</item>
</style>
<style name="Preference.CheckBoxPreference.Material">
<item name="android:layout">@layout/preference_material</item>
- <item name="allowDividerAbove">false</item>
- <item name="allowDividerBelow">true</item>
- <item name="iconSpaceReserved">true</item>
</style>
<style name="Preference.SwitchPreferenceCompat.Material">
@@ -116,10 +106,6 @@
<style name="Preference.SwitchPreference.Material">
<item name="android:layout">@layout/preference_material</item>
- <item name="allowDividerAbove">false</item>
- <item name="allowDividerBelow">true</item>
- <item name="singleLineTitle">false</item>
- <item name="iconSpaceReserved">true</item>
</style>
<style name="Preference.SeekBarPreference.Material">
@@ -130,31 +116,18 @@
<style name="Preference.PreferenceScreen.Material">
<item name="android:layout">@layout/preference_material</item>
- <item name="allowDividerAbove">false</item>
- <item name="allowDividerBelow">true</item>
- <item name="iconSpaceReserved">true</item>
</style>
<style name="Preference.DialogPreference.Material">
<item name="android:layout">@layout/preference_material</item>
- <item name="allowDividerAbove">false</item>
- <item name="allowDividerBelow">true</item>
- <item name="iconSpaceReserved">true</item>
</style>
<style name="Preference.DialogPreference.EditTextPreference.Material">
<item name="android:layout">@layout/preference_material</item>
- <item name="allowDividerAbove">false</item>
- <item name="allowDividerBelow">true</item>
- <item name="singleLineTitle">false</item>
- <item name="iconSpaceReserved">true</item>
</style>
<style name="Preference.DropDown.Material">
<item name="android:layout">@layout/preference_dropdown_material</item>
- <item name="allowDividerAbove">false</item>
- <item name="allowDividerBelow">true</item>
- <item name="iconSpaceReserved">true</item>
</style>
<style name="Preference_TextAppearanceMaterialBody2">
@@ -173,7 +146,6 @@
<style name="PreferenceFragment.Material">
<item name="android:divider">@drawable/preference_list_divider_material</item>
- <item name="allowDividerAfterLastItem">false</item>
</style>
<style name="PreferenceFragmentList.Material">
diff --git a/v7/preference/res/values/themes.xml b/v7/preference/res/values/themes.xml
index 598c24f..1f8f158 100644
--- a/v7/preference/res/values/themes.xml
+++ b/v7/preference/res/values/themes.xml
@@ -51,6 +51,5 @@
<item name="editTextPreferenceStyle">@style/Preference.DialogPreference.EditTextPreference.Material</item>
<item name="dropdownPreferenceStyle">@style/Preference.DropDown.Material</item>
<item name="preferenceFragmentListStyle">@style/PreferenceFragmentList.Material</item>
- <item name="android:scrollbars">vertical</item>
</style>
</resources>