1c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay/*
2c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay * Copyright (C) 2017 The Android Open Source Project
3c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay *
4c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay * Licensed under the Apache License, Version 2.0 (the "License");
5c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay * you may not use this file except in compliance with the License.
6c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay * You may obtain a copy of the License at
7c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay *
8c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay *      http://www.apache.org/licenses/LICENSE-2.0
9c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay *
10c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay * Unless required by applicable law or agreed to in writing, software
11c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay * distributed under the License is distributed on an "AS IS" BASIS,
12c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay * See the License for the specific language governing permissions and
14c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay * limitations under the License.
15c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay */
16c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay
17ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikaspackage androidx.contentpager.content;
18c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay
19ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport static androidx.core.util.Preconditions.checkArgument;
20c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay
21c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKayimport android.content.ContentResolver;
22c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKayimport android.database.Cursor;
23c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKayimport android.net.Uri;
24c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKayimport android.os.Build;
25c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKayimport android.os.Bundle;
26c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKayimport android.os.CancellationSignal;
27fb4b6f71b6a30ea0acc67fce323853e4beb096d7Aurimas Liutikasimport android.util.Log;
28fb4b6f71b6a30ea0acc67fce323853e4beb096d7Aurimas Liutikas
29ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport androidx.annotation.NonNull;
30ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport androidx.annotation.Nullable;
31c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay
32c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKayimport java.util.Arrays;
33c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay
34c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay/**
35c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay * Encapsulates information related to calling {@link ContentResolver#query},
36c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay * including the logic determining the best query method to call.
37c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay */
38c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKaypublic final class Query {
39c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay
40c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    private static final boolean DEBUG = true;
41c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    private static final String TAG = "Query";
42c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay
43c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    private final Uri mUri;
44c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    private final @Nullable String[] mProjection;
45c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    private final Bundle mQueryArgs;
46c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay
47c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    private final int mId;
48c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    private final int mOffset;
49c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    private final int mLimit;
50c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay
51c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    private final CancellationSignal mCancellationSignal;
52c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    private final ContentPager.ContentCallback mCallback;
53c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay
54c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    Query(
55c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay            @NonNull Uri uri,
56c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay            @Nullable String[] projection,
57c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay            @NonNull Bundle args,
58c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay            @Nullable CancellationSignal cancellationSignal,
59c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay            @NonNull ContentPager.ContentCallback callback) {
60c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay
61c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        checkArgument(uri != null);
62c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        checkArgument(args != null);
63c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        checkArgument(callback != null);
64c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay
65c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        this.mUri = uri;
66c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        this.mProjection = projection;
67c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        this.mQueryArgs = args;
68c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        this.mCancellationSignal = cancellationSignal;
69c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        this.mCallback = callback;
70c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay
71c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        this.mOffset = args.getInt(ContentPager.QUERY_ARG_OFFSET, -1);
72c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        this.mLimit = args.getInt(ContentPager.QUERY_ARG_LIMIT, -1);
73c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay
74c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        // NOTE: We omit mProjection and other details from ID. If a client wishes
75c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        // to request a page with a different mProjection or sorting, they should
76c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        // wait for first request to finish. Same goes for mCallback.
77c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        this.mId = uri.hashCode() << 16 | (mOffset | (mLimit << 8));
78c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay
79c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        checkArgument(mOffset >= 0);  // mOffset must be set, mLimit is optional.
80c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    }
81c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay
82c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    /**
83c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay     * @return the id for this query. Derived from Uri as well as paging arguments.
84c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay     */
85c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    public int getId() {
86c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        return mId;
87c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    }
88c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay
89c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    /**
90c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay     * @return the Uri.
91c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay     */
92c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    public @NonNull Uri getUri() {
93c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        return mUri;
94c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    }
95c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay
96c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    /**
97c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay     * @return the offset.
98c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay     */
99c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    public int getOffset() {
100c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        return mOffset;
101c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    }
102c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay
103c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    /**
104c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay     * @return the limit.
105c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay     */
106c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    public int getLimit() {
107c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        return mLimit;
108c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    }
109c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay
110c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    @NonNull ContentPager.ContentCallback getCallback() {
111c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        return mCallback;
112c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    }
113c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay
114c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    @Nullable Cursor run(@NonNull ContentResolver resolver) {
115c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
116c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay            return resolver.query(
117c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay                    mUri,
118c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay                    mProjection,
119c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay                    mQueryArgs,
120c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay                    mCancellationSignal);
121c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        }
122c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay
123c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
124c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay            if (DEBUG) Log.d(TAG, "Falling back to pre-O query method.");
125c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay            return resolver.query(
126c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay                    mUri,
127c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay                    mProjection,
128c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay                    null,
129c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay                    null,
130c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay                    null,
131c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay                    mCancellationSignal);
132c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        }
133c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay
134c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        if (DEBUG) Log.d(TAG, "Falling back to pre-jellybean query method.");
135c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        return resolver.query(
136c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay                mUri,
137c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay                mProjection,
138c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay                null,
139c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay                null,
140c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay                null);
141c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    }
142c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay
143c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    void cancel() {
144c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
145c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay            if (mCancellationSignal != null && !mCancellationSignal.isCanceled()) {
146c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay                if (DEBUG) {
147c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay                    Log.d(TAG, "Attemping to cancel query provider processings: " + this);
148c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay                }
149c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay                mCancellationSignal.cancel();
150c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay            }
151c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        }
152c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    }
153c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay
154c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    @Override
155c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    public boolean equals(Object obj) {
156c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        if (obj == null) {
157c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay            return false;
158c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        }
159c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay
160c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        if (this == obj) {
161c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay            return true;
162c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        }
163c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay
164c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        if (!(obj instanceof Query)) {
165c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay            return false;
166c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        }
167c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay
168c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        Query other = (Query) obj;
169c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay
170c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        return mId == other.mId
171c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay                && mUri.equals(other.mUri)
172c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay                && mOffset == other.mOffset
173c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay                && mLimit == other.mLimit;
174c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    }
175c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay
176c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    @Override
177c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    public int hashCode() {
178c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        return getId();
179c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    }
180c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay
181c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    @Override
182c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    public String toString() {
183c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay        return "Query{"
184c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay                + "id:" + mId
185c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay                + " uri:" + mUri
186c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay                + " projection:" + Arrays.toString(mProjection)
187c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay                + " offset:" + mOffset
188c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay                + " limit:" + mLimit
189c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay                + " cancellationSignal:" + mCancellationSignal
190c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay                + " callback:" + mCallback
191c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay                + "}";
192c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay    }
193c01ec9664a26a603d90b067d1ca7ca39950eb025Steve McKay}
194