1

I am trying to enable/disable mobile data at specific time of the day. This is what I have so far:

  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

        Calendar objCal = Calendar.getInstance();
    objCal.set(Calendar.HOUR_OF_DAY, 11);
    objCal.set(Calendar.MINUTE, 0);
    objCal.set(Calendar.SECOND, 0);
    //
    // Intent intent = new Intent(this, MainActivity.class);
    // intent.setAction("com.sang.mobiledata.ACTION");
    //
     PendingIntent pi = PendingIntent.getActivity(this, 0, new Intent(
     this, MainActivity.class), PendingIntent.FLAG_UPDATE_CURRENT);
     AlarmManager am = (AlarmManager)
     this.getSystemService(Context.ALARM_SERVICE);
     am.setRepeating(AlarmManager.RTC_WAKEUP, objCal.getTimeInMillis(),
     AlarmManager.INTERVAL_DAY, pi);

Basically, I would like to turn off the data connection say at 10pm. I know this will be achieved by this line:

objNetwork.setMobileDataEnabled(getBaseContext(), false);

and again turn it on at say 6am

objNetwork.setMobileDataEnabled(getBaseContext(), true);

I just dont know how (and where) to give that condition.

EDIT:

public class Network {

public void setMobileDataEnabled(Context context, boolean enabled) {

    try {
        ConnectivityManager conman = (ConnectivityManager) context
                .getSystemService(Context.CONNECTIVITY_SERVICE);

        Method setMobileDataEnabledMethod = ConnectivityManager.class
                .getDeclaredMethod("setMobileDataEnabled", boolean.class);

        setMobileDataEnabledMethod.setAccessible(true);
        setMobileDataEnabledMethod.invoke(conman, enabled);
    } catch (Exception e) {
        e.printStackTrace();
    }

}

EDIT 2 (complete code):

ConnBroadCastReceiver.java

public class ConnBroadcastReceiver extends BroadcastReceiver {

private static final String CONN_ACTION = "com.sang.mobiledata.IntentAction.RECEIVE_CONN_UPDATE";
Network objNetwork = new Network();
@Override
public void onReceive(Context context, Intent intent) {
    if(CONN_ACTION.equals(intent.getAction())) {
        boolean enableConn = intent.getBooleanExtra("FLAG_KEY", false);
        objNetwork.setMobileDataEnabled(context, enableConn);
    }
 }

}

MainActivity.java

public class MainActivity extends Activity {

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    triggerEnable(true, 6);
    triggerEnable(false, 22);
}

private void triggerEnable(boolean enableData, int hourInDay) {
    Calendar calendar = Calendar.getInstance();
    if (enableData) {
        calendar.set(Calendar.HOUR_OF_DAY, hourInDay);
    } else {
        calendar.set(Calendar.HOUR_OF_DAY, hourInDay);
    }
    calendar.set(Calendar.MINUTE, 0);
    calendar.set(Calendar.SECOND, 0);
    Intent broadcastIntent = new Intent("com.sang.mobiledata.IntentAction.RECEIVE_CONN_UPDATE");
    broadcastIntent.putExtra("FLAG_KEY", enableData);
    PendingIntent pi = PendingIntent.getBroadcast(this, 0, broadcastIntent,
            PendingIntent.FLAG_UPDATE_CURRENT);
    AlarmManager am = (AlarmManager) this.getSystemService(Context.ALARM_SERVICE);
    am.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(),
            AlarmManager.INTERVAL_DAY, pi);
}

Network.java

 public class Network {

public void setMobileDataEnabled(Context context, boolean enabled) {

    try {
        ConnectivityManager conman = (ConnectivityManager) context
                .getSystemService(Context.CONNECTIVITY_SERVICE);

        Method setMobileDataEnabledMethod = ConnectivityManager.class
                .getDeclaredMethod("setMobileDataEnabled", boolean.class);

        setMobileDataEnabledMethod.setAccessible(true);
          setMobileDataEnabledMethod.invoke(conman, enabled);
    } catch (Exception e) {
        e.printStackTrace();
     }

}

manifest.xml

 <application
    android:allowBackup="true"
    android:icon="@drawable/ic_launcher"
    android:label="@string/app_name"
    android:theme="@style/AppTheme" >
    <receiver
        android:name="com.sang.mobiledata.ConnBroadcastReceiver"
        android:exported="false" >
        <intent-filter>
            <action android:name="com.sang.mobiledata.IntentAction.RECEIVE_CONN_UPDATE" />
        </intent-filter>
    </receiver>
who-aditya-nawandar
  • 1,334
  • 9
  • 39
  • 89

2 Answers2

2

I've never tried to toggle data connection - assuming above will work if you provide proper permissions (if any is supposed to have) and above code doesn't make use of reflection as I have seen other people are shooting themselves in the foot ...

However, if you intend to open an application activity at a specific time, then I would say that's a bad practice at least from user experience point of view. Instead of doing that, you could send a broadcast message through PendingIntent.getBroadcast(...).

That being said:

  1. Construct an intent with an action of your own, add a boolean flag inside that is meaningfull (true to enable connectivity, false otherwise).
  2. Pass that intent to your PendingIntent.getBroadcast
  3. Create a BroadcastReceiver in your class, register it in the Manifest and handle properly that action. Something like:

The BroadcastReceiver class:

public class ConnBroadcastReceiver extends BroadcastReceiver {
    private static final String CONN_ACTION = "my_package_name.IntentAction.RECEIVE_CONN_UPDATE";

    @Override
    public void onReceive(Context context, Intent intent) {
        if(CONN_ACTION.equals(intent.getAction())) {
            boolean enableConn = intent.getBooleanExtra("FLAG_KEY", false);
            objNetwork.setMobileDataEnabled(context, enableConn);
        }
    }
}

register it in the Manifest:

<receiver
    android:name="my_package_name.ConnBroadcastReceiver"
    android:exported="false" >
        <intent-filter>
            <action android:name="my_package_name.IntentAction.RECEIVE_CONN_UPDATE" />
        </intent-filter>
</receiver>

and trigger the broadcast from your above code:

Intent broadcastIntent = new Intent("my_package_name.IntentAction.RECEIVE_CONN_UPDATE");
broadcastIntent.putExtra("FLAG_KEY", enableData);
PendingIntent pi = PendingIntent.getBroadcast(this, 0, broadcastIntent, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager am = (AlarmManager) this.getSystemService(Context.ALARM_SERVICE);
am.setRepeating(AlarmManager.RTC_WAKEUP, objCal.getTimeInMillis(), AlarmManager.INTERVAL_DAY, pi);

EDIT Above onCreate can be re-writen to:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    triggerEnable(true, 6);
    triggerEnable(false, 22);
}

private void triggerEnable(boolean enableData, int hourInDay) {
    Calendar calendar = Calendar.getInstance();
    if (enableData) {
        calendar.set(Calendar.HOUR_OF_DAY, hourInDay);
    } else {
        calendar.set(Calendar.HOUR_OF_DAY, hourInDay);
    }
    calendar.set(Calendar.MINUTE, 0);
    calendar.set(Calendar.SECOND, 0);
    Intent broadcastIntent = new Intent("my_package_name.IntentAction.RECEIVE_CONN_UPDATE");
    broadcastIntent.putExtra("FLAG_KEY", enableData);
    PendingIntent pi = PendingIntent.getBroadcast(this, 0, broadcastIntent,
            PendingIntent.FLAG_UPDATE_CURRENT);
    AlarmManager am = (AlarmManager) this.getSystemService(Context.ALARM_SERVICE);
    am.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(),
            AlarmManager.INTERVAL_DAY, pi);
}
gunar
  • 14,660
  • 7
  • 56
  • 87
  • while all that you said sounds perfect and awesome, I really don't know how to do that... Also, please see my edit as am not very sure if it makes use of reflection or not. – who-aditya-nawandar Nov 13 '13 at 07:04
  • Yes, that makes use of reflection. It's generally a bad idea (repeat, generally), as private API is not supposed to be called by apps for specific reasons. In this case: the app is enabling data connectivity, the user will pay from it. So your app is basically stealing money from his pocket. :) However, if you still intend to that, even I strongly disagree, I will try to expand the answer. Only because we live in the same coordinates :) – gunar Nov 13 '13 at 07:07
  • cant afford to be ethical rt nw :)... I'll go ahead with this... thanks.. waiting for ur edit... – who-aditya-nawandar Nov 13 '13 at 07:13
  • I have started android programming 2 days back. If there's anything that is to be added in this code by me, I think your efforts will be in vain... I'll still try this... – who-aditya-nawandar Nov 13 '13 at 07:21
  • 1
    and starting service is another option, just do not use activity. – handrenliang Nov 13 '13 at 07:23
  • and where am I declaring enableData? – who-aditya-nawandar Nov 13 '13 at 07:32
  • Well, you have to register the connectivity change alarm even twice: one to enable, then to disable. – gunar Nov 13 '13 at 07:52
  • and what about registering the connectivity alarm twice? – who-aditya-nawandar Nov 13 '13 at 09:29
  • Don't you want to register two events? One to enable, one to disable – gunar Nov 13 '13 at 09:31
  • btw, I am getting this - "Activity not started, its current task has been brought to the front"... – who-aditya-nawandar Nov 13 '13 at 09:39
  • ... that means the app you want to install has EXACTLY same code as the one from your device – gunar Nov 13 '13 at 09:40
  • yes, am getting this error in console and thats why I am unable to test my app: - [2013-11-13 15:36:33 - MobileData] ActivityManager: Starting: Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] cmp=com.sang.mobiledata/.MainActivity } [2013-11-13 15:36:33 - MobileData] ActivityManager: Warning: Activity not started, its current task has been brought to the front – who-aditya-nawandar Nov 13 '13 at 10:10
  • if I knew what to change, this discussion would have been over long before... :) – who-aditya-nawandar Nov 13 '13 at 10:20
  • Dude, "greu de cap" comes from the deep of the mountains :P ... from above comment (if you consider reading all comments): `that means the app you want to install has EXACTLY same code as the one from your device` ... So add two spaces anywhere in your code, save the Java file and re-install. – gunar Nov 13 '13 at 10:23
  • ya I got that after my comment :) ... ok, now how do you suggest I test it?? – who-aditya-nawandar Nov 13 '13 at 10:24
  • Start the app, start drinking until 10 PM, check then if the data connectivity is off, then if success, continue drinking until 6 AM and check then if connectivity is on. If so, I expect a beer pack too ... Or if you can't rise to this challenge, change the times above so the enabling and disabling are scheduled after 5 and 10 minutes your time. I don't want to hear you can't do it ... – gunar Nov 13 '13 at 10:35
  • I would say "Multzam fain" for an upvote :) ... I'm hunting some badges ;) – gunar Nov 13 '13 at 10:36
  • I think its working, I'll have to retest it though... Thanks for your gr8 efforts..! – who-aditya-nawandar Nov 13 '13 at 10:37
  • Unfortunately, I don't have enough reputation to upvote... tried that already... n btw, the connection din't get back on @ 6:00.. so its not completely working... :) – who-aditya-nawandar Nov 13 '13 at 10:41
  • Maybe because you're using reflection code ... I think you have enough reputation for a single upvote – gunar Nov 13 '13 at 11:00
  • requires 15 reputation points... I got 13.. will do it, dnt wry... its not cause I am using reflection code but because in the onReceive I only have code to turn it off... I need to put the code to turn it on as well... – who-aditya-nawandar Nov 13 '13 at 11:08
0

You can set two alarms, one for 10pm and another for 6am, and then when the alarms trigger, system will start services for you to do your own works.

   PendingIntent pi = PendingIntent.getService(this, 0, new Intent(
     this, YourOwnerService.class), PendingIntent.FLAG_UPDATE_CURRENT);
handrenliang
  • 1,047
  • 1
  • 10
  • 21