Merge "Throw if Activity is not attached to Application, when querying for VM" into oc-mr1-support-27.0-dev
diff --git a/compat/api/current.txt b/compat/api/current.txt
index c4e7fd3..85ad7f2 100644
--- a/compat/api/current.txt
+++ b/compat/api/current.txt
@@ -641,12 +641,12 @@
field public static final java.lang.String EXTRA_START_PLAYBACK = "android.intent.extra.START_PLAYBACK";
}
- public final class SharedPreferencesCompat {
+ public final deprecated class SharedPreferencesCompat {
}
- public static final class SharedPreferencesCompat.EditorCompat {
- method public void apply(android.content.SharedPreferences.Editor);
- method public static android.support.v4.content.SharedPreferencesCompat.EditorCompat getInstance();
+ public static final deprecated class SharedPreferencesCompat.EditorCompat {
+ method public deprecated void apply(android.content.SharedPreferences.Editor);
+ method public static deprecated android.support.v4.content.SharedPreferencesCompat.EditorCompat getInstance();
}
}
diff --git a/compat/java/android/support/v4/content/SharedPreferencesCompat.java b/compat/java/android/support/v4/content/SharedPreferencesCompat.java
index 7d51fed..1d43c2e 100644
--- a/compat/java/android/support/v4/content/SharedPreferencesCompat.java
+++ b/compat/java/android/support/v4/content/SharedPreferencesCompat.java
@@ -19,8 +19,18 @@
import android.content.SharedPreferences;
import android.support.annotation.NonNull;
+/**
+ * @deprecated This compatibility class is no longer required. Use {@link SharedPreferences}
+ * directly.
+ */
+@Deprecated
public final class SharedPreferencesCompat {
+ /**
+ * @deprecated This compatibility class is no longer required. Use
+ * {@link SharedPreferences.Editor} directly.
+ */
+ @Deprecated
public final static class EditorCompat {
private static EditorCompat sInstance;
@@ -46,14 +56,22 @@
private EditorCompat() {
mHelper = new Helper();
}
-
+ /**
+ * @deprecated This compatibility class is no longer required. Use
+ * {@link SharedPreferences.Editor} directly.
+ */
+ @Deprecated
public static EditorCompat getInstance() {
if (sInstance == null) {
sInstance = new EditorCompat();
}
return sInstance;
}
-
+ /**
+ * @deprecated This compatibility method is no longer required. Use
+ * {@link SharedPreferences.Editor#apply()} directly.
+ */
+ @Deprecated
public void apply(@NonNull SharedPreferences.Editor editor) {
// Note that this redirection is needed to not break the public API chain
// of getInstance().apply() calls. Otherwise this method could (and should)
diff --git a/core-utils/Android.mk b/core-utils/Android.mk
index 5ea200e..6dda862 100644
--- a/core-utils/Android.mk
+++ b/core-utils/Android.mk
@@ -27,7 +27,6 @@
LOCAL_MODULE := android-support-core-utils
LOCAL_SDK_VERSION := $(SUPPORT_CURRENT_SDK_VERSION)
LOCAL_SRC_FILES := \
- $(call all-java-files-under,gingerbread) \
$(call all-java-files-under,kitkat) \
$(call all-java-files-under,api21) \
$(call all-java-files-under,java)
diff --git a/core-utils/build.gradle b/core-utils/build.gradle
index 0fe309b..29fe86c 100644
--- a/core-utils/build.gradle
+++ b/core-utils/build.gradle
@@ -17,12 +17,8 @@
sourceSets {
main.java.srcDirs = [
- 'gingerbread',
'kitkat',
- 'api20',
'api21',
- 'api23',
- 'api24',
'java'
]
}
diff --git a/core-utils/java/android/support/v4/app/AppLaunchChecker.java b/core-utils/java/android/support/v4/app/AppLaunchChecker.java
index 0b2cc4f..af9512a 100644
--- a/core-utils/java/android/support/v4/app/AppLaunchChecker.java
+++ b/core-utils/java/android/support/v4/app/AppLaunchChecker.java
@@ -24,7 +24,6 @@
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.content.IntentCompat;
-import android.support.v4.content.SharedPreferencesCompat;
/**
* This class provides APIs for determining how an app has been launched.
@@ -77,8 +76,7 @@
if (Intent.ACTION_MAIN.equals(launchIntent.getAction())
&& (launchIntent.hasCategory(Intent.CATEGORY_LAUNCHER)
|| launchIntent.hasCategory(IntentCompat.CATEGORY_LEANBACK_LAUNCHER))) {
- SharedPreferencesCompat.EditorCompat.getInstance().apply(
- sp.edit().putBoolean(KEY_STARTED_FROM_LAUNCHER, true));
+ sp.edit().putBoolean(KEY_STARTED_FROM_LAUNCHER, true).apply();
}
}
}
diff --git a/core-utils/java/android/support/v4/content/AsyncTaskLoader.java b/core-utils/java/android/support/v4/content/AsyncTaskLoader.java
index faa13ad..5882f69 100644
--- a/core-utils/java/android/support/v4/content/AsyncTaskLoader.java
+++ b/core-utils/java/android/support/v4/content/AsyncTaskLoader.java
@@ -21,6 +21,8 @@
import android.content.Context;
import android.os.Handler;
import android.os.SystemClock;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
import android.support.annotation.RestrictTo;
import android.support.v4.os.OperationCanceledException;
import android.support.v4.util.TimeUtils;
@@ -121,11 +123,11 @@
long mLastLoadCompleteTime = -10000;
Handler mHandler;
- public AsyncTaskLoader(Context context) {
+ public AsyncTaskLoader(@NonNull Context context) {
this(context, ModernAsyncTask.THREAD_POOL_EXECUTOR);
}
- private AsyncTaskLoader(Context context, Executor executor) {
+ private AsyncTaskLoader(@NonNull Context context, @NonNull Executor executor) {
super(context);
mExecutor = executor;
}
@@ -200,7 +202,7 @@
* @param data The value that was returned by {@link #loadInBackground}, or null
* if the task threw {@link OperationCanceledException}.
*/
- public void onCanceled(D data) {
+ public void onCanceled(@Nullable D data) {
}
void executePendingTask() {
@@ -284,6 +286,7 @@
* @see #cancelLoadInBackground
* @see #onCanceled
*/
+ @Nullable
public abstract D loadInBackground();
/**
@@ -298,6 +301,7 @@
*
* @see #loadInBackground
*/
+ @Nullable
protected D onLoadInBackground() {
return loadInBackground();
}
diff --git a/core-utils/java/android/support/v4/content/CursorLoader.java b/core-utils/java/android/support/v4/content/CursorLoader.java
index 503bb9c..5c6925d 100644
--- a/core-utils/java/android/support/v4/content/CursorLoader.java
+++ b/core-utils/java/android/support/v4/content/CursorLoader.java
@@ -20,6 +20,8 @@
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
import android.support.v4.os.CancellationSignal;
import android.support.v4.os.OperationCanceledException;
@@ -115,7 +117,7 @@
* calls to {@link #setUri(Uri)}, {@link #setSelection(String)}, etc
* to specify the query to perform.
*/
- public CursorLoader(Context context) {
+ public CursorLoader(@NonNull Context context) {
super(context);
mObserver = new ForceLoadContentObserver();
}
@@ -126,8 +128,9 @@
* ContentResolver.query()} for documentation on the meaning of the
* parameters. These will be passed as-is to that call.
*/
- public CursorLoader(Context context, Uri uri, String[] projection, String selection,
- String[] selectionArgs, String sortOrder) {
+ public CursorLoader(@NonNull Context context, @NonNull Uri uri, @Nullable String[] projection,
+ @Nullable String selection, @Nullable String[] selectionArgs,
+ @Nullable String sortOrder) {
super(context);
mObserver = new ForceLoadContentObserver();
mUri = uri;
@@ -183,43 +186,48 @@
mCursor = null;
}
+ @NonNull
public Uri getUri() {
return mUri;
}
- public void setUri(Uri uri) {
+ public void setUri(@NonNull Uri uri) {
mUri = uri;
}
+ @Nullable
public String[] getProjection() {
return mProjection;
}
- public void setProjection(String[] projection) {
+ public void setProjection(@Nullable String[] projection) {
mProjection = projection;
}
+ @Nullable
public String getSelection() {
return mSelection;
}
- public void setSelection(String selection) {
+ public void setSelection(@Nullable String selection) {
mSelection = selection;
}
+ @Nullable
public String[] getSelectionArgs() {
return mSelectionArgs;
}
- public void setSelectionArgs(String[] selectionArgs) {
+ public void setSelectionArgs(@Nullable String[] selectionArgs) {
mSelectionArgs = selectionArgs;
}
+ @Nullable
public String getSortOrder() {
return mSortOrder;
}
- public void setSortOrder(String sortOrder) {
+ public void setSortOrder(@Nullable String sortOrder) {
mSortOrder = sortOrder;
}
diff --git a/core-utils/java/android/support/v4/content/FileProvider.java b/core-utils/java/android/support/v4/content/FileProvider.java
index c49fc12..8599911 100644
--- a/core-utils/java/android/support/v4/content/FileProvider.java
+++ b/core-utils/java/android/support/v4/content/FileProvider.java
@@ -33,6 +33,8 @@
import android.os.ParcelFileDescriptor;
import android.provider.OpenableColumns;
import android.support.annotation.GuardedBy;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
import android.text.TextUtils;
import android.webkit.MimeTypeMap;
@@ -362,7 +364,7 @@
* @param info A {@link ProviderInfo} for the new provider.
*/
@Override
- public void attachInfo(Context context, ProviderInfo info) {
+ public void attachInfo(@NonNull Context context, @NonNull ProviderInfo info) {
super.attachInfo(context, info);
// Sanity check our security
@@ -396,7 +398,8 @@
* @throws IllegalArgumentException When the given {@link File} is outside
* the paths supported by the provider.
*/
- public static Uri getUriForFile(Context context, String authority, File file) {
+ public static Uri getUriForFile(@NonNull Context context, @NonNull String authority,
+ @NonNull File file) {
final PathStrategy strategy = getPathStrategy(context, authority);
return strategy.getUriForFile(file);
}
@@ -430,8 +433,9 @@
*
*/
@Override
- public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
- String sortOrder) {
+ public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection,
+ @Nullable String[] selectionArgs,
+ @Nullable String sortOrder) {
// ContentProvider has already checked granted permissions
final File file = mStrategy.getFileForUri(uri);
@@ -470,7 +474,7 @@
* extension; otherwise <code>application/octet-stream</code>.
*/
@Override
- public String getType(Uri uri) {
+ public String getType(@NonNull Uri uri) {
// ContentProvider has already checked granted permissions
final File file = mStrategy.getFileForUri(uri);
@@ -491,7 +495,7 @@
* subclass FileProvider if you want to provide different functionality.
*/
@Override
- public Uri insert(Uri uri, ContentValues values) {
+ public Uri insert(@NonNull Uri uri, ContentValues values) {
throw new UnsupportedOperationException("No external inserts");
}
@@ -500,7 +504,8 @@
* subclass FileProvider if you want to provide different functionality.
*/
@Override
- public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
+ public int update(@NonNull Uri uri, ContentValues values, @Nullable String selection,
+ @Nullable String[] selectionArgs) {
throw new UnsupportedOperationException("No external updates");
}
@@ -516,7 +521,8 @@
* @return 1 if the delete succeeds; otherwise, 0.
*/
@Override
- public int delete(Uri uri, String selection, String[] selectionArgs) {
+ public int delete(@NonNull Uri uri, @Nullable String selection,
+ @Nullable String[] selectionArgs) {
// ContentProvider has already checked granted permissions
final File file = mStrategy.getFileForUri(uri);
return file.delete() ? 1 : 0;
@@ -538,7 +544,8 @@
* @return A new {@link ParcelFileDescriptor} with which you can access the file.
*/
@Override
- public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException {
+ public ParcelFileDescriptor openFile(@NonNull Uri uri, @NonNull String mode)
+ throws FileNotFoundException {
// ContentProvider has already checked granted permissions
final File file = mStrategy.getFileForUri(uri);
final int fileMode = modeToMode(mode);
diff --git a/core-utils/java/android/support/v4/content/Loader.java b/core-utils/java/android/support/v4/content/Loader.java
index 40b459f..2ac10d7 100644
--- a/core-utils/java/android/support/v4/content/Loader.java
+++ b/core-utils/java/android/support/v4/content/Loader.java
@@ -19,6 +19,8 @@
import android.content.Context;
import android.database.ContentObserver;
import android.os.Handler;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
import android.support.v4.util.DebugUtils;
import java.io.FileDescriptor;
@@ -80,7 +82,7 @@
* @param loader the loader that completed the load
* @param data the result of the load
*/
- public void onLoadComplete(Loader<D> loader, D data);
+ void onLoadComplete(@NonNull Loader<D> loader, @Nullable D data);
}
/**
@@ -97,7 +99,7 @@
*
* @param loader the loader that canceled the load
*/
- public void onLoadCanceled(Loader<D> loader);
+ void onLoadCanceled(@NonNull Loader<D> loader);
}
/**
@@ -110,7 +112,7 @@
*
* @param context used to retrieve the application context.
*/
- public Loader(Context context) {
+ public Loader(@NonNull Context context) {
mContext = context.getApplicationContext();
}
@@ -121,7 +123,7 @@
*
* @param data the result of the load
*/
- public void deliverResult(D data) {
+ public void deliverResult(@Nullable D data) {
if (mListener != null) {
mListener.onLoadComplete(this, data);
}
@@ -142,6 +144,7 @@
/**
* @return an application context retrieved from the Context passed to the constructor.
*/
+ @NonNull
public Context getContext() {
return mContext;
}
@@ -160,7 +163,7 @@
*
* <p>Must be called from the process's main thread.
*/
- public void registerListener(int id, OnLoadCompleteListener<D> listener) {
+ public void registerListener(int id, @NonNull OnLoadCompleteListener<D> listener) {
if (mListener != null) {
throw new IllegalStateException("There is already a listener registered");
}
@@ -173,7 +176,7 @@
*
* Must be called from the process's main thread.
*/
- public void unregisterListener(OnLoadCompleteListener<D> listener) {
+ public void unregisterListener(@NonNull OnLoadCompleteListener<D> listener) {
if (mListener == null) {
throw new IllegalStateException("No listener register");
}
@@ -192,7 +195,7 @@
*
* @param listener The listener to register.
*/
- public void registerOnLoadCanceledListener(OnLoadCanceledListener<D> listener) {
+ public void registerOnLoadCanceledListener(@NonNull OnLoadCanceledListener<D> listener) {
if (mOnLoadCanceledListener != null) {
throw new IllegalStateException("There is already a listener registered");
}
@@ -207,7 +210,7 @@
*
* @param listener The listener to unregister.
*/
- public void unregisterOnLoadCanceledListener(OnLoadCanceledListener<D> listener) {
+ public void unregisterOnLoadCanceledListener(@NonNull OnLoadCanceledListener<D> listener) {
if (mOnLoadCanceledListener == null) {
throw new IllegalStateException("No listener register");
}
@@ -493,7 +496,8 @@
* For debugging, converts an instance of the Loader's data class to
* a string that can be printed. Must handle a null data.
*/
- public String dataToString(D data) {
+ @NonNull
+ public String dataToString(@Nullable D data) {
StringBuilder sb = new StringBuilder(64);
DebugUtils.buildShortClassTag(data, sb);
sb.append("}");
diff --git a/core-utils/java/android/support/v4/content/LocalBroadcastManager.java b/core-utils/java/android/support/v4/content/LocalBroadcastManager.java
index 324bb30..aaaf8be 100644
--- a/core-utils/java/android/support/v4/content/LocalBroadcastManager.java
+++ b/core-utils/java/android/support/v4/content/LocalBroadcastManager.java
@@ -16,10 +16,6 @@
package android.support.v4.content;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Set;
-
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -27,8 +23,13 @@
import android.net.Uri;
import android.os.Handler;
import android.os.Message;
+import android.support.annotation.NonNull;
import android.util.Log;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Set;
+
/**
* Helper to register for and send broadcasts of Intents to local objects
* within your process. This has a number of advantages over sending
@@ -98,7 +99,8 @@
private static final Object mLock = new Object();
private static LocalBroadcastManager mInstance;
- public static LocalBroadcastManager getInstance(Context context) {
+ @NonNull
+ public static LocalBroadcastManager getInstance(@NonNull Context context) {
synchronized (mLock) {
if (mInstance == null) {
mInstance = new LocalBroadcastManager(context.getApplicationContext());
@@ -132,7 +134,8 @@
*
* @see #unregisterReceiver
*/
- public void registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
+ public void registerReceiver(@NonNull BroadcastReceiver receiver,
+ @NonNull IntentFilter filter) {
synchronized (mReceivers) {
ReceiverRecord entry = new ReceiverRecord(filter, receiver);
ArrayList<ReceiverRecord> filters = mReceivers.get(receiver);
@@ -162,7 +165,7 @@
*
* @see #registerReceiver
*/
- public void unregisterReceiver(BroadcastReceiver receiver) {
+ public void unregisterReceiver(@NonNull BroadcastReceiver receiver) {
synchronized (mReceivers) {
final ArrayList<ReceiverRecord> filters = mReceivers.remove(receiver);
if (filters == null) {
@@ -205,7 +208,7 @@
* broadcast receivers. (Note tha delivery may not ultimately take place if one of those
* receivers is unregistered before it is dispatched.)
*/
- public boolean sendBroadcast(Intent intent) {
+ public boolean sendBroadcast(@NonNull Intent intent) {
synchronized (mReceivers) {
final String action = intent.getAction();
final String type = intent.resolveTypeIfNeeded(
@@ -281,7 +284,7 @@
* the Intent this function will block and immediately dispatch them before
* returning.
*/
- public void sendBroadcastSync(Intent intent) {
+ public void sendBroadcastSync(@NonNull Intent intent) {
if (sendBroadcast(intent)) {
executePendingBroadcasts();
}
diff --git a/core-utils/java/android/support/v4/content/MimeTypeFilter.java b/core-utils/java/android/support/v4/content/MimeTypeFilter.java
index 8734c4d..8a90c62 100644
--- a/core-utils/java/android/support/v4/content/MimeTypeFilter.java
+++ b/core-utils/java/android/support/v4/content/MimeTypeFilter.java
@@ -87,6 +87,7 @@
* Matches one nullable MIME type against an array of MIME type filters.
* @return The first matching filter, or null if nothing matches.
*/
+ @Nullable
public static String matches(
@Nullable String mimeType, @NonNull String[] filters) {
if (mimeType == null) {
@@ -108,6 +109,7 @@
* Matches multiple MIME types against an array of MIME type filters.
* @return The first matching MIME type, or null if nothing matches.
*/
+ @Nullable
public static String matches(
@Nullable String[] mimeTypes, @NonNull String filter) {
if (mimeTypes == null) {
@@ -129,6 +131,7 @@
* Matches multiple MIME types against an array of MIME type filters.
* @return The list of matching MIME types, or empty array if nothing matches.
*/
+ @NonNull
public static String[] matchesMany(
@Nullable String[] mimeTypes, @NonNull String filter) {
if (mimeTypes == null) {
diff --git a/core-utils/java/android/support/v4/content/PermissionChecker.java b/core-utils/java/android/support/v4/content/PermissionChecker.java
index 0866273..c9f18a9 100644
--- a/core-utils/java/android/support/v4/content/PermissionChecker.java
+++ b/core-utils/java/android/support/v4/content/PermissionChecker.java
@@ -24,6 +24,7 @@
import android.os.Process;
import android.support.annotation.IntDef;
import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
import android.support.annotation.RestrictTo;
import android.support.v4.app.AppOpsManagerCompat;
@@ -91,7 +92,7 @@
*/
@PermissionResult
public static int checkPermission(@NonNull Context context, @NonNull String permission,
- int pid, int uid, String packageName) {
+ int pid, int uid, @Nullable String packageName) {
if (context.checkPermission(permission, pid, uid) == PackageManager.PERMISSION_DENIED) {
return PERMISSION_DENIED;
}
@@ -146,7 +147,7 @@
*/
@PermissionResult
public static int checkCallingPermission(@NonNull Context context,
- @NonNull String permission, String packageName) {
+ @NonNull String permission, @Nullable String packageName) {
if (Binder.getCallingPid() == Process.myPid()) {
return PERMISSION_DENIED;
}
diff --git a/core-utils/gingerbread/android/support/v4/graphics/drawable/RoundedBitmapDrawable.java b/core-utils/java/android/support/v4/graphics/drawable/RoundedBitmapDrawable.java
similarity index 97%
rename from core-utils/gingerbread/android/support/v4/graphics/drawable/RoundedBitmapDrawable.java
rename to core-utils/java/android/support/v4/graphics/drawable/RoundedBitmapDrawable.java
index d515561..795126d 100644
--- a/core-utils/gingerbread/android/support/v4/graphics/drawable/RoundedBitmapDrawable.java
+++ b/core-utils/java/android/support/v4/graphics/drawable/RoundedBitmapDrawable.java
@@ -27,6 +27,8 @@
import android.graphics.RectF;
import android.graphics.Shader;
import android.graphics.drawable.Drawable;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
import android.support.annotation.RequiresApi;
import android.util.DisplayMetrics;
import android.view.Gravity;
@@ -66,6 +68,7 @@
/**
* Returns the paint used to render this drawable.
*/
+ @NonNull
public final Paint getPaint() {
return mPaint;
}
@@ -73,6 +76,7 @@
/**
* Returns the bitmap used by this drawable to render. May be null.
*/
+ @Nullable
public final Bitmap getBitmap() {
return mBitmap;
}
@@ -92,7 +96,7 @@
* @see android.graphics.Bitmap#setDensity(int)
* @see android.graphics.Bitmap#getDensity()
*/
- public void setTargetDensity(Canvas canvas) {
+ public void setTargetDensity(@NonNull Canvas canvas) {
setTargetDensity(canvas.getDensity());
}
@@ -104,7 +108,7 @@
* @see android.graphics.Bitmap#setDensity(int)
* @see android.graphics.Bitmap#getDensity()
*/
- public void setTargetDensity(DisplayMetrics metrics) {
+ public void setTargetDensity(@NonNull DisplayMetrics metrics) {
setTargetDensity(metrics.densityDpi);
}
@@ -253,7 +257,7 @@
}
@Override
- public void draw(Canvas canvas) {
+ public void draw(@NonNull Canvas canvas) {
final Bitmap bitmap = mBitmap;
if (bitmap == null) {
return;
diff --git a/core-utils/java/android/support/v4/graphics/drawable/RoundedBitmapDrawableFactory.java b/core-utils/java/android/support/v4/graphics/drawable/RoundedBitmapDrawableFactory.java
index 5e144c7..7790055 100644
--- a/core-utils/java/android/support/v4/graphics/drawable/RoundedBitmapDrawableFactory.java
+++ b/core-utils/java/android/support/v4/graphics/drawable/RoundedBitmapDrawableFactory.java
@@ -21,11 +21,15 @@
import android.graphics.BitmapFactory;
import android.graphics.Rect;
import android.os.Build;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
import android.support.v4.graphics.BitmapCompat;
import android.support.v4.view.GravityCompat;
import android.support.v4.view.ViewCompat;
import android.util.Log;
+import java.io.InputStream;
+
/**
* Constructs {@link RoundedBitmapDrawable RoundedBitmapDrawable} objects,
* either from Bitmaps directly, or from streams and files.
@@ -63,7 +67,8 @@
* Returns a new drawable by creating it from a bitmap, setting initial target density based on
* the display metrics of the resources.
*/
- public static RoundedBitmapDrawable create(Resources res, Bitmap bitmap) {
+ @NonNull
+ public static RoundedBitmapDrawable create(@NonNull Resources res, @Nullable Bitmap bitmap) {
if (Build.VERSION.SDK_INT >= 21) {
return new RoundedBitmapDrawable21(res, bitmap);
}
@@ -73,8 +78,8 @@
/**
* Returns a new drawable, creating it by opening a given file path and decoding the bitmap.
*/
- public static RoundedBitmapDrawable create(Resources res,
- String filepath) {
+ @NonNull
+ public static RoundedBitmapDrawable create(@NonNull Resources res, @NonNull String filepath) {
final RoundedBitmapDrawable drawable = create(res, BitmapFactory.decodeFile(filepath));
if (drawable.getBitmap() == null) {
Log.w(TAG, "RoundedBitmapDrawable cannot decode " + filepath);
@@ -86,8 +91,8 @@
/**
* Returns a new drawable, creating it by decoding a bitmap from the given input stream.
*/
- public static RoundedBitmapDrawable create(Resources res,
- java.io.InputStream is) {
+ @NonNull
+ public static RoundedBitmapDrawable create(@NonNull Resources res, @NonNull InputStream is) {
final RoundedBitmapDrawable drawable = create(res, BitmapFactory.decodeStream(is));
if (drawable.getBitmap() == null) {
Log.w(TAG, "RoundedBitmapDrawable cannot decode " + is);
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 c9e3e18..0d957dc 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
@@ -112,7 +112,7 @@
val indexInputs = entityIndices + fieldIndices + superIndices
val indices = validateAndCreateIndices(indexInputs, pojo)
- val primaryKey = findPrimaryKey(pojo.fields, pojo.embeddedFields)
+ val primaryKey = findAndValidatePrimaryKey(pojo.fields, pojo.embeddedFields)
val affinity = primaryKey.fields.firstOrNull()?.affinity ?: SQLTypeAffinity.TEXT
context.checker.check(
!primaryKey.autoGenerateId || affinity == SQLTypeAffinity.INTEGER,
@@ -226,7 +226,7 @@
}.filterNotNull()
}
- private fun findPrimaryKey(fields: List<Field>, embeddedFields: List<EmbeddedField>)
+ private fun findAndValidatePrimaryKey(fields: List<Field>, embeddedFields: List<EmbeddedField>)
: PrimaryKey {
val candidates = collectPrimaryKeysFromEntityAnnotations(element, fields) +
collectPrimaryKeysFromPrimaryKeyAnnotations(fields) +
@@ -242,7 +242,15 @@
.map { candidate ->
candidate.fields.map { field ->
context.checker.check(field.nonNull, field.element,
- ProcessorErrors.PRIMARY_KEY_NULL)
+ ProcessorErrors.primaryKeyNull(field.getPath()))
+ // Validate parents for nullability
+ var parent = field.parent
+ while(parent != null) {
+ val parentField = parent.field
+ context.checker.check(parentField.nonNull, parentField.element,
+ ProcessorErrors.primaryKeyNull(parentField.getPath()))
+ parent = parentField.parent
+ }
}
}
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 a576aa2..62429eb 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
@@ -25,7 +25,6 @@
import android.arch.persistence.room.vo.CustomTypeConverter
import android.arch.persistence.room.vo.Field
import com.squareup.javapoet.TypeName
-import javax.lang.model.type.TypeMirror
object ProcessorErrors {
private fun String.trim(): String {
@@ -134,9 +133,9 @@
val LIVE_DATA_QUERY_WITHOUT_SELECT = "LiveData return type can only be used with SELECT" +
" queries."
- val LIVE_DATA_QUERY_NOTHING_TO_OBSERVE = "LiveData return type can only be used with SELECT" +
- " queries that directly or indirectly (via @Relation, for example) access at least" +
- " one table.";
+ val OBSERVABLE_QUERY_NOTHING_TO_OBSERVE = "Observable query return type (LiveData, Flowable" +
+ " etc) can only be used with SELECT queries that directly or indirectly (via" +
+ " @Relation, for example) access at least one table."
private val TOO_MANY_MATCHING_GETTERS = "Ambiguous getter for %s. All of the following " +
"match: %s. You can @Ignore the ones that you don't want to match."
@@ -450,7 +449,10 @@
val PAGING_SPECIFY_DATA_SOURCE_TYPE = "For now, Room only supports TiledDataSource class."
- val PRIMARY_KEY_NULL = "You must annotate primary keys with @NonNull. SQLite considers this a " +
- "bug and Room does not allow it. See SQLite docs for details: " +
- "https://www.sqlite.org/lang_createtable.html"
+ fun primaryKeyNull(field: String): String{
+ return "You must annotate primary keys with @NonNull. \"$field\" is nullable. SQLite " +
+ "considers this a " +
+ "bug and Room does not allow it. See SQLite docs for details: " +
+ "https://www.sqlite.org/lang_createtable.html"
+ }
}
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/ObservableQueryResultBinderProvider.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/ObservableQueryResultBinderProvider.kt
new file mode 100644
index 0000000..89b0072
--- /dev/null
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/ObservableQueryResultBinderProvider.kt
@@ -0,0 +1,51 @@
+/*
+ * 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.solver
+
+import android.arch.persistence.room.parser.ParsedQuery
+import android.arch.persistence.room.processor.Context
+import android.arch.persistence.room.processor.ProcessorErrors
+import android.arch.persistence.room.solver.query.result.QueryResultAdapter
+import android.arch.persistence.room.solver.query.result.QueryResultBinder
+import javax.lang.model.type.DeclaredType
+import javax.lang.model.type.TypeMirror
+
+/**
+ * Binder provider class that has common functionality for observables.
+ */
+abstract class ObservableQueryResultBinderProvider(val context: Context)
+ : QueryResultBinderProvider {
+ protected abstract fun extractTypeArg(declared: DeclaredType) : TypeMirror
+ protected abstract fun create(typeArg: TypeMirror,
+ resultAdapter: QueryResultAdapter?,
+ tableNames : Set<String>) : QueryResultBinder
+
+ override final fun provide(declared: DeclaredType, query: ParsedQuery): QueryResultBinder {
+ val typeArg = extractTypeArg(declared)
+ val adapter = context.typeAdapterStore.findQueryResultAdapter(typeArg, query)
+ val tableNames = ((adapter?.accessedTableNames() ?: emptyList()) +
+ query.tables.map { it.name }).toSet()
+ context.checker.check(!tableNames.isEmpty(),
+ declared.asElement(),
+ ProcessorErrors.OBSERVABLE_QUERY_NOTHING_TO_OBSERVE)
+ return create(
+ typeArg = typeArg,
+ resultAdapter = adapter,
+ tableNames = tableNames
+ )
+ }
+}
\ No newline at end of file
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/binderprovider/FlowableQueryResultBinderProvider.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/binderprovider/FlowableQueryResultBinderProvider.kt
index 828f5a7..6a2c901 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/binderprovider/FlowableQueryResultBinderProvider.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/binderprovider/FlowableQueryResultBinderProvider.kt
@@ -18,17 +18,17 @@
import android.arch.persistence.room.ext.RoomRxJava2TypeNames
import android.arch.persistence.room.ext.RxJava2TypeNames
-import android.arch.persistence.room.parser.ParsedQuery
import android.arch.persistence.room.processor.Context
import android.arch.persistence.room.processor.ProcessorErrors
-import android.arch.persistence.room.solver.QueryResultBinderProvider
+import android.arch.persistence.room.solver.ObservableQueryResultBinderProvider
import android.arch.persistence.room.solver.query.result.FlowableQueryResultBinder
+import android.arch.persistence.room.solver.query.result.QueryResultAdapter
import android.arch.persistence.room.solver.query.result.QueryResultBinder
-import com.google.common.annotations.VisibleForTesting
import javax.lang.model.type.DeclaredType
import javax.lang.model.type.TypeMirror
-class FlowableQueryResultBinderProvider(val context : Context) : QueryResultBinderProvider {
+class FlowableQueryResultBinderProvider(context: Context) :
+ ObservableQueryResultBinderProvider(context) {
private val flowableTypeMirror: TypeMirror? by lazy {
context.processingEnv.elementUtils
.getTypeElement(RxJava2TypeNames.FLOWABLE.toString())?.asType()
@@ -39,10 +39,14 @@
.getTypeElement(RoomRxJava2TypeNames.RX_ROOM.toString()) != null
}
- override fun provide(declared: DeclaredType, query: ParsedQuery): QueryResultBinder {
- val typeArg = declared.typeArguments.first()
- return FlowableQueryResultBinder(typeArg, query.tables.map { it.name },
- context.typeAdapterStore.findQueryResultAdapter(typeArg, query))
+ override fun extractTypeArg(declared: DeclaredType): TypeMirror = declared.typeArguments.first()
+
+ override fun create(typeArg: TypeMirror, resultAdapter: QueryResultAdapter?,
+ tableNames: Set<String>): QueryResultBinder {
+ return FlowableQueryResultBinder(
+ typeArg = typeArg,
+ queryTableNames = tableNames,
+ adapter = resultAdapter)
}
override fun matches(declared: DeclaredType): Boolean =
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/binderprovider/LiveDataQueryResultBinderProvider.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/binderprovider/LiveDataQueryResultBinderProvider.kt
index 7e6725f..650ec19 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/binderprovider/LiveDataQueryResultBinderProvider.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/binderprovider/LiveDataQueryResultBinderProvider.kt
@@ -17,34 +17,29 @@
package android.arch.persistence.room.solver.binderprovider
import android.arch.persistence.room.ext.LifecyclesTypeNames
-import android.arch.persistence.room.parser.ParsedQuery
import android.arch.persistence.room.processor.Context
-import android.arch.persistence.room.processor.ProcessorErrors
-import android.arch.persistence.room.solver.QueryResultBinderProvider
+import android.arch.persistence.room.solver.ObservableQueryResultBinderProvider
import android.arch.persistence.room.solver.query.result.LiveDataQueryResultBinder
+import android.arch.persistence.room.solver.query.result.QueryResultAdapter
import android.arch.persistence.room.solver.query.result.QueryResultBinder
import javax.lang.model.type.DeclaredType
import javax.lang.model.type.TypeMirror
-class LiveDataQueryResultBinderProvider(val context : Context) : QueryResultBinderProvider {
+class LiveDataQueryResultBinderProvider(context : Context)
+ : ObservableQueryResultBinderProvider(context) {
private val liveDataTypeMirror: TypeMirror? by lazy {
context.processingEnv.elementUtils
.getTypeElement(LifecyclesTypeNames.LIVE_DATA.toString())?.asType()
}
- override fun provide(declared: DeclaredType, query: ParsedQuery): QueryResultBinder {
- val liveDataTypeArg = declared.typeArguments.first()
- val queryResultAdapter =
- context.typeAdapterStore.findQueryResultAdapter(liveDataTypeArg, query)
- val tableNames = ((queryResultAdapter?.accessedTableNames() ?: emptyList()) +
- query.tables.map { it.name }).toSet()
- context.checker.check(!tableNames.isEmpty(),
- declared.asElement(),
- ProcessorErrors.LIVE_DATA_QUERY_NOTHING_TO_OBSERVE);
+ override fun extractTypeArg(declared: DeclaredType): TypeMirror = declared.typeArguments.first()
+
+ override fun create(typeArg: TypeMirror, resultAdapter: QueryResultAdapter?,
+ tableNames: Set<String>): QueryResultBinder {
return LiveDataQueryResultBinder(
- liveDataTypeArg,
- tableNames,
- queryResultAdapter)
+ typeArg = typeArg,
+ tableNames = tableNames,
+ adapter = resultAdapter)
}
override fun matches(declared: DeclaredType): Boolean =
diff --git a/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/query/result/FlowableQueryResultBinder.kt b/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/query/result/FlowableQueryResultBinder.kt
index dbd66ce..5c8e3e7 100644
--- a/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/query/result/FlowableQueryResultBinder.kt
+++ b/room/compiler/src/main/kotlin/android/arch/persistence/room/solver/query/result/FlowableQueryResultBinder.kt
@@ -34,7 +34,7 @@
/**
* Binds the result as an RxJava2 Flowable.
*/
-class FlowableQueryResultBinder(val typeArg: TypeMirror, val queryTableNames: List<String>,
+class FlowableQueryResultBinder(val typeArg: TypeMirror, val queryTableNames: Set<String>,
adapter: QueryResultAdapter?)
: BaseObservableQueryResultBinder(adapter) {
override fun convertAndReturn(roomSQLiteQueryVar: String, dbField: FieldSpec,
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 c25d001..ababef6 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
@@ -18,7 +18,6 @@
import COMMON
import android.arch.persistence.room.parser.SQLTypeAffinity
-import android.arch.persistence.room.processor.ProcessorErrors.PRIMARY_KEY_NULL
import android.arch.persistence.room.processor.ProcessorErrors.RELATION_IN_ENTITY
import android.arch.persistence.room.vo.CallType
import android.arch.persistence.room.vo.Field
@@ -1163,7 +1162,7 @@
""") { entity, _ ->
assertThat(entity.primaryKey.fields.size, `is`(1))
assertThat(entity.primaryKey.fields.firstOrNull()?.name, `is`("id"))
- }.failsToCompile().withErrorContaining(PRIMARY_KEY_NULL)
+ }.failsToCompile().withErrorContaining(ProcessorErrors.primaryKeyNull("id"))
}
@Test
@@ -1175,7 +1174,8 @@
@PrimaryKey
public String anotherId;
""") { entity, _ ->
- }.failsToCompile().withErrorContaining(PRIMARY_KEY_NULL)
+ }.failsToCompile().withErrorContaining(ProcessorErrors.primaryKeyNull("id"))
+ .and().withErrorContaining(ProcessorErrors.primaryKeyNull("anotherId"))
}
@Test
@@ -1188,7 +1188,7 @@
@PrimaryKey
public String anotherId;
""") { entity, _ ->
- }.failsToCompile().withErrorContaining(PRIMARY_KEY_NULL)
+ }.failsToCompile().withErrorContaining(ProcessorErrors.primaryKeyNull("anotherId"))
}
@Test
@@ -1199,7 +1199,7 @@
public String foo;
""",
attributes = mapOf("primaryKeys" to "{\"id\", \"foo\"}")) { _, _ ->
- }.failsToCompile().withErrorContaining(PRIMARY_KEY_NULL)
+ }.failsToCompile().withErrorContaining(ProcessorErrors.primaryKeyNull("foo"))
}
@Test
@@ -1216,6 +1216,176 @@
}
@Test
+ fun primaryKey_nullableEmbedded(){
+ singleEntity(
+ """
+ public int id;
+
+ @Embedded(prefix = "bar_")
+ @PrimaryKey
+ public Foo foo;
+
+ static class Foo {
+ public int a;
+ public int b;
+ }
+ """) { _, _ ->
+ }.failsToCompile().withErrorContaining(ProcessorErrors.primaryKeyNull("foo"))
+ }
+
+ @Test
+ fun primaryKey_nullableEmbeddedObject(){
+ singleEntity(
+ """
+ public int id;
+
+ @Embedded(prefix = "bar_")
+ @PrimaryKey
+ public Foo foo;
+
+ static class Foo {
+ public String a;
+ public String b;
+ }
+ """) { _, _ ->
+ }.failsToCompile().withErrorContaining(ProcessorErrors.primaryKeyNull("foo > a"))
+ .and().withErrorContaining(ProcessorErrors.primaryKeyNull("foo > b"))
+ .and().withErrorContaining(ProcessorErrors.primaryKeyNull("foo"))
+ .and().withErrorCount(3)
+ }
+
+ @Test
+ fun primaryKey_nullableEmbeddedObject_multipleParents(){
+ singleEntity(
+ """
+ public int id;
+
+ @Embedded(prefix = "bar_")
+ @PrimaryKey
+ public Foo foo;
+
+ static class Foo {
+ @Embedded(prefix = "baz_")
+ public Baz a;
+ public String b;
+
+ static class Baz {
+ public String bb;
+ }
+ }
+ """) { _, _ ->
+ }.failsToCompile().withErrorContaining(ProcessorErrors.primaryKeyNull("foo > a"))
+ .and().withErrorContaining(ProcessorErrors.primaryKeyNull("foo > b"))
+ .and().withErrorContaining(ProcessorErrors.primaryKeyNull("foo"))
+ .and().withErrorContaining(ProcessorErrors.primaryKeyNull("foo > a > bb"))
+ .and().withErrorCount(4)
+ }
+
+ @Test
+ fun primaryKey_nullableEmbeddedInherited(){
+ val parent = JavaFileObjects.forSourceLines("foo.bar.Base",
+ """
+ package foo.bar;
+ import android.support.annotation.NonNull;
+ import android.arch.persistence.room.*;
+
+ public class Base {
+ long baseId;
+ String name, lastName;
+ @Embedded(prefix = "bar_")
+ @PrimaryKey
+ public Foo foo;
+
+ static class Foo {
+ public int a;
+ public int b;
+ }
+ }
+ """)
+ singleEntity(
+ """
+ public int id;
+ """,
+ baseClass = "foo.bar.Base",
+ jfos = listOf(parent)) { _, _ ->
+ }.failsToCompile().withErrorContaining(ProcessorErrors.primaryKeyNull("foo"))
+ .and().withErrorContaining(ProcessorErrors.primaryKeyNull("foo > a"))
+ .and().withErrorContaining(ProcessorErrors.primaryKeyNull("foo > b"))
+ .and().withErrorCount(3)
+ }
+
+ @Test
+ fun primaryKey_nullableOverrideViaEmbedded() {
+ val parent = JavaFileObjects.forSourceLines("foo.bar.Base",
+ """
+ package foo.bar;
+ import android.arch.persistence.room.*;
+
+ @Entity(primaryKeys = "baseId")
+ public class Base {
+ long baseId;
+ String name, lastName;
+ }
+ """)
+ singleEntity(
+ """
+ public int id;
+ @Embedded(prefix = "bar_")
+ @PrimaryKey
+ public Foo foo;
+
+ static class Foo {
+ public int a;
+ public int b;
+ }
+ """,
+ baseClass = "foo.bar.Base",
+ jfos = listOf(parent)) { _, _ ->
+ }.failsToCompile().withErrorContaining(ProcessorErrors.primaryKeyNull("foo"))
+ .and().withErrorContaining(ProcessorErrors.primaryKeyNull("foo > a"))
+ .and().withErrorContaining(ProcessorErrors.primaryKeyNull("foo > b"))
+ .and().withNoteContaining(
+ "PrimaryKey[baseId] is overridden by PrimaryKey[foo > a, foo > b]")
+ .and().withErrorCount(3)
+ }
+
+ @Test
+ fun primaryKey_nullableOverrideEmbedded() {
+ val parent = JavaFileObjects.forSourceLines("foo.bar.Base",
+ """
+ package foo.bar;
+ import android.support.annotation.NonNull;
+ import android.arch.persistence.room.*;
+
+ public class Base {
+ long baseId;
+ String name, lastName;
+ @Embedded(prefix = "bar_")
+ @PrimaryKey
+ public Foo foo;
+
+ static class Foo {
+ public int a;
+ public int b;
+ }
+ }
+ """)
+ singleEntity(
+ """
+ @PrimaryKey
+ public int id;
+ """,
+ baseClass = "foo.bar.Base",
+ jfos = listOf(parent)) { _, _ ->
+ }.failsToCompile().withErrorContaining(ProcessorErrors.primaryKeyNull("foo"))
+ .and().withErrorContaining(ProcessorErrors.primaryKeyNull("foo > a"))
+ .and().withErrorContaining(ProcessorErrors.primaryKeyNull("foo > b"))
+ .and().withNoteContaining(
+ "PrimaryKey[foo > a, foo > b] is overridden by PrimaryKey[id]")
+ .and().withErrorCount(3)
+ }
+
+ @Test
fun relationInEntity() {
singleEntity(
"""
diff --git a/room/compiler/src/test/kotlin/android/arch/persistence/room/processor/QueryMethodProcessorTest.kt b/room/compiler/src/test/kotlin/android/arch/persistence/room/processor/QueryMethodProcessorTest.kt
index 1172194..7e892b7 100644
--- a/room/compiler/src/test/kotlin/android/arch/persistence/room/processor/QueryMethodProcessorTest.kt
+++ b/room/compiler/src/test/kotlin/android/arch/persistence/room/processor/QueryMethodProcessorTest.kt
@@ -312,7 +312,7 @@
""") { _, _ ->
// do nothing
}.failsToCompile()
- .withErrorContaining(ProcessorErrors.LIVE_DATA_QUERY_NOTHING_TO_OBSERVE)
+ .withErrorContaining(ProcessorErrors.OBSERVABLE_QUERY_NOTHING_TO_OBSERVE)
}
@Test
@@ -324,7 +324,7 @@
""") { _, _ ->
// do nothing
}.failsToCompile()
- .withErrorContaining(ProcessorErrors.LIVE_DATA_QUERY_NOTHING_TO_OBSERVE)
+ .withErrorContaining(ProcessorErrors.OBSERVABLE_QUERY_NOTHING_TO_OBSERVE)
}
@Test
diff --git a/room/integration-tests/testapp/src/androidTest/java/android/arch/persistence/room/integration/testapp/dao/UserPetDao.java b/room/integration-tests/testapp/src/androidTest/java/android/arch/persistence/room/integration/testapp/dao/UserPetDao.java
index 3507aee..eb15901 100644
--- a/room/integration-tests/testapp/src/androidTest/java/android/arch/persistence/room/integration/testapp/dao/UserPetDao.java
+++ b/room/integration-tests/testapp/src/androidTest/java/android/arch/persistence/room/integration/testapp/dao/UserPetDao.java
@@ -33,6 +33,8 @@
import java.util.List;
+import io.reactivex.Flowable;
+
@Dao
public interface UserPetDao {
@Query("SELECT * FROM User u, Pet p WHERE u.mId = p.mUserId")
@@ -62,6 +64,9 @@
@Query("SELECT * FROM User u where u.mId = :userId")
LiveData<UserAndAllPets> liveUserWithPets(int userId);
+ @Query("SELECT * FROM User u where u.mId = :userId")
+ Flowable<UserAndAllPets> flowableUserWithPets(int userId);
+
@Query("SELECT * FROM User u where u.mId = :uid")
EmbeddedUserAndAllPets loadUserAndPetsAsEmbedded(int uid);
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 1bbc140..98783f2 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
@@ -22,7 +22,9 @@
import android.arch.core.executor.AppToolkitTaskExecutor;
import android.arch.core.executor.TaskExecutor;
import android.arch.persistence.room.EmptyResultSetException;
+import android.arch.persistence.room.integration.testapp.vo.Pet;
import android.arch.persistence.room.integration.testapp.vo.User;
+import android.arch.persistence.room.integration.testapp.vo.UserAndAllPets;
import android.support.test.filters.MediumTest;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
@@ -38,6 +40,7 @@
import java.util.List;
import io.reactivex.disposables.Disposable;
+import io.reactivex.functions.Predicate;
import io.reactivex.observers.TestObserver;
import io.reactivex.schedulers.TestScheduler;
import io.reactivex.subscribers.TestSubscriber;
@@ -269,4 +272,37 @@
subscriber.cancel();
subscriber.assertNoErrors();
}
+
+ @Test
+ public void flowableWithRelation() throws InterruptedException {
+ final TestSubscriber<UserAndAllPets> subscriber = new TestSubscriber<>();
+
+ mUserPetDao.flowableUserWithPets(3).subscribe(subscriber);
+ drain();
+ subscriber.assertSubscribed();
+
+ drain();
+ subscriber.assertNoValues();
+
+ final User user = TestUtil.createUser(3);
+ mUserDao.insert(user);
+ drain();
+ subscriber.assertValue(new Predicate<UserAndAllPets>() {
+ @Override
+ public boolean test(UserAndAllPets userAndAllPets) throws Exception {
+ return userAndAllPets.user.equals(user);
+ }
+ });
+ subscriber.assertValueCount(1);
+ final Pet[] pets = TestUtil.createPetsForUser(3, 1, 2);
+ mPetDao.insertAll(pets);
+ drain();
+ subscriber.assertValueAt(1, new Predicate<UserAndAllPets>() {
+ @Override
+ public boolean test(UserAndAllPets userAndAllPets) throws Exception {
+ return userAndAllPets.user.equals(user)
+ && userAndAllPets.pets.equals(Arrays.asList(pets));
+ }
+ });
+ }
}
diff --git a/v7/preference/src/android/support/v7/preference/Preference.java b/v7/preference/src/android/support/v7/preference/Preference.java
index cfc4311..fa8461d 100644
--- a/v7/preference/src/android/support/v7/preference/Preference.java
+++ b/v7/preference/src/android/support/v7/preference/Preference.java
@@ -31,7 +31,6 @@
import android.support.annotation.Nullable;
import android.support.annotation.RestrictTo;
import android.support.v4.content.ContextCompat;
-import android.support.v4.content.SharedPreferencesCompat;
import android.support.v4.content.res.TypedArrayUtils;
import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
import android.text.TextUtils;
@@ -1543,7 +1542,7 @@
private void tryCommit(@NonNull SharedPreferences.Editor editor) {
if (mPreferenceManager.shouldCommit()) {
- SharedPreferencesCompat.EditorCompat.getInstance().apply(editor);
+ editor.apply();
}
}
diff --git a/v7/preference/src/android/support/v7/preference/PreferenceManager.java b/v7/preference/src/android/support/v7/preference/PreferenceManager.java
index 83af86c..19b6908 100644
--- a/v7/preference/src/android/support/v7/preference/PreferenceManager.java
+++ b/v7/preference/src/android/support/v7/preference/PreferenceManager.java
@@ -25,7 +25,6 @@
import android.support.annotation.Nullable;
import android.support.annotation.RestrictTo;
import android.support.v4.content.ContextCompat;
-import android.support.v4.content.SharedPreferencesCompat;
import android.text.TextUtils;
/**
@@ -464,10 +463,9 @@
pm.setSharedPreferencesMode(sharedPreferencesMode);
pm.inflateFromResource(context, resId, null);
- SharedPreferences.Editor editor =
- defaultValueSp.edit().putBoolean(KEY_HAS_SET_DEFAULT_VALUES, true);
-
- SharedPreferencesCompat.EditorCompat.getInstance().apply(editor);
+ defaultValueSp.edit()
+ .putBoolean(KEY_HAS_SET_DEFAULT_VALUES, true)
+ .apply();
}
}
@@ -511,7 +509,7 @@
private void setNoCommit(boolean noCommit) {
if (!noCommit && mEditor != null) {
- SharedPreferencesCompat.EditorCompat.getInstance().apply(mEditor);
+ mEditor.apply();
}
mNoCommit = noCommit;
}