1 /* 2 * Copyright (C) 2011 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.content.Context; 25 import android.content.Intent; 26 import android.net.Uri; 27 import android.os.Build; 28 import android.os.Bundle; 29 import android.support.v4.content.FileProvider; 30 import android.util.Log; 31 import android.view.View; 32 import android.view.View.OnClickListener; 33 import android.widget.Button; 34 import android.widget.Toast; 35 36 import java.io.File; 37 import java.io.FileOutputStream; 38 import java.io.IOException; 39 import java.io.InputStream; 40 41 42 /** 43 * Demonstration of package installation and uninstallation using the original (non-Session) 44 * package installation API that uses {@link Intent#ACTION_INSTALL_PACKAGE}. 45 * 46 * @see InstallApkSessionApi for a demo of the newer Session API. 47 */ 48 public class InstallApk extends Activity { 49 static final int REQUEST_INSTALL = 1; 50 static final int REQUEST_UNINSTALL = 2; 51 52 @Override 53 protected void onCreate(Bundle savedInstanceState) { 54 super.onCreate(savedInstanceState); 55 56 setContentView(R.layout.install_apk); 57 58 // Watch for button clicks. 59 Button button = (Button)findViewById(R.id.unknown_source); 60 button.setOnClickListener(mUnknownSourceListener); 61 button = (Button)findViewById(R.id.my_source); 62 button.setOnClickListener(mMySourceListener); 63 button = (Button)findViewById(R.id.uninstall); 64 button.setOnClickListener(mUninstallListener); 65 button = (Button)findViewById(R.id.uninstall_result); 66 button.setOnClickListener(mUninstallResultListener); 67 } 68 69 @Override 70 public void onActivityResult(int requestCode, int resultCode, Intent intent) { 71 if (requestCode == REQUEST_INSTALL) { 72 if (resultCode == Activity.RESULT_OK) { 73 Toast.makeText(this, "Install succeeded!", Toast.LENGTH_SHORT).show(); 74 } else if (resultCode == Activity.RESULT_CANCELED) { 75 Toast.makeText(this, "Install canceled!", Toast.LENGTH_SHORT).show(); 76 } else { 77 Toast.makeText(this, "Install Failed!", Toast.LENGTH_SHORT).show(); 78 } 79 } else if (requestCode == REQUEST_UNINSTALL) { 80 if (resultCode == Activity.RESULT_OK) { 81 Toast.makeText(this, "Uninstall succeeded!", Toast.LENGTH_SHORT).show(); 82 } else if (resultCode == Activity.RESULT_CANCELED) { 83 Toast.makeText(this, "Uninstall canceled!", Toast.LENGTH_SHORT).show(); 84 } else { 85 Toast.makeText(this, "Uninstall Failed!", Toast.LENGTH_SHORT).show(); 86 } 87 } 88 } 89 90 private OnClickListener mUnknownSourceListener = new OnClickListener() { 91 public void onClick(View v) { 92 Intent intent = new Intent(Intent.ACTION_INSTALL_PACKAGE); 93 intent.setData(getApkUri("HelloActivity.apk")); 94 intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); 95 startActivity(intent); 96 } 97 }; 98 99 private OnClickListener mMySourceListener = new OnClickListener() { 100 public void onClick(View v) { 101 Intent intent = new Intent(Intent.ACTION_INSTALL_PACKAGE); 102 intent.setData(getApkUri("HelloActivity.apk")); 103 intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); 104 intent.putExtra(Intent.EXTRA_NOT_UNKNOWN_SOURCE, true); 105 intent.putExtra(Intent.EXTRA_RETURN_RESULT, true); 106 intent.putExtra(Intent.EXTRA_INSTALLER_PACKAGE_NAME, 107 getApplicationInfo().packageName); 108 startActivityForResult(intent, REQUEST_INSTALL); 109 } 110 }; 111 112 private OnClickListener mUninstallListener = new OnClickListener() { 113 public void onClick(View v) { 114 Intent intent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE); 115 intent.setData(Uri.parse( 116 "package:com.example.android.helloactivity")); 117 startActivity(intent); 118 } 119 }; 120 121 private OnClickListener mUninstallResultListener = new OnClickListener() { 122 public void onClick(View v) { 123 Intent intent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE); 124 intent.setData(Uri.parse( 125 "package:com.example.android.helloactivity")); 126 intent.putExtra(Intent.EXTRA_RETURN_RESULT, true); 127 startActivityForResult(intent, REQUEST_UNINSTALL); 128 } 129 }; 130 131 /** 132 * Returns a Uri pointing to the APK to install. 133 */ 134 private Uri getApkUri(String assetName) { 135 // Before N, a MODE_WORLD_READABLE file could be passed via the ACTION_INSTALL_PACKAGE 136 // Intent. Since N, MODE_WORLD_READABLE files are forbidden, and a FileProvider is 137 // recommended. 138 boolean useFileProvider = Build.VERSION.SDK_INT >= Build.VERSION_CODES.N; 139 140 // Copy the given asset out into a file so that it can be installed. 141 // Returns the path to the file. 142 String tempFilename = "tmp.apk"; 143 byte[] buffer = new byte[16384]; 144 int fileMode = useFileProvider ? Context.MODE_PRIVATE : Context.MODE_WORLD_READABLE; 145 146 try (InputStream is = getAssets().open(assetName); 147 FileOutputStream fout = openFileOutput(tempFilename, fileMode)) { 148 int n; 149 while ((n=is.read(buffer)) >= 0) { 150 fout.write(buffer, 0, n); 151 } 152 } catch (IOException e) { 153 Log.i("InstallApk", "Failed to write temporary APK file", e); 154 } 155 156 if (useFileProvider) { 157 File toInstall = new File(this.getFilesDir(), tempFilename); 158 return FileProvider.getUriForFile( 159 this, "com.example.android.apis.installapkprovider", toInstall); 160 } else { 161 return Uri.fromFile(getFileStreamPath(tempFilename)); 162 } 163 } 164 } 165