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

Commit d6f226a1 authored by Philip P. Moltmann's avatar Philip P. Moltmann Committed by Android (Google) Code Review
Browse files

Merge "Split installing from display result."

parents 53502fb9 71a394c3
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -53,6 +53,9 @@
            </intent-filter>
        </activity>

        <activity android:name=".InstallInstalling"
                android:exported="false" />

        <activity android:name=".InstallAppProgress"
                android:configChanges="orientation|keyboardHidden|screenSize"
                android:exported="false" />
+108 −0
Original line number Diff line number Diff line
<?xml version="1.0" encoding="utf-8"?>

<!-- Copyright (C) 2016 The Android Open Source Project

     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at

          http://www.apache.org/licenses/LICENSE-2.0

     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     See the License for the specific language governing permissions and
     limitations under the License.
-->

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
            android:id="@+id/app_snippet"
            android:layout_width="match_parent"
            android:layout_height="?android:attr/actionBarSize"
            android:orientation="horizontal"
            android:gravity="center_vertical">

        <ImageView
                android:id="@+id/app_icon"
                android:layout_width="24dp"
                android:layout_height="24dp"
                android:layout_marginLeft="16dp"
                android:scaleType="fitCenter" />

        <TextView
                android:id="@+id/app_name"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginLeft="32dp"
                android:layout_marginRight="16dp"
                android:ellipsize="end"
                android:singleLine="true"
                android:textAppearance="?android:attr/titleTextStyle" />

    </LinearLayout>

    <LinearLayout
            android:id="@+id/center_view"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:gravity="center"
            android:orientation="vertical"
            android:paddingLeft="16dip"
            android:paddingRight="16dip">

        <ImageView
                android:id="@+id/center_icon"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginBottom="12dp"
                android:contentDescription="@null"
                android:src="@drawable/ic_android_92" />

        <ProgressBar
                android:id="@+id/progress_bar"
                style="?android:attr/progressBarStyleHorizontal"
                android:layout_width="250dp"
                android:layout_height="wrap_content"
                android:indeterminate="true" />

        <TextView
                android:id="@+id/center_text"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:gravity="center_horizontal"
                android:text="@string/installing"
                android:textAppearance="?android:attr/textAppearanceMedium" />

    </LinearLayout>

    <LinearLayout
            android:id="@+id/buttons_panel"
            style="?android:attr/buttonBarStyle"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:measureWithLargestChild="true"
            android:orientation="horizontal"
            android:padding="8dip">

        <View
                android:layout_width="0dp"
                android:layout_height="0dp"
                android:layout_weight="1" />

        <Button
                android:id="@+id/cancel_button"
                style="?android:attr/buttonBarButtonStyle"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:maxLines="2"
                android:text="@string/cancel" />

    </LinearLayout>

</LinearLayout>
+0 −7
Original line number Diff line number Diff line
@@ -38,13 +38,6 @@
                android:src="@drawable/ic_android_92"
                android:contentDescription="@null" />

        <ProgressBar android:id="@+id/progress_bar"
                android:layout_width="250dp"
                android:layout_height="wrap_content"
                android:indeterminate="true"
                style="?android:attr/progressBarStyleHorizontal">
        </ProgressBar>

        <TextView android:id="@+id/center_text"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
+10 −186
Original line number Diff line number Diff line
@@ -22,42 +22,25 @@ import android.annotation.Nullable;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.PendingIntent;
import android.content.ActivityNotFoundException;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnCancelListener;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.PackageParser;
import android.content.pm.PackageParser.PackageLite;
import android.content.pm.ResolveInfo;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;
import com.android.packageinstaller.permission.utils.IoUtils;

import com.android.internal.content.PackageHelper;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;

/**
@@ -70,13 +53,9 @@ import java.util.List;
 */
public class InstallAppProgress extends Activity implements View.OnClickListener, OnCancelListener {
    private final String TAG="InstallAppProgress";
    private static final String BROADCAST_ACTION =
            "com.android.packageinstaller.ACTION_INSTALL_COMMIT";
    private static final String BROADCAST_SENDER_PERMISSION =
            "android.permission.INSTALL_PACKAGES";

    private ApplicationInfo mAppInfo;
    private Uri mPackageURI;
    private ProgressBar mProgressBar;
    private View mOkPanel;
    private TextView mStatusTextView;
    private TextView mExplanationTextView;
@@ -86,8 +65,6 @@ public class InstallAppProgress extends Activity implements View.OnClickListener
    private Intent mLaunchIntent;
    private static final int DLG_OUT_OF_SPACE = 1;
    private CharSequence mLabel;
    private HandlerThread mInstallThread;
    private Handler mInstallHandler;

    private Handler mHandler = new Handler() {
        public void handleMessage(Message msg) {
@@ -99,11 +76,9 @@ public class InstallAppProgress extends Activity implements View.OnClickListener
                        setResult(msg.arg1 == PackageInstaller.STATUS_SUCCESS
                                ? Activity.RESULT_OK : Activity.RESULT_FIRST_USER,
                                        result);
                        clearCachedApkIfNeededAndFinish();
                        finish();
                        return;
                    }
                    // Update the status text
                    mProgressBar.setVisibility(View.GONE);
                    // Show the ok button
                    int centerTextLabel;
                    String centerExplanationLabel = null;
@@ -161,20 +136,6 @@ public class InstallAppProgress extends Activity implements View.OnClickListener
        }
    };

    private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            final int statusCode = intent.getIntExtra(
                    PackageInstaller.EXTRA_STATUS, PackageInstaller.STATUS_FAILURE);
            if (statusCode == PackageInstaller.STATUS_PENDING_USER_ACTION) {
                context.startActivity((Intent)intent.getParcelableExtra(Intent.EXTRA_INTENT));
            } else {
                onPackageInstalled(statusCode, intent.getStringExtra(
                        PackageInstaller.EXTRA_STATUS_MESSAGE));
            }
        }
    };

    private int getExplanationFromErrorCode(int errCode) {
        Log.d(TAG, "Installation error code: " + errCode);
        switch (errCode) {
@@ -194,30 +155,15 @@ public class InstallAppProgress extends Activity implements View.OnClickListener
    @Override
    public void onCreate(Bundle icicle) {
        super.onCreate(icicle);

        Intent intent = getIntent();
        mAppInfo = intent.getParcelableExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO);
        mPackageURI = intent.getData();

        final String scheme = mPackageURI.getScheme();
        if (scheme != null && !"file".equals(scheme) && !"package".equals(scheme)) {
            throw new IllegalArgumentException("unexpected scheme " + scheme);
        }

        mInstallThread = new HandlerThread("InstallThread");
        mInstallThread.start();
        mInstallHandler = new Handler(mInstallThread.getLooper());

        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(BROADCAST_ACTION);
        registerReceiver(
                mBroadcastReceiver, intentFilter, BROADCAST_SENDER_PERMISSION, null /*scheduler*/);

        initView();
    }

    @Override
    public void onBackPressed() {
        clearCachedApkIfNeededAndFinish();
        onPackageInstalled(getIntent().getIntExtra(
                PackageInstaller.EXTRA_STATUS, PackageInstaller.STATUS_FAILURE),
                getIntent().getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE));
    }

    @SuppressWarnings("deprecation")
@@ -234,13 +180,13 @@ public class InstallAppProgress extends Activity implements View.OnClickListener
                            //launch manage applications
                            Intent intent = new Intent("android.intent.action.MANAGE_PACKAGE_STORAGE");
                            startActivity(intent);
                            clearCachedApkIfNeededAndFinish();
                            finish();
                        }
                    })
                    .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialog, int which) {
                            Log.i(TAG, "Canceling installation");
                            clearCachedApkIfNeededAndFinish();
                            finish();
                        }
                    })
                    .setOnCancelListener(this)
@@ -262,73 +208,12 @@ public class InstallAppProgress extends Activity implements View.OnClickListener
        mHandler.sendMessage(msg);
    }

    int getInstallFlags(String packageName) {
        PackageManager pm = getPackageManager();
        try {
            PackageInfo pi =
                    pm.getPackageInfo(packageName, PackageManager.GET_UNINSTALLED_PACKAGES);
            if (pi != null) {
                return PackageManager.INSTALL_REPLACE_EXISTING;
            }
        } catch (NameNotFoundException e) {
        }
        return 0;
    }

    private void doPackageStage(PackageManager pm, PackageInstaller.SessionParams params) {
        final PackageInstaller packageInstaller = pm.getPackageInstaller();
        PackageInstaller.Session session = null;
        try {
            final String packageLocation = mPackageURI.getPath();
            final File file = new File(packageLocation);
            final int sessionId = packageInstaller.createSession(params);
            final byte[] buffer = new byte[65536];

            session = packageInstaller.openSession(sessionId);

            final InputStream in = new FileInputStream(file);
            final long sizeBytes = file.length();
            final OutputStream out = session.openWrite("PackageInstaller", 0, sizeBytes);
            try {
                int c;
                while ((c = in.read(buffer)) != -1) {
                    out.write(buffer, 0, c);
                    if (sizeBytes > 0) {
                        final float fraction = ((float) c / (float) sizeBytes);
                        session.addProgress(fraction);
                    }
                }
                session.fsync(out);
            } finally {
                IoUtils.closeQuietly(in);
                IoUtils.closeQuietly(out);
            }

            // Create a PendingIntent and use it to generate the IntentSender
            Intent broadcastIntent = new Intent(BROADCAST_ACTION);
            PendingIntent pendingIntent = PendingIntent.getBroadcast(
                    InstallAppProgress.this /*context*/,
                    sessionId,
                    broadcastIntent,
                    PendingIntent.FLAG_UPDATE_CURRENT);
            session.commit(pendingIntent.getIntentSender());
        } catch (IOException e) {
            onPackageInstalled(PackageInstaller.STATUS_FAILURE, null);
        } finally {
            IoUtils.closeQuietly(session);
        }
    }

    void initView() {
        setContentView(R.layout.op_progress);

        final PackageUtil.AppSnippet as;
        final PackageManager pm = getPackageManager();
        final int installFlags = getInstallFlags(mAppInfo.packageName);

        if((installFlags & PackageManager.INSTALL_REPLACE_EXISTING )!= 0) {
            Log.w(TAG, "Replacing package:" + mAppInfo.packageName);
        }
        if ("package".equals(mPackageURI.getScheme())) {
            as = new PackageUtil.AppSnippet(pm.getApplicationLabel(mAppInfo),
                    pm.getApplicationIcon(mAppInfo));
@@ -340,59 +225,11 @@ public class InstallAppProgress extends Activity implements View.OnClickListener
        PackageUtil.initSnippetForNewApp(this, as, R.id.app_snippet);
        mStatusTextView = (TextView)findViewById(R.id.center_text);
        mExplanationTextView = (TextView) findViewById(R.id.explanation);
        mProgressBar = (ProgressBar) findViewById(R.id.progress_bar);
        mProgressBar.setIndeterminate(true);
        // Hide button till progress is being displayed
        mOkPanel = findViewById(R.id.buttons_panel);
        mDoneButton = (Button)findViewById(R.id.done_button);
        mLaunchButton = (Button)findViewById(R.id.launch_button);
        mOkPanel.setVisibility(View.INVISIBLE);

        if ("package".equals(mPackageURI.getScheme())) {
            try {
                pm.installExistingPackage(mAppInfo.packageName);
                onPackageInstalled(PackageInstaller.STATUS_SUCCESS, null);
            } catch (PackageManager.NameNotFoundException e) {
                onPackageInstalled(PackageInstaller.STATUS_FAILURE_INVALID, null);
            }
        } else {
            final PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(
                    PackageInstaller.SessionParams.MODE_FULL_INSTALL);
            params.referrerUri = getIntent().getParcelableExtra(Intent.EXTRA_REFERRER);
            params.originatingUri = getIntent().getParcelableExtra(Intent.EXTRA_ORIGINATING_URI);
            params.originatingUid = getIntent().getIntExtra(Intent.EXTRA_ORIGINATING_UID,
                    UID_UNKNOWN);

            File file = new File(mPackageURI.getPath());
            try {
                PackageLite pkg = PackageParser.parsePackageLite(file, 0);
                params.setAppPackageName(pkg.packageName);
                params.setInstallLocation(pkg.installLocation);
                params.setSize(
                    PackageHelper.calculateInstalledSize(pkg, false, params.abiOverride));
            } catch (PackageParser.PackageParserException e) {
                Log.e(TAG, "Cannot parse package " + file + ". Assuming defaults.");
                Log.e(TAG, "Cannot calculate installed size " + file + ". Try only apk size.");
                params.setSize(file.length());
            } catch (IOException e) {
                Log.e(TAG, "Cannot calculate installed size " + file + ". Try only apk size.");
                params.setSize(file.length());
            }

            mInstallHandler.post(new Runnable() {
                @Override
                public void run() {
                    doPackageStage(pm, params);
                }
            });
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        unregisterReceiver(mBroadcastReceiver);
        mInstallThread.getLooper().quitSafely();
    }

    public void onClick(View v) {
@@ -400,31 +237,18 @@ public class InstallAppProgress extends Activity implements View.OnClickListener
            if (mAppInfo.packageName != null) {
                Log.i(TAG, "Finished installing "+mAppInfo.packageName);
            }
            clearCachedApkIfNeededAndFinish();
            finish();
        } else if(v == mLaunchButton) {
            try {
                startActivity(mLaunchIntent);
            } catch (ActivityNotFoundException e) {
                Log.e(TAG, "Could not start activity", e);
            }
            clearCachedApkIfNeededAndFinish();
            finish();
        }
    }

    public void onCancel(DialogInterface dialog) {
        clearCachedApkIfNeededAndFinish();
    }

    private void clearCachedApkIfNeededAndFinish() {
        // If we are installing from a content:// the apk is copied in the cache
        // dir and passed in here. As we aren't started for a result because our
        // caller needs to be able to forward the result, here we make sure the
        // staging file in the cache dir is removed.
        if ("file".equals(mPackageURI.getScheme()) && mPackageURI.getPath() != null
                && mPackageURI.getPath().startsWith(getCacheDir().toString())) {
            File file = new File(mPackageURI.getPath());
            file.delete();
        }
        finish();
    }
}
+356 −0

File added.

Preview size limit exceeded, changes collapsed.

Loading