mirror of
git://xwords.git.sourceforge.net/gitroot/xwords/xwords
synced 2025-01-29 08:34:37 +01:00
permissions: ask for READ_CONTACTS
On launching SMS invite dialog, ask for READ_CONTACTS permission. Where it's needed, though, is for the user-invisible process of translating phone numbers to names (not launching the Contacts app via an Intent). This just seems like the best place to ask since the user's thinking about contacts and phone numbers.
This commit is contained in:
parent
09188bc704
commit
f199aef738
9 changed files with 474 additions and 378 deletions
File diff suppressed because it is too large
Load diff
|
@ -1971,8 +1971,6 @@
|
|||
up please make sure that WiFi is turned on, that Crosswords is
|
||||
installed, and that play via WiFi Direct is enabled.</string>
|
||||
|
||||
<!-- -->
|
||||
<string name="manual_owner_name">(Not in contacts)</string>
|
||||
<!-- -->
|
||||
<string name="warn_nomobile_fmt">The number %1$s for %2$s is not
|
||||
a \"mobile\" number. Import anyway?</string>
|
||||
|
@ -2732,6 +2730,13 @@
|
|||
safe to permanently deny permission.
|
||||
</string>
|
||||
|
||||
<string name="contacts_rationale">Crosswords want access to your
|
||||
contacts in order to put a name to phone numbers that send you
|
||||
invitations via SMS. You\'ll still be able to receive invitations if
|
||||
you don\'t grant this permission, but only the phone number of the
|
||||
sender will be displayed.</string>
|
||||
|
||||
<string name="remove_sms">Remove SMS</string>
|
||||
<string name="contact_not_found">Not in Contacts</string>
|
||||
|
||||
</resources>
|
||||
|
|
|
@ -1705,8 +1705,6 @@
|
|||
pu esaelp ekam erus taht IfIw si denrut ,no taht Sdrowssorc si
|
||||
,dellatsni dna taht yalp aiv IfIw Tcerid si delbane.</string>
|
||||
<!-- -->
|
||||
<string name="manual_owner_name">tOn( ni )stcatnoc</string>
|
||||
<!-- -->
|
||||
<string name="warn_nomobile_fmt">Eht rebmun %1$s rof %2$s si ton
|
||||
a \"elibom\" rebmun. Tropmi ?yawyna</string>
|
||||
<!-- Shows in SMS Invite dialog when no phone numbers have been saved previously -->
|
||||
|
@ -2332,5 +2330,11 @@
|
|||
e.g. esuaceb uoy yap rof hcae egassem ro evah a Nozirev ,enohp ti\'s
|
||||
efas ot yltnenamrep yned noissimrep.
|
||||
</string>
|
||||
<string name="contacts_rationale">Sdrowssorc tnaw ssecca ot ruoy
|
||||
stcatnoc ni redro ot tup a eman ot enohp srebmun taht dnes uoy
|
||||
snoitativni aiv SMS. Uoy\'ll llits eb elba ot eviecer snoitativni fi
|
||||
uoy nod\'t tnarg siht ,noissimrep tub ylno eht enohp rebmun fo eht
|
||||
rednes lliw eb deyalpsid.</string>
|
||||
<string name="remove_sms">Evomer SMS</string>
|
||||
<string name="contact_not_found">Ton ni Stcatnoc</string>
|
||||
</resources>
|
||||
|
|
|
@ -1705,8 +1705,6 @@
|
|||
UP PLEASE MAKE SURE THAT WIFI IS TURNED ON, THAT CROSSWORDS IS
|
||||
INSTALLED, AND THAT PLAY VIA WIFI DIRECT IS ENABLED.</string>
|
||||
<!-- -->
|
||||
<string name="manual_owner_name">(NOT IN CONTACTS)</string>
|
||||
<!-- -->
|
||||
<string name="warn_nomobile_fmt">THE NUMBER %1$s FOR %2$s IS NOT
|
||||
A \"MOBILE\" NUMBER. IMPORT ANYWAY?</string>
|
||||
<!-- Shows in SMS Invite dialog when no phone numbers have been saved previously -->
|
||||
|
@ -2332,5 +2330,11 @@
|
|||
E.G. BECAUSE YOU PAY FOR EACH MESSAGE OR HAVE A VERIZON PHONE, IT\'S
|
||||
SAFE TO PERMANENTLY DENY PERMISSION.
|
||||
</string>
|
||||
<string name="contacts_rationale">CROSSWORDS WANT ACCESS TO YOUR
|
||||
CONTACTS IN ORDER TO PUT A NAME TO PHONE NUMBERS THAT SEND YOU
|
||||
INVITATIONS VIA SMS. YOU\'LL STILL BE ABLE TO RECEIVE INVITATIONS IF
|
||||
YOU DON\'T GRANT THIS PERMISSION, BUT ONLY THE PHONE NUMBER OF THE
|
||||
SENDER WILL BE DISPLAYED.</string>
|
||||
<string name="remove_sms">REMOVE SMS</string>
|
||||
<string name="contact_not_found">NOT IN CONTACTS</string>
|
||||
</resources>
|
||||
|
|
|
@ -112,6 +112,7 @@ public class DlgDelegate {
|
|||
CLEAR_ACTION,
|
||||
USE_IMMOBILE_ACTION,
|
||||
POST_WARNING_ACTION,
|
||||
RETRY_CONTACTS_ACTION,
|
||||
|
||||
// BT Invite
|
||||
OPEN_BT_PREFS_ACTION,
|
||||
|
|
|
@ -87,6 +87,11 @@ public class Perms23 {
|
|||
return this;
|
||||
}
|
||||
|
||||
public void asyncQuery( Activity activity )
|
||||
{
|
||||
asyncQuery( activity, null );
|
||||
}
|
||||
|
||||
public void asyncQuery( Activity activity, PermCbck cbck )
|
||||
{
|
||||
DbgUtils.logd( TAG, "asyncQuery(%s)", m_perms.toString() );
|
||||
|
@ -117,11 +122,13 @@ public class Perms23 {
|
|||
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 );
|
||||
if ( null != cbck ) {
|
||||
Map<Perm, Boolean> map = new HashMap<Perm, Boolean>();
|
||||
for ( Perm perm : m_perms ) {
|
||||
map.put( perm, true );
|
||||
}
|
||||
cbck.onPermissionResult( map );
|
||||
}
|
||||
cbck.onPermissionResult( map );
|
||||
} else {
|
||||
String[] permsArray = askStrings.toArray( new String[askStrings.size()] );
|
||||
int code = register( cbck );
|
||||
|
@ -135,16 +142,19 @@ public class Perms23 {
|
|||
private static Map<Integer, PermCbck> s_map = new HashMap<Integer, PermCbck>();
|
||||
public static void gotPermissionResult( int code, String[] perms, int[] granteds )
|
||||
{
|
||||
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];
|
||||
result.put( perm, granted );
|
||||
// DbgUtils.logd( TAG, "calling %s.onPermissionResult(%s, %b)",
|
||||
// record.cbck.getClass().getSimpleName(), perm.toString(),
|
||||
// granted );
|
||||
PermCbck cbck = s_map.get( code );
|
||||
if ( null != cbck ) {
|
||||
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];
|
||||
result.put( perm, granted );
|
||||
// DbgUtils.logd( TAG, "calling %s.onPermissionResult(%s, %b)",
|
||||
// record.cbck.getClass().getSimpleName(), perm.toString(),
|
||||
// granted );
|
||||
}
|
||||
cbck.onPermissionResult( result );
|
||||
}
|
||||
s_map.get( code ).onPermissionResult( result );
|
||||
}
|
||||
|
||||
public static boolean havePermission( Perm perm )
|
||||
|
|
|
@ -48,8 +48,12 @@ import java.util.ArrayList;
|
|||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.json.JSONObject;
|
||||
import org.json.JSONException;
|
||||
|
||||
public class SMSInviteDelegate extends InviteDelegate
|
||||
implements View.OnClickListener {
|
||||
private static final String TAG = SMSInviteDelegate.class.getSimpleName();
|
||||
|
@ -100,6 +104,8 @@ public class SMSInviteDelegate extends InviteDelegate
|
|||
|
||||
getSavedState();
|
||||
rebuildList( true );
|
||||
|
||||
askContactsPermission( true );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -210,32 +216,48 @@ public class SMSInviteDelegate extends InviteDelegate
|
|||
|
||||
// DlgDelegate.DlgClickNotify interface
|
||||
@Override
|
||||
public void dlgButtonClicked( Action action, int which, Object[] params )
|
||||
public void dlgButtonClicked( Action action, int which,
|
||||
final Object[] params )
|
||||
{
|
||||
switch( which ) {
|
||||
case AlertDialog.BUTTON_POSITIVE:
|
||||
switch( action ) {
|
||||
case CLEAR_ACTION:
|
||||
boolean isPositive = AlertDialog.BUTTON_POSITIVE == which;
|
||||
DbgUtils.logd( TAG, "dlgButtonClicked(%s,pos:%b)",
|
||||
action.toString(), isPositive );
|
||||
|
||||
switch ( action ) {
|
||||
case RETRY_CONTACTS_ACTION:
|
||||
askContactsPermission( false );
|
||||
break;
|
||||
case CLEAR_ACTION:
|
||||
if ( isPositive) {
|
||||
clearSelectedImpl();
|
||||
break;
|
||||
case USE_IMMOBILE_ACTION:
|
||||
m_immobileConfirmed = true;
|
||||
break;
|
||||
case POST_WARNING_ACTION:
|
||||
}
|
||||
break;
|
||||
case POST_WARNING_ACTION:
|
||||
DbgUtils.printStack( TAG );
|
||||
if ( isPositive ) { // ???
|
||||
Assert.assertTrue( ((String)params[0]).equals(m_pendingNumber) );
|
||||
Assert.assertTrue( params[1] == null
|
||||
|| ((String)params[1]).equals(m_pendingName) );
|
||||
m_phoneRecs.add( new PhoneRec( m_pendingName, m_pendingNumber ) );
|
||||
saveAndRebuild();
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case DlgDelegate.DISMISS_BUTTON:
|
||||
if ( Action.USE_IMMOBILE_ACTION == action && m_immobileConfirmed ) {
|
||||
makeConfirmThenBuilder( R.string.warn_unlimited,
|
||||
Action.POST_WARNING_ACTION )
|
||||
.setPosButton( R.string.button_yes )
|
||||
.show();
|
||||
case USE_IMMOBILE_ACTION:
|
||||
if ( isPositive ) {
|
||||
m_immobileConfirmed = true;
|
||||
} else if ( m_immobileConfirmed ) {
|
||||
// Putting up a new alert from inside another's handler
|
||||
// confuses things. So post instead.
|
||||
post( new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
makeConfirmThenBuilder( R.string.warn_unlimited,
|
||||
Action.POST_WARNING_ACTION )
|
||||
.setPosButton( R.string.button_yes )
|
||||
.setParams( params )
|
||||
.show();
|
||||
}
|
||||
} );
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -279,6 +301,7 @@ public class SMSInviteDelegate extends InviteDelegate
|
|||
number, name );
|
||||
makeConfirmThenBuilder( msg, Action.USE_IMMOBILE_ACTION )
|
||||
.setPosButton( R.string.button_yes )
|
||||
.setParams( number, name )
|
||||
.show();
|
||||
}
|
||||
}
|
||||
|
@ -306,22 +329,28 @@ public class SMSInviteDelegate extends InviteDelegate
|
|||
|
||||
private void getSavedState()
|
||||
{
|
||||
String[] phones = XWPrefs.getSMSPhones( m_activity );
|
||||
JSONObject phones = XWPrefs.getSMSPhones( m_activity );
|
||||
|
||||
m_phoneRecs = new ArrayList<PhoneRec>(phones.length);
|
||||
for ( String phone : phones ) {
|
||||
PhoneRec rec = new PhoneRec( null, phone );
|
||||
m_phoneRecs = new ArrayList<PhoneRec>();
|
||||
for ( Iterator<String> iter = phones.keys(); iter.hasNext(); ) {
|
||||
String phone = iter.next();
|
||||
String name = phones.optString( phone, null );
|
||||
PhoneRec rec = new PhoneRec( name, phone );
|
||||
m_phoneRecs.add( rec );
|
||||
}
|
||||
}
|
||||
|
||||
private void saveAndRebuild()
|
||||
{
|
||||
String[] phones = new String[m_phoneRecs.size()];
|
||||
JSONObject phones = new JSONObject();
|
||||
Iterator<PhoneRec> iter = m_phoneRecs.iterator();
|
||||
for ( int ii = 0; iter.hasNext(); ++ii ) {
|
||||
while ( iter.hasNext() ) {
|
||||
PhoneRec rec = iter.next();
|
||||
phones[ii] = rec.m_phone;
|
||||
try {
|
||||
phones.put( rec.m_phone, rec.m_name );
|
||||
} catch ( JSONException ex ) {
|
||||
DbgUtils.logex( TAG, ex );
|
||||
}
|
||||
}
|
||||
XWPrefs.setSMSPhones( m_activity, phones );
|
||||
|
||||
|
@ -340,6 +369,23 @@ public class SMSInviteDelegate extends InviteDelegate
|
|||
saveAndRebuild();
|
||||
}
|
||||
|
||||
private void askContactsPermission( boolean showRationale )
|
||||
{
|
||||
Perms23.Builder builder = new Perms23.Builder( Perms23.Perm.READ_CONTACTS );
|
||||
if ( showRationale ) {
|
||||
builder.setOnShowRationale( new Perms23.OnShowRationale() {
|
||||
@Override
|
||||
public void onShouldShowRationale( Set<Perms23.Perm> perms )
|
||||
{
|
||||
makeOkOnlyBuilder( R.string.contacts_rationale )
|
||||
.setAction( Action.RETRY_CONTACTS_ACTION )
|
||||
.show();
|
||||
}
|
||||
} );
|
||||
}
|
||||
builder.asyncQuery( m_activity );
|
||||
}
|
||||
|
||||
private class PhoneRec implements InviterItem {
|
||||
public String m_phone;
|
||||
public String m_name;
|
||||
|
@ -354,10 +400,7 @@ public class SMSInviteDelegate extends InviteDelegate
|
|||
m_phone = phone;
|
||||
|
||||
if ( null == name ) {
|
||||
name = Utils.phoneToContact( m_activity, phone, false );
|
||||
if ( null == name ) {
|
||||
name = getString( R.string.manual_owner_name );
|
||||
}
|
||||
name = getString( R.string.contact_not_found );
|
||||
}
|
||||
m_name = name;
|
||||
}
|
||||
|
|
|
@ -295,7 +295,8 @@ public class Utils {
|
|||
cursor.close();
|
||||
s_phonesHash.put( phone, name );
|
||||
} catch ( Exception ex ) {
|
||||
name = "not found";
|
||||
// could just be lack of permsisions
|
||||
name = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,12 +26,16 @@ import android.content.res.Configuration;
|
|||
import android.preference.PreferenceManager;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
import org.eehouse.android.xw4.jni.CommsAddrRec.CommsConnType;
|
||||
import org.eehouse.android.xw4.jni.CommsAddrRec.CommsConnTypeSet;
|
||||
|
||||
public class XWPrefs {
|
||||
private static final String TAG = XWPrefs.class.getSimpleName();
|
||||
|
||||
// No reason to put this in xml if they're private to this file!
|
||||
private static final String key_checked_upgrades = "key_checked_upgrades";
|
||||
|
@ -236,14 +240,39 @@ public class XWPrefs {
|
|||
return getPrefsStringArray( context, R.string.key_closed_langs );
|
||||
}
|
||||
|
||||
public static void setSMSPhones( Context context, String[] names )
|
||||
public static void setSMSPhones( Context context, JSONObject phones )
|
||||
{
|
||||
setPrefsStringArray( context, R.string.key_sms_phones, names );
|
||||
setPrefsString( context, R.string.key_sms_phones, phones.toString() );
|
||||
}
|
||||
|
||||
public static String[] getSMSPhones( Context context )
|
||||
public static JSONObject getSMSPhones( Context context )
|
||||
{
|
||||
return getPrefsStringArray( context, R.string.key_sms_phones );
|
||||
String asStr = getPrefsString( context, R.string.key_sms_phones );
|
||||
JSONObject obj = null;
|
||||
|
||||
if ( null != asStr ) {
|
||||
try {
|
||||
obj = new JSONObject( asStr );
|
||||
} catch ( JSONException ex ) {
|
||||
obj = null;
|
||||
}
|
||||
}
|
||||
|
||||
if ( null == obj ) {
|
||||
obj = new JSONObject();
|
||||
if ( null != asStr ) {
|
||||
String[] numbers = TextUtils.split( asStr, "\n" );
|
||||
for ( String number : numbers ) {
|
||||
try {
|
||||
obj.put( number, (String)null );
|
||||
} catch ( JSONException ex ) {
|
||||
DbgUtils.logex( TAG, ex );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
// Used by RelayInviteDelegate.java
|
||||
|
|
Loading…
Add table
Reference in a new issue