-
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
dd07737
commit 83d6db4
Showing
4 changed files
with
178 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
161 changes: 161 additions & 0 deletions
161
server/src/main/java/org/cagnulein/android_remote/wrappers/ContentProvider.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,161 @@ | ||
package org.cagnulein.android_remote.wrappers; | ||
|
||
import org.cagnulein.android_remote.FakeContext; | ||
import org.cagnulein.android_remote.Ln; | ||
import org.cagnulein.android_remote.SettingsException; | ||
|
||
import android.annotation.SuppressLint; | ||
import android.content.AttributionSource; | ||
import android.os.Build; | ||
import android.os.Bundle; | ||
import android.os.IBinder; | ||
|
||
import java.io.Closeable; | ||
import java.lang.reflect.Method; | ||
|
||
public final class ContentProvider implements Closeable { | ||
|
||
public static final String TABLE_SYSTEM = "system"; | ||
public static final String TABLE_SECURE = "secure"; | ||
public static final String TABLE_GLOBAL = "global"; | ||
|
||
// See android/providerHolder/Settings.java | ||
private static final String CALL_METHOD_GET_SYSTEM = "GET_system"; | ||
private static final String CALL_METHOD_GET_SECURE = "GET_secure"; | ||
private static final String CALL_METHOD_GET_GLOBAL = "GET_global"; | ||
|
||
private static final String CALL_METHOD_PUT_SYSTEM = "PUT_system"; | ||
private static final String CALL_METHOD_PUT_SECURE = "PUT_secure"; | ||
private static final String CALL_METHOD_PUT_GLOBAL = "PUT_global"; | ||
|
||
private static final String CALL_METHOD_USER_KEY = "_user"; | ||
|
||
private static final String NAME_VALUE_TABLE_VALUE = "value"; | ||
|
||
private final ActivityManager manager; | ||
// android.content.IContentProvider | ||
private final Object provider; | ||
private final String name; | ||
private final IBinder token; | ||
|
||
private Method callMethod; | ||
private int callMethodVersion; | ||
|
||
ContentProvider(ActivityManager manager, Object provider, String name, IBinder token) { | ||
this.manager = manager; | ||
this.provider = provider; | ||
this.name = name; | ||
this.token = token; | ||
} | ||
|
||
@SuppressLint("PrivateApi") | ||
private Method getCallMethod() throws NoSuchMethodException { | ||
if (callMethod == null) { | ||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { | ||
callMethod = provider.getClass().getMethod("call", AttributionSource.class, String.class, String.class, String.class, Bundle.class); | ||
callMethodVersion = 0; | ||
} else { | ||
// old versions | ||
try { | ||
callMethod = provider.getClass() | ||
.getMethod("call", String.class, String.class, String.class, String.class, String.class, Bundle.class); | ||
callMethodVersion = 1; | ||
} catch (NoSuchMethodException e1) { | ||
try { | ||
callMethod = provider.getClass().getMethod("call", String.class, String.class, String.class, String.class, Bundle.class); | ||
callMethodVersion = 2; | ||
} catch (NoSuchMethodException e2) { | ||
callMethod = provider.getClass().getMethod("call", String.class, String.class, String.class, Bundle.class); | ||
callMethodVersion = 3; | ||
} | ||
} | ||
} | ||
} | ||
return callMethod; | ||
} | ||
|
||
private Bundle call(String callMethod, String arg, Bundle extras) throws ReflectiveOperationException { | ||
try { | ||
Method method = getCallMethod(); | ||
Object[] args; | ||
|
||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S && callMethodVersion == 0) { | ||
args = new Object[]{FakeContext.get().getAttributionSource(), "settings", callMethod, arg, extras}; | ||
} else { | ||
switch (callMethodVersion) { | ||
case 1: | ||
args = new Object[]{FakeContext.PACKAGE_NAME, null, "settings", callMethod, arg, extras}; | ||
break; | ||
case 2: | ||
args = new Object[]{FakeContext.PACKAGE_NAME, "settings", callMethod, arg, extras}; | ||
break; | ||
default: | ||
args = new Object[]{FakeContext.PACKAGE_NAME, callMethod, arg, extras}; | ||
break; | ||
} | ||
} | ||
return (Bundle) method.invoke(provider, args); | ||
} catch (ReflectiveOperationException e) { | ||
Ln.e("Could not invoke method", e); | ||
throw e; | ||
} | ||
} | ||
|
||
public void close() { | ||
manager.removeContentProviderExternal(name, token); | ||
} | ||
|
||
private static String getGetMethod(String table) { | ||
switch (table) { | ||
case TABLE_SECURE: | ||
return CALL_METHOD_GET_SECURE; | ||
case TABLE_SYSTEM: | ||
return CALL_METHOD_GET_SYSTEM; | ||
case TABLE_GLOBAL: | ||
return CALL_METHOD_GET_GLOBAL; | ||
default: | ||
throw new IllegalArgumentException("Invalid table: " + table); | ||
} | ||
} | ||
|
||
private static String getPutMethod(String table) { | ||
switch (table) { | ||
case TABLE_SECURE: | ||
return CALL_METHOD_PUT_SECURE; | ||
case TABLE_SYSTEM: | ||
return CALL_METHOD_PUT_SYSTEM; | ||
case TABLE_GLOBAL: | ||
return CALL_METHOD_PUT_GLOBAL; | ||
default: | ||
throw new IllegalArgumentException("Invalid table: " + table); | ||
} | ||
} | ||
|
||
public String getValue(String table, String key) throws SettingsException { | ||
String method = getGetMethod(table); | ||
Bundle arg = new Bundle(); | ||
arg.putInt(CALL_METHOD_USER_KEY, FakeContext.ROOT_UID); | ||
try { | ||
Bundle bundle = call(method, key, arg); | ||
if (bundle == null) { | ||
return null; | ||
} | ||
return bundle.getString("value"); | ||
} catch (Exception e) { | ||
throw new SettingsException(table, "get", key, null, e); | ||
} | ||
|
||
} | ||
|
||
public void putValue(String table, String key, String value) throws SettingsException { | ||
String method = getPutMethod(table); | ||
Bundle arg = new Bundle(); | ||
arg.putInt(CALL_METHOD_USER_KEY, FakeContext.ROOT_UID); | ||
arg.putString(NAME_VALUE_TABLE_VALUE, value); | ||
try { | ||
call(method, key, arg); | ||
} catch (Exception e) { | ||
throw new SettingsException(table, "put", key, value, e); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters