1package com.xtremelabs.robolectric.shadows; 2 3import android.app.Activity; 4import android.app.Dialog; 5import android.content.Context; 6import android.content.DialogInterface; 7import android.os.Bundle; 8import android.view.LayoutInflater; 9import android.view.View; 10import android.view.ViewGroup; 11import android.view.Window; 12import com.xtremelabs.robolectric.Robolectric; 13import com.xtremelabs.robolectric.internal.Implementation; 14import com.xtremelabs.robolectric.internal.Implements; 15import com.xtremelabs.robolectric.internal.RealObject; 16import com.xtremelabs.robolectric.tester.android.view.TestWindow; 17 18import java.lang.reflect.Method; 19import java.util.ArrayList; 20import java.util.List; 21 22import static com.xtremelabs.robolectric.Robolectric.shadowOf; 23 24@SuppressWarnings({"UnusedDeclaration"}) 25@Implements(Dialog.class) 26public 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 46 public static void reset() { 47 setLatestDialog(null); 48 shownDialogs.clear(); 49 } 50 51 public static Dialog getLatestDialog() { 52 ShadowDialog dialog = Robolectric.getShadowApplication().getLatestDialog(); 53 return dialog == null ? null : dialog.realDialog; 54 } 55 56 public static void setLatestDialog(ShadowDialog latestDialog) { 57 Robolectric.getShadowApplication().setLatestDialog(latestDialog); 58 } 59 60 public void __constructor__(Context context) { 61 __constructor__(context, -1); 62 } 63 64 public void __constructor__(Context context, int themeId) { 65 this.context = context; 66 this.themeId = themeId; 67 } 68 69 @Implementation 70 public void setContentView(int layoutResID) { 71 layoutId = layoutResID; 72 } 73 74 @Implementation 75 public void setContentView(View view) { 76 inflatedView = view; 77 } 78 79 @Implementation 80 public void setTitle(int stringResourceId) { 81 this.title = context.getResources().getText(stringResourceId); 82 } 83 84 @Implementation(i18nSafe = false) 85 public void setTitle(CharSequence title) { 86 this.title = title; 87 } 88 89 @Implementation 90 public void setOwnerActivity(Activity activity) { 91 this.ownerActivity = activity; 92 } 93 94 @Implementation 95 public Activity getOwnerActivity() { 96 return this.ownerActivity; 97 } 98 99 @Implementation 100 public Context getContext() { 101 return context; 102 } 103 104 @Implementation 105 public void onBackPressed() { 106 cancel(); 107 } 108 109 @Implementation 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 131 public void hide() { 132 isShowing = false; 133 } 134 135 @Implementation 136 public boolean isShowing() { 137 return isShowing; 138 } 139 140 @Implementation 141 public void dismiss() { 142 isShowing = false; 143 hasBeenDismissed = true; 144 145 if (onDismissListener != null) { 146 onDismissListener.onDismiss(realDialog); 147 } 148 } 149 150 @Implementation 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 162 public void clickOn(int viewId) { 163 findViewById(viewId).performClick(); 164 } 165 166 @Implementation 167 public void setOnDismissListener(DialogInterface.OnDismissListener onDismissListener) { 168 this.onDismissListener = onDismissListener; 169 } 170 171 @Implementation 172 public void setCancelable(boolean flag) { 173 isCancelable = flag; 174 } 175 176 @Implementation 177 public void setCanceledOnTouchOutside(boolean flag) { 178 isCancelableOnTouchOutside = flag; 179 } 180 181 public boolean isCancelable() { 182 return isCancelable; 183 } 184 185 public boolean isCancelableOnTouchOutside() { 186 return isCancelableOnTouchOutside; 187 } 188 189 @Implementation 190 public void cancel() { 191 if (onCancelListener != null) { 192 onCancelListener.onCancel(realDialog); 193 } 194 realDialog.dismiss(); 195 } 196 197 @Implementation 198 public void setOnCancelListener(DialogInterface.OnCancelListener listener) { 199 this.onCancelListener = listener; 200 } 201 202 public DialogInterface.OnCancelListener getOnCancelListener() { 203 return onCancelListener; 204 } 205 206 @Implementation 207 public Window getWindow() { 208 if (window == null) { 209 window = new TestWindow(realDialog.getContext()); 210 } 211 return window; 212 } 213 214 215 @Implementation 216 public LayoutInflater getLayoutInflater() { 217 return LayoutInflater.from(realDialog.getContext()); 218 } 219 220 public int getLayoutId() { 221 return layoutId; 222 } 223 224 public int getThemeId() { 225 return themeId; 226 } 227 228 public boolean hasBeenDismissed() { 229 return hasBeenDismissed; 230 } 231 232 public CharSequence getTitle() { 233 return title; 234 } 235 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 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 263 public static List<Dialog> getShownDialogs() { 264 return shownDialogs; 265 } 266} 267