Beautify Android 6 permission request
This commit is contained in:
parent
93e9567830
commit
2a3eb5f403
@ -151,7 +151,8 @@ THE SOFTWARE.
|
||||
<activity
|
||||
android:name="FilebrowserStartActivity" />
|
||||
<activity
|
||||
android:name="PermissionRequestActivity" />
|
||||
android:name="PermissionRequestActivity"
|
||||
android:theme="@android:style/Theme.Translucent.NoTitleBar" />
|
||||
|
||||
<activity android:name="AudioPickerActivity" android:theme="@style/DialogMinWidth"
|
||||
android:excludeFromRecents="true" android:exported="true" >
|
||||
|
@ -42,5 +42,6 @@ THE SOFTWARE.
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="fill_parent" />
|
||||
</HorizontalScrollView>
|
||||
<include layout="@layout/permission_request" />
|
||||
</LinearLayout>
|
||||
|
||||
|
42
res/layout/permission_request.xml
Normal file
42
res/layout/permission_request.xml
Normal file
@ -0,0 +1,42 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2015 Adrian Ulrich <adrian@blinkenlights.ch>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/permission_request"
|
||||
android:visibility="gone"
|
||||
android:clickable="true"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:stretchColumns="0"
|
||||
android:shrinkColumns="0"
|
||||
android:background="#FF212121">
|
||||
<TableRow>
|
||||
<TextView
|
||||
android:id="@+id/permission_request_title"
|
||||
android:layout_marginLeft="8dip"
|
||||
android:layout_marginBottom="8dip"
|
||||
android:layout_marginTop="8dip"
|
||||
android:text="@string/permission_request_summary"
|
||||
android:textColor="#FFFFFFFF" />
|
||||
<Button
|
||||
android:id="@+id/permission_request_button"
|
||||
android:clickable="false"
|
||||
android:layout_marginRight="8dip"
|
||||
android:layout_gravity="center"
|
||||
android:text="@string/ok" />
|
||||
</TableRow>
|
||||
</TableLayout>
|
@ -310,4 +310,6 @@ THE SOFTWARE.
|
||||
<string name="autoplaylist_playcounts_disabled">Do not create an automatic playlist</string>
|
||||
<string name="autoplaylist_playcounts_name" formatted="false">Top %d</string>
|
||||
|
||||
<string name="permission_request_summary">Vanilla Music needs read permission to display your music library</string>
|
||||
<string name="ok">Ok</string>
|
||||
</resources>
|
||||
|
@ -44,6 +44,11 @@ public class AudioPickerActivity extends PlaybackActivity {
|
||||
return;
|
||||
}
|
||||
|
||||
if (PermissionRequestActivity.requestPermissions(this, intent)) {
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
|
||||
Uri uri = intent.getData();
|
||||
if (uri == null) {
|
||||
finish();
|
||||
@ -120,7 +125,7 @@ public class AudioPickerActivity extends PlaybackActivity {
|
||||
Cursor cursor = null;
|
||||
|
||||
if (uri.getScheme().equals("content"))
|
||||
cursor = getContentResolver().query(uri, Song.FILLED_PROJECTION, null, null, null);
|
||||
cursor = MediaUtils.queryResolver(getContentResolver(), uri, Song.FILLED_PROJECTION, null, null, null);
|
||||
if (uri.getScheme().equals("file"))
|
||||
cursor = MediaUtils.getCursorForFileQuery(uri.getPath());
|
||||
|
||||
|
@ -135,6 +135,7 @@ public class LibraryActivity
|
||||
private TextView mArtist;
|
||||
private ImageView mCover;
|
||||
private View mEmptyQueue;
|
||||
private View mPermissionRequest;
|
||||
private MenuItem mSearchMenuItem;
|
||||
|
||||
private HorizontalScrollView mLimiterScroller;
|
||||
@ -195,6 +196,15 @@ public class LibraryActivity
|
||||
controls.setOnClickListener(this);
|
||||
mActionControls = controls;
|
||||
|
||||
mPermissionRequest = (View)findViewById(R.id.permission_request);
|
||||
|
||||
if(PermissionRequestActivity.havePermissions(this) == false) {
|
||||
// We are lacking permissions: bind and display nag bar
|
||||
mPermissionRequest.setOnClickListener(this);
|
||||
mPermissionRequest.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
|
||||
loadTabOrder();
|
||||
int page = settings.getInt(PrefKeys.LIBRARY_PAGE, PrefDefaults.LIBRARY_PAGE);
|
||||
if (page != 0) {
|
||||
@ -524,6 +534,8 @@ public class LibraryActivity
|
||||
{
|
||||
if (view == mCover || view == mActionControls) {
|
||||
openPlaybackActivity();
|
||||
} else if (view == mPermissionRequest) {
|
||||
PermissionRequestActivity.requestPermissions(this, getIntent());
|
||||
} else if (view == mEmptyQueue) {
|
||||
setState(PlaybackService.get(this).setFinishAction(SongTimeline.FINISH_RANDOM));
|
||||
} else if (view.getTag() != null) {
|
||||
@ -564,7 +576,7 @@ public class LibraryActivity
|
||||
ContentResolver resolver = getContentResolver();
|
||||
Uri uri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
|
||||
String[] projection = new String[] { MediaStore.Audio.Media.ARTIST_ID, MediaStore.Audio.Media.ALBUM_ID, MediaStore.Audio.Media.ARTIST, MediaStore.Audio.Media.ALBUM };
|
||||
Cursor cursor = resolver.query(uri, projection, selection, null, null);
|
||||
Cursor cursor = MediaUtils.queryResolver(resolver, uri, projection, selection, null, null);
|
||||
if (cursor != null) {
|
||||
if (cursor.moveToNext()) {
|
||||
String[] fields;
|
||||
|
@ -273,7 +273,7 @@ public class MediaUtils {
|
||||
{
|
||||
String[] projection = { "_id" };
|
||||
Uri uri = CompatHoneycomb.getContentUriForAudioId((int)id);
|
||||
Cursor cursor = resolver.query(uri, projection, null, null, null);
|
||||
Cursor cursor = queryResolver(resolver, uri, projection, null, null, null);
|
||||
|
||||
if (cursor != null) {
|
||||
if (cursor.moveToNext())
|
||||
@ -380,7 +380,7 @@ public class MediaUtils {
|
||||
Uri media = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
|
||||
String selection = MediaStore.Audio.Media.IS_MUSIC;
|
||||
selection += " AND length(_data)";
|
||||
Cursor cursor = resolver.query(media, new String[]{"count(_id)"}, selection, null, null);
|
||||
Cursor cursor = queryResolver(resolver, media, new String[]{"count(_id)"}, selection, null, null);
|
||||
if (cursor == null) {
|
||||
sSongCount = 0;
|
||||
} else {
|
||||
@ -404,7 +404,7 @@ public class MediaUtils {
|
||||
Uri media = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
|
||||
String selection = MediaStore.Audio.Media.IS_MUSIC;
|
||||
selection += " AND length(_data)";
|
||||
Cursor cursor = resolver.query(media, Song.EMPTY_PROJECTION, selection, null, null);
|
||||
Cursor cursor = queryResolver(resolver, media, Song.EMPTY_PROJECTION, selection, null, null);
|
||||
if (cursor == null || cursor.getCount() == 0) {
|
||||
sSongCount = 0;
|
||||
return null;
|
||||
@ -425,6 +425,30 @@ public class MediaUtils {
|
||||
return ids;
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs a query on the passed content resolver.
|
||||
* Catches (and returns null on) SecurityException (= user revoked read permission)
|
||||
*
|
||||
* @param resolver The content resolver to use
|
||||
* @param uri the uri to query
|
||||
* @param projection the projection to use
|
||||
* @param selection the selection to use
|
||||
* @param selectionArgs arguments for the selection
|
||||
* @param sortOrder sort order of the returned result
|
||||
*
|
||||
* @return a cursor or null
|
||||
*/
|
||||
public static Cursor queryResolver(ContentResolver resolver, Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)
|
||||
{
|
||||
Cursor cursor = null;
|
||||
try {
|
||||
cursor = resolver.query(uri, projection, selection, selectionArgs, sortOrder);
|
||||
} catch(java.lang.SecurityException e) {
|
||||
// we do not have read permission - just return a null cursor
|
||||
}
|
||||
return cursor;
|
||||
}
|
||||
|
||||
public static void onMediaChange()
|
||||
{
|
||||
sSongCount = -1;
|
||||
|
@ -30,23 +30,24 @@ import android.os.Bundle;
|
||||
|
||||
public class PermissionRequestActivity extends Activity {
|
||||
|
||||
// 'dangerous' permissions not granted by the manifest on versions >= M
|
||||
/**
|
||||
* 'dangerous' permissions not granted by the manifest on versions >= M
|
||||
*/
|
||||
private static final String[] NEEDED_PERMISSIONS = { Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE };
|
||||
/**
|
||||
* The intent to start after acquiring the required permissions
|
||||
*/
|
||||
private Intent mCallbackIntent;
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.M)
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
ThemeHelper.setTheme(this, R.style.VanillaBase);
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
setTitle(R.string.app_name);
|
||||
// Fixme: This should probably be some welcome dialog with a button to launch askForPermissions
|
||||
// setContentView(R.layout.showqueue_listview);
|
||||
|
||||
mCallbackIntent = getIntent().getExtras().getParcelable("callbackIntent");
|
||||
requestPermissions(NEEDED_PERMISSIONS, 0);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Called by Activity after the user interacted with the permission request
|
||||
* Will launch the main activity if all permissions were granted, exits otherwise
|
||||
@ -63,31 +64,37 @@ public class PermissionRequestActivity extends Activity {
|
||||
grantedPermissions++;
|
||||
}
|
||||
|
||||
// set as finished before (possibly) killing ourselfs
|
||||
finish();
|
||||
|
||||
if (grantedPermissions == grantResults.length) {
|
||||
Intent intent = getPackageManager().getLaunchIntentForPackage(getPackageName());
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
startActivity(intent);
|
||||
if (mCallbackIntent != null) {
|
||||
// start the old intent but ensure to make it a new task & clear any old attached activites
|
||||
mCallbackIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
|
||||
startActivity(mCallbackIntent);
|
||||
}
|
||||
// Hack: We *kill* ourselfs (while launching the main activity) to get startet
|
||||
// in a new process: This works around a bug/feature in 6.0 that would cause us
|
||||
// to get 'partial read' permissions (eg: reading from the content provider works
|
||||
// but reading from /sdcard doesn't)
|
||||
android.os.Process.killProcess(android.os.Process.myPid());
|
||||
}
|
||||
finish();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Launches a permission request dialog if needed
|
||||
*
|
||||
* @param activity The activitys context to use for the permission check
|
||||
* @return boolean true if we showed a permission request dialog
|
||||
*/
|
||||
public static boolean requestPermissions(Activity activity) {
|
||||
public static boolean requestPermissions(Activity activity, Intent callbackIntent) {
|
||||
boolean havePermissions = havePermissions(activity);
|
||||
|
||||
if (havePermissions == false)
|
||||
activity.startActivity(new Intent(activity, PermissionRequestActivity.class));
|
||||
if (havePermissions == false) {
|
||||
Intent intent = new Intent(activity, PermissionRequestActivity.class);
|
||||
intent.putExtra("callbackIntent", callbackIntent);
|
||||
activity.startActivity(intent);
|
||||
}
|
||||
|
||||
return !havePermissions;
|
||||
}
|
||||
@ -98,7 +105,7 @@ public class PermissionRequestActivity extends Activity {
|
||||
* @param context The context to use
|
||||
* @return boolean true if all permissions have been granded
|
||||
*/
|
||||
private static boolean havePermissions(Context context) {
|
||||
public static boolean havePermissions(Context context) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
for (String permission : NEEDED_PERMISSIONS) {
|
||||
if (context.checkSelfPermission(permission) != PackageManager.PERMISSION_GRANTED) {
|
||||
|
@ -98,8 +98,6 @@ public abstract class PlaybackActivity extends Activity
|
||||
mLooper = thread.getLooper();
|
||||
mHandler = new Handler(mLooper, this);
|
||||
|
||||
if (PermissionRequestActivity.requestPermissions(this))
|
||||
finish();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -47,7 +47,7 @@ public class Playlist {
|
||||
Uri media = MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI;
|
||||
String[] projection = { MediaStore.Audio.Playlists._ID, MediaStore.Audio.Playlists.NAME };
|
||||
String sort = MediaStore.Audio.Playlists.NAME;
|
||||
return resolver.query(media, projection, null, null, sort);
|
||||
return MediaUtils.queryResolver(resolver, media, projection, null, null, sort);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -79,7 +79,7 @@ public class Playlist {
|
||||
{
|
||||
long id = -1;
|
||||
|
||||
Cursor cursor = resolver.query(MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI,
|
||||
Cursor cursor = MediaUtils.queryResolver(resolver, MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI,
|
||||
new String[] { MediaStore.Audio.Playlists._ID },
|
||||
MediaStore.Audio.Playlists.NAME + "=?",
|
||||
new String[] { name }, null);
|
||||
@ -163,7 +163,7 @@ public class Playlist {
|
||||
// Find the greatest PLAY_ORDER in the playlist
|
||||
Uri uri = MediaStore.Audio.Playlists.Members.getContentUri("external", playlistId);
|
||||
String[] projection = new String[] { MediaStore.Audio.Playlists.Members.PLAY_ORDER };
|
||||
Cursor cursor = resolver.query(uri, projection, null, null, null);
|
||||
Cursor cursor = MediaUtils.queryResolver(resolver, uri, projection, null, null, null);
|
||||
int base = 0;
|
||||
if (cursor.moveToLast())
|
||||
base = cursor.getInt(0) + 1;
|
||||
|
@ -73,6 +73,6 @@ public class QueryTask {
|
||||
*/
|
||||
public Cursor runQuery(ContentResolver resolver)
|
||||
{
|
||||
return resolver.query(uri, projection, selection, selectionArgs, sortOrder);
|
||||
return MediaUtils.queryResolver(resolver, uri, projection, selection, selectionArgs, sortOrder);
|
||||
}
|
||||
}
|
||||
|
@ -346,7 +346,7 @@ public final class SongTimeline {
|
||||
ContentResolver resolver = mContext.getContentResolver();
|
||||
Uri media = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
|
||||
|
||||
Cursor cursor = resolver.query(media, Song.FILLED_PROJECTION, selection.toString(), null, "_id");
|
||||
Cursor cursor = MediaUtils.queryResolver(resolver, media, Song.FILLED_PROJECTION, selection.toString(), null, "_id");
|
||||
if (cursor != null) {
|
||||
if (cursor.getCount() != 0) {
|
||||
cursor.moveToNext();
|
||||
|
Loading…
x
Reference in New Issue
Block a user