fix: DummyActivity: implement installation progress dialog
* This fixes the apparent stalling when installing / cloning applications. * Also moves apk reading to another thread.
This commit is contained in:
parent
97f4b918b7
commit
7774395819
|
@ -41,7 +41,7 @@
|
|||
<activity android:name=".ui.DummyActivity"
|
||||
android:excludeFromRecents="true"
|
||||
android:launchMode="singleTask"
|
||||
android:theme="@android:style/Theme.Translucent.NoTitleBar">
|
||||
android:theme="@style/Theme.AppCompat.Translucent.NoTitleBar">
|
||||
<intent-filter>
|
||||
<action android:name="net.typeblog.shelter.action.FINALIZE_PROVISION" />
|
||||
<action android:name="net.typeblog.shelter.action.START_SERVICE" />
|
||||
|
|
|
@ -3,6 +3,7 @@ package net.typeblog.shelter.ui;
|
|||
import android.Manifest;
|
||||
import android.app.Activity;
|
||||
import android.app.PendingIntent;
|
||||
import android.app.ProgressDialog;
|
||||
import android.app.admin.DevicePolicyManager;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Intent;
|
||||
|
@ -15,10 +16,14 @@ import android.os.Bundle;
|
|||
import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
import android.os.StrictMode;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
|
||||
import net.typeblog.shelter.R;
|
||||
import net.typeblog.shelter.ShelterApplication;
|
||||
|
@ -29,6 +34,7 @@ import net.typeblog.shelter.services.IFileShuttleService;
|
|||
import net.typeblog.shelter.services.IFileShuttleServiceCallback;
|
||||
import net.typeblog.shelter.util.AuthenticationUtility;
|
||||
import net.typeblog.shelter.util.FileProviderProxy;
|
||||
import net.typeblog.shelter.util.InstallationProgressListener;
|
||||
import net.typeblog.shelter.util.LocalStorageManager;
|
||||
import net.typeblog.shelter.util.SettingsManager;
|
||||
import net.typeblog.shelter.util.Utility;
|
||||
|
@ -314,20 +320,40 @@ public class DummyActivity extends Activity {
|
|||
PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(
|
||||
PackageInstaller.SessionParams.MODE_FULL_INSTALL);
|
||||
int sessionId = pi.createSession(params);
|
||||
|
||||
// Show the progress dialog first
|
||||
pi.registerSessionCallback(new InstallationProgressListener(this, pi, sessionId));
|
||||
|
||||
PackageInstaller.Session session = pi.openSession(sessionId);
|
||||
doInstallPackageQ(uri, session, () -> {
|
||||
// We have finished piping the streams, show the progress as 10%
|
||||
session.setStagingProgress(0.1f);
|
||||
|
||||
InputStream is = getContentResolver().openInputStream(uri);
|
||||
OutputStream os = session.openWrite(UUID.randomUUID().toString(), 0, is.available());
|
||||
Utility.pipe(is, os);
|
||||
session.fsync(os);
|
||||
os.close();
|
||||
is.close();
|
||||
// Commit the session
|
||||
Intent intent = new Intent(this, DummyActivity.class);
|
||||
intent.setAction(PACKAGEINSTALLER_CALLBACK);
|
||||
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,
|
||||
intent, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
session.commit(pendingIntent.getIntentSender());
|
||||
});
|
||||
}
|
||||
|
||||
Intent intent = new Intent(this, DummyActivity.class);
|
||||
intent.setAction(PACKAGEINSTALLER_CALLBACK);
|
||||
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,
|
||||
intent, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
session.commit(pendingIntent.getIntentSender());
|
||||
// The background part of the installation process on Q (reading APKs etc)
|
||||
// that must be executed on another thread
|
||||
// Put them in background to avoid stalling the UI thread
|
||||
private void doInstallPackageQ(Uri uri, PackageInstaller.Session session, Runnable callback) {
|
||||
new Thread(() -> {
|
||||
try (InputStream is = getContentResolver().openInputStream(uri);
|
||||
OutputStream os = session.openWrite(UUID.randomUUID().toString(), 0, is.available())
|
||||
) {
|
||||
Utility.pipe(is, os);
|
||||
session.fsync(os);
|
||||
} catch (IOException e) {
|
||||
|
||||
}
|
||||
|
||||
runOnUiThread(callback);
|
||||
}).start();
|
||||
}
|
||||
|
||||
private void actionUninstallPackage() {
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
package net.typeblog.shelter.util;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.pm.PackageInstaller;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ProgressBar;
|
||||
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
|
||||
import net.typeblog.shelter.R;
|
||||
|
||||
public class InstallationProgressListener extends PackageInstaller.SessionCallback {
|
||||
private AlertDialog mDialog;
|
||||
private ProgressBar mProgress;
|
||||
private int mSessionId;
|
||||
private PackageInstaller mPi;
|
||||
|
||||
// Create a listener from an activity, and show a progress dialog for the sessionId
|
||||
// Only cares about the one sessionId provided here.
|
||||
// The caller is responsible for registering the callback;
|
||||
// however, this class will remove itself once the session has been finished.
|
||||
public InstallationProgressListener(Activity activity, PackageInstaller pi, int sessionId) {
|
||||
mPi = pi;
|
||||
|
||||
ViewGroup layout = (ViewGroup) LayoutInflater.from(activity)
|
||||
.inflate(R.layout.progress_dialog, (ViewGroup) activity.getWindow().getDecorView(), false);
|
||||
mProgress = layout.findViewById(R.id.progress);
|
||||
|
||||
mDialog = new AlertDialog.Builder(activity)
|
||||
.setCancelable(false)
|
||||
.setTitle(R.string.app_installing)
|
||||
.setView(layout)
|
||||
.create();
|
||||
mDialog.show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreated(int sessionId) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBadgingChanged(int sessionId) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActiveChanged(int sessionId, boolean active) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onProgressChanged(int sessionId, float progress) {
|
||||
mProgress.setProgress((int) (progress * 100));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFinished(int sessionId, boolean success) {
|
||||
if (sessionId != mSessionId) {
|
||||
return;
|
||||
}
|
||||
|
||||
mDialog.hide();
|
||||
mPi.unregisterSessionCallback(this);
|
||||
}
|
||||
}
|
18
app/src/main/res/layout/progress_dialog.xml
Normal file
18
app/src/main/res/layout/progress_dialog.xml
Normal file
|
@ -0,0 +1,18 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center">
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/progress"
|
||||
style="@android:style/Widget.Material.ProgressBar.Horizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="20dp"
|
||||
android:layout_marginEnd="20dp"
|
||||
android:layout_marginTop="10dp"
|
||||
android:indeterminate="false"
|
||||
android:max="100"/>
|
||||
|
||||
</FrameLayout>
|
|
@ -17,6 +17,7 @@
|
|||
<string name="service_auto_freeze_title">Auto-freeze pending</string>
|
||||
<string name="service_auto_freeze_desc">Shelter will auto-freeze apps launched from \"Unfreeze & Launch\" on the next screen lock event.</string>
|
||||
<string name="service_auto_freeze_now">Freeze Now</string>
|
||||
<string name="app_installing">Installing...</string>
|
||||
|
||||
<!-- Main UI -->
|
||||
<string name="fragment_profile_main">Main</string>
|
||||
|
|
|
@ -15,4 +15,13 @@
|
|||
<item name="android:textColorPrimary">@color/colorAccent</item>
|
||||
</style>
|
||||
|
||||
<!-- For DummyActivity -->
|
||||
<style name="Theme.AppCompat.Translucent.NoTitleBar" parent="Theme.AppCompat.Light.NoActionBar">
|
||||
<item name="android:windowNoTitle">true</item>
|
||||
<item name="android:windowBackground">@android:color/transparent</item>
|
||||
<item name="android:colorBackgroundCacheHint">@null</item>
|
||||
<item name="android:windowIsTranslucent">true</item>
|
||||
<item name="android:windowAnimationStyle">@android:style/Animation</item>
|
||||
</style>
|
||||
|
||||
</resources>
|
||||
|
|
Loading…
Reference in a new issue