Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4c37bcb9 authored by Sumedh Sen's avatar Sumedh Sen
Browse files

Convert code in InstallRepository and related classes from Java to Kotlin (install repo)

This is the 2nd CL in a 2-part change from Java to Kotlin. This CL
changes java code to kotlin.

Bug: 182205982
Test: builds successfully
Change-Id: I364b1751393b057032596cbfd82f4349b639bc10
parent 96759613
Loading
Loading
Loading
Loading
+606 −639

File changed.

Preview size limit exceeded, changes collapsed.

+81 −90
Original line number Diff line number Diff line
@@ -14,113 +14,104 @@
 * limitations under the License.
 */

package com.android.packageinstaller.v2.model;

import static android.content.res.AssetFileDescriptor.UNKNOWN_LENGTH;

import android.content.Context;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageInstaller.SessionInfo;
import android.content.res.AssetFileDescriptor;
import android.net.Uri;
import android.os.AsyncTask;
import android.util.Log;
import androidx.lifecycle.MutableLiveData;
import com.android.packageinstaller.v2.model.InstallRepository.SessionStageListener;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

public class SessionStager extends AsyncTask<Void, Integer, SessionInfo> {

    private static final String TAG = SessionStager.class.getSimpleName();
    private final Context mContext;
    private final Uri mUri;
    private final int mStagedSessionId;
    private final MutableLiveData<Integer> mProgressLiveData = new MutableLiveData<>(0);
    private final SessionStageListener mListener;

    SessionStager(Context context, Uri uri, int stagedSessionId, SessionStageListener listener) {
        mContext = context;
        mUri = uri;
        mStagedSessionId = stagedSessionId;
        mListener = listener;
    }

    @Override
    protected PackageInstaller.SessionInfo doInBackground(Void... params) {
        PackageInstaller pi = mContext.getPackageManager().getPackageInstaller();
        try (PackageInstaller.Session session = pi.openSession(mStagedSessionId);
            InputStream in = mContext.getContentResolver().openInputStream(mUri)) {
            session.setStagingProgress(0);

            if (in == null) {
                return null;
            }
            final long sizeBytes = getContentSizeBytes();
            mProgressLiveData.postValue(sizeBytes > 0 ? 0 : -1);

            long totalRead = 0;
            try (OutputStream out = session.openWrite("PackageInstaller", 0, sizeBytes)) {
                byte[] buffer = new byte[1024 * 1024];
package com.android.packageinstaller.v2.model

import android.content.Context
import android.content.pm.PackageInstaller
import android.content.res.AssetFileDescriptor
import android.net.Uri
import android.os.AsyncTask
import android.util.Log
import androidx.lifecycle.MutableLiveData
import com.android.packageinstaller.v2.model.InstallRepository.SessionStageListener
import java.io.IOException

class SessionStager internal constructor(
    private val context: Context,
    private val uri: Uri,
    private val stagedSessionId: Int,
    private val listener: SessionStageListener,
) : AsyncTask<Void, Int, PackageInstaller.SessionInfo?>() {

    companion object {
        private val LOG_TAG = SessionStager::class.java.simpleName
    }

    val progress = MutableLiveData(0)

    override fun doInBackground(vararg params: Void): PackageInstaller.SessionInfo? {
        val pi = context.packageManager.packageInstaller
        try {
            val session = pi.openSession(stagedSessionId)
            context.contentResolver.openInputStream(uri).use { instream ->
                session.setStagingProgress(0f)

                if (instream == null) {
                    return null
                }

                val sizeBytes = getContentSizeBytes()
                progress.postValue(if (sizeBytes > 0) 0 else -1)

                var totalRead: Long = 0
                session.openWrite("PackageInstaller", 0, sizeBytes).use { out ->
                    val buffer = ByteArray(1024 * 1024)
                    while (true) {
                    int numRead = in.read(buffer);
                        val numRead = instream.read(buffer)

                        if (numRead == -1) {
                        session.fsync(out);
                        break;
                            session.fsync(out)
                            break
                        }

                    if (isCancelled()) {
                        break;
                        if (isCancelled) {
                            break
                        }

                    out.write(buffer, 0, numRead);
                        out.write(buffer, 0, numRead)
                        if (sizeBytes > 0) {
                        totalRead += numRead;
                        float fraction = ((float) totalRead / (float) sizeBytes);
                        session.setStagingProgress(fraction);
                        publishProgress((int) (fraction * 100.0));
                    }
                            totalRead += numRead.toLong()
                            val fraction = totalRead.toFloat() / sizeBytes.toFloat()
                            session.setStagingProgress(fraction)
                            publishProgress((fraction * 100.0).toInt())
                        }
                    }
            return pi.getSessionInfo(mStagedSessionId);
        } catch (IOException | SecurityException | IllegalStateException
                 | IllegalArgumentException e) {
            Log.w(TAG, "Error staging apk from content URI", e);
            return null;
                }
                return pi.getSessionInfo(stagedSessionId)!!
            }

    private long getContentSizeBytes() {
        try (AssetFileDescriptor afd = mContext.getContentResolver()
            .openAssetFileDescriptor(mUri, "r")) {
            return afd != null ? afd.getLength() : UNKNOWN_LENGTH;
        } catch (IOException e) {
            Log.w(TAG, "Failed to open asset file descriptor", e);
            return UNKNOWN_LENGTH;
        } catch (e: Exception) {
            Log.w(LOG_TAG, "Error staging apk from content URI", e)
            return null
        }
    }

    public MutableLiveData<Integer> getProgress() {
        return mProgressLiveData;
    private fun getContentSizeBytes(): Long {
        return try {
            context.contentResolver
                .openAssetFileDescriptor(uri, "r")
                .use { afd -> afd?.length ?: AssetFileDescriptor.UNKNOWN_LENGTH }
        } catch (e: IOException) {
            Log.w(LOG_TAG, "Failed to open asset file descriptor", e)
            AssetFileDescriptor.UNKNOWN_LENGTH
        }
    }

    @Override
    protected void onProgressUpdate(Integer... progress) {
        if (progress != null && progress.length > 0) {
            mProgressLiveData.setValue(progress[0]);
    override fun onPostExecute(sessionInfo: PackageInstaller.SessionInfo?) {
        if ((sessionInfo == null)
            || !sessionInfo.isActive
            || (sessionInfo.resolvedBaseApkPath == null)
        ) {
            Log.w(LOG_TAG, "Session info is invalid: $sessionInfo")
            listener.onStagingFailure()
            return
        }
        listener.onStagingSuccess(sessionInfo)
    }

    @Override
    protected void onPostExecute(SessionInfo sessionInfo) {
        if (sessionInfo == null || !sessionInfo.isActive()
            || sessionInfo.getResolvedBaseApkPath() == null) {
            Log.w(TAG, "Session info is invalid: " + sessionInfo);
            mListener.onStagingFailure();
            return;
    override fun onProgressUpdate(vararg progressVal: Int?) {
        if (progressVal.isNotEmpty()) {
            progress.value = progressVal[0]
        }
        mListener.onStagingSuccess(sessionInfo);
    }
}