ClipboardManager.java revision 327fbd2c8fa294b919475feb4c74a74ee1981e02
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
17package android.content;
18
19import android.content.Context;
20import android.os.Message;
21import android.os.RemoteException;
22import android.os.Handler;
23import android.os.IBinder;
24import android.os.ServiceManager;
25import android.util.Log;
26
27import java.util.ArrayList;
28
29/**
30 * Interface to the clipboard service, for placing and retrieving text in
31 * the global clipboard.
32 *
33 * <p>
34 * You do not instantiate this class directly; instead, retrieve it through
35 * {@link android.content.Context#getSystemService}.
36 *
37 * <p>
38 * The ClipboardManager API itself is very simple: it consists of methods
39 * to atomically get and set the current primary clipboard data.  That data
40 * is expressed as a {@link ClipData} object, which defines the protocol
41 * for data exchange between applications.
42 *
43 * @see android.content.Context#getSystemService
44 */
45public class ClipboardManager extends android.text.ClipboardManager {
46    private final static Object sStaticLock = new Object();
47    private static IClipboard sService;
48
49    private final Context mContext;
50
51    private final ArrayList<OnPrimaryClipChangedListener> mPrimaryClipChangedListeners
52             = new ArrayList<OnPrimaryClipChangedListener>();
53
54    private final IOnPrimaryClipChangedListener.Stub mPrimaryClipChangedServiceListener
55            = new IOnPrimaryClipChangedListener.Stub() {
56        public void dispatchPrimaryClipChanged() {
57            mHandler.sendEmptyMessage(MSG_REPORT_PRIMARY_CLIP_CHANGED);
58        }
59    };
60
61    static final int MSG_REPORT_PRIMARY_CLIP_CHANGED = 1;
62
63    private final Handler mHandler = new Handler() {
64        @Override
65        public void handleMessage(Message msg) {
66            switch (msg.what) {
67                case MSG_REPORT_PRIMARY_CLIP_CHANGED:
68                    reportPrimaryClipChanged();
69            }
70        }
71    };
72
73    public interface OnPrimaryClipChangedListener {
74        void onPrimaryClipChanged();
75    }
76
77    static private IClipboard getService() {
78        synchronized (sStaticLock) {
79            if (sService != null) {
80                return sService;
81            }
82            IBinder b = ServiceManager.getService("clipboard");
83            sService = IClipboard.Stub.asInterface(b);
84            return sService;
85        }
86    }
87
88    /** {@hide} */
89    public ClipboardManager(Context context, Handler handler) {
90        mContext = context;
91    }
92
93    /**
94     * Sets the current primary clip on the clipboard.  This is the clip that
95     * is involved in normal cut and paste operations.
96     *
97     * @param clip The clipped data item to set.
98     */
99    public void setPrimaryClip(ClipData clip) {
100        try {
101            getService().setPrimaryClip(clip);
102        } catch (RemoteException e) {
103        }
104    }
105
106    /**
107     * Returns the current primary clip on the clipboard.
108     */
109    public ClipData getPrimaryClip() {
110        try {
111            return getService().getPrimaryClip(mContext.getPackageName());
112        } catch (RemoteException e) {
113            return null;
114        }
115    }
116
117    /**
118     * Returns a description of the current primary clip on the clipboard
119     * but not a copy of its data.
120     */
121    public ClipDescription getPrimaryClipDescription() {
122        try {
123            return getService().getPrimaryClipDescription();
124        } catch (RemoteException e) {
125            return null;
126        }
127    }
128
129    /**
130     * Returns true if there is currently a primary clip on the clipboard.
131     */
132    public boolean hasPrimaryClip() {
133        try {
134            return getService().hasPrimaryClip();
135        } catch (RemoteException e) {
136            return false;
137        }
138    }
139
140    public void addPrimaryClipChangedListener(OnPrimaryClipChangedListener what) {
141        synchronized (mPrimaryClipChangedListeners) {
142            if (mPrimaryClipChangedListeners.size() == 0) {
143                try {
144                    getService().addPrimaryClipChangedListener(
145                            mPrimaryClipChangedServiceListener);
146                } catch (RemoteException e) {
147                }
148            }
149            mPrimaryClipChangedListeners.add(what);
150        }
151    }
152
153    public void removePrimaryClipChangedListener(OnPrimaryClipChangedListener what) {
154        synchronized (mPrimaryClipChangedListeners) {
155            mPrimaryClipChangedListeners.remove(what);
156            if (mPrimaryClipChangedListeners.size() == 0) {
157                try {
158                    getService().removePrimaryClipChangedListener(
159                            mPrimaryClipChangedServiceListener);
160                } catch (RemoteException e) {
161                }
162            }
163        }
164    }
165
166    /**
167     * @deprecated Use {@link #getPrimaryClip()} instead.  This retrieves
168     * the primary clip and tries to coerce it to a string.
169     */
170    public CharSequence getText() {
171        ClipData clip = getPrimaryClip();
172        if (clip != null && clip.getItemCount() > 0) {
173            return clip.getItemAt(0).coerceToText(mContext);
174        }
175        return null;
176    }
177
178    /**
179     * @deprecated Use {@link #setPrimaryClip(ClipData)} instead.  This
180     * creates a ClippedItem holding the given text and sets it as the
181     * primary clip.  It has no label or icon.
182     */
183    public void setText(CharSequence text) {
184        setPrimaryClip(ClipData.newPlainText(null, text));
185    }
186
187    /**
188     * @deprecated Use {@link #hasPrimaryClip()} instead.
189     */
190    public boolean hasText() {
191        try {
192            return getService().hasClipboardText();
193        } catch (RemoteException e) {
194            return false;
195        }
196    }
197
198    void reportPrimaryClipChanged() {
199        Object[] listeners;
200
201        synchronized (mPrimaryClipChangedListeners) {
202            final int N = mPrimaryClipChangedListeners.size();
203            if (N <= 0) {
204                return;
205            }
206            listeners = mPrimaryClipChangedListeners.toArray();
207        }
208
209        for (int i=0; i<listeners.length; i++) {
210            ((OnPrimaryClipChangedListener)listeners[i]).onPrimaryClipChanged();
211        }
212    }
213}
214