How to write a DashClock Extension: Dial Extension example

You can find here a new DashClock Extension example.

In previous post I wrote a Battery Extension.
This time I tried to make a Dial Extension.


We are going to write our service DialExtension that extends the DashClockExtension class.
public class DialExtension extends DashClockExtension {

 private static final String TAG = "DialExtension";
 
 public static final String PREF_FAVORITE_CONTACT = "pref_dial_contact";
 
 // Prefs
 protected Contact prefContact = null;
 
 @Override
 protected void onUpdateData(int reason) {
  
  //Read Preferences
  readPreferences();
  
  //publish
  publishUpdateExtensionData();
 }

 
 /**
  * publish Update data
  */
 private void publishUpdateExtensionData() {
  
  if (prefContact!=null){
   //Intent
   Intent dialIntent = new Intent (Intent.ACTION_DIAL,
                          Uri.parse(prefContact.getPhoneNumber()));
     
   // Publish the extension data update.
   publishUpdate(new ExtensionData()
     .visible(true)
     .icon(R.drawable.ic_extension_dial)
     .status(getString(R.string.dial))
     .expandedTitle(getString(R.string.dial))
     .expandedBody(
       prefContact.getDisplayName())
     .clickIntent(dialIntent));
  }
 }
 

 /**
  * Read preference
  */
 private void readPreferences() {
  // Get preference value.
  SharedPreferences sp = PreferenceManager
    .getDefaultSharedPreferences(this);
  String _idPrefContact = sp.getString(PREF_FAVORITE_CONTACT, null);
  prefContact=Contact.loadData(getApplicationContext(), _idPrefContact);
    
 }
It's very simple.

We read from preferences the favorite contact, we search and display the name and initiate phone calls.
In this case we are using an Intent.ACTION_DIAL Intent, specifying the number to dial by setting the Intents data using a tel: schema:
  Intent dialIntent = new Intent (Intent.ACTION_DIAL,
      Uri.parse(“tel:xxx-xxxx”));
As a result,using the ACTION_DIAL Intent action doesn’t require any special permissions.

You can change this code with:
  Intent dialIntent = new Intent (Intent.ACTION_CALL,
      Uri.parse(“tel:xxx-xxxx”));
In this case, to use this action, your application must request the CALL_PHONE uses-permission:
  <uses-permission android:name="android.permission.CALL_PHONE"/>

In our settingsActivity we can choose our favorite contact to dial.
To display a list of contacts for your users to select from, you can use the Intent.ACTION_PICK action along with the ContactsContract.Contacts.CONTENT_URI.
public class DialSettingsActivity extends BaseSettingsActivity {

 private static final String TAG = "DialSettingsActivity";
 private static int PICK_CONTACT = 0;
 private Preference mContact;
 private String mContactKey="pref_dial_contact";
 
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        getActionBar().setIcon(R.drawable.ic_extension_dial);
    }

    @Override
    protected void setupSimplePreferencesScreen() {
        // In the simplified UI, fragments are not used at all and we instead
        // use the older PreferenceActivity APIs.

        // Add 'general' preferences.
        addPreferencesFromResource(R.xml.prefs_dial);

        //Get Custom contact Pref
        mContact = (Preference)findPreference(mContactKey);
        mContact.setOnPreferenceClickListener(new OnPreferenceClickListener() {

            @Override
            public boolean onPreferenceClick(Preference preference) {
                Intent i = new Intent(Intent.ACTION_PICK);
                i.setType(ContactsContract.Contacts.CONTENT_TYPE);
                startActivityForResult(i, PICK_CONTACT);
                return true;
            }
        });
        
        setSummaryValue(null);
    }
    
    
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
     super.onActivityResult(requestCode, resultCode, data);
     if ((requestCode == PICK_CONTACT) && (resultCode == RESULT_OK)) {
       Log.d(TAG,"ActivityResult="+data.toString());
       if (data != null) {
          Uri uri = data.getData();
          Log.d(TAG,"Uri="+uri);
                String contactUri=  uri != null ? uri.toString() : "";
                Log.d(TAG,"ContactUri="+contactUri);
                
                SharedPreferences.Editor editor = getPreferenceManager().
                                             getSharedPreferences().edit();
                editor.putString(mContactKey, contactUri);
                editor.apply();
                
                setSummaryValue(contactUri);
          }
     }
    }
    
    /**
     * Set summary
     * @param contactUri
     */
    private void setSummaryValue(String contactUri){
     
     if (contactUri==null)
      contactUri=getPreferenceManager().getSharedPreferences().getString(mContactKey, "");
     
     Contact contact = Contact.loadData(getApplicationContext(), contactUri);
     if (contact!=null){
          mContact.setSummary(contact.displayName);
     }else{ 
            mContact.setSummary(null);
     }
   }
   
}


This will display a List View of the contacts available.
When the user selects a contact, it will be returned as a URI within the data property of the returned Intent.
With the URI we can access the Contacts Contract Contact Content Provider, and query for additional information, as display name, phone number..

public class Contact {

 private static String TAG="Contact";
 
 protected String _id;
 protected String displayName;
 protected String phoneNumber;
 
 /**
  * Load data from UriContact
  * 
  * @param context     context
  * @param uriContact  uriContact
  */
 public static Contact loadData(Context context,String uriContact){
  
  if (context==null || uriContact==null) return null;
  
  Contact mContact=null;
  Log.d(TAG,"Load Data id="+uriContact);
  
  Uri uri= Uri.parse(uriContact);
  
  //Search for uri
  Cursor cursor = context.getContentResolver().query(uri, null, null, null, null);
        if (cursor.moveToFirst()) {
          Log.d(TAG,"cursor="+cursor);
                mContact=new Contact();
         
          mContact._id=cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts._ID));
          Log.d(TAG, "id="+mContact._id);
        }
        cursor.close();
  
        if (mContact==null) return null;
  
      
     // Return all the PHONE data for the contact.
     String where = ContactsContract.Data.CONTACT_ID +  " = " + mContact._id + " AND " +
          ContactsContract.Data.MIMETYPE + " = '" +
          ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE +
          "'" ; 
          //ContactsContract.Data.IS_SUPER_PRIMARY + " = 1";
     String[] projection = new String[] {
         ContactsContract.Data.DISPLAY_NAME,
         ContactsContract.CommonDataKinds.Phone.NUMBER };
     
     Cursor dataCursor = context.getContentResolver().query(ContactsContract.Data.CONTENT_URI,
          projection, where, null, null);
     
     
     // Get the indexes of the required columns.
     int nameIdx = dataCursor.getColumnIndexOrThrow(ContactsContract.Data.DISPLAY_NAME);
     int phoneIdx = dataCursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Phone.NUMBER);
     
     if(dataCursor.moveToNext()){ 
      mContact=new Contact();
      // Extract the name.
      mContact.displayName = dataCursor.getString(nameIdx);
      // Extract the phone number.
      mContact.phoneNumber = dataCursor.getString(phoneIdx);
      Log.d(TAG,"name="+ mContact.displayName + " (" + mContact.phoneNumber + ")");
     }
     dataCursor.close();

     return mContact;
     
 }

}
It requires a user-permission.

    <!-- Contact permissions -->
    <uses-permission android:name="android.permission.READ_CONTACTS"/>
Add the corresponding service tag to our AndroidManifest.xml file

     <service
            android:name=".DialExtension"
            android:icon="@drawable/ic_extension_dial"
            android:label="@string/extension_title"
            android:permission=
                "com.google.android.apps.dashclock.permission.READ_EXTENSION_DATA" >
            <intent-filter>
                <action android:name="com.google.android.apps.dashclock.Extension" />
            </intent-filter>

            <meta-data
                android:name="protocolVersion"
                android:value="1" />
            <meta-data
                android:name="description"
                android:value="@string/extension_description" />
            <!-- A settings activity -->
            <meta-data
                android:name="settingsActivity"
                android:value=".DialSettingsActivity" />
        </service>

        <activity
            android:name=".DialSettingsActivity"
            android:exported="true"
            android:label="@string/extension_titlePref" />
And that's all....

In next post I'll try to write a Whatsapp Extension.

You can get code from GitHub:

Comments

Popular posts from this blog

AntiPattern: freezing a UI with Broadcast Receiver

NotificationListenerService and kitkat

How to centralize the support libraries dependencies in gradle