1 /*
2  * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 
26 package java.awt;
27 
28 import java.awt.peer.TaskbarPeer;
29 import sun.awt.SunToolkit;
30 
31 /**
32  * The {@code Taskbar} class allows a Java application to interact with
33  * the system task area (taskbar, Dock, etc.).
34  *
35  * <p>
36  * There are a variety of interactions depending on the current platform such as
37  * displaying progress of some task, appending user-specified menu to the application
38  * icon context menu, etc.
39  *
40  * @implNote Linux support is currently limited to Unity. However to make these
41  * features work on Unity, the app should be run from a .desktop file with
42  * specified {@code java.desktop.appName} system property set to this .desktop
43  * file name:
44  * {@code Exec=java -Djava.desktop.appName=MyApp.desktop -jar /path/to/myapp.jar}
45  * see <a href="https://help.ubuntu.com/community/UnityLaunchersAndDesktopFiles">
46  * https://help.ubuntu.com/community/UnityLaunchersAndDesktopFiles</a>
47  *
48  * @since 9
49  */
50 
51 public class Taskbar {
52 
53     /**
54      * List of provided features. Each platform supports a different
55      * set of features.  You may use the {@link Taskbar#isSupported}
56      * method to determine if the given feature is supported by the
57      * current platform.
58      */
59     public static enum Feature {
60 
61         /**
62          * Represents a textual icon badge feature.
63          * @see #setIconBadge(java.lang.String)
64          */
65         ICON_BADGE_TEXT,
66 
67         /**
68          * Represents a numerical icon badge feature.
69          * @see #setIconBadge(java.lang.String)
70          */
71         ICON_BADGE_NUMBER,
72 
73         /**
74          * Represents a graphical icon badge feature for a window.
75          * @see #setWindowIconBadge(java.awt.Window, java.awt.Image)
76          */
77         ICON_BADGE_IMAGE_WINDOW,
78 
79         /**
80          * Represents an icon feature.
81          * @see #setIconImage(java.awt.Image)
82          */
83         ICON_IMAGE,
84 
85         /**
86          * Represents a menu feature.
87          * @see #setMenu(java.awt.PopupMenu)
88          * @see #getMenu()
89          */
90         MENU,
91 
92         /**
93          * Represents a progress state feature for a specified window.
94          * @see #setWindowProgressState(java.awt.Window, State)
95          */
96         PROGRESS_STATE_WINDOW,
97 
98         /**
99          * Represents a progress value feature.
100          * @see #setProgressValue(int)
101          */
102         PROGRESS_VALUE,
103 
104         /**
105          * Represents a progress value feature for a specified window.
106          * @see #setWindowProgressValue(java.awt.Window, int)
107          */
108         PROGRESS_VALUE_WINDOW,
109 
110         /**
111          * Represents a user attention request feature.
112          * @see #requestUserAttention(boolean, boolean)
113          */
114         USER_ATTENTION,
115 
116         /**
117          * Represents a user attention request feature for a specified window.
118          * @see #requestWindowUserAttention(java.awt.Window)
119          */
120         USER_ATTENTION_WINDOW
121     }
122 
123     /**
124      * Kinds of available window progress states.
125      *
126      * @see #setWindowProgressState(java.awt.Window, java.awt.Taskbar.State)
127      */
128     public static enum State {
129         /**
130          * Stops displaying the progress.
131          */
132         OFF,
133         /**
134          * The progress indicator displays with normal color and determinate
135          * mode.
136          */
137         NORMAL,
138         /**
139          * Shows progress as paused, progress can be resumed by the user.
140          * Switches to the determinate display.
141          */
142         PAUSED,
143         /**
144          * The progress indicator displays activity without specifying what
145          * proportion of the progress is complete.
146          */
147         INDETERMINATE,
148         /**
149          * Shows that an error has occurred. Switches to the determinate
150          * display.
151          */
152         ERROR
153     }
154 
155     private TaskbarPeer peer;
156 
157     /**
158      * Tests whether a {@code Feature} is supported on the current platform.
159      * @param feature the specified {@link Feature}
160      * @return true if the specified feature is supported on the current platform
161      */
isSupported(Feature feature)162     public boolean isSupported(Feature feature) {
163         return peer.isSupported(feature);
164     }
165 
166     /**
167      * Checks if the feature type is supported.
168      *
169      * @param featureType the action type in question
170      * @throws UnsupportedOperationException if the specified action type is not
171      *         supported on the current platform
172      */
checkFeatureSupport(Feature featureType)173     private void checkFeatureSupport(Feature featureType){
174         if (!isSupported(featureType)) {
175             throw new UnsupportedOperationException("The " + featureType.name()
176                     + " feature is not supported on the current platform!");
177         }
178     }
179 
180     /**
181      *  Calls to the security manager's {@code checkPermission} method with
182      *  an {@code RuntimePermission("canProcessApplicationEvents")} permissions.
183      */
checkEventsProcessingPermission()184     private void checkEventsProcessingPermission(){
185         SecurityManager sm = System.getSecurityManager();
186         if (sm != null) {
187             sm.checkPermission(new RuntimePermission(
188                     "canProcessApplicationEvents"));
189         }
190     }
191 
Taskbar()192     private Taskbar() {
193         Toolkit defaultToolkit = Toolkit.getDefaultToolkit();
194         if (defaultToolkit instanceof SunToolkit) {
195             peer = ((SunToolkit) defaultToolkit).createTaskbarPeer(this);
196         }
197     }
198 
199     /**
200      * Returns the {@code Taskbar} instance of the current
201      * taskbar context.  On some platforms the Taskbar API may not be
202      * supported; use the {@link #isTaskbarSupported} method to
203      * determine if the current taskbar is supported.
204      * @return the Taskbar instance
205      * @throws HeadlessException if {@link
206      * GraphicsEnvironment#isHeadless()} returns {@code true}
207      * @throws UnsupportedOperationException if this class is not
208      * supported on the current platform
209      * @see #isTaskbarSupported()
210      * @see java.awt.GraphicsEnvironment#isHeadless
211      */
getTaskbar()212     public static synchronized Taskbar getTaskbar(){
213         if (GraphicsEnvironment.isHeadless()) throw new HeadlessException();
214 
215         if (!Taskbar.isTaskbarSupported()) {
216             throw new UnsupportedOperationException("Taskbar API is not " +
217                                                     "supported on the current platform");
218         }
219 
220         sun.awt.AppContext context = sun.awt.AppContext.getAppContext();
221         Taskbar taskbar = (Taskbar)context.get(Taskbar.class);
222 
223         if (taskbar == null) {
224             taskbar = new Taskbar();
225             context.put(Taskbar.class, taskbar);
226         }
227 
228         return taskbar;
229     }
230 
231     /**
232      * Tests whether this class is supported on the current platform.
233      * If it's supported, use {@link #getTaskbar()} to retrieve an
234      * instance.
235      *
236      * @return {@code true} if this class is supported on the
237      *         current platform; {@code false} otherwise
238      * @see #getTaskbar()
239      */
isTaskbarSupported()240     public static boolean isTaskbarSupported(){
241         Toolkit defaultToolkit = Toolkit.getDefaultToolkit();
242         if (defaultToolkit instanceof SunToolkit) {
243             return ((SunToolkit)defaultToolkit).isTaskbarSupported();
244         }
245         return false;
246     }
247 
248     /**
249      * Requests user attention to this application.
250      *
251      * Depending on the platform, this may be visually indicated by a bouncing
252      * or flashing icon in the task area. It may have no effect on an already active
253      * application.
254      *
255      * On some platforms (e.g. Mac OS) this effect may disappear upon app activation
256      * and cannot be dismissed by setting {@code enabled} to false.
257      * Other platforms may require an additional call
258      * {@link #requestUserAttention} to dismiss this request
259      * with {@code enabled} parameter set to false.
260      *
261      * @param enabled disables this request if false
262      * @param critical if this is an important request
263      * @throws SecurityException if a security manager exists and it denies the
264      * {@code RuntimePermission("canProcessApplicationEvents")} permission.
265      * @throws UnsupportedOperationException if the current platform
266      * does not support the {@link Taskbar.Feature#USER_ATTENTION} feature
267      */
requestUserAttention(final boolean enabled, final boolean critical)268     public void requestUserAttention(final boolean enabled, final boolean critical) {
269         checkEventsProcessingPermission();
270         checkFeatureSupport(Feature.USER_ATTENTION);
271         peer.requestUserAttention(enabled, critical);
272     }
273 
274     /**
275      * Requests user attention to the specified window.
276      *
277      * Has no effect if a window representation is not displayable in
278      * the task area. Whether it is displayable is dependent on all
279      * of window type, platform, and implementation.
280      *
281      * @param w window
282      * @throws SecurityException if a security manager exists and it denies the
283      * {@code RuntimePermission("canProcessApplicationEvents")} permission.
284      * @throws UnsupportedOperationException if the current platform
285      * does not support the {@link Taskbar.Feature#USER_ATTENTION_WINDOW} feature
286      */
requestWindowUserAttention(Window w)287     public void requestWindowUserAttention(Window w) {
288         checkEventsProcessingPermission();
289         checkFeatureSupport(Feature.USER_ATTENTION_WINDOW);
290         peer.requestWindowUserAttention(w);
291     }
292 
293     /**
294      * Attaches the contents of the provided PopupMenu to the application icon
295      * in the task area.
296      *
297      * @param menu the PopupMenu to attach to this application
298      * @throws SecurityException if a security manager exists and it denies the
299      * {@code RuntimePermission("canProcessApplicationEvents")} permission.
300      * @throws UnsupportedOperationException if the current platform
301      * does not support the {@link Taskbar.Feature#MENU} feature
302      */
setMenu(final PopupMenu menu)303     public void setMenu(final PopupMenu menu) {
304         checkEventsProcessingPermission();
305         checkFeatureSupport(Feature.MENU);
306         peer.setMenu(menu);
307     }
308 
309     /**
310      * Gets PopupMenu used to add items to this application's icon in system task area.
311      *
312      * @return the PopupMenu
313      * @throws SecurityException if a security manager exists and it denies the
314      * {@code RuntimePermission("canProcessApplicationEvents")} permission.
315      * @throws UnsupportedOperationException if the current platform
316      * does not support the {@link Taskbar.Feature#MENU} feature
317      */
getMenu()318     public PopupMenu getMenu() {
319         checkEventsProcessingPermission();
320         checkFeatureSupport(Feature.MENU);
321         return peer.getMenu();
322     }
323 
324     /**
325      * Changes this application's icon to the provided image.
326      *
327      * @param image to change
328      * @throws SecurityException if a security manager exists and it denies the
329      * {@code RuntimePermission("canProcessApplicationEvents")} permission.
330      * @throws UnsupportedOperationException if the current platform
331      * does not support the {@link Taskbar.Feature#ICON_IMAGE} feature
332      */
setIconImage(final Image image)333     public void setIconImage(final Image image) {
334         checkEventsProcessingPermission();
335         checkFeatureSupport(Feature.ICON_IMAGE);
336         peer.setIconImage(image);
337     }
338 
339     /**
340      * Obtains an image of this application's icon.
341      *
342      * @return an image of this application's icon
343      * @throws SecurityException if a security manager exists and it denies the
344      * {@code RuntimePermission("canProcessApplicationEvents")} permission.
345      * @throws UnsupportedOperationException if the current platform
346      * does not support the {@link Taskbar.Feature#ICON_IMAGE} feature
347      */
getIconImage()348     public Image getIconImage() {
349         checkEventsProcessingPermission();
350         checkFeatureSupport(Feature.ICON_IMAGE);
351         return peer.getIconImage();
352     }
353 
354     /**
355      * Affixes a small system-provided badge to this application's icon.
356      * Usually a number.
357      *
358      * Some platforms do not support string values and accept only integer
359      * values. In this case, pass an integer represented as a string as parameter.
360      * This can be tested by {@code Feature.ICON_BADGE_TEXT} and
361      * {@code Feature.ICON_BADGE_NUMBER}.
362      *
363      * Passing {@code null} as parameter hides the badge.
364      * @param badge label to affix to the icon
365      * @throws SecurityException if a security manager exists and it denies the
366      * {@code RuntimePermission("canProcessApplicationEvents")} permission.
367      * @throws UnsupportedOperationException if the current platform
368      * does not support the {@link Taskbar.Feature#ICON_BADGE_NUMBER}
369      * or {@link Taskbar.Feature#ICON_BADGE_TEXT} feature
370      */
setIconBadge(final String badge)371     public void setIconBadge(final String badge) {
372         checkEventsProcessingPermission();
373         checkFeatureSupport(Feature.ICON_BADGE_NUMBER);
374         peer.setIconBadge(badge);
375     }
376 
377     /**
378      * Affixes a small badge to this application's icon in the task area
379      * for the specified window.
380      * It may be disabled by system settings.
381      *
382      * Has no effect if a window representation is not displayable in
383      * the task area. Whether it is displayable is dependent on all
384      * of window type, platform, and implementation.
385      *
386      * @param w window to update
387      * @param badge image to affix to the icon
388      * @throws SecurityException if a security manager exists and it denies the
389      * {@code RuntimePermission("canProcessApplicationEvents")} permission.
390      * @throws UnsupportedOperationException if the current platform
391      * does not support the {@link Taskbar.Feature#ICON_BADGE_IMAGE_WINDOW} feature
392      */
setWindowIconBadge(Window w, final Image badge)393     public void setWindowIconBadge(Window w, final Image badge) {
394         checkEventsProcessingPermission();
395         checkFeatureSupport(Feature.ICON_BADGE_IMAGE_WINDOW);
396         if (w != null) {
397             peer.setWindowIconBadge(w, badge);
398         }
399     }
400 
401 
402     /**
403      * Affixes a small system-provided progress bar to this application's icon.
404      *
405      * @param value from 0 to 100, other to disable progress indication
406      * @throws SecurityException if a security manager exists and it denies the
407      * {@code RuntimePermission("canProcessApplicationEvents")} permission.
408      * @throws UnsupportedOperationException if the current platform
409      * does not support the {@link Taskbar.Feature#PROGRESS_VALUE} feature
410      */
setProgressValue(int value)411     public void setProgressValue(int value) {
412         checkEventsProcessingPermission();
413         checkFeatureSupport(Feature.PROGRESS_VALUE);
414         peer.setProgressValue(value);
415     }
416 
417     /**
418      * Displays a determinate progress bar in the task area for the specified
419      * window.
420      *
421      * Has no effect if a window representation is not displayable in
422      * the task area. Whether it is displayable is dependent on all
423      * of window type, platform, and implementation.
424      *
425      * <br>
426      * The visual behavior is platform and {@link State} dependent.
427      * <br>
428      * This call cancels the {@link State#INDETERMINATE INDETERMINATE} state
429      * of the window.
430      * <br>
431      * Note that when multiple windows is grouped in the task area
432      * the behavior is platform specific.
433      *
434      * @param w window to update
435      * @param value from 0 to 100, other to switch to {@link State#OFF} state
436      *              and disable progress indication
437      * @see #setWindowProgressState(java.awt.Window, State)
438      * @throws SecurityException if a security manager exists and it denies the
439      * {@code RuntimePermission("canProcessApplicationEvents")} permission.
440      * @throws UnsupportedOperationException if the current platform
441      * does not support the {@link Taskbar.Feature#PROGRESS_VALUE_WINDOW} feature
442      */
setWindowProgressValue(Window w, int value)443     public void setWindowProgressValue(Window w, int value) {
444         checkEventsProcessingPermission();
445         checkFeatureSupport(Feature.PROGRESS_VALUE_WINDOW);
446         if (w != null) {
447             peer.setWindowProgressValue(w, value);
448         }
449     }
450 
451     /**
452      * Sets a progress state for a specified window.
453      *
454      * Has no effect if a window representation is not displayable in
455      * the task area. Whether it is displayable is dependent on all
456      * of window type, platform, and implementation.
457      * <br>
458      * Each state displays a progress in a platform-dependent way.
459      * <br>
460      * Note than switching from {@link State#INDETERMINATE INDETERMINATE} state
461      * to any of determinate states may reset value set by
462      * {@link #setWindowProgressValue(java.awt.Window, int) setWindowProgressValue}
463      *
464      * @param w window
465      * @param state to change to
466      * @see State#OFF
467      * @see State#NORMAL
468      * @see State#PAUSED
469      * @see State#ERROR
470      * @see State#INDETERMINATE
471      * @see #setWindowProgressValue(java.awt.Window, int)
472      * @throws SecurityException if a security manager exists and it denies the
473      * {@code RuntimePermission("canProcessApplicationEvents")} permission.
474      * @throws UnsupportedOperationException if the current platform
475      * does not support the {@link Taskbar.Feature#PROGRESS_STATE_WINDOW} feature
476      */
setWindowProgressState(Window w, State state)477     public void setWindowProgressState(Window w, State state) {
478         checkEventsProcessingPermission();
479         checkFeatureSupport(Feature.PROGRESS_STATE_WINDOW);
480         if (w != null) {
481             peer.setWindowProgressState(w, state);
482         }
483     }
484 }
485