package com.oasisfeng.android.provider; import android.annotation.SuppressLint; import android.content.ComponentName; import android.content.ContentProvider; import android.content.ContentValues; import android.content.Context; import android.database.Cursor; import android.net.Uri; import android.os.Handler; import android.os.MessageQueue; import android.os.Process; import android.provider.Settings; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import static android.Manifest.permission.WRITE_SECURE_SETTINGS; import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT; import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED; import static android.content.pm.PackageManager.DONT_KILL_APP; import static android.content.pm.PackageManager.PERMISSION_GRANTED; /** * Created by Oasis on 2018/2/21. */ public abstract class SettingsProxyProvider extends ContentProvider { protected abstract boolean shouldAllow(); @Nullable @Override public Cursor query(@NonNull final Uri uri, @Nullable final String[] projection, @Nullable final String selection, @Nullable final String[] selectionArgs, @Nullable final String sortOrder) { return context().getContentResolver().query(translate(uri), projection, selection, selectionArgs, sortOrder); } @Nullable @Override public Uri insert(@NonNull final Uri uri, @Nullable final ContentValues values) { return context().getContentResolver().insert(translate(uri), values); } @Override public int delete(@NonNull final Uri uri, @Nullable final String selection, @Nullable final String[] selectionArgs) { return context().getContentResolver().delete(translate(uri), selection, selectionArgs); } @Override public int update(@NonNull final Uri uri, @Nullable final ContentValues values, @Nullable final String selection, @Nullable final String[] selectionArgs) { return context().getContentResolver().update(translate(uri), values, selection, selectionArgs); } @Nullable @Override public String getType(@NonNull final Uri uri) { return context().getContentResolver().getType(translate(uri)); } private Uri translate(final @NonNull Uri uri) { if (! shouldAllow()) throw new SecurityException("Not allowed"); return uri.buildUpon().authority(Settings.AUTHORITY).build(); } @SuppressLint("NewApi")/* getQueue() is hidden but accessible before M */ @Override public boolean onCreate() { new Handler().getLooper().getQueue().addIdleHandler(new MessageQueue.IdleHandler() { @Override public boolean queueIdle() { final int result = SettingsProxyProvider.this.context().checkPermission(WRITE_SECURE_SETTINGS, Process.myPid(), Process.myUid()); context().getPackageManager().setComponentEnabledSetting(new ComponentName(context(), SettingsProxyProvider.this.getClass()), result == PERMISSION_GRANTED ? COMPONENT_ENABLED_STATE_ENABLED : COMPONENT_ENABLED_STATE_DEFAULT, DONT_KILL_APP); return false; }}); return true; } @SuppressWarnings("ConstantConditions") protected @NonNull Context context() { return getContext(); } }