Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Let user update the app #355

Open
wants to merge 14 commits into
base: master
Choose a base branch
from
2 changes: 1 addition & 1 deletion app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ dependencies {
implementation ('com.github.bumptech.glide:glide:4.13.2') {
exclude group: "com.android.support"
}
annotationProcessor 'com.github.bumptech.glide:compiler:4.13.2'
implementation 'com.squareup.okhttp3:okhttp:4.9.1'

fullImplementation 'com.google.firebase:firebase-analytics:19.0.1'
Expand Down Expand Up @@ -137,7 +138,6 @@ dependencies {
//noinspection AnnotationProcessorOnCompilePath
compileOnly 'org.projectlombok:lombok:1.18.22'
annotationProcessor 'org.projectlombok:lombok:1.18.22'
annotationProcessor 'com.github.bumptech.glide:compiler:4.11.0'

implementation 'org.ocpsoft.prettytime:prettytime:5.0.2.Final'

Expand Down
2 changes: 2 additions & 0 deletions app/src/full/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS" />

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

<application
android:name=".OdyseeApp"
android:allowBackup="true"
Expand Down
10 changes: 10 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,16 @@
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/filepaths" />
</provider>

<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/provider_paths" />
</provider>
</application>

</manifest>
Original file line number Diff line number Diff line change
@@ -1,11 +1,21 @@
package com.odysee.app.ui.findcontent;

import android.Manifest;
import android.app.DownloadManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.content.pm.InstallSourceInfo;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
Expand All @@ -14,22 +24,36 @@

import androidx.annotation.NonNull;
import androidx.core.content.ContextCompat;
import androidx.core.content.FileProvider;
import androidx.preference.PreferenceManager;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import com.google.android.material.chip.Chip;
import com.google.android.material.chip.ChipGroup;

import com.google.android.material.snackbar.BaseTransientBottomBar;
import com.google.android.material.snackbar.Snackbar;
import com.odysee.app.BuildConfig;
import com.odysee.app.OdyseeApp;
import com.odysee.app.callable.ChannelLiveStatus;
import com.odysee.app.callable.Search;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.ResponseBody;
import org.jetbrains.annotations.NotNull;
import org.json.JSONException;
import org.json.JSONObject;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
Expand Down Expand Up @@ -110,6 +134,8 @@ public class AllContentFragment extends BaseFragment implements DownloadActionLi
private int wildWestIndex = -1;
private int moviesIndex = -1;

private long latestVersionCheck = 0L;

private void buildAndDisplayContentCategories() {
if (contentCategoriesDisplayed) {
return;
Expand Down Expand Up @@ -435,6 +461,15 @@ public void onResume() {

Context context = getContext();
if (context instanceof MainActivity) {
// After updating the app, the APK fiel can be deleted here, as app will be restarted
String filePath = context.getExternalFilesDir(null).getAbsolutePath().concat("/odysee-android.apk");
File f = new File(filePath);

if (f.exists()) {
//noinspection ResultOfMethodCallIgnored
f.delete();
}

MainActivity activity = (MainActivity) context;
if (singleTagView) {
LbryAnalytics.setCurrentScreen(activity, "Tag", "Tag");
Expand All @@ -454,6 +489,9 @@ public void onResume() {
}

applyFilterForMutedChannels(Lbryio.mutedChannels);

// Check for app auto-update
checkAppUpdater();
}

public void onPause() {
Expand All @@ -466,6 +504,165 @@ public void onPause() {
super.onPause();
}

private void checkAppUpdater() {
if (BuildConfig.DEBUG) {
return;
}

Date now = new Date();
Context activity = getActivity();
// Check for a new version once in a day
if (activity != null && (now.getTime() - latestVersionCheck) > (24 * 3600 * 1000)) {
latestVersionCheck = now.getTime();

PackageManager pm = activity.getPackageManager();
try {
String installer;
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.Q) {
InstallSourceInfo installSourceInfo = pm.getInstallSourceInfo(activity.getPackageName());
installer = installSourceInfo.getInstallingPackageName();
} else {
//noinspection deprecation
kekkyojin marked this conversation as resolved.
Show resolved Hide resolved
installer = pm.getInstallerPackageName(activity.getPackageName());
}

List<String> packagesNotAutoUpdating = Arrays.asList("com.google.android.feedback", "com.android.ending", "org.fdroid.fdroid");
kekkyojin marked this conversation as resolved.
Show resolved Hide resolved

if (installer == null || !packagesNotAutoUpdating.contains(installer)) {
((OdyseeApp)getActivity().getApplication()).getExecutor().submit(new Runnable() {
@Override
public void run() {
checkRemoteLatestVersion(getView());
}
});
}
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
}
}

/**
* Checks for a new version on the remote server and then updates the app if a new one is available
* @param root the root view to show the snackbar
*/
private void checkRemoteLatestVersion(View root) {
/* JSON file format:
* {
* latest_version_code: integer,
* url: string including https and package file
* }
*/
Request.Builder builder = new Request.Builder();
builder = builder.url("https://apk.odysee.tv/odysee-android-latest.json");
Request request = builder.build();
OkHttpClient okHttpClient = new OkHttpClient.Builder().build();
Call call = okHttpClient.newCall(request);

call.enqueue(new Callback() {
@Override
public void onFailure(@NotNull Call call, @NotNull IOException e) {
Log.e("RemoteLatestVersion", e.getMessage());
}

@Override
public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
ResponseBody body = response.body();

if (body != null) {
String respBody = body.string();

try {
JSONObject responseJson = new JSONObject(respBody);

long latestCode = responseJson.getLong("latest_version_code");
String latestUrl = responseJson.getString("url");

if (latestCode > BuildConfig.VERSION_CODE && !Helper.isNullOrEmpty(latestUrl)) {
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
Snackbar snackbar = Snackbar.make(root.findViewById(R.id.coordinator_root), getResources().getString(R.string.snackbar_new_version_available), BaseTransientBottomBar.LENGTH_INDEFINITE);
snackbar.setAction(getResources().getString(R.string.snackbar_install_button), new View.OnClickListener() {
@Override
public void onClick(View view) {
Context context = getContext();
if (context != null) {
String filePath = context.getExternalFilesDir(null).getAbsolutePath().concat("/odysee-android.apk");
File f = new File(filePath);

if (f.exists()) {
//noinspection ResultOfMethodCallIgnored
f.delete();
}

final Uri uri = Uri.parse("file://" + filePath);
DownloadManager.Request request = new DownloadManager.Request(Uri.parse(latestUrl));
request.setDescription("Odysee new version available");
request.setTitle(getResources().getString(R.string.downloadmanager_downloading_new_version));

//set destination
request.setDestinationUri(uri);
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE);

// get download service and enqueue file
final DownloadManager manager = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);
manager.enqueue(request);

//set BroadcastReceiver to install app when .apk is downloaded
BroadcastReceiver onComplete = new BroadcastReceiver() {
public void onReceive(Context ctxt, Intent intent) {
ContextCompat.checkSelfPermission(ctxt, Manifest.permission.READ_EXTERNAL_STORAGE);

installApk();
getContext().unregisterReceiver(this);
}
};

//register receiver for when .apk download is complete
context.registerReceiver(onComplete, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
}
}
});
snackbar.show();
}
});
}
} catch (JSONException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
}

});
}

private void installApk() {
try {
Context context = getContext();
if (context != null) {
File file = new File(getContext().getExternalFilesDir(null).getAbsolutePath().concat("/odysee-android.apk"));
Intent intent = new Intent(Intent.ACTION_VIEW);
Uri downloaded_apk;
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.M) {
downloaded_apk = FileProvider.getUriForFile(context, context.getApplicationContext().getPackageName() + ".provider", file);
context.grantUriPermission(context.getApplicationContext().getPackageName() + ".provider", downloaded_apk, Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);
} else {
downloaded_apk = Uri.fromFile(file);
intent.setAction(Intent.ACTION_VIEW);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
}
intent.setDataAndType(downloaded_apk, "application/vnd.android.package-archive");
startActivity(intent);
}
} catch (Exception e) {
e.printStackTrace();
}
}

private Map<String, Object> buildContentOptions() {
Context context = getContext();
boolean canShowMatureContent = false;
Expand Down
Loading