diff --git a/mastodon/src/main/java/org/joinmastodon/android/fragments/ProfileQrCodeFragment.java b/mastodon/src/main/java/org/joinmastodon/android/fragments/ProfileQrCodeFragment.java index 4110ce32..3324bbd6 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/fragments/ProfileQrCodeFragment.java +++ b/mastodon/src/main/java/org/joinmastodon/android/fragments/ProfileQrCodeFragment.java @@ -282,77 +282,7 @@ public class ProfileQrCodeFragment extends AppKitFragment{ if(scannerIntent.resolveActivity(getActivity().getPackageManager())!=null){ startActivityForResult(scannerIntent, SCAN_RESULT); }else{ - ProgressDialog progress=new ProgressDialog(getActivity()); - progress.setMessage(getString(R.string.loading)); - progress.setCancelable(false); - progress.show(); - GmsClient.getModuleInstallerService(getActivity(), new GmsClient.ServiceConnectionCallback<>(){ - @Override - public void onSuccess(IModuleInstallService service, int connectionID){ - ApiFeatureRequest req=new ApiFeatureRequest(); - req.callingPackage=getActivity().getPackageName(); - Feature feature=new Feature(); - feature.name="mlkit.barcode.ui"; - feature.version=1; - feature.oldVersion=-1; - req.features=List.of(feature); - req.urgent=true; - try{ - service.installModules(new IModuleInstallCallbacks.Stub(){ - @Override - public void onModuleAvailabilityResponse(Status status, ModuleAvailabilityResponse response) throws RemoteException{} - - @Override - public void onModuleInstallResponse(Status status, ModuleInstallResponse response) throws RemoteException{} - - @Override - public void onModuleInstallIntentResponse(Status status, ModuleInstallIntentResponse response) throws RemoteException{} - - @Override - public void onStatus(Status status) throws RemoteException{} - }, req, new IModuleInstallStatusListener.Stub(){ - @Override - public void onModuleInstallStatusUpdate(ModuleInstallStatusUpdate statusUpdate) throws RemoteException{ - if(statusUpdate.installState==ModuleInstallStatusUpdate.STATE_COMPLETED){ - Runnable r=new Runnable(){ - @Override - public void run(){ - if(scannerIntent.resolveActivity(getActivity().getPackageManager())!=null){ - progress.dismiss(); - startActivityForResult(scannerIntent, SCAN_RESULT); - }else{ - codeContainer.postDelayed(this, 100); - } - } - }; - getActivity().runOnUiThread(r); - GmsClient.disconnectFromService(getActivity(), connectionID); - }else if(statusUpdate.installState==ModuleInstallStatusUpdate.STATE_FAILED || statusUpdate.installState==ModuleInstallStatusUpdate.STATE_CANCELED){ - getActivity().runOnUiThread(()->{ - progress.dismiss(); - Toast.makeText(themeWrapper, R.string.error, Toast.LENGTH_SHORT).show(); - }); - GmsClient.disconnectFromService(getActivity(), connectionID); - } - } - }); - }catch(RemoteException e){ - Log.e(TAG, "onSuccess: ", e); - getActivity().runOnUiThread(()->{ - progress.dismiss(); - Toast.makeText(themeWrapper, R.string.error, Toast.LENGTH_SHORT).show(); - }); - GmsClient.disconnectFromService(getActivity(), connectionID); - } - } - - @Override - public void onError(Exception error){ - Log.e(TAG, "onError() called with: error = ["+error+"]"); - Toast.makeText(themeWrapper, R.string.error, Toast.LENGTH_SHORT).show(); - progress.dismiss(); - } - }); + BarcodeScanner.installScannerModule(themeWrapper, ()->startActivityForResult(scannerIntent, SCAN_RESULT)); } return true; } diff --git a/mastodon/src/main/java/org/joinmastodon/android/fragments/discover/DiscoverFragment.java b/mastodon/src/main/java/org/joinmastodon/android/fragments/discover/DiscoverFragment.java index ca9d05b0..cb53a04e 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/fragments/discover/DiscoverFragment.java +++ b/mastodon/src/main/java/org/joinmastodon/android/fragments/discover/DiscoverFragment.java @@ -1,6 +1,9 @@ package org.joinmastodon.android.fragments.discover; +import android.app.Activity; import android.app.Fragment; +import android.content.Intent; +import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.text.TextUtils; @@ -11,9 +14,14 @@ import android.widget.FrameLayout; import android.widget.ImageButton; import android.widget.LinearLayout; import android.widget.TextView; +import android.widget.Toast; +import org.joinmastodon.android.MainActivity; import org.joinmastodon.android.R; import org.joinmastodon.android.fragments.ScrollableToTop; +import org.joinmastodon.android.googleservices.GmsClient; +import org.joinmastodon.android.googleservices.barcodescanner.Barcode; +import org.joinmastodon.android.googleservices.barcodescanner.BarcodeScanner; import org.joinmastodon.android.model.SearchResult; import org.joinmastodon.android.ui.OutlineProviders; import org.joinmastodon.android.ui.SimpleViewHolder; @@ -33,6 +41,7 @@ import me.grishka.appkit.utils.V; public class DiscoverFragment extends AppKitFragment implements ScrollableToTop, OnBackPressedListener{ private static final int QUERY_RESULT=937; + private static final int SCAN_RESULT=456; private TabLayout tabLayout; private ViewPager2 pager; @@ -40,7 +49,7 @@ public class DiscoverFragment extends AppKitFragment implements ScrollableToTop, private TabLayoutMediator tabLayoutMediator; private boolean searchActive; private FrameLayout searchView; - private ImageButton searchBack; + private ImageButton searchBack, searchScanQR; private TextView searchText; private View tabsDivider; @@ -52,6 +61,7 @@ public class DiscoverFragment extends AppKitFragment implements ScrollableToTop, private String accountID; private String currentQuery; + private Intent scannerIntent; @Override public void onCreate(Bundle savedInstanceState){ @@ -60,6 +70,7 @@ public class DiscoverFragment extends AppKitFragment implements ScrollableToTop, setRetainInstance(true); accountID=getArguments().getString("account"); + scannerIntent=BarcodeScanner.createIntent(Barcode.FORMAT_QR_CODE, false, true); } @Nullable @@ -174,6 +185,12 @@ public class DiscoverFragment extends AppKitFragment implements ScrollableToTop, tabLayout.setVisibility(View.GONE); searchView.setVisibility(View.VISIBLE); } + searchScanQR=view.findViewById(R.id.search_scan_qr); + if(!GmsClient.isGooglePlayServicesAvailable(getActivity())){ + searchScanQR.setVisibility(View.GONE); + }else{ + searchScanQR.setOnClickListener(v->openQrScanner()); + } View searchWrap=view.findViewById(R.id.search_wrap); searchWrap.setOutlineProvider(OutlineProviders.roundedRect(28)); @@ -268,6 +285,28 @@ public class DiscoverFragment extends AppKitFragment implements ScrollableToTop, } } + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data){ + if(requestCode==SCAN_RESULT && resultCode==Activity.RESULT_OK && BarcodeScanner.isValidResult(data)){ + Barcode code=BarcodeScanner.getResult(data); + if(code!=null){ + if(code.rawValue.startsWith("https:") || code.rawValue.startsWith("http:")){ + ((MainActivity)getActivity()).handleURL(Uri.parse(code.rawValue), accountID); + }else{ + Toast.makeText(getActivity(), R.string.link_not_supported, Toast.LENGTH_SHORT).show(); + } + } + } + } + + private void openQrScanner(){ + if(scannerIntent.resolveActivity(getActivity().getPackageManager())!=null){ + startActivityForResult(scannerIntent, SCAN_RESULT); + }else{ + BarcodeScanner.installScannerModule(getActivity(), ()->startActivityForResult(scannerIntent, SCAN_RESULT)); + } + } + private class DiscoverPagerAdapter extends RecyclerView.Adapter{ @NonNull @Override diff --git a/mastodon/src/main/java/org/joinmastodon/android/googleservices/barcodescanner/BarcodeScanner.java b/mastodon/src/main/java/org/joinmastodon/android/googleservices/barcodescanner/BarcodeScanner.java index 40de1f60..8116729b 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/googleservices/barcodescanner/BarcodeScanner.java +++ b/mastodon/src/main/java/org/joinmastodon/android/googleservices/barcodescanner/BarcodeScanner.java @@ -1,12 +1,35 @@ package org.joinmastodon.android.googleservices.barcodescanner; +import android.app.ProgressDialog; +import android.content.Context; import android.content.Intent; import android.content.pm.ApplicationInfo; import android.os.Parcel; +import android.os.RemoteException; +import android.util.Log; +import android.widget.Toast; + +import com.google.android.gms.common.Feature; +import com.google.android.gms.common.api.Status; +import com.google.android.gms.common.moduleinstall.ModuleAvailabilityResponse; +import com.google.android.gms.common.moduleinstall.ModuleInstallIntentResponse; +import com.google.android.gms.common.moduleinstall.ModuleInstallResponse; +import com.google.android.gms.common.moduleinstall.ModuleInstallStatusUpdate; +import com.google.android.gms.common.moduleinstall.internal.ApiFeatureRequest; +import com.google.android.gms.common.moduleinstall.internal.IModuleInstallCallbacks; +import com.google.android.gms.common.moduleinstall.internal.IModuleInstallService; +import com.google.android.gms.common.moduleinstall.internal.IModuleInstallStatusListener; import org.joinmastodon.android.MastodonApp; +import org.joinmastodon.android.R; +import org.joinmastodon.android.googleservices.GmsClient; +import org.joinmastodon.android.ui.utils.UiUtils; + +import java.util.List; public class BarcodeScanner{ + private static final String TAG="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; @@ -35,4 +58,79 @@ public class BarcodeScanner{ parcel.recycle(); return barcode; } + + public static void installScannerModule(Context context, Runnable onSuccess){ + ProgressDialog progress=new ProgressDialog(context); + progress.setMessage(context.getString(R.string.loading)); + progress.setCancelable(false); + progress.show(); + GmsClient.getModuleInstallerService(context, new GmsClient.ServiceConnectionCallback<>(){ + @Override + public void onSuccess(IModuleInstallService service, int connectionID){ + ApiFeatureRequest req=new ApiFeatureRequest(); + req.callingPackage=context.getPackageName(); + Feature feature=new Feature(); + feature.name="mlkit.barcode.ui"; + feature.version=1; + feature.oldVersion=-1; + req.features=List.of(feature); + req.urgent=true; + try{ + service.installModules(new IModuleInstallCallbacks.Stub(){ + @Override + public void onModuleAvailabilityResponse(Status status, ModuleAvailabilityResponse response) throws RemoteException{} + + @Override + public void onModuleInstallResponse(Status status, ModuleInstallResponse response) throws RemoteException{} + + @Override + public void onModuleInstallIntentResponse(Status status, ModuleInstallIntentResponse response) throws RemoteException{} + + @Override + public void onStatus(Status status) throws RemoteException{} + }, req, new IModuleInstallStatusListener.Stub(){ + @Override + public void onModuleInstallStatusUpdate(ModuleInstallStatusUpdate statusUpdate) throws RemoteException{ + if(statusUpdate.installState==ModuleInstallStatusUpdate.STATE_COMPLETED){ + Intent scannerIntent=createIntent(0, false, false); + Runnable r=new Runnable(){ + @Override + public void run(){ + if(scannerIntent.resolveActivity(context.getPackageManager())!=null){ + progress.dismiss(); + onSuccess.run(); + }else{ + UiUtils.runOnUiThread(this, 100); + } + } + }; + UiUtils.runOnUiThread(r); + GmsClient.disconnectFromService(context, connectionID); + }else if(statusUpdate.installState==ModuleInstallStatusUpdate.STATE_FAILED || statusUpdate.installState==ModuleInstallStatusUpdate.STATE_CANCELED){ + UiUtils.runOnUiThread(()->{ + progress.dismiss(); + Toast.makeText(context, R.string.error, Toast.LENGTH_SHORT).show(); + }); + GmsClient.disconnectFromService(context, connectionID); + } + } + }); + }catch(RemoteException e){ + Log.e(TAG, "onSuccess: ", e); + UiUtils.runOnUiThread(()->{ + progress.dismiss(); + Toast.makeText(context, R.string.error, Toast.LENGTH_SHORT).show(); + }); + GmsClient.disconnectFromService(context, connectionID); + } + } + + @Override + public void onError(Exception error){ + Log.e(TAG, "onError() called with: error = ["+error+"]"); + Toast.makeText(context, R.string.error, Toast.LENGTH_SHORT).show(); + progress.dismiss(); + } + }); + } } diff --git a/mastodon/src/main/res/layout/fragment_discover.xml b/mastodon/src/main/res/layout/fragment_discover.xml index c3b1c831..a09ef1d5 100644 --- a/mastodon/src/main/res/layout/fragment_discover.xml +++ b/mastodon/src/main/res/layout/fragment_discover.xml @@ -30,8 +30,9 @@ + +