1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.example.android.apis.content; 18 19 // Need the following import to get access to the app resources, since this 20 // class is in a sub-package. 21 import com.example.android.apis.R; 22 23 import android.app.Activity; 24 import android.app.PendingIntent; 25 import android.content.Context; 26 import android.content.Intent; 27 import android.content.IntentSender; 28 import android.content.pm.PackageInstaller; 29 import android.os.Bundle; 30 import android.view.View; 31 import android.view.View.OnClickListener; 32 import android.widget.Button; 33 import android.widget.Toast; 34 35 import java.io.IOException; 36 import java.io.InputStream; 37 import java.io.OutputStream; 38 39 40 /** 41 * Demonstration of package installation and uninstallation using the package installer Session 42 * API. 43 * 44 * @see InstallApk for a demo of the original (non-Session) API. 45 */ 46 public class InstallApkSessionApi extends Activity { 47 private static final String PACKAGE_INSTALLED_ACTION = 48 "com.example.android.apis.content.SESSION_API_PACKAGE_INSTALLED"; 49 50 @Override onCreate(Bundle savedInstanceState)51 protected void onCreate(Bundle savedInstanceState) { 52 super.onCreate(savedInstanceState); 53 54 setContentView(R.layout.install_apk_session_api); 55 56 // Watch for button clicks. 57 Button button = (Button) findViewById(R.id.install); 58 button.setOnClickListener(new OnClickListener() { 59 public void onClick(View v) { 60 PackageInstaller.Session session = null; 61 try { 62 PackageInstaller packageInstaller = getPackageManager().getPackageInstaller(); 63 PackageInstaller.SessionParams params = new PackageInstaller.SessionParams( 64 PackageInstaller.SessionParams.MODE_FULL_INSTALL); 65 int sessionId = packageInstaller.createSession(params); 66 session = packageInstaller.openSession(sessionId); 67 68 addApkToInstallSession("HelloActivity.apk", session); 69 70 // Create an install status receiver. 71 Context context = InstallApkSessionApi.this; 72 Intent intent = new Intent(context, InstallApkSessionApi.class); 73 intent.setAction(PACKAGE_INSTALLED_ACTION); 74 PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0); 75 IntentSender statusReceiver = pendingIntent.getIntentSender(); 76 77 // Commit the session (this will start the installation workflow). 78 session.commit(statusReceiver); 79 } catch (IOException e) { 80 throw new RuntimeException("Couldn't install package", e); 81 } catch (RuntimeException e) { 82 if (session != null) { 83 session.abandon(); 84 } 85 throw e; 86 } 87 } 88 }); 89 } 90 addApkToInstallSession(String assetName, PackageInstaller.Session session)91 private void addApkToInstallSession(String assetName, PackageInstaller.Session session) 92 throws IOException { 93 // It's recommended to pass the file size to openWrite(). Otherwise installation may fail 94 // if the disk is almost full. 95 try (OutputStream packageInSession = session.openWrite("package", 0, -1); 96 InputStream is = getAssets().open(assetName)) { 97 byte[] buffer = new byte[16384]; 98 int n; 99 while ((n = is.read(buffer)) >= 0) { 100 packageInSession.write(buffer, 0, n); 101 } 102 } 103 } 104 105 // Note: this Activity must run in singleTop launchMode for it to be able to receive the intent 106 // in onNewIntent(). 107 @Override onNewIntent(Intent intent)108 protected void onNewIntent(Intent intent) { 109 Bundle extras = intent.getExtras(); 110 if (PACKAGE_INSTALLED_ACTION.equals(intent.getAction())) { 111 int status = extras.getInt(PackageInstaller.EXTRA_STATUS); 112 String message = extras.getString(PackageInstaller.EXTRA_STATUS_MESSAGE); 113 114 switch (status) { 115 case PackageInstaller.STATUS_PENDING_USER_ACTION: 116 // This test app isn't privileged, so the user has to confirm the install. 117 Intent confirmIntent = (Intent) extras.get(Intent.EXTRA_INTENT); 118 startActivity(confirmIntent); 119 break; 120 121 case PackageInstaller.STATUS_SUCCESS: 122 Toast.makeText(this, "Install succeeded!", Toast.LENGTH_SHORT).show(); 123 break; 124 125 case PackageInstaller.STATUS_FAILURE: 126 case PackageInstaller.STATUS_FAILURE_ABORTED: 127 case PackageInstaller.STATUS_FAILURE_BLOCKED: 128 case PackageInstaller.STATUS_FAILURE_CONFLICT: 129 case PackageInstaller.STATUS_FAILURE_INCOMPATIBLE: 130 case PackageInstaller.STATUS_FAILURE_INVALID: 131 case PackageInstaller.STATUS_FAILURE_STORAGE: 132 Toast.makeText(this, "Install failed! " + status + ", " + message, 133 Toast.LENGTH_SHORT).show(); 134 break; 135 default: 136 Toast.makeText(this, "Unrecognized status received from installer: " + status, 137 Toast.LENGTH_SHORT).show(); 138 } 139 } 140 } 141 } 142