1 /* 2 * Copyright (C) 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.android.settings.applications; 17 18 import static android.os.storage.StorageVolume.ScopedAccessProviderContract.AUTHORITY; 19 import static android.os.storage.StorageVolume.ScopedAccessProviderContract.TABLE_PACKAGES; 20 import static android.os.storage.StorageVolume.ScopedAccessProviderContract.TABLE_PACKAGES_COLUMNS; 21 import static android.os.storage.StorageVolume.ScopedAccessProviderContract.TABLE_PACKAGES_COL_PACKAGE; 22 23 import android.content.ContentResolver; 24 import android.content.Context; 25 import android.database.Cursor; 26 import android.net.Uri; 27 import android.util.ArraySet; 28 import android.util.Log; 29 30 import com.android.settingslib.applications.ApplicationsState; 31 import com.android.settingslib.applications.ApplicationsState.AppEntry; 32 import com.android.settingslib.applications.ApplicationsState.AppFilter; 33 34 import java.util.Set; 35 36 // TODO(b/72055774): add unit tests 37 public class AppStateDirectoryAccessBridge extends AppStateBaseBridge { 38 39 private static final String TAG = "DirectoryAccessBridge"; 40 41 // TODO(b/72055774): set to false once feature is ready (or use Log.isLoggable) 42 static final boolean DEBUG = true; 43 static final boolean VERBOSE = true; 44 AppStateDirectoryAccessBridge(ApplicationsState appState, Callback callback)45 public AppStateDirectoryAccessBridge(ApplicationsState appState, Callback callback) { 46 super(appState, callback); 47 } 48 49 @Override loadAllExtraInfo()50 protected void loadAllExtraInfo() { } 51 52 @Override updateExtraInfo(AppEntry app, String pkg, int uid)53 protected void updateExtraInfo(AppEntry app, String pkg, int uid) { } 54 55 public static final AppFilter FILTER_APP_HAS_DIRECTORY_ACCESS = new AppFilter() { 56 57 private Set<String> mPackages; 58 59 @Override 60 public void init() { 61 throw new UnsupportedOperationException("Need to call constructor that takes context"); 62 } 63 64 @Override 65 public void init(Context context) { 66 mPackages = null; 67 final Uri providerUri = new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT) 68 .authority(AUTHORITY).appendPath(TABLE_PACKAGES).appendPath("*") 69 .build(); 70 try (Cursor cursor = context.getContentResolver().query(providerUri, 71 TABLE_PACKAGES_COLUMNS, null, null)) { 72 if (cursor == null) { 73 Log.w(TAG, "Didn't get cursor for " + providerUri); 74 return; 75 } 76 final int count = cursor.getCount(); 77 if (count == 0) { 78 if (DEBUG) { 79 Log.d(TAG, "No packages anymore (was " + mPackages + ")"); 80 } 81 return; 82 } 83 mPackages = new ArraySet<>(count); 84 while (cursor.moveToNext()) { 85 mPackages.add(cursor.getString(TABLE_PACKAGES_COL_PACKAGE)); 86 } 87 if (DEBUG) { 88 Log.d(TAG, "init(): " + mPackages); 89 } 90 } 91 } 92 93 94 @Override 95 public boolean filterApp(AppEntry info) { 96 return mPackages != null && mPackages.contains(info.info.packageName); 97 } 98 }; 99 } 100