Merge lp:~mterry/unity8/warn-on-xapp into lp:unity8

Proposed by Michael Terry
Status: Work in progress
Proposed branch: lp:~mterry/unity8/warn-on-xapp
Merge into: lp:unity8
Prerequisite: lp:~mzanetti/unity8/modeswitchwarning
Diff against target: 752 lines (+258/-45)
27 files modified
CMakeLists.txt (+2/-1)
debian/control (+6/-6)
plugins/Greeter/Unity/Launcher/CMakeLists.txt (+0/-1)
plugins/Greeter/Unity/Launcher/launcheritem.cpp (+14/-0)
plugins/Greeter/Unity/Launcher/launcheritem.h (+3/-0)
plugins/Greeter/Unity/Launcher/launchermodelas.cpp (+10/-4)
plugins/Unity/Launcher/CMakeLists.txt (+0/-1)
plugins/Unity/Launcher/desktopfilehandler.cpp (+12/-0)
plugins/Unity/Launcher/desktopfilehandler.h (+1/-0)
plugins/Unity/Launcher/launcheritem.cpp (+14/-0)
plugins/Unity/Launcher/launcheritem.h (+3/-0)
plugins/Unity/Launcher/launchermodel.cpp (+30/-22)
plugins/Unity/Launcher/launchermodel.h (+1/-1)
qml/Components/Dialogs.qml (+26/-4)
qml/Components/LegacyAppLaunchWarningDialog.qml (+51/-0)
qml/Shell.qml (+9/-0)
tests/mocks/Unity/Application/Application.qmltypes (+5/-0)
tests/mocks/Unity/Application/ApplicationManager.cpp (+14/-0)
tests/mocks/Unity/Application/ApplicationManager.h (+1/-0)
tests/mocks/Unity/Launcher/CMakeLists.txt (+0/-2)
tests/mocks/Unity/Launcher/MockLauncherItem.cpp (+13/-0)
tests/mocks/Unity/Launcher/MockLauncherItem.h (+3/-0)
tests/mocks/Unity/Launcher/MockLauncherModel.cpp (+2/-0)
tests/plugins/Greeter/Unity/Launcher/CMakeLists.txt (+0/-2)
tests/plugins/Unity/Launcher/CMakeLists.txt (+0/-1)
tests/plugins/Unity/Launcher/launchermodeltest.cpp (+3/-0)
tests/qmltests/tst_Shell.qml (+35/-0)
To merge this branch: bzr merge lp:~mterry/unity8/warn-on-xapp
Reviewer Review Type Date Requested Status
Unity8 CI Bot continuous-integration Needs Fixing
Gerry Boland (community) Needs Fixing
PS Jenkins bot (community) continuous-integration Needs Fixing
Albert Astals Cid (community) merges fine Abstain
Michael Zanetti (community) Needs Information
Review via email: mp+277915@code.launchpad.net

Commit message

Prevent user from launching legacy xapps when in tablet or phone mode.

Description of the change

Prevent user from launching legacy xapps when in tablet or phone mode.

There are open design questions ("what should the text be?" and "should we make the legacy icons look different?") that I'm waiting on answers for. But this can be reviewed from a technical POV already.

Note that the LauncherItem changes to support isTouchApp aren't used yet. But they might be if Design wants a different look for them.

== Checklist ==

 * Are there any related MPs required for this MP to build/function as expected? Please list.
 https://code.launchpad.net/~mterry/unity-api/warn-on-xapp/+merge/277922
 https://code.launchpad.net/~mterry/qtmir/warn-on-xapp/+merge/279172
 https://code.launchpad.net/~mterry/ubuntu-app-launch/warn-on-xapp/+merge/278497

 * Did you perform an exploratory manual test run of your code change and any related functionality?
 Yes

 * Did you make sure that your branch does not contain spurious tags?
 Yes

 * If you changed the packaging (debian), did you subscribe the ubuntu-unity team to this MP?
 I'm on that team

 * If you changed the UI, has there been a design review?
 Not yet, working on it.

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Michael Zanetti (mzanetti) wrote :

As discussed on IRC, this probably won't cut it. For instance it won't prevent the dash to launch the app. also anything else can do Qt.openUrlExternally(legacyApp).

I think the proper way to go would be to extend ApplicationManager to request permission for launching an app with the shell. Let's do a hangout with Gerry regarding this today.

review: Needs Information
Revision history for this message
Albert Astals Cid (aacid) wrote :

Text conflict in tests/qmltests/tst_Shell.qml
1 conflicts encountered.

review: Needs Fixing
lp:~mterry/unity8/warn-on-xapp updated
2042. By Michael Terry

Merge from trunk

Revision history for this message
Michael Terry (mterry) wrote :

Fixed conflicts.

Revision history for this message
Albert Astals Cid (aacid) :
review: Abstain (merges fine)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Albert Astals Cid (aacid) wrote :

Text conflict in CMakeLists.txt
1 conflicts encountered.

review: Needs Fixing
lp:~mterry/unity8/warn-on-xapp updated
2043. By Michael Terry

Merge from trunk

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Albert Astals Cid (aacid) :
review: Abstain (merges fine)
lp:~mterry/unity8/warn-on-xapp updated
2044. By Michael Terry

Update to use new approval API in ApplicationManager

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
lp:~mterry/unity8/warn-on-xapp updated
2045. By Michael Terry

Fix typo by actually specifying appId when docking

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Albert Astals Cid (aacid) wrote :

Text conflict in CMakeLists.txt
1 conflicts encountered.

Revision history for this message
Gerry Boland (gerboland) wrote :

=== modified file 'plugins/Greeter/Unity/Launcher/launchermodelas.cpp'
+ case RoleAlerting:
+ return item->alerting();
Unrelated to this MP.

=== modified file 'plugins/Unity/Launcher/desktopfilehandler.cpp'
Off topic (since I see it being done elsewhere in the file)

+bool DesktopFileHandler::isTouchApp() const
+{
+ if (isValid()) {
+ QSettings settings(m_filename, QSettings::IniFormat);
+ settings.setIniCodec("UTF-8");
+ settings.beginGroup(QStringLiteral("Desktop Entry"));
+ return settings.value(QStringLiteral("X-Ubuntu-Touch")).toBool(); // false for empty or "false"

Rest looks ok to me, but would prefer launcher owner have a look.
Creating the QSettings object and parse the desktop file for each property read isn't very efficient. Any idea why we don't just parse it once at DesktopFileHandler creation?

review: Needs Fixing
Revision history for this message
Michael Zanetti (mzanetti) wrote :

> +bool DesktopFileHandler::isTouchApp() const
> +{
> + if (isValid()) {
> + QSettings settings(m_filename, QSettings::IniFormat);
> + settings.setIniCodec("UTF-8");
> + settings.beginGroup(QStringLiteral("Desktop Entry"));
> + return settings.value(QStringLiteral("X-Ubuntu-Touch")).toBool(); // false
> for empty or "false"
>
> Rest looks ok to me, but would prefer launcher owner have a look.
> Creating the QSettings object and parse the desktop file for each property
> read isn't very efficient. Any idea why we don't just parse it once at
> DesktopFileHandler creation?

From the QSettings docs: "Constructing and destroying a QSettings object is very fast."

Revision history for this message
Michael Zanetti (mzanetti) wrote :

that said, parsing can be costly indeed. However, following the code around it, this is called only once when a launcher item is created. IMO we're ok here.

Revision history for this message
Michael Terry (mterry) wrote :

Regarding the QSettings, I didn't want to make any big changes because Lukas has a rewrite of that code in https://code.launchpad.net/~lukas-kde/unity8/desktopFileActions/+merge/276408 which converts to GKeyFile.

And as mzanetti said, it's one time.

Regarding the unrelated Role switch statement resortings, it's just a bit of cleanup. Everytime a property gets added to the application interface, they need to be added to a bunch of switch statements around the place. And currently, they are all in different orders, which makes it hard to tell if any are missing from one. For example, when adding RoleIsTouchApp for this MP, I noticed that launchermodelas.cpp was missing RoleRecent and RoleAlerting. So I added them here and sorted them to all be the same order, so it's less likely we'll miss future ones. So tangentially related, but not wholly unrelated.

Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote :

FAILED: Continuous integration, rev:2045
https://unity8-jenkins.ubuntu.com/job/lp-unity8-1-ci/28/
Executed test runs:

Click here to trigger a rebuild:
https://unity8-jenkins.ubuntu.com/job/lp-unity8-1-ci/28/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Albert Astals Cid (aacid) wrote :

Text conflict in CMakeLists.txt
Text conflict in debian/control
2 conflicts

Unmerged revisions

2045. By Michael Terry

Fix typo by actually specifying appId when docking

2044. By Michael Terry

Update to use new approval API in ApplicationManager

2043. By Michael Terry

Merge from trunk

2042. By Michael Terry

Merge from trunk

2041. By Michael Terry

First pass at warning when launching a legacy app

2040. By Michael Terry

Merge in mzanetti's modeswitchwarning branch, we'll use a similar dialog

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'CMakeLists.txt'
2--- CMakeLists.txt 2015-11-26 13:51:24 +0000
3+++ CMakeLists.txt 2015-12-02 17:26:09 +0000
4@@ -57,7 +57,8 @@
5 find_package(Qt5Concurrent 5.4 REQUIRED)
6 find_package(Qt5Sql 5.4 REQUIRED)
7
8-pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=11)
9+pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=12)
10+pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=8)
11
12 # Standard install paths
13 include(GNUInstallDirs)
14
15=== modified file 'debian/control'
16--- debian/control 2015-11-26 13:51:24 +0000
17+++ debian/control 2015-12-02 17:26:09 +0000
18@@ -29,7 +29,7 @@
19 libqt5xmlpatterns5-dev,
20 libsystemsettings-dev,
21 libudev-dev,
22- libunity-api-dev (>= 7.103),
23+ libunity-api-dev (>= 7.104),
24 libusermetricsoutput1-dev,
25 libxcb1-dev,
26 pkg-config,
27@@ -98,11 +98,11 @@
28 qml-module-qtquick-xmllistmodel,
29 qml-module-qtsysteminfo,
30 qtdeclarative5-gsettings1.0,
31- qtdeclarative5-qtmir-plugin (>= 0.4.5),
32+ qtdeclarative5-qtmir-plugin (>= 0.4.7),
33 qtdeclarative5-ubuntu-telephony0.1,
34 qtdeclarative5-ubuntu-web-plugin,
35 ubuntu-system-settings,
36- unity-launcher-impl-7,
37+ unity-launcher-impl-8,
38 unity8-common (= ${source:Version}),
39 unity8-private (= ${binary:Version}),
40 unity8-private | unity-launcher-impl,
41@@ -128,7 +128,7 @@
42 qtdeclarative5-ubuntu-ui-toolkit-plugin (>= 1.3.1627) | qtdeclarative5-ubuntu-ui-toolkit-plugin-gles (>= 1.3.1627),
43 qtdeclarative5-unity-notifications-plugin (>= 0.1.2) | unity-notifications-impl,
44 ubuntu-thumbnailer-impl-0,
45- unity-application-impl-11,
46+ unity-application-impl-12,
47 unity-notifications-impl-3,
48 unity-plugin-scopes | unity-scopes-impl,
49 unity-scopes-impl-7,
50@@ -174,7 +174,7 @@
51 Depends: ${misc:Depends},
52 ${shlibs:Depends},
53 Provides: unity-application-impl,
54- unity-application-impl-11,
55+ unity-application-impl-12,
56 Replaces: unity8-autopilot (<< 8.02+15.04.20150422-0ubuntu1)
57 Description: Fake environment for running Unity 8 shell
58 Provides fake implementations of some QML modules used by Unity 8 shell
59@@ -192,7 +192,7 @@
60 ${misc:Depends},
61 ${shlibs:Depends},
62 Provides: unity-launcher-impl,
63- unity-launcher-impl-7,
64+ unity-launcher-impl-8,
65 Description: Unity 8 private libs
66 The Unity 8 shell is the primary user interface for Ubuntu devices.
67 .
68
69=== modified file 'plugins/Greeter/Unity/Launcher/CMakeLists.txt'
70--- plugins/Greeter/Unity/Launcher/CMakeLists.txt 2015-08-03 13:47:44 +0000
71+++ plugins/Greeter/Unity/Launcher/CMakeLists.txt 2015-12-02 17:26:09 +0000
72@@ -1,4 +1,3 @@
73-pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=7)
74 pkg_check_modules(GSETTINGS_QT REQUIRED gsettings-qt)
75
76 add_definitions(-DSM_BUSNAME=systemBus)
77
78=== modified file 'plugins/Greeter/Unity/Launcher/launcheritem.cpp'
79--- plugins/Greeter/Unity/Launcher/launcheritem.cpp 2015-09-14 09:11:08 +0000
80+++ plugins/Greeter/Unity/Launcher/launcheritem.cpp 2015-12-02 17:26:09 +0000
81@@ -32,6 +32,7 @@
82 m_countVisible(false),
83 m_focused(false),
84 m_alerting(false),
85+ m_isTouchApp(false),
86 m_quickList(new QuickListModel(this))
87 {
88 QuickListEntry nameAction;
89@@ -179,6 +180,19 @@
90 }
91 }
92
93+bool LauncherItem::isTouchApp() const
94+{
95+ return m_isTouchApp;
96+}
97+
98+void LauncherItem::setIsTouchApp(bool isTouchApp)
99+{
100+ if (m_isTouchApp != isTouchApp) {
101+ m_isTouchApp = isTouchApp;
102+ Q_EMIT isTouchAppChanged(isTouchApp);
103+ }
104+}
105+
106 unity::shell::launcher::QuickListModelInterface *LauncherItem::quickList() const
107 {
108 return m_quickList;
109
110=== modified file 'plugins/Greeter/Unity/Launcher/launcheritem.h'
111--- plugins/Greeter/Unity/Launcher/launcheritem.h 2015-06-02 13:50:46 +0000
112+++ plugins/Greeter/Unity/Launcher/launcheritem.h 2015-12-02 17:26:09 +0000
113@@ -42,6 +42,7 @@
114 bool countVisible() const override;
115 bool focused() const override;
116 bool alerting() const override;
117+ bool isTouchApp() const override;
118
119 unity::shell::launcher::QuickListModelInterface *quickList() const override;
120
121@@ -56,6 +57,7 @@
122 void setCountVisible(bool countVisible);
123 void setFocused(bool focused);
124 void setAlerting(bool alerting);
125+ void setIsTouchApp(bool isTouchApp);
126
127
128 private:
129@@ -70,6 +72,7 @@
130 bool m_countVisible;
131 bool m_focused;
132 bool m_alerting;
133+ bool m_isTouchApp;
134 QuickListModel *m_quickList;
135
136 friend class LauncherModel;
137
138=== modified file 'plugins/Greeter/Unity/Launcher/launchermodelas.cpp'
139--- plugins/Greeter/Unity/Launcher/launchermodelas.cpp 2015-10-26 14:05:14 +0000
140+++ plugins/Greeter/Unity/Launcher/launchermodelas.cpp 2015-12-02 17:26:09 +0000
141@@ -59,16 +59,22 @@
142 return item->icon();
143 case RolePinned:
144 return item->pinned();
145+ case RoleRunning:
146+ return item->running();
147+ case RoleRecent:
148+ return item->recent();
149+ case RoleProgress:
150+ return item->progress();
151 case RoleCount:
152 return item->count();
153 case RoleCountVisible:
154 return item->countVisible();
155- case RoleProgress:
156- return item->progress();
157 case RoleFocused:
158 return item->focused();
159- case RoleRunning:
160- return item->running();
161+ case RoleAlerting:
162+ return item->alerting();
163+ case RoleIsTouchApp:
164+ return item->isTouchApp();
165 }
166
167 return QVariant();
168
169=== modified file 'plugins/Unity/Launcher/CMakeLists.txt'
170--- plugins/Unity/Launcher/CMakeLists.txt 2015-08-03 13:47:44 +0000
171+++ plugins/Unity/Launcher/CMakeLists.txt 2015-12-02 17:26:09 +0000
172@@ -1,4 +1,3 @@
173-pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=7)
174 pkg_check_modules(GSETTINGS_QT REQUIRED gsettings-qt)
175
176 add_definitions(-DSM_BUSNAME=systemBus)
177
178=== modified file 'plugins/Unity/Launcher/desktopfilehandler.cpp'
179--- plugins/Unity/Launcher/desktopfilehandler.cpp 2015-09-30 12:43:53 +0000
180+++ plugins/Unity/Launcher/desktopfilehandler.cpp 2015-12-02 17:26:09 +0000
181@@ -57,6 +57,18 @@
182 return !m_filename.isEmpty();
183 }
184
185+bool DesktopFileHandler::isTouchApp() const
186+{
187+ if (isValid()) {
188+ QSettings settings(m_filename, QSettings::IniFormat);
189+ settings.setIniCodec("UTF-8");
190+ settings.beginGroup(QStringLiteral("Desktop Entry"));
191+ return settings.value(QStringLiteral("X-Ubuntu-Touch")).toBool(); // false for empty or "false"
192+ } else {
193+ return false;
194+ }
195+}
196+
197 void DesktopFileHandler::load()
198 {
199 m_filename.clear();
200
201=== modified file 'plugins/Unity/Launcher/desktopfilehandler.h'
202--- plugins/Unity/Launcher/desktopfilehandler.h 2014-09-02 17:45:50 +0000
203+++ plugins/Unity/Launcher/desktopfilehandler.h 2015-12-02 17:26:09 +0000
204@@ -42,6 +42,7 @@
205 void setAppId(const QString &appId);
206
207 bool isValid() const;
208+ bool isTouchApp() const;
209 QString filename() const;
210 QString displayName() const;
211 QString icon() const;
212
213=== modified file 'plugins/Unity/Launcher/launcheritem.cpp'
214--- plugins/Unity/Launcher/launcheritem.cpp 2015-09-14 09:11:08 +0000
215+++ plugins/Unity/Launcher/launcheritem.cpp 2015-12-02 17:26:09 +0000
216@@ -35,6 +35,7 @@
217 m_countVisible(false),
218 m_focused(false),
219 m_alerting(false),
220+ m_isTouchApp(false),
221 m_quickList(new QuickListModel(this))
222 {
223 QuickListEntry nameAction;
224@@ -212,6 +213,19 @@
225 }
226 }
227
228+bool LauncherItem::isTouchApp() const
229+{
230+ return m_isTouchApp;
231+}
232+
233+void LauncherItem::setIsTouchApp(bool isTouchApp)
234+{
235+ if (m_isTouchApp != isTouchApp) {
236+ m_isTouchApp = isTouchApp;
237+ Q_EMIT isTouchAppChanged(isTouchApp);
238+ }
239+}
240+
241 unity::shell::launcher::QuickListModelInterface *LauncherItem::quickList() const
242 {
243 return m_quickList;
244
245=== modified file 'plugins/Unity/Launcher/launcheritem.h'
246--- plugins/Unity/Launcher/launcheritem.h 2015-07-23 14:13:57 +0000
247+++ plugins/Unity/Launcher/launcheritem.h 2015-12-02 17:26:09 +0000
248@@ -45,6 +45,7 @@
249 bool countVisible() const override;
250 bool focused() const override;
251 bool alerting() const override;
252+ bool isTouchApp() const override;
253
254 unity::shell::launcher::QuickListModelInterface *quickList() const override;
255
256@@ -59,6 +60,7 @@
257 void setCountVisible(bool countVisible);
258 void setFocused(bool focused);
259 void setAlerting(bool alerting);
260+ void setIsTouchApp(bool isTouchApp);
261
262 private:
263 QString m_appId;
264@@ -72,6 +74,7 @@
265 bool m_countVisible;
266 bool m_focused;
267 bool m_alerting;
268+ bool m_isTouchApp;
269 QuickListModel *m_quickList;
270 QuickListEntry m_quitAction;
271
272
273=== modified file 'plugins/Unity/Launcher/launchermodel.cpp'
274--- plugins/Unity/Launcher/launchermodel.cpp 2015-09-14 09:11:08 +0000
275+++ plugins/Unity/Launcher/launchermodel.cpp 2015-12-02 17:26:09 +0000
276@@ -76,18 +76,22 @@
277 return item->icon();
278 case RolePinned:
279 return item->pinned();
280+ case RoleRunning:
281+ return item->running();
282+ case RoleRecent:
283+ return item->recent();
284+ case RoleProgress:
285+ return item->progress();
286 case RoleCount:
287 return item->count();
288 case RoleCountVisible:
289 return item->countVisible();
290- case RoleProgress:
291- return item->progress();
292 case RoleFocused:
293 return item->focused();
294 case RoleAlerting:
295 return item->alerting();
296- case RoleRunning:
297- return item->running();
298+ case RoleIsTouchApp:
299+ return item->isTouchApp();
300 default:
301 qWarning() << Q_FUNC_INFO << "missing role, implement me";
302 return QVariant();
303@@ -147,6 +151,21 @@
304 }
305 }
306
307+LauncherItem *LauncherModel::loadLauncherItem(const QString &appId)
308+{
309+ DesktopFileHandler desktopFile(appId);
310+ if (!desktopFile.isValid()) {
311+ return nullptr;
312+ }
313+
314+ LauncherItem *item = new LauncherItem(appId,
315+ desktopFile.displayName(),
316+ desktopFile.icon(),
317+ this);
318+ item->setIsTouchApp(desktopFile.isTouchApp());
319+ return item;
320+}
321+
322 void LauncherModel::pin(const QString &appId, int index)
323 {
324 int currentIndex = findApplication(appId);
325@@ -166,17 +185,13 @@
326 index = m_list.count();
327 }
328
329- DesktopFileHandler desktopFile(appId);
330- if (!desktopFile.isValid()) {
331+ LauncherItem *item = loadLauncherItem(appId);
332+ if (!item) {
333 qWarning() << "Can't pin this application, there is no .desktop file available.";
334 return;
335 }
336
337 beginInsertRows(QModelIndex(), index, index);
338- LauncherItem *item = new LauncherItem(appId,
339- desktopFile.displayName(),
340- desktopFile.icon(),
341- this);
342 item->setPinned(true);
343 m_list.insert(index, item);
344 endInsertRows();
345@@ -385,11 +400,8 @@
346 }
347 } else {
348 // Need to create a new LauncherItem and show the highlight
349- DesktopFileHandler desktopFile(appId);
350- if (countVisible && desktopFile.isValid()) {
351- LauncherItem *item = new LauncherItem(appId,
352- desktopFile.displayName(),
353- desktopFile.icon());
354+ LauncherItem *item = loadLauncherItem(appId);
355+ if (countVisible && item) {
356 item->setCountVisible(true);
357 beginInsertRows(QModelIndex(), m_list.count(), m_list.count());
358 m_list.append(item);
359@@ -447,16 +459,12 @@
360 if (itemIndex == -1) {
361 // Need to add it. Just add it into the addedIndex to keep same ordering as the list
362 // in the settings.
363- DesktopFileHandler desktopFile(entry);
364- if (!desktopFile.isValid()) {
365+ LauncherItem *item = loadLauncherItem(entry);
366+ if (!item) {
367 qWarning() << "Couldn't find a .desktop file for" << entry << ". Skipping...";
368 continue;
369 }
370
371- LauncherItem *item = new LauncherItem(entry,
372- desktopFile.displayName(),
373- desktopFile.icon(),
374- this);
375 item->setPinned(true);
376 beginInsertRows(QModelIndex(), addedIndex, addedIndex);
377 m_list.insert(addedIndex, item);
378@@ -521,7 +529,7 @@
379 item->setRecent(true);
380 item->setRunning(true);
381 item->setFocused(app->focused());
382-
383+ item->setIsTouchApp(app->isTouchApp());
384 beginInsertRows(QModelIndex(), m_list.count(), m_list.count());
385 m_list.append(item);
386 endInsertRows();
387
388=== modified file 'plugins/Unity/Launcher/launchermodel.h'
389--- plugins/Unity/Launcher/launchermodel.h 2015-07-29 12:32:57 +0000
390+++ plugins/Unity/Launcher/launchermodel.h 2015-12-02 17:26:09 +0000
391@@ -68,8 +68,8 @@
392
393 private:
394 void storeAppList();
395-
396 void unpin(const QString &appId);
397+ LauncherItem *loadLauncherItem(const QString &appId);
398
399 private Q_SLOTS:
400 void countChanged(const QString &appId, int count);
401
402=== modified file 'qml/Components/Dialogs.qml'
403--- qml/Components/Dialogs.qml 2015-11-06 10:06:58 +0000
404+++ qml/Components/Dialogs.qml 2015-12-02 17:26:09 +0000
405@@ -46,6 +46,19 @@
406 d.showPowerDialog();
407 }
408
409+ function showLegacyAppLaunchDialog(appId) {
410+ if (usageScenario != "desktop" && !d.legacyAppLaunchWarningPopup) {
411+ var comp = Qt.createComponent(Qt.resolvedUrl("LegacyAppLaunchWarningDialog.qml"))
412+ d.legacyAppLaunchWarningPopup = comp.createObject(root, {appId: appId});
413+ d.legacyAppLaunchWarningPopup.cancel.connect(function() {
414+ ApplicationManager.approveApplicationStart(d.legacyAppLaunchWarningPopup.appId, false);
415+ d.legacyAppLaunchWarningPopup.hide();
416+ d.legacyAppLaunchWarningPopup.destroy();
417+ d.legacyAppLaunchWarningPopup = null;
418+ });
419+ }
420+ }
421+
422 onUsageScenarioChanged: {
423 if (usageScenario != "desktop" && legacyAppsModel.count > 0 && !d.modeSwitchWarningPopup) {
424 var comp = Qt.createComponent(Qt.resolvedUrl("ModeSwitchWarningDialog.qml"))
425@@ -58,10 +71,18 @@
426 d.modeSwitchWarningPopup.destroy();
427 d.modeSwitchWarningPopup = null;
428 })
429- } else if (usageScenario == "desktop" && d.modeSwitchWarningPopup) {
430- d.modeSwitchWarningPopup.hide();
431- d.modeSwitchWarningPopup.destroy();
432- d.modeSwitchWarningPopup = null;
433+ } else if (usageScenario == "desktop") {
434+ if (d.modeSwitchWarningPopup) {
435+ d.modeSwitchWarningPopup.hide();
436+ d.modeSwitchWarningPopup.destroy();
437+ d.modeSwitchWarningPopup = null;
438+ }
439+ if (d.legacyAppLaunchWarningPopup) {
440+ ApplicationManager.approveApplicationStart(d.legacyAppLaunchWarningPopup.appId, true);
441+ d.legacyAppLaunchWarningPopup.hide();
442+ d.legacyAppLaunchWarningPopup.destroy();
443+ d.legacyAppLaunchWarningPopup = null;
444+ }
445 }
446 }
447
448@@ -118,6 +139,7 @@
449 objectName: "dialogsPrivate"
450
451 property var modeSwitchWarningPopup: null
452+ property var legacyAppLaunchWarningPopup: null
453
454 function showPowerDialog() {
455 if (!dialogLoader.active) {
456
457=== added file 'qml/Components/LegacyAppLaunchWarningDialog.qml'
458--- qml/Components/LegacyAppLaunchWarningDialog.qml 1970-01-01 00:00:00 +0000
459+++ qml/Components/LegacyAppLaunchWarningDialog.qml 2015-12-02 17:26:09 +0000
460@@ -0,0 +1,51 @@
461+/*
462+ * Copyright (C) 2015 Canonical, Ltd.
463+ *
464+ * This program is free software; you can redistribute it and/or modify
465+ * it under the terms of the GNU General Public License as published by
466+ * the Free Software Foundation; version 3.
467+ *
468+ * This program is distributed in the hope that it will be useful,
469+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
470+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
471+ * GNU General Public License for more details.
472+ *
473+ * You should have received a copy of the GNU General Public License
474+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
475+ */
476+
477+import QtQuick 2.4
478+import QtQuick.Layouts 1.1
479+import Ubuntu.Components 1.3
480+import Ubuntu.Components.ListItems 1.3
481+
482+ShellDialog {
483+ id: root
484+ objectName: "legacyAppLaunchWarningDialog"
485+
486+ property string appId
487+
488+ signal cancel()
489+
490+ Label {
491+ text: i18n.tr("Dock your device to open this app")
492+ fontSize: "large"
493+ wrapMode: Text.Wrap
494+ color: "#5D5D5D"
495+ }
496+
497+ ThinDivider {}
498+
499+ RowLayout {
500+ layoutDirection: Qt.RightToLeft
501+
502+ Button {
503+ objectName: "cancelButton"
504+ text: i18n.tr("Cancel")
505+ color: UbuntuColors.lightGrey
506+ onClicked: {
507+ root.cancel();
508+ }
509+ }
510+ }
511+}
512
513=== modified file 'qml/Shell.qml'
514--- qml/Shell.qml 2015-11-26 13:28:43 +0000
515+++ qml/Shell.qml 2015-12-02 17:26:09 +0000
516@@ -216,6 +216,15 @@
517 onApplicationAdded: {
518 launcher.hide();
519 }
520+
521+ onApplicationStartApprovalRequested: {
522+ var app = ApplicationManager.findApplication(appId);
523+ if (!app.isTouchApp && shell.usageScenario !== "desktop") {
524+ dialogs.showLegacyAppLaunchDialog(appId);
525+ } else {
526+ ApplicationManager.approveApplicationStart(appId, true);
527+ }
528+ }
529 }
530
531 Loader {
532
533=== modified file 'tests/mocks/Unity/Application/Application.qmltypes'
534--- tests/mocks/Unity/Application/Application.qmltypes 2015-02-13 09:01:16 +0000
535+++ tests/mocks/Unity/Application/Application.qmltypes 2015-12-02 17:26:09 +0000
536@@ -164,6 +164,11 @@
537 type: "bool"
538 Parameter { name: "appId"; type: "string" }
539 }
540+ Method {
541+ name: "approveApplicationStart"
542+ Parameter { name: "appId"; type: "string" }
543+ Parameter { name: "approved"; type: "bool" }
544+ }
545 Method { name: "availableApplications"; type: "QStringList" }
546 Method {
547 name: "add"
548
549=== modified file 'tests/mocks/Unity/Application/ApplicationManager.cpp'
550--- tests/mocks/Unity/Application/ApplicationManager.cpp 2015-11-05 14:04:32 +0000
551+++ tests/mocks/Unity/Application/ApplicationManager.cpp 2015-12-02 17:26:09 +0000
552@@ -219,6 +219,8 @@
553 }
554 application->setState(ApplicationInfo::Starting);
555
556+ Q_EMIT applicationStartApprovalRequested(appId);
557+
558 return application;
559 }
560
561@@ -253,6 +255,18 @@
562 return true;
563 }
564
565+bool ApplicationManager::approveApplicationStart(const QString &appId, bool approved)
566+{
567+ ApplicationInfo *application = findApplication(appId);
568+ if (application == nullptr)
569+ return false;
570+
571+ if (!approved) {
572+ remove(application);
573+ }
574+ return true;
575+}
576+
577 QString ApplicationManager::focusedApplicationId() const {
578 for (ApplicationInfo *app : m_runningApplications) {
579 if (app->focused()) {
580
581=== modified file 'tests/mocks/Unity/Application/ApplicationManager.h'
582--- tests/mocks/Unity/Application/ApplicationManager.h 2015-10-01 17:43:10 +0000
583+++ tests/mocks/Unity/Application/ApplicationManager.h 2015-12-02 17:26:09 +0000
584@@ -67,6 +67,7 @@
585 Q_INVOKABLE ApplicationInfo *startApplication(const QString &appId, const QStringList &arguments = QStringList()) override;
586 Q_INVOKABLE ApplicationInfo *startApplication(const QString &appId, ExecFlags flags, const QStringList &arguments = QStringList());
587 Q_INVOKABLE bool stopApplication(const QString &appId) override;
588+ Q_INVOKABLE bool approveApplicationStart(const QString &appId, bool approved) override;
589
590 QString focusedApplicationId() const override;
591
592
593=== modified file 'tests/mocks/Unity/Launcher/CMakeLists.txt'
594--- tests/mocks/Unity/Launcher/CMakeLists.txt 2015-07-23 10:31:56 +0000
595+++ tests/mocks/Unity/Launcher/CMakeLists.txt 2015-12-02 17:26:09 +0000
596@@ -1,5 +1,3 @@
597-pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=7)
598-
599 include_directories(
600 ${CMAKE_CURRENT_SOURCE_DIR}
601 )
602
603=== modified file 'tests/mocks/Unity/Launcher/MockLauncherItem.cpp'
604--- tests/mocks/Unity/Launcher/MockLauncherItem.cpp 2015-09-22 10:44:21 +0000
605+++ tests/mocks/Unity/Launcher/MockLauncherItem.cpp 2015-12-02 17:26:09 +0000
606@@ -182,6 +182,19 @@
607 }
608 }
609
610+bool MockLauncherItem::isTouchApp() const
611+{
612+ return m_isTouchApp;
613+}
614+
615+void MockLauncherItem::setIsTouchApp(bool isTouchApp)
616+{
617+ if (m_isTouchApp != isTouchApp) {
618+ m_isTouchApp = isTouchApp;
619+ Q_EMIT isTouchAppChanged(isTouchApp);
620+ }
621+}
622+
623 unity::shell::launcher::QuickListModelInterface *MockLauncherItem::quickList() const
624 {
625 return m_quickList;
626
627=== modified file 'tests/mocks/Unity/Launcher/MockLauncherItem.h'
628--- tests/mocks/Unity/Launcher/MockLauncherItem.h 2015-07-23 14:13:57 +0000
629+++ tests/mocks/Unity/Launcher/MockLauncherItem.h 2015-12-02 17:26:09 +0000
630@@ -46,6 +46,7 @@
631 bool countVisible() const override;
632 bool focused() const override;
633 bool alerting() const override;
634+ bool isTouchApp() const override;
635
636 unity::shell::launcher::QuickListModelInterface *quickList() const override;
637
638@@ -58,6 +59,7 @@
639 void setCountVisible(bool countVisible);
640 void setFocused(bool focused);
641 void setAlerting(bool alerting);
642+ void setIsTouchApp(bool isTouchApp);
643
644 QString m_appId;
645 QString m_desktopFile;
646@@ -71,6 +73,7 @@
647 bool m_countVisible;
648 bool m_focused;
649 bool m_alerting;
650+ bool m_isTouchApp;
651 MockQuickListModel *m_quickList;
652
653 friend class MockLauncherModel;
654
655=== modified file 'tests/mocks/Unity/Launcher/MockLauncherModel.cpp'
656--- tests/mocks/Unity/Launcher/MockLauncherModel.cpp 2015-11-04 11:29:16 +0000
657+++ tests/mocks/Unity/Launcher/MockLauncherModel.cpp 2015-12-02 17:26:09 +0000
658@@ -117,6 +117,8 @@
659 return item->focused();
660 case RoleAlerting:
661 return item->alerting();
662+ case RoleIsTouchApp:
663+ return item->isTouchApp();
664 }
665
666 return QVariant();
667
668=== modified file 'tests/plugins/Greeter/Unity/Launcher/CMakeLists.txt'
669--- tests/plugins/Greeter/Unity/Launcher/CMakeLists.txt 2015-10-26 14:05:14 +0000
670+++ tests/plugins/Greeter/Unity/Launcher/CMakeLists.txt 2015-12-02 17:26:09 +0000
671@@ -1,5 +1,3 @@
672-pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=7)
673-
674 include_directories(
675 ${CMAKE_CURRENT_SOURCE_DIR}
676 ${CMAKE_CURRENT_BINARY_DIR}
677
678=== modified file 'tests/plugins/Unity/Launcher/CMakeLists.txt'
679--- tests/plugins/Unity/Launcher/CMakeLists.txt 2015-10-26 14:05:14 +0000
680+++ tests/plugins/Unity/Launcher/CMakeLists.txt 2015-12-02 17:26:09 +0000
681@@ -1,5 +1,4 @@
682 pkg_check_modules(GSETTINGS_QT REQUIRED gsettings-qt)
683-pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=7)
684
685 include_directories(
686 ${CMAKE_CURRENT_SOURCE_DIR}
687
688=== modified file 'tests/plugins/Unity/Launcher/launchermodeltest.cpp'
689--- tests/plugins/Unity/Launcher/launchermodeltest.cpp 2015-11-06 13:27:15 +0000
690+++ tests/plugins/Unity/Launcher/launchermodeltest.cpp 2015-12-02 17:26:09 +0000
691@@ -101,6 +101,9 @@
692 }
693 return false;
694 }
695+ bool approveApplicationStart(const QString &, bool) override {
696+ return true;
697+ }
698 bool focusApplication(const QString &appId) override {
699 Q_FOREACH(MockApp* app, m_list) {
700 app->setFocused(app->appId() == appId);
701
702=== modified file 'tests/qmltests/tst_Shell.qml'
703--- tests/qmltests/tst_Shell.qml 2015-11-24 17:44:18 +0000
704+++ tests/qmltests/tst_Shell.qml 2015-12-02 17:26:09 +0000
705@@ -25,6 +25,7 @@
706 import Unity.Application 0.1
707 import Unity.Connectivity 0.1
708 import Unity.Indicators 0.1
709+import Unity.Launcher 0.1
710 import Unity.Notifications 1.0
711 import Unity.Test 0.1
712 import Powerd 0.1
713@@ -1947,5 +1948,39 @@
714 compare(ApplicationManager.findApplication("libreoffice") === null, true);
715 }
716 }
717+
718+ function test_preventOpeningLegacyAppsWithoutDesktop_data() {
719+ return [
720+ {tag: "cancel", plug: false },
721+ {tag: "dock", plug: true }
722+ ];
723+ }
724+
725+ function test_preventOpeningLegacyAppsWithoutDesktop(data) {
726+ loadShell("phone");
727+
728+ // Start a legacy app
729+ ApplicationManager.startApplication("libreoffice");
730+
731+ // The popup should appear
732+ var popup = findChild(root, "legacyAppLaunchWarningDialog");
733+ verify(popup !== null);
734+
735+ if (data.plug) {
736+ shell.usageScenario = "desktop";
737+ waitForRendering(shell);
738+ } else {
739+ var cancelButton = findChild(popup, "cancelButton");
740+ mouseClick(cancelButton);
741+ waitForRendering(root);
742+ }
743+
744+ // Popup must be gone now
745+ popup = findChild(root, "legacyAppLaunchWarningDialog");
746+ verify(popup === null);
747+
748+ // And libreoffice will be started or not depending on user action
749+ compare(ApplicationManager.findApplication("libreoffice") !== null, data.plug);
750+ }
751 }
752 }

Subscribers

People subscribed via source and target branches