Upgrade to SDK 34 (#5790)

* change the overridden method signature as per API 34

* add version check condition to compare with API 23 before adding flag

* refactor: add final keywords, fix typo, and remove redundant spaces

For optimized code only

* upgrade: migrate to SDK 34 and upgrade APG

Additionally, add Jetpack Compose to the project

* AndroidManifest: add new permission for API 34

DescriptionActivity should not be exposed

* refactor: permission should not be check on onCreate for some cases

* add method to get correct storage permission and check partial access

Additionally, add final keywords to reduce compiler warnings

* refactor: prevent app from crashing for SDKs >= 34

* add new UI component to allows user to manage partially access photos

Implement using composeView

* change the overridden method signature as per API 34

* add version check condition to compare with API 23 before adding flag

* refactor: add final keywords, fix typo, and remove redundant spaces

For optimized code only

* upgrade: migrate to SDK 34 and upgrade APG

Additionally, add Jetpack Compose to the project

* AndroidManifest: add new permission for API 34

DescriptionActivity should not be exposed

* refactor: permission should not be check on onCreate for some cases

* add method to get correct storage permission and check partial access

Additionally, add final keywords to reduce compiler warnings

* refactor: prevent app from crashing for SDKs >= 34

* add new UI component to allows user to manage partially access photos

Implement using composeView

* replace deprecated circular progress bar with material progress bar

* remove redundant appcompat dependency

* add condition to check for partial access on API >= 34

It prevents invoking photo picker on UploadActivity.

* UploadWorker: add foreground service type

* fix typos in UploadWorker.kt

* add permission to access media location
This commit is contained in:
Rohit Verma 2024-09-17 20:28:44 +05:30 committed by GitHub
parent eb027b74ce
commit 3e915f9848
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
17 changed files with 433 additions and 200 deletions

View file

@ -9,10 +9,9 @@ import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.net.Uri;
import android.os.Build;
import android.widget.RemoteViews;
import androidx.annotation.Nullable;
import com.facebook.common.executors.CallerThreadExecutor;
import com.facebook.common.references.CloseableReference;
import com.facebook.datasource.DataSource;
@ -22,10 +21,8 @@ import com.facebook.imagepipeline.datasource.BaseBitmapDataSubscriber;
import com.facebook.imagepipeline.image.CloseableImage;
import com.facebook.imagepipeline.request.ImageRequest;
import com.facebook.imagepipeline.request.ImageRequestBuilder;
import fr.free.nrw.commons.media.MediaClient;
import javax.inject.Inject;
import fr.free.nrw.commons.R;
import fr.free.nrw.commons.contributions.MainActivity;
import fr.free.nrw.commons.di.ApplicationlessInjection;
@ -41,17 +38,28 @@ import static android.content.Intent.ACTION_VIEW;
*/
public class PicOfDayAppWidget extends AppWidgetProvider {
private CompositeDisposable compositeDisposable = new CompositeDisposable();
private final CompositeDisposable compositeDisposable = new CompositeDisposable();
@Inject
MediaClient mediaClient;
void updateAppWidget(Context context, AppWidgetManager appWidgetManager, int appWidgetId) {
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.pic_of_day_app_widget);
void updateAppWidget(
final Context context,
final AppWidgetManager appWidgetManager,
final int appWidgetId
) {
final RemoteViews views = new RemoteViews(
context.getPackageName(), R.layout.pic_of_day_app_widget);
// Launch App on Button Click
Intent viewIntent = new Intent(context, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, viewIntent, PendingIntent.FLAG_IMMUTABLE);
final Intent viewIntent = new Intent(context, MainActivity.class);
int flags = PendingIntent.FLAG_UPDATE_CURRENT;
if (Build.VERSION.SDK_INT>= Build.VERSION_CODES.M) {
flags |= PendingIntent.FLAG_IMMUTABLE;
}
final PendingIntent pendingIntent = PendingIntent.getActivity(
context, 0, viewIntent, flags);
views.setOnClickPendingIntent(R.id.camera_button, pendingIntent);
appWidgetManager.updateAppWidget(appWidgetId, views);
@ -60,61 +68,76 @@ public class PicOfDayAppWidget extends AppWidgetProvider {
/**
* Loads the picture of the day using media wiki API
* @param context
* @param views
* @param appWidgetManager
* @param appWidgetId
* @param context The application context.
* @param views The RemoteViews object used to update the App Widget UI.
* @param appWidgetManager The AppWidgetManager instance for managing the widget.
* @param appWidgetId he ID of the App Widget to update.
*/
private void loadPictureOfTheDay(Context context,
RemoteViews views,
AppWidgetManager appWidgetManager,
int appWidgetId) {
private void loadPictureOfTheDay(
final Context context,
final RemoteViews views,
final AppWidgetManager appWidgetManager,
final int appWidgetId
) {
compositeDisposable.add(mediaClient.getPictureOfTheDay()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
response -> {
if (response != null) {
views.setTextViewText(R.id.appwidget_title, response.getDisplayTitle());
response -> {
if (response != null) {
views.setTextViewText(R.id.appwidget_title, response.getDisplayTitle());
// View in browser
Intent viewIntent = new Intent();
viewIntent.setAction(ACTION_VIEW);
viewIntent.setData(Uri.parse(response.getPageTitle().getMobileUri()));
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, viewIntent, PendingIntent.FLAG_IMMUTABLE);
views.setOnClickPendingIntent(R.id.appwidget_image, pendingIntent);
// View in browser
final Intent viewIntent = new Intent();
viewIntent.setAction(ACTION_VIEW);
viewIntent.setData(Uri.parse(response.getPageTitle().getMobileUri()));
loadImageFromUrl(response.getThumbUrl(), context, views, appWidgetManager, appWidgetId);
int flags = PendingIntent.FLAG_UPDATE_CURRENT;
if (Build.VERSION.SDK_INT>= Build.VERSION_CODES.M) {
flags |= PendingIntent.FLAG_IMMUTABLE;
}
},
t -> Timber.e(t, "Fetching picture of the day failed")
final PendingIntent pendingIntent = PendingIntent.getActivity(
context, 0, viewIntent, flags);
views.setOnClickPendingIntent(R.id.appwidget_image, pendingIntent);
loadImageFromUrl(response.getThumbUrl(),
context, views, appWidgetManager, appWidgetId);
}
},
t -> Timber.e(t, "Fetching picture of the day failed")
));
}
/**
* Uses Fresco to load an image from Url
* @param imageUrl
* @param context
* @param views
* @param appWidgetManager
* @param appWidgetId
* @param imageUrl The URL of the image to load.
* @param context The application context.
* @param views The RemoteViews object used to update the App Widget UI.
* @param appWidgetManager The AppWidgetManager instance for managing the widget.
* @param appWidgetId he ID of the App Widget to update.
*/
private void loadImageFromUrl(String imageUrl,
Context context,
RemoteViews views,
AppWidgetManager appWidgetManager,
int appWidgetId) {
ImageRequest request = ImageRequestBuilder.newBuilderWithSource(Uri.parse(imageUrl)).build();
ImagePipeline imagePipeline = Fresco.getImagePipeline();
DataSource<CloseableReference<CloseableImage>> dataSource
= imagePipeline.fetchDecodedImage(request, context);
private void loadImageFromUrl(
final String imageUrl,
final Context context,
final RemoteViews views,
final AppWidgetManager appWidgetManager,
final int appWidgetId
) {
final ImageRequest request = ImageRequestBuilder
.newBuilderWithSource(Uri.parse(imageUrl)).build();
final ImagePipeline imagePipeline = Fresco.getImagePipeline();
final DataSource<CloseableReference<CloseableImage>> dataSource = imagePipeline
.fetchDecodedImage(request, context);
dataSource.subscribe(new BaseBitmapDataSubscriber() {
@Override
protected void onNewResultImpl(@Nullable Bitmap tempBitmap) {
protected void onNewResultImpl(@Nullable final Bitmap tempBitmap) {
Bitmap bitmap = null;
if (tempBitmap != null) {
bitmap = Bitmap.createBitmap(tempBitmap.getWidth(), tempBitmap.getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
bitmap = Bitmap.createBitmap(
tempBitmap.getWidth(), tempBitmap.getHeight(), Bitmap.Config.ARGB_8888
);
final Canvas canvas = new Canvas(bitmap);
canvas.drawBitmap(tempBitmap, 0f, 0f, new Paint());
}
views.setImageViewBitmap(R.id.appwidget_image, bitmap);
@ -122,32 +145,37 @@ public class PicOfDayAppWidget extends AppWidgetProvider {
}
@Override
protected void onFailureImpl(DataSource<CloseableReference<CloseableImage>> dataSource) {
protected void onFailureImpl(
final DataSource<CloseableReference<CloseableImage>> dataSource
) {
// Ignore failure for now.
}
}, CallerThreadExecutor.getInstance());
}
@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
public void onUpdate(
final Context context,
final AppWidgetManager appWidgetManager,
final int[] appWidgetIds
) {
ApplicationlessInjection
.getInstance(context
.getApplicationContext())
.getInstance(context.getApplicationContext())
.getCommonsApplicationComponent()
.inject(this);
// There may be multiple widgets active, so update all of them
for (int appWidgetId : appWidgetIds) {
for (final int appWidgetId : appWidgetIds) {
updateAppWidget(context, appWidgetManager, appWidgetId);
}
}
@Override
public void onEnabled(Context context) {
public void onEnabled(final Context context) {
// Enter relevant functionality for when the first widget is created
}
@Override
public void onDisabled(Context context) {
public void onDisabled(final Context context) {
// Enter relevant functionality for when the last widget is disabled
}
}