mirror of
git://xwords.git.sourceforge.net/gitroot/xwords/xwords
synced 2025-01-03 23:04:08 +01:00
perms: ask for the set needed to open a game
rewrite perms23 class to use Builder pattern, making it easier to pass more than one required permission. Use that (with hard-coded set for now) to check and ask for permissions a game needs to communicate. Offer to remove the comms methods the user doesn't want to permit (but that's not implemented yet.)
This commit is contained in:
parent
dfb22c13fa
commit
c398af2ac9
9 changed files with 941 additions and 836 deletions
File diff suppressed because it is too large
Load diff
|
@ -125,6 +125,7 @@
|
|||
<string name="key_nag_intervals">key_nag_intervals</string>
|
||||
<string name="key_download_path">key_download_path</string>
|
||||
<string name="key_got_langdict">key_got_langdict</string>
|
||||
<string name="key_notagain_missing_perms">key_notagain_missing_perms</string>
|
||||
<string name="key_xlations_locale">key_xlations_locale</string>
|
||||
<string name="key_xlations_enabled">key_xlations_enabled</string>
|
||||
<string name="key_invite_multi">key_invite_multi</string>
|
||||
|
|
|
@ -2718,4 +2718,13 @@
|
|||
<string name="dualpane_restart">Exiting app…</string>
|
||||
<string name="after_restart">This change will not take effect until
|
||||
you restart Crosswords.</string>
|
||||
|
||||
<string name="not_again_missing_perms">This game is configured to
|
||||
communicate in at least one way that requires a permission that has
|
||||
not been granted. You can still open it, but it may not be able to
|
||||
send or receive moves.\n\nYou can re-open it to be asked again. Or
|
||||
you can remove the settings that require missing permissions.</string>
|
||||
|
||||
<string name="remove_connvia">Remove</string>
|
||||
|
||||
</resources>
|
||||
|
|
|
@ -2321,4 +2321,10 @@
|
|||
<string name="dualpane_restart">Gnitixe ppa…</string>
|
||||
<string name="after_restart">Siht egnahc lliw ton ekat tceffe litnu
|
||||
uoy tratser Sdrowssorc.</string>
|
||||
<string name="not_again_missing_perms">Siht emag si derugifnoc ot
|
||||
etacinummoc ni ta tsael eno yaw taht seriuqer a noissimrep taht sah
|
||||
ton neeb detnarg. Uoy nac llits nepo ,ti tub ti yam ton eb elba ot
|
||||
dnes ro eviecer sevom.\n\nUoy nac nepo-er ti ot eb deksa niaga. Ro
|
||||
uoy nac evomer eht sgnittes taht eriuqer gnissim snoissimrep.</string>
|
||||
<string name="remove_connvia">Evomer</string>
|
||||
</resources>
|
||||
|
|
|
@ -2321,4 +2321,10 @@
|
|||
<string name="dualpane_restart">EXITING APP…</string>
|
||||
<string name="after_restart">THIS CHANGE WILL NOT TAKE EFFECT UNTIL
|
||||
YOU RESTART CROSSWORDS.</string>
|
||||
<string name="not_again_missing_perms">THIS GAME IS CONFIGURED TO
|
||||
COMMUNICATE IN AT LEAST ONE WAY THAT REQUIRES A PERMISSION THAT HAS
|
||||
NOT BEEN GRANTED. YOU CAN STILL OPEN IT, BUT IT MAY NOT BE ABLE TO
|
||||
SEND OR RECEIVE MOVES.\n\nYOU CAN RE-OPEN IT TO BE ASKED AGAIN. OR
|
||||
YOU CAN REMOVE THE SETTINGS THAT REQUIRE MISSING PERMISSIONS.</string>
|
||||
<string name="remove_connvia">REMOVE</string>
|
||||
</resources>
|
||||
|
|
|
@ -28,6 +28,8 @@ import android.widget.CompoundButton.OnCheckedChangeListener;
|
|||
import android.widget.CompoundButton;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
import org.eehouse.android.xw4.jni.CommsAddrRec.CommsConnType;
|
||||
|
@ -82,12 +84,13 @@ public class ConnViaViewLayout extends LinearLayout {
|
|||
// ask for it here. When we get what we're getting, proceed to
|
||||
// actually check for what's supported. Those methods will return
|
||||
// false if they don't have the permission they need.
|
||||
Perms23.doWithPermission( m_activity, Perms23.Perm.READ_PHONE_STATE,
|
||||
new Perms23.PermCbck() {
|
||||
public void onPermissionResult( Perms23.Perm perm, boolean granted ) {
|
||||
addConnectionsPostPermCheck();
|
||||
}
|
||||
} );
|
||||
new Perms23.Builder( Perms23.Perm.READ_PHONE_STATE )
|
||||
.asyncQuery( m_activity, new Perms23.PermCbck() {
|
||||
@Override
|
||||
public void onPermissionResult( Map<Perms23.Perm, Boolean> granted ) {
|
||||
addConnectionsPostPermCheck();
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
private void addConnectionsPostPermCheck()
|
||||
|
|
|
@ -71,6 +71,8 @@ public class DlgDelegate {
|
|||
NEW_GAME_DFLT_NAME,
|
||||
ENABLE_DUALPANE,
|
||||
ENABLE_DUALPANE_EXIT,
|
||||
LAUNCH_PERMS_REMOVE,
|
||||
LAUNCH_PERMS,
|
||||
|
||||
// BoardDelegate
|
||||
UNDO_LAST_ACTION,
|
||||
|
|
|
@ -1315,6 +1315,15 @@ public class GamesListDelegate extends ListDelegateBase
|
|||
m_newGameParams = params;
|
||||
askDefaultName();
|
||||
break;
|
||||
|
||||
case LAUNCH_PERMS_REMOVE:
|
||||
Assert.fail(); // not implemented
|
||||
break;
|
||||
case LAUNCH_PERMS:
|
||||
long rowid = (Long)params[0];
|
||||
launchGameAfterPerms( rowid );
|
||||
break;
|
||||
|
||||
default:
|
||||
Assert.fail();
|
||||
}
|
||||
|
@ -1559,33 +1568,33 @@ public class GamesListDelegate extends ListDelegateBase
|
|||
break;
|
||||
|
||||
case R.id.games_menu_loaddb:
|
||||
Perms23.doWithPermission( m_activity, Perms23.Perm.STORAGE,
|
||||
new Perms23.PermCbck() {
|
||||
public void onPermissionResult( Perms23.Perm perm,
|
||||
boolean granted )
|
||||
{
|
||||
Assert.assertTrue( Perms23.Perm.STORAGE == perm );
|
||||
if ( granted ) {
|
||||
DBUtils.loadDB( m_activity );
|
||||
XWPrefs.clearGroupPositions( m_activity );
|
||||
mkListAdapter();
|
||||
}
|
||||
}
|
||||
} );
|
||||
new Perms23.Builder( Perms23.Perm.STORAGE )
|
||||
.asyncQuery( m_activity, new Perms23.PermCbck() {
|
||||
@Override
|
||||
public void onPermissionResult( Map<Perms23.Perm, Boolean> granted )
|
||||
{
|
||||
Assert.assertTrue( granted.containsKey(Perms23.Perm.STORAGE) );
|
||||
if ( granted.get(Perms23.Perm.STORAGE) ) {
|
||||
DBUtils.loadDB( m_activity );
|
||||
XWPrefs.clearGroupPositions( m_activity );
|
||||
mkListAdapter();
|
||||
}
|
||||
}
|
||||
} );
|
||||
break;
|
||||
case R.id.games_menu_storedb:
|
||||
Perms23.doWithPermission( m_activity, Perms23.Perm.STORAGE,
|
||||
new Perms23.PermCbck() {
|
||||
public void onPermissionResult( Perms23.Perm perm,
|
||||
boolean granted )
|
||||
{
|
||||
Assert.assertTrue( Perms23.Perm.STORAGE == perm );
|
||||
if ( granted ) {
|
||||
DBUtils.saveDB( m_activity );
|
||||
showToast( R.string.db_store_done );
|
||||
}
|
||||
}
|
||||
} );
|
||||
new Perms23.Builder( Perms23.Perm.STORAGE )
|
||||
.asyncQuery( m_activity, new Perms23.PermCbck() {
|
||||
@Override
|
||||
public void onPermissionResult( Map<Perms23.Perm, Boolean> granted )
|
||||
{
|
||||
Assert.assertTrue( granted.containsKey( Perms23.Perm.STORAGE ) );
|
||||
if ( granted.get( Perms23.Perm.STORAGE ) ) {
|
||||
DBUtils.saveDB( m_activity );
|
||||
showToast( R.string.db_store_done );
|
||||
}
|
||||
}
|
||||
} );
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -2423,23 +2432,74 @@ public class GamesListDelegate extends ListDelegateBase
|
|||
tryNFCIntent( intent );
|
||||
}
|
||||
|
||||
private Set<Perms23.Perm> getPermsNeededFor( GameSummary summary )
|
||||
{
|
||||
// PENDING: do this for real
|
||||
Set<Perms23.Perm> perms = new HashSet<Perms23.Perm>();
|
||||
perms.add( Perms23.Perm.READ_PHONE_STATE );
|
||||
perms.add( Perms23.Perm.STORAGE );
|
||||
perms.add( Perms23.Perm.SEND_SMS );
|
||||
perms.add( Perms23.Perm.READ_CONTACTS );
|
||||
return perms;
|
||||
}
|
||||
|
||||
private void doOpenGame( Object[] params )
|
||||
{
|
||||
GameSummary summary = (GameSummary)params[1];
|
||||
long rowid = (Long)params[0];
|
||||
final long rowid = (Long)params[0];
|
||||
|
||||
if ( summary.conTypes.contains( CommsAddrRec.CommsConnType.COMMS_CONN_RELAY )
|
||||
&& summary.roomName.length() == 0 ) {
|
||||
Assert.fail();
|
||||
} else {
|
||||
try {
|
||||
if ( checkWarnNoDict( rowid ) ) {
|
||||
launchGame( rowid );
|
||||
}
|
||||
} catch ( GameLock.GameLockedException gle ) {
|
||||
DbgUtils.logex( TAG, gle );
|
||||
finish();
|
||||
final Set<Perms23.Perm> perms = getPermsNeededFor( summary );
|
||||
new Perms23.Builder( perms )
|
||||
.asyncQuery( m_activity, new Perms23.PermCbck() {
|
||||
@Override
|
||||
public void onPermissionResult( Map<Perms23.Perm,
|
||||
Boolean> perms ) {
|
||||
// If we get here, we were missing some
|
||||
// permissions. The user may or may not have
|
||||
// granted them. We'll go ahead and launch the
|
||||
// game, but some stuff may fail (because we'll
|
||||
// check for permissions later, e.g. when sending
|
||||
// an SMS message, without allowing for asking
|
||||
// again.
|
||||
Set<Perms23.Perm> missing = new HashSet<Perms23.Perm>();
|
||||
for ( Iterator<Perms23.Perm> iter = perms.keySet().iterator();
|
||||
iter.hasNext(); ) {
|
||||
Perms23.Perm perm = iter.next();
|
||||
boolean granted = perms.get( perm );
|
||||
if ( !granted ) {
|
||||
missing.add( perm );
|
||||
}
|
||||
}
|
||||
if ( 0 == missing.size() ) {
|
||||
launchGameAfterPerms( rowid );
|
||||
} else {
|
||||
ActionPair pair = new ActionPair( Action.LAUNCH_PERMS_REMOVE,
|
||||
R.string.remove_connvia );
|
||||
makeNotAgainBuilder( R.string.not_again_missing_perms,
|
||||
R.string.key_notagain_missing_perms,
|
||||
Action.LAUNCH_PERMS )
|
||||
.setActionPair( pair )
|
||||
.setParams( rowid, missing )
|
||||
.show();
|
||||
}
|
||||
}
|
||||
} );
|
||||
}
|
||||
}
|
||||
|
||||
private void launchGameAfterPerms( long rowid )
|
||||
{
|
||||
try {
|
||||
if ( checkWarnNoDict( rowid ) ) {
|
||||
launchGame( rowid );
|
||||
}
|
||||
} catch ( GameLock.GameLockedException gle ) {
|
||||
DbgUtils.logex( TAG, gle );
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -24,15 +24,20 @@ import android.content.pm.PackageManager;
|
|||
import android.support.v4.app.ActivityCompat;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public class Perms23 {
|
||||
private static final String TAG = Perms23.class.getSimpleName();
|
||||
|
||||
public static enum Perm {
|
||||
READ_PHONE_STATE("android.permission.READ_PHONE_STATE"),
|
||||
STORAGE("android.permission.WRITE_EXTERNAL_STORAGE")
|
||||
STORAGE("android.permission.WRITE_EXTERNAL_STORAGE"),
|
||||
SEND_SMS("android.permission.SEND_SMS"),
|
||||
READ_CONTACTS("android.permission.READ_CONTACTS")
|
||||
;
|
||||
|
||||
private String m_str;
|
||||
|
@ -51,56 +56,77 @@ public class Perms23 {
|
|||
}
|
||||
|
||||
public interface PermCbck {
|
||||
void onPermissionResult( Perm perm, boolean granted );
|
||||
void onPermissionResult( Map<Perm, Boolean> perms );
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
private Set<Perm> m_perms = new HashSet<Perm>();
|
||||
|
||||
public Builder(Set<Perm> perms) {
|
||||
m_perms.addAll( perms );
|
||||
}
|
||||
|
||||
public Builder( Perm perm ) {
|
||||
m_perms.add( perm );
|
||||
}
|
||||
|
||||
public void asyncQuery( Activity activity, PermCbck cbck )
|
||||
{
|
||||
DbgUtils.logd( TAG, "asyncQuery()" );
|
||||
boolean haveAll = true;
|
||||
boolean shouldShow = false;
|
||||
|
||||
ArrayList<String> askStrings = new ArrayList<String>();
|
||||
for ( Perm perm : m_perms ) {
|
||||
String permStr = perm.getString();
|
||||
boolean haveIt = PackageManager.PERMISSION_GRANTED
|
||||
== ContextCompat.checkSelfPermission( activity, permStr );
|
||||
|
||||
// For research: ask the OS if we should be printing a rationale
|
||||
if ( BuildConfig.DEBUG && !haveIt ) {
|
||||
shouldShow = shouldShow || ActivityCompat
|
||||
.shouldShowRequestPermissionRationale( activity, permStr );
|
||||
}
|
||||
|
||||
haveAll = haveAll && haveIt;
|
||||
if ( !haveIt ) {
|
||||
askStrings.add( permStr );
|
||||
}
|
||||
}
|
||||
|
||||
if ( shouldShow ) {
|
||||
DbgUtils.showf( "Should show rationale!!!" );
|
||||
}
|
||||
|
||||
if ( haveAll ) {
|
||||
Map<Perm, Boolean> map = new HashMap<Perm, Boolean>();
|
||||
for ( Perm perm : m_perms ) {
|
||||
map.put( perm, true );
|
||||
}
|
||||
cbck.onPermissionResult( map );
|
||||
} else {
|
||||
String[] permsArray = askStrings.toArray( new String[askStrings.size()] );
|
||||
int code = register( cbck );
|
||||
ActivityCompat.requestPermissions( activity, permsArray, code );
|
||||
}
|
||||
|
||||
DbgUtils.logd( TAG, "asyncQuery(%s) => %b", m_perms.toString(), haveAll );
|
||||
}
|
||||
}
|
||||
|
||||
private static Map<Integer, PermCbck> s_map = new HashMap<Integer, PermCbck>();
|
||||
public static void gotPermissionResult( int code, String[] perms, int[] granteds )
|
||||
{
|
||||
CbckRecord record = s_map.get( code );
|
||||
Map<Perm, Boolean> result = new HashMap<Perm, Boolean>();
|
||||
for ( int ii = 0; ii < perms.length; ++ii ) {
|
||||
Perm perm = Perm.getFor( perms[ii] );
|
||||
boolean granted = PackageManager.PERMISSION_GRANTED == granteds[ii];
|
||||
DbgUtils.logd( TAG, "calling %s.onPermissionResult(%s, %b)",
|
||||
record.cbck.getClass().getSimpleName(), perm.toString(),
|
||||
granted );
|
||||
record.cbck.onPermissionResult( perm, granted );
|
||||
result.put( perm, granted );
|
||||
// DbgUtils.logd( TAG, "calling %s.onPermissionResult(%s, %b)",
|
||||
// record.cbck.getClass().getSimpleName(), perm.toString(),
|
||||
// granted );
|
||||
}
|
||||
}
|
||||
|
||||
public static void doWithPermission( Activity activity, Perm perm, PermCbck cbck )
|
||||
{
|
||||
DbgUtils.logd( TAG, "doWithPermission()" );
|
||||
String permStr = perm.getString();
|
||||
|
||||
if ( PackageManager.PERMISSION_GRANTED == ContextCompat.checkSelfPermission( activity, permStr ) ) {
|
||||
DbgUtils.logd( TAG, "doWithPermission(): already have it" );
|
||||
cbck.onPermissionResult( perm, true );
|
||||
} else {
|
||||
// Should we show an explanation?
|
||||
boolean shouldShow = ActivityCompat
|
||||
.shouldShowRequestPermissionRationale( activity, permStr );
|
||||
if ( shouldShow && BuildConfig.DEBUG ) {
|
||||
DbgUtils.logd( TAG, "should show rationalle!!!" );
|
||||
}
|
||||
// Show an explanation to the user *asynchronously* -- don't
|
||||
// block // this thread waiting for the user's
|
||||
// response! After the user // sees the
|
||||
// explanation, try again to request the
|
||||
// permission.
|
||||
|
||||
String[] perms = new String[]{ permStr };
|
||||
int code = register( perms, cbck );
|
||||
ActivityCompat.requestPermissions( activity, perms, code );
|
||||
}
|
||||
|
||||
// int check = ContextCompat.checkSelfPermission( activity, permStr );
|
||||
// if ( PackageManager.PERMISSION_GRANTED == check ) {
|
||||
// if ( null != onSuccess ) {
|
||||
// onSuccess.run();
|
||||
// }
|
||||
// } else {
|
||||
// Assert.assertTrue( PackageManager.PERMISSION_DENIED == check );
|
||||
// }
|
||||
s_map.get( code ).onPermissionResult( result );
|
||||
}
|
||||
|
||||
public static boolean havePermission( Perm perm )
|
||||
|
@ -112,23 +138,12 @@ public class Perms23 {
|
|||
return result;
|
||||
}
|
||||
|
||||
private static class CbckRecord {
|
||||
public PermCbck cbck;
|
||||
public String[] perms;
|
||||
public CbckRecord( String[] perms, PermCbck cbck ) {
|
||||
this.perms = perms;
|
||||
this.cbck = cbck;
|
||||
}
|
||||
}
|
||||
|
||||
private static int s_nextRecord;
|
||||
private static Map<Integer, CbckRecord> s_map = new HashMap<Integer, CbckRecord>();
|
||||
private static int register( String[] perms, PermCbck cbck )
|
||||
private static int register( PermCbck cbck )
|
||||
{
|
||||
DbgUtils.assertOnUIThread();
|
||||
int code = ++s_nextRecord;
|
||||
CbckRecord record = new CbckRecord( perms, cbck );
|
||||
s_map.put( code, record );
|
||||
s_map.put( code, cbck );
|
||||
return code;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue