/* ** ** Copyright 2007, The Android Open Source Project ** Copyright 2015 Daniel Martí <mvdan@mvdan.cc> ** ** 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. */ package org.fdroid.fdroid.privileged.views; import android.content.Context; import android.content.DialogInterface; import android.content.DialogInterface.OnCancelListener; import android.content.Intent; import android.content.pm.ApplicationInfo; import android.graphics.Bitmap; import android.net.Uri; import android.os.Bundle; import android.support.v4.app.FragmentActivity; import android.support.v4.view.ViewPager; import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; import android.widget.Button; import android.widget.ImageView; import android.widget.TabHost; import android.widget.TextView; import com.nostra13.universalimageloader.core.DisplayImageOptions; import com.nostra13.universalimageloader.core.ImageLoader; import com.nostra13.universalimageloader.core.assist.ImageScaleType; import org.fdroid.fdroid.FDroidApp; import org.fdroid.fdroid.R; import org.fdroid.fdroid.data.Apk; import org.fdroid.fdroid.data.ApkProvider; import org.fdroid.fdroid.data.App; import org.fdroid.fdroid.data.AppProvider; import org.fdroid.fdroid.data.Schema; /** * NOTES: * Parts are based on AOSP src/com/android/packageinstaller/PackageInstallerActivity.java * latest included commit: c23d802958158d522e7350321ad9ac6d43013883 */ public class InstallConfirmActivity extends FragmentActivity implements OnCancelListener, OnClickListener { private Intent intent; private AppDiff appDiff; // View for install progress private View installConfirm; // Buttons to indicate user acceptance private Button okButton; private Button cancelButton; private CaffeinatedScrollView scrollView; private boolean okCanInstall; private static final String TAB_ID_ALL = "all"; private static final String TAB_ID_NEW = "new"; private App app; private final DisplayImageOptions displayImageOptions = new DisplayImageOptions.Builder() .cacheInMemory(true) .cacheOnDisk(true) .imageScaleType(ImageScaleType.NONE) .showImageOnLoading(R.drawable.ic_repo_app_default) .showImageForEmptyUri(R.drawable.ic_repo_app_default) .bitmapConfig(Bitmap.Config.RGB_565) .build(); private void startInstallConfirm() { View appSnippet = findViewById(R.id.app_snippet); TextView appName = (TextView) appSnippet.findViewById(R.id.app_name); ImageView appIcon = (ImageView) appSnippet.findViewById(R.id.app_icon); TabHost tabHost = (TabHost) findViewById(android.R.id.tabhost); appName.setText(app.name); ImageLoader.getInstance().displayImage(app.iconUrlLarge, appIcon, displayImageOptions); tabHost.setup(); ViewPager viewPager = (ViewPager) findViewById(R.id.pager); TabsAdapter adapter = new TabsAdapter(this, tabHost, viewPager); adapter.setOnTabChangedListener(new TabHost.OnTabChangeListener() { @Override public void onTabChanged(String tabId) { } }); boolean permVisible = false; scrollView = null; okCanInstall = false; int msg = 0; AppSecurityPermissions perms = new AppSecurityPermissions(this, appDiff.pkgInfo); if (appDiff.installedAppInfo != null) { msg = (appDiff.installedAppInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0 ? R.string.install_confirm_update_system : R.string.install_confirm_update; scrollView = new CaffeinatedScrollView(this); scrollView.setFillViewport(true); final boolean newPermissionsFound = perms.getPermissionCount(AppSecurityPermissions.WHICH_NEW) > 0; if (newPermissionsFound) { permVisible = true; scrollView.addView(perms.getPermissionsView( AppSecurityPermissions.WHICH_NEW)); } else { throw new RuntimeException("This should not happen. No new permissions were found but InstallConfirmActivity has been started!"); } adapter.addTab(tabHost.newTabSpec(TAB_ID_NEW).setIndicator( getText(R.string.newPerms)), scrollView); } else { findViewById(R.id.tabscontainer).setVisibility(View.GONE); findViewById(R.id.divider).setVisibility(View.VISIBLE); } final int n = perms.getPermissionCount(AppSecurityPermissions.WHICH_ALL); if (n > 0) { permVisible = true; LayoutInflater inflater = (LayoutInflater) getSystemService( Context.LAYOUT_INFLATER_SERVICE); View root = inflater.inflate(R.layout.permissions_list, null); if (scrollView == null) { scrollView = (CaffeinatedScrollView) root.findViewById(R.id.scrollview); } final ViewGroup permList = (ViewGroup) root.findViewById(R.id.permission_list); permList.addView(perms.getPermissionsView(AppSecurityPermissions.WHICH_ALL)); adapter.addTab(tabHost.newTabSpec(TAB_ID_ALL).setIndicator( getText(R.string.allPerms)), root); } if (!permVisible) { if (appDiff.installedAppInfo != null) { // This is an update to an application, but there are no // permissions at all. msg = (appDiff.installedAppInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0 ? R.string.install_confirm_update_system_no_perms : R.string.install_confirm_update_no_perms; } else { // This is a new application with no permissions. throw new RuntimeException("no permissions requested. This screen should not appear!"); } tabHost.setVisibility(View.GONE); findViewById(R.id.filler).setVisibility(View.VISIBLE); findViewById(R.id.divider).setVisibility(View.GONE); scrollView = null; } if (msg != 0) { ((TextView) findViewById(R.id.install_confirm)).setText(msg); } installConfirm.setVisibility(View.VISIBLE); okButton = (Button) findViewById(R.id.ok_button); cancelButton = (Button) findViewById(R.id.cancel_button); okButton.setOnClickListener(this); cancelButton.setOnClickListener(this); if (scrollView == null) { // There is nothing to scroll view, so the ok button is immediately // set to install. okButton.setText(R.string.menu_install); okCanInstall = true; } else { scrollView.setFullScrollAction(new Runnable() { @Override public void run() { okButton.setText(R.string.menu_install); okCanInstall = true; } }); } } @Override protected void onCreate(Bundle icicle) { super.onCreate(icicle); ((FDroidApp) getApplication()).applyDialogTheme(this); intent = getIntent(); Uri uri = intent.getData(); Apk apk = ApkProvider.Helper.findByUri(this, uri, Schema.ApkTable.Cols.ALL); app = AppProvider.Helper.findSpecificApp(getContentResolver(), apk.packageName, apk.repo, Schema.AppMetadataTable.Cols.ALL); appDiff = new AppDiff(getPackageManager(), apk); setContentView(R.layout.install_start); // increase dialog to full width getWindow().setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); installConfirm = findViewById(R.id.install_confirm_panel); installConfirm.setVisibility(View.INVISIBLE); startInstallConfirm(); } // Generic handling when pressing back key public void onCancel(DialogInterface dialog) { finish(); } public void onClick(View v) { if (v == okButton) { if (okCanInstall || scrollView == null) { setResult(RESULT_OK, intent); finish(); } else { scrollView.pageScroll(View.FOCUS_DOWN); } } else if (v == cancelButton) { setResult(RESULT_CANCELED, intent); finish(); } } }