You've already forked android_translation_layer
mirror of
https://gitlab.com/android_translation_layer/android_translation_layer.git
synced 2025-10-27 11:48:10 -07:00
implement ContentResolver
ContentUris.java and UriMatcher.java are copied from AOSP
This commit is contained in:
@@ -1,8 +1,15 @@
|
||||
package android.content;
|
||||
|
||||
import android.content.pm.PackageParser;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class ContentProvider {
|
||||
import android.content.pm.PackageParser;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
|
||||
public abstract class ContentProvider {
|
||||
|
||||
static Map<String, ContentProvider> providers = new HashMap<String, ContentProvider>();
|
||||
|
||||
static void createContentProviders() throws Exception {
|
||||
for (PackageParser.Provider provider_parsed : Context.pkg.providers) {
|
||||
@@ -11,6 +18,7 @@ public class ContentProvider {
|
||||
Class<? extends ContentProvider> providerCls = Class.forName(providerName).asSubclass(ContentProvider.class);
|
||||
ContentProvider provider = providerCls.getConstructor().newInstance();
|
||||
provider.onCreate();
|
||||
providers.put(provider_parsed.info.authority, provider);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,4 +28,10 @@ public class ContentProvider {
|
||||
return new Context();
|
||||
}
|
||||
|
||||
public abstract Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder);
|
||||
|
||||
public abstract Uri insert(Uri uri, ContentValues values);
|
||||
|
||||
public abstract int delete(Uri uri, String selection, String[] selectionArgs);
|
||||
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ package android.content;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
|
||||
import android.database.AbstractCursor;
|
||||
import android.database.ContentObserver;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
@@ -28,17 +27,11 @@ public class ContentResolver {
|
||||
}
|
||||
|
||||
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
|
||||
return new AbstractCursor() {
|
||||
public int getCount() { return 0; }
|
||||
public String[] getColumnNames() { return new String[0]; }
|
||||
public String getString(int column) { throw new IndexOutOfBoundsException(); }
|
||||
public short getShort(int column) { throw new IndexOutOfBoundsException(); }
|
||||
public int getInt(int column) { throw new IndexOutOfBoundsException(); }
|
||||
public long getLong(int column) { throw new IndexOutOfBoundsException(); }
|
||||
public float getFloat(int column) { throw new IndexOutOfBoundsException(); }
|
||||
public double getDouble(int column) { throw new IndexOutOfBoundsException(); }
|
||||
public boolean isNull(int column) { throw new IndexOutOfBoundsException(); }
|
||||
};
|
||||
ContentProvider provider = ContentProvider.providers.get(uri.getAuthority());
|
||||
if (provider != null)
|
||||
return provider.query(uri, projection, selection, selectionArgs, sortOrder);
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder, CancellationSignal cancellationSignal) {
|
||||
@@ -46,6 +39,18 @@ public class ContentResolver {
|
||||
}
|
||||
|
||||
public int delete(Uri uri, String selection, String[] selectionArgs) {
|
||||
ContentProvider provider = ContentProvider.providers.get(uri.getAuthority());
|
||||
if (provider != null)
|
||||
return provider.delete(uri, selection, selectionArgs);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
public Uri insert(Uri uri, ContentValues values) {
|
||||
ContentProvider provider = ContentProvider.providers.get(uri.getAuthority());
|
||||
if (provider != null)
|
||||
return provider.insert(uri, values);
|
||||
else
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
140
src/api-impl/android/content/ContentUris.java
Normal file
140
src/api-impl/android/content/ContentUris.java
Normal file
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
* Copyright (C) 2007 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.content;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import android.net.Uri;
|
||||
|
||||
/**
|
||||
* Utility methods useful for working with {@link android.net.Uri} objects
|
||||
* that use the "content" (content://) scheme.
|
||||
*
|
||||
*<p>
|
||||
* Content URIs have the syntax
|
||||
*</p>
|
||||
*<p>
|
||||
* <code>content://<em>authority</em>/<em>path</em>/<em>id</em></code>
|
||||
*</p>
|
||||
*<dl>
|
||||
* <dt>
|
||||
* <code>content:</code>
|
||||
* </dt>
|
||||
* <dd>
|
||||
* The scheme portion of the URI. This is always set to {@link
|
||||
* android.content.ContentResolver#SCHEME_CONTENT ContentResolver.SCHEME_CONTENT} (value
|
||||
* <code>content://</code>).
|
||||
* </dd>
|
||||
* <dt>
|
||||
* <em>authority</em>
|
||||
* </dt>
|
||||
* <dd>
|
||||
* A string that identifies the entire content provider. All the content URIs for the provider
|
||||
* start with this string. To guarantee a unique authority, providers should consider
|
||||
* using an authority that is the same as the provider class' package identifier.
|
||||
* </dd>
|
||||
* <dt>
|
||||
* <em>path</em>
|
||||
* </dt>
|
||||
* <dd>
|
||||
* Zero or more segments, separated by a forward slash (<code>/</code>), that identify
|
||||
* some subset of the provider's data. Most providers use the path part to identify
|
||||
* individual tables. Individual segments in the path are often called
|
||||
* "directories" although they do not refer to file directories. The right-most
|
||||
* segment in a path is often called a "twig"
|
||||
* </dd>
|
||||
* <dt>
|
||||
* <em>id</em>
|
||||
* </dt>
|
||||
* <dd>
|
||||
* A unique numeric identifier for a single row in the subset of data identified by the
|
||||
* preceding path part. Most providers recognize content URIs that contain an id part
|
||||
* and give them special handling. A table that contains a column named <code>_ID</code>
|
||||
* often expects the id part to be a particular value for that column.
|
||||
* </dd>
|
||||
*</dl>
|
||||
*
|
||||
*/
|
||||
public class ContentUris {
|
||||
|
||||
/**
|
||||
* Converts the last path segment to a long.
|
||||
*
|
||||
* <p>This supports a common convention for content URIs where an ID is
|
||||
* stored in the last segment.
|
||||
*
|
||||
* @throws UnsupportedOperationException if this isn't a hierarchical URI
|
||||
* @throws NumberFormatException if the last segment isn't a number
|
||||
*
|
||||
* @return the long conversion of the last segment or -1 if the path is
|
||||
* empty
|
||||
*/
|
||||
public static long parseId(Uri contentUri) {
|
||||
String last = contentUri.getLastPathSegment();
|
||||
return last == null ? -1 : Long.parseLong(last);
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends the given ID to the end of the path.
|
||||
*
|
||||
* @param builder to append the ID to
|
||||
* @param id to append
|
||||
*
|
||||
* @return the given builder
|
||||
*/
|
||||
public static Uri.Builder appendId(Uri.Builder builder, long id) {
|
||||
return builder.appendEncodedPath(String.valueOf(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends the given ID to the end of the path.
|
||||
*
|
||||
* @param contentUri to start with
|
||||
* @param id to append
|
||||
*
|
||||
* @return a new URI with the given ID appended to the end of the path
|
||||
*/
|
||||
public static Uri withAppendedId(Uri contentUri, long id) {
|
||||
return appendId(contentUri.buildUpon(), id).build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes any ID from the end of the path.
|
||||
*
|
||||
* @param contentUri that ends with an ID
|
||||
* @return a new URI with the ID removed from the end of the path
|
||||
* @throws IllegalArgumentException when the given URI has no ID to remove
|
||||
* from the end of the path
|
||||
*/
|
||||
public static Uri removeId(Uri contentUri) {
|
||||
// Verify that we have a valid ID to actually remove
|
||||
final String last = contentUri.getLastPathSegment();
|
||||
if (last == null) {
|
||||
throw new IllegalArgumentException("No path segments to remove");
|
||||
} else {
|
||||
Long.parseLong(last);
|
||||
}
|
||||
|
||||
final List<String> segments = contentUri.getPathSegments();
|
||||
final Uri.Builder builder = contentUri.buildUpon();
|
||||
builder.path(null);
|
||||
for (int i = 0; i < segments.size() - 1; i++) {
|
||||
builder.appendPath(segments.get(i));
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,23 @@
|
||||
package android.content;
|
||||
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
|
||||
public class SearchRecentSuggestionsProvider extends ContentProvider {
|
||||
public void setupSuggestions(String s, int i) {}
|
||||
|
||||
@Override
|
||||
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
|
||||
throw new UnsupportedOperationException("Unimplemented method 'query'");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Uri insert(Uri uri, ContentValues values) {
|
||||
throw new UnsupportedOperationException("Unimplemented method 'insert'");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int delete(Uri uri, String selection, String[] selectionArgs) {
|
||||
throw new UnsupportedOperationException("Unimplemented method 'delete'");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,282 @@
|
||||
/*
|
||||
* Copyright (C) 2006 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.content;
|
||||
|
||||
public class UriMatcher {
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public UriMatcher(int code) {}
|
||||
import android.net.Uri;
|
||||
|
||||
public void addURI(String authority, String path, int code) {}
|
||||
/**
|
||||
Utility class to aid in matching URIs in content providers.
|
||||
|
||||
<p>To use this class, build up a tree of <code>UriMatcher</code> objects.
|
||||
For example:
|
||||
<pre>
|
||||
private static final int PEOPLE = 1;
|
||||
private static final int PEOPLE_ID = 2;
|
||||
private static final int PEOPLE_PHONES = 3;
|
||||
private static final int PEOPLE_PHONES_ID = 4;
|
||||
private static final int PEOPLE_CONTACTMETHODS = 7;
|
||||
private static final int PEOPLE_CONTACTMETHODS_ID = 8;
|
||||
|
||||
private static final int DELETED_PEOPLE = 20;
|
||||
|
||||
private static final int PHONES = 9;
|
||||
private static final int PHONES_ID = 10;
|
||||
private static final int PHONES_FILTER = 14;
|
||||
|
||||
private static final int CONTACTMETHODS = 18;
|
||||
private static final int CONTACTMETHODS_ID = 19;
|
||||
|
||||
private static final int CALLS = 11;
|
||||
private static final int CALLS_ID = 12;
|
||||
private static final int CALLS_FILTER = 15;
|
||||
|
||||
private static final UriMatcher sURIMatcher = new UriMatcher(UriMatcher.NO_MATCH);
|
||||
|
||||
static
|
||||
{
|
||||
sURIMatcher.addURI("contacts", "people", PEOPLE);
|
||||
sURIMatcher.addURI("contacts", "people/#", PEOPLE_ID);
|
||||
sURIMatcher.addURI("contacts", "people/#/phones", PEOPLE_PHONES);
|
||||
sURIMatcher.addURI("contacts", "people/#/phones/#", PEOPLE_PHONES_ID);
|
||||
sURIMatcher.addURI("contacts", "people/#/contact_methods", PEOPLE_CONTACTMETHODS);
|
||||
sURIMatcher.addURI("contacts", "people/#/contact_methods/#", PEOPLE_CONTACTMETHODS_ID);
|
||||
sURIMatcher.addURI("contacts", "deleted_people", DELETED_PEOPLE);
|
||||
sURIMatcher.addURI("contacts", "phones", PHONES);
|
||||
sURIMatcher.addURI("contacts", "phones/filter/*", PHONES_FILTER);
|
||||
sURIMatcher.addURI("contacts", "phones/#", PHONES_ID);
|
||||
sURIMatcher.addURI("contacts", "contact_methods", CONTACTMETHODS);
|
||||
sURIMatcher.addURI("contacts", "contact_methods/#", CONTACTMETHODS_ID);
|
||||
sURIMatcher.addURI("call_log", "calls", CALLS);
|
||||
sURIMatcher.addURI("call_log", "calls/filter/*", CALLS_FILTER);
|
||||
sURIMatcher.addURI("call_log", "calls/#", CALLS_ID);
|
||||
}
|
||||
</pre>
|
||||
<p>Starting from API level {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, paths can start
|
||||
with a leading slash. For example:
|
||||
<pre>
|
||||
sURIMatcher.addURI("contacts", "/people", PEOPLE);
|
||||
</pre>
|
||||
<p>Then when you need to match against a URI, call {@link #match}, providing
|
||||
the URL that you have been given. You can use the result to build a query,
|
||||
return a type, insert or delete a row, or whatever you need, without duplicating
|
||||
all of the if-else logic that you would otherwise need. For example:
|
||||
<pre>
|
||||
public String getType(Uri url)
|
||||
{
|
||||
int match = sURIMatcher.match(url);
|
||||
switch (match)
|
||||
{
|
||||
case PEOPLE:
|
||||
return "vnd.android.cursor.dir/person";
|
||||
case PEOPLE_ID:
|
||||
return "vnd.android.cursor.item/person";
|
||||
... snip ...
|
||||
return "vnd.android.cursor.dir/snail-mail";
|
||||
case PEOPLE_ADDRESS_ID:
|
||||
return "vnd.android.cursor.item/snail-mail";
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
</pre>
|
||||
instead of:
|
||||
<pre>
|
||||
public String getType(Uri url)
|
||||
{
|
||||
List<String> pathSegments = url.getPathSegments();
|
||||
if (pathSegments.size() >= 2) {
|
||||
if ("people".equals(pathSegments.get(1))) {
|
||||
if (pathSegments.size() == 2) {
|
||||
return "vnd.android.cursor.dir/person";
|
||||
} else if (pathSegments.size() == 3) {
|
||||
return "vnd.android.cursor.item/person";
|
||||
... snip ...
|
||||
return "vnd.android.cursor.dir/snail-mail";
|
||||
} else if (pathSegments.size() == 3) {
|
||||
return "vnd.android.cursor.item/snail-mail";
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
</pre>
|
||||
*/
|
||||
public class UriMatcher
|
||||
{
|
||||
public static final int NO_MATCH = -1;
|
||||
/**
|
||||
* Creates the root node of the URI tree.
|
||||
*
|
||||
* @param code the code to match for the root URI
|
||||
*/
|
||||
public UriMatcher(int code)
|
||||
{
|
||||
mCode = code;
|
||||
mWhich = -1;
|
||||
mChildren = new ArrayList<UriMatcher>();
|
||||
mText = null;
|
||||
}
|
||||
|
||||
private UriMatcher(int which, String text)
|
||||
{
|
||||
mCode = NO_MATCH;
|
||||
mWhich = which;
|
||||
mChildren = new ArrayList<UriMatcher>();
|
||||
mText = text;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a URI to match, and the code to return when this URI is
|
||||
* matched. URI nodes may be exact match string, the token "*"
|
||||
* that matches any text, or the token "#" that matches only
|
||||
* numbers.
|
||||
* <p>
|
||||
* Starting from API level {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2},
|
||||
* this method will accept a leading slash in the path.
|
||||
*
|
||||
* @param authority the authority to match
|
||||
* @param path the path to match. * may be used as a wild card for
|
||||
* any text, and # may be used as a wild card for numbers.
|
||||
* @param code the code that is returned when a URI is matched
|
||||
* against the given components. Must be positive.
|
||||
*/
|
||||
public void addURI(String authority, String path, int code)
|
||||
{
|
||||
if (code < 0) {
|
||||
throw new IllegalArgumentException("code " + code + " is invalid: it must be positive");
|
||||
}
|
||||
|
||||
String[] tokens = null;
|
||||
if (path != null) {
|
||||
String newPath = path;
|
||||
// Strip leading slash if present.
|
||||
if (path.length() > 1 && path.charAt(0) == '/') {
|
||||
newPath = path.substring(1);
|
||||
}
|
||||
tokens = newPath.split("/");
|
||||
}
|
||||
|
||||
int numTokens = tokens != null ? tokens.length : 0;
|
||||
UriMatcher node = this;
|
||||
for (int i = -1; i < numTokens; i++) {
|
||||
String token = i < 0 ? authority : tokens[i];
|
||||
ArrayList<UriMatcher> children = node.mChildren;
|
||||
int numChildren = children.size();
|
||||
UriMatcher child;
|
||||
int j;
|
||||
for (j = 0; j < numChildren; j++) {
|
||||
child = children.get(j);
|
||||
if (token.equals(child.mText)) {
|
||||
node = child;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (j == numChildren) {
|
||||
// Child not found, create it
|
||||
child = createChild(token);
|
||||
node.mChildren.add(child);
|
||||
node = child;
|
||||
}
|
||||
}
|
||||
node.mCode = code;
|
||||
}
|
||||
|
||||
private static UriMatcher createChild(String token) {
|
||||
switch (token) {
|
||||
case "#":
|
||||
return new UriMatcher(NUMBER, "#");
|
||||
case "*":
|
||||
return new UriMatcher(TEXT, "*");
|
||||
default:
|
||||
return new UriMatcher(EXACT, token);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to match against the path in a url.
|
||||
*
|
||||
* @param uri The url whose path we will match against.
|
||||
*
|
||||
* @return The code for the matched node (added using addURI),
|
||||
* or -1 if there is no matched node.
|
||||
*/
|
||||
public int match(Uri uri)
|
||||
{
|
||||
final List<String> pathSegments = uri.getPathSegments();
|
||||
final int li = pathSegments.size();
|
||||
|
||||
UriMatcher node = this;
|
||||
|
||||
if (li == 0 && uri.getAuthority() == null) {
|
||||
return this.mCode;
|
||||
}
|
||||
|
||||
for (int i=-1; i<li; i++) {
|
||||
String u = i < 0 ? uri.getAuthority() : pathSegments.get(i);
|
||||
ArrayList<UriMatcher> list = node.mChildren;
|
||||
if (list == null) {
|
||||
break;
|
||||
}
|
||||
node = null;
|
||||
int lj = list.size();
|
||||
for (int j=0; j<lj; j++) {
|
||||
UriMatcher n = list.get(j);
|
||||
which_switch:
|
||||
switch (n.mWhich) {
|
||||
case EXACT:
|
||||
if (n.mText.equals(u)) {
|
||||
node = n;
|
||||
}
|
||||
break;
|
||||
case NUMBER:
|
||||
int lk = u.length();
|
||||
for (int k=0; k<lk; k++) {
|
||||
char c = u.charAt(k);
|
||||
if (c < '0' || c > '9') {
|
||||
break which_switch;
|
||||
}
|
||||
}
|
||||
node = n;
|
||||
break;
|
||||
case TEXT:
|
||||
node = n;
|
||||
break;
|
||||
}
|
||||
if (node != null) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (node == null) {
|
||||
return NO_MATCH;
|
||||
}
|
||||
}
|
||||
|
||||
return node.mCode;
|
||||
}
|
||||
|
||||
private static final int EXACT = 0;
|
||||
private static final int NUMBER = 1;
|
||||
private static final int TEXT = 2;
|
||||
|
||||
private int mCode;
|
||||
private final int mWhich;
|
||||
private final String mText;
|
||||
private ArrayList<UriMatcher> mChildren;
|
||||
}
|
||||
|
||||
@@ -65,6 +65,7 @@ hax_jar = jar('hax', [
|
||||
'android/content/ComponentName.java',
|
||||
'android/content/ContentProvider.java',
|
||||
'android/content/ContentResolver.java',
|
||||
'android/content/ContentUris.java',
|
||||
'android/content/ContentValues.java',
|
||||
'android/content/Context.java',
|
||||
'android/content/ContextWrapper.java',
|
||||
|
||||
Reference in New Issue
Block a user