1 /*
2  * Copyright (C) 2010 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.app;
18 
19 import com.android.ide.common.rendering.api.LayoutlibCallback;
20 import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
21 
22 import android.content.Context;
23 import android.os.Bundle;
24 
25 /**
26  * Delegate used to provide new implementation of a select few methods of {@link Fragment}
27  *
28  * Through the layoutlib_create tool, the original  methods of Fragment have been replaced
29  * by calls to methods of the same name in this delegate class.
30  *
31  * The methods being re-implemented are the ones responsible for instantiating Fragment objects.
32  * Because the classes of these objects are found in the project, these methods need access to
33  * {@link LayoutlibCallback} object. They are however static methods, so the callback is set
34  * before the inflation through {@link #setLayoutlibCallback(LayoutlibCallback)}.
35  */
36 public class Fragment_Delegate {
37 
38     private static LayoutlibCallback sLayoutlibCallback;
39 
40     /**
41      * Sets the current {@link LayoutlibCallback} to be used to instantiate classes coming
42      * from the project being rendered.
43      */
setLayoutlibCallback(LayoutlibCallback layoutlibCallback)44     public static void setLayoutlibCallback(LayoutlibCallback layoutlibCallback) {
45         sLayoutlibCallback = layoutlibCallback;
46     }
47 
48     /**
49      * Like {@link #instantiate(Context, String, Bundle)} but with a null
50      * argument Bundle.
51      */
52     @LayoutlibDelegate
instantiate(Context context, String fname)53     /*package*/ static Fragment instantiate(Context context, String fname) {
54         return instantiate(context, fname, null);
55     }
56 
57     /**
58      * Create a new instance of a Fragment with the given class name.  This is
59      * the same as calling its empty constructor.
60      *
61      * @param context The calling context being used to instantiate the fragment.
62      * This is currently just used to get its ClassLoader.
63      * @param fname The class name of the fragment to instantiate.
64      * @param args Bundle of arguments to supply to the fragment, which it
65      * can retrieve with {@link Fragment#getArguments()}.  May be null.
66      * @return Returns a new fragment instance.
67      * @throws Fragment.InstantiationException If there is a failure in instantiating
68      * the given fragment class.  This is a runtime exception; it is not
69      * normally expected to happen.
70      */
71     @LayoutlibDelegate
instantiate(Context context, String fname, Bundle args)72     /*package*/ static Fragment instantiate(Context context, String fname, Bundle args) {
73         try {
74             if (sLayoutlibCallback != null) {
75                 Fragment f = (Fragment) sLayoutlibCallback.loadView(fname,
76                         new Class[0], new Object[0]);
77 
78                 if (args != null) {
79                     args.setClassLoader(f.getClass().getClassLoader());
80                     f.mArguments = args;
81                 }
82                 return f;
83             }
84 
85             return null;
86         } catch (ClassNotFoundException e) {
87             throw new Fragment.InstantiationException("Unable to instantiate fragment " + fname
88                     + ": make sure class name exists, is public, and has an"
89                     + " empty constructor that is public", e);
90         } catch (java.lang.InstantiationException e) {
91             throw new Fragment.InstantiationException("Unable to instantiate fragment " + fname
92                     + ": make sure class name exists, is public, and has an"
93                     + " empty constructor that is public", e);
94         } catch (IllegalAccessException e) {
95             throw new Fragment.InstantiationException("Unable to instantiate fragment " + fname
96                     + ": make sure class name exists, is public, and has an"
97                     + " empty constructor that is public", e);
98         } catch (Exception e) {
99             throw new Fragment.InstantiationException("Unable to instantiate fragment " + fname
100                     + ": make sure class name exists, is public, and has an"
101                     + " empty constructor that is public", e);
102         }
103     }
104 }
105