Home | History | Annotate | Download | only in content
      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