/*
This file is part of Project MAXS.
MAXS and its modules 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.
MAXS 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 MAXS. If not, see <http://www.gnu.org/licenses/>.
*/
package org.projectmaxs.shared.global.util;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import android.annotation.TargetApi;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.PermissionInfo;
import android.os.Build;
import android.os.Bundle;
import android.widget.TextView;
import android.widget.Toast;
public class PermissionUtil {
private static final Log LOG = Log.getLog();
private static final AtomicInteger NEXT_REQUEST_CODE = new AtomicInteger();
private static final Map<Integer, PendingRequestData> PENDING_REQUESTS = new ConcurrentHashMap<>();
private static class PendingRequestData {
PendingRequestData(String[] permissionsToRequest, Intent postServiceIntent) {
this.permissionsToRequest = permissionsToRequest;
this.postServiceIntent = postServiceIntent;
}
public final String[] permissionsToRequest;
public final Intent postServiceIntent;
}
/**
* Check if the requested permissions have been granted. Request them if not. This does nothing
* if the Android version is lower than 6.0.
*
* @param context
* a Context.
* @param postServiceIntent
* a optional service intent, fired after the user granted all permissions.
* @return <code>true</code> if the permissions are ok, <code>false</code>otherwise.
*/
@TargetApi(23)
public static boolean checkAndRequestIfNecessary(Context context, Intent postServiceIntent) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
return true;
}
PackageManager packageManager = context.getPackageManager();
PackageInfo packageInfo;
try {
packageInfo = packageManager.getPackageInfo(context.getPackageName(),
PackageManager.GET_PERMISSIONS);
} catch (NameNotFoundException e) {
throw new AssertionError(e);
}
List<String> permissionsToRequest = new LinkedList<>();
for (int i = 0; i < packageInfo.requestedPermissions.length; i++) {
String permission = packageInfo.requestedPermissions[i];
int res = context.checkSelfPermission(permission);
switch (res) {
case PackageManager.PERMISSION_DENIED:
break;
case PackageManager.PERMISSION_GRANTED:
default:
continue;
}
PermissionInfo permissionInfo;
try {
permissionInfo = packageManager.getPermissionInfo(permission,
PackageManager.GET_META_DATA);
} catch (NameNotFoundException e) {
throw new AssertionError(e);
}
if (permissionInfo.protectionLevel != PermissionInfo.PROTECTION_DANGEROUS) {
continue;
}
permissionsToRequest.add(permission);
}
if (permissionsToRequest.isEmpty()) {
return true;
}
LOG.i("Going to request the following permissions: "
+ SharedStringUtil.listCollection(permissionsToRequest) + '.');
String[] permissionToRequestArray = permissionsToRequest
.toArray(new String[permissionsToRequest.size()]);
int request = NEXT_REQUEST_CODE.incrementAndGet();
PENDING_REQUESTS.put(request, new PendingRequestData(permissionToRequestArray, postServiceIntent));
Intent intent = new Intent(context, RequestPermissionDialog.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
return false;
}
/**
* A invisible activity. It will only show an {@link AlertDialog} explaining the user what this
* MAXS components needs some permissions and that the user should grant them.
*/
@TargetApi(23)
public static class RequestPermissionDialog extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(this);
TextView textView = new TextView(this);
textView.setText(RTool.getStringId(this, "request_permission_info"));
dialogBuilder.setView(textView);
dialogBuilder.setPositiveButton(RTool.getStringId(this, "proceed"),
new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Iterator<Entry<Integer, PendingRequestData>> it = PENDING_REQUESTS
.entrySet()
.iterator();
while (it.hasNext()) {
Entry<Integer, PendingRequestData> entry = it.next();
requestPermissions(entry.getValue().permissionsToRequest,
entry.getKey());
}
}
});
dialogBuilder.create().show();
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions,
int[] grantResults) {
final PendingRequestData pendingRequestData = PENDING_REQUESTS.remove(requestCode);
if (pendingRequestData == null) {
LOG.w("Could not find request for " + requestCode);
return;
}
if (permissions.length == 0) {
LOG.d("User cancelled permission dialog");
return;
}
List<String> deniedPermissions = new ArrayList<>(permissions.length);
for (int i = 0; i < permissions.length; i++) {
if (grantResults[i] == PackageManager.PERMISSION_GRANTED) {
LOG.i("User granted " + permissions[i] + ". \\o/");
continue;
}
LOG.w("User did not grant " + permissions[i] + ". :(");
deniedPermissions.add(permissions[i]);
}
if (!deniedPermissions.isEmpty()) {
StringBuilder sb = new StringBuilder();
sb.append(RTool.getString(this, "request_permission_denied"));
sb.append(SharedStringUtil.listCollection(deniedPermissions));
sb.append('.');
Toast.makeText(this, sb, Toast.LENGTH_LONG).show();
} else if (pendingRequestData.postServiceIntent != null) {
LOG.i("User granted *all* permissions. PostServiceIntent set, starting "
+ pendingRequestData.postServiceIntent);
this.startService(pendingRequestData.postServiceIntent);
}
// We are done here
finish();
}
}
}