Sunday, September 22, 2013

Pending Intent

https://allaudin.github.io/pending-intent/- A good reference

A PendingIntent is a token that you give to another application (e.g. Notification Manager, Alarm Manager or other 3rd party applications), which allows this other application to use the permissions of your application to execute a predefined piece of code.

For Example, if we want to start our Service(which requires some special  permission like gps, action battery change etc), through AlarmManager which will trigger that service some-point in future at regular interval.
Then we create a pending intent for our service and we give this intent to other application viz. in this case is AlarmManager Now AlarmManager will use the permission(gps, vibrate, etc) of our service to execute code.
Intent intent = new Intent(this, MyService.class);
    PendingIntent pendingIntent = PendingIntent.getBroadcast(this.getApplicationContext(), 234324243, intent, 0);
    AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
    alarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis()
        + (i * 1000), pendingIntent);
If you give the foreign application an Intent, and that application sends/broadcasts the Intent you gave, they will execute the Intent with their own permissions. But if you instead give the foreign application a PendingIntent you created using your own permission, that application will execute the contained Intent using your application's permission.
A PendingIntent has defined Activity, Broadcast or Service  within it, and those can be sent to other applications to use it.
I can define my Intent (Activity, BroadcastReceiver or Service) and can send to other application to use it. 

Why PendingIntent is required ?

If I create Intent,
Intent bIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);

and sending "bIntent" to other application , which is not having permission (android.permission.BLUETOOTH_ADMIN).

So, When I do, 
startActivity(bIntent);

It will never launch bluetooth enabling Activity.

If we use PendingIntent, the application (which use PendingIntent) no need to have permission. But the application which creates PendingIntent must have required permission for Intents.

PendingIntent can be created using it's static methods getActivity(), getBroadcast() and getService().

Let's see sample for PendingIntent,

public class IParcel implements Parcelable
{

    PendingIntent pIntent = null;
   
    public IParcel(PendingIntent pi)
    {
        pIntent = pi;
    }
   
    public IParcel(Parcel in)
    {
        pIntent = (PendingIntent)in.readValue(null);
    }
   
    public static Parcelable.Creator<IParcel> CREATOR = new Parcelable.Creator<IParcel>(){

        @Override
        public IParcel createFromParcel(Parcel source) {
            // TODO Auto-generated method stub
            return new IParcel(source);
        }

        @Override
        public IParcel[] newArray(int size) {
            // TODO Auto-generated method stub
            return null;
        }
       
    };
  
    @Override
    public int describeContents() {
        // TODO Auto-generated method stub
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        // TODO Auto-generated method stub
        dest.writeValue(pIntent);
       
    }
   
}

public class FirstApp extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        super.onCreate(savedInstanceState);
    
        Intent myIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
        PendingIntent pIntent = PendingIntent.getActivity(this, 0, myIntent,PendingIntent.FLAG_ONE_SHOT);//FLAG_ONE_SHOT - only once pIntent can use the myIntent
     
        IParcel ip = new IParcel(pIntent);
    
        Intent sndApp = new Intent();
        sndApp.setComponent(new ComponentName("com.myapp", "com.myapp.SecondApp"));
        sndApp.putExtra("obj",ip);
        startActivity(sndApp);
        }

}

public class SecondApp extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        super.onCreate(savedInstanceState);

       IParcel pc = getIntent().getExtras().getParcelable("obj");
       if(pc != null){
               pc.pIntent.send(); // this will launch the bluetooth enabling activity
       } 
       }
}