Commit 33d59044 authored by Julia Reynolds's avatar Julia Reynolds Committed by Android (Google) Code Review

Merge "Migrate package level notification settings to topic level."

parents df0a005d 6f526fca
......@@ -6011,6 +6011,9 @@
<!-- Sound & notification > Notification section: Title for the option managing notifications per application. [CHAR LIMIT=30] -->
<string name="app_notifications_title">App notifications</string>
<!-- Sound & notification > Notification section: Title for the option managing notifications per topic. [CHAR LIMIT=30] -->
<string name="topic_notifications_title">Topic notifications</string>
<!-- Sound & notification > Sound section: Title for the other sounds option and associated settings page. [CHAR LIMIT=30] -->
<string name="other_sound_settings">Other sounds</string>
......@@ -6093,17 +6096,17 @@
<!-- [CHAR LIMIT=NONE] App notification settings: Block option description-->
<string name="app_notification_block_summary">Never show notifications from this app</string>
<!-- [CHAR LIMIT=NONE] App notification settings: Priority option title -->
<string name="app_notification_priority_title">Treat as priority</string>
<!-- [CHAR LIMIT=NONE] App notification settings: Override DND option title -->
<string name="app_notification_override_dnd_title">Override Do Not Disturb</string>
<!-- [CHAR LIMIT=NONE] App notification settings: Priority option description-->
<string name="app_notification_priority_summary">Let this app\u2019s notifications be heard when Do not disturb is set to Priority only</string>
<!-- [CHAR LIMIT=NONE] App notification settings: Override DND option description-->
<string name="app_notification_override_dnd_summary">Let these notifications continue to interrupt when Do Not Disturb is set to Priority Only</string>
<!-- [CHAR LIMIT=NONE] App notification settings: Sensitive option title -->
<string name="app_notification_sensitive_title">Hide sensitive content</string>
<!-- [CHAR LIMIT=NONE] App notification settings: Sensitive option description-->
<string name="app_notification_sensitive_summary">When the device is locked, hide content in this app\u2019s notifications that might reveal private information</string>
<string name="app_notification_sensitive_summary">When the device is locked, hide content in these notifications that might reveal private information</string>
<!-- [CHAR LIMIT=20] Notification settings: App notifications row summary when banned -->
<string name="app_notification_row_banned">Blocked</string>
......@@ -6484,10 +6487,6 @@
<string name="notifications_enabled">Normal</string>
<!-- App notification summary with notifications disabled [CHAR LIMIT=40] -->
<string name="notifications_disabled">Block</string>
<!-- App notification summary with notifications sensitive [CHAR LIMIT=40] -->
<string name="notifications_sensitive">Sensitive content hidden</string>
<!-- App notification summary with notifications priority [CHAR LIMIT=40] -->
<string name="notifications_priority">Priority</string>
<!-- App notification summary with 2 items [CHAR LIMIT=15] -->
<string name="notifications_two_items"><xliff:g id="notif_state" example="Priority">%1$s</xliff:g> / <xliff:g id="notif_state" example="Priority">%2$s</xliff:g></string>
<!-- App notification summary with 3 items [CHAR LIMIT=15] -->
......@@ -6528,10 +6527,6 @@
<string name="filter_work_apps">Work</string>
<!-- Label for showing apps with blocked notifications in list [CHAR LIMIT=30] -->
<string name="filter_notif_blocked_apps">Blocked</string>
<!-- Label for showing apps with priority notifications in list [CHAR LIMIT=30] -->
<string name="filter_notif_priority_apps">Priority</string>
<!-- Label for showing apps with sensitive notifications in list [CHAR LIMIT=30] -->
<string name="filter_notif_sensitive_apps">Sensitive content hidden</string>
<!-- Label for showing apps with domain URLs (data URI with http or https) in list [CHAR LIMIT=30] -->
<string name="filter_with_domain_urls_apps">With domain URLs</string>
......
......@@ -26,22 +26,6 @@
android:order="1"
android:persistent="false" />
<!-- Priority -->
<SwitchPreference
android:key="priority"
android:title="@string/app_notification_priority_title"
android:summary="@string/app_notification_priority_summary"
android:order="2"
android:persistent="false" />
<!-- Sensitive -->
<SwitchPreference
android:key="sensitive"
android:title="@string/app_notification_sensitive_title"
android:summary="@string/app_notification_sensitive_summary"
android:order="4"
android:persistent="false" />
<!-- App notification preferences -->
<Preference
android:key="app_settings"
......
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2015 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
android:title="@string/topic_notifications_title"
android:key="topic_notification_settings">
<!-- Bypass DND -->
<SwitchPreference
android:key="bypass_dnd"
android:title="@string/app_notification_override_dnd_title"
android:summary="@string/app_notification_override_dnd_summary"
android:order="2"
android:persistent="false" />
<!-- Sensitive -->
<SwitchPreference
android:key="sensitive"
android:title="@string/app_notification_sensitive_title"
android:summary="@string/app_notification_sensitive_summary"
android:order="4"
android:persistent="false" />
</PreferenceScreen>
......@@ -66,26 +66,4 @@ public class AppStateNotificationBridge extends AppStateBaseBridge {
return info.extraInfo != null && ((AppRow) info.extraInfo).banned;
}
};
public static final AppFilter FILTER_APP_NOTIFICATION_PRIORITY = new AppFilter() {
@Override
public void init() {
}
@Override
public boolean filterApp(AppEntry info) {
return info.extraInfo != null && ((AppRow) info.extraInfo).priority;
}
};
public static final AppFilter FILTER_APP_NOTIFICATION_SENSITIVE = new AppFilter() {
@Override
public void init() {
}
@Override
public boolean filterApp(AppEntry info) {
return info.extraInfo != null && ((AppRow) info.extraInfo).sensitive;
}
};
}
......@@ -814,25 +814,7 @@ public class InstalledAppDetails extends AppInfoBase
if (appRow.banned) {
return context.getString(R.string.notifications_disabled);
}
ArrayList<CharSequence> notifSummary = new ArrayList<>();
if (appRow.priority) {
notifSummary.add(context.getString(R.string.notifications_priority));
}
if (appRow.sensitive) {
notifSummary.add(context.getString(R.string.notifications_sensitive));
}
switch (notifSummary.size()) {
case 3:
return context.getString(R.string.notifications_three_items,
notifSummary.get(0), notifSummary.get(1), notifSummary.get(2));
case 2:
return context.getString(R.string.notifications_two_items,
notifSummary.get(0), notifSummary.get(1));
case 1:
return notifSummary.get(0);
default:
return context.getString(R.string.notifications_enabled);
}
return context.getString(R.string.notifications_enabled);
}
private class MemoryUpdater extends AsyncTask<Void, Void, ProcStatsPackageEntry> {
......
......@@ -138,8 +138,6 @@ public class ManageApplications extends InstrumentedFragment
R.string.filter_enabled_apps, // Enabled
R.string.filter_apps_disabled, // Disabled
R.string.filter_notif_blocked_apps, // Blocked Notifications
R.string.filter_notif_priority_apps, // Priority Notifications
R.string.filter_notif_sensitive_apps, // Sensitive Notifications
R.string.filter_personal_apps, // Personal
R.string.filter_work_apps, // Work
R.string.filter_with_domain_urls_apps, // Domain URLs
......@@ -158,8 +156,6 @@ public class ManageApplications extends InstrumentedFragment
ApplicationsState.FILTER_ALL_ENABLED, // Enabled
ApplicationsState.FILTER_DISABLED, // Disabled
AppStateNotificationBridge.FILTER_APP_NOTIFICATION_BLOCKED, // Blocked Notifications
AppStateNotificationBridge.FILTER_APP_NOTIFICATION_PRIORITY, // Priority Notifications
AppStateNotificationBridge.FILTER_APP_NOTIFICATION_SENSITIVE, // Sensitive Notifications
ApplicationsState.FILTER_PERSONAL, // Personal
ApplicationsState.FILTER_WORK, // Work
ApplicationsState.FILTER_WITH_DOMAIN_URLS, // Apps with Domain URLs
......
......@@ -54,8 +54,6 @@ public class AppNotificationSettings extends SettingsPreferenceFragment {
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
private static final String KEY_BLOCK = "block";
private static final String KEY_PRIORITY = "priority";
private static final String KEY_SENSITIVE = "sensitive";
private static final String KEY_APP_SETTINGS = "app_settings";
private static final Intent APP_NOTIFICATION_PREFS_CATEGORY_INTENT
......@@ -66,8 +64,6 @@ public class AppNotificationSettings extends SettingsPreferenceFragment {
private Context mContext;
private SwitchPreference mBlock;
private SwitchPreference mPriority;
private SwitchPreference mSensitive;
private AppRow mAppRow;
private boolean mCreated;
private boolean mIsSystemPackage;
......@@ -130,8 +126,6 @@ public class AppNotificationSettings extends SettingsPreferenceFragment {
addPreferencesFromResource(R.xml.app_notification_settings);
mBlock = (SwitchPreference) findPreference(KEY_BLOCK);
mPriority = (SwitchPreference) findPreference(KEY_PRIORITY);
mSensitive = (SwitchPreference) findPreference(KEY_SENSITIVE);
mAppRow = mBackend.loadAppRow(pm, info.applicationInfo);
......@@ -140,10 +134,29 @@ public class AppNotificationSettings extends SettingsPreferenceFragment {
rows.put(mAppRow.pkg, mAppRow);
collectConfigActivities(getPackageManager(), rows);
// Add topics
List<Notification.Topic> topics = mBackend.getTopics(pkg, mUid);
for (Notification.Topic topic : topics) {
Preference topicPreference = new Preference(mContext);
topicPreference.setKey(topic.getId());
topicPreference.setTitle(topic.getLabel());
// Create intent for this preference.
Bundle topicArgs = new Bundle();
topicArgs.putInt(AppInfoBase.ARG_PACKAGE_UID, mUid);
topicArgs.putParcelable(TopicNotificationSettings.ARG_TOPIC, topic);
topicArgs.putBoolean(AppHeader.EXTRA_HIDE_INFO_BUTTON, true);
topicArgs.putParcelable(TopicNotificationSettings.ARG_PACKAGE_INFO, info);
Intent topicIntent = Utils.onBuildStartFragmentIntent(getActivity(),
TopicNotificationSettings.class.getName(),
topicArgs, null, R.string.topic_notifications_title, null, false);
topicPreference.setIntent(topicIntent);
// Add preference to the settings menu.
getPreferenceScreen().addPreference(topicPreference);
}
mBlock.setChecked(mAppRow.banned);
updateDependents(mAppRow.banned);
mPriority.setChecked(mAppRow.priority);
mSensitive.setChecked(mAppRow.sensitive);
mBlock.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
@Override
......@@ -160,22 +173,6 @@ public class AppNotificationSettings extends SettingsPreferenceFragment {
}
});
mPriority.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
final boolean priority = (Boolean) newValue;
return mBackend.setHighPriority(pkg, mUid, priority);
}
});
mSensitive.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
final boolean sensitive = (Boolean) newValue;
return mBackend.setSensitive(pkg, mUid, sensitive);
}
});
if (mAppRow.settingsIntent != null) {
findPreference(KEY_APP_SETTINGS).setOnPreferenceClickListener(
new OnPreferenceClickListener() {
......@@ -200,15 +197,7 @@ public class AppNotificationSettings extends SettingsPreferenceFragment {
}
private void updateDependents(boolean banned) {
final boolean lockscreenSecure = new LockPatternUtils(getActivity()).isSecure(
UserHandle.myUserId());
final boolean lockscreenNotificationsEnabled = getLockscreenNotificationsEnabled();
final boolean allowPrivate = getLockscreenAllowPrivateNotifications();
setVisible(mBlock, !mIsSystemPackage);
setVisible(mPriority, mIsSystemPackage || !banned);
setVisible(mSensitive, mIsSystemPackage || !banned && lockscreenSecure
&& lockscreenNotificationsEnabled && allowPrivate);
}
private void setVisible(Preference p, boolean visible) {
......@@ -221,16 +210,6 @@ public class AppNotificationSettings extends SettingsPreferenceFragment {
}
}
private boolean getLockscreenNotificationsEnabled() {
return Settings.Secure.getInt(getContentResolver(),
Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, 0) != 0;
}
private boolean getLockscreenAllowPrivateNotifications() {
return Settings.Secure.getInt(getContentResolver(),
Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, 0) != 0;
}
private void toastAndFinish() {
Toast.makeText(mContext, R.string.app_not_found_dlg_text, Toast.LENGTH_SHORT).show();
getActivity().finish();
......
......@@ -15,17 +15,22 @@
*/
package com.android.settings.notification;
import com.google.android.collect.Lists;
import android.app.INotificationManager;
import android.app.Notification;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.ParceledListSlice;
import android.graphics.drawable.Drawable;
import android.os.ServiceManager;
import android.service.notification.NotificationListenerService;
import android.util.Log;
import java.util.List;
public class NotificationBackend {
private static final String TAG = "NotificationBackend";
......@@ -44,8 +49,19 @@ public class NotificationBackend {
}
row.icon = app.loadIcon(pm);
row.banned = getNotificationsBanned(row.pkg, row.uid);
row.priority = getHighPriority(row.pkg, row.uid);
row.sensitive = getSensitive(row.pkg, row.uid);
return row;
}
public TopicRow loadTopicRow(PackageManager pm, ApplicationInfo app, Notification.Topic topic) {
final TopicRow row = new TopicRow();
row.pkg = app.packageName;
row.uid = app.uid;
row.label = topic.getLabel();
row.icon = app.loadIcon(pm);
row.topic = topic;
row.priority = getBypassZenMode(row.pkg, row.uid, row.topic);
row.sensitive = getSensitive(row.pkg, row.uid, row.topic);
row.banned = getNotificationsBanned(row.pkg, row.uid);
return row;
}
......@@ -69,19 +85,20 @@ public class NotificationBackend {
}
}
public boolean getHighPriority(String pkg, int uid) {
public boolean getBypassZenMode(String pkg, int uid, Notification.Topic topic) {
try {
return sINM.getPackagePriority(pkg, uid) == Notification.PRIORITY_MAX;
return sINM.getTopicPriority(pkg, uid, topic) == Notification.PRIORITY_MAX;
} catch (Exception e) {
Log.w(TAG, "Error calling NoMan", e);
return false;
}
}
public boolean setHighPriority(String pkg, int uid, boolean highPriority) {
public boolean setBypassZenMode(String pkg, int uid, Notification.Topic topic,
boolean bypassZen) {
try {
sINM.setPackagePriority(pkg, uid,
highPriority ? Notification.PRIORITY_MAX : Notification.PRIORITY_DEFAULT);
sINM.setTopicPriority(pkg, uid, topic,
bypassZen ? Notification.PRIORITY_MAX : Notification.PRIORITY_DEFAULT);
return true;
} catch (Exception e) {
Log.w(TAG, "Error calling NoMan", e);
......@@ -89,18 +106,19 @@ public class NotificationBackend {
}
}
public boolean getSensitive(String pkg, int uid) {
public boolean getSensitive(String pkg, int uid, Notification.Topic topic) {
try {
return sINM.getPackageVisibilityOverride(pkg, uid) == Notification.VISIBILITY_PRIVATE;
return sINM.getTopicVisibilityOverride(pkg, uid, topic)
== Notification.VISIBILITY_PRIVATE;
} catch (Exception e) {
Log.w(TAG, "Error calling NoMan", e);
return false;
}
}
public boolean setSensitive(String pkg, int uid, boolean sensitive) {
public boolean setSensitive(String pkg, int uid, Notification.Topic topic, boolean sensitive) {
try {
sINM.setPackageVisibilityOverride(pkg, uid,
sINM.setTopicVisibilityOverride(pkg, uid, topic,
sensitive ? Notification.VISIBILITY_PRIVATE
: NotificationListenerService.Ranking.VISIBILITY_NO_OVERRIDE);
return true;
......@@ -110,6 +128,16 @@ public class NotificationBackend {
}
}
public List<Notification.Topic> getTopics(String pkg, int uid) {
try {
final ParceledListSlice<Notification.Topic> parceledList = sINM.getTopics(pkg, uid);
return parceledList.getList();
} catch (Exception e) {
Log.w(TAG, "Error calling NoMan", e);
return Lists.newArrayList();
}
}
static class Row {
public String section;
}
......@@ -121,9 +149,13 @@ public class NotificationBackend {
public CharSequence label;
public Intent settingsIntent;
public boolean banned;
public boolean first; // first app in section
}
public static class TopicRow extends AppRow {
public Notification.Topic topic;
public boolean priority;
public boolean sensitive;
public boolean first; // first app in section
}
}
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.notification;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.widget.LockPatternUtils;
import com.android.settings.AppHeader;
import com.android.settings.R;
import com.android.settings.SettingsPreferenceFragment;
import com.android.settings.Utils;
import com.android.settings.applications.AppInfoBase;
import com.android.settings.notification.NotificationBackend.TopicRow;
import android.app.Notification;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Bundle;
import android.os.UserHandle;
import android.provider.Settings;
import android.support.v14.preference.SwitchPreference;
import android.support.v7.preference.Preference;
import android.support.v7.preference.Preference.OnPreferenceChangeListener;
import android.text.TextUtils;
import android.util.Log;
import android.widget.Toast;
/** These settings are per topic, so should not be returned in global search results. */
public class TopicNotificationSettings extends SettingsPreferenceFragment {
private static final String TAG = "TopicNotiSettings";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
protected static final String ARG_TOPIC = "arg_topic";
protected static final String ARG_PACKAGE_INFO = "arg_info";
private static final String KEY_BYPASS_DND = "bypass_dnd";
private static final String KEY_SENSITIVE = "sensitive";
private final NotificationBackend mBackend = new NotificationBackend();
private Context mContext;
private SwitchPreference mPriority;
private SwitchPreference mSensitive;
private TopicRow mTopicRow;
private boolean mCreated;
private boolean mIsSystemPackage;
private int mUid;
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if (DEBUG) Log.d(TAG, "onActivityCreated mCreated=" + mCreated);
if (mCreated) {
Log.w(TAG, "onActivityCreated: ignoring duplicate call");
return;
}
mCreated = true;
if (mTopicRow == null) return;
AppHeader.createAppHeader(
this, mTopicRow.icon, mTopicRow.label, mTopicRow.pkg, mTopicRow.uid);
}
@Override
protected int getMetricsCategory() {
return MetricsLogger.NOTIFICATION_TOPIC_NOTIFICATION;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mContext = getActivity();
Intent intent = getActivity().getIntent();
Bundle args = getArguments();
if (DEBUG) Log.d(TAG, "onCreate getIntent()=" + intent);
if (intent == null && args == null) {
Log.w(TAG, "No intent");
toastAndFinish();
return;
}
final Notification.Topic topic = args != null && args.containsKey(ARG_TOPIC)
? (Notification.Topic) args.getParcelable(ARG_TOPIC) : null;
if (topic == null) {
toastAndFinish();
return;
}
final PackageInfo info = args != null && args.containsKey(ARG_PACKAGE_INFO)
? (PackageInfo) args.getParcelable(ARG_PACKAGE_INFO) : null;
if (info == null) {
Log.w(TAG, "Failed to find package info");
toastAndFinish();
return;
}
mUid = args != null && args.containsKey(AppInfoBase.ARG_PACKAGE_UID)
? args.getInt(AppInfoBase.ARG_PACKAGE_UID)
: intent.getIntExtra(Settings.EXTRA_APP_UID, -1);
if (mUid == -1) {
Log.w(TAG, "Missing extras: " + Settings.EXTRA_APP_UID + " was " + mUid);
toastAndFinish();
return;
}
final PackageManager pm = getPackageManager();
mIsSystemPackage = Utils.isSystemPackage(pm, info);
addPreferencesFromResource(R.xml.topic_notification_settings);
mPriority = (SwitchPreference) findPreference(KEY_BYPASS_DND);
mSensitive = (SwitchPreference) findPreference(KEY_SENSITIVE);
mTopicRow = mBackend.loadTopicRow(pm, info.applicationInfo, topic);
mPriority.setChecked(mTopicRow.priority);
mSensitive.setChecked(mTopicRow.sensitive);
mPriority.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
final boolean bypassZenMode = (Boolean) newValue;
return mBackend.setBypassZenMode(info.packageName, mUid, topic, bypassZenMode);
}
});
mSensitive.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
final boolean sensitive = (Boolean) newValue;
return mBackend.setSensitive(info.packageName, mUid, topic, sensitive);
}
});
updateDependents(mTopicRow.banned);
}
@Override
public void onResume() {
super.onResume();
if (mUid != -1 && getPackageManager().getPackagesForUid(mUid) == null) {
// App isn't around anymore, must have been removed.
finish();
}
}
private void updateDependents(boolean banned) {
final boolean lockscreenSecure = new LockPatternUtils(getActivity()).isSecure(
UserHandle.myUserId());
final boolean lockscreenNotificationsEnabled = getLockscreenNotificationsEnabled();
final boolean allowPrivate = getLockscreenAllowPrivateNotifications();
setVisible(mPriority, mIsSystemPackage || !banned);
setVisible(mSensitive, mIsSystemPackage || !banned && lockscreenSecure
&& lockscreenNotificationsEnabled && allowPrivate);
}
private void setVisible(Preference p, boolean visible) {
final boolean isVisible = getPreferenceScreen().findPreference(p.getKey()) != null;
if (isVisible == visible) return;
if (visible) {
getPreferenceScreen().addPreference(p);
} else {
getPreferenceScreen().removePreference(p);
}
}
private boolean getLockscreenNotificationsEnabled() {
return Settings.Secure.getInt(getContentResolver(),
Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, 0) != 0;
}
private boolean getLockscreenAllowPrivateNotifications() {
return Settings.Secure.getInt(getContentResolver(),
Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, 0) != 0;
}
private void toastAndFinish() {
Toast.makeText(mContext, R.string.app_not_found_dlg_text, Toast.LENGTH_SHORT).show();
getActivity().finish();
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment