Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2c68c023 authored by Fynn Godau's avatar Fynn Godau
Browse files

Notify is user not signed in to any Google account

parent 003052a7
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -10,6 +10,7 @@
        android:protectionLevel="normal" />

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>

    <uses-permission
        android:name="android.permission.GET_ACCOUNTS"
@@ -64,5 +65,11 @@
                <category android:name="android.intent.category.INFO" />
            </intent-filter>
        </activity>

        <receiver android:name="com.android.vending.licensing.LicenseServiceNotificationRunnable$IgnoreReceiver"
            android:exported="false" />
        <receiver android:name="com.android.vending.licensing.LicenseServiceNotificationRunnable$SignInReceiver"
            android:exported="false" />

    </application>
</manifest>
+157 −0
Original line number Diff line number Diff line
package com.android.vending.licensing;

import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Build;
import android.util.Log;

import androidx.annotation.CallSuper;
import androidx.core.app.NotificationCompat;
import androidx.core.app.NotificationManagerCompat;

import com.android.vending.R;

import java.util.Collections;
import java.util.Set;
import java.util.TreeSet;

public class LicenseServiceNotificationRunnable implements Runnable {

    private final Context context;

    public String callerPackageName;
    public CharSequence callerAppName;
    public int callerUid;

    private static final String TAG = "FakeLicenseNotification";
    private static final String GMS_PACKAGE_NAME = "com.google.android.gms";
    private static final String GMS_AUTH_INTENT_ACTION = "com.google.android.gms.auth.login.LOGIN";

    private static final String PREFERENCES_KEY_IGNORE_PACKAGES_LIST = "ignorePackages";
    private static final String PREFERENCES_FILE_NAME = "licensing";

    private static final String INTENT_KEY_IGNORE_PACKAGE_NAME = "package";
    private static final String INTENT_KEY_NOTIFICATION_ID = "id";


    public LicenseServiceNotificationRunnable(Context context) {
        this.context = context;
    }

    private static final String CHANNEL_ID = "LicenseNotification";

    @Override
    public void run() {
        registerNotificationChannel();

        SharedPreferences preferences = context.getSharedPreferences(PREFERENCES_FILE_NAME, Context.MODE_PRIVATE);

        Set<String> ignoreList = preferences.getStringSet(PREFERENCES_KEY_IGNORE_PACKAGES_LIST, Collections.emptySet());
        for (String ignoredPackage : ignoreList) {
            if (callerPackageName.equals(ignoredPackage)) {
                Log.d(TAG, "Not notifying about license check, as user has ignored notifications for package " + ignoredPackage);
                return;
            }
        }

        Intent authIntent = new Intent(context, LicenseServiceNotificationRunnable.SignInReceiver.class);
        authIntent.putExtra(INTENT_KEY_NOTIFICATION_ID, callerUid);
        PendingIntent authPendingIntent = PendingIntent.getBroadcast(
            context, callerUid * 2, authIntent, PendingIntent.FLAG_IMMUTABLE
        );

        Intent ignoreIntent = new Intent(context, LicenseServiceNotificationRunnable.IgnoreReceiver.class);
        ignoreIntent.putExtra(INTENT_KEY_IGNORE_PACKAGE_NAME, callerPackageName);
        ignoreIntent.putExtra(INTENT_KEY_NOTIFICATION_ID, callerUid);
        PendingIntent ignorePendingIntent = PendingIntent.getBroadcast(
            context, callerUid * 2 + 1, ignoreIntent, PendingIntent.FLAG_IMMUTABLE
        );

        Notification notification = new NotificationCompat.Builder(context, CHANNEL_ID)
            .setSmallIcon(R.drawable.ic_app_foreground)
            .setContentTitle(context.getString(R.string.license_notification_title, callerAppName))
            .setContentText(context.getString(R.string.license_notification_body))
            .addAction(
                new NotificationCompat.Action.Builder(
                    null, context.getString(R.string.license_notification_sign_in), authPendingIntent
                ).build()
            )
            .addAction(
                new NotificationCompat.Action.Builder(
                    null, context.getString(R.string.license_notification_ignore), ignorePendingIntent
                ).build()
            )
            .setAutoCancel(true)
            .build();

        NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context);
        notificationManager.notify(callerUid, notification);

    }

    private void registerNotificationChannel() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationChannel channel = new NotificationChannel(
                CHANNEL_ID,
                context.getString(R.string.license_notification_channel_name),
                NotificationManager.IMPORTANCE_HIGH
            );
            channel.setDescription(context.getString(R.string.license_notification_channel_description));

            NotificationManager notificationManager = context.getSystemService(NotificationManager.class);
            notificationManager.createNotificationChannel(channel);
        }

    }

    private static class Receiver extends BroadcastReceiver {

        @Override
        @CallSuper
        public void onReceive(Context context, Intent intent) {
            // Dismiss notification
            NotificationManagerCompat.from(context)
                .cancel(intent.getIntExtra(INTENT_KEY_NOTIFICATION_ID, -1));
        }
    }

    public static final class IgnoreReceiver extends Receiver {

        @Override
        public void onReceive(Context context, Intent intent) {
            super.onReceive(context, intent);

            SharedPreferences preferences = context.getSharedPreferences(PREFERENCES_FILE_NAME, Context.MODE_PRIVATE);

            Set<String> ignoreList = new TreeSet<>(
                preferences.getStringSet(PREFERENCES_KEY_IGNORE_PACKAGES_LIST, Collections.emptySet())
            );

            String newIgnorePackage = intent.getStringExtra(INTENT_KEY_IGNORE_PACKAGE_NAME);
            Log.d(TAG, "Adding package " + newIgnorePackage + " to ignore list");

            ignoreList.add(newIgnorePackage);
            preferences.edit().putStringSet(PREFERENCES_KEY_IGNORE_PACKAGES_LIST, ignoreList).apply();
        }
    }

    public static final class SignInReceiver extends Receiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            super.onReceive(context, intent);

            Log.d(TAG, "Starting sign in activity");
            Intent authIntent = new Intent(GMS_AUTH_INTENT_ACTION);
            authIntent.setPackage(GMS_PACKAGE_NAME);
            authIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            context.startActivity(authIntent);
        }
    }

}
+14 −2
Original line number Diff line number Diff line
@@ -33,6 +33,7 @@ public class LicensingService extends Service {
    private static final String TAG = "FakeLicenseService";
    private RequestQueue queue;
    private AccountManager accountManager;
    private LicenseServiceNotificationRunnable notificationRunnable;

    private static final String KEY_V2_RESULT_JWT = "LICENSE_DATA";

@@ -89,7 +90,8 @@ public class LicensingService extends Service {
        public void checkLicense(long nonce, String packageName, ILicenseResultListener listener) throws RemoteException {
            Log.v(TAG, "checkLicense(" + nonce + ", " + packageName + ")");
            try {
                PackageInfo packageInfo = getPackageManager().getPackageInfo(packageName, 0);
                PackageManager packageManager = getPackageManager();
                PackageInfo packageInfo = packageManager.getPackageInfo(packageName, 0);
                int versionCode = packageInfo.versionCode;

                // Verify caller identity
@@ -102,6 +104,10 @@ public class LicensingService extends Service {

                    if (accounts.length == 0) {
                        Log.e(TAG, "not checking license, as user is not signed in");
                        notificationRunnable.callerPackageName = packageName;
                        notificationRunnable.callerUid = packageInfo.applicationInfo.uid;
                        notificationRunnable.callerAppName = packageManager.getApplicationLabel(packageInfo.applicationInfo);
                        notificationRunnable.run();
                    } else accountManager.getAuthToken(
                        accounts[0], AUTH_TOKEN_SCOPE, false,
                        future -> {
@@ -153,7 +159,8 @@ public class LicensingService extends Service {
            Log.v(TAG, "checkLicenseV2(" + packageName + ", " + extraParams + ")");

            try {
                PackageInfo packageInfo = getPackageManager().getPackageInfo(packageName, 0);
                PackageManager packageManager = getPackageManager();
                PackageInfo packageInfo = packageManager.getPackageInfo(packageName, 0);
                int versionCode = packageInfo.versionCode;

                // Verify caller identity
@@ -165,6 +172,10 @@ public class LicensingService extends Service {

                    if (accounts.length == 0) {
                        Log.e(TAG, "not checking license, as user is not signed in");
                        notificationRunnable.callerPackageName = packageName;
                        notificationRunnable.callerUid = packageInfo.applicationInfo.uid;
                        notificationRunnable.callerAppName = packageManager.getApplicationLabel(packageInfo.applicationInfo);
                        notificationRunnable.run();
                    } else accountManager.getAuthToken(
                        accounts[0], AUTH_TOKEN_SCOPE, false,
                        future -> {
@@ -224,6 +235,7 @@ public class LicensingService extends Service {
    public IBinder onBind(Intent intent) {
        queue = Volley.newRequestQueue(this);
        accountManager = AccountManager.get(this);
        notificationRunnable = new LicenseServiceNotificationRunnable(this);

        return mLicenseService;
    }
+8 −0
Original line number Diff line number Diff line
@@ -8,4 +8,12 @@
    <string name="app_name">microG Companion</string>
    <string name="toast_installed">microG Companion cannot be used standalone. Opened microG Services settings instead.</string>
    <string name="toast_not_installed">microG Companion cannot be used standalone. Please install microG Services to use microG.</string>

    <string name="license_notification_channel_name">License notifications</string>
    <string name="license_notification_channel_description">Notifies when an app tries to validate its license, but you are not signed in to any Google account.</string>
    <string name="license_notification_title">%1$s could not verify license</string>
    <string name="license_notification_body">If the app is misbehaving, sign in to a Google account with which you have bought the app.</string>

    <string name="license_notification_sign_in">Sign In</string>
    <string name="license_notification_ignore">Ignore</string>
</resources>
 No newline at end of file