Loading res/values/strings.xml +5 −0 Original line number Diff line number Diff line Loading @@ -9174,4 +9174,9 @@ <!-- UI debug setting: preference summary - describes the behavior of forcing full raw GNSS satellite measurements [CHAR LIMIT=NONE] --> <string name="enable_gnss_raw_meas_full_tracking_summary">Track all GNSS constellations and frequencies with no duty cycling</string> <!-- Title for Storage Access settings --> <string name="storage_access">Storage access</string> <!-- Keywords for Storage Access settings --> <string name="keywords_storage_access">storage access scoped directory</string> </resources> res/xml/special_access.xml +12 −0 Original line number Diff line number Diff line Loading @@ -111,4 +111,16 @@ android:value="com.android.settings.Settings$VrListenersSettingsActivity" /> </Preference> <!-- TODO(b/63720392): add when ready <Preference android:key="special_app_storage_access" android:title="@string/storage_access" android:fragment="com.android.settings.applications.manageapplications.ManageApplications" settings:keywords="@string/keywords_storage_access"> <extra android:name="classname" android:value="com.android.settings.Settings$StorageAccessSettingsActivity" /> </Preference> --> </PreferenceScreen> src/com/android/settings/Settings.java +1 −0 Original line number Diff line number Diff line Loading @@ -120,6 +120,7 @@ public class Settings extends SettingsActivity { public static class PhotosStorageActivity extends SettingsActivity { /* empty */ } public static class StorageAccessSettingsActivity extends SettingsActivity { /* empty */ } public static class TopLevelSettings extends SettingsActivity { /* empty */ } public static class ApnSettingsActivity extends SettingsActivity { /* empty */ } Loading src/com/android/settings/applications/AppStateStorageAccessBridge.java 0 → 100644 +88 −0 Original line number Diff line number Diff line /* * Copyright (C) 2018 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 com.android.settings.applications; import static android.os.storage.StorageVolume.ScopedAccessProviderContract.AUTHORITY; import static android.os.storage.StorageVolume.ScopedAccessProviderContract.TABLE_PACKAGES; import static android.os.storage.StorageVolume.ScopedAccessProviderContract.TABLE_PACKAGES_COLUMNS; import static android.os.storage.StorageVolume.ScopedAccessProviderContract.TABLE_PACKAGES_COL_PACKAGE; import android.content.ContentResolver; import android.content.Context; import android.database.Cursor; import android.net.Uri; import android.util.ArraySet; import android.util.Log; import com.android.settingslib.applications.ApplicationsState; import com.android.settingslib.applications.ApplicationsState.AppEntry; import com.android.settingslib.applications.ApplicationsState.AppFilter; import java.util.Set; // TODO(b/63720392): add unit tests public class AppStateStorageAccessBridge extends AppStateBaseBridge { private static final String TAG = "StorageAccessBridge"; public AppStateStorageAccessBridge(ApplicationsState appState, Callback callback) { super(appState, callback); } @Override protected void loadAllExtraInfo() { } @Override protected void updateExtraInfo(AppEntry app, String pkg, int uid) { } public static final AppFilter FILTER_APP_HAS_STORAGE_ACCESS = new AppFilter() { private Set<String> mPackages; @Override public void init() { throw new UnsupportedOperationException("Need to call constructor that takes context"); } @Override public void init(Context context) { try (Cursor cursor = context.getContentResolver().query( new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT) .authority(AUTHORITY).appendPath(TABLE_PACKAGES).appendPath("*") .build(), TABLE_PACKAGES_COLUMNS, null, null)) { if (cursor == null) { Log.w(TAG, "didn't get cursor"); return; } final int count = cursor.getCount(); if (count == 0) { Log.d(TAG, "no packages"); return; } mPackages = new ArraySet<>(count); while (cursor.moveToNext()) { mPackages.add(cursor.getString(TABLE_PACKAGES_COL_PACKAGE)); } Log.v(TAG, "init(): " + mPackages); } } @Override public boolean filterApp(AppEntry info) { return mPackages != null && mPackages.contains(info.info.packageName); } }; } src/com/android/settings/applications/StorageAccessDetails.java 0 → 100644 +110 −0 Original line number Diff line number Diff line /* * Copyright (C) 2018 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 com.android.settings.applications; import static android.os.storage.StorageVolume.ScopedAccessProviderContract.AUTHORITY; import static android.os.storage.StorageVolume.ScopedAccessProviderContract.TABLE_PERMISSIONS; import static android.os.storage.StorageVolume.ScopedAccessProviderContract.TABLE_PERMISSIONS_COLUMNS; import static android.os.storage.StorageVolume.ScopedAccessProviderContract.TABLE_PERMISSIONS_COL_DIRECTORY; import static android.os.storage.StorageVolume.ScopedAccessProviderContract.TABLE_PERMISSIONS_COL_GRANTED; import static android.os.storage.StorageVolume.ScopedAccessProviderContract.TABLE_PERMISSIONS_COL_PACKAGE; import static android.os.storage.StorageVolume.ScopedAccessProviderContract.TABLE_PERMISSIONS_COL_VOLUME_UUID; import android.app.AlertDialog; import android.content.ContentResolver; import android.database.Cursor; import android.net.Uri; import android.os.Bundle; import android.support.v7.preference.Preference; import android.support.v7.preference.Preference.OnPreferenceChangeListener; import android.support.v7.preference.Preference.OnPreferenceClickListener; import android.util.Log; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.settings.R; /** * Detailed settings for an app's storage access permissions (A.K.A Scoped Directory Access). */ // TODO(b/63720392): explain its layout // TODO(b/63720392): add unit tests public class StorageAccessDetails extends AppInfoWithHeader implements OnPreferenceChangeListener, OnPreferenceClickListener { private static final String MY_TAG = "StorageAccessDetails"; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (true) { // TODO(b/63720392): temporarily hack so the screen doesn't crash.. addPreferencesFromResource(R.xml.app_ops_permissions_details); // ... we need to dynamically create the preferences by calling the provider instead: try (Cursor cursor = getContentResolver().query( new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT) .authority(AUTHORITY).appendPath(TABLE_PERMISSIONS).appendPath("*") .build(), TABLE_PERMISSIONS_COLUMNS, null, null)) { if (cursor == null) { Log.w(TAG, "didn't get cursor"); return; } final int count = cursor.getCount(); if (count == 0) { Log.d(TAG, "no permissions"); return; } while (cursor.moveToNext()) { final String pkg = cursor.getString(TABLE_PERMISSIONS_COL_PACKAGE); final String uuid = cursor.getString(TABLE_PERMISSIONS_COL_VOLUME_UUID); final String dir = cursor.getString(TABLE_PERMISSIONS_COL_DIRECTORY); final boolean granted = cursor.getInt(TABLE_PERMISSIONS_COL_GRANTED) == 1; Log.v(MY_TAG, "pkg:" + pkg + " uuid: " + uuid + " dir: " + dir + "> " + granted); } } } } @Override public boolean onPreferenceClick(Preference preference) { // TODO(b/63720392): implement or remove listener return false; } @Override public boolean onPreferenceChange(Preference preference, Object newValue) { // TODO(b/63720392): implement or remove listener return false; } @Override protected boolean refreshUi() { // TODO(b/63720392): implement return true; } @Override protected AlertDialog createDialog(int id, int errorCode) { return null; } @Override public int getMetricsCategory() { return MetricsEvent.APPLICATIONS_USAGE_ACCESS_DETAIL; } } Loading
res/values/strings.xml +5 −0 Original line number Diff line number Diff line Loading @@ -9174,4 +9174,9 @@ <!-- UI debug setting: preference summary - describes the behavior of forcing full raw GNSS satellite measurements [CHAR LIMIT=NONE] --> <string name="enable_gnss_raw_meas_full_tracking_summary">Track all GNSS constellations and frequencies with no duty cycling</string> <!-- Title for Storage Access settings --> <string name="storage_access">Storage access</string> <!-- Keywords for Storage Access settings --> <string name="keywords_storage_access">storage access scoped directory</string> </resources>
res/xml/special_access.xml +12 −0 Original line number Diff line number Diff line Loading @@ -111,4 +111,16 @@ android:value="com.android.settings.Settings$VrListenersSettingsActivity" /> </Preference> <!-- TODO(b/63720392): add when ready <Preference android:key="special_app_storage_access" android:title="@string/storage_access" android:fragment="com.android.settings.applications.manageapplications.ManageApplications" settings:keywords="@string/keywords_storage_access"> <extra android:name="classname" android:value="com.android.settings.Settings$StorageAccessSettingsActivity" /> </Preference> --> </PreferenceScreen>
src/com/android/settings/Settings.java +1 −0 Original line number Diff line number Diff line Loading @@ -120,6 +120,7 @@ public class Settings extends SettingsActivity { public static class PhotosStorageActivity extends SettingsActivity { /* empty */ } public static class StorageAccessSettingsActivity extends SettingsActivity { /* empty */ } public static class TopLevelSettings extends SettingsActivity { /* empty */ } public static class ApnSettingsActivity extends SettingsActivity { /* empty */ } Loading
src/com/android/settings/applications/AppStateStorageAccessBridge.java 0 → 100644 +88 −0 Original line number Diff line number Diff line /* * Copyright (C) 2018 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 com.android.settings.applications; import static android.os.storage.StorageVolume.ScopedAccessProviderContract.AUTHORITY; import static android.os.storage.StorageVolume.ScopedAccessProviderContract.TABLE_PACKAGES; import static android.os.storage.StorageVolume.ScopedAccessProviderContract.TABLE_PACKAGES_COLUMNS; import static android.os.storage.StorageVolume.ScopedAccessProviderContract.TABLE_PACKAGES_COL_PACKAGE; import android.content.ContentResolver; import android.content.Context; import android.database.Cursor; import android.net.Uri; import android.util.ArraySet; import android.util.Log; import com.android.settingslib.applications.ApplicationsState; import com.android.settingslib.applications.ApplicationsState.AppEntry; import com.android.settingslib.applications.ApplicationsState.AppFilter; import java.util.Set; // TODO(b/63720392): add unit tests public class AppStateStorageAccessBridge extends AppStateBaseBridge { private static final String TAG = "StorageAccessBridge"; public AppStateStorageAccessBridge(ApplicationsState appState, Callback callback) { super(appState, callback); } @Override protected void loadAllExtraInfo() { } @Override protected void updateExtraInfo(AppEntry app, String pkg, int uid) { } public static final AppFilter FILTER_APP_HAS_STORAGE_ACCESS = new AppFilter() { private Set<String> mPackages; @Override public void init() { throw new UnsupportedOperationException("Need to call constructor that takes context"); } @Override public void init(Context context) { try (Cursor cursor = context.getContentResolver().query( new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT) .authority(AUTHORITY).appendPath(TABLE_PACKAGES).appendPath("*") .build(), TABLE_PACKAGES_COLUMNS, null, null)) { if (cursor == null) { Log.w(TAG, "didn't get cursor"); return; } final int count = cursor.getCount(); if (count == 0) { Log.d(TAG, "no packages"); return; } mPackages = new ArraySet<>(count); while (cursor.moveToNext()) { mPackages.add(cursor.getString(TABLE_PACKAGES_COL_PACKAGE)); } Log.v(TAG, "init(): " + mPackages); } } @Override public boolean filterApp(AppEntry info) { return mPackages != null && mPackages.contains(info.info.packageName); } }; }
src/com/android/settings/applications/StorageAccessDetails.java 0 → 100644 +110 −0 Original line number Diff line number Diff line /* * Copyright (C) 2018 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 com.android.settings.applications; import static android.os.storage.StorageVolume.ScopedAccessProviderContract.AUTHORITY; import static android.os.storage.StorageVolume.ScopedAccessProviderContract.TABLE_PERMISSIONS; import static android.os.storage.StorageVolume.ScopedAccessProviderContract.TABLE_PERMISSIONS_COLUMNS; import static android.os.storage.StorageVolume.ScopedAccessProviderContract.TABLE_PERMISSIONS_COL_DIRECTORY; import static android.os.storage.StorageVolume.ScopedAccessProviderContract.TABLE_PERMISSIONS_COL_GRANTED; import static android.os.storage.StorageVolume.ScopedAccessProviderContract.TABLE_PERMISSIONS_COL_PACKAGE; import static android.os.storage.StorageVolume.ScopedAccessProviderContract.TABLE_PERMISSIONS_COL_VOLUME_UUID; import android.app.AlertDialog; import android.content.ContentResolver; import android.database.Cursor; import android.net.Uri; import android.os.Bundle; import android.support.v7.preference.Preference; import android.support.v7.preference.Preference.OnPreferenceChangeListener; import android.support.v7.preference.Preference.OnPreferenceClickListener; import android.util.Log; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.settings.R; /** * Detailed settings for an app's storage access permissions (A.K.A Scoped Directory Access). */ // TODO(b/63720392): explain its layout // TODO(b/63720392): add unit tests public class StorageAccessDetails extends AppInfoWithHeader implements OnPreferenceChangeListener, OnPreferenceClickListener { private static final String MY_TAG = "StorageAccessDetails"; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (true) { // TODO(b/63720392): temporarily hack so the screen doesn't crash.. addPreferencesFromResource(R.xml.app_ops_permissions_details); // ... we need to dynamically create the preferences by calling the provider instead: try (Cursor cursor = getContentResolver().query( new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT) .authority(AUTHORITY).appendPath(TABLE_PERMISSIONS).appendPath("*") .build(), TABLE_PERMISSIONS_COLUMNS, null, null)) { if (cursor == null) { Log.w(TAG, "didn't get cursor"); return; } final int count = cursor.getCount(); if (count == 0) { Log.d(TAG, "no permissions"); return; } while (cursor.moveToNext()) { final String pkg = cursor.getString(TABLE_PERMISSIONS_COL_PACKAGE); final String uuid = cursor.getString(TABLE_PERMISSIONS_COL_VOLUME_UUID); final String dir = cursor.getString(TABLE_PERMISSIONS_COL_DIRECTORY); final boolean granted = cursor.getInt(TABLE_PERMISSIONS_COL_GRANTED) == 1; Log.v(MY_TAG, "pkg:" + pkg + " uuid: " + uuid + " dir: " + dir + "> " + granted); } } } } @Override public boolean onPreferenceClick(Preference preference) { // TODO(b/63720392): implement or remove listener return false; } @Override public boolean onPreferenceChange(Preference preference, Object newValue) { // TODO(b/63720392): implement or remove listener return false; } @Override protected boolean refreshUi() { // TODO(b/63720392): implement return true; } @Override protected AlertDialog createDialog(int id, int errorCode) { return null; } @Override public int getMetricsCategory() { return MetricsEvent.APPLICATIONS_USAGE_ACCESS_DETAIL; } }