QR codes for profiles
This commit is contained in:
@@ -0,0 +1,47 @@
|
||||
package org.joinmastodon.android.googleservices;
|
||||
|
||||
import android.app.PendingIntent;
|
||||
|
||||
import org.microg.safeparcel.AutoSafeParcelable;
|
||||
import org.microg.safeparcel.SafeParceled;
|
||||
|
||||
public class ConnectionResult extends AutoSafeParcelable{
|
||||
public static final int UNKNOWN = -1;
|
||||
public static final int SUCCESS = 0;
|
||||
public static final int SERVICE_MISSING = 1;
|
||||
public static final int SERVICE_VERSION_UPDATE_REQUIRED = 2;
|
||||
public static final int SERVICE_DISABLED = 3;
|
||||
public static final int SIGN_IN_REQUIRED = 4;
|
||||
public static final int INVALID_ACCOUNT = 5;
|
||||
public static final int RESOLUTION_REQUIRED = 6;
|
||||
public static final int NETWORK_ERROR = 7;
|
||||
public static final int INTERNAL_ERROR = 8;
|
||||
public static final int SERVICE_INVALID = 9;
|
||||
public static final int DEVELOPER_ERROR = 10;
|
||||
public static final int LICENSE_CHECK_FAILED = 11;
|
||||
public static final int CANCELED = 13;
|
||||
public static final int TIMEOUT = 14;
|
||||
public static final int INTERRUPTED = 15;
|
||||
public static final int API_UNAVAILABLE = 16;
|
||||
public static final int SIGN_IN_FAILED = 17;
|
||||
public static final int SERVICE_UPDATING = 18;
|
||||
public static final int SERVICE_MISSING_PERMISSION = 19;
|
||||
public static final int RESTRICTED_PROFILE = 20;
|
||||
public static final int RESOLUTION_ACTIVITY_NOT_FOUND = 22;
|
||||
public static final int API_DISABLED = 23;
|
||||
public static final int API_DISABLED_FOR_CONNECTION = 24;
|
||||
@Deprecated
|
||||
public static final int DRIVE_EXTERNAL_STORAGE_REQUIRED = 1500;
|
||||
|
||||
|
||||
@SafeParceled(1)
|
||||
public int versionCode;
|
||||
@SafeParceled(2)
|
||||
public int errorCode;
|
||||
@SafeParceled(3)
|
||||
public PendingIntent resolution;
|
||||
@SafeParceled(4)
|
||||
public String errorMessage;
|
||||
|
||||
public static final Creator<ConnectionResult> CREATOR=new AutoCreator<>(ConnectionResult.class);
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
package org.joinmastodon.android.googleservices;
|
||||
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.ServiceConnection;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.os.IBinder;
|
||||
import android.os.IInterface;
|
||||
import android.os.RemoteException;
|
||||
import android.util.Log;
|
||||
import android.util.SparseArray;
|
||||
|
||||
import com.google.android.gms.common.internal.ConnectionInfo;
|
||||
import com.google.android.gms.common.internal.GetServiceRequest;
|
||||
import com.google.android.gms.common.internal.IGmsCallbacks;
|
||||
import com.google.android.gms.common.internal.IGmsServiceBroker;
|
||||
import com.google.android.gms.common.moduleinstall.internal.IModuleInstallService;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
public class GmsClient{
|
||||
private static final String TAG="GmsClient";
|
||||
private static final SparseArray<ServiceConnection> currentConnections=new SparseArray<>();
|
||||
private static int nextConnectionID=0;
|
||||
|
||||
public static <I extends IInterface> void connectToService(Context context, String action, int id, boolean useDynamicLookup, ServiceConnectionCallback<I> callback, Function<IBinder, I> asInterface){
|
||||
Intent intent;
|
||||
if(useDynamicLookup){
|
||||
try{
|
||||
Bundle args=new Bundle();
|
||||
args.putString("serviceActionBundleKey", action);
|
||||
Bundle result=context.getContentResolver().call(new Uri.Builder().scheme("content").authority("com.google.android.gms.chimera").build(), "serviceIntentCall", null, args);
|
||||
if(result==null)
|
||||
throw new IllegalStateException("Dynamic lookup failed");
|
||||
intent=result.getParcelable("serviceResponseIntentKey");
|
||||
if(intent==null)
|
||||
throw new IllegalStateException("Dynamic lookup returned null");
|
||||
}catch(Exception x){
|
||||
callback.onError(x);
|
||||
return;
|
||||
}
|
||||
}else{
|
||||
intent=new Intent(action);
|
||||
}
|
||||
intent.setPackage("com.google.android.gms");
|
||||
ServiceConnection conn=new ServiceConnection(){
|
||||
@Override
|
||||
public void onServiceConnected(ComponentName name, IBinder service){
|
||||
IGmsServiceBroker broker=IGmsServiceBroker.Stub.asInterface(service);
|
||||
GetServiceRequest req=new GetServiceRequest();
|
||||
req.serviceId=id;
|
||||
req.packageName=context.getPackageName();
|
||||
ServiceConnection serviceConnectionThis=this;
|
||||
try{
|
||||
broker.getService(new IGmsCallbacks.Stub(){
|
||||
@Override
|
||||
public void onPostInitComplete(int statusCode, IBinder binder, Bundle params) throws RemoteException{
|
||||
int connectionID=nextConnectionID++;
|
||||
currentConnections.put(connectionID, serviceConnectionThis);
|
||||
callback.onSuccess(asInterface.apply(binder), connectionID);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAccountValidationComplete(int statusCode, Bundle params) throws RemoteException{}
|
||||
|
||||
@Override
|
||||
public void onPostInitCompleteWithConnectionInfo(int statusCode, IBinder binder, ConnectionInfo info) throws RemoteException{
|
||||
onPostInitComplete(statusCode, binder, info!=null ? info.params : null);
|
||||
}
|
||||
}, req);
|
||||
}catch(Exception x){
|
||||
callback.onError(x);
|
||||
context.unbindService(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServiceDisconnected(ComponentName name){}
|
||||
};
|
||||
boolean res=context.bindService(intent, conn, Context.BIND_AUTO_CREATE | Context.BIND_DEBUG_UNBIND | Context.BIND_ADJUST_WITH_ACTIVITY);
|
||||
if(!res){
|
||||
context.unbindService(conn);
|
||||
callback.onError(new IllegalStateException("Service connection failed"));
|
||||
}
|
||||
}
|
||||
|
||||
public static void disconnectFromService(Context context, int connectionID){
|
||||
ServiceConnection conn=currentConnections.get(connectionID);
|
||||
if(conn!=null){
|
||||
currentConnections.remove(connectionID);
|
||||
context.unbindService(conn);
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isGooglePlayServicesAvailable(Context context){
|
||||
PackageManager pm=context.getPackageManager();
|
||||
try{
|
||||
pm.getPackageInfo("com.google.android.gms", 0);
|
||||
return true;
|
||||
}catch(PackageManager.NameNotFoundException e){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static void getModuleInstallerService(Context context, ServiceConnectionCallback<IModuleInstallService> callback){
|
||||
connectToService(context, "com.google.android.gms.chimera.container.moduleinstall.ModuleInstallService.START", 308, true, callback, IModuleInstallService.Stub::asInterface);
|
||||
}
|
||||
|
||||
public interface ServiceConnectionCallback<I extends IInterface>{
|
||||
void onSuccess(I service, int connectionID);
|
||||
void onError(Exception error);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,253 @@
|
||||
package org.joinmastodon.android.googleservices.barcodescanner;
|
||||
|
||||
import android.graphics.Point;
|
||||
|
||||
import org.microg.safeparcel.AutoSafeParcelable;
|
||||
import org.microg.safeparcel.SafeParceled;
|
||||
|
||||
public class Barcode extends AutoSafeParcelable{
|
||||
public static final int FORMAT_UNKNOWN = -1;
|
||||
public static final int FORMAT_ALL_FORMATS = 0;
|
||||
public static final int FORMAT_CODE_128 = 1;
|
||||
public static final int FORMAT_CODE_39 = 2;
|
||||
public static final int FORMAT_CODE_93 = 4;
|
||||
public static final int FORMAT_CODABAR = 8;
|
||||
public static final int FORMAT_DATA_MATRIX = 16;
|
||||
public static final int FORMAT_EAN_13 = 32;
|
||||
public static final int FORMAT_EAN_8 = 64;
|
||||
public static final int FORMAT_ITF = 128;
|
||||
public static final int FORMAT_QR_CODE = 256;
|
||||
public static final int FORMAT_UPC_A = 512;
|
||||
public static final int FORMAT_UPC_E = 1024;
|
||||
public static final int FORMAT_PDF417 = 2048;
|
||||
public static final int FORMAT_AZTEC = 4096;
|
||||
public static final int TYPE_UNKNOWN = 0;
|
||||
public static final int TYPE_CONTACT_INFO = 1;
|
||||
public static final int TYPE_EMAIL = 2;
|
||||
public static final int TYPE_ISBN = 3;
|
||||
public static final int TYPE_PHONE = 4;
|
||||
public static final int TYPE_PRODUCT = 5;
|
||||
public static final int TYPE_SMS = 6;
|
||||
public static final int TYPE_TEXT = 7;
|
||||
public static final int TYPE_URL = 8;
|
||||
public static final int TYPE_WIFI = 9;
|
||||
public static final int TYPE_GEO = 10;
|
||||
public static final int TYPE_CALENDAR_EVENT = 11;
|
||||
public static final int TYPE_DRIVER_LICENSE = 12;
|
||||
|
||||
@SafeParceled(1)
|
||||
public int format;
|
||||
@SafeParceled(2)
|
||||
public String displayValue;
|
||||
@SafeParceled(3)
|
||||
public String rawValue;
|
||||
@SafeParceled(4)
|
||||
public byte[] rawBytes;
|
||||
@SafeParceled(5)
|
||||
public Point[] cornerPoints;
|
||||
@SafeParceled(6)
|
||||
public int valueType;
|
||||
@SafeParceled(7)
|
||||
public Email emailValue;
|
||||
@SafeParceled(8)
|
||||
public Phone phoneValue;
|
||||
@SafeParceled(9)
|
||||
public SMS smsValue;
|
||||
@SafeParceled(10)
|
||||
public WiFi wifiValue;
|
||||
@SafeParceled(11)
|
||||
public UrlBookmark urlBookmarkValue;
|
||||
@SafeParceled(12)
|
||||
public GeoPoint geoPointValue;
|
||||
@SafeParceled(13)
|
||||
public CalendarEvent calendarEventValue;
|
||||
@SafeParceled(14)
|
||||
public ContactInfo contactInfoValue;
|
||||
@SafeParceled(15)
|
||||
public DriverLicense driverLicenseValue;
|
||||
|
||||
public static final Creator<Barcode> CREATOR=new AutoCreator<>(Barcode.class);
|
||||
|
||||
// None of the following is needed or used in the Mastodon app and its use cases for QR code scanning,
|
||||
// but I'm putting it out there in case someone else is crazy enough to want to use Google Services without their libraries
|
||||
|
||||
public static class Email extends AutoSafeParcelable{
|
||||
@SafeParceled(1)
|
||||
public int type;
|
||||
@SafeParceled(2)
|
||||
public String address;
|
||||
@SafeParceled(3)
|
||||
public String subject;
|
||||
@SafeParceled(4)
|
||||
public String body;
|
||||
|
||||
public static final Creator<Email> CREATOR=new AutoCreator<>(Email.class);
|
||||
}
|
||||
|
||||
public static class Phone extends AutoSafeParcelable{
|
||||
@SafeParceled(1)
|
||||
public int type;
|
||||
@SafeParceled(2)
|
||||
public String number;
|
||||
|
||||
public static final Creator<Phone> CREATOR=new AutoCreator<>(Phone.class);
|
||||
}
|
||||
|
||||
public static class SMS extends AutoSafeParcelable{
|
||||
@SafeParceled(1)
|
||||
public String message;
|
||||
@SafeParceled(2)
|
||||
public String phoneNumber;
|
||||
|
||||
public static final Creator<SMS> CREATOR=new AutoCreator<>(SMS.class);
|
||||
}
|
||||
|
||||
public static class WiFi extends AutoSafeParcelable{
|
||||
@SafeParceled(1)
|
||||
public String ssid;
|
||||
@SafeParceled(2)
|
||||
public String password;
|
||||
@SafeParceled(3)
|
||||
public int encryptionType;
|
||||
|
||||
public static final Creator<WiFi> CREATOR=new AutoCreator<>(WiFi.class);
|
||||
}
|
||||
|
||||
public static class UrlBookmark extends AutoSafeParcelable{
|
||||
@SafeParceled(1)
|
||||
public String title;
|
||||
@SafeParceled(2)
|
||||
public String url;
|
||||
|
||||
public static final Creator<UrlBookmark> CREATOR=new AutoCreator<>(UrlBookmark.class);
|
||||
}
|
||||
|
||||
public static class GeoPoint extends AutoSafeParcelable{
|
||||
@SafeParceled(1)
|
||||
public double lat;
|
||||
@SafeParceled(2)
|
||||
public double lng;
|
||||
|
||||
public static final Creator<GeoPoint> CREATOR=new AutoCreator<>(GeoPoint.class);
|
||||
}
|
||||
|
||||
public static class EventDateTime extends AutoSafeParcelable{
|
||||
@SafeParceled(1)
|
||||
public int year;
|
||||
@SafeParceled(2)
|
||||
public int month;
|
||||
@SafeParceled(3)
|
||||
public int day;
|
||||
@SafeParceled(4)
|
||||
public int hours;
|
||||
@SafeParceled(5)
|
||||
public int minutes;
|
||||
@SafeParceled(6)
|
||||
public int seconds;
|
||||
@SafeParceled(7)
|
||||
public boolean isUtc;
|
||||
@SafeParceled(8)
|
||||
public String rawValue;
|
||||
|
||||
public static final Creator<EventDateTime> CREATOR=new AutoCreator<>(EventDateTime.class);
|
||||
}
|
||||
|
||||
public static class CalendarEvent extends AutoSafeParcelable{
|
||||
@SafeParceled(1)
|
||||
public String summary;
|
||||
@SafeParceled(2)
|
||||
public String description;
|
||||
@SafeParceled(3)
|
||||
public String location;
|
||||
@SafeParceled(4)
|
||||
public String organizer;
|
||||
@SafeParceled(5)
|
||||
public String status;
|
||||
@SafeParceled(6)
|
||||
public EventDateTime start;
|
||||
@SafeParceled(7)
|
||||
public EventDateTime end;
|
||||
|
||||
public static final Creator<CalendarEvent> CREATOR=new AutoCreator<>(CalendarEvent.class);
|
||||
}
|
||||
|
||||
public static class Address extends AutoSafeParcelable{
|
||||
@SafeParceled(1)
|
||||
public int type;
|
||||
@SafeParceled(2)
|
||||
public String[] addressLines;
|
||||
|
||||
public static final Creator<Address> CREATOR=new AutoCreator<>(Address.class);
|
||||
}
|
||||
|
||||
public static class PersonName extends AutoSafeParcelable{
|
||||
@SafeParceled(1)
|
||||
public String formattedName;
|
||||
@SafeParceled(2)
|
||||
public String pronunciation;
|
||||
@SafeParceled(3)
|
||||
public String prefix;
|
||||
@SafeParceled(4)
|
||||
public String first;
|
||||
@SafeParceled(5)
|
||||
public String middle;
|
||||
@SafeParceled(6)
|
||||
public String last;
|
||||
@SafeParceled(7)
|
||||
public String suffix;
|
||||
|
||||
public static final Creator<PersonName> CREATOR=new AutoCreator<>(PersonName.class);
|
||||
}
|
||||
|
||||
public static class ContactInfo extends AutoSafeParcelable{
|
||||
@SafeParceled(1)
|
||||
public PersonName name;
|
||||
@SafeParceled(2)
|
||||
public String organization;
|
||||
@SafeParceled(3)
|
||||
public String title;
|
||||
@SafeParceled(4)
|
||||
public Phone[] phones;
|
||||
@SafeParceled(5)
|
||||
public Email[] emails;
|
||||
@SafeParceled(6)
|
||||
public String[] urls;
|
||||
@SafeParceled(7)
|
||||
public Address[] addresses;
|
||||
|
||||
public static final Creator<ContactInfo> CREATOR=new AutoCreator<>(ContactInfo.class);
|
||||
}
|
||||
|
||||
public static class DriverLicense extends AutoSafeParcelable{
|
||||
@SafeParceled(1)
|
||||
public String documentType;
|
||||
@SafeParceled(2)
|
||||
public String firstName;
|
||||
@SafeParceled(3)
|
||||
public String middleName;
|
||||
@SafeParceled(4)
|
||||
public String lastName;
|
||||
@SafeParceled(5)
|
||||
public String gender;
|
||||
@SafeParceled(6)
|
||||
public String addressStreet;
|
||||
@SafeParceled(7)
|
||||
public String addressCity;
|
||||
@SafeParceled(8)
|
||||
public String addressState;
|
||||
@SafeParceled(9)
|
||||
public String addressZip;
|
||||
@SafeParceled(10)
|
||||
public String licenseNumber;
|
||||
@SafeParceled(11)
|
||||
public String issueDate;
|
||||
@SafeParceled(12)
|
||||
public String expiryDate;
|
||||
@SafeParceled(13)
|
||||
public String birthDate;
|
||||
@SafeParceled(14)
|
||||
public String issuingCountry;
|
||||
|
||||
public static final Creator<DriverLicense> CREATOR=new AutoCreator<>(DriverLicense.class);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package org.joinmastodon.android.googleservices.barcodescanner;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.os.Parcel;
|
||||
|
||||
import org.joinmastodon.android.MastodonApp;
|
||||
|
||||
public class BarcodeScanner{
|
||||
public static Intent createIntent(int formats, boolean allowManualInout, boolean enableAutoZoom){
|
||||
Intent intent=new Intent().setPackage("com.google.android.gms").setAction("com.google.android.gms.mlkit.ACTION_SCAN_BARCODE");
|
||||
String appName;
|
||||
ApplicationInfo appInfo=MastodonApp.context.getApplicationInfo();
|
||||
if(appInfo.labelRes!=0)
|
||||
appName=MastodonApp.context.getString(appInfo.labelRes);
|
||||
else
|
||||
appName=MastodonApp.context.getPackageManager().getApplicationLabel(appInfo).toString();
|
||||
intent.putExtra("extra_calling_app_name", appName);
|
||||
intent.putExtra("extra_supported_formats", formats);
|
||||
intent.putExtra("extra_allow_manual_input", allowManualInout);
|
||||
intent.putExtra("extra_enable_auto_zoom", enableAutoZoom);
|
||||
return intent;
|
||||
}
|
||||
|
||||
public static boolean isValidResult(Intent intent){
|
||||
return intent!=null && intent.hasExtra("extra_barcode_result");
|
||||
}
|
||||
|
||||
public static Barcode getResult(Intent intent){
|
||||
byte[] serialized=intent.getByteArrayExtra("extra_barcode_result");
|
||||
Parcel parcel=Parcel.obtain();
|
||||
parcel.unmarshall(serialized, 0, serialized.length);
|
||||
parcel.setDataPosition(0);
|
||||
Barcode barcode=Barcode.CREATOR.createFromParcel(parcel);
|
||||
parcel.recycle();
|
||||
return barcode;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user