Launch VPNService from android widget

I am starting a VPNService in my activity, and I want to start some kind of thread after starting the service. this is how i start the service:

Intent intent = VpnService.prepare(getActivity());
if (intent != null) {
    startActivityForResult(intent, 123);
else {
    onActivityResult(123, Activity.RESULT_OK, null);
}

And in onActivityResult I start my thread

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (requestCode == 123) {
        // Start some thread
    }
}

Now I want to be able to do all this from the widget of my application. It seems that I can only use startActivity inside the widget, and this is the correct way to use VPNService. is there any way to achieve this from my widget? some kind of callback from startActivity, maybe?

+4
source share
2 answers

Not too much experience with widgets, but suggest going like this:

  • startActivityForResult() ( , @android:style/Theme.NoDisplay);
  • ;
  • SharedPreferences ;

:

AndroidManifest.xml:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="com.alexstarc.testapp"
          android:versionCode="1"
          android:versionName="1.0">

    <uses-sdk android:minSdkVersion="19"
        android:targetSdkVersion="19"/>

    <application
        android:label="@string/app_name"
        android:icon="@drawable/ic_launcher"
        android:allowBackup="true">
        <activity
            android:name=".MyActivity"
            android:label="@string/app_name"
            android:theme="@android:style/Theme.NoDisplay">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>
                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>

        <receiver android:name="TestWidgetProvider"
                  android:exported="false">
            <intent-filter>
                <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />

                <!-- Custom actions -->
                <action android:name="com.alexstarc.testapp.ACTION_BTN" />
                <action android:name="com.alexstarc.testapp.ACTION_VPN_RESULT" />
            </intent-filter>
            <meta-data android:name="android.appwidget.provider"
                       android:resource="@xml/appwidget_info" />
        </receiver>
    </application>
</manifest>

appwidget_info.xml:

<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
    android:minWidth="180dp"
    android:minHeight="40dp"
    android:updatePeriodMillis="0"
    android:initialLayout="@layout/appwidget"
    android:resizeMode="horizontal|vertical"
    android:widgetCategory="home_screen"
    android:previewImage="@drawable/widget_preview"/>

appwidget.xml:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="4dp"
    android:background="@drawable/appwidget_bg">

    <ImageButton
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/launchVPN"
        android:src="@android:drawable/ic_media_play"/>

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/resultText"
        style="@android:style/TextAppearance.DeviceDefault.Medium.Inverse"
        android:layout_toRightOf="@id/launchVPN"
        android:text="@string/test_text"
        android:gravity="bottom"/>
</RelativeLayout>

MyActivity.java:

public class MyActivity extends Activity {

    private static final int VPN_LAUNCH_CODE = 123;

    public static String SHARED_PREFS_NAME = "shared_prefs";
    public static String RESULT_VPN = "vpn_launch_result";
    public static String ACTION_VPN_RESULT = "com.alexstarc.testapp.ACTION_VPN_RESULT";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        Intent intent = VpnService.prepare(MyActivity.this);
        if (intent != null) {
            startActivityForResult(intent, VPN_LAUNCH_CODE);
        } else {
            onActivityResult(VPN_LAUNCH_CODE, Activity.RESULT_OK, null);
        }
    }

    @Override
    protected void onActivityResult(final int requestCode, final int resultCode, final Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        if (requestCode == 123) {
            getSharedPreferences(SHARED_PREFS_NAME, MODE_MULTI_PROCESS).edit().putString(RESULT_VPN, "VPN Result is " + resultCode).commit();

            final Intent resultIntent = new Intent(ACTION_VPN_RESULT);

            sendBroadcast(resultIntent);
            finish();
        }
    }
}

TestWidgetProvider.java:

public final class TestWidgetProvider extends AppWidgetProvider {

    private static final String ACTION_START_BTN = "com.alexstarc.testapp.ACTION_BTN";

    // TODO: Use Shared Prefs for this
    private static int sWidgetId = 0;
    private static boolean sVPNDone = false;

    @Override
    public void onUpdate(final Context context, final AppWidgetManager appWidgetManager, final int[] appWidgetIds) {
        for (int widgetId : appWidgetIds) {
            updateWidget(context, appWidgetManager, widgetId);
        }

        sWidgetId = appWidgetIds[0];
    }

    /**
     * Updates single App Widget
     *
     * @param context {@link android.content.Context}
     * @param appWidgetManager {@link android.appwidget.AppWidgetManager}
     * @param widgetId of current widget
     */
    private static void updateWidget(final Context context, final AppWidgetManager appWidgetManager, final int widgetId) {
        final ArrayList<Integer> widgets = new ArrayList<Integer>();

        final Intent btnClickIntent = new Intent(context, TestWidgetProvider.class);

        btnClickIntent.setAction(ACTION_START_BTN);

        final PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, btnClickIntent, 0);

        // Get the layout for the App Widget and attach an on-click listener
        // to the button
        RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.appwidget);

        views.setOnClickPendingIntent(R.id.launchVPN, pendingIntent);

        // Update from shared preferences after activity  was launched
        if (sVPNDone) {
            views.setTextViewText(R.id.resultText,
                    context.getSharedPreferences(MyActivity.SHARED_PREFS_NAME, Context.MODE_PRIVATE).getString(MyActivity.RESULT_VPN, "No result"));
        }

        appWidgetManager.updateAppWidget(widgetId, views);
    }

    @Override
    public void onReceive(final Context context, final Intent intent) {
        final String action = intent.getAction();

        if (ACTION_START_BTN.equals(action)) {
            // Start listening service
            final Intent vpnActivityIntent = new Intent(context, MyActivity.class);

            vpnActivityIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            context.startActivity(vpnActivityIntent);
        } else if (MyActivity.ACTION_VPN_RESULT.equals(action)) {
            sVPNDone = true;
            updateWidget(context, AppWidgetManager.getInstance(context), sWidgetId);
        } else {
            super.onReceive(context, intent);
        }
    }
}
+1

. , , , , .

AndroidManifest.xml:

<!-- Specify a new kind of permission based on your signature -->
<permission
    android:name="com.example.VPN"
    android:protectionLevel="signature" />

<!-- This application uses this new permission -->
<uses-permission android:name="com.example.VPN" />

<!-- Let the VPN service use the permission and listen for an implicit intent -->
<service
    android:name="com.example.VpnService"
    android:exported="true"
    android:permission="com.example.VPN" >
    <intent-filter>
        <action android:name="com.example.intent.action.START_VPN" />

        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</service>

VpnService:

public static final String ACTION_START_VPN = "com.example.intent.action.START_VPN";

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    super.onStartCommand(intent, flags, startId);

    if (null != intent && ACTION_START_VPN.equals(intent.getAction()) {

        // Do your stuff here

    }
}

:

    Intent intent = new Intent(VpnService.ACTION_START_VPN);
    context.startService(intent);
0

Source: https://habr.com/ru/post/1539620/


All Articles