1 package com.xtremelabs.robolectric.shadows; 2 3 import android.app.Activity; 4 import android.app.Dialog; 5 import android.content.Context; 6 import android.content.DialogInterface; 7 import android.os.Bundle; 8 import android.view.LayoutInflater; 9 import android.view.View; 10 import android.view.ViewGroup; 11 import android.view.Window; 12 import com.xtremelabs.robolectric.Robolectric; 13 import com.xtremelabs.robolectric.internal.Implementation; 14 import com.xtremelabs.robolectric.internal.Implements; 15 import com.xtremelabs.robolectric.internal.RealObject; 16 import com.xtremelabs.robolectric.tester.android.view.TestWindow; 17 18 import java.lang.reflect.Method; 19 import java.util.ArrayList; 20 import java.util.List; 21 22 import static com.xtremelabs.robolectric.Robolectric.shadowOf; 23 24 @SuppressWarnings({"UnusedDeclaration"}) 25 @Implements(Dialog.class) 26 public class ShadowDialog { 27 28 @RealObject private Dialog realDialog; 29 30 private boolean isShowing; 31 Context context; 32 private int layoutId; 33 private int themeId; 34 private View inflatedView; 35 private boolean hasBeenDismissed; 36 private DialogInterface.OnDismissListener onDismissListener; 37 protected CharSequence title; 38 private DialogInterface.OnCancelListener onCancelListener; 39 private Window window; 40 private Activity ownerActivity; 41 private boolean isCancelable = true; 42 private boolean hasShownBefore; 43 private static final ArrayList<Dialog> shownDialogs = new ArrayList<Dialog>(); 44 private boolean isCancelableOnTouchOutside; 45 reset()46 public static void reset() { 47 setLatestDialog(null); 48 shownDialogs.clear(); 49 } 50 getLatestDialog()51 public static Dialog getLatestDialog() { 52 ShadowDialog dialog = Robolectric.getShadowApplication().getLatestDialog(); 53 return dialog == null ? null : dialog.realDialog; 54 } 55 setLatestDialog(ShadowDialog latestDialog)56 public static void setLatestDialog(ShadowDialog latestDialog) { 57 Robolectric.getShadowApplication().setLatestDialog(latestDialog); 58 } 59 __constructor__(Context context)60 public void __constructor__(Context context) { 61 __constructor__(context, -1); 62 } 63 __constructor__(Context context, int themeId)64 public void __constructor__(Context context, int themeId) { 65 this.context = context; 66 this.themeId = themeId; 67 } 68 69 @Implementation setContentView(int layoutResID)70 public void setContentView(int layoutResID) { 71 layoutId = layoutResID; 72 } 73 74 @Implementation setContentView(View view)75 public void setContentView(View view) { 76 inflatedView = view; 77 } 78 79 @Implementation setTitle(int stringResourceId)80 public void setTitle(int stringResourceId) { 81 this.title = context.getResources().getText(stringResourceId); 82 } 83 84 @Implementation(i18nSafe = false) setTitle(CharSequence title)85 public void setTitle(CharSequence title) { 86 this.title = title; 87 } 88 89 @Implementation setOwnerActivity(Activity activity)90 public void setOwnerActivity(Activity activity) { 91 this.ownerActivity = activity; 92 } 93 94 @Implementation getOwnerActivity()95 public Activity getOwnerActivity() { 96 return this.ownerActivity; 97 } 98 99 @Implementation getContext()100 public Context getContext() { 101 return context; 102 } 103 104 @Implementation onBackPressed()105 public void onBackPressed() { 106 cancel(); 107 } 108 109 @Implementation show()110 public void show() { 111 setLatestDialog(this); 112 shownDialogs.add(realDialog); 113 isShowing = true; 114 try { 115 if (!hasShownBefore) { 116 Method onCreateMethod = Dialog.class.getDeclaredMethod("onCreate", Bundle.class); 117 onCreateMethod.setAccessible(true); 118 onCreateMethod.invoke(realDialog, (Bundle) null); 119 } 120 121 Method onStartMethod = Dialog.class.getDeclaredMethod("onStart"); 122 onStartMethod.setAccessible(true); 123 onStartMethod.invoke(realDialog); 124 } catch (Exception e) { 125 throw new RuntimeException(e); 126 } 127 hasShownBefore = true; 128 } 129 130 @Implementation hide()131 public void hide() { 132 isShowing = false; 133 } 134 135 @Implementation isShowing()136 public boolean isShowing() { 137 return isShowing; 138 } 139 140 @Implementation dismiss()141 public void dismiss() { 142 isShowing = false; 143 hasBeenDismissed = true; 144 145 if (onDismissListener != null) { 146 onDismissListener.onDismiss(realDialog); 147 } 148 } 149 150 @Implementation findViewById(int viewId)151 public View findViewById(int viewId) { 152 if (inflatedView != null) { 153 return inflatedView.findViewById(viewId); 154 } 155 if (layoutId > 0 && context != null) { 156 inflatedView = ShadowLayoutInflater.from(context).inflate(layoutId, null); 157 return inflatedView.findViewById(viewId); 158 } 159 return null; 160 } 161 clickOn(int viewId)162 public void clickOn(int viewId) { 163 findViewById(viewId).performClick(); 164 } 165 166 @Implementation setOnDismissListener(DialogInterface.OnDismissListener onDismissListener)167 public void setOnDismissListener(DialogInterface.OnDismissListener onDismissListener) { 168 this.onDismissListener = onDismissListener; 169 } 170 171 @Implementation setCancelable(boolean flag)172 public void setCancelable(boolean flag) { 173 isCancelable = flag; 174 } 175 176 @Implementation setCanceledOnTouchOutside(boolean flag)177 public void setCanceledOnTouchOutside(boolean flag) { 178 isCancelableOnTouchOutside = flag; 179 } 180 isCancelable()181 public boolean isCancelable() { 182 return isCancelable; 183 } 184 isCancelableOnTouchOutside()185 public boolean isCancelableOnTouchOutside() { 186 return isCancelableOnTouchOutside; 187 } 188 189 @Implementation cancel()190 public void cancel() { 191 if (onCancelListener != null) { 192 onCancelListener.onCancel(realDialog); 193 } 194 realDialog.dismiss(); 195 } 196 197 @Implementation setOnCancelListener(DialogInterface.OnCancelListener listener)198 public void setOnCancelListener(DialogInterface.OnCancelListener listener) { 199 this.onCancelListener = listener; 200 } 201 getOnCancelListener()202 public DialogInterface.OnCancelListener getOnCancelListener() { 203 return onCancelListener; 204 } 205 206 @Implementation getWindow()207 public Window getWindow() { 208 if (window == null) { 209 window = new TestWindow(realDialog.getContext()); 210 } 211 return window; 212 } 213 214 215 @Implementation getLayoutInflater()216 public LayoutInflater getLayoutInflater() { 217 return LayoutInflater.from(realDialog.getContext()); 218 } 219 getLayoutId()220 public int getLayoutId() { 221 return layoutId; 222 } 223 getThemeId()224 public int getThemeId() { 225 return themeId; 226 } 227 hasBeenDismissed()228 public boolean hasBeenDismissed() { 229 return hasBeenDismissed; 230 } 231 getTitle()232 public CharSequence getTitle() { 233 return title; 234 } 235 clickOnText(int textId)236 public void clickOnText(int textId) { 237 if (inflatedView == null) { 238 inflatedView = ShadowLayoutInflater.from(context).inflate(layoutId, null); 239 } 240 String text = getContext().getResources().getString(textId); 241 if (!clickOnText(inflatedView, text)) { 242 throw new IllegalArgumentException("Text not found: " + text); 243 } 244 } 245 clickOnText(View view, String text)246 private boolean clickOnText(View view, String text) { 247 if (text.equals(shadowOf(view).innerText())) { 248 view.performClick(); 249 return true; 250 } 251 if (view instanceof ViewGroup) { 252 ViewGroup viewGroup = (ViewGroup) view; 253 for (int i = 0; i < viewGroup.getChildCount(); i++) { 254 View child = viewGroup.getChildAt(i); 255 if (clickOnText(child, text)) { 256 return true; 257 } 258 } 259 } 260 return false; 261 } 262 getShownDialogs()263 public static List<Dialog> getShownDialogs() { 264 return shownDialogs; 265 } 266 } 267