Stuck Progress Notification (SPN)

ECn Categories > Stuck Progress Notification (SPN)

This ECn type is exhibited when a progress noti cation gets stuck in the GUI (not necessarily blocking the app) because of a connection problem.

Amount of Issues App List
14 (A2) Wire, (A10) OsmAnd, (A23) Prey, (A31) OpenWeather, (A32) Cannonball, (A36) Stepik, (A39) Habitica, (A46) Open Food, (A49) PocketHub for GitHub

Examples

PocketHub

Category: Productivity
v 0.3.1
Scenario: Login without internet connection
This video shows the login process in PocketHub app, at second 2 the user clicks in the top right corder of the screen on the "LOG IN" button, this redirects to the github login screen, the user fill the form with its credentials and clicks the "sign in" button at second 13, after that a new dialog is displayed letting him know that the process is being executed, nevertheless due to the conectionless state and as it can be seen in the snippets explanation the dialog will not disapear until the response from the web page is returned, but that will not happen without internet. This is a clear example of a stucked progress notification.

The following code snippets show the classes and files that are involved in the generation of the previuos issue.

To start in the following snippet we can see the menu item that the user clicks at the first second of the video, this menu item has an id defined at line 21.

app/src/main/res/menu/activity_login.xml

   <item
21.    android:id="@+id/m_login"
       app:showAsAction="always"
       android:title="@string/log_in"/>

Now that we know the id of the menu item we can search in the class that manages the event, where the id is used. Following the android schema for menu usage we have to look in the “onCreateOptionsMenu” that the layour used is the same that the one that defines our menu item.

app/src/main/java/com/github/pockethub/android/accounts/LoginActivity.java

    @Override
    public boolean onCreateOptionsMenu(Menu optionMenu) {
251.    getMenuInflater().inflate(R.menu.activity_login, optionMenu);
        return true;
    }

Aditionally, we have to search in “onOptionsItemSelected” what is the action assigned to the menu item. As we can see at lines 208 and 209, once it is clicked the “handleLogin” method is called.

app/src/main/java/com/github/pockethub/android/accounts/LoginActivity.java

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
        case R.id.m_login:
            handleLogin();
            return true;
        default:
            return super.onOptionsItemSelected(item);
    }
}

But from the implementation that can be seen in the following snippet the “handleLogin” method only calls “openLoginInBrowser” method.

app/src/main/java/com/github/pockethub/android/accounts/LoginActivity.java

    public void handleLogin() {
178.    openLoginInBrowser();
    }

Now we have arrived to the main method of the event flow in this class, as we can see at betwwen lines 183 to 190 and url is build, but the important of this method happen between lines 192 to 194 where the url is send to an activity in charge of managing the login process using the url already created.

app/src/main/java/com/github/pockethub/android/accounts/LoginActivity.java

    private void openLoginInBrowser() {
        String initialScope = "user,public_repo,repo,delete_repo,notifications,gist";
        HttpUrl.Builder url = new HttpUrl.Builder()
                .scheme("https")
                .host(OAUTH_HOST)
                .addPathSegment("login")
                .addPathSegment("oauth")
                .addPathSegment("authorize")
                .addQueryParameter("client_id", getString(R.string.github_client))
                .addQueryParameter("scope", initialScope);
    
192.    Intent intent = new Intent(this, LoginWebViewActivity.class);
193.    intent.putExtra(INTENT_EXTRA_URL, url.toString());
194.    startActivityForResult(intent, WEBVIEW_REQUEST_CODE);
    }

Finally when the event flow arrives to this class, on the “onCreate” method the webview that manages the url received via intend extra is initialized. First a dialog is created with the text “Loading…” that can be seen at second 13 of the video. It is worth noting that at line 56 in the progress assign a “true” value is send, this allows the library used for the dialogs to know that this progress dialog will not have a intermediate state, so the the loading circle will turn while the dialog is shown.

app/src/main/java/com/github/pockethub/android/accounts/LoginWebViewActivity.java

   webView.setWebViewClient(new WebViewClient() {
       MaterialDialog dialog = new MaterialDialog.Builder(LoginWebViewActivity.this)
               .content(R.string.loading)
56.            .progress(true, 0)
               .build();

As part of the webview initialization, some method have to be override in order to work. First, we have “onPageStarted” that will be called when the url loading process is started, in this specific case once the wep page loading starts the dialog already created is shown.

app/src/main/java/com/github/pockethub/android/accounts/LoginWebViewActivity.java

   @Override
   public void onPageStarted(android.webkit.WebView view, String url, Bitmap favicon) {
61.    dialog.show();
   }

Second, we have “onPageFinished” method that is called when the web page loading process end, in this specific case once the web page ends its loading the dialog that says loading is dismissed.

app/src/main/java/com/github/pockethub/android/accounts/LoginWebViewActivity.java

   @Override
   public void onPageFinished(android.webkit.WebView view, String url) {
66.    dialog.dismiss();
   }

Third, we have “shouldOverrideurlLoading” method that is called when inside of the loaded web page an anchor to other web page is activated, so there is a new url to be displayed inside the webView. In this specific case this method is called when the user already fill the form and click in “sign in” button. It is worth nothing that this method has to return a boolean value to know if the event is going to be managed in the existent webView or if it will be managed on the host application.

app/src/main/java/com/github/pockethub/android/accounts/LoginWebViewActivity.java

   @Override
   public boolean shouldOverrideUrlLoading(android.webkit.WebView view,
                                           WebResourceRequest request) {
   
80.    return overrideOAuth(request.getUrl())
81.            || super.shouldOverrideUrlLoading(view, request);
   }

To end this event flow, when the url is changed the “shouldOverrideUrlLoading” call overrideOAuth. This method verifies if the user clicks on the “sign in” button or in oen of the other links that are displayed in the webpage. If the user click in other link the webview manages the event and shos the new webpage. If the user clicks in the “sign in” button the event is managed by the host application and the already explained method will be called. In specific the “onPageStarted” method will be called while due to connectionless state the “onPageFinished” method will not.

app/src/main/java/com/github/pockethub/android/accounts/LoginWebViewActivity.java

   private boolean overrideOAuth(Uri uri) {
85.    if (uri.getScheme().equals(getString(R.string.github_oauth_scheme))) {
           Intent data = new Intent();
           data.setData(uri);
           setResult(RESULT_OK, data);
           finish();
90.        return true;
       }
   
       return false;
   }