permissions: ask when opening SMS game

Add post-open test for SMS and then ask for SMS permission, giving
rationale if the OS says I should. Meant adding a new interface for
rationales and wiring that in. It's a bit spaghetti and I may think of a
cleaner way later.
This commit is contained in:
Eric House 2016-12-16 21:04:15 -08:00
parent 3a53abce52
commit 29afb19cb4
7 changed files with 94 additions and 20 deletions

View file

@ -5058,6 +5058,7 @@ XLATE-ME
*/
public static final int phone_label=0x7f050223;
public static final int phone_state_rationale=0x7f050359;
/** Don't warn, but simply force to skip turn (give 0 points)
when user attempts to play word not in the wordlist.
Don't warn, but simply force to skip turn (give 0 points)
@ -5822,7 +5823,7 @@ XLATE-ME
*/
public static final int remote_undone=0x7f050226;
public static final int remove_sms=0x7f050359;
public static final int remove_sms=0x7f05035a;
/** <string name="rename_group_label">Change the name of this group to:</string>
*/
public static final int rename_group_label=0x7f050273;

View file

@ -2725,6 +2725,13 @@
receive moves.\n\nYou can re-open it to be asked for permission
again. Or you can remove the SMS communication setting.</string>
<string name="phone_state_rationale">Crosswords wants to determine
whether your phone can send SMS \"data\" messages to give you the
option of playing that way. If you don\'t ever want to play via SMS,
e.g. because you pay for each message or have a Verizon phone, it\'s
safe to permanently deny permission.
</string>
<string name="remove_sms">Remove SMS</string>
</resources>

View file

@ -2326,5 +2326,11 @@
os. Uoy nac llits nepo eht ,emag tub ti yam ton eb elba ot dnes ro
eviecer sevom.\n\nUoy nac nepo-er ti ot eb deksa rof noissimrep
niaga. Ro uoy nac evomer eht SMS noitacinummoc gnittes.</string>
<string name="phone_state_rationale">Sdrowssorc stnaw ot enimreted
rehtehw ruoy enohp nac dnes SMS \"atad\" segassem ot evig uoy eht
noitpo fo gniyalp taht yaw. Fi uoy nod\'t reve tnaw ot yalp aiv ,SMs
e.g. esuaceb uoy yap rof hcae egassem ro evah a Nozirev ,enohp ti\'s
efas ot yltnenamrep yned noissimrep.
</string>
<string name="remove_sms">Evomer SMS</string>
</resources>

View file

@ -2326,5 +2326,11 @@
SO. YOU CAN STILL OPEN THE GAME, BUT IT MAY NOT BE ABLE TO SEND OR
RECEIVE MOVES.\n\nYOU CAN RE-OPEN IT TO BE ASKED FOR PERMISSION
AGAIN. OR YOU CAN REMOVE THE SMS COMMUNICATION SETTING.</string>
<string name="phone_state_rationale">CROSSWORDS WANTS TO DETERMINE
WHETHER YOUR PHONE CAN SEND SMS \"DATA\" MESSAGES TO GIVE YOU THE
OPTION OF PLAYING THAT WAY. IF YOU DON\'T EVER WANT TO PLAY VIA SMS,
E.G. BECAUSE YOU PAY FOR EACH MESSAGE OR HAVE A VERIZON PHONE, IT\'S
SAFE TO PERMANENTLY DENY PERMISSION.
</string>
<string name="remove_sms">REMOVE SMS</string>
</resources>

View file

@ -42,7 +42,12 @@ import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Map;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Semaphore;
import junit.framework.Assert;
@ -68,10 +73,6 @@ import org.eehouse.android.xw4.jni.UtilCtxtImpl;
import org.eehouse.android.xw4.jni.XwJNI.GamePtr;
import org.eehouse.android.xw4.jni.XwJNI;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.concurrent.Semaphore;
public class BoardDelegate extends DelegateBase
implements TransportProcs.TPMsgHandler, View.OnClickListener,
DwnldDelegate.DownloadFinishedListener,
@ -405,8 +406,8 @@ public class BoardDelegate extends DelegateBase
if ( self.m_summary.hasRematchInfo() ) {
self.tryRematchInvites( true );
} else {
self.showInviteChoicesThen( Action.LAUNCH_INVITE_ACTION,
self.m_sentInfo );
self.callInviteChoices( Action.LAUNCH_INVITE_ACTION,
self.m_sentInfo, true );
}
} else {
self.askDropRelay();
@ -714,6 +715,43 @@ public class BoardDelegate extends DelegateBase
}
}
// Invitations need to check phone state to decide whether to offer SMS
// invitation. Complexity (showRationale) boolean is to prevent infinite
// loop of showing the rationale over and over. Android will always tell
// us to show the rationale, but if we've done it already we need to go
// straight to asking for the permission.
private void callInviteChoices( final Action action,
final DBUtils.SentInvitesInfo info,
boolean showRationale )
{
Perms23.Builder builder =
new Perms23.Builder( Perms23.Perm.READ_PHONE_STATE );
if ( showRationale ) {
builder.setOnShowRationale( new Perms23.OnShowRationale() {
@Override
public void onShouldShowRationale( Set<Perms23.Perm> perms )
{
makeOkOnlyBuilder( R.string.phone_state_rationale )
.setAction( Action.RETRY_PHONE_STATE_ACTION )
.setParams( action, info )
.show();
}
} );
}
builder.asyncQuery( m_activity, new Perms23.PermCbck() {
@Override
public void onPermissionResult( Map<Perms23.Perm,
Boolean> perms )
{
// Do the work regardless of result; just won't have
// SMS option
showInviteChoicesThen( action, info );
}
});
}
@Override
public void orientationChanged()
{
@ -1006,6 +1044,10 @@ public class BoardDelegate extends DelegateBase
}
}, 10 );
}
} else if ( Action.RETRY_PHONE_STATE_ACTION == action ) {
Action stateAction = (Action)params[0];
DBUtils.SentInvitesInfo info = (DBUtils.SentInvitesInfo)params[1];
callInviteChoices( stateAction, info, false );
} else if ( positive ) {
handled = true;
JNICmd cmd = JNICmd.CMD_NONE;

View file

@ -93,6 +93,7 @@ public class DlgDelegate {
NFC_TO_SELF,
DROP_RELAY_ACTION,
DROP_SMS_ACTION,
RETRY_PHONE_STATE_ACTION,
// Dict Browser
FINISH_ACTION,

View file

@ -60,9 +60,13 @@ public class Perms23 {
public interface PermCbck {
void onPermissionResult( Map<Perm, Boolean> perms );
}
public interface OnShowRationale {
void onShouldShowRationale( Set<Perms23.Perm> perms );
}
public static class Builder {
private Set<Perm> m_perms = new HashSet<Perm>();
private OnShowRationale m_onShow;
public Builder(Set<Perm> perms) {
m_perms.addAll( perms );
@ -77,11 +81,18 @@ public class Perms23 {
return this;
}
public Builder setOnShowRationale( OnShowRationale onShow )
{
m_onShow = onShow;
return this;
}
public void asyncQuery( Activity activity, PermCbck cbck )
{
DbgUtils.logd( TAG, "asyncQuery()" );
DbgUtils.logd( TAG, "asyncQuery(%s)", m_perms.toString() );
boolean haveAll = true;
boolean shouldShow = false;
Set<Perm> needShow = new HashSet<Perm>();
ArrayList<String> askStrings = new ArrayList<String>();
for ( Perm perm : m_perms ) {
@ -90,22 +101,22 @@ public class Perms23 {
== 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 );
if ( !haveIt ) {
askStrings.add( permStr );
if ( ActivityCompat
.shouldShowRequestPermissionRationale( activity,
permStr ) ) {
needShow.add( perm );
}
}
haveAll = haveAll && haveIt;
if ( !haveIt ) {
askStrings.add( permStr );
}
}
if ( shouldShow ) {
DbgUtils.showf( "Should show rationale!!!" );
}
if ( haveAll ) {
if ( 0 < needShow.size() && null != m_onShow ) {
m_onShow.onShouldShowRationale( needShow );
} else if ( haveAll ) {
Map<Perm, Boolean> map = new HashMap<Perm, Boolean>();
for ( Perm perm : m_perms ) {
map.put( perm, true );
@ -117,7 +128,7 @@ public class Perms23 {
ActivityCompat.requestPermissions( activity, permsArray, code );
}
DbgUtils.logd( TAG, "asyncQuery(%s) => %b", m_perms.toString(), haveAll );
DbgUtils.logd( TAG, "asyncQuery(%s) DONE", m_perms.toString() );
}
}