@Override public void onViewCreated(View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); mAcceptButton = (Button) view.findViewById(R.id.terms_accept); mSendReportCheckBox = (CheckBox) view.findViewById(R.id.send_report_checkbox); mTosAndPrivacy = (TextView) view.findViewById(R.id.tos_and_privacy); mAcceptButton.setOnClickListener( new OnClickListener() { @Override public void onClick(View v) { getPageDelegate().acceptTermsOfService(mSendReportCheckBox.isChecked()); } }); if (ChromeVersionInfo.isOfficialBuild()) { int paddingStart = getResources().getDimensionPixelSize(R.dimen.fre_tos_checkbox_padding); ApiCompatibilityUtils.setPaddingRelative( mSendReportCheckBox, ApiCompatibilityUtils.getPaddingStart(mSendReportCheckBox) + paddingStart, mSendReportCheckBox.getPaddingTop(), ApiCompatibilityUtils.getPaddingEnd(mSendReportCheckBox), mSendReportCheckBox.getPaddingBottom()); mSendReportCheckBox.setChecked(FirstRunActivity.DEFAULT_METRICS_AND_CRASH_REPORTING); } else { mSendReportCheckBox.setVisibility(View.GONE); } mTosAndPrivacy.setMovementMethod(LinkMovementMethod.getInstance()); NoUnderlineClickableSpan clickableTermsSpan = new NoUnderlineClickableSpan() { @Override public void onClick(View widget) { if (!isAdded()) return; getPageDelegate() .showEmbedContentViewActivity( R.string.terms_of_service_title, R.string.chrome_terms_of_service_url); } }; NoUnderlineClickableSpan clickablePrivacySpan = new NoUnderlineClickableSpan() { @Override public void onClick(View widget) { if (!isAdded()) return; getPageDelegate() .showEmbedContentViewActivity( R.string.privacy_notice_title, R.string.chrome_privacy_notice_url); } }; mTosAndPrivacy.setText( SpanApplier.applySpans( getString(R.string.fre_tos_and_privacy), new SpanInfo("<LINK1>", "</LINK1>", clickableTermsSpan), new SpanInfo("<LINK2>", "</LINK2>", clickablePrivacySpan))); }
@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Intent intent = getIntent(); WebappInfo webappInfo = WebappInfo.create(intent); String webappId = webappInfo.id(); String webappUrl = webappInfo.uri().toString(); int webappSource = webappInfo.source(); if (webappId != null && webappUrl != null) { String webappMacString = IntentUtils.safeGetStringExtra(intent, ShortcutHelper.EXTRA_MAC); byte[] webappMac = webappMacString == null ? null : Base64.decode(webappMacString, Base64.DEFAULT); Intent launchIntent = null; if (webappMac != null && WebappAuthenticator.isUrlValid(this, webappUrl, webappMac)) { LaunchMetrics.recordHomeScreenLaunchIntoStandaloneActivity(webappUrl, webappSource); String activityName = WebappActivity.class.getName(); if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { // Specifically assign the app to a particular WebappActivity instance. int activityIndex = ActivityAssigner.instance(this).assign(webappId); activityName += String.valueOf(activityIndex); } // Create an intent to launch the Webapp in an unmapped WebappActivity. launchIntent = new Intent(); launchIntent.setClassName(this, activityName); webappInfo.setWebappIntentExtras(launchIntent); // On L+, firing intents with the exact same data should relaunch a particular // Activity. launchIntent.setAction(Intent.ACTION_VIEW); launchIntent.setData(Uri.parse(WebappActivity.WEBAPP_SCHEME + "://" + webappId)); } else { Log.e(TAG, "Shortcut (" + webappUrl + ") opened in Chrome."); // The shortcut data doesn't match the current encoding. Change the intent action // launch the URL with a VIEW Intent in the regular browser. launchIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(webappUrl)); launchIntent.setClassName(getPackageName(), ChromeLauncherActivity.class.getName()); launchIntent.putExtra(ShortcutHelper.REUSE_URL_MATCHING_TAB_ELSE_NEW_TAB, true); launchIntent.putExtra(ShortcutHelper.EXTRA_SOURCE, webappSource); } launchIntent.setFlags( Intent.FLAG_ACTIVITY_NEW_TASK | ApiCompatibilityUtils.getActivityNewDocumentFlag()); startActivity(launchIntent); } ApiCompatibilityUtils.finishAndRemoveTask(this); }
@Override public void updateVisualsForState() { Resources resources = getResources(); updateSecurityIcon(getSecurityLevel()); ColorStateList colorStateList = resources.getColorStateList( mUseDarkColors ? R.color.dark_mode_tint : R.color.light_mode_tint); mMenuButton.setTint(colorStateList); if (mCloseButton.getDrawable() instanceof TintedDrawable) { ((TintedDrawable) mCloseButton.getDrawable()).setTint(colorStateList); } if (mCustomActionButton.getDrawable() instanceof TintedDrawable) { ((TintedDrawable) mCustomActionButton.getDrawable()).setTint(colorStateList); } mUrlBar.setUseDarkTextColors(mUseDarkColors); int titleTextColor = mUseDarkColors ? resources.getColor(R.color.url_emphasis_default_text) : resources.getColor(R.color.url_emphasis_light_default_text); mTitleBar.setTextColor(titleTextColor); if (getProgressBar() != null) { int progressBarResource = !mUseDarkColors ? R.drawable.progress_bar_white : R.drawable.progress_bar; getProgressBar() .setProgressDrawable( ApiCompatibilityUtils.getDrawable(getResources(), progressBarResource)); } }
/** * Creates a standard toggle switch and adds it to the layout. * * <p>------------------------------------------------- | ICON | MESSAGE | TOGGLE | * ------------------------------------------------- If an icon is not provided, the ImageView * that would normally show it is hidden. * * @param iconResourceId ID of the drawable to use for the icon, or 0 to hide the ImageView. * @param iconColorId ID of the tint color for the icon, or 0 for default. * @param toggleMessage Message to display for the toggle. * @param toggleId ID to use for the toggle. * @param isChecked Whether the toggle should start off checked. */ public View addSwitch( int iconResourceId, int iconColorId, CharSequence toggleMessage, int toggleId, boolean isChecked) { LinearLayout switchLayout = (LinearLayout) LayoutInflater.from(getContext()).inflate(R.layout.infobar_control_toggle, this, false); addView(switchLayout, new ControlLayoutParams()); ImageView iconView = (ImageView) switchLayout.findViewById(R.id.control_icon); if (iconResourceId == 0) { switchLayout.removeView(iconView); } else { iconView.setImageResource(iconResourceId); if (iconColorId != 0) { iconView.setColorFilter(ApiCompatibilityUtils.getColor(getResources(), iconColorId)); } } TextView messageView = (TextView) switchLayout.findViewById(R.id.control_message); messageView.setText(toggleMessage); SwitchCompat switchView = (SwitchCompat) switchLayout.findViewById(R.id.control_toggle_switch); switchView.setId(toggleId); switchView.setChecked(isChecked); return switchLayout; }
/** * Adds an icon with a descriptive message to the layout. * * <p>----------------------------------------------------- | ICON | PRIMARY MESSAGE SECONDARY * MESSAGE | ----------------------------------------------------- If an icon is not provided, the * ImageView that would normally show it is hidden. * * @param iconResourceId ID of the drawable to use for the icon. * @param iconColorId ID of the tint color for the icon, or 0 for default. * @param primaryMessage Message to display for the toggle. * @param secondaryMessage Additional descriptive text for the toggle. May be null. */ public View addIcon( int iconResourceId, int iconColorId, CharSequence primaryMessage, CharSequence secondaryMessage) { LinearLayout layout = (LinearLayout) LayoutInflater.from(getContext()) .inflate(R.layout.infobar_control_icon_with_description, this, false); addView(layout, new ControlLayoutParams()); ImageView iconView = (ImageView) layout.findViewById(R.id.control_icon); iconView.setImageResource(iconResourceId); if (iconColorId != 0) { iconView.setColorFilter(ApiCompatibilityUtils.getColor(getResources(), iconColorId)); } // The primary message text is always displayed. TextView primaryView = (TextView) layout.findViewById(R.id.control_message); primaryView.setText(primaryMessage); // The secondary message text is optional. TextView secondaryView = (TextView) layout.findViewById(R.id.control_secondary_message); if (secondaryMessage == null) { layout.removeView(secondaryView); } else { secondaryView.setText(secondaryMessage); } return layout; }
/** * Adds one, two, or three buttons to the layout. * * @param primaryText Text for the primary button. * @param secondaryText Text for the secondary button, or null if there isn't a second button. * @param tertiaryText Text for the tertiary button, or null if there isn't a third button. */ public void setButtons(String primaryText, String secondaryText, String tertiaryText) { if (TextUtils.isEmpty(primaryText)) return; mPrimaryButton = new ButtonCompat(getContext(), mAccentColor); mPrimaryButton.setId(R.id.button_primary); mPrimaryButton.setOnClickListener(this); mPrimaryButton.setText(primaryText); mPrimaryButton.setTextColor(Color.WHITE); if (TextUtils.isEmpty(secondaryText)) return; mSecondaryButton = ButtonCompat.createBorderlessButton(getContext()); mSecondaryButton.setId(R.id.button_secondary); mSecondaryButton.setOnClickListener(this); mSecondaryButton.setText(secondaryText); mSecondaryButton.setTextColor(mAccentColor); if (TextUtils.isEmpty(tertiaryText)) return; mTertiaryButton = ButtonCompat.createBorderlessButton(getContext()); mTertiaryButton.setId(R.id.button_tertiary); mTertiaryButton.setOnClickListener(this); mTertiaryButton.setText(tertiaryText); mTertiaryButton.setPadding( mMargin / 2, mTertiaryButton.getPaddingTop(), mMargin / 2, mTertiaryButton.getPaddingBottom()); mTertiaryButton.setTextColor( ApiCompatibilityUtils.getColor( getContext().getResources(), R.color.infobar_tertiary_button_text)); }
/** * Checks if the First Run needs to be launched. * * @return The intent to launch the First Run Experience if necessary, or null. * @param context The context. * @param fromIntent The intent that was used to launch Chrome. * @param forLightweightFre Whether this is a check for the Lightweight First Run Experience. */ public static Intent checkIfFirstRunIsNecessary( Context context, Intent fromIntent, boolean forLightweightFre) { // If FRE is disabled (e.g. in tests), proceed directly to the intent handling. if (CommandLine.getInstance().hasSwitch(ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE) || ApiCompatibilityUtils.isDemoUser(context)) { return null; } // If Chrome isn't opened via the Chrome icon, and the user accepted the ToS // in the Setup Wizard, skip any First Run Experience screens and proceed directly // to the intent handling. final boolean fromChromeIcon = fromIntent != null && TextUtils.equals(fromIntent.getAction(), Intent.ACTION_MAIN); if (!fromChromeIcon && ToSAckedReceiver.checkAnyUserHasSeenToS(context)) return null; final boolean baseFreComplete = FirstRunStatus.getFirstRunFlowComplete(context); if (!baseFreComplete) { if (forLightweightFre && CommandLine.getInstance() .hasSwitch(ChromeSwitches.ENABLE_LIGHTWEIGHT_FIRST_RUN_EXPERIENCE)) { if (!FirstRunStatus.shouldSkipWelcomePage(context) && !FirstRunStatus.getLightweightFirstRunFlowComplete(context)) { return createLightweightFirstRunIntent(context, fromChromeIcon); } } else { return createGenericFirstRunIntent(context, fromChromeIcon); } } // Promo pages are removed, so there is nothing else to show in FRE. return null; }
/** * Constructs a layout for the specified InfoBar. After calling this, be sure to set the message, * the buttons, and/or the custom content using setMessage(), setButtons(), and * setCustomContent(). * * @param context The context used to render. * @param infoBarView InfoBarView that listens to events. * @param iconResourceId ID of the icon to use for the InfoBar. * @param iconBitmap Bitmap for the icon to use, if the resource ID wasn't passed through. * @param message The message to show in the infobar. */ public InfoBarLayout( Context context, InfoBarView infoBarView, int iconResourceId, Bitmap iconBitmap, CharSequence message) { super(context); mInfoBarView = infoBarView; // Grab the dimensions. Resources res = getResources(); mMargin = res.getDimensionPixelOffset(R.dimen.infobar_margin); mIconSize = res.getDimensionPixelSize(R.dimen.infobar_icon_size); mMinWidth = res.getDimensionPixelSize(R.dimen.infobar_min_width); mAccentColor = ApiCompatibilityUtils.getColor(res, R.color.infobar_accent_blue); // Set up the close button. Apply padding so it has a big touch target. mCloseButton = new ImageButton(context); mCloseButton.setId(R.id.infobar_close_button); mCloseButton.setImageResource(R.drawable.btn_close); TypedArray a = getContext().obtainStyledAttributes(new int[] {R.attr.selectableItemBackground}); Drawable closeButtonBackground = a.getDrawable(0); a.recycle(); mCloseButton.setBackground(closeButtonBackground); mCloseButton.setPadding(mMargin, mMargin, mMargin, mMargin); mCloseButton.setOnClickListener(this); mCloseButton.setContentDescription(res.getString(R.string.infobar_close)); mCloseButton.setLayoutParams(new LayoutParams(0, -mMargin, -mMargin, -mMargin)); // Set up the icon. if (iconResourceId != 0 || iconBitmap != null) { mIconView = new ImageView(context); if (iconResourceId != 0) { mIconView.setImageResource(iconResourceId); } else if (iconBitmap != null) { mIconView.setImageBitmap(iconBitmap); } mIconView.setLayoutParams(new LayoutParams(0, 0, mMargin / 2, 0)); mIconView.getLayoutParams().width = mIconSize; mIconView.getLayoutParams().height = mIconSize; mIconView.setFocusable(false); } // Set up the message view. mMessageTextView = (TextView) LayoutInflater.from(context).inflate(R.layout.infobar_text, null); mMessageTextView.setText(message, TextView.BufferType.SPANNABLE); mMessageTextView.setMovementMethod(LinkMovementMethod.getInstance()); mMessageTextView.setLinkTextColor(mAccentColor); mMessageView = mMessageTextView; }
/** * Displays Auto sign-in snackbar, which communicates to the users that they were signed in to the * web site. */ @CalledByNative private static void showSnackbar(Tab tab, String text) { SnackbarManager snackbarManager = tab.getSnackbarManager(); if (snackbarManager == null) return; AutoSigninSnackbarController snackbarController = new AutoSigninSnackbarController(snackbarManager, tab); Snackbar snackbar = Snackbar.make(text, snackbarController); Resources resources = tab.getWindowAndroid().getActivity().get().getResources(); int backgroundColor = ApiCompatibilityUtils.getColor( resources, R.color.smart_lock_auto_signin_snackbar_background_color); Bitmap icon = BitmapFactory.decodeResource(resources, R.drawable.account_management_no_picture); snackbar.setSingleLine(false).setBackgroundColor(backgroundColor).setProfileImage(icon); snackbarManager.showSnackbar(snackbar); }
@Override protected void updateBookmarkButton(boolean isBookmarked, boolean editingAllowed) { if (isBookmarked) { mBookmarkButton.setImageResource(R.drawable.btn_star_filled); // Non-incognito mode shows a blue filled star. mBookmarkButton.setTint( isIncognito() ? mLightModeTint : ApiCompatibilityUtils.getColorStateList(getResources(), R.color.blue_mode_tint)); } else { mBookmarkButton.setImageResource(R.drawable.btn_star); mBookmarkButton.setTint(isIncognito() ? mLightModeTint : mDarkModeTint); } mBookmarkButton.setEnabled(editingAllowed); }
@Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { int width = right - left; boolean isRtl = ApiCompatibilityUtils.isLayoutRtl(this); // Child positions were already determined during the measurement pass. for (int childIndex = 0; childIndex < getChildCount(); childIndex++) { View child = getChildAt(childIndex); int childLeft = getControlLayoutParams(child).start; if (isRtl) childLeft = width - childLeft - child.getMeasuredWidth(); int childTop = getControlLayoutParams(child).top; int childRight = childLeft + child.getMeasuredWidth(); int childBottom = childTop + child.getMeasuredHeight(); child.layout(childLeft, childTop, childRight, childBottom); } }
/** Starts determining parameters for the First Run. Once finished, calls onFlowIsKnown(). */ public void start() { if (CommandLine.getInstance().hasSwitch(ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE) || ApiCompatibilityUtils.isDemoUser(mActivity)) { onFlowIsKnown(null); return; } if (!mLaunchProperties.getBoolean(FirstRunActivity.EXTRA_USE_FRE_FLOW_SEQUENCER)) { onFlowIsKnown(mLaunchProperties); return; } new AndroidEduAndChildAccountHelper() { @Override public void onParametersReady() { processFreEnvironment(isAndroidEduDevice(), hasChildAccount()); } }.start(mActivity.getApplicationContext()); }
@Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { // Place all the views in the positions already determined during onMeasure(). int width = right - left; boolean isRtl = ApiCompatibilityUtils.isLayoutRtl(this); for (int i = 0; i < getChildCount(); i++) { View child = getChildAt(i); LayoutParams lp = (LayoutParams) child.getLayoutParams(); int childLeft = lp.start; int childRight = lp.start + child.getMeasuredWidth(); if (isRtl) { int tmp = width - childRight; childRight = width - childLeft; childLeft = tmp; } child.layout(childLeft, lp.top, childRight, lp.top + child.getMeasuredHeight()); } }
/** Shows the work profile badge if it is needed. */ private void addWorkProfileBadge(RemoteViews view) { Resources resources = mContext.getResources(); DisplayMetrics metrics = resources.getDisplayMetrics(); int size = dpToPx(WORK_PROFILE_BADGE_SIZE_DP, metrics); int[] colors = new int[size * size]; // Create an immutable bitmap, so that it can not be reused for painting a badge into it. Bitmap bitmap = Bitmap.createBitmap(colors, size, size, Bitmap.Config.ARGB_8888); Drawable inputDrawable = new BitmapDrawable(resources, bitmap); Drawable outputDrawable = ApiCompatibilityUtils.getUserBadgedDrawableForDensity( mContext, inputDrawable, null /* badgeLocation */, metrics.densityDpi); // The input bitmap is immutable, so the output drawable will be a different instance from // the input drawable if the work profile badge was applied. if (inputDrawable != outputDrawable && outputDrawable instanceof BitmapDrawable) { view.setImageViewBitmap( R.id.work_profile_badge, ((BitmapDrawable) outputDrawable).getBitmap()); view.setViewVisibility(R.id.work_profile_badge, View.VISIBLE); } }
/** * Creates an InterestsPage. * * @param context The view context for showing the page. * @param tab The tab from which interests page is loaded. * @param profile The profile from which to load interests. */ public InterestsPage(final Context context, Tab tab, Profile profile) { mTitle = context.getResources().getString(R.string.ntp_interests); mBackgroundColor = NtpColorUtils.getBackgroundColorResource(context.getResources(), false); mThemeColor = ApiCompatibilityUtils.getColor(context.getResources(), R.color.default_primary_color); mPageView = (InterestsView) View.inflate(context, R.layout.interests_page, null); new InterestsService(profile) .getInterests( new GetInterestsCallback() { @Override public void onInterestsAvailable(Interest[] interests) { boolean gotInterests = interests != null; RecordHistogram.recordBooleanHistogram( "NewTabPage.Interests.InterestsFetchSuccess", gotInterests); if (!gotInterests) { showToastOnFailure(); return; } List<Interest> interestList = Arrays.asList(interests); // We use sparse histograms here like in NewTabPage.Snippets.NumArticles, // NewTabPage.NumberOfTiles etc as this will measure a small number (< 30) // which is expected to be constant for a user and prefer exact counts // without defining artificial bucket boundaries. RecordHistogram.recordSparseSlowlyHistogram( "NewTabPage.Interests.NumInterests", interestList.size()); if (interestList.size() == 0) { showToastOnFailure(); return; } mPageView.setInterests(interestList); } private void showToastOnFailure() { Toast.makeText(context, R.string.ntp_no_interests_toast, Toast.LENGTH_SHORT).show(); } }); }
@Override public void onFinishInflate() { super.onFinishInflate(); mLocationBar = (LocationBar) findViewById(R.id.location_bar); mHomeButton = (TintedImageButton) findViewById(R.id.home_button); mBackButton = (TintedImageButton) findViewById(R.id.back_button); mForwardButton = (TintedImageButton) findViewById(R.id.forward_button); mReloadButton = (TintedImageButton) findViewById(R.id.refresh_button); mShowTabStack = DeviceClassManager.isAccessibilityModeEnabled(getContext()) || CommandLine.getInstance().hasSwitch(ChromeSwitches.ENABLE_TABLET_TAB_STACK); mTabSwitcherButtonDrawable = TabSwitcherDrawable.createTabSwitcherDrawable(getResources(), false); mTabSwitcherButtonDrawableLight = TabSwitcherDrawable.createTabSwitcherDrawable(getResources(), true); mAccessibilitySwitcherButton = (ImageButton) findViewById(R.id.tab_switcher_button); mAccessibilitySwitcherButton.setImageDrawable(mTabSwitcherButtonDrawable); updateSwitcherButtonVisibility(mShowTabStack); mBookmarkButton = (TintedImageButton) findViewById(R.id.bookmark_button); mMenuButton = (TintedImageButton) findViewById(R.id.menu_button); mMenuButtonWrapper.setVisibility(shouldShowMenuButton() ? View.VISIBLE : View.GONE); if (mAccessibilitySwitcherButton.getVisibility() == View.GONE && mMenuButtonWrapper.getVisibility() == View.GONE) { ApiCompatibilityUtils.setPaddingRelative( (View) mMenuButtonWrapper.getParent(), 0, 0, getResources().getDimensionPixelSize(R.dimen.tablet_toolbar_end_padding), 0); } }
/** * Test a basic printing flow by emulating the corresponding system calls to the printing * controller: onStart, onLayout, onWrite, onFinish. Each one is called once, and in this order, * in the UI thread. */ @TargetApi(Build.VERSION_CODES.KITKAT) @LargeTest @Feature({"Printing"}) public void testNormalPrintingFlow() throws Throwable { if (!ApiCompatibilityUtils.isPrintingSupported()) return; final ChromeShellTab currentTab = launchChromeShellWithUrl(URL).getActiveTab(); assertTrue(waitForActiveShellToBeDoneLoading()); final PrintingControllerImpl printingController = createControllerOnUiThread(); startControllerOnUiThread(printingController, currentTab); // {@link PrintDocumentAdapter#onStart} is always called first. callStartOnUiThread(printingController); // Create a temporary file to save the PDF. final File cacheDir = getInstrumentation().getTargetContext().getCacheDir(); final File tempFile = File.createTempFile(TEMP_FILE_NAME, TEMP_FILE_EXTENSION, cacheDir); final ParcelFileDescriptor fileDescriptor = ParcelFileDescriptor.open( tempFile, (ParcelFileDescriptor.MODE_CREATE | ParcelFileDescriptor.MODE_READ_WRITE)); PrintAttributes attributes = new PrintAttributes.Builder() .setMediaSize(PrintAttributes.MediaSize.ISO_A4) .setResolution(new PrintAttributes.Resolution("foo", "bar", 300, 300)) .setMinMargins(PrintAttributes.Margins.NO_MARGINS) .build(); // Use this to wait for PDF generation to complete, as it will happen asynchronously. final FutureTask<Boolean> result = new FutureTask<Boolean>( new Callable<Boolean>() { @Override public Boolean call() { return true; } }); callLayoutOnUiThread( printingController, null, attributes, new LayoutResultCallbackWrapperMock() { // Called on UI thread @Override public void onLayoutFinished(PrintDocumentInfo info, boolean changed) { callWriteOnUiThread(printingController, fileDescriptor, result); } }); FileInputStream in = null; try { // This blocks until the PDF is generated. result.get(TEST_TIMEOUT, TimeUnit.MILLISECONDS); assertTrue(tempFile.length() > 0); in = new FileInputStream(tempFile); byte[] b = new byte[PDF_PREAMBLE.length()]; in.read(b); String preamble = new String(b); assertEquals(PDF_PREAMBLE, preamble); } finally { callFinishOnUiThread(printingController); if (in != null) in.close(); // Close the descriptor, if not closed already. fileDescriptor.close(); TestFileUtil.deleteFile(tempFile.getAbsolutePath()); } }
/** * Creates and shows the app menu anchored to the specified view. * * @param context The context of the AppMenu (ensure the proper theme is set on this context). * @param anchorView The anchor {@link View} of the {@link ListPopupWindow}. * @param isByPermanentButton Whether or not permanent hardware button triggered it. (oppose to * software button or keyboard). * @param screenRotation Current device screen rotation. * @param visibleDisplayFrame The display area rect in which AppMenu is supposed to fit in. * @param screenHeight Current device screen height. * @param footerResourceId The resource id for a view to add to the end of the menu list. Can be 0 * if no such view is required. */ void show( Context context, View anchorView, boolean isByPermanentButton, int screenRotation, Rect visibleDisplayFrame, int screenHeight, int footerResourceId) { mPopup = new ListPopupWindow(context, null, android.R.attr.popupMenuStyle); mPopup.setModal(true); mPopup.setAnchorView(anchorView); mPopup.setInputMethodMode(PopupWindow.INPUT_METHOD_NOT_NEEDED); int footerHeight = 0; if (footerResourceId != 0) { mPopup.setPromptPosition(ListPopupWindow.POSITION_PROMPT_BELOW); View promptView = LayoutInflater.from(context).inflate(footerResourceId, null); mPopup.setPromptView(promptView); int measureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); promptView.measure(measureSpec, measureSpec); footerHeight = promptView.getMeasuredHeight(); } mPopup.setOnDismissListener( new OnDismissListener() { @Override public void onDismiss() { if (mPopup.getAnchorView() instanceof ImageButton) { ((ImageButton) mPopup.getAnchorView()).setSelected(false); } if (mMenuItemEnterAnimator != null) mMenuItemEnterAnimator.cancel(); mHandler.appMenuDismissed(); mHandler.onMenuVisibilityChanged(false); } }); // Some OEMs don't actually let us change the background... but they still return the // padding of the new background, which breaks the menu height. If we still have a // drawable here even though our style says @null we should use this padding instead... Drawable originalBgDrawable = mPopup.getBackground(); // Need to explicitly set the background here. Relying on it being set in the style caused // an incorrectly drawn background. if (isByPermanentButton) { mPopup.setBackgroundDrawable( ApiCompatibilityUtils.getDrawable(context.getResources(), R.drawable.menu_bg)); } else { mPopup.setBackgroundDrawable( ApiCompatibilityUtils.getDrawable(context.getResources(), R.drawable.edge_menu_bg)); mPopup.setAnimationStyle(R.style.OverflowMenuAnim); } // Turn off window animations for low end devices, and on Android M, which has built-in menu // animations. if (SysUtils.isLowEndDevice() || Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { mPopup.setAnimationStyle(0); } Rect bgPadding = new Rect(); mPopup.getBackground().getPadding(bgPadding); int popupWidth = context.getResources().getDimensionPixelSize(R.dimen.menu_width) + bgPadding.left + bgPadding.right; mPopup.setWidth(popupWidth); mCurrentScreenRotation = screenRotation; mIsByPermanentButton = isByPermanentButton; // Extract visible items from the Menu. int numItems = mMenu.size(); List<MenuItem> menuItems = new ArrayList<MenuItem>(); for (int i = 0; i < numItems; ++i) { MenuItem item = mMenu.getItem(i); if (item.isVisible()) { menuItems.add(item); } } Rect sizingPadding = new Rect(bgPadding); if (isByPermanentButton && originalBgDrawable != null) { Rect originalPadding = new Rect(); originalBgDrawable.getPadding(originalPadding); sizingPadding.top = originalPadding.top; sizingPadding.bottom = originalPadding.bottom; } // A List adapter for visible items in the Menu. The first row is added as a header to the // list view. mAdapter = new AppMenuAdapter(this, menuItems, LayoutInflater.from(context)); mPopup.setAdapter(mAdapter); setMenuHeight(menuItems.size(), visibleDisplayFrame, screenHeight, sizingPadding, footerHeight); setPopupOffset(mPopup, mCurrentScreenRotation, visibleDisplayFrame, sizingPadding); mPopup.setOnItemClickListener(this); mPopup.show(); mPopup.getListView().setItemsCanFocus(true); mPopup.getListView().setOnKeyListener(this); mHandler.onMenuVisibilityChanged(true); if (mVerticalFadeDistance > 0) { mPopup.getListView().setVerticalFadingEdgeEnabled(true); mPopup.getListView().setFadingEdgeLength(mVerticalFadeDistance); } // Don't animate the menu items for low end devices. if (!SysUtils.isLowEndDevice() && Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { mPopup .getListView() .addOnLayoutChangeListener( new View.OnLayoutChangeListener() { @Override public void onLayoutChange( View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) { mPopup.getListView().removeOnLayoutChangeListener(this); runMenuItemEnterAnimations(); } }); } }
@Override public View getView(int position, View convertView, ViewGroup parent) { View view = convertView; if (convertView == null) { view = mLayoutInflater.inflate(R.layout.search_engine, null); } view.setOnClickListener(this); view.setTag(position); // TODO(finnur): There's a tinting bug in the AppCompat lib (see http://crbug.com/474695), // which causes the first radiobox to always appear selected, even if it is not. It is being // addressed, but in the meantime we should use the native RadioButton instead. RadioButton radioButton = (RadioButton) view.findViewById(R.id.radiobutton); // On Lollipop this removes the redundant animation ring on selection but on older versions // it would cause the radio button to disappear. // TODO(finnur): Remove the encompassing if statement once we go back to using the AppCompat // control. final boolean selected = position == mSelectedSearchEnginePosition; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { radioButton.setBackgroundResource(0); } radioButton.setChecked(selected); TextView description = (TextView) view.findViewById(R.id.description); TemplateUrl templateUrl = mSearchEngines.get(position); Resources resources = mContext.getResources(); description.setText(templateUrl.getShortName()); // To improve the explore-by-touch experience, the radio button is hidden from accessibility // and instead, "checked" or "not checked" is read along with the search engine's name, e.g. // "google.com checked" or "google.com not checked". radioButton.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO); description.setAccessibilityDelegate( new AccessibilityDelegate() { @Override public void onInitializeAccessibilityEvent(View host, AccessibilityEvent event) { super.onInitializeAccessibilityEvent(host, event); event.setChecked(selected); } @Override public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) { super.onInitializeAccessibilityNodeInfo(host, info); info.setCheckable(true); info.setChecked(selected); } }); TextView link = (TextView) view.findViewById(R.id.link); link.setVisibility(selected ? View.VISIBLE : View.GONE); if (selected) { ForegroundColorSpan linkSpan = new ForegroundColorSpan( ApiCompatibilityUtils.getColor(resources, R.color.pref_accent_color)); if (LocationSettings.getInstance().isSystemLocationSettingEnabled()) { String message = mContext.getString( locationEnabled(position, true) ? R.string.search_engine_location_allowed : R.string.search_engine_location_blocked); SpannableString messageWithLink = new SpannableString(message); messageWithLink.setSpan(linkSpan, 0, messageWithLink.length(), 0); link.setText(messageWithLink); } else { link.setText( SpanApplier.applySpans( mContext.getString(R.string.android_location_off), new SpanInfo("<link>", "</link>", linkSpan))); } link.setOnClickListener(this); } return view; }
private void updateLayoutParams() { int startMargin = 0; int locationBarLayoutChildIndex = -1; for (int i = 0; i < getChildCount(); i++) { View childView = getChildAt(i); if (childView.getVisibility() != GONE) { LayoutParams childLayoutParams = (LayoutParams) childView.getLayoutParams(); if (ApiCompatibilityUtils.getMarginStart(childLayoutParams) != startMargin) { ApiCompatibilityUtils.setMarginStart(childLayoutParams, startMargin); childView.setLayoutParams(childLayoutParams); } if (childView == mLocationBarFrameLayout) { locationBarLayoutChildIndex = i; break; } int widthMeasureSpec; int heightMeasureSpec; if (childLayoutParams.width == LayoutParams.WRAP_CONTENT) { widthMeasureSpec = MeasureSpec.makeMeasureSpec(getMeasuredWidth(), MeasureSpec.AT_MOST); } else if (childLayoutParams.width == LayoutParams.MATCH_PARENT) { widthMeasureSpec = MeasureSpec.makeMeasureSpec(getMeasuredWidth(), MeasureSpec.EXACTLY); } else { widthMeasureSpec = MeasureSpec.makeMeasureSpec(childLayoutParams.width, MeasureSpec.EXACTLY); } if (childLayoutParams.height == LayoutParams.WRAP_CONTENT) { heightMeasureSpec = MeasureSpec.makeMeasureSpec(getMeasuredHeight(), MeasureSpec.AT_MOST); } else if (childLayoutParams.height == LayoutParams.MATCH_PARENT) { heightMeasureSpec = MeasureSpec.makeMeasureSpec(getMeasuredHeight(), MeasureSpec.EXACTLY); } else { heightMeasureSpec = MeasureSpec.makeMeasureSpec(childLayoutParams.height, MeasureSpec.EXACTLY); } childView.measure(widthMeasureSpec, heightMeasureSpec); startMargin += childView.getMeasuredWidth(); } } assert locationBarLayoutChildIndex != -1; int locationBarLayoutEndMargin = 0; for (int i = locationBarLayoutChildIndex + 1; i < getChildCount(); i++) { View childView = getChildAt(i); if (childView.getVisibility() != GONE) { locationBarLayoutEndMargin += childView.getMeasuredWidth(); } } LayoutParams urlLayoutParams = (LayoutParams) mLocationBarFrameLayout.getLayoutParams(); if (ApiCompatibilityUtils.getMarginEnd(urlLayoutParams) != locationBarLayoutEndMargin) { ApiCompatibilityUtils.setMarginEnd(urlLayoutParams, locationBarLayoutEndMargin); mLocationBarFrameLayout.setLayoutParams(urlLayoutParams); } // Update left margin of mTitleUrlContainer here to make sure the security icon is always // placed left of the urlbar. LayoutParams lp = (LayoutParams) mTitleUrlContainer.getLayoutParams(); if (mSecurityButton.getVisibility() == View.GONE) { lp.leftMargin = 0; } else { lp.leftMargin = mSecurityButton.getMeasuredWidth(); } mTitleUrlContainer.setLayoutParams(lp); }
/** Updates the title of chrome shown in recent tasks. It only takes effect in document mode. */ public static void setTaskDescriptionInDocumentMode(Activity activity, String description) { if (FeatureUtilities.isDocumentMode(activity)) { // Setting icon to be null and color to be 0 will means "take no effect". ApiCompatibilityUtils.setTaskDescription(activity, description, null, 0); } }
/** * Pushes all relevant {@link LayoutTab}s from a {@link Layout} to the CC Layer tree. This will * let them be rendered on the screen. This should only be called when the Compositor has disabled * ScheduleComposite calls as this will change the tree and could subsequently cause unnecessary * follow up renders. * * @param context The {@link Context} to use to query device information. * @param layout The {@link Layout} to push to the screen. */ public void pushLayers( Context context, Rect viewport, Rect contentViewport, Layout layout, LayerTitleCache layerTitleCache, TabContentManager tabContentManager, ResourceManager resourceManager) { if (mNativePtr == 0) return; Resources res = context.getResources(); final float dpToPx = res.getDisplayMetrics().density; LayoutTab[] tabs = layout.getLayoutTabsToRender(); int tabsCount = tabs != null ? tabs.length : 0; nativeBeginBuildingFrame(mNativePtr); for (int i = 0; i < tabsCount; i++) { LayoutTab t = tabs[i]; assert t.isVisible() : "LayoutTab in that list should be visible"; final float decoration = t.getDecorationAlpha(); int borderResource = t.isIncognito() ? R.drawable.tabswitcher_border_frame_incognito : R.drawable.tabswitcher_border_frame; int closeBtnResource = t.isIncognito() ? R.drawable.btn_tab_close_white_normal : R.drawable.btn_tab_close_normal; int borderColorResource = t.isIncognito() ? R.color.tab_back_incognito : R.color.tab_back; // TODO(dtrainor, clholgat): remove "* dpToPx" once the native part fully supports dp. nativePutLayer( mNativePtr, t.getId(), R.id.control_container, closeBtnResource, R.drawable.tabswitcher_border_frame_shadow, R.drawable.tabswitcher_border_frame_decoration, R.drawable.logo_card_back, borderResource, t.canUseLiveTexture(), (t.getFallbackThumbnailId() == ChromeTab.NTP_TAB_ID), t.getBackgroundColor(), ApiCompatibilityUtils.getColor(res, R.color.tab_switcher_background), ApiCompatibilityUtils.getColor(res, borderColorResource), t.isIncognito(), layout.getOrientation() == Orientation.PORTRAIT, t.getRenderX() * dpToPx, t.getRenderY() * dpToPx, t.getScaledContentWidth() * dpToPx, t.getScaledContentHeight() * dpToPx, t.getOriginalContentWidth() * dpToPx, t.getOriginalContentHeight() * dpToPx, contentViewport.height(), viewport.left, viewport.top, viewport.width(), viewport.height(), t.getClippedX() * dpToPx, t.getClippedY() * dpToPx, Math.min(t.getClippedWidth(), t.getScaledContentWidth()) * dpToPx, Math.min(t.getClippedHeight(), t.getScaledContentHeight()) * dpToPx, t.getTiltXPivotOffset() * dpToPx, t.getTiltYPivotOffset() * dpToPx, t.getTiltX(), t.getTiltY(), t.getAlpha(), t.getBorderAlpha() * decoration, decoration, t.getShadowOpacity() * decoration, t.getBorderCloseButtonAlpha() * decoration, LayoutTab.CLOSE_BUTTON_WIDTH_DP * dpToPx, t.getStaticToViewBlend(), t.getBorderScale(), t.getSaturation(), t.getBrightness(), t.showToolbar(), t.anonymizeToolbar(), t.getTextBoxBackgroundColor(), t.getToolbarAlpha(), t.getToolbarYOffset() * dpToPx, t.getSideBorderScale(), true, t.insetBorderVertical(), layerTitleCache, tabContentManager, resourceManager); } nativeFinishBuildingFrame(mNativePtr); }
@VisibleForTesting protected boolean shouldSkipFirstUseHints() { return ApiCompatibilityUtils.shouldSkipFirstUseHints(mActivity.getContentResolver()); }