Merge "Move to using build-tools 27.0.0" into oc-mr1-support-27.0-dev
diff --git a/app-toolkit/core-testing/src/androidTest/java/android/arch/core/executor/testing/CountingTaskExecutorRuleTest.java b/app-toolkit/core-testing/src/androidTest/java/android/arch/core/executor/testing/CountingTaskExecutorRuleTest.java
index ad36b9b..a6a5b2e 100644
--- a/app-toolkit/core-testing/src/androidTest/java/android/arch/core/executor/testing/CountingTaskExecutorRuleTest.java
+++ b/app-toolkit/core-testing/src/androidTest/java/android/arch/core/executor/testing/CountingTaskExecutorRuleTest.java
@@ -19,7 +19,7 @@
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
-import android.arch.core.executor.AppToolkitTaskExecutor;
+import android.arch.core.executor.ArchTaskExecutor;
import android.support.test.filters.MediumTest;
import android.support.test.runner.AndroidJUnit4;
@@ -115,13 +115,13 @@
private LatchRunnable runOnIO() {
LatchRunnable latchRunnable = new LatchRunnable();
- AppToolkitTaskExecutor.getInstance().executeOnDiskIO(latchRunnable);
+ ArchTaskExecutor.getInstance().executeOnDiskIO(latchRunnable);
return latchRunnable;
}
private LatchRunnable runOnMain() {
LatchRunnable latchRunnable = new LatchRunnable();
- AppToolkitTaskExecutor.getInstance().executeOnMainThread(latchRunnable);
+ ArchTaskExecutor.getInstance().executeOnMainThread(latchRunnable);
return latchRunnable;
}
diff --git a/app-toolkit/core-testing/src/main/java/android/arch/core/executor/JunitTaskExecutorRule.java b/app-toolkit/core-testing/src/main/java/android/arch/core/executor/JunitTaskExecutorRule.java
index cd4f8f5..c3366f3 100644
--- a/app-toolkit/core-testing/src/main/java/android/arch/core/executor/JunitTaskExecutorRule.java
+++ b/app-toolkit/core-testing/src/main/java/android/arch/core/executor/JunitTaskExecutorRule.java
@@ -46,11 +46,11 @@
}
private void beforeStart() {
- AppToolkitTaskExecutor.getInstance().setDelegate(mTaskExecutor);
+ ArchTaskExecutor.getInstance().setDelegate(mTaskExecutor);
}
private void afterFinished() {
- AppToolkitTaskExecutor.getInstance().setDelegate(null);
+ ArchTaskExecutor.getInstance().setDelegate(null);
}
public TaskExecutor getTaskExecutor() {
diff --git a/app-toolkit/core-testing/src/main/java/android/arch/core/executor/testing/CountingTaskExecutorRule.java b/app-toolkit/core-testing/src/main/java/android/arch/core/executor/testing/CountingTaskExecutorRule.java
index ad930aa..77133d5 100644
--- a/app-toolkit/core-testing/src/main/java/android/arch/core/executor/testing/CountingTaskExecutorRule.java
+++ b/app-toolkit/core-testing/src/main/java/android/arch/core/executor/testing/CountingTaskExecutorRule.java
@@ -16,7 +16,7 @@
package android.arch.core.executor.testing;
-import android.arch.core.executor.AppToolkitTaskExecutor;
+import android.arch.core.executor.ArchTaskExecutor;
import android.arch.core.executor.DefaultTaskExecutor;
import android.os.SystemClock;
@@ -39,7 +39,7 @@
@Override
protected void starting(Description description) {
super.starting(description);
- AppToolkitTaskExecutor.getInstance().setDelegate(new DefaultTaskExecutor() {
+ ArchTaskExecutor.getInstance().setDelegate(new DefaultTaskExecutor() {
@Override
public void executeOnDiskIO(Runnable runnable) {
super.executeOnDiskIO(new CountingRunnable(runnable));
@@ -55,7 +55,7 @@
@Override
protected void finished(Description description) {
super.finished(description);
- AppToolkitTaskExecutor.getInstance().setDelegate(null);
+ ArchTaskExecutor.getInstance().setDelegate(null);
}
private void increment() {
diff --git a/app-toolkit/core-testing/src/main/java/android/arch/core/executor/testing/InstantTaskExecutorRule.java b/app-toolkit/core-testing/src/main/java/android/arch/core/executor/testing/InstantTaskExecutorRule.java
index 07dcf1f..f88a3e3 100644
--- a/app-toolkit/core-testing/src/main/java/android/arch/core/executor/testing/InstantTaskExecutorRule.java
+++ b/app-toolkit/core-testing/src/main/java/android/arch/core/executor/testing/InstantTaskExecutorRule.java
@@ -16,7 +16,7 @@
package android.arch.core.executor.testing;
-import android.arch.core.executor.AppToolkitTaskExecutor;
+import android.arch.core.executor.ArchTaskExecutor;
import android.arch.core.executor.TaskExecutor;
import org.junit.rules.TestWatcher;
@@ -32,7 +32,7 @@
@Override
protected void starting(Description description) {
super.starting(description);
- AppToolkitTaskExecutor.getInstance().setDelegate(new TaskExecutor() {
+ ArchTaskExecutor.getInstance().setDelegate(new TaskExecutor() {
@Override
public void executeOnDiskIO(Runnable runnable) {
runnable.run();
@@ -53,6 +53,6 @@
@Override
protected void finished(Description description) {
super.finished(description);
- AppToolkitTaskExecutor.getInstance().setDelegate(null);
+ ArchTaskExecutor.getInstance().setDelegate(null);
}
}
diff --git a/app-toolkit/core-testing/src/test/java/android/arch/core/executor/testing/InstantTaskExecutorRuleTest.java b/app-toolkit/core-testing/src/test/java/android/arch/core/executor/testing/InstantTaskExecutorRuleTest.java
index 4345fd1..0fdcbfb 100644
--- a/app-toolkit/core-testing/src/test/java/android/arch/core/executor/testing/InstantTaskExecutorRuleTest.java
+++ b/app-toolkit/core-testing/src/test/java/android/arch/core/executor/testing/InstantTaskExecutorRuleTest.java
@@ -18,7 +18,7 @@
import static org.junit.Assert.assertTrue;
-import android.arch.core.executor.AppToolkitTaskExecutor;
+import android.arch.core.executor.ArchTaskExecutor;
import org.junit.Rule;
import org.junit.Test;
@@ -46,7 +46,7 @@
return null;
}
});
- AppToolkitTaskExecutor.getInstance().executeOnMainThread(check);
+ ArchTaskExecutor.getInstance().executeOnMainThread(check);
check.get(1, TimeUnit.SECONDS);
}
@@ -60,7 +60,7 @@
return null;
}
});
- AppToolkitTaskExecutor.getInstance().executeOnDiskIO(check);
+ ArchTaskExecutor.getInstance().executeOnDiskIO(check);
check.get(1, TimeUnit.SECONDS);
}
}
diff --git a/app-toolkit/runtime/src/main/java/android/arch/core/executor/AppToolkitTaskExecutor.java b/app-toolkit/runtime/src/main/java/android/arch/core/executor/ArchTaskExecutor.java
similarity index 88%
rename from app-toolkit/runtime/src/main/java/android/arch/core/executor/AppToolkitTaskExecutor.java
rename to app-toolkit/runtime/src/main/java/android/arch/core/executor/ArchTaskExecutor.java
index 7337f74..2401a73 100644
--- a/app-toolkit/runtime/src/main/java/android/arch/core/executor/AppToolkitTaskExecutor.java
+++ b/app-toolkit/runtime/src/main/java/android/arch/core/executor/ArchTaskExecutor.java
@@ -29,8 +29,8 @@
* @hide This API is not final.
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
-public class AppToolkitTaskExecutor extends TaskExecutor {
- private static volatile AppToolkitTaskExecutor sInstance;
+public class ArchTaskExecutor extends TaskExecutor {
+ private static volatile ArchTaskExecutor sInstance;
@NonNull
private TaskExecutor mDelegate;
@@ -54,7 +54,7 @@
}
};
- private AppToolkitTaskExecutor() {
+ private ArchTaskExecutor() {
mDefaultTaskExecutor = new DefaultTaskExecutor();
mDelegate = mDefaultTaskExecutor;
}
@@ -62,15 +62,15 @@
/**
* Returns an instance of the task executor.
*
- * @return The singleton AppToolkitTaskExecutor.
+ * @return The singleton ArchTaskExecutor.
*/
- public static AppToolkitTaskExecutor getInstance() {
+ public static ArchTaskExecutor getInstance() {
if (sInstance != null) {
return sInstance;
}
- synchronized (AppToolkitTaskExecutor.class) {
+ synchronized (ArchTaskExecutor.class) {
if (sInstance == null) {
- sInstance = new AppToolkitTaskExecutor();
+ sInstance = new ArchTaskExecutor();
}
}
return sInstance;
diff --git a/compat/java/android/support/v4/app/ActivityCompat.java b/compat/java/android/support/v4/app/ActivityCompat.java
index a26b64c..2ce5a30 100644
--- a/compat/java/android/support/v4/app/ActivityCompat.java
+++ b/compat/java/android/support/v4/app/ActivityCompat.java
@@ -148,8 +148,8 @@
* supplied here; there are no supported definitions for
* building it manually.
*/
- public static void startActivityForResult(Activity activity, Intent intent, int requestCode,
- @Nullable Bundle options) {
+ public static void startActivityForResult(@NonNull Activity activity, @NonNull Intent intent,
+ int requestCode, @Nullable Bundle options) {
if (Build.VERSION.SDK_INT >= 16) {
activity.startActivityForResult(intent, requestCode, options);
} else {
@@ -183,9 +183,10 @@
* supplied here; there are no supported definitions for
* building it manually.
*/
- public static void startIntentSenderForResult(Activity activity, IntentSender intent,
- int requestCode, Intent fillInIntent, int flagsMask, int flagsValues,
- int extraFlags, @Nullable Bundle options) throws IntentSender.SendIntentException {
+ public static void startIntentSenderForResult(@NonNull Activity activity,
+ @NonNull IntentSender intent, int requestCode, @Nullable Intent fillInIntent,
+ int flagsMask, int flagsValues, int extraFlags, @Nullable Bundle options)
+ throws IntentSender.SendIntentException {
if (Build.VERSION.SDK_INT >= 16) {
activity.startIntentSenderForResult(intent, requestCode, fillInIntent, flagsMask,
flagsValues, extraFlags, options);
@@ -202,7 +203,7 @@
* <p>On Android 4.1+ calling this method will call through to the native version of this
* method. For other platforms {@link Activity#finish()} will be called instead.</p>
*/
- public static void finishAffinity(Activity activity) {
+ public static void finishAffinity(@NonNull Activity activity) {
if (Build.VERSION.SDK_INT >= 16) {
activity.finishAffinity();
} else {
@@ -219,7 +220,7 @@
* <p>On Android 4.4 or lower, this method only finishes the Activity with no
* special exit transition.</p>
*/
- public static void finishAfterTransition(Activity activity) {
+ public static void finishAfterTransition(@NonNull Activity activity) {
if (Build.VERSION.SDK_INT >= 21) {
activity.finishAfterTransition();
} else {
@@ -244,7 +245,7 @@
* referrer information, applications can spoof it.</p>
*/
@Nullable
- public static Uri getReferrer(Activity activity) {
+ public static Uri getReferrer(@NonNull Activity activity) {
if (Build.VERSION.SDK_INT >= 22) {
return activity.getReferrer();
}
@@ -268,8 +269,8 @@
*
* @param callback Used to manipulate shared element transitions on the launched Activity.
*/
- public static void setEnterSharedElementCallback(Activity activity,
- SharedElementCallback callback) {
+ public static void setEnterSharedElementCallback(@NonNull Activity activity,
+ @Nullable SharedElementCallback callback) {
if (Build.VERSION.SDK_INT >= 23) {
android.app.SharedElementCallback frameworkCallback = callback != null
? new SharedElementCallback23Impl(callback)
@@ -292,8 +293,8 @@
*
* @param callback Used to manipulate shared element transitions on the launching Activity.
*/
- public static void setExitSharedElementCallback(Activity activity,
- SharedElementCallback callback) {
+ public static void setExitSharedElementCallback(@NonNull Activity activity,
+ @Nullable SharedElementCallback callback) {
if (Build.VERSION.SDK_INT >= 23) {
android.app.SharedElementCallback frameworkCallback = callback != null
? new SharedElementCallback23Impl(callback)
@@ -307,13 +308,13 @@
}
}
- public static void postponeEnterTransition(Activity activity) {
+ public static void postponeEnterTransition(@NonNull Activity activity) {
if (Build.VERSION.SDK_INT >= 21) {
activity.postponeEnterTransition();
}
}
- public static void startPostponedEnterTransition(Activity activity) {
+ public static void startPostponedEnterTransition(@NonNull Activity activity) {
if (Build.VERSION.SDK_INT >= 21) {
activity.startPostponedEnterTransition();
}
diff --git a/compat/java/android/support/v4/app/ActivityOptionsCompat.java b/compat/java/android/support/v4/app/ActivityOptionsCompat.java
index 2957c50..6676805 100644
--- a/compat/java/android/support/v4/app/ActivityOptionsCompat.java
+++ b/compat/java/android/support/v4/app/ActivityOptionsCompat.java
@@ -24,6 +24,7 @@
import android.graphics.Rect;
import android.os.Build;
import android.os.Bundle;
+import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.RequiresApi;
import android.support.v4.util.Pair;
@@ -60,7 +61,8 @@
* @return Returns a new ActivityOptions object that you can use to supply
* these options as the options Bundle when starting an activity.
*/
- public static ActivityOptionsCompat makeCustomAnimation(Context context,
+ @NonNull
+ public static ActivityOptionsCompat makeCustomAnimation(@NonNull Context context,
int enterResId, int exitResId) {
if (Build.VERSION.SDK_INT >= 16) {
return createImpl(ActivityOptions.makeCustomAnimation(context, enterResId, exitResId));
@@ -88,7 +90,8 @@
* @return Returns a new ActivityOptions object that you can use to supply
* these options as the options Bundle when starting an activity.
*/
- public static ActivityOptionsCompat makeScaleUpAnimation(View source,
+ @NonNull
+ public static ActivityOptionsCompat makeScaleUpAnimation(@NonNull View source,
int startX, int startY, int startWidth, int startHeight) {
if (Build.VERSION.SDK_INT >= 16) {
return createImpl(ActivityOptions.makeScaleUpAnimation(
@@ -111,7 +114,8 @@
* @return Returns a new ActivityOptions object that you can use to
* supply these options as the options Bundle when starting an activity.
*/
- public static ActivityOptionsCompat makeClipRevealAnimation(View source,
+ @NonNull
+ public static ActivityOptionsCompat makeClipRevealAnimation(@NonNull View source,
int startX, int startY, int width, int height) {
if (Build.VERSION.SDK_INT >= 23) {
return createImpl(ActivityOptions.makeClipRevealAnimation(
@@ -139,8 +143,9 @@
* @return Returns a new ActivityOptions object that you can use to supply
* these options as the options Bundle when starting an activity.
*/
- public static ActivityOptionsCompat makeThumbnailScaleUpAnimation(View source,
- Bitmap thumbnail, int startX, int startY) {
+ @NonNull
+ public static ActivityOptionsCompat makeThumbnailScaleUpAnimation(@NonNull View source,
+ @NonNull Bitmap thumbnail, int startX, int startY) {
if (Build.VERSION.SDK_INT >= 16) {
return createImpl(ActivityOptions.makeThumbnailScaleUpAnimation(
source, thumbnail, startX, startY));
@@ -166,8 +171,9 @@
* @return Returns a new ActivityOptions object that you can use to
* supply these options as the options Bundle when starting an activity.
*/
- public static ActivityOptionsCompat makeSceneTransitionAnimation(Activity activity,
- View sharedElement, String sharedElementName) {
+ @NonNull
+ public static ActivityOptionsCompat makeSceneTransitionAnimation(@NonNull Activity activity,
+ @NonNull View sharedElement, @NonNull String sharedElementName) {
if (Build.VERSION.SDK_INT >= 21) {
return createImpl(ActivityOptions.makeSceneTransitionAnimation(
activity, sharedElement, sharedElementName));
@@ -192,8 +198,9 @@
* @return Returns a new ActivityOptions object that you can use to
* supply these options as the options Bundle when starting an activity.
*/
+ @NonNull
@SuppressWarnings("unchecked")
- public static ActivityOptionsCompat makeSceneTransitionAnimation(Activity activity,
+ public static ActivityOptionsCompat makeSceneTransitionAnimation(@NonNull Activity activity,
Pair<View, String>... sharedElements) {
if (Build.VERSION.SDK_INT >= 21) {
android.util.Pair<View, String>[] pairs = null;
@@ -219,6 +226,7 @@
* {@link android.R.attr#launchMode launchMode} values of
* <code>singleInstance</code> or <code>singleTask</code>.
*/
+ @NonNull
public static ActivityOptionsCompat makeTaskLaunchBehind() {
if (Build.VERSION.SDK_INT >= 21) {
return createImpl(ActivityOptions.makeTaskLaunchBehind());
@@ -230,6 +238,7 @@
* Create a basic ActivityOptions that has no special animation associated with it.
* Other options can still be set.
*/
+ @NonNull
public static ActivityOptionsCompat makeBasic() {
if (Build.VERSION.SDK_INT >= 23) {
return createImpl(ActivityOptions.makeBasic());
@@ -314,6 +323,7 @@
* {@link android.content.pm.PackageManager#FEATURE_PICTURE_IN_PICTURE} enabled.
* @param screenSpacePixelRect Launch bounds to use for the activity or null for fullscreen.
*/
+ @NonNull
public ActivityOptionsCompat setLaunchBounds(@Nullable Rect screenSpacePixelRect) {
return this;
}
@@ -335,6 +345,7 @@
* object; you must not modify it, but can supply it to the startActivity
* methods that take an options Bundle.
*/
+ @Nullable
public Bundle toBundle() {
return null;
}
@@ -344,7 +355,7 @@
* otherOptions. Any values defined in otherOptions replace those in the
* base options.
*/
- public void update(ActivityOptionsCompat otherOptions) {
+ public void update(@NonNull ActivityOptionsCompat otherOptions) {
// Do nothing.
}
@@ -372,7 +383,7 @@
*
* @param receiver A broadcast receiver that will receive the report.
*/
- public void requestUsageTimeReport(PendingIntent receiver) {
+ public void requestUsageTimeReport(@NonNull PendingIntent receiver) {
// Do nothing.
}
}
diff --git a/compat/java/android/support/v4/app/AlarmManagerCompat.java b/compat/java/android/support/v4/app/AlarmManagerCompat.java
index 5a4582b..a297cb5 100644
--- a/compat/java/android/support/v4/app/AlarmManagerCompat.java
+++ b/compat/java/android/support/v4/app/AlarmManagerCompat.java
@@ -19,6 +19,7 @@
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.os.Build;
+import android.support.annotation.NonNull;
/**
* Compatibility library for {@link AlarmManager} with fallbacks for older platforms.
@@ -52,8 +53,8 @@
* @see android.content.Context#registerReceiver
* @see android.content.Intent#filterEquals
*/
- public static void setAlarmClock(AlarmManager alarmManager, long triggerTime,
- PendingIntent showIntent, PendingIntent operation) {
+ public static void setAlarmClock(@NonNull AlarmManager alarmManager, long triggerTime,
+ @NonNull PendingIntent showIntent, @NonNull PendingIntent operation) {
if (Build.VERSION.SDK_INT >= 21) {
alarmManager.setAlarmClock(new AlarmManager.AlarmClockInfo(triggerTime, showIntent),
operation);
@@ -110,8 +111,8 @@
* @see AlarmManager#RTC
* @see AlarmManager#RTC_WAKEUP
*/
- public static void setAndAllowWhileIdle(AlarmManager alarmManager, int type,
- long triggerAtMillis, PendingIntent operation) {
+ public static void setAndAllowWhileIdle(@NonNull AlarmManager alarmManager, int type,
+ long triggerAtMillis, @NonNull PendingIntent operation) {
if (Build.VERSION.SDK_INT >= 23) {
alarmManager.setAndAllowWhileIdle(type, triggerAtMillis, operation);
} else {
@@ -155,8 +156,8 @@
* @see AlarmManager#RTC
* @see AlarmManager#RTC_WAKEUP
*/
- public static void setExact(AlarmManager alarmManager, int type, long triggerAtMillis,
- PendingIntent operation) {
+ public static void setExact(@NonNull AlarmManager alarmManager, int type, long triggerAtMillis,
+ @NonNull PendingIntent operation) {
if (Build.VERSION.SDK_INT >= 19) {
alarmManager.setExact(type, triggerAtMillis, operation);
} else {
@@ -215,8 +216,8 @@
* @see AlarmManager#RTC
* @see AlarmManager#RTC_WAKEUP
*/
- public static void setExactAndAllowWhileIdle(AlarmManager alarmManager, int type,
- long triggerAtMillis, PendingIntent operation) {
+ public static void setExactAndAllowWhileIdle(@NonNull AlarmManager alarmManager, int type,
+ long triggerAtMillis, @NonNull PendingIntent operation) {
if (Build.VERSION.SDK_INT >= 23) {
alarmManager.setExactAndAllowWhileIdle(type, triggerAtMillis, operation);
} else {
diff --git a/compat/java/android/support/v4/app/AppOpsManagerCompat.java b/compat/java/android/support/v4/app/AppOpsManagerCompat.java
index ce2d2c6..7e97199 100644
--- a/compat/java/android/support/v4/app/AppOpsManagerCompat.java
+++ b/compat/java/android/support/v4/app/AppOpsManagerCompat.java
@@ -21,6 +21,7 @@
import android.app.AppOpsManager;
import android.content.Context;
import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
/**
* Helper for accessing features in {@link android.app.AppOpsManager}.
@@ -56,6 +57,7 @@
* @param permission The permission.
* @return The app op associated with the permission or null.
*/
+ @Nullable
public static String permissionToOp(@NonNull String permission) {
if (SDK_INT >= 23) {
return AppOpsManager.permissionToOp(permission);
diff --git a/compat/java/android/support/v4/app/BundleCompat.java b/compat/java/android/support/v4/app/BundleCompat.java
index e5fc302..21d730d 100644
--- a/compat/java/android/support/v4/app/BundleCompat.java
+++ b/compat/java/android/support/v4/app/BundleCompat.java
@@ -19,6 +19,8 @@
import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
import android.util.Log;
import java.lang.reflect.InvocationTargetException;
@@ -94,7 +96,8 @@
* @param key The key to use while getting the {@link IBinder}.
* @return The {@link IBinder} that was obtained.
*/
- public static IBinder getBinder(Bundle bundle, String key) {
+ @Nullable
+ public static IBinder getBinder(@NonNull Bundle bundle, @Nullable String key) {
if (Build.VERSION.SDK_INT >= 18) {
return bundle.getBinder(key);
} else {
@@ -109,7 +112,8 @@
* @param key The key to use while putting the {@link IBinder}.
* @param binder The {@link IBinder} to put.
*/
- public static void putBinder(Bundle bundle, String key, IBinder binder) {
+ public static void putBinder(@NonNull Bundle bundle, @Nullable String key,
+ @Nullable IBinder binder) {
if (Build.VERSION.SDK_INT >= 18) {
bundle.putBinder(key, binder);
} else {
diff --git a/compat/java/android/support/v4/app/NotificationManagerCompat.java b/compat/java/android/support/v4/app/NotificationManagerCompat.java
index 93775ec..1a0f1bc 100644
--- a/compat/java/android/support/v4/app/NotificationManagerCompat.java
+++ b/compat/java/android/support/v4/app/NotificationManagerCompat.java
@@ -36,6 +36,8 @@
import android.os.RemoteException;
import android.provider.Settings;
import android.support.annotation.GuardedBy;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
import android.util.Log;
import java.lang.reflect.Field;
@@ -144,7 +146,8 @@
public static final int IMPORTANCE_MAX = 5;
/** Get a {@link NotificationManagerCompat} instance for a provided context. */
- public static NotificationManagerCompat from(Context context) {
+ @NonNull
+ public static NotificationManagerCompat from(@NonNull Context context) {
return new NotificationManagerCompat(context);
}
@@ -167,7 +170,7 @@
* @param tag the string identifier of the notification.
* @param id the ID of the notification
*/
- public void cancel(String tag, int id) {
+ public void cancel(@Nullable String tag, int id) {
mNotificationManager.cancel(tag, id);
if (Build.VERSION.SDK_INT <= MAX_SIDE_CHANNEL_SDK_VERSION) {
pushSideChannelQueue(new CancelTask(mContext.getPackageName(), id, tag));
@@ -197,7 +200,7 @@
* @param id the ID of the notification. The pair (tag, id) must be unique within your app.
* @param notification the notification to post to the system
*/
- public void notify(String tag, int id, Notification notification) {
+ public void notify(@Nullable String tag, int id, @NonNull Notification notification) {
if (useSideChannelForNotification(notification)) {
pushSideChannelQueue(new NotifyTask(mContext.getPackageName(), id, tag, notification));
// Cancel this notification in notification manager if it just transitioned to being
@@ -253,7 +256,8 @@
/**
* Get the set of packages that have an enabled notification listener component within them.
*/
- public static Set<String> getEnabledListenerPackages(Context context) {
+ @NonNull
+ public static Set<String> getEnabledListenerPackages(@NonNull Context context) {
final String enabledNotificationListeners = Settings.Secure.getString(
context.getContentResolver(),
SETTING_ENABLED_NOTIFICATION_LISTENERS);
diff --git a/compat/java/android/support/v4/app/ServiceCompat.java b/compat/java/android/support/v4/app/ServiceCompat.java
index 1676ee8..2e63b23 100644
--- a/compat/java/android/support/v4/app/ServiceCompat.java
+++ b/compat/java/android/support/v4/app/ServiceCompat.java
@@ -22,6 +22,7 @@
import android.app.Service;
import android.os.Build;
import android.support.annotation.IntDef;
+import android.support.annotation.NonNull;
import android.support.annotation.RestrictTo;
import java.lang.annotation.Retention;
@@ -92,7 +93,7 @@
* {@link #STOP_FOREGROUND_DETACH}.
* @see Service#startForeground(int, Notification)
*/
- public static void stopForeground(Service service, @StopForegroundFlags int flags) {
+ public static void stopForeground(@NonNull Service service, @StopForegroundFlags int flags) {
if (Build.VERSION.SDK_INT >= 24) {
service.stopForeground(flags);
} else {
diff --git a/compat/java/android/support/v4/widget/EdgeEffectCompat.java b/compat/java/android/support/v4/widget/EdgeEffectCompat.java
index 9293e60..0d370a8 100644
--- a/compat/java/android/support/v4/widget/EdgeEffectCompat.java
+++ b/compat/java/android/support/v4/widget/EdgeEffectCompat.java
@@ -18,6 +18,7 @@
import android.content.Context;
import android.graphics.Canvas;
import android.os.Build;
+import android.support.annotation.NonNull;
import android.support.annotation.RequiresApi;
import android.widget.EdgeEffect;
@@ -170,7 +171,8 @@
*
* @see {@link EdgeEffect#onPull(float, float)}
*/
- public static void onPull(EdgeEffect edgeEffect, float deltaDistance, float displacement) {
+ public static void onPull(@NonNull EdgeEffect edgeEffect, float deltaDistance,
+ float displacement) {
IMPL.onPull(edgeEffect, deltaDistance, displacement);
}
diff --git a/compat/java/android/support/v4/widget/ImageViewCompat.java b/compat/java/android/support/v4/widget/ImageViewCompat.java
index acaaf63..b517de5 100644
--- a/compat/java/android/support/v4/widget/ImageViewCompat.java
+++ b/compat/java/android/support/v4/widget/ImageViewCompat.java
@@ -20,6 +20,8 @@
import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
import android.os.Build;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
import android.support.annotation.RequiresApi;
import android.widget.ImageView;
@@ -130,21 +132,24 @@
/**
* Return the tint applied to the image drawable, if specified.
*/
- public static ColorStateList getImageTintList(ImageView view) {
+ @Nullable
+ public static ColorStateList getImageTintList(@NonNull ImageView view) {
return IMPL.getImageTintList(view);
}
/**
* Applies a tint to the image drawable.
*/
- public static void setImageTintList(ImageView view, ColorStateList tintList) {
+ public static void setImageTintList(@NonNull ImageView view,
+ @Nullable ColorStateList tintList) {
IMPL.setImageTintList(view, tintList);
}
/**
* Return the blending mode used to apply the tint to the image drawable, if specified.
*/
- public static PorterDuff.Mode getImageTintMode(ImageView view) {
+ @Nullable
+ public static PorterDuff.Mode getImageTintMode(@NonNull ImageView view) {
return IMPL.getImageTintMode(view);
}
@@ -153,7 +158,7 @@
* {@link #setImageTintList(android.widget.ImageView, android.content.res.ColorStateList)}
* to the image drawable. The default mode is {@link PorterDuff.Mode#SRC_IN}.
*/
- public static void setImageTintMode(ImageView view, PorterDuff.Mode mode) {
+ public static void setImageTintMode(@NonNull ImageView view, @Nullable PorterDuff.Mode mode) {
IMPL.setImageTintMode(view, mode);
}
diff --git a/compat/java/android/support/v4/widget/ListPopupWindowCompat.java b/compat/java/android/support/v4/widget/ListPopupWindowCompat.java
index ab86e58..4532733 100644
--- a/compat/java/android/support/v4/widget/ListPopupWindowCompat.java
+++ b/compat/java/android/support/v4/widget/ListPopupWindowCompat.java
@@ -17,6 +17,8 @@
package android.support.v4.widget;
import android.os.Build;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
import android.view.View;
import android.view.View.OnTouchListener;
import android.widget.ListPopupWindow;
@@ -88,8 +90,9 @@
* @return a touch listener that controls drag-to-open behavior, or {@code null} on
* unsupported APIs
*/
+ @Nullable
public static OnTouchListener createDragToOpenListener(
- ListPopupWindow listPopupWindow, View src) {
+ @NonNull ListPopupWindow listPopupWindow, @NonNull View src) {
if (Build.VERSION.SDK_INT >= 19) {
return listPopupWindow.createDragToOpenListener(src);
} else {
diff --git a/compat/java/android/support/v4/widget/PopupMenuCompat.java b/compat/java/android/support/v4/widget/PopupMenuCompat.java
index 639a84b..10c5ff3 100644
--- a/compat/java/android/support/v4/widget/PopupMenuCompat.java
+++ b/compat/java/android/support/v4/widget/PopupMenuCompat.java
@@ -17,6 +17,8 @@
package android.support.v4.widget;
import android.os.Build;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
import android.view.View.OnTouchListener;
import android.widget.PopupMenu;
@@ -47,7 +49,8 @@
* @return a touch listener that controls drag-to-open behavior, or {@code null} on
* unsupported APIs
*/
- public static OnTouchListener getDragToOpenListener(Object popupMenu) {
+ @Nullable
+ public static OnTouchListener getDragToOpenListener(@NonNull Object popupMenu) {
if (Build.VERSION.SDK_INT >= 19) {
return ((PopupMenu) popupMenu).getDragToOpenListener();
} else {
diff --git a/compat/java/android/support/v4/widget/PopupWindowCompat.java b/compat/java/android/support/v4/widget/PopupWindowCompat.java
index d846b40..d9de3db 100644
--- a/compat/java/android/support/v4/widget/PopupWindowCompat.java
+++ b/compat/java/android/support/v4/widget/PopupWindowCompat.java
@@ -17,6 +17,7 @@
package android.support.v4.widget;
import android.os.Build;
+import android.support.annotation.NonNull;
import android.support.annotation.RequiresApi;
import android.support.v4.view.GravityCompat;
import android.support.v4.view.ViewCompat;
@@ -213,8 +214,8 @@
* @param yoff A vertical offset from the anchor in pixels
* @param gravity Alignment of the popup relative to the anchor
*/
- public static void showAsDropDown(PopupWindow popup, View anchor, int xoff, int yoff,
- int gravity) {
+ public static void showAsDropDown(@NonNull PopupWindow popup, @NonNull View anchor,
+ int xoff, int yoff, int gravity) {
IMPL.showAsDropDown(popup, anchor, xoff, yoff, gravity);
}
@@ -224,7 +225,7 @@
*
* @param overlapAnchor Whether the popup should overlap its anchor.
*/
- public static void setOverlapAnchor(PopupWindow popupWindow, boolean overlapAnchor) {
+ public static void setOverlapAnchor(@NonNull PopupWindow popupWindow, boolean overlapAnchor) {
IMPL.setOverlapAnchor(popupWindow, overlapAnchor);
}
@@ -234,7 +235,7 @@
*
* @return Whether the popup should overlap its anchor.
*/
- public static boolean getOverlapAnchor(PopupWindow popupWindow) {
+ public static boolean getOverlapAnchor(@NonNull PopupWindow popupWindow) {
return IMPL.getOverlapAnchor(popupWindow);
}
@@ -247,7 +248,7 @@
*
* @see android.view.WindowManager.LayoutParams#type
*/
- public static void setWindowLayoutType(PopupWindow popupWindow, int layoutType) {
+ public static void setWindowLayoutType(@NonNull PopupWindow popupWindow, int layoutType) {
IMPL.setWindowLayoutType(popupWindow, layoutType);
}
@@ -256,7 +257,7 @@
*
* @see #setWindowLayoutType(PopupWindow popupWindow, int)
*/
- public static int getWindowLayoutType(PopupWindow popupWindow) {
+ public static int getWindowLayoutType(@NonNull PopupWindow popupWindow) {
return IMPL.getWindowLayoutType(popupWindow);
}
}
diff --git a/compat/java/android/support/v4/widget/TextViewCompat.java b/compat/java/android/support/v4/widget/TextViewCompat.java
index 8d9e4ab..dc87a38 100644
--- a/compat/java/android/support/v4/widget/TextViewCompat.java
+++ b/compat/java/android/support/v4/widget/TextViewCompat.java
@@ -479,6 +479,7 @@
/**
* Returns drawables for the start, top, end, and bottom borders from the given text view.
*/
+ @NonNull
public static Drawable[] getCompoundDrawablesRelative(@NonNull TextView textView) {
return IMPL.getCompoundDrawablesRelative(textView);
}
@@ -493,7 +494,8 @@
*
* @attr name android:autoSizeTextType
*/
- public static void setAutoSizeTextTypeWithDefaults(TextView textView, int autoSizeTextType) {
+ public static void setAutoSizeTextTypeWithDefaults(@NonNull TextView textView,
+ int autoSizeTextType) {
IMPL.setAutoSizeTextTypeWithDefaults(textView, autoSizeTextType);
}
@@ -519,7 +521,7 @@
* @attr name android:autoSizeStepGranularity
*/
public static void setAutoSizeTextTypeUniformWithConfiguration(
- TextView textView,
+ @NonNull TextView textView,
int autoSizeMinTextSize,
int autoSizeMaxTextSize,
int autoSizeStepGranularity,
@@ -542,7 +544,7 @@
* @attr name android:autoSizeTextType
* @attr name android:autoSizePresetSizes
*/
- public static void setAutoSizeTextTypeUniformWithPresetSizes(TextView textView,
+ public static void setAutoSizeTextTypeUniformWithPresetSizes(@NonNull TextView textView,
@NonNull int[] presetSizes, int unit) throws IllegalArgumentException {
IMPL.setAutoSizeTextTypeUniformWithPresetSizes(textView, presetSizes, unit);
}
@@ -556,7 +558,7 @@
*
* @attr name android:autoSizeTextType
*/
- public static int getAutoSizeTextType(TextView textView) {
+ public static int getAutoSizeTextType(@NonNull TextView textView) {
return IMPL.getAutoSizeTextType(textView);
}
@@ -565,7 +567,7 @@
*
* @attr name android:autoSizeStepGranularity
*/
- public static int getAutoSizeStepGranularity(TextView textView) {
+ public static int getAutoSizeStepGranularity(@NonNull TextView textView) {
return IMPL.getAutoSizeStepGranularity(textView);
}
@@ -575,7 +577,7 @@
*
* @attr name android:autoSizeMinTextSize
*/
- public static int getAutoSizeMinTextSize(TextView textView) {
+ public static int getAutoSizeMinTextSize(@NonNull TextView textView) {
return IMPL.getAutoSizeMinTextSize(textView);
}
@@ -585,7 +587,7 @@
*
* @attr name android:autoSizeMaxTextSize
*/
- public static int getAutoSizeMaxTextSize(TextView textView) {
+ public static int getAutoSizeMaxTextSize(@NonNull TextView textView) {
return IMPL.getAutoSizeMaxTextSize(textView);
}
@@ -594,7 +596,8 @@
*
* @attr name android:autoSizePresetSizes
*/
- public static int[] getAutoSizeTextAvailableSizes(TextView textView) {
+ @NonNull
+ public static int[] getAutoSizeTextAvailableSizes(@NonNull TextView textView) {
return IMPL.getAutoSizeTextAvailableSizes(textView);
}
}
diff --git a/core-utils/Android.mk b/core-utils/Android.mk
index 6dda862..a6855fc 100644
--- a/core-utils/Android.mk
+++ b/core-utils/Android.mk
@@ -27,9 +27,7 @@
LOCAL_MODULE := android-support-core-utils
LOCAL_SDK_VERSION := $(SUPPORT_CURRENT_SDK_VERSION)
LOCAL_SRC_FILES := \
- $(call all-java-files-under,kitkat) \
- $(call all-java-files-under,api21) \
- $(call all-java-files-under,java)
+ $(call all-java-files-under,src/main/java)
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
LOCAL_SHARED_ANDROID_LIBRARIES := \
android-support-compat \
diff --git a/core-utils/build.gradle b/core-utils/build.gradle
index 29fe86c..55fe2bb 100644
--- a/core-utils/build.gradle
+++ b/core-utils/build.gradle
@@ -14,14 +14,6 @@
defaultConfig {
minSdkVersion 14
}
-
- sourceSets {
- main.java.srcDirs = [
- 'kitkat',
- 'api21',
- 'java'
- ]
- }
}
supportLibrary {
diff --git a/core-utils/java/android/support/v4/app/AppLaunchChecker.java b/core-utils/src/main/java/android/support/v4/app/AppLaunchChecker.java
similarity index 100%
rename from core-utils/java/android/support/v4/app/AppLaunchChecker.java
rename to core-utils/src/main/java/android/support/v4/app/AppLaunchChecker.java
diff --git a/core-utils/java/android/support/v4/app/FrameMetricsAggregator.java b/core-utils/src/main/java/android/support/v4/app/FrameMetricsAggregator.java
similarity index 100%
rename from core-utils/java/android/support/v4/app/FrameMetricsAggregator.java
rename to core-utils/src/main/java/android/support/v4/app/FrameMetricsAggregator.java
diff --git a/core-utils/java/android/support/v4/app/NavUtils.java b/core-utils/src/main/java/android/support/v4/app/NavUtils.java
similarity index 100%
rename from core-utils/java/android/support/v4/app/NavUtils.java
rename to core-utils/src/main/java/android/support/v4/app/NavUtils.java
diff --git a/core-utils/java/android/support/v4/app/TaskStackBuilder.java b/core-utils/src/main/java/android/support/v4/app/TaskStackBuilder.java
similarity index 100%
rename from core-utils/java/android/support/v4/app/TaskStackBuilder.java
rename to core-utils/src/main/java/android/support/v4/app/TaskStackBuilder.java
diff --git a/core-utils/java/android/support/v4/app/package.html b/core-utils/src/main/java/android/support/v4/app/package.html
similarity index 100%
rename from core-utils/java/android/support/v4/app/package.html
rename to core-utils/src/main/java/android/support/v4/app/package.html
diff --git a/core-utils/java/android/support/v4/content/AsyncTaskLoader.java b/core-utils/src/main/java/android/support/v4/content/AsyncTaskLoader.java
similarity index 100%
rename from core-utils/java/android/support/v4/content/AsyncTaskLoader.java
rename to core-utils/src/main/java/android/support/v4/content/AsyncTaskLoader.java
diff --git a/core-utils/java/android/support/v4/content/CursorLoader.java b/core-utils/src/main/java/android/support/v4/content/CursorLoader.java
similarity index 100%
rename from core-utils/java/android/support/v4/content/CursorLoader.java
rename to core-utils/src/main/java/android/support/v4/content/CursorLoader.java
diff --git a/core-utils/java/android/support/v4/content/FileProvider.java b/core-utils/src/main/java/android/support/v4/content/FileProvider.java
similarity index 100%
rename from core-utils/java/android/support/v4/content/FileProvider.java
rename to core-utils/src/main/java/android/support/v4/content/FileProvider.java
diff --git a/core-utils/java/android/support/v4/content/Loader.java b/core-utils/src/main/java/android/support/v4/content/Loader.java
similarity index 100%
rename from core-utils/java/android/support/v4/content/Loader.java
rename to core-utils/src/main/java/android/support/v4/content/Loader.java
diff --git a/core-utils/java/android/support/v4/content/LocalBroadcastManager.java b/core-utils/src/main/java/android/support/v4/content/LocalBroadcastManager.java
similarity index 100%
rename from core-utils/java/android/support/v4/content/LocalBroadcastManager.java
rename to core-utils/src/main/java/android/support/v4/content/LocalBroadcastManager.java
diff --git a/core-utils/java/android/support/v4/content/MimeTypeFilter.java b/core-utils/src/main/java/android/support/v4/content/MimeTypeFilter.java
similarity index 100%
rename from core-utils/java/android/support/v4/content/MimeTypeFilter.java
rename to core-utils/src/main/java/android/support/v4/content/MimeTypeFilter.java
diff --git a/core-utils/java/android/support/v4/content/ModernAsyncTask.java b/core-utils/src/main/java/android/support/v4/content/ModernAsyncTask.java
similarity index 100%
rename from core-utils/java/android/support/v4/content/ModernAsyncTask.java
rename to core-utils/src/main/java/android/support/v4/content/ModernAsyncTask.java
diff --git a/core-utils/java/android/support/v4/content/PermissionChecker.java b/core-utils/src/main/java/android/support/v4/content/PermissionChecker.java
similarity index 100%
rename from core-utils/java/android/support/v4/content/PermissionChecker.java
rename to core-utils/src/main/java/android/support/v4/content/PermissionChecker.java
diff --git a/core-utils/java/android/support/v4/content/WakefulBroadcastReceiver.java b/core-utils/src/main/java/android/support/v4/content/WakefulBroadcastReceiver.java
similarity index 100%
rename from core-utils/java/android/support/v4/content/WakefulBroadcastReceiver.java
rename to core-utils/src/main/java/android/support/v4/content/WakefulBroadcastReceiver.java
diff --git a/core-utils/java/android/support/v4/content/package.html b/core-utils/src/main/java/android/support/v4/content/package.html
similarity index 100%
rename from core-utils/java/android/support/v4/content/package.html
rename to core-utils/src/main/java/android/support/v4/content/package.html
diff --git a/core-utils/java/android/support/v4/graphics/ColorUtils.java b/core-utils/src/main/java/android/support/v4/graphics/ColorUtils.java
similarity index 100%
rename from core-utils/java/android/support/v4/graphics/ColorUtils.java
rename to core-utils/src/main/java/android/support/v4/graphics/ColorUtils.java
diff --git a/core-utils/java/android/support/v4/graphics/drawable/RoundedBitmapDrawable.java b/core-utils/src/main/java/android/support/v4/graphics/drawable/RoundedBitmapDrawable.java
similarity index 100%
rename from core-utils/java/android/support/v4/graphics/drawable/RoundedBitmapDrawable.java
rename to core-utils/src/main/java/android/support/v4/graphics/drawable/RoundedBitmapDrawable.java
diff --git a/core-utils/api21/android/support/v4/graphics/drawable/RoundedBitmapDrawable21.java b/core-utils/src/main/java/android/support/v4/graphics/drawable/RoundedBitmapDrawable21.java
similarity index 100%
rename from core-utils/api21/android/support/v4/graphics/drawable/RoundedBitmapDrawable21.java
rename to core-utils/src/main/java/android/support/v4/graphics/drawable/RoundedBitmapDrawable21.java
diff --git a/core-utils/java/android/support/v4/graphics/drawable/RoundedBitmapDrawableFactory.java b/core-utils/src/main/java/android/support/v4/graphics/drawable/RoundedBitmapDrawableFactory.java
similarity index 100%
rename from core-utils/java/android/support/v4/graphics/drawable/RoundedBitmapDrawableFactory.java
rename to core-utils/src/main/java/android/support/v4/graphics/drawable/RoundedBitmapDrawableFactory.java
diff --git a/core-utils/java/android/support/v4/math/MathUtils.java b/core-utils/src/main/java/android/support/v4/math/MathUtils.java
similarity index 100%
rename from core-utils/java/android/support/v4/math/MathUtils.java
rename to core-utils/src/main/java/android/support/v4/math/MathUtils.java
diff --git a/core-utils/java/android/support/v4/print/PrintHelper.java b/core-utils/src/main/java/android/support/v4/print/PrintHelper.java
similarity index 100%
rename from core-utils/java/android/support/v4/print/PrintHelper.java
rename to core-utils/src/main/java/android/support/v4/print/PrintHelper.java
diff --git a/core-utils/java/android/support/v4/provider/DocumentFile.java b/core-utils/src/main/java/android/support/v4/provider/DocumentFile.java
similarity index 100%
rename from core-utils/java/android/support/v4/provider/DocumentFile.java
rename to core-utils/src/main/java/android/support/v4/provider/DocumentFile.java
diff --git a/core-utils/kitkat/android/support/v4/provider/DocumentsContractApi19.java b/core-utils/src/main/java/android/support/v4/provider/DocumentsContractApi19.java
similarity index 100%
rename from core-utils/kitkat/android/support/v4/provider/DocumentsContractApi19.java
rename to core-utils/src/main/java/android/support/v4/provider/DocumentsContractApi19.java
diff --git a/core-utils/java/android/support/v4/provider/RawDocumentFile.java b/core-utils/src/main/java/android/support/v4/provider/RawDocumentFile.java
similarity index 100%
rename from core-utils/java/android/support/v4/provider/RawDocumentFile.java
rename to core-utils/src/main/java/android/support/v4/provider/RawDocumentFile.java
diff --git a/core-utils/java/android/support/v4/provider/SingleDocumentFile.java b/core-utils/src/main/java/android/support/v4/provider/SingleDocumentFile.java
similarity index 100%
rename from core-utils/java/android/support/v4/provider/SingleDocumentFile.java
rename to core-utils/src/main/java/android/support/v4/provider/SingleDocumentFile.java
diff --git a/core-utils/java/android/support/v4/provider/TreeDocumentFile.java b/core-utils/src/main/java/android/support/v4/provider/TreeDocumentFile.java
similarity index 100%
rename from core-utils/java/android/support/v4/provider/TreeDocumentFile.java
rename to core-utils/src/main/java/android/support/v4/provider/TreeDocumentFile.java
diff --git a/customtabs/api/current.txt b/customtabs/api/current.txt
index 58cd212..05c16c1 100644
--- a/customtabs/api/current.txt
+++ b/customtabs/api/current.txt
@@ -6,6 +6,7 @@
method public void onMessageChannelReady(android.os.Bundle);
method public void onNavigationEvent(int, android.os.Bundle);
method public void onPostMessage(java.lang.String, android.os.Bundle);
+ method public void onRelationshipValidationResult(int, android.net.Uri, boolean, android.os.Bundle);
field public static final int NAVIGATION_ABORTED = 4; // 0x4
field public static final int NAVIGATION_FAILED = 3; // 0x3
field public static final int NAVIGATION_FINISHED = 2; // 0x2
@@ -88,15 +89,21 @@
method protected abstract int postMessage(android.support.customtabs.CustomTabsSessionToken, java.lang.String, android.os.Bundle);
method protected abstract boolean requestPostMessageChannel(android.support.customtabs.CustomTabsSessionToken, android.net.Uri);
method protected abstract boolean updateVisuals(android.support.customtabs.CustomTabsSessionToken, android.os.Bundle);
+ method protected abstract boolean validateRelationship(android.support.customtabs.CustomTabsSessionToken, int, android.net.Uri, android.os.Bundle);
method protected abstract boolean warmup(long);
field public static final java.lang.String ACTION_CUSTOM_TABS_CONNECTION = "android.support.customtabs.action.CustomTabsService";
field public static final java.lang.String KEY_URL = "android.support.customtabs.otherurls.URL";
+ field public static final int RELATION_HANDLE_ALL_URLS = 2; // 0x2
+ field public static final int RELATION_USE_AS_ORIGIN = 1; // 0x1
field public static final int RESULT_FAILURE_DISALLOWED = -1; // 0xffffffff
field public static final int RESULT_FAILURE_MESSAGING_ERROR = -3; // 0xfffffffd
field public static final int RESULT_FAILURE_REMOTE_ERROR = -2; // 0xfffffffe
field public static final int RESULT_SUCCESS = 0; // 0x0
}
+ public static abstract class CustomTabsService.Relation implements java.lang.annotation.Annotation {
+ }
+
public static abstract class CustomTabsService.Result implements java.lang.annotation.Annotation {
}
@@ -113,6 +120,7 @@
method public boolean setActionButton(android.graphics.Bitmap, java.lang.String);
method public boolean setSecondaryToolbarViews(android.widget.RemoteViews, int[], android.app.PendingIntent);
method public deprecated boolean setToolbarItem(int, android.graphics.Bitmap, java.lang.String);
+ method public boolean validateRelationship(int, android.net.Uri, android.os.Bundle);
}
public class CustomTabsSessionToken {
diff --git a/customtabs/src/android/support/customtabs/CustomTabsCallback.java b/customtabs/src/android/support/customtabs/CustomTabsCallback.java
index 818118a..f8d349a 100644
--- a/customtabs/src/android/support/customtabs/CustomTabsCallback.java
+++ b/customtabs/src/android/support/customtabs/CustomTabsCallback.java
@@ -16,7 +16,9 @@
package android.support.customtabs;
+import android.net.Uri;
import android.os.Bundle;
+import android.support.customtabs.CustomTabsService.Relation;
/**
* A callback class for custom tabs client to get messages regarding events in their custom tabs. In
@@ -98,4 +100,18 @@
* @param extras Reserved for future use.
*/
public void onPostMessage(String message, Bundle extras) {}
+
+ /**
+ * Called when a relationship validation result is available.
+ *
+ * @param relation Relation for which the result is available. Value previously passed to
+ * {@link CustomTabsSession#validateRelationship(int, Uri, Bundle)}. Must be one
+ * of the {@code CustomTabsService#RELATION_* } constants.
+ * @param requestedOrigin Origin requested. Value previously passed to
+ * {@link CustomTabsSession#validateRelationship(int, Uri, Bundle)}.
+ * @param result Whether the relation was validated.
+ * @param extras Reserved for future use.
+ */
+ public void onRelationshipValidationResult(@Relation int relation, Uri requestedOrigin,
+ boolean result, Bundle extras) {}
}
diff --git a/customtabs/src/android/support/customtabs/CustomTabsClient.java b/customtabs/src/android/support/customtabs/CustomTabsClient.java
index 09f3110..2e955cb 100644
--- a/customtabs/src/android/support/customtabs/CustomTabsClient.java
+++ b/customtabs/src/android/support/customtabs/CustomTabsClient.java
@@ -31,6 +31,7 @@
import android.os.RemoteException;
import android.support.annotation.Nullable;
import android.support.annotation.RestrictTo;
+import android.support.customtabs.CustomTabsService.Relation;
import android.text.TextUtils;
import java.util.ArrayList;
@@ -234,6 +235,20 @@
}
});
}
+
+ @Override
+ public void onRelationshipValidationResult(
+ final @Relation int relation, final Uri requestedOrigin, final boolean result,
+ final @Nullable Bundle extras) throws RemoteException {
+ if (callback == null) return;
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ callback.onRelationshipValidationResult(
+ relation, requestedOrigin, result, extras);
+ }
+ });
+ }
};
try {
diff --git a/customtabs/src/android/support/customtabs/CustomTabsService.java b/customtabs/src/android/support/customtabs/CustomTabsService.java
index 5a940cf..aad174c 100644
--- a/customtabs/src/android/support/customtabs/CustomTabsService.java
+++ b/customtabs/src/android/support/customtabs/CustomTabsService.java
@@ -78,6 +78,23 @@
*/
public static final int RESULT_FAILURE_MESSAGING_ERROR = -3;
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({RELATION_USE_AS_ORIGIN, RELATION_HANDLE_ALL_URLS})
+ public @interface Relation {
+ }
+
+ /**
+ * Used for {@link CustomTabsSession#validateRelationship(int, Uri, Bundle)}. For
+ * App -> Web transitions, requests the app to use the declared origin to be used as origin for
+ * the client app in the web APIs context.
+ */
+ public static final int RELATION_USE_AS_ORIGIN = 1;
+ /**
+ * Used for {@link CustomTabsSession#validateRelationship(int, Uri, Bundle)}. Requests the
+ * ability to handle all URLs from a given origin.
+ */
+ public static final int RELATION_HANDLE_ALL_URLS = 2;
+
private final Map<IBinder, DeathRecipient> mDeathRecipientMap = new ArrayMap<>();
private ICustomTabsService.Stub mBinder = new ICustomTabsService.Stub() {
@@ -137,6 +154,13 @@
return CustomTabsService.this.postMessage(
new CustomTabsSessionToken(callback), message, extras);
}
+
+ @Override
+ public boolean validateRelationship(
+ ICustomTabsCallback callback, @Relation int relation, Uri origin, Bundle extras) {
+ return CustomTabsService.this.validateRelationship(
+ new CustomTabsSessionToken(callback), relation, origin, extras);
+ }
};
@Override
@@ -268,4 +292,23 @@
@Result
protected abstract int postMessage(
CustomTabsSessionToken sessionToken, String message, Bundle extras);
+
+ /**
+ * Request to validate a relationship between the application and an origin.
+ *
+ * If this method returns true, the validation result will be provided through
+ * {@link CustomTabsCallback#onRelationshipValidationResult(int, Uri, boolean, Bundle)}.
+ * Otherwise the request didn't succeed. The client must call
+ * {@link CustomTabsClient#warmup(long)} before this.
+ *
+ * @param sessionToken The unique identifier for the session. Can not be null.
+ * @param relation Relation to check, must be one of the {@code CustomTabsService#RELATION_* }
+ * constants.
+ * @param origin Origin for the relation query.
+ * @param extras Reserved for future use.
+ * @return true if the request has been submitted successfully.
+ */
+ protected abstract boolean validateRelationship(
+ CustomTabsSessionToken sessionToken, @Relation int relation, Uri origin,
+ Bundle extras);
}
diff --git a/customtabs/src/android/support/customtabs/CustomTabsSession.java b/customtabs/src/android/support/customtabs/CustomTabsSession.java
index cad897c..d4930ae 100644
--- a/customtabs/src/android/support/customtabs/CustomTabsSession.java
+++ b/customtabs/src/android/support/customtabs/CustomTabsSession.java
@@ -25,6 +25,7 @@
import android.os.RemoteException;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
+import android.support.customtabs.CustomTabsService.Relation;
import android.support.customtabs.CustomTabsService.Result;
import android.view.View;
import android.widget.RemoteViews;
@@ -185,6 +186,39 @@
}
}
+ /**
+ * Requests to validate a relationship between the application and an origin.
+ *
+ * <p>
+ * See <a href="https://developers.google.com/digital-asset-links/v1/getting-started">here</a>
+ * for documentation about Digital Asset Links. This methods requests the browser to verify
+ * a relation with the calling application, to grant the associated rights.
+ *
+ * <p>
+ * If this method returns {@code true}, the validation result will be provided through
+ * {@link CustomTabsCallback#onRelationshipValidationResult(int, Uri, boolean, Bundle)}.
+ * Otherwise the request didn't succeed. The client must call
+ * {@link CustomTabsClient#warmup(long)} before this.
+ *
+ * @param relation Relation to check, must be one of the {@code CustomTabsService#RELATION_* }
+ * constants.
+ * @param origin Origin.
+ * @param extras Reserved for future use.
+ * @return {@code true} if the request has been submitted successfully.
+ */
+ public boolean validateRelationship(@Relation int relation, @NonNull Uri origin,
+ @Nullable Bundle extras) {
+ if (relation < CustomTabsService.RELATION_USE_AS_ORIGIN
+ || relation > CustomTabsService.RELATION_HANDLE_ALL_URLS) {
+ return false;
+ }
+ try {
+ return mService.validateRelationship(mCallback, relation, origin, extras);
+ } catch (RemoteException e) {
+ return false;
+ }
+ }
+
/* package */ IBinder getBinder() {
return mCallback.asBinder();
}
diff --git a/customtabs/src/android/support/customtabs/CustomTabsSessionToken.java b/customtabs/src/android/support/customtabs/CustomTabsSessionToken.java
index adfadd9..ee47278 100644
--- a/customtabs/src/android/support/customtabs/CustomTabsSessionToken.java
+++ b/customtabs/src/android/support/customtabs/CustomTabsSessionToken.java
@@ -17,9 +17,11 @@
package android.support.customtabs;
import android.content.Intent;
+import android.net.Uri;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
+import android.support.customtabs.CustomTabsService.Relation;
import android.support.v4.app.BundleCompat;
import android.util.Log;
@@ -85,6 +87,18 @@
Log.e(TAG, "RemoteException during ICustomTabsCallback transaction");
}
}
+
+ @Override
+ public void onRelationshipValidationResult(@Relation int relation, Uri origin,
+ boolean result, Bundle extras) {
+ try {
+ mCallbackBinder.onRelationshipValidationResult(
+ relation, origin, result, extras);
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException during ICustomTabsCallback transaction");
+ }
+ }
+
};
}
diff --git a/customtabs/src/android/support/customtabs/ICustomTabsCallback.aidl b/customtabs/src/android/support/customtabs/ICustomTabsCallback.aidl
index 32b6e9b..3e2c48c 100644
--- a/customtabs/src/android/support/customtabs/ICustomTabsCallback.aidl
+++ b/customtabs/src/android/support/customtabs/ICustomTabsCallback.aidl
@@ -27,4 +27,5 @@
void extraCallback(String callbackName, in Bundle args) = 2;
void onMessageChannelReady(in Bundle extras) = 3;
void onPostMessage(String message, in Bundle extras) = 4;
+ void onRelationshipValidationResult(int relation, in Uri origin, boolean result, in Bundle extras) = 5;
}
diff --git a/customtabs/src/android/support/customtabs/ICustomTabsService.aidl b/customtabs/src/android/support/customtabs/ICustomTabsService.aidl
index b24b0dd..376c2a4 100644
--- a/customtabs/src/android/support/customtabs/ICustomTabsService.aidl
+++ b/customtabs/src/android/support/customtabs/ICustomTabsService.aidl
@@ -36,4 +36,5 @@
boolean updateVisuals(in ICustomTabsCallback callback, in Bundle bundle) = 5;
boolean requestPostMessageChannel(in ICustomTabsCallback callback, in Uri postMessageOrigin) = 6;
int postMessage(in ICustomTabsCallback callback, String message, in Bundle extras) = 7;
+ boolean validateRelationship(in ICustomTabsCallback callback, int relation, in Uri origin, in Bundle extras) = 8;
}
diff --git a/customtabs/tests/src/android/support/customtabs/TestCustomTabsCallback.java b/customtabs/tests/src/android/support/customtabs/TestCustomTabsCallback.java
index 56b1817..804d354 100644
--- a/customtabs/tests/src/android/support/customtabs/TestCustomTabsCallback.java
+++ b/customtabs/tests/src/android/support/customtabs/TestCustomTabsCallback.java
@@ -16,6 +16,7 @@
package android.support.customtabs;
+import android.net.Uri;
import android.os.Bundle;
import android.os.RemoteException;
@@ -50,6 +51,13 @@
throws RemoteException {
TestCustomTabsCallback.this.onPostMessage(message, extras);
}
+
+ @Override
+ public void onRelationshipValidationResult(int relation, Uri origin, boolean result,
+ Bundle extras) throws RemoteException {
+ TestCustomTabsCallback.this.onRelationshipValidationResult(
+ relation, origin, result, extras);
+ }
};
/* package */ ICustomTabsCallback getStub() {
diff --git a/customtabs/tests/src/android/support/customtabs/TestCustomTabsService.java b/customtabs/tests/src/android/support/customtabs/TestCustomTabsService.java
index b5c5e86..e3d5fa8 100644
--- a/customtabs/tests/src/android/support/customtabs/TestCustomTabsService.java
+++ b/customtabs/tests/src/android/support/customtabs/TestCustomTabsService.java
@@ -71,4 +71,10 @@
if (!mPostMessageRequested) return CustomTabsService.RESULT_FAILURE_DISALLOWED;
return CustomTabsService.RESULT_SUCCESS;
}
+
+ @Override
+ protected boolean validateRelationship(CustomTabsSessionToken sessionToken,
+ @Relation int relation, Uri origin, Bundle extras) {
+ return false;
+ }
}
diff --git a/emoji/appcompat/Android.mk b/emoji/appcompat/Android.mk
index 54f6b14..f04d158 100644
--- a/emoji/appcompat/Android.mk
+++ b/emoji/appcompat/Android.mk
@@ -29,7 +29,7 @@
LOCAL_USE_AAPT2 := true
LOCAL_MODULE := android-support-emoji-appcompat
LOCAL_SDK_VERSION := $(SUPPORT_CURRENT_SDK_VERSION)
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_SRC_FILES := $(call all-java-files-under, src/main/java)
LOCAL_SHARED_ANDROID_LIBRARIES := \
android-support-annotations \
android-support-v7-appcompat \
diff --git a/emoji/appcompat/build.gradle b/emoji/appcompat/build.gradle
index 9b6e0d4..e22000c 100644
--- a/emoji/appcompat/build.gradle
+++ b/emoji/appcompat/build.gradle
@@ -26,10 +26,6 @@
defaultConfig {
minSdkVersion 14
}
-
- sourceSets {
- main.java.srcDir 'src'
- }
}
supportLibrary {
diff --git a/emoji/appcompat/src/android/support/text/emoji/widget/EmojiAppCompatButton.java b/emoji/appcompat/src/main/java/android/support/text/emoji/widget/EmojiAppCompatButton.java
similarity index 100%
rename from emoji/appcompat/src/android/support/text/emoji/widget/EmojiAppCompatButton.java
rename to emoji/appcompat/src/main/java/android/support/text/emoji/widget/EmojiAppCompatButton.java
diff --git a/emoji/appcompat/src/android/support/text/emoji/widget/EmojiAppCompatEditText.java b/emoji/appcompat/src/main/java/android/support/text/emoji/widget/EmojiAppCompatEditText.java
similarity index 100%
rename from emoji/appcompat/src/android/support/text/emoji/widget/EmojiAppCompatEditText.java
rename to emoji/appcompat/src/main/java/android/support/text/emoji/widget/EmojiAppCompatEditText.java
diff --git a/emoji/appcompat/src/android/support/text/emoji/widget/EmojiAppCompatTextView.java b/emoji/appcompat/src/main/java/android/support/text/emoji/widget/EmojiAppCompatTextView.java
similarity index 100%
rename from emoji/appcompat/src/android/support/text/emoji/widget/EmojiAppCompatTextView.java
rename to emoji/appcompat/src/main/java/android/support/text/emoji/widget/EmojiAppCompatTextView.java
diff --git a/emoji/bundled/Android.mk b/emoji/bundled/Android.mk
index 3b6b181..29f0d58 100644
--- a/emoji/bundled/Android.mk
+++ b/emoji/bundled/Android.mk
@@ -28,7 +28,7 @@
LOCAL_USE_AAPT2 := true
LOCAL_MODULE := android-support-emoji-bundled
LOCAL_SDK_VERSION := $(SUPPORT_CURRENT_SDK_VERSION)
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_SRC_FILES := $(call all-java-files-under, src/main/java)
LOCAL_SHARED_ANDROID_LIBRARIES := \
android-support-annotations \
android-support-emoji \
diff --git a/emoji/bundled/build.gradle b/emoji/bundled/build.gradle
index b882ee1..766d165 100644
--- a/emoji/bundled/build.gradle
+++ b/emoji/bundled/build.gradle
@@ -10,7 +10,6 @@
}
sourceSets {
- main.java.srcDir 'src'
main.assets.srcDirs new File(fontDir, "font").getAbsolutePath()
}
}
diff --git a/emoji/bundled/src/android/support/text/emoji/bundled/BundledEmojiCompatConfig.java b/emoji/bundled/src/main/java/android/support/text/emoji/bundled/BundledEmojiCompatConfig.java
similarity index 100%
rename from emoji/bundled/src/android/support/text/emoji/bundled/BundledEmojiCompatConfig.java
rename to emoji/bundled/src/main/java/android/support/text/emoji/bundled/BundledEmojiCompatConfig.java
diff --git a/emoji/core/Android.mk b/emoji/core/Android.mk
index 774ba29..8b7a032 100644
--- a/emoji/core/Android.mk
+++ b/emoji/core/Android.mk
@@ -27,8 +27,8 @@
LOCAL_USE_AAPT2 := true
LOCAL_MODULE := android-support-emoji
LOCAL_SDK_VERSION := $(SUPPORT_CURRENT_SDK_VERSION)
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
+LOCAL_SRC_FILES := $(call all-java-files-under, src/main/java)
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/src/main/res
LOCAL_STATIC_JAVA_LIBRARIES := \
noto-emoji-compat-java
LOCAL_SHARED_ANDROID_LIBRARIES := \
diff --git a/emoji/core/build.gradle b/emoji/core/build.gradle
index c0881d2..b4cd3fc 100644
--- a/emoji/core/build.gradle
+++ b/emoji/core/build.gradle
@@ -29,10 +29,7 @@
}
sourceSets {
- main.java {
- srcDirs = ['src']
- }
- main.res.srcDirs = ['res', 'res-public']
+ main.res.srcDirs += 'src/main/res-public'
main.resources {
srcDirs = [fontDir.getAbsolutePath()]
includes = ["LICENSE_UNICODE", "LICENSE_OFL"]
diff --git a/emoji/core/src/android/support/text/emoji/EmojiCompat.java b/emoji/core/src/main/java/android/support/text/emoji/EmojiCompat.java
similarity index 100%
rename from emoji/core/src/android/support/text/emoji/EmojiCompat.java
rename to emoji/core/src/main/java/android/support/text/emoji/EmojiCompat.java
diff --git a/emoji/core/src/android/support/text/emoji/EmojiMetadata.java b/emoji/core/src/main/java/android/support/text/emoji/EmojiMetadata.java
similarity index 100%
rename from emoji/core/src/android/support/text/emoji/EmojiMetadata.java
rename to emoji/core/src/main/java/android/support/text/emoji/EmojiMetadata.java
diff --git a/emoji/core/src/android/support/text/emoji/EmojiProcessor.java b/emoji/core/src/main/java/android/support/text/emoji/EmojiProcessor.java
similarity index 100%
rename from emoji/core/src/android/support/text/emoji/EmojiProcessor.java
rename to emoji/core/src/main/java/android/support/text/emoji/EmojiProcessor.java
diff --git a/emoji/core/src/android/support/text/emoji/EmojiSpan.java b/emoji/core/src/main/java/android/support/text/emoji/EmojiSpan.java
similarity index 100%
rename from emoji/core/src/android/support/text/emoji/EmojiSpan.java
rename to emoji/core/src/main/java/android/support/text/emoji/EmojiSpan.java
diff --git a/emoji/core/src/android/support/text/emoji/FontRequestEmojiCompatConfig.java b/emoji/core/src/main/java/android/support/text/emoji/FontRequestEmojiCompatConfig.java
similarity index 100%
rename from emoji/core/src/android/support/text/emoji/FontRequestEmojiCompatConfig.java
rename to emoji/core/src/main/java/android/support/text/emoji/FontRequestEmojiCompatConfig.java
diff --git a/emoji/core/src/android/support/text/emoji/MetadataListReader.java b/emoji/core/src/main/java/android/support/text/emoji/MetadataListReader.java
similarity index 100%
rename from emoji/core/src/android/support/text/emoji/MetadataListReader.java
rename to emoji/core/src/main/java/android/support/text/emoji/MetadataListReader.java
diff --git a/emoji/core/src/android/support/text/emoji/MetadataRepo.java b/emoji/core/src/main/java/android/support/text/emoji/MetadataRepo.java
similarity index 100%
rename from emoji/core/src/android/support/text/emoji/MetadataRepo.java
rename to emoji/core/src/main/java/android/support/text/emoji/MetadataRepo.java
diff --git a/emoji/core/src/android/support/text/emoji/TypefaceEmojiSpan.java b/emoji/core/src/main/java/android/support/text/emoji/TypefaceEmojiSpan.java
similarity index 100%
rename from emoji/core/src/android/support/text/emoji/TypefaceEmojiSpan.java
rename to emoji/core/src/main/java/android/support/text/emoji/TypefaceEmojiSpan.java
diff --git a/emoji/core/src/android/support/text/emoji/widget/EditTextAttributeHelper.java b/emoji/core/src/main/java/android/support/text/emoji/widget/EditTextAttributeHelper.java
similarity index 100%
rename from emoji/core/src/android/support/text/emoji/widget/EditTextAttributeHelper.java
rename to emoji/core/src/main/java/android/support/text/emoji/widget/EditTextAttributeHelper.java
diff --git a/emoji/core/src/android/support/text/emoji/widget/EmojiButton.java b/emoji/core/src/main/java/android/support/text/emoji/widget/EmojiButton.java
similarity index 100%
rename from emoji/core/src/android/support/text/emoji/widget/EmojiButton.java
rename to emoji/core/src/main/java/android/support/text/emoji/widget/EmojiButton.java
diff --git a/emoji/core/src/android/support/text/emoji/widget/EmojiEditText.java b/emoji/core/src/main/java/android/support/text/emoji/widget/EmojiEditText.java
similarity index 100%
rename from emoji/core/src/android/support/text/emoji/widget/EmojiEditText.java
rename to emoji/core/src/main/java/android/support/text/emoji/widget/EmojiEditText.java
diff --git a/emoji/core/src/android/support/text/emoji/widget/EmojiEditTextHelper.java b/emoji/core/src/main/java/android/support/text/emoji/widget/EmojiEditTextHelper.java
similarity index 100%
rename from emoji/core/src/android/support/text/emoji/widget/EmojiEditTextHelper.java
rename to emoji/core/src/main/java/android/support/text/emoji/widget/EmojiEditTextHelper.java
diff --git a/emoji/core/src/android/support/text/emoji/widget/EmojiEditableFactory.java b/emoji/core/src/main/java/android/support/text/emoji/widget/EmojiEditableFactory.java
similarity index 100%
rename from emoji/core/src/android/support/text/emoji/widget/EmojiEditableFactory.java
rename to emoji/core/src/main/java/android/support/text/emoji/widget/EmojiEditableFactory.java
diff --git a/emoji/core/src/android/support/text/emoji/widget/EmojiExtractEditText.java b/emoji/core/src/main/java/android/support/text/emoji/widget/EmojiExtractEditText.java
similarity index 100%
rename from emoji/core/src/android/support/text/emoji/widget/EmojiExtractEditText.java
rename to emoji/core/src/main/java/android/support/text/emoji/widget/EmojiExtractEditText.java
diff --git a/emoji/core/src/android/support/text/emoji/widget/EmojiExtractTextLayout.java b/emoji/core/src/main/java/android/support/text/emoji/widget/EmojiExtractTextLayout.java
similarity index 100%
rename from emoji/core/src/android/support/text/emoji/widget/EmojiExtractTextLayout.java
rename to emoji/core/src/main/java/android/support/text/emoji/widget/EmojiExtractTextLayout.java
diff --git a/emoji/core/src/android/support/text/emoji/widget/EmojiInputConnection.java b/emoji/core/src/main/java/android/support/text/emoji/widget/EmojiInputConnection.java
similarity index 100%
rename from emoji/core/src/android/support/text/emoji/widget/EmojiInputConnection.java
rename to emoji/core/src/main/java/android/support/text/emoji/widget/EmojiInputConnection.java
diff --git a/emoji/core/src/android/support/text/emoji/widget/EmojiInputFilter.java b/emoji/core/src/main/java/android/support/text/emoji/widget/EmojiInputFilter.java
similarity index 100%
rename from emoji/core/src/android/support/text/emoji/widget/EmojiInputFilter.java
rename to emoji/core/src/main/java/android/support/text/emoji/widget/EmojiInputFilter.java
diff --git a/emoji/core/src/android/support/text/emoji/widget/EmojiKeyListener.java b/emoji/core/src/main/java/android/support/text/emoji/widget/EmojiKeyListener.java
similarity index 100%
rename from emoji/core/src/android/support/text/emoji/widget/EmojiKeyListener.java
rename to emoji/core/src/main/java/android/support/text/emoji/widget/EmojiKeyListener.java
diff --git a/emoji/core/src/android/support/text/emoji/widget/EmojiTextView.java b/emoji/core/src/main/java/android/support/text/emoji/widget/EmojiTextView.java
similarity index 100%
rename from emoji/core/src/android/support/text/emoji/widget/EmojiTextView.java
rename to emoji/core/src/main/java/android/support/text/emoji/widget/EmojiTextView.java
diff --git a/emoji/core/src/android/support/text/emoji/widget/EmojiTextViewHelper.java b/emoji/core/src/main/java/android/support/text/emoji/widget/EmojiTextViewHelper.java
similarity index 100%
rename from emoji/core/src/android/support/text/emoji/widget/EmojiTextViewHelper.java
rename to emoji/core/src/main/java/android/support/text/emoji/widget/EmojiTextViewHelper.java
diff --git a/emoji/core/src/android/support/text/emoji/widget/EmojiTextWatcher.java b/emoji/core/src/main/java/android/support/text/emoji/widget/EmojiTextWatcher.java
similarity index 100%
rename from emoji/core/src/android/support/text/emoji/widget/EmojiTextWatcher.java
rename to emoji/core/src/main/java/android/support/text/emoji/widget/EmojiTextWatcher.java
diff --git a/emoji/core/src/android/support/text/emoji/widget/EmojiTransformationMethod.java b/emoji/core/src/main/java/android/support/text/emoji/widget/EmojiTransformationMethod.java
similarity index 100%
rename from emoji/core/src/android/support/text/emoji/widget/EmojiTransformationMethod.java
rename to emoji/core/src/main/java/android/support/text/emoji/widget/EmojiTransformationMethod.java
diff --git a/emoji/core/src/android/support/text/emoji/widget/ExtractButtonCompat.java b/emoji/core/src/main/java/android/support/text/emoji/widget/ExtractButtonCompat.java
similarity index 100%
rename from emoji/core/src/android/support/text/emoji/widget/ExtractButtonCompat.java
rename to emoji/core/src/main/java/android/support/text/emoji/widget/ExtractButtonCompat.java
diff --git a/emoji/core/src/android/support/text/emoji/widget/SpannableBuilder.java b/emoji/core/src/main/java/android/support/text/emoji/widget/SpannableBuilder.java
similarity index 100%
rename from emoji/core/src/android/support/text/emoji/widget/SpannableBuilder.java
rename to emoji/core/src/main/java/android/support/text/emoji/widget/SpannableBuilder.java
diff --git a/emoji/core/res-public/values/public_attrs.xml b/emoji/core/src/main/res-public/values/public_attrs.xml
similarity index 100%
rename from emoji/core/res-public/values/public_attrs.xml
rename to emoji/core/src/main/res-public/values/public_attrs.xml
diff --git a/emoji/core/res/layout/input_method_extract_view.xml b/emoji/core/src/main/res/layout/input_method_extract_view.xml
similarity index 100%
rename from emoji/core/res/layout/input_method_extract_view.xml
rename to emoji/core/src/main/res/layout/input_method_extract_view.xml
diff --git a/emoji/core/res/values/attrs.xml b/emoji/core/src/main/res/values/attrs.xml
similarity index 100%
rename from emoji/core/res/values/attrs.xml
rename to emoji/core/src/main/res/values/attrs.xml
diff --git a/lifecycle/extensions/build.gradle b/lifecycle/extensions/build.gradle
index 241e99a..9d33e55 100644
--- a/lifecycle/extensions/build.gradle
+++ b/lifecycle/extensions/build.gradle
@@ -39,11 +39,11 @@
}
}
dependencies {
- compile project(":lifecycle:common")
compile project(":lifecycle:runtime")
compile project(":arch:common")
compile project(":arch:runtime")
compile libs.support.fragments, libs.support_exclude_config
+ compile project(":lifecycle:common")
annotationProcessor project(":lifecycle:compiler")
diff --git a/lifecycle/extensions/src/main/java/android/arch/lifecycle/ComputableLiveData.java b/lifecycle/extensions/src/main/java/android/arch/lifecycle/ComputableLiveData.java
index fe18243..1ddcb1a 100644
--- a/lifecycle/extensions/src/main/java/android/arch/lifecycle/ComputableLiveData.java
+++ b/lifecycle/extensions/src/main/java/android/arch/lifecycle/ComputableLiveData.java
@@ -16,7 +16,7 @@
package android.arch.lifecycle;
-import android.arch.core.executor.AppToolkitTaskExecutor;
+import android.arch.core.executor.ArchTaskExecutor;
import android.support.annotation.MainThread;
import android.support.annotation.NonNull;
import android.support.annotation.RestrictTo;
@@ -53,7 +53,7 @@
@Override
protected void onActive() {
// TODO if we make this class public, we should accept an executor
- AppToolkitTaskExecutor.getInstance().executeOnDiskIO(mRefreshRunnable);
+ ArchTaskExecutor.getInstance().executeOnDiskIO(mRefreshRunnable);
}
};
}
@@ -115,7 +115,7 @@
if (mInvalid.compareAndSet(false, true)) {
if (isActive) {
// TODO if we make this class public, we should accept an executor.
- AppToolkitTaskExecutor.getInstance().executeOnDiskIO(mRefreshRunnable);
+ ArchTaskExecutor.getInstance().executeOnDiskIO(mRefreshRunnable);
}
}
}
@@ -127,7 +127,7 @@
* When there are active observers, this will trigger a call to {@link #compute()}.
*/
public void invalidate() {
- AppToolkitTaskExecutor.getInstance().executeOnMainThread(mInvalidationRunnable);
+ ArchTaskExecutor.getInstance().executeOnMainThread(mInvalidationRunnable);
}
@SuppressWarnings("WeakerAccess")
diff --git a/lifecycle/extensions/src/main/java/android/arch/lifecycle/LiveData.java b/lifecycle/extensions/src/main/java/android/arch/lifecycle/LiveData.java
index 99d859c..da5600c 100644
--- a/lifecycle/extensions/src/main/java/android/arch/lifecycle/LiveData.java
+++ b/lifecycle/extensions/src/main/java/android/arch/lifecycle/LiveData.java
@@ -19,7 +19,7 @@
import static android.arch.lifecycle.Lifecycle.State.DESTROYED;
import static android.arch.lifecycle.Lifecycle.State.STARTED;
-import android.arch.core.executor.AppToolkitTaskExecutor;
+import android.arch.core.executor.ArchTaskExecutor;
import android.arch.core.internal.SafeIterableMap;
import android.arch.lifecycle.Lifecycle.State;
import android.support.annotation.MainThread;
@@ -197,7 +197,6 @@
return;
}
owner.getLifecycle().addObserver(wrapper);
- wrapper.activeStateChanged(isActiveState(owner.getLifecycle().getCurrentState()));
}
/**
@@ -274,7 +273,7 @@
if (!postTask) {
return;
}
- AppToolkitTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
+ ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
}
/**
@@ -376,7 +375,6 @@
// immediately set active state, so we'd never dispatch anything to inactive
// owner
activeStateChanged(isActiveState(owner.getLifecycle().getCurrentState()));
-
}
void activeStateChanged(boolean newActive) {
@@ -403,7 +401,7 @@
}
private void assertMainThread(String methodName) {
- if (!AppToolkitTaskExecutor.getInstance().isMainThread()) {
+ if (!ArchTaskExecutor.getInstance().isMainThread()) {
throw new IllegalStateException("Cannot invoke " + methodName + " on a background"
+ " thread");
}
diff --git a/lifecycle/extensions/src/test/java/android/arch/lifecycle/ComputableLiveDataTest.java b/lifecycle/extensions/src/test/java/android/arch/lifecycle/ComputableLiveDataTest.java
index 0a3fbed..eb89d8d 100644
--- a/lifecycle/extensions/src/test/java/android/arch/lifecycle/ComputableLiveDataTest.java
+++ b/lifecycle/extensions/src/test/java/android/arch/lifecycle/ComputableLiveDataTest.java
@@ -27,7 +27,7 @@
import static org.mockito.Mockito.timeout;
import static org.mockito.Mockito.verify;
-import android.arch.core.executor.AppToolkitTaskExecutor;
+import android.arch.core.executor.ArchTaskExecutor;
import android.arch.core.executor.TaskExecutor;
import android.arch.core.executor.TaskExecutorWithFakeMainThread;
import android.arch.lifecycle.util.InstantTaskExecutor;
@@ -58,12 +58,12 @@
@Before
public void swapExecutorDelegate() {
mTaskExecutor = spy(new InstantTaskExecutor());
- AppToolkitTaskExecutor.getInstance().setDelegate(mTaskExecutor);
+ ArchTaskExecutor.getInstance().setDelegate(mTaskExecutor);
}
@After
public void removeExecutorDelegate() {
- AppToolkitTaskExecutor.getInstance().setDelegate(null);
+ ArchTaskExecutor.getInstance().setDelegate(null);
}
@Test
@@ -76,7 +76,7 @@
@Test
public void noConcurrentCompute() throws InterruptedException {
TaskExecutorWithFakeMainThread executor = new TaskExecutorWithFakeMainThread(2);
- AppToolkitTaskExecutor.getInstance().setDelegate(executor);
+ ArchTaskExecutor.getInstance().setDelegate(executor);
try {
// # of compute calls
final Semaphore computeCounter = new Semaphore(0);
@@ -121,7 +121,7 @@
// assert no other results arrive
verify(observer, never()).onChanged(anyInt());
} finally {
- AppToolkitTaskExecutor.getInstance().setDelegate(null);
+ ArchTaskExecutor.getInstance().setDelegate(null);
}
}
diff --git a/lifecycle/extensions/src/test/java/android/arch/lifecycle/LiveDataTest.java b/lifecycle/extensions/src/test/java/android/arch/lifecycle/LiveDataTest.java
index ed2a35d..9f0b425 100644
--- a/lifecycle/extensions/src/test/java/android/arch/lifecycle/LiveDataTest.java
+++ b/lifecycle/extensions/src/test/java/android/arch/lifecycle/LiveDataTest.java
@@ -36,16 +36,20 @@
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
-import android.arch.core.executor.AppToolkitTaskExecutor;
+import android.arch.core.executor.ArchTaskExecutor;
import android.arch.lifecycle.util.InstantTaskExecutor;
import android.support.annotation.Nullable;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import org.mockito.InOrder;
import org.mockito.Mockito;
@SuppressWarnings({"unchecked"})
+@RunWith(JUnit4.class)
public class LiveDataTest {
private PublicLiveData<String> mLiveData;
private LifecycleOwner mOwner;
@@ -66,12 +70,12 @@
@Before
public void swapExecutorDelegate() {
- AppToolkitTaskExecutor.getInstance().setDelegate(new InstantTaskExecutor());
+ ArchTaskExecutor.getInstance().setDelegate(new InstantTaskExecutor());
}
@After
public void removeExecutorDelegate() {
- AppToolkitTaskExecutor.getInstance().setDelegate(null);
+ ArchTaskExecutor.getInstance().setDelegate(null);
}
@Test
@@ -418,6 +422,40 @@
verify(mActiveObserversChanged, never()).onCall(anyBoolean());
}
+ @Test
+ public void testRemoveDuringAddition() {
+ mRegistry.handleLifecycleEvent(ON_START);
+ mLiveData.setValue("bla");
+ mLiveData.observeForever(new Observer<String>() {
+ @Override
+ public void onChanged(@Nullable String s) {
+ mLiveData.removeObserver(this);
+ }
+ });
+ assertThat(mLiveData.hasActiveObservers(), is(false));
+ InOrder inOrder = Mockito.inOrder(mActiveObserversChanged);
+ inOrder.verify(mActiveObserversChanged).onCall(true);
+ inOrder.verify(mActiveObserversChanged).onCall(false);
+ inOrder.verifyNoMoreInteractions();
+ }
+
+ @Test
+ public void testRemoveDuringBringingUpToState() {
+ mLiveData.setValue("bla");
+ mLiveData.observeForever(new Observer<String>() {
+ @Override
+ public void onChanged(@Nullable String s) {
+ mLiveData.removeObserver(this);
+ }
+ });
+ mRegistry.handleLifecycleEvent(ON_RESUME);
+ assertThat(mLiveData.hasActiveObservers(), is(false));
+ InOrder inOrder = Mockito.inOrder(mActiveObserversChanged);
+ inOrder.verify(mActiveObserversChanged).onCall(true);
+ inOrder.verify(mActiveObserversChanged).onCall(false);
+ inOrder.verifyNoMoreInteractions();
+ }
+
@SuppressWarnings("WeakerAccess")
static class PublicLiveData<T> extends LiveData<T> {
// cannot spy due to internal calls
diff --git a/lifecycle/extensions/src/test/java/android/arch/lifecycle/MediatorLiveDataTest.java b/lifecycle/extensions/src/test/java/android/arch/lifecycle/MediatorLiveDataTest.java
index 3de3eee..e2eadbe 100644
--- a/lifecycle/extensions/src/test/java/android/arch/lifecycle/MediatorLiveDataTest.java
+++ b/lifecycle/extensions/src/test/java/android/arch/lifecycle/MediatorLiveDataTest.java
@@ -25,7 +25,7 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-import android.arch.core.executor.AppToolkitTaskExecutor;
+import android.arch.core.executor.ArchTaskExecutor;
import android.arch.lifecycle.util.InstantTaskExecutor;
import android.support.annotation.Nullable;
@@ -69,7 +69,7 @@
@Before
public void swapExecutorDelegate() {
- AppToolkitTaskExecutor.getInstance().setDelegate(new InstantTaskExecutor());
+ ArchTaskExecutor.getInstance().setDelegate(new InstantTaskExecutor());
}
@Test
diff --git a/lifecycle/extensions/src/test/java/android/arch/lifecycle/TransformationsTest.java b/lifecycle/extensions/src/test/java/android/arch/lifecycle/TransformationsTest.java
index e92ecca..940a3e8 100644
--- a/lifecycle/extensions/src/test/java/android/arch/lifecycle/TransformationsTest.java
+++ b/lifecycle/extensions/src/test/java/android/arch/lifecycle/TransformationsTest.java
@@ -25,7 +25,7 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-import android.arch.core.executor.AppToolkitTaskExecutor;
+import android.arch.core.executor.ArchTaskExecutor;
import android.arch.core.util.Function;
import android.arch.lifecycle.util.InstantTaskExecutor;
@@ -42,7 +42,7 @@
@Before
public void swapExecutorDelegate() {
- AppToolkitTaskExecutor.getInstance().setDelegate(new InstantTaskExecutor());
+ ArchTaskExecutor.getInstance().setDelegate(new InstantTaskExecutor());
}
@Before
diff --git a/lifecycle/reactivestreams/src/main/java/android/arch/lifecycle/LiveDataReactiveStreams.java b/lifecycle/reactivestreams/src/main/java/android/arch/lifecycle/LiveDataReactiveStreams.java
index 0be0149..ec9b7f1 100644
--- a/lifecycle/reactivestreams/src/main/java/android/arch/lifecycle/LiveDataReactiveStreams.java
+++ b/lifecycle/reactivestreams/src/main/java/android/arch/lifecycle/LiveDataReactiveStreams.java
@@ -16,7 +16,7 @@
package android.arch.lifecycle;
-import android.arch.core.executor.AppToolkitTaskExecutor;
+import android.arch.core.executor.ArchTaskExecutor;
import android.support.annotation.Nullable;
import org.reactivestreams.Publisher;
@@ -85,7 +85,7 @@
if (n < 0 || mCanceled) {
return;
}
- AppToolkitTaskExecutor.getInstance().executeOnMainThread(new Runnable() {
+ ArchTaskExecutor.getInstance().executeOnMainThread(new Runnable() {
@Override
public void run() {
if (mCanceled) {
@@ -110,7 +110,7 @@
if (mCanceled) {
return;
}
- AppToolkitTaskExecutor.getInstance().executeOnMainThread(new Runnable() {
+ ArchTaskExecutor.getInstance().executeOnMainThread(new Runnable() {
@Override
public void run() {
if (mCanceled) {
diff --git a/lifecycle/reactivestreams/src/test/java/android/arch/lifecycle/LiveDataReactiveStreamsTest.java b/lifecycle/reactivestreams/src/test/java/android/arch/lifecycle/LiveDataReactiveStreamsTest.java
index 87fba27..ca52ee5 100644
--- a/lifecycle/reactivestreams/src/test/java/android/arch/lifecycle/LiveDataReactiveStreamsTest.java
+++ b/lifecycle/reactivestreams/src/test/java/android/arch/lifecycle/LiveDataReactiveStreamsTest.java
@@ -16,12 +16,10 @@
package android.arch.lifecycle;
-import static android.arch.lifecycle.Lifecycle.State.RESUMED;
-
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
-import android.arch.core.executor.AppToolkitTaskExecutor;
+import android.arch.core.executor.ArchTaskExecutor;
import android.arch.core.executor.TaskExecutor;
import android.support.annotation.Nullable;
import android.support.test.filters.SmallTest;
@@ -47,28 +45,7 @@
@SmallTest
public class LiveDataReactiveStreamsTest {
- private static final Lifecycle sLifecycle = new Lifecycle() {
- @Override
- public void addObserver(LifecycleObserver observer) {
- }
-
- @Override
- public void removeObserver(LifecycleObserver observer) {
- }
-
- @Override
- public State getCurrentState() {
- return RESUMED;
- }
- };
- private static final LifecycleOwner S_LIFECYCLE_OWNER = new LifecycleOwner() {
-
- @Override
- public Lifecycle getLifecycle() {
- return sLifecycle;
- }
-
- };
+ private LifecycleOwner mLifecycleOwner;
private final List<String> mLiveDataOutput = new ArrayList<>();
private final Observer<String> mObserver = new Observer<String>() {
@@ -85,8 +62,19 @@
@Before
public void init() {
+ mLifecycleOwner = new LifecycleOwner() {
+ LifecycleRegistry mRegistry = new LifecycleRegistry(this);
+ {
+ mRegistry.handleLifecycleEvent(Lifecycle.Event.ON_RESUME);
+ }
+
+ @Override
+ public Lifecycle getLifecycle() {
+ return mRegistry;
+ }
+ };
mTestThread = Thread.currentThread();
- AppToolkitTaskExecutor.getInstance().setDelegate(new TaskExecutor() {
+ ArchTaskExecutor.getInstance().setDelegate(new TaskExecutor() {
@Override
public void executeOnDiskIO(Runnable runnable) {
@@ -109,7 +97,7 @@
@After
public void removeExecutorDelegate() {
- AppToolkitTaskExecutor.getInstance().setDelegate(null);
+ ArchTaskExecutor.getInstance().setDelegate(null);
}
@Test
@@ -117,7 +105,7 @@
PublishProcessor<String> processor = PublishProcessor.create();
LiveData<String> liveData = LiveDataReactiveStreams.fromPublisher(processor);
- liveData.observe(S_LIFECYCLE_OWNER, mObserver);
+ liveData.observe(mLifecycleOwner, mObserver);
processor.onNext("foo");
processor.onNext("bar");
@@ -132,13 +120,13 @@
PublishProcessor<String> processor = PublishProcessor.create();
LiveData<String> liveData = LiveDataReactiveStreams.fromPublisher(processor);
- liveData.observe(S_LIFECYCLE_OWNER, mObserver);
+ liveData.observe(mLifecycleOwner, mObserver);
processor.onNext("foo");
processor.onNext("bar");
// The second mObserver should only get the newest value and any later values.
- liveData.observe(S_LIFECYCLE_OWNER, new Observer<String>() {
+ liveData.observe(mLifecycleOwner, new Observer<String>() {
@Override
public void onChanged(@Nullable String s) {
output2.add(s);
@@ -157,7 +145,7 @@
.concatWith(Flowable.just("bar", "baz").observeOn(sBackgroundScheduler));
LiveData<String> liveData = LiveDataReactiveStreams.fromPublisher(input);
- liveData.observe(S_LIFECYCLE_OWNER, mObserver);
+ liveData.observe(mLifecycleOwner, mObserver);
assertThat(mLiveDataOutput, is(Collections.singletonList("foo")));
sBackgroundScheduler.triggerActions();
@@ -170,7 +158,7 @@
liveData.setValue("foo");
assertThat(liveData.getValue(), is("foo"));
- Flowable.fromPublisher(LiveDataReactiveStreams.toPublisher(S_LIFECYCLE_OWNER, liveData))
+ Flowable.fromPublisher(LiveDataReactiveStreams.toPublisher(mLifecycleOwner, liveData))
.subscribe(mOutputProcessor);
liveData.setValue("bar");
@@ -188,7 +176,7 @@
assertThat(liveData.getValue(), is("foo"));
Disposable disposable = Flowable
- .fromPublisher(LiveDataReactiveStreams.toPublisher(S_LIFECYCLE_OWNER, liveData))
+ .fromPublisher(LiveDataReactiveStreams.toPublisher(mLifecycleOwner, liveData))
.subscribe(new Consumer<String>() {
@Override
public void accept(String s) throws Exception {
@@ -216,7 +204,7 @@
final AsyncSubject<Subscription> subscriptionSubject = AsyncSubject.create();
- Flowable.fromPublisher(LiveDataReactiveStreams.toPublisher(S_LIFECYCLE_OWNER, liveData))
+ Flowable.fromPublisher(LiveDataReactiveStreams.toPublisher(mLifecycleOwner, liveData))
.subscribe(new Subscriber<String>() {
@Override
public void onSubscribe(Subscription s) {
@@ -275,7 +263,7 @@
public void convertsToPublisherWithAsyncData() {
MutableLiveData<String> liveData = new MutableLiveData<>();
- Flowable.fromPublisher(LiveDataReactiveStreams.toPublisher(S_LIFECYCLE_OWNER, liveData))
+ Flowable.fromPublisher(LiveDataReactiveStreams.toPublisher(mLifecycleOwner, liveData))
.observeOn(sBackgroundScheduler)
.subscribe(mOutputProcessor);
diff --git a/paging/runtime/src/main/java/android/arch/paging/LivePagedListProvider.java b/paging/runtime/src/main/java/android/arch/paging/LivePagedListProvider.java
index 1250aa1..07dd84b 100644
--- a/paging/runtime/src/main/java/android/arch/paging/LivePagedListProvider.java
+++ b/paging/runtime/src/main/java/android/arch/paging/LivePagedListProvider.java
@@ -16,7 +16,7 @@
package android.arch.paging;
-import android.arch.core.executor.AppToolkitTaskExecutor;
+import android.arch.core.executor.ArchTaskExecutor;
import android.arch.lifecycle.ComputableLiveData;
import android.arch.lifecycle.LiveData;
import android.support.annotation.AnyThread;
@@ -134,9 +134,9 @@
mList = new PagedList.Builder<Key, Value>()
.setDataSource(mDataSource)
- .setMainThreadExecutor(AppToolkitTaskExecutor.getMainThreadExecutor())
+ .setMainThreadExecutor(ArchTaskExecutor.getMainThreadExecutor())
.setBackgroundThreadExecutor(
- AppToolkitTaskExecutor.getIOThreadExecutor())
+ ArchTaskExecutor.getIOThreadExecutor())
.setConfig(config)
.setInitialKey(initializeKey)
.build();
diff --git a/paging/runtime/src/main/java/android/support/v7/recyclerview/extensions/ListAdapterConfig.java b/paging/runtime/src/main/java/android/support/v7/recyclerview/extensions/ListAdapterConfig.java
index f861242..25697a1 100644
--- a/paging/runtime/src/main/java/android/support/v7/recyclerview/extensions/ListAdapterConfig.java
+++ b/paging/runtime/src/main/java/android/support/v7/recyclerview/extensions/ListAdapterConfig.java
@@ -16,7 +16,7 @@
package android.support.v7.recyclerview.extensions;
-import android.arch.core.executor.AppToolkitTaskExecutor;
+import android.arch.core.executor.ArchTaskExecutor;
import java.util.concurrent.Executor;
@@ -118,10 +118,10 @@
throw new IllegalArgumentException("Must provide a diffCallback");
}
if (mBackgroundThreadExecutor == null) {
- mBackgroundThreadExecutor = AppToolkitTaskExecutor.getIOThreadExecutor();
+ mBackgroundThreadExecutor = ArchTaskExecutor.getIOThreadExecutor();
}
if (mMainThreadExecutor == null) {
- mMainThreadExecutor = AppToolkitTaskExecutor.getMainThreadExecutor();
+ mMainThreadExecutor = ArchTaskExecutor.getMainThreadExecutor();
}
return new ListAdapterConfig<>(
mMainThreadExecutor,
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/ext/javapoet_ext.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/ext/javapoet_ext.kt
index 6dc71f6..daaa8e3 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/ext/javapoet_ext.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/ext/javapoet_ext.kt
@@ -84,7 +84,7 @@
object ArchTypeNames {
val APP_EXECUTOR : ClassName =
- ClassName.get("android.arch.core.executor", "AppToolkitTaskExecutor")
+ ClassName.get("android.arch.core.executor", "ArchTaskExecutor")
}
object PagingTypeNames {
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 a4e8946..85e89d1 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
@@ -24,7 +24,6 @@
import org.antlr.v4.runtime.Recognizer
import org.antlr.v4.runtime.tree.ParseTree
import org.antlr.v4.runtime.tree.TerminalNode
-import java.util.ArrayList
import javax.annotation.processing.ProcessingEnvironment
import javax.lang.model.type.TypeKind
import javax.lang.model.type.TypeMirror
@@ -120,6 +119,7 @@
class SqlParser {
companion object {
+ private val INVALID_IDENTIFIER_CHARS = arrayOf('`', '\"')
fun parse(input: String): ParsedQuery {
val inputStream = ANTLRInputStream(input)
val lexer = SQLiteLexer(inputStream)
@@ -153,6 +153,9 @@
listOf("unknown error while parsing $input : ${antlrError.message}"))
}
}
+
+ fun isValidIdentifier(input : String) : Boolean =
+ input.isNotBlank() && INVALID_IDENTIFIER_CHARS.none { input.contains(it) }
}
}
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/processor/EntityProcessor.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/processor/EntityProcessor.kt
index cb8dd13..540c95a 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/processor/EntityProcessor.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/processor/EntityProcessor.kt
@@ -22,6 +22,7 @@
import android.arch.persistence.room.ext.getAsStringList
import android.arch.persistence.room.ext.toType
import android.arch.persistence.room.parser.SQLTypeAffinity
+import android.arch.persistence.room.parser.SqlParser
import android.arch.persistence.room.processor.ProcessorErrors.INDEX_COLUMNS_CANNOT_BE_EMPTY
import android.arch.persistence.room.processor.ProcessorErrors.RELATION_IN_ENTITY
import android.arch.persistence.room.processor.cache.Cache
@@ -127,6 +128,13 @@
val entityForeignKeys = validateAndCreateForeignKeyReferences(foreignKeyInputs, pojo)
checkIndicesForForeignKeys(entityForeignKeys, primaryKey, indices)
+ context.checker.check(SqlParser.isValidIdentifier(tableName), element,
+ ProcessorErrors.INVALID_TABLE_NAME)
+ pojo.fields.forEach {
+ context.checker.check(SqlParser.isValidIdentifier(it.columnName), it.element,
+ ProcessorErrors.INVALID_COLUMN_NAME)
+ }
+
val entity = Entity(element = element,
tableName = tableName,
type = pojo.type,
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/processor/ProcessorErrors.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/processor/ProcessorErrors.kt
index b1e8661..2ab0182 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/processor/ProcessorErrors.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/processor/ProcessorErrors.kt
@@ -17,7 +17,6 @@
package android.arch.persistence.room.processor
import android.arch.persistence.room.Delete
-import android.arch.persistence.room.Embedded
import android.arch.persistence.room.Insert
import android.arch.persistence.room.Query
import android.arch.persistence.room.Update
@@ -459,4 +458,9 @@
"bug and Room does not allow it. See SQLite docs for details: " +
"https://www.sqlite.org/lang_createtable.html"
}
+
+ val INVALID_COLUMN_NAME = "Invalid column name. Room does not allow using ` or \" in column" +
+ " names"
+
+ val INVALID_TABLE_NAME = "Invalid table name. Room does not allow using ` or \" in table names"
}
diff --git a/room/compiler/src/test/kotlin/android/arch/persistence/room/parser/SqlParserTest.kt b/room/compiler/src/test/kotlin/android/arch/persistence/room/parser/SqlParserTest.kt
index 68b1868..6d3e194 100644
--- a/room/compiler/src/test/kotlin/android/arch/persistence/room/parser/SqlParserTest.kt
+++ b/room/compiler/src/test/kotlin/android/arch/persistence/room/parser/SqlParserTest.kt
@@ -63,6 +63,22 @@
}
@Test
+ fun validColumnNames() {
+ listOf("f", "fo", "f2", "f 2", "foo_2", "foo-2", "_", "foo bar baz",
+ "foo 2 baz", "_baz", "fooBar", "2", "*", "foo*2", "dsa$", "\$fsa",
+ "-bar", "şoöğüı").forEach {
+ assertThat("name: $it", SqlParser.isValidIdentifier(it), `is`(true))
+ }
+ }
+
+ @Test
+ fun invalidColumnNames() {
+ listOf("", " ", "fd`a`", "f`a", "`a", "\"foo bar\"", "\"", "`").forEach {
+ assertThat("name: $it", SqlParser.isValidIdentifier(it), `is`(false))
+ }
+ }
+
+ @Test
fun extractTableNames() {
assertThat(SqlParser.parse("select * from users").tables,
`is`(setOf(Table("users", "users"))))
diff --git a/room/compiler/src/test/kotlin/android/arch/persistence/room/processor/EntityProcessorTest.kt b/room/compiler/src/test/kotlin/android/arch/persistence/room/processor/EntityProcessorTest.kt
index 42fc3df..533d8c4 100644
--- a/room/compiler/src/test/kotlin/android/arch/persistence/room/processor/EntityProcessorTest.kt
+++ b/room/compiler/src/test/kotlin/android/arch/persistence/room/processor/EntityProcessorTest.kt
@@ -1775,7 +1775,47 @@
@Embedded
MyEntity myEntity;
}
- """){ _, _ ->
+ """) { _, _ ->
}.failsToCompile().withErrorContaining(ProcessorErrors.RECURSIVE_REFERENCE_DETECTED.format("foo.bar.MyEntity -> foo.bar.MyEntity.A -> foo.bar.MyEntity"))
}
+ fun okTableName() {
+ val annotation = mapOf("tableName" to "\"foo bar\"")
+ singleEntity(
+ """
+ @PrimaryKey
+ int id;
+ String name;
+ """,
+ attributes = annotation, jfos = listOf(COMMON.USER)
+ ){ _, _ ->
+ }.compilesWithoutError()
+ }
+
+ @Test
+ fun badTableName() {
+ val annotation = mapOf("tableName" to """ "foo`bar" """)
+ singleEntity(
+ """
+ @PrimaryKey
+ int id;
+ String name;
+ """,
+ attributes = annotation, jfos = listOf(COMMON.USER)
+ ){ _, _ ->
+ }.failsToCompile().withErrorContaining(ProcessorErrors.INVALID_TABLE_NAME)
+ }
+
+ @Test
+ fun badColumnName() {
+ singleEntity(
+ """
+ @PrimaryKey
+ int id;
+ @ColumnInfo(name = "\"foo bar\"")
+ String name;
+ """,
+ jfos = listOf(COMMON.USER)
+ ){ _, _ ->
+ }.failsToCompile().withErrorContaining(ProcessorErrors.INVALID_COLUMN_NAME)
+ }
}
diff --git a/room/integration-tests/testapp/src/androidTest/java/android/arch/persistence/room/integration/testapp/TestDatabase.java b/room/integration-tests/testapp/src/androidTest/java/android/arch/persistence/room/integration/testapp/TestDatabase.java
index 9417296..2fad7b1 100644
--- a/room/integration-tests/testapp/src/androidTest/java/android/arch/persistence/room/integration/testapp/TestDatabase.java
+++ b/room/integration-tests/testapp/src/androidTest/java/android/arch/persistence/room/integration/testapp/TestDatabase.java
@@ -21,6 +21,7 @@
import android.arch.persistence.room.TypeConverter;
import android.arch.persistence.room.TypeConverters;
import android.arch.persistence.room.integration.testapp.dao.BlobEntityDao;
+import android.arch.persistence.room.integration.testapp.dao.FunnyNamedDao;
import android.arch.persistence.room.integration.testapp.dao.PetCoupleDao;
import android.arch.persistence.room.integration.testapp.dao.PetDao;
import android.arch.persistence.room.integration.testapp.dao.ProductDao;
@@ -31,6 +32,7 @@
import android.arch.persistence.room.integration.testapp.dao.UserPetDao;
import android.arch.persistence.room.integration.testapp.dao.WithClauseDao;
import android.arch.persistence.room.integration.testapp.vo.BlobEntity;
+import android.arch.persistence.room.integration.testapp.vo.FunnyNamedEntity;
import android.arch.persistence.room.integration.testapp.vo.Pet;
import android.arch.persistence.room.integration.testapp.vo.PetCouple;
import android.arch.persistence.room.integration.testapp.vo.Product;
@@ -41,7 +43,7 @@
import java.util.Date;
@Database(entities = {User.class, Pet.class, School.class, PetCouple.class, Toy.class,
- BlobEntity.class, Product.class},
+ BlobEntity.class, Product.class, FunnyNamedEntity.class},
version = 1, exportSchema = false)
@TypeConverters(TestDatabase.Converters.class)
public abstract class TestDatabase extends RoomDatabase {
@@ -55,6 +57,7 @@
public abstract ProductDao getProductDao();
public abstract SpecificDogDao getSpecificDogDao();
public abstract WithClauseDao getWithClauseDao();
+ public abstract FunnyNamedDao getFunnyNamedDao();
@SuppressWarnings("unused")
public static class Converters {
diff --git a/room/integration-tests/testapp/src/androidTest/java/android/arch/persistence/room/integration/testapp/dao/FunnyNamedDao.java b/room/integration-tests/testapp/src/androidTest/java/android/arch/persistence/room/integration/testapp/dao/FunnyNamedDao.java
new file mode 100644
index 0000000..93b5e72
--- /dev/null
+++ b/room/integration-tests/testapp/src/androidTest/java/android/arch/persistence/room/integration/testapp/dao/FunnyNamedDao.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.arch.persistence.room.integration.testapp.dao;
+
+import static android.arch.persistence.room.integration.testapp.vo.FunnyNamedEntity.COLUMN_ID;
+import static android.arch.persistence.room.integration.testapp.vo.FunnyNamedEntity.TABLE_NAME;
+
+import android.arch.lifecycle.LiveData;
+import android.arch.persistence.room.Dao;
+import android.arch.persistence.room.Delete;
+import android.arch.persistence.room.Insert;
+import android.arch.persistence.room.Query;
+import android.arch.persistence.room.Update;
+import android.arch.persistence.room.integration.testapp.vo.FunnyNamedEntity;
+
+import java.util.List;
+
+@Dao
+public interface FunnyNamedDao {
+ String SELECT_ONE = "select * from \"" + TABLE_NAME + "\" WHERE \"" + COLUMN_ID + "\" = :id";
+ @Insert
+ void insert(FunnyNamedEntity... entities);
+ @Delete
+ void delete(FunnyNamedEntity... entities);
+ @Update
+ void update(FunnyNamedEntity... entities);
+
+ @Query("select * from \"" + TABLE_NAME + "\" WHERE \"" + COLUMN_ID + "\" IN (:ids)")
+ List<FunnyNamedEntity> loadAll(int... ids);
+
+ @Query(SELECT_ONE)
+ LiveData<FunnyNamedEntity> observableOne(int id);
+
+ @Query(SELECT_ONE)
+ FunnyNamedEntity load(int id);
+}
diff --git a/room/integration-tests/testapp/src/androidTest/java/android/arch/persistence/room/integration/testapp/paging/LivePagedListProviderTest.java b/room/integration-tests/testapp/src/androidTest/java/android/arch/persistence/room/integration/testapp/paging/LivePagedListProviderTest.java
index 4c9d73e..df70a17 100644
--- a/room/integration-tests/testapp/src/androidTest/java/android/arch/persistence/room/integration/testapp/paging/LivePagedListProviderTest.java
+++ b/room/integration-tests/testapp/src/androidTest/java/android/arch/persistence/room/integration/testapp/paging/LivePagedListProviderTest.java
@@ -21,17 +21,17 @@
import static org.hamcrest.CoreMatchers.nullValue;
import static org.hamcrest.MatcherAssert.assertThat;
-import android.arch.core.executor.AppToolkitTaskExecutor;
+import android.arch.core.executor.ArchTaskExecutor;
import android.arch.core.executor.testing.CountingTaskExecutorRule;
import android.arch.lifecycle.Lifecycle;
import android.arch.lifecycle.LifecycleOwner;
import android.arch.lifecycle.LifecycleRegistry;
import android.arch.lifecycle.LiveData;
import android.arch.lifecycle.Observer;
+import android.arch.paging.PagedList;
import android.arch.persistence.room.integration.testapp.test.TestDatabaseTest;
import android.arch.persistence.room.integration.testapp.test.TestUtil;
import android.arch.persistence.room.integration.testapp.vo.User;
-import android.arch.paging.PagedList;
import android.support.annotation.Nullable;
import android.support.test.filters.LargeTest;
import android.support.test.runner.AndroidJUnit4;
@@ -131,7 +131,7 @@
return null;
}
});
- AppToolkitTaskExecutor.getInstance().executeOnMainThread(futureTask);
+ ArchTaskExecutor.getInstance().executeOnMainThread(futureTask);
futureTask.get();
}
@@ -155,7 +155,7 @@
private static class PagedListObserver<T> implements Observer<PagedList<T>> {
private PagedList<T> mList;
- public void reset() {
+ void reset() {
mList = null;
}
diff --git a/room/integration-tests/testapp/src/androidTest/java/android/arch/persistence/room/integration/testapp/test/FunnyNamedDaoTest.java b/room/integration-tests/testapp/src/androidTest/java/android/arch/persistence/room/integration/testapp/test/FunnyNamedDaoTest.java
new file mode 100644
index 0000000..f4fca7f
--- /dev/null
+++ b/room/integration-tests/testapp/src/androidTest/java/android/arch/persistence/room/integration/testapp/test/FunnyNamedDaoTest.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.arch.persistence.room.integration.testapp.test;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.notNullValue;
+import static org.hamcrest.CoreMatchers.nullValue;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+import android.arch.core.executor.testing.CountingTaskExecutorRule;
+import android.arch.lifecycle.Observer;
+import android.arch.persistence.room.integration.testapp.vo.FunnyNamedEntity;
+import android.support.annotation.Nullable;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class FunnyNamedDaoTest extends TestDatabaseTest {
+ @Rule
+ public CountingTaskExecutorRule mExecutorRule = new CountingTaskExecutorRule();
+
+ @Test
+ public void readWrite() {
+ FunnyNamedEntity entity = new FunnyNamedEntity(1, "a");
+ mFunnyNamedDao.insert(entity);
+ FunnyNamedEntity loaded = mFunnyNamedDao.load(1);
+ assertThat(loaded, is(entity));
+ }
+
+ @Test
+ public void update() {
+ FunnyNamedEntity entity = new FunnyNamedEntity(1, "a");
+ mFunnyNamedDao.insert(entity);
+ entity.setValue("b");
+ mFunnyNamedDao.update(entity);
+ FunnyNamedEntity loaded = mFunnyNamedDao.load(1);
+ assertThat(loaded.getValue(), is("b"));
+ }
+
+ @Test
+ public void delete() {
+ FunnyNamedEntity entity = new FunnyNamedEntity(1, "a");
+ mFunnyNamedDao.insert(entity);
+ assertThat(mFunnyNamedDao.load(1), notNullValue());
+ mFunnyNamedDao.delete(entity);
+ assertThat(mFunnyNamedDao.load(1), nullValue());
+ }
+
+ @Test
+ public void observe() throws TimeoutException, InterruptedException {
+ final FunnyNamedEntity[] item = new FunnyNamedEntity[1];
+ mFunnyNamedDao.observableOne(2).observeForever(new Observer<FunnyNamedEntity>() {
+ @Override
+ public void onChanged(@Nullable FunnyNamedEntity funnyNamedEntity) {
+ item[0] = funnyNamedEntity;
+ }
+ });
+
+ FunnyNamedEntity entity = new FunnyNamedEntity(1, "a");
+ mFunnyNamedDao.insert(entity);
+ mExecutorRule.drainTasks(1, TimeUnit.MINUTES);
+ assertThat(item[0], nullValue());
+
+ final FunnyNamedEntity entity2 = new FunnyNamedEntity(2, "b");
+ mFunnyNamedDao.insert(entity2);
+ mExecutorRule.drainTasks(1, TimeUnit.MINUTES);
+ assertThat(item[0], is(entity2));
+
+ final FunnyNamedEntity entity3 = new FunnyNamedEntity(2, "c");
+ mFunnyNamedDao.update(entity3);
+ mExecutorRule.drainTasks(1, TimeUnit.MINUTES);
+ assertThat(item[0], is(entity3));
+ }
+}
diff --git a/room/integration-tests/testapp/src/androidTest/java/android/arch/persistence/room/integration/testapp/test/InvalidationTest.java b/room/integration-tests/testapp/src/androidTest/java/android/arch/persistence/room/integration/testapp/test/InvalidationTest.java
index 4787ce5..84f20ec 100644
--- a/room/integration-tests/testapp/src/androidTest/java/android/arch/persistence/room/integration/testapp/test/InvalidationTest.java
+++ b/room/integration-tests/testapp/src/androidTest/java/android/arch/persistence/room/integration/testapp/test/InvalidationTest.java
@@ -21,7 +21,7 @@
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.collection.IsCollectionWithSize.hasSize;
-import android.arch.core.executor.AppToolkitTaskExecutor;
+import android.arch.core.executor.ArchTaskExecutor;
import android.arch.core.executor.TaskExecutor;
import android.arch.persistence.room.InvalidationTracker;
import android.arch.persistence.room.Room;
@@ -68,7 +68,7 @@
@Before
public void setSingleThreadedIO() {
- AppToolkitTaskExecutor.getInstance().setDelegate(new TaskExecutor() {
+ ArchTaskExecutor.getInstance().setDelegate(new TaskExecutor() {
ExecutorService mIOExecutor = Executors.newSingleThreadExecutor();
Handler mHandler = new Handler(Looper.getMainLooper());
@@ -91,7 +91,7 @@
@After
public void clearExecutor() {
- AppToolkitTaskExecutor.getInstance().setDelegate(null);
+ ArchTaskExecutor.getInstance().setDelegate(null);
}
private void waitUntilIOThreadIsIdle() {
@@ -101,7 +101,7 @@
return null;
}
});
- AppToolkitTaskExecutor.getInstance().executeOnDiskIO(future);
+ ArchTaskExecutor.getInstance().executeOnDiskIO(future);
//noinspection TryWithIdenticalCatches
try {
future.get();
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 cae8445..b1f6851 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
@@ -21,7 +21,7 @@
import static org.hamcrest.CoreMatchers.nullValue;
import static org.hamcrest.MatcherAssert.assertThat;
-import android.arch.core.executor.AppToolkitTaskExecutor;
+import android.arch.core.executor.ArchTaskExecutor;
import android.arch.core.executor.testing.CountingTaskExecutorRule;
import android.arch.lifecycle.Lifecycle;
import android.arch.lifecycle.LifecycleOwner;
@@ -322,7 +322,7 @@
return null;
}
});
- AppToolkitTaskExecutor.getInstance().executeOnMainThread(futureTask);
+ ArchTaskExecutor.getInstance().executeOnMainThread(futureTask);
futureTask.get();
}
diff --git a/room/integration-tests/testapp/src/androidTest/java/android/arch/persistence/room/integration/testapp/test/RxJava2Test.java b/room/integration-tests/testapp/src/androidTest/java/android/arch/persistence/room/integration/testapp/test/RxJava2Test.java
index 98783f2..01d071e 100644
--- a/room/integration-tests/testapp/src/androidTest/java/android/arch/persistence/room/integration/testapp/test/RxJava2Test.java
+++ b/room/integration-tests/testapp/src/androidTest/java/android/arch/persistence/room/integration/testapp/test/RxJava2Test.java
@@ -19,7 +19,7 @@
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
-import android.arch.core.executor.AppToolkitTaskExecutor;
+import android.arch.core.executor.ArchTaskExecutor;
import android.arch.core.executor.TaskExecutor;
import android.arch.persistence.room.EmptyResultSetException;
import android.arch.persistence.room.integration.testapp.vo.Pet;
@@ -55,7 +55,7 @@
public void setupSchedulers() {
mTestScheduler = new TestScheduler();
mTestScheduler.start();
- AppToolkitTaskExecutor.getInstance().setDelegate(new TaskExecutor() {
+ ArchTaskExecutor.getInstance().setDelegate(new TaskExecutor() {
@Override
public void executeOnDiskIO(Runnable runnable) {
mTestScheduler.scheduleDirect(runnable);
@@ -76,7 +76,7 @@
@After
public void clearSchedulers() {
mTestScheduler.shutdown();
- AppToolkitTaskExecutor.getInstance().setDelegate(null);
+ ArchTaskExecutor.getInstance().setDelegate(null);
}
private void drain() throws InterruptedException {
@@ -305,4 +305,27 @@
}
});
}
+
+ @Test
+ public void flowable_updateInTransaction() throws InterruptedException {
+ // When subscribing to the emissions of the user
+ final TestSubscriber<User> userTestSubscriber = mUserDao
+ .flowableUserById(3)
+ .observeOn(mTestScheduler)
+ .test();
+ drain();
+ userTestSubscriber.assertValueCount(0);
+
+ // When inserting a new user in the data source
+ mDatabase.beginTransaction();
+ try {
+ mUserDao.insert(TestUtil.createUser(3));
+ mDatabase.setTransactionSuccessful();
+
+ } finally {
+ mDatabase.endTransaction();
+ }
+ drain();
+ userTestSubscriber.assertValueCount(1);
+ }
}
diff --git a/room/integration-tests/testapp/src/androidTest/java/android/arch/persistence/room/integration/testapp/test/RxJava2WithInstantTaskExecutorTest.java b/room/integration-tests/testapp/src/androidTest/java/android/arch/persistence/room/integration/testapp/test/RxJava2WithInstantTaskExecutorTest.java
new file mode 100644
index 0000000..fcd0b00
--- /dev/null
+++ b/room/integration-tests/testapp/src/androidTest/java/android/arch/persistence/room/integration/testapp/test/RxJava2WithInstantTaskExecutorTest.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.arch.persistence.room.integration.testapp.test;
+
+import android.arch.core.executor.testing.InstantTaskExecutorRule;
+import android.arch.persistence.room.Room;
+import android.arch.persistence.room.integration.testapp.TestDatabase;
+import android.arch.persistence.room.integration.testapp.vo.User;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import io.reactivex.subscribers.TestSubscriber;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class RxJava2WithInstantTaskExecutorTest {
+ @Rule
+ public InstantTaskExecutorRule instantTaskExecutorRule = new InstantTaskExecutorRule();
+
+ private TestDatabase mDatabase;
+
+ @Before
+ public void initDb() throws Exception {
+ // using an in-memory database because the information stored here disappears when the
+ // process is killed
+ mDatabase = Room.inMemoryDatabaseBuilder(InstrumentationRegistry.getContext(),
+ TestDatabase.class)
+ // allowing main thread queries, just for testing
+ .allowMainThreadQueries()
+ .build();
+ }
+
+ @Test
+ public void testFlowableInTransaction() {
+ // When subscribing to the emissions of the user
+ TestSubscriber<User> subscriber = mDatabase.getUserDao().flowableUserById(3).test();
+ subscriber.assertValueCount(0);
+
+ // When inserting a new user in the data source
+ mDatabase.beginTransaction();
+ try {
+ mDatabase.getUserDao().insert(TestUtil.createUser(3));
+ mDatabase.setTransactionSuccessful();
+ } finally {
+ mDatabase.endTransaction();
+ }
+
+ subscriber.assertValueCount(1);
+ }
+}
diff --git a/room/integration-tests/testapp/src/androidTest/java/android/arch/persistence/room/integration/testapp/test/TestDatabaseTest.java b/room/integration-tests/testapp/src/androidTest/java/android/arch/persistence/room/integration/testapp/test/TestDatabaseTest.java
index 51d5bb3..ec77561 100644
--- a/room/integration-tests/testapp/src/androidTest/java/android/arch/persistence/room/integration/testapp/test/TestDatabaseTest.java
+++ b/room/integration-tests/testapp/src/androidTest/java/android/arch/persistence/room/integration/testapp/test/TestDatabaseTest.java
@@ -18,6 +18,7 @@
import android.arch.persistence.room.Room;
import android.arch.persistence.room.integration.testapp.TestDatabase;
+import android.arch.persistence.room.integration.testapp.dao.FunnyNamedDao;
import android.arch.persistence.room.integration.testapp.dao.PetCoupleDao;
import android.arch.persistence.room.integration.testapp.dao.PetDao;
import android.arch.persistence.room.integration.testapp.dao.SchoolDao;
@@ -42,6 +43,7 @@
protected ToyDao mToyDao;
protected SpecificDogDao mSpecificDogDao;
protected WithClauseDao mWithClauseDao;
+ protected FunnyNamedDao mFunnyNamedDao;
@Before
public void createDb() {
@@ -55,5 +57,6 @@
mToyDao = mDatabase.getToyDao();
mSpecificDogDao = mDatabase.getSpecificDogDao();
mWithClauseDao = mDatabase.getWithClauseDao();
+ mFunnyNamedDao = mDatabase.getFunnyNamedDao();
}
}
diff --git a/room/integration-tests/testapp/src/androidTest/java/android/arch/persistence/room/integration/testapp/vo/FunnyNamedEntity.java b/room/integration-tests/testapp/src/androidTest/java/android/arch/persistence/room/integration/testapp/vo/FunnyNamedEntity.java
new file mode 100644
index 0000000..20f3c21
--- /dev/null
+++ b/room/integration-tests/testapp/src/androidTest/java/android/arch/persistence/room/integration/testapp/vo/FunnyNamedEntity.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.arch.persistence.room.integration.testapp.vo;
+
+import android.arch.persistence.room.ColumnInfo;
+import android.arch.persistence.room.Entity;
+import android.arch.persistence.room.PrimaryKey;
+
+/**
+ * An entity that was weird names
+ */
+@Entity(tableName = FunnyNamedEntity.TABLE_NAME)
+public class FunnyNamedEntity {
+ public static final String TABLE_NAME = "funny but not so funny";
+ public static final String COLUMN_ID = "_this $is id$";
+ public static final String COLUMN_VALUE = "unlikely-Ωşå¨ıünames";
+ @PrimaryKey(autoGenerate = true)
+ @ColumnInfo(name = COLUMN_ID)
+ private int mId;
+ @ColumnInfo(name = COLUMN_VALUE)
+ private String mValue;
+
+ public FunnyNamedEntity(int id, String value) {
+ mId = id;
+ mValue = value;
+ }
+
+ public int getId() {
+ return mId;
+ }
+
+ public void setId(int id) {
+ mId = id;
+ }
+
+ public String getValue() {
+ return mValue;
+ }
+
+ public void setValue(String value) {
+ mValue = value;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ FunnyNamedEntity entity = (FunnyNamedEntity) o;
+
+ if (mId != entity.mId) return false;
+ return mValue != null ? mValue.equals(entity.mValue) : entity.mValue == null;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = mId;
+ result = 31 * result + (mValue != null ? mValue.hashCode() : 0);
+ return result;
+ }
+}
diff --git a/room/integration-tests/testapp/src/main/java/android/arch/persistence/room/integration/testapp/CustomerViewModel.java b/room/integration-tests/testapp/src/main/java/android/arch/persistence/room/integration/testapp/CustomerViewModel.java
index 1f434ad..320b2cd 100644
--- a/room/integration-tests/testapp/src/main/java/android/arch/persistence/room/integration/testapp/CustomerViewModel.java
+++ b/room/integration-tests/testapp/src/main/java/android/arch/persistence/room/integration/testapp/CustomerViewModel.java
@@ -17,7 +17,7 @@
package android.arch.persistence.room.integration.testapp;
import android.app.Application;
-import android.arch.core.executor.AppToolkitTaskExecutor;
+import android.arch.core.executor.ArchTaskExecutor;
import android.arch.lifecycle.AndroidViewModel;
import android.arch.lifecycle.LiveData;
import android.arch.paging.DataSource;
@@ -47,7 +47,7 @@
mDatabase = Room.databaseBuilder(this.getApplication(),
SampleDatabase.class, "customerDatabase").build();
- AppToolkitTaskExecutor.getInstance().executeOnDiskIO(new Runnable() {
+ ArchTaskExecutor.getInstance().executeOnDiskIO(new Runnable() {
@Override
public void run() {
// fill with some simple data
@@ -73,7 +73,7 @@
}
void insertCustomer() {
- AppToolkitTaskExecutor.getInstance().executeOnDiskIO(new Runnable() {
+ ArchTaskExecutor.getInstance().executeOnDiskIO(new Runnable() {
@Override
public void run() {
mDatabase.getCustomerDao().insert(createCustomer());
diff --git a/room/runtime/src/main/java/android/arch/persistence/room/InvalidationTracker.java b/room/runtime/src/main/java/android/arch/persistence/room/InvalidationTracker.java
index 33bc4ed..45ec028 100644
--- a/room/runtime/src/main/java/android/arch/persistence/room/InvalidationTracker.java
+++ b/room/runtime/src/main/java/android/arch/persistence/room/InvalidationTracker.java
@@ -16,7 +16,7 @@
package android.arch.persistence.room;
-import android.arch.core.executor.AppToolkitTaskExecutor;
+import android.arch.core.executor.ArchTaskExecutor;
import android.arch.core.internal.SafeIterableMap;
import android.arch.persistence.db.SupportSQLiteDatabase;
import android.arch.persistence.db.SupportSQLiteStatement;
@@ -166,10 +166,12 @@
private static void appendTriggerName(StringBuilder builder, String tableName,
String triggerType) {
- builder.append("room_table_modification_trigger_")
+ builder.append("`")
+ .append("room_table_modification_trigger_")
.append(tableName)
.append("_")
- .append(triggerType);
+ .append(triggerType)
+ .append("`");
}
private void stopTrackingTable(SupportSQLiteDatabase writableDb, int tableId) {
@@ -192,9 +194,9 @@
appendTriggerName(stringBuilder, tableName, trigger);
stringBuilder.append(" AFTER ")
.append(trigger)
- .append(" ON ")
+ .append(" ON `")
.append(tableName)
- .append(" BEGIN INSERT OR REPLACE INTO ")
+ .append("` BEGIN INSERT OR REPLACE INTO ")
.append(UPDATE_TABLE_NAME)
.append(" VALUES(null, ")
.append(tableId)
@@ -238,7 +240,7 @@
currentObserver = mObserverMap.putIfAbsent(observer, wrapper);
}
if (currentObserver == null && mObservedTableTracker.onAdded(tableIds)) {
- AppToolkitTaskExecutor.getInstance().executeOnDiskIO(mSyncTriggers);
+ ArchTaskExecutor.getInstance().executeOnDiskIO(mSyncTriggers);
}
}
@@ -269,7 +271,7 @@
wrapper = mObserverMap.remove(observer);
}
if (wrapper != null && mObservedTableTracker.onRemoved(wrapper.mTableIds)) {
- AppToolkitTaskExecutor.getInstance().executeOnDiskIO(mSyncTriggers);
+ ArchTaskExecutor.getInstance().executeOnDiskIO(mSyncTriggers);
}
}
@@ -350,11 +352,18 @@
return;
}
- if (mDatabase.inTransaction()
- || !mPendingRefresh.compareAndSet(true, false)) {
+ if (!mPendingRefresh.compareAndSet(true, false)) {
// no pending refresh
return;
}
+
+ if (mDatabase.inTransaction()) {
+ // current thread is in a transaction. when it ends, it will invoke
+ // refreshRunnable again. mPendingRefresh is left as false on purpose
+ // so that the last transaction can flip it on again.
+ return;
+ }
+
mCleanupStatement.executeUpdateDelete();
mQueryArgs[0] = mMaxVersion;
Cursor cursor = mDatabase.query(SELECT_UPDATED_TABLES_SQL, mQueryArgs);
@@ -400,7 +409,7 @@
public void refreshVersionsAsync() {
// TODO we should consider doing this sync instead of async.
if (mPendingRefresh.compareAndSet(false, true)) {
- AppToolkitTaskExecutor.getInstance().executeOnDiskIO(mRefreshRunnable);
+ ArchTaskExecutor.getInstance().executeOnDiskIO(mRefreshRunnable);
}
}
diff --git a/room/runtime/src/main/java/android/arch/persistence/room/RoomDatabase.java b/room/runtime/src/main/java/android/arch/persistence/room/RoomDatabase.java
index d6a7f8e..cdad868 100644
--- a/room/runtime/src/main/java/android/arch/persistence/room/RoomDatabase.java
+++ b/room/runtime/src/main/java/android/arch/persistence/room/RoomDatabase.java
@@ -16,7 +16,7 @@
package android.arch.persistence.room;
-import android.arch.core.executor.AppToolkitTaskExecutor;
+import android.arch.core.executor.ArchTaskExecutor;
import android.arch.persistence.db.SimpleSQLiteQuery;
import android.arch.persistence.db.SupportSQLiteDatabase;
import android.arch.persistence.db.SupportSQLiteOpenHelper;
@@ -158,7 +158,7 @@
if (mAllowMainThreadQueries) {
return;
}
- if (AppToolkitTaskExecutor.getInstance().isMainThread()) {
+ if (ArchTaskExecutor.getInstance().isMainThread()) {
throw new IllegalStateException("Cannot access database on the main thread since"
+ " it may potentially lock the UI for a long period of time.");
}
@@ -216,7 +216,11 @@
*/
public void endTransaction() {
mOpenHelper.getWritableDatabase().endTransaction();
- mInvalidationTracker.refreshVersionsAsync();
+ if (!inTransaction()) {
+ // enqueue refresh only if we are NOT in a transaction. Otherwise, wait for the last
+ // endTransaction call to do it.
+ mInvalidationTracker.refreshVersionsAsync();
+ }
}
/**
diff --git a/room/rxjava2/src/main/java/android/arch/persistence/room/RxRoom.java b/room/rxjava2/src/main/java/android/arch/persistence/room/RxRoom.java
index adfca27..285b3f8 100644
--- a/room/rxjava2/src/main/java/android/arch/persistence/room/RxRoom.java
+++ b/room/rxjava2/src/main/java/android/arch/persistence/room/RxRoom.java
@@ -16,7 +16,7 @@
package android.arch.persistence.room;
-import android.arch.core.executor.AppToolkitTaskExecutor;
+import android.arch.core.executor.ArchTaskExecutor;
import android.support.annotation.Nullable;
import android.support.annotation.RestrictTo;
@@ -133,7 +133,7 @@
public Disposable schedule(@NonNull Runnable run, long delay,
@NonNull TimeUnit unit) {
DisposableRunnable disposable = new DisposableRunnable(run, mDisposed);
- AppToolkitTaskExecutor.getInstance().executeOnDiskIO(run);
+ ArchTaskExecutor.getInstance().executeOnDiskIO(run);
return disposable;
}
diff --git a/v17/leanback/src/android/support/v17/leanback/app/package-info.java b/v17/leanback/src/android/support/v17/leanback/app/package-info.java
index f82570e..b736909 100644
--- a/v17/leanback/src/android/support/v17/leanback/app/package-info.java
+++ b/v17/leanback/src/android/support/v17/leanback/app/package-info.java
@@ -15,37 +15,37 @@
/**
* <p>Support classes providing high level Leanback user interface building blocks.</p>
* <p>
- * Leanback fragments are available both as platform fragments (subclassed from
- * {@link android.app.Fragment android.app.Fragment}) and as support fragments (subclassed from
- * {@link android.support.v4.app.Fragment android.support.v4.app.Fragment}). A few of the most
+ * Leanback fragments are available both as support fragments (subclassed from
+ * {@link android.support.v4.app.Fragment android.support.v4.app.Fragment}) and as platform
+ * fragments (subclassed from {@link android.app.Fragment android.app.Fragment}). A few of the most
* commonly used leanback fragments are described here.
* </p>
* <p>
- * A {@link android.support.v17.leanback.app.BrowseFragment} by default operates in the "row" mode.
- * It includes an optional “fastlane”
+ * A {@link android.support.v17.leanback.app.BrowseSupportFragment} by default operates in the "row"
+ * mode. It includes an optional “fastlane”
* navigation side panel and a list of rows, with one-to-one correspondance between each header
* in the fastlane and a row. The application supplies the
* {@link android.support.v17.leanback.widget.ObjectAdapter} containing the list of
* rows and a {@link android.support.v17.leanback.widget.PresenterSelector} of row presenters.
* </p>
* <p>
- * A {@link android.support.v17.leanback.app.BrowseFragment} also works in a "page" mode when
+ * A {@link android.support.v17.leanback.app.BrowseSupportFragment} also works in a "page" mode when
* each row of fastlane is mapped to a fragment that the app registers in
- * {@link android.support.v17.leanback.app.BrowseFragment#getMainFragmentRegistry()}.
+ * {@link android.support.v17.leanback.app.BrowseSupportFragment#getMainFragmentRegistry()}.
* </p>
* <p>
- * A {@link android.support.v17.leanback.app.DetailsFragment} will typically consist of a large
- * overview of an item at the top,
+ * A {@link android.support.v17.leanback.app.DetailsSupportFragment} will typically consist of a
+ * large overview of an item at the top,
* some actions that a user can perform, and possibly rows of additional or related items.
- * The content for this fragment is specified in the same way as for the BrowseFragment, with the
- * convention that the first element in the ObjectAdapter corresponds to the overview row.
+ * The content for this fragment is specified in the same way as for the BrowseSupportFragment, with
+ * the convention that the first element in the ObjectAdapter corresponds to the overview row.
* The {@link android.support.v17.leanback.widget.DetailsOverviewRow} and
* {@link android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter} provide a
* default template for this row.
* </p>
* <p>
- * A {@link android.support.v17.leanback.app.PlaybackFragment} or its subclass
- * {@link android.support.v17.leanback.app.VideoFragment} hosts
+ * A {@link android.support.v17.leanback.app.PlaybackSupportFragment} or its subclass
+ * {@link android.support.v17.leanback.app.VideoSupportFragment} hosts
* {@link android.support.v17.leanback.media.PlaybackTransportControlGlue}
* or {@link android.support.v17.leanback.media.PlaybackBannerControlGlue} with a Leanback
* look and feel. It is recommended to use an instance of
@@ -54,13 +54,13 @@
* the most commonly used controls as well as video scrubbing.
* </p>
* <p>
- * A {@link android.support.v17.leanback.app.SearchFragment} allows the developer to accept a query
- * from a user and display the results
+ * A {@link android.support.v17.leanback.app.SearchSupportFragment} allows the developer to accept a
+ * query from a user and display the results
* using the familiar list rows.
* </p>
* <p>
- * A {@link android.support.v17.leanback.app.GuidedStepFragment} is used to guide the user through a
- * decision or series of decisions.
+ * A {@link android.support.v17.leanback.app.GuidedStepSupportFragment} is used to guide the user
+ * through a decision or series of decisions.
* </p>
**/
diff --git a/v17/leanback/src/android/support/v17/leanback/package-info.java b/v17/leanback/src/android/support/v17/leanback/package-info.java
index 5259f63..80b26e9 100644
--- a/v17/leanback/src/android/support/v17/leanback/package-info.java
+++ b/v17/leanback/src/android/support/v17/leanback/package-info.java
@@ -41,13 +41,13 @@
* <p>
* Leanback contains a mixture of higher level building blocks such as Fragments in the
* {@link android.support.v17.leanback.app} package. Notable examples are the
- * {@link android.support.v17.leanback.app.BrowseFragment},
- * {@link android.support.v17.leanback.app.DetailsFragment},
- * {@link android.support.v17.leanback.app.PlaybackFragment} and the
- * {@link android.support.v17.leanback.app.GuidedStepFragment}. Helper classes are also provided
- * that work with the leanback fragments, for example the
+ * {@link android.support.v17.leanback.app.BrowseSupportFragment},
+ * {@link android.support.v17.leanback.app.DetailsSupportFragment},
+ * {@link android.support.v17.leanback.app.PlaybackSupportFragment} and the
+ * {@link android.support.v17.leanback.app.GuidedStepSupportFragment}. Helper classes are also
+ * provided that work with the leanback fragments, for example the
* {@link android.support.v17.leanback.media.PlaybackTransportControlGlue} and
- * {@link android.support.v17.leanback.app.PlaybackFragmentGlueHost}.
+ * {@link android.support.v17.leanback.app.PlaybackSupportFragmentGlueHost}.
* </p>
* <p>
* Many lower level building blocks are also provided in the {@link android.support.v17.leanback.widget} package.
diff --git a/v7/recyclerview/src/android/support/v7/widget/helper/ItemTouchHelper.java b/v7/recyclerview/src/android/support/v7/widget/helper/ItemTouchHelper.java
index b0a2cb3..aee48df 100644
--- a/v7/recyclerview/src/android/support/v7/widget/helper/ItemTouchHelper.java
+++ b/v7/recyclerview/src/android/support/v7/widget/helper/ItemTouchHelper.java
@@ -292,6 +292,11 @@
*/
GestureDetectorCompat mGestureDetector;
+ /**
+ * Callback for when long press occurs.
+ */
+ private ItemTouchHelperGestureListener mItemTouchHelperGestureListener;
+
private final OnItemTouchListener mOnItemTouchListener = new OnItemTouchListener() {
@Override
public boolean onInterceptTouchEvent(RecyclerView recyclerView, MotionEvent event) {
@@ -468,7 +473,7 @@
mRecyclerView.addItemDecoration(this);
mRecyclerView.addOnItemTouchListener(mOnItemTouchListener);
mRecyclerView.addOnChildAttachStateChangeListener(this);
- initGestureDetector();
+ startGestureDetection();
}
private void destroyCallbacks() {
@@ -485,14 +490,23 @@
mOverdrawChild = null;
mOverdrawChildPosition = -1;
releaseVelocityTracker();
+ stopGestureDetection();
}
- private void initGestureDetector() {
- if (mGestureDetector != null) {
- return;
- }
+ private void startGestureDetection() {
+ mItemTouchHelperGestureListener = new ItemTouchHelperGestureListener();
mGestureDetector = new GestureDetectorCompat(mRecyclerView.getContext(),
- new ItemTouchHelperGestureListener());
+ mItemTouchHelperGestureListener);
+ }
+
+ private void stopGestureDetection() {
+ if (mItemTouchHelperGestureListener != null) {
+ mItemTouchHelperGestureListener.doNotReactToLongPress();
+ mItemTouchHelperGestureListener = null;
+ }
+ if (mGestureDetector != null) {
+ mGestureDetector = null;
+ }
}
private void getSelectedDxDy(float[] outPosition) {
@@ -2242,9 +2256,33 @@
private class ItemTouchHelperGestureListener extends GestureDetector.SimpleOnGestureListener {
+ /**
+ * Whether to execute code in response to the the invoking of
+ * {@link ItemTouchHelperGestureListener#onLongPress(MotionEvent)}.
+ *
+ * It is necessary to control this here because
+ * {@link GestureDetector.SimpleOnGestureListener} can only be set on a
+ * {@link GestureDetector} in a GestureDetector's constructor, a GestureDetector will call
+ * onLongPress if an {@link MotionEvent#ACTION_DOWN} event is not followed by another event
+ * that would cancel it (like {@link MotionEvent#ACTION_UP} or
+ * {@link MotionEvent#ACTION_CANCEL}), the long press responding to the long press event
+ * needs to be cancellable to prevent unexpected behavior.
+ *
+ * @see #doNotReactToLongPress()
+ */
+ private boolean mShouldReactToLongPress = true;
+
ItemTouchHelperGestureListener() {
}
+ /**
+ * Call to prevent executing code in response to
+ * {@link ItemTouchHelperGestureListener#onLongPress(MotionEvent)} being called.
+ */
+ void doNotReactToLongPress() {
+ mShouldReactToLongPress = false;
+ }
+
@Override
public boolean onDown(MotionEvent e) {
return true;
@@ -2252,6 +2290,9 @@
@Override
public void onLongPress(MotionEvent e) {
+ if (!mShouldReactToLongPress) {
+ return;
+ }
View child = findChildView(e);
if (child != null) {
ViewHolder vh = mRecyclerView.getChildViewHolder(child);
diff --git a/v7/recyclerview/tests/src/android/support/v7/util/TouchUtils.java b/v7/recyclerview/tests/src/android/support/v7/util/TouchUtils.java
index 02099ba..1a64e3c 100644
--- a/v7/recyclerview/tests/src/android/support/v7/util/TouchUtils.java
+++ b/v7/recyclerview/tests/src/android/support/v7/util/TouchUtils.java
@@ -142,13 +142,6 @@
inst.sendPointerSync(event);
inst.waitForIdleSync();
- eventTime = SystemClock.uptimeMillis();
- final int touchSlop = ViewConfiguration.get(v.getContext()).getScaledTouchSlop();
- event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_MOVE,
- x + touchSlop / 2, y + touchSlop / 2, 0);
- inst.sendPointerSync(event);
- inst.waitForIdleSync();
-
try {
Thread.sleep((long) (ViewConfiguration.getLongPressTimeout() * 1.5f));
} catch (InterruptedException e) {
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/helper/ItemTouchHelperTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/helper/ItemTouchHelperTest.java
index 18af47b..090ea69 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/helper/ItemTouchHelperTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/helper/ItemTouchHelperTest.java
@@ -32,11 +32,13 @@
import android.support.test.filters.Suppress;
import android.support.test.runner.AndroidJUnit4;
import android.support.testutils.PollingCheck;
+import android.support.v4.util.Pair;
import android.support.v7.util.TouchUtils;
import android.support.v7.widget.BaseRecyclerViewInstrumentationTest;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.WrappedRecyclerView;
import android.view.Gravity;
+import android.view.View;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -48,26 +50,27 @@
@RunWith(AndroidJUnit4.class)
public class ItemTouchHelperTest extends BaseRecyclerViewInstrumentationTest {
- TestAdapter mAdapter;
-
- TestLayoutManager mLayoutManager;
+ private static class RecyclerViewState {
+ public TestAdapter mAdapter;
+ public TestLayoutManager mLayoutManager;
+ public WrappedRecyclerView mWrappedRecyclerView;
+ }
private LoggingCalback mCalback;
private LoggingItemTouchHelper mItemTouchHelper;
- private WrappedRecyclerView mWrappedRecyclerView;
-
private Boolean mSetupRTL;
public ItemTouchHelperTest() {
super(false);
}
- private RecyclerView setup(int dragDirs, int swipeDirs) throws Throwable {
- mWrappedRecyclerView = inflateWrappedRV();
- mAdapter = new TestAdapter(10);
- mLayoutManager = new TestLayoutManager() {
+ private RecyclerViewState setupRecyclerView() throws Throwable {
+ RecyclerViewState rvs = new RecyclerViewState();
+ rvs.mWrappedRecyclerView = inflateWrappedRV();
+ rvs.mAdapter = new TestAdapter(10);
+ rvs.mLayoutManager = new TestLayoutManager() {
@Override
public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
detachAndScrapAttachedViews(recycler);
@@ -85,19 +88,24 @@
return false;
}
};
- mWrappedRecyclerView.setFakeRTL(mSetupRTL);
- mWrappedRecyclerView.setAdapter(mAdapter);
- mWrappedRecyclerView.setLayoutManager(mLayoutManager);
+ rvs.mWrappedRecyclerView.setFakeRTL(mSetupRTL);
+ rvs.mWrappedRecyclerView.setAdapter(rvs.mAdapter);
+ rvs.mWrappedRecyclerView.setLayoutManager(rvs.mLayoutManager);
+ return rvs;
+ }
+
+ private RecyclerViewState setupItemTouchHelper(final RecyclerViewState rvs, int dragDirs,
+ int swipeDirs) throws Throwable {
mCalback = new LoggingCalback(dragDirs, swipeDirs);
mItemTouchHelper = new LoggingItemTouchHelper(mCalback);
mActivityRule.runOnUiThread(new Runnable() {
@Override
public void run() {
- mItemTouchHelper.attachToRecyclerView(mWrappedRecyclerView);
+ mItemTouchHelper.attachToRecyclerView(rvs.mWrappedRecyclerView);
}
});
- return mWrappedRecyclerView;
+ return rvs;
}
@Test
@@ -136,11 +144,60 @@
basicSwipeTest(END, START | END, -getActivity().getWindow().getDecorView().getWidth());
}
+ @Test
+ public void attachToNullRecycleViewDuringLongPress() throws Throwable {
+ final RecyclerViewState rvs = setupItemTouchHelper(setupRecyclerView(), END, 0);
+ rvs.mLayoutManager.expectLayouts(1);
+ setRecyclerView(rvs.mWrappedRecyclerView);
+ rvs.mLayoutManager.waitForLayout(1);
+
+ final RecyclerView.ViewHolder target = mRecyclerView
+ .findViewHolderForAdapterPosition(1);
+ target.itemView.setOnLongClickListener(new View.OnLongClickListener() {
+ @Override
+ public boolean onLongClick(View v) {
+ mItemTouchHelper.attachToRecyclerView(null);
+ return false;
+ }
+ });
+ TouchUtils.longClickView(getInstrumentation(), target.itemView);
+ }
+
+ @Test
+ public void attachToAnotherRecycleViewDuringLongPress() throws Throwable {
+ final RecyclerViewState rvs2 = setupRecyclerView();
+ rvs2.mLayoutManager.expectLayouts(1);
+ mActivityRule.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ getActivity().getContainer().addView(rvs2.mWrappedRecyclerView);
+ }
+ });
+ rvs2.mLayoutManager.waitForLayout(1);
+
+ final RecyclerViewState rvs = setupItemTouchHelper(setupRecyclerView(), END, 0);
+ rvs.mLayoutManager.expectLayouts(1);
+ setRecyclerView(rvs.mWrappedRecyclerView);
+ rvs.mLayoutManager.waitForLayout(1);
+
+ final RecyclerView.ViewHolder target = mRecyclerView
+ .findViewHolderForAdapterPosition(1);
+ target.itemView.setOnLongClickListener(new View.OnLongClickListener() {
+ @Override
+ public boolean onLongClick(View v) {
+ mItemTouchHelper.attachToRecyclerView(rvs2.mWrappedRecyclerView);
+ return false;
+ }
+ });
+ TouchUtils.longClickView(getInstrumentation(), target.itemView);
+ assertEquals(0, mCalback.mHasDragFlag.size());
+ }
+
public void basicSwipeTest(int dir, int swipeDirs, int targetX) throws Throwable {
- final RecyclerView recyclerView = setup(0, swipeDirs);
- mLayoutManager.expectLayouts(1);
- setRecyclerView(recyclerView);
- mLayoutManager.waitForLayout(1);
+ final RecyclerViewState rvs = setupItemTouchHelper(setupRecyclerView(), 0, swipeDirs);
+ rvs.mLayoutManager.expectLayouts(1);
+ setRecyclerView(rvs.mWrappedRecyclerView);
+ rvs.mLayoutManager.waitForLayout(1);
final RecyclerView.ViewHolder target = mRecyclerView
.findViewHolderForAdapterPosition(1);
@@ -158,9 +215,9 @@
assertEquals(1, mItemTouchHelper.mRecoverAnimations.size());
assertEquals(1, mItemTouchHelper.mPendingCleanup.size());
// get rid of the view
- mLayoutManager.expectLayouts(1);
- mAdapter.deleteAndNotify(1, 1);
- mLayoutManager.waitForLayout(1);
+ rvs.mLayoutManager.expectLayouts(1);
+ rvs.mAdapter.deleteAndNotify(1, 1);
+ rvs.mLayoutManager.waitForLayout(1);
waitForAnimations();
assertEquals(0, mItemTouchHelper.mRecoverAnimations.size());
assertEquals(0, mItemTouchHelper.mPendingCleanup.size());
@@ -181,6 +238,8 @@
private List<RecyclerView.ViewHolder> mCleared = new ArrayList<RecyclerView.ViewHolder>();
+ public List<Pair<RecyclerView, RecyclerView.ViewHolder>> mHasDragFlag = new ArrayList<>();
+
LoggingCalback(int dragDirs, int swipeDirs) {
super(dragDirs, swipeDirs);
}
@@ -212,6 +271,12 @@
mCleared.add(viewHolder);
}
+ @Override
+ boolean hasDragFlag(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
+ mHasDragFlag.add(new Pair<>(recyclerView, viewHolder));
+ return super.hasDragFlag(recyclerView, viewHolder);
+ }
+
public SwipeRecord getSwipe(RecyclerView.ViewHolder vh) {
for (SwipeRecord swipe : mSwipeRecords) {
if (swipe.viewHolder == vh) {