Skip to content
This repository was archived by the owner on Jul 22, 2024. It is now read-only.

Commit d3d2abf

Browse files
authored
What's new implementation (#3441)
Show what's new on first run
1 parent 20eff6d commit d3d2abf

16 files changed

+301
-14
lines changed

app/build.gradle

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,10 +105,12 @@ android {
105105
minifyEnabled true
106106
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
107107
signingConfig getUseDebugSigningOnRelease() ? debug.signingConfig : release.signingConfig
108+
buildConfigField 'String', 'PROPS_ENDPOINT', '"http://mixedreality.mozilla.org/FirefoxReality/props.json"'
108109
}
109110
debug {
110111
applicationIdSuffix getDevApplicationIdSuffix()
111112
pseudoLocalesEnabled true
113+
buildConfigField 'String', 'PROPS_ENDPOINT', '"http://mixedreality.mozilla.org/FirefoxReality/props.json"'
112114
}
113115
}
114116

app/src/common/shared/org/mozilla/vrbrowser/browser/SettingsStore.java

Lines changed: 60 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,13 @@
22

33
import android.content.Context;
44
import android.content.SharedPreferences;
5-
import android.database.Observable;
65
import android.graphics.Color;
76
import android.os.StrictMode;
87
import android.preference.PreferenceManager;
98
import android.util.Log;
109

1110
import androidx.annotation.IntDef;
1211
import androidx.annotation.NonNull;
13-
import androidx.databinding.ObservableBoolean;
14-
import androidx.lifecycle.Observer;
1512
import androidx.lifecycle.ViewModelProvider;
1613

1714
import org.json.JSONArray;
@@ -22,6 +19,8 @@
2219
import org.mozilla.vrbrowser.BuildConfig;
2320
import org.mozilla.vrbrowser.R;
2421
import org.mozilla.vrbrowser.VRBrowserActivity;
22+
import org.mozilla.vrbrowser.VRBrowserApplication;
23+
import org.mozilla.vrbrowser.browser.engine.EngineProvider;
2524
import org.mozilla.vrbrowser.telemetry.GleanMetricsService;
2625
import org.mozilla.vrbrowser.telemetry.TelemetryWrapper;
2726
import org.mozilla.vrbrowser.ui.viewmodel.SettingsViewModel;
@@ -30,11 +29,16 @@
3029
import org.mozilla.vrbrowser.utils.StringUtils;
3130
import org.mozilla.vrbrowser.utils.SystemUtils;
3231

32+
import java.io.IOException;
33+
import java.nio.charset.StandardCharsets;
3334
import java.util.ArrayList;
3435
import java.util.Iterator;
3536
import java.util.List;
3637
import java.util.Locale;
3738

39+
import mozilla.components.concept.fetch.Request;
40+
import mozilla.components.concept.fetch.Response;
41+
3842
import static org.mozilla.vrbrowser.utils.ServoUtils.isServoAvailable;
3943

4044
public class SettingsStore {
@@ -125,6 +129,46 @@ public void initModel(@NonNull Context context) {
125129
ViewModelProvider.AndroidViewModelFactory.getInstance(((VRBrowserActivity) context).getApplication()))
126130
.get(SettingsViewModel.class);
127131
mSettingsViewModel.refresh();
132+
update();
133+
}
134+
135+
/**
136+
* Synchronizes the remote properties with the settings storage and notifies the model.
137+
* Any consumer listening to the SettingsViewModel will get notified of the properties updates.
138+
*/
139+
private void update() {
140+
((VRBrowserApplication) mContext.getApplicationContext()).getExecutors().backgroundThread().post(() -> {
141+
Request request = new Request(
142+
BuildConfig.PROPS_ENDPOINT,
143+
Request.Method.GET,
144+
null,
145+
null,
146+
null,
147+
null,
148+
Request.Redirect.FOLLOW,
149+
Request.CookiePolicy.INCLUDE,
150+
false
151+
);
152+
try {
153+
Response response = EngineProvider.INSTANCE.getDefaultClient(mContext).fetch(request);
154+
if (response.getStatus() == 200) {
155+
String json = response.getBody().string(StandardCharsets.UTF_8);
156+
SharedPreferences.Editor editor = mPrefs.edit();
157+
editor.putString(mContext.getString(R.string.settings_key_remote_props), json);
158+
editor.commit();
159+
160+
mSettingsViewModel.setProps(json);
161+
162+
} else {
163+
String json = mPrefs.getString(mContext.getString(R.string.settings_key_remote_props), null);
164+
mSettingsViewModel.setProps(json);
165+
}
166+
167+
} catch (IOException e) {
168+
String json = mPrefs.getString(mContext.getString(R.string.settings_key_remote_props), null);
169+
mSettingsViewModel.setProps(json);
170+
}
171+
});
128172
}
129173

130174
public boolean isCrashReportingEnabled() {
@@ -738,5 +782,17 @@ public void setDownloadsSortingOrder(@SortingContextMenuWidget.Order int order)
738782
public @Storage int getDownloadsSortingOrder() {
739783
return mPrefs.getInt(mContext.getString(R.string.settings_key_downloads_sorting_order), DOWNLOADS_SORTING_ORDER_DEFAULT);
740784
}
741-
}
742785

786+
public void setRemotePropsVersionName(String versionName) {
787+
SharedPreferences.Editor editor = mPrefs.edit();
788+
editor.putString(mContext.getString(R.string.settings_key_remote_props_version_name), versionName);
789+
editor.commit();
790+
791+
mSettingsViewModel.setPropsVersionName(versionName);
792+
}
793+
794+
public String getRemotePropsVersionName() {
795+
return mPrefs.getString(mContext.getString(R.string.settings_key_remote_props_version_name), "0");
796+
}
797+
798+
}

app/src/common/shared/org/mozilla/vrbrowser/ui/viewmodel/SettingsViewModel.java

Lines changed: 54 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,28 @@
77
import androidx.lifecycle.AndroidViewModel;
88
import androidx.lifecycle.MutableLiveData;
99

10+
import com.google.gson.Gson;
11+
import com.google.gson.GsonBuilder;
12+
import com.google.gson.reflect.TypeToken;
13+
1014
import org.mozilla.geckoview.ContentBlocking;
15+
import org.mozilla.vrbrowser.BuildConfig;
1116
import org.mozilla.vrbrowser.browser.SettingsStore;
17+
import org.mozilla.vrbrowser.utils.RemoteProperties;
18+
19+
import java.lang.reflect.Type;
20+
import java.util.Collections;
21+
import java.util.Map;
1222

1323
public class SettingsViewModel extends AndroidViewModel {
1424

1525
private MutableLiveData<ObservableBoolean> isTrackingProtectionEnabled;
1626
private MutableLiveData<ObservableBoolean> isDRMEnabled;
1727
private MutableLiveData<ObservableBoolean> isPopupBlockingEnabled;
1828
private MutableLiveData<ObservableBoolean> isWebXREnabled;
29+
private MutableLiveData<String> propsVersionName;
30+
private MutableLiveData<Map<String, RemoteProperties>> props;
31+
private MutableLiveData<ObservableBoolean> isWhatsNewVisible;
1932

2033
public SettingsViewModel(@NonNull Application application) {
2134
super(application);
@@ -24,21 +37,36 @@ public SettingsViewModel(@NonNull Application application) {
2437
isDRMEnabled = new MutableLiveData<>(new ObservableBoolean(false));
2538
isPopupBlockingEnabled = new MutableLiveData<>(new ObservableBoolean(false));
2639
isWebXREnabled = new MutableLiveData<>(new ObservableBoolean(false));
40+
propsVersionName = new MutableLiveData<>();
41+
props = new MutableLiveData<>(Collections.emptyMap());
42+
isWhatsNewVisible = new MutableLiveData<>(new ObservableBoolean(false));
43+
44+
propsVersionName.observeForever(props -> isWhatsNewVisible());
45+
props.observeForever(versionName -> isWhatsNewVisible());
2746
}
2847

2948
public void refresh() {
3049
int level = SettingsStore.getInstance(getApplication().getBaseContext()).getTrackingProtectionLevel();
3150
boolean isEnabled = level != ContentBlocking.EtpLevel.NONE;
32-
isTrackingProtectionEnabled.setValue(new ObservableBoolean(isEnabled));
51+
isTrackingProtectionEnabled.postValue(new ObservableBoolean(isEnabled));
3352

3453
boolean drmEnabled = SettingsStore.getInstance(getApplication().getBaseContext()).isDrmContentPlaybackEnabled();
35-
isDRMEnabled = new MutableLiveData<>(new ObservableBoolean(drmEnabled));
54+
isDRMEnabled.postValue(new ObservableBoolean(drmEnabled));
3655

3756
boolean popupBlockingEnabled = SettingsStore.getInstance(getApplication().getBaseContext()).isPopUpsBlockingEnabled();
38-
isPopupBlockingEnabled = new MutableLiveData<>(new ObservableBoolean(popupBlockingEnabled));
57+
isPopupBlockingEnabled.postValue(new ObservableBoolean(popupBlockingEnabled));
3958

4059
boolean webxrEnabled = SettingsStore.getInstance(getApplication().getBaseContext()).isWebXREnabled();
41-
isWebXREnabled = new MutableLiveData<>(new ObservableBoolean(webxrEnabled));
60+
isWebXREnabled.postValue(new ObservableBoolean(webxrEnabled));
61+
62+
String appVersionName = SettingsStore.getInstance(getApplication().getBaseContext()).getRemotePropsVersionName();
63+
propsVersionName.postValue(appVersionName);
64+
}
65+
66+
private void isWhatsNewVisible() {
67+
boolean value = !BuildConfig.VERSION_NAME.equals(propsVersionName.getValue()) &&
68+
props.getValue().containsKey(BuildConfig.VERSION_NAME);
69+
isWhatsNewVisible.postValue(new ObservableBoolean(value));
4270
}
4371

4472
public void setIsTrackingProtectionEnabled(boolean isEnabled) {
@@ -73,4 +101,26 @@ public MutableLiveData<ObservableBoolean> getIsWebXREnabled() {
73101
return isWebXREnabled;
74102
}
75103

104+
public void setPropsVersionName(String appVersionName) {
105+
this.propsVersionName.setValue(appVersionName);
106+
}
107+
108+
public MutableLiveData<String> getPropsVersionName() {
109+
return propsVersionName;
110+
}
111+
112+
public void setProps(String json) {
113+
Gson gson = new GsonBuilder().create();
114+
Type type = new TypeToken<Map<String, RemoteProperties>>() {}.getType();
115+
this.props.postValue(gson.fromJson(json, type));
116+
}
117+
118+
public MutableLiveData<Map<String, RemoteProperties>> getProps() {
119+
return props;
120+
}
121+
122+
public MutableLiveData<ObservableBoolean> getIsWhatsNewVisible() {
123+
return isWhatsNewVisible;
124+
}
125+
76126
}

app/src/common/shared/org/mozilla/vrbrowser/ui/viewmodel/WindowViewModel.java

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import androidx.annotation.NonNull;
1212
import androidx.annotation.Nullable;
1313
import androidx.databinding.ObservableBoolean;
14+
import androidx.databinding.ObservableInt;
1415
import androidx.lifecycle.AndroidViewModel;
1516
import androidx.lifecycle.MediatorLiveData;
1617
import androidx.lifecycle.MutableLiveData;
@@ -71,6 +72,8 @@ public class WindowViewModel extends AndroidViewModel {
7172
private MutableLiveData<ObservableBoolean> isDrmUsed;
7273
private MediatorLiveData<ObservableBoolean> isUrlBarButtonsVisible;
7374
private MediatorLiveData<ObservableBoolean> isUrlBarIconsVisible;
75+
private MutableLiveData<ObservableInt> mWidth;
76+
private MutableLiveData<ObservableInt> mHeight;
7477

7578
public WindowViewModel(Application application) {
7679
super(application);
@@ -180,6 +183,9 @@ public WindowViewModel(Application application) {
180183
isUrlBarIconsVisible.addSource(isLoading, mIsUrlBarIconsVisibleObserver);
181184
isUrlBarIconsVisible.addSource(isInsecureVisible, mIsUrlBarIconsVisibleObserver);
182185
isUrlBarIconsVisible.setValue(new ObservableBoolean(false));
186+
187+
mWidth = new MutableLiveData<>(new ObservableInt());
188+
mHeight = new MutableLiveData<>(new ObservableInt());
183189
}
184190

185191
private Observer<ObservableBoolean> mIsTopBarVisibleObserver = new Observer<ObservableBoolean>() {
@@ -373,6 +379,8 @@ public void refresh() {
373379
isWebXRBlocked.postValue(isWebXRBlocked.getValue());
374380
isTrackingEnabled.postValue(isTrackingEnabled.getValue());
375381
isDrmUsed.postValue(isDrmUsed.getValue());
382+
mWidth.postValue(mWidth.getValue());
383+
mHeight.postValue(mHeight.getValue());
376384
}
377385

378386
@NonNull
@@ -785,4 +793,22 @@ public MutableLiveData<ObservableBoolean> getIsUrlBarButtonsVisible() {
785793
public MutableLiveData<ObservableBoolean> getIsUrlBarIconsVisible() {
786794
return isUrlBarIconsVisible;
787795
}
796+
797+
@NonNull
798+
public MutableLiveData<ObservableInt> getWidth() {
799+
return mWidth;
800+
}
801+
802+
public void setWidth(int width) {
803+
this.mWidth.setValue(new ObservableInt(width));
804+
}
805+
806+
@NonNull
807+
public MutableLiveData<ObservableInt> getHeight() {
808+
return mHeight;
809+
}
810+
811+
public void setHeight(int height) {
812+
this.mHeight.setValue(new ObservableInt(height));
813+
}
788814
}

app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/NavigationBarWidget.java

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
import android.util.Log;
1616
import android.util.Pair;
1717
import android.view.LayoutInflater;
18-
import android.view.MotionEvent;
1918
import android.view.View;
2019
import android.webkit.URLUtil;
2120
import android.widget.EditText;
@@ -29,6 +28,7 @@
2928

3029
import org.mozilla.geckoview.GeckoSession;
3130
import org.mozilla.geckoview.GeckoSessionSettings;
31+
import org.mozilla.vrbrowser.BuildConfig;
3232
import org.mozilla.vrbrowser.R;
3333
import org.mozilla.vrbrowser.VRBrowserActivity;
3434
import org.mozilla.vrbrowser.VRBrowserApplication;
@@ -44,6 +44,7 @@
4444
import org.mozilla.vrbrowser.search.suggestions.SuggestionsProvider;
4545
import org.mozilla.vrbrowser.telemetry.GleanMetricsService;
4646
import org.mozilla.vrbrowser.telemetry.TelemetryWrapper;
47+
import org.mozilla.vrbrowser.ui.viewmodel.SettingsViewModel;
4748
import org.mozilla.vrbrowser.ui.viewmodel.TrayViewModel;
4849
import org.mozilla.vrbrowser.ui.viewmodel.WindowViewModel;
4950
import org.mozilla.vrbrowser.ui.views.NavigationURLBar;
@@ -59,6 +60,7 @@
5960
import org.mozilla.vrbrowser.ui.widgets.menus.VideoProjectionMenuWidget;
6061
import org.mozilla.vrbrowser.utils.AnimationHelper;
6162
import org.mozilla.vrbrowser.utils.ConnectivityReceiver;
63+
import org.mozilla.vrbrowser.utils.RemoteProperties;
6264
import org.mozilla.vrbrowser.utils.UrlUtils;
6365

6466
import java.util.ArrayList;
@@ -92,6 +94,7 @@ public interface NavigationListener {
9294

9395
private WindowViewModel mViewModel;
9496
private TrayViewModel mTrayViewModel;
97+
private SettingsViewModel mSettingsViewModel;
9598
private NavigationBarBinding mBinding;
9699
private AudioEngine mAudio;
97100
private WindowWidget mAttachedWindow;
@@ -254,6 +257,14 @@ private void updateUI() {
254257
}
255258
});
256259

260+
mBinding.navigationBarNavigation.whatsNew.setOnClickListener(v -> {
261+
SettingsStore.getInstance(getContext()).setRemotePropsVersionName(BuildConfig.VERSION_NAME);
262+
RemoteProperties props = mSettingsViewModel.getProps().getValue().get(BuildConfig.VERSION_NAME);
263+
if (props != null) {
264+
mWidgetManager.openNewTabForeground(props.getWhatsNewUrl());
265+
}
266+
});
267+
257268
mBinding.navigationBarNavigation.menuButton.setOnClickListener(view -> {
258269
view.requestFocusFromTouch();
259270

@@ -510,6 +521,10 @@ public void detachFromWindow() {
510521
mViewModel.getIsPopUpBlocked().removeObserver(mIsPopUpBlockedListener);
511522
mViewModel = null;
512523
}
524+
525+
if (mSettingsViewModel != null) {
526+
mSettingsViewModel = null;
527+
}
513528
}
514529

515530
@Override
@@ -526,8 +541,15 @@ public void attachToWindow(@NonNull WindowWidget aWindow) {
526541
(VRBrowserActivity)getContext(),
527542
ViewModelProvider.AndroidViewModelFactory.getInstance(((VRBrowserActivity) getContext()).getApplication()))
528543
.get(String.valueOf(mAttachedWindow.hashCode()), WindowViewModel.class);
544+
mSettingsViewModel = new ViewModelProvider(
545+
(VRBrowserActivity)getContext(),
546+
ViewModelProvider.AndroidViewModelFactory.getInstance(((VRBrowserActivity) getContext()).getApplication()))
547+
.get(SettingsViewModel.class);
529548

530549
mBinding.setViewmodel(mViewModel);
550+
mBinding.setSettingsmodel(mSettingsViewModel);
551+
552+
mSettingsViewModel.refresh();
531553

532554
mViewModel.getIsActiveWindow().observeForever(mIsActiveWindowObserver);
533555
mViewModel.getIsPopUpBlocked().observeForever(mIsPopUpBlockedListener);

0 commit comments

Comments
 (0)