1a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev/* 2a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev * Copyright (C) 2017 The Android Open Source Project 3a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev * 4a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev * Licensed under the Apache License, Version 2.0 (the "License"); 5a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev * you may not use this file except in compliance with the License. 6a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev * You may obtain a copy of the License at 7a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev * 8a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev * http://www.apache.org/licenses/LICENSE-2.0 9a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev * 10a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev * Unless required by applicable law or agreed to in writing, software 11a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev * distributed under the License is distributed on an "AS IS" BASIS, 12a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev * See the License for the specific language governing permissions and 14a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev * limitations under the License. 15a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev */ 16a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev 17ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikaspackage androidx.appcompat.widget; 18a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev 19ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP; 20a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev 21a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheevimport android.app.Activity; 22a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheevimport android.content.Context; 23a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheevimport android.content.ContextWrapper; 24a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheevimport android.content.res.Resources; 25a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheevimport android.graphics.PixelFormat; 26a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheevimport android.graphics.Rect; 27a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheevimport android.util.DisplayMetrics; 28a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheevimport android.util.Log; 29a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheevimport android.view.Gravity; 30a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheevimport android.view.LayoutInflater; 31a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheevimport android.view.View; 32b607c1d938533c862a0470eda3ffc25ecc8101d9Vladislav Kaznacheevimport android.view.ViewGroup; 33a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheevimport android.view.WindowManager; 34a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheevimport android.widget.TextView; 35a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev 363de8a4e8305507475d7890205184946a25cf45e7Aurimas Liutikasimport androidx.annotation.RestrictTo; 373de8a4e8305507475d7890205184946a25cf45e7Aurimas Liutikasimport androidx.appcompat.R; 383de8a4e8305507475d7890205184946a25cf45e7Aurimas Liutikas 39a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev/** 40a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev * A popup window displaying a text message aligned to a specified view. 41a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev * 42a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev * @hide 43a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev */ 44a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev@RestrictTo(LIBRARY_GROUP) 45a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheevclass TooltipPopup { 46a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev private static final String TAG = "TooltipPopup"; 47a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev 48a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev private final Context mContext; 49a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev 50a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev private final View mContentView; 51a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev private final TextView mMessageView; 52a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev 53a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev private final WindowManager.LayoutParams mLayoutParams = new WindowManager.LayoutParams(); 54a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev private final Rect mTmpDisplayFrame = new Rect(); 55a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev private final int[] mTmpAnchorPos = new int[2]; 56a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev private final int[] mTmpAppPos = new int[2]; 57a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev 58a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev TooltipPopup(Context context) { 59a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev mContext = context; 60a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev 617e4cce488592095f820da1bdf70497bb84b808f8Vladislav Kaznacheev mContentView = LayoutInflater.from(mContext).inflate(R.layout.abc_tooltip, null); 62a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev mMessageView = (TextView) mContentView.findViewById(R.id.message); 63a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev 64a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev mLayoutParams.setTitle(getClass().getSimpleName()); 65a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev mLayoutParams.packageName = mContext.getPackageName(); 66a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev mLayoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL; 67a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev mLayoutParams.width = WindowManager.LayoutParams.WRAP_CONTENT; 68a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev mLayoutParams.height = WindowManager.LayoutParams.WRAP_CONTENT; 69a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev mLayoutParams.format = PixelFormat.TRANSLUCENT; 70a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev mLayoutParams.windowAnimations = R.style.Animation_AppCompat_Tooltip; 71a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev mLayoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE 72a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE; 73a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev } 74a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev 75a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev void show(View anchorView, int anchorX, int anchorY, boolean fromTouch, 76a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev CharSequence tooltipText) { 77a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev if (isShowing()) { 78a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev hide(); 79a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev } 80a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev 81a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev mMessageView.setText(tooltipText); 82a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev 83a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev computePosition(anchorView, anchorX, anchorY, fromTouch, mLayoutParams); 84a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev 85a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev WindowManager wm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE); 86a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev wm.addView(mContentView, mLayoutParams); 87a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev } 88a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev 89a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev void hide() { 90a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev if (!isShowing()) { 91a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev return; 92a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev } 93a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev 94a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev WindowManager wm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE); 95a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev wm.removeView(mContentView); 96a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev } 97a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev 98a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev boolean isShowing() { 99a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev return mContentView.getParent() != null; 100a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev } 101a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev 102a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev private void computePosition(View anchorView, int anchorX, int anchorY, boolean fromTouch, 103a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev WindowManager.LayoutParams outParams) { 104b607c1d938533c862a0470eda3ffc25ecc8101d9Vladislav Kaznacheev outParams.token = anchorView.getApplicationWindowToken(); 105a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev final int tooltipPreciseAnchorThreshold = mContext.getResources().getDimensionPixelOffset( 106a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev R.dimen.tooltip_precise_anchor_threshold); 107a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev 108a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev final int offsetX; 109a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev if (anchorView.getWidth() >= tooltipPreciseAnchorThreshold) { 110a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev // Wide view. Align the tooltip horizontally to the precise X position. 111a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev offsetX = anchorX; 112a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev } else { 113a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev // Otherwise anchor the tooltip to the view center. 114a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev offsetX = anchorView.getWidth() / 2; // Center on the view horizontally. 115a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev } 116a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev 117a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev final int offsetBelow; 118a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev final int offsetAbove; 119a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev if (anchorView.getHeight() >= tooltipPreciseAnchorThreshold) { 120a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev // Tall view. Align the tooltip vertically to the precise Y position. 121a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev final int offsetExtra = mContext.getResources().getDimensionPixelOffset( 122a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev R.dimen.tooltip_precise_anchor_extra_offset); 123a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev offsetBelow = anchorY + offsetExtra; 124a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev offsetAbove = anchorY - offsetExtra; 125a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev } else { 126a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev // Otherwise anchor the tooltip to the view center. 127a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev offsetBelow = anchorView.getHeight(); // Place below the view in most cases. 128a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev offsetAbove = 0; // Place above the view if the tooltip does not fit below. 129a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev } 130a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev 131a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev outParams.gravity = Gravity.CENTER_HORIZONTAL | Gravity.TOP; 132a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev 133a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev final int tooltipOffset = mContext.getResources().getDimensionPixelOffset( 134a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev fromTouch ? R.dimen.tooltip_y_offset_touch : R.dimen.tooltip_y_offset_non_touch); 135a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev 136a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev final View appView = getAppRootView(anchorView); 137a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev if (appView == null) { 138a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev Log.e(TAG, "Cannot find app view"); 139a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev return; 140a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev } 141a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev appView.getWindowVisibleDisplayFrame(mTmpDisplayFrame); 142a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev if (mTmpDisplayFrame.left < 0 && mTmpDisplayFrame.top < 0) { 143a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev // No meaningful display frame, the anchor view is probably in a subpanel 144a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev // (such as a popup window). Use the screen frame as a reasonable approximation. 145a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev final Resources res = mContext.getResources(); 146a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev final int statusBarHeight; 147a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev int resourceId = res.getIdentifier("status_bar_height", "dimen", "android"); 14827498b224061104ba9f5f388c7c838cf0bee4af4Adam Lesinski if (resourceId != 0) { 149a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev statusBarHeight = res.getDimensionPixelSize(resourceId); 150a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev } else { 151a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev statusBarHeight = 0; 152a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev } 153a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev final DisplayMetrics metrics = res.getDisplayMetrics(); 154a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev mTmpDisplayFrame.set(0, statusBarHeight, metrics.widthPixels, metrics.heightPixels); 155a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev } 156a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev appView.getLocationOnScreen(mTmpAppPos); 157a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev 158a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev anchorView.getLocationOnScreen(mTmpAnchorPos); 159a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev mTmpAnchorPos[0] -= mTmpAppPos[0]; 160a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev mTmpAnchorPos[1] -= mTmpAppPos[1]; 161a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev // mTmpAnchorPos is now relative to the main app window. 162a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev 163b607c1d938533c862a0470eda3ffc25ecc8101d9Vladislav Kaznacheev outParams.x = mTmpAnchorPos[0] + offsetX - appView.getWidth() / 2; 164a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev 165a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev final int spec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED); 166a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev mContentView.measure(spec, spec); 167a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev final int tooltipHeight = mContentView.getMeasuredHeight(); 168a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev 169a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev final int yAbove = mTmpAnchorPos[1] + offsetAbove - tooltipOffset - tooltipHeight; 170a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev final int yBelow = mTmpAnchorPos[1] + offsetBelow + tooltipOffset; 171a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev if (fromTouch) { 172a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev if (yAbove >= 0) { 173a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev outParams.y = yAbove; 174a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev } else { 175a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev outParams.y = yBelow; 176a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev } 177a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev } else { 178a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev if (yBelow + tooltipHeight <= mTmpDisplayFrame.height()) { 179a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev outParams.y = yBelow; 180a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev } else { 181a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev outParams.y = yAbove; 182a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev } 183a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev } 184a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev } 185a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev 186a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev private static View getAppRootView(View anchorView) { 187b607c1d938533c862a0470eda3ffc25ecc8101d9Vladislav Kaznacheev View rootView = anchorView.getRootView(); 188b607c1d938533c862a0470eda3ffc25ecc8101d9Vladislav Kaznacheev ViewGroup.LayoutParams lp = rootView.getLayoutParams(); 189b607c1d938533c862a0470eda3ffc25ecc8101d9Vladislav Kaznacheev if (lp instanceof WindowManager.LayoutParams 190b607c1d938533c862a0470eda3ffc25ecc8101d9Vladislav Kaznacheev && (((WindowManager.LayoutParams) lp).type 191b607c1d938533c862a0470eda3ffc25ecc8101d9Vladislav Kaznacheev == WindowManager.LayoutParams.TYPE_APPLICATION)) { 192b607c1d938533c862a0470eda3ffc25ecc8101d9Vladislav Kaznacheev // This covers regular app windows and Dialog windows. 193b607c1d938533c862a0470eda3ffc25ecc8101d9Vladislav Kaznacheev return rootView; 194b607c1d938533c862a0470eda3ffc25ecc8101d9Vladislav Kaznacheev } 195b607c1d938533c862a0470eda3ffc25ecc8101d9Vladislav Kaznacheev // For non-application window types (such as popup windows) try to find the main app window 196b607c1d938533c862a0470eda3ffc25ecc8101d9Vladislav Kaznacheev // through the context. 197a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev Context context = anchorView.getContext(); 198a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev while (context instanceof ContextWrapper) { 199a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev if (context instanceof Activity) { 200a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev return ((Activity) context).getWindow().getDecorView(); 201a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev } else { 202a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev context = ((ContextWrapper) context).getBaseContext(); 203a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev } 204a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev } 205b607c1d938533c862a0470eda3ffc25ecc8101d9Vladislav Kaznacheev // Main app window not found, fall back to the anchor's root view. There is no guarantee 206b607c1d938533c862a0470eda3ffc25ecc8101d9Vladislav Kaznacheev // that the tooltip position will be computed correctly. 207b607c1d938533c862a0470eda3ffc25ecc8101d9Vladislav Kaznacheev return rootView; 208a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev } 209a4c6825b4b077cb12adb4f14b825001b6fd0e865Vladislav Kaznacheev} 210