0

I am new to android.

What I intent to do is to get the nr of sms that are currently inside the device sms inbox. I want this number to appear inside a text view.

I know from other posts that the permission mechanism changed in API 23. But in all those posts we have an activity. In my case I don't have an activity, I am trying to get the number of sms inside the onUpdate method of a AppWidgetProvider.

On my Manifest file I added the permission for READ_SMS.

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.globa8track.smsgtw">    
    **<uses-permission android:name="android.permission.READ_SMS"/>**
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <receiver android:name=".smsGtw">
            <intent-filter>
                <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
            </intent-filter>

            <meta-data
                android:name="android.appwidget.provider"
                android:resource="@xml/sms_gtw_info" />
        </receiver>    
    </application>
</manifest>

Then On my Widget Java Class smsGtw.java

package com.globa8track.smsgtw;

import android.Manifest;
import android.app.DownloadManager;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.ContentResolver;
import android.content.Context;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.net.Uri;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.widget.RemoteViews;

import java.util.ArrayList;

    public class smsGtw extends AppWidgetProvider {

        void updateAppWidget(Context context, AppWidgetManager appWidgetManager,
                             int appWidgetId) {

            ArrayList<String> inboxSms;
            int nrSmsInInbox = 0;


            inboxSms = fetchInbox(context);
            nrSmsInInbox = inboxSms.size();



            CharSequence widgetText = "Gtw Total Sms Received: " + nrSmsInInbox;

            // Construct the RemoteViews object
            RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.sms_gtw);
            views.setTextViewText(R.id.appwidget_text, widgetText);

            // Instruct the widget manager to update the widget
            appWidgetManager.updateAppWidget(appWidgetId, views);
        }

        @Override
        public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
            // There may be multiple widgets active, so update all of them
            for (int appWidgetId : appWidgetIds) {
                updateAppWidget(context, appWidgetManager, appWidgetId);
            }
        }

        @Override
        public void onEnabled(Context context) {
            // Enter relevant functionality for when the first widget is created
        }

        @Override
        public void onDisabled(Context context) {
            // Enter relevant functionality for when the last widget is disabled
        }


        public static ArrayList<String> fetchInbox(Context context){

            ArrayList<String> sms=new ArrayList<String>();

            Uri uriSms=Uri.parse("content://sms/inbox");

            ContentResolver cr = context.getContentResolver();
            Cursor cursor = cr.query(uriSms, new String[]{"_id", "address", "date", "body"}, null, null, null);
            cursor.moveToFirst();

            while(cursor.moveToNext()){

                String address=cursor.getString(1);
                String body=cursor.getString(3);

                sms.add("Address=>"+address+"\n Sms=>"+body);
            }

            return sms;
        }


    }

When I run this code on Android Studio emulator (Nexus 5 API 23) I get the following error:

Process: com.globa8track.smsgtw, PID: 5397 java.lang.RuntimeException: Unable to start receiver com.globa8track.smsgtw.smsGtw: java.lang.SecurityException: Permission Denial: reading com.android.providers.telephony.SmsProvider uri content://sms/inbox from pid=5397, uid=10057 requires android.permission.READ_SMS, or grantUriPermission()

From the post : Why does Android ignore READ_SMS permission?

I understood that it is needed to ask first permission, then check for that permission. As @Tomáš Navara said. But in his case there is an activity.

Do I have to have an activity too? I don't want user interaction, neither a user interface for checking the amount of sms stored in the inbox.

Another thing, could you help me get started in the android widget world? Where should I start? Could you provide me some pointers/resources?   Thank you all for your patience.

Community
  • 1
  • 1
ThelmaJay
  • 79
  • 1
  • 14
  • 1
    "Do I have to have an activity too?" -- yes. – CommonsWare Feb 26 '16 at 16:39
  • Tk u @CommonsWare. So I have to create an activity SMSRead that is called by the widgets onUpdate() through an intent? And how do I get the result printed on widget's text view? – ThelmaJay Feb 26 '16 at 17:34

1 Answers1

1

So I have to create an activity SMSRead that is called by the widgets onUpdate() through an intent?

No. Your existing code is fine (presumably) for getting the messages and updating the app widget. If it works on older devices, and if it works on Android 6.0 if you manually grant the permission via your app's screen in Settings, then that stuff is fine.

Where you need an activity is to be able to request the READ_SMS permission from the user.

So, in your app widget code, you will need to call ContextCompat.checkSelfPermission() to see if you have READ_SMS access or not. If you do have access, go ahead and update your app widget. If you do not, raise a Notification to let the user know that you need them to grant you permission. Ideally, that Notification would be tied to an activity of yours, where you can then use ActivityCompat.requestPermissions() to request READ_SMS.

You could also arrange to have that activity be your app widget configuration activity, which is started automatically when your app widget is added to the user's home screen. This allows you to request the permission right away. However, you will still need to call checkSelfPermission() in the AppWidgetProvider, as the user could revoke the permission via the Settings app.

CommonsWare
  • 986,068
  • 189
  • 2,389
  • 2,491
  • Thank you @CommonsWare. I added a main activity to my widget and added the `checkSelfPermission` and `requestPermissions`. I am now able to get the number of received sms on my widget. This [link](https://guides.codepath.com/android/Understanding-App-Permissions) helped me a lot to understand how to request permission. – ThelmaJay Feb 26 '16 at 23:06