1 package com.android.car.media;
2 
3 import android.app.PendingIntent;
4 import android.car.drivingstate.CarUxRestrictions;
5 import android.os.Bundle;
6 import android.util.Log;
7 import android.view.LayoutInflater;
8 import android.view.View;
9 import android.view.ViewGroup;
10 
11 import androidx.annotation.NonNull;
12 import androidx.fragment.app.Fragment;
13 
14 import com.android.car.apps.common.UxrButton;
15 import com.android.car.apps.common.UxrTextView;
16 import com.android.car.apps.common.util.CarPackageManagerUtils;
17 
18 /**
19  * A {@link Fragment} that displays the playback state error.
20  */
21 public class ErrorFragment extends Fragment {
22     private final String TAG = "ErrorFragment";
23 
24     private static final String ERROR_RESOLUTION_ACTION_MESSAGE = "ERROR_RESOLUTION_ACTION_MESSAGE";
25     private static final String ERROR_RESOLUTION_ACTION_LABEL = "ERROR_RESOLUTION_ACTION_LABEL";
26     private static final String ERROR_RESOLUTION_ACTION_INTENT = "ERROR_RESOLUTION_ACTION_INTENT";
27 
28     // mErrorMessageView is defined explicitly as a UxrTextView instead of a TextView to
29     // provide clarity as it may be misleading to assume that mErrorMessageView extends all TextView
30     // methods. In addition, it increases discoverability of runtime issues that may occur.
31     private UxrTextView mErrorMessageView;
32     private UxrButton mErrorButton;
33 
34     private String mErrorMessageStr;
35     private String mErrorLabel;
36     private PendingIntent mPendingIntent;
37 
newInstance(String message, String label, PendingIntent intent)38     public static ErrorFragment newInstance(String message, String label, PendingIntent intent) {
39         ErrorFragment fragment = new ErrorFragment();
40 
41         Bundle args = new Bundle();
42         args.putString(ERROR_RESOLUTION_ACTION_MESSAGE, message);
43         args.putString(ERROR_RESOLUTION_ACTION_LABEL, label);
44         args.putParcelable(ERROR_RESOLUTION_ACTION_INTENT, intent);
45         fragment.setArguments(args);
46 
47         return fragment;
48     }
49 
50     @Override
onCreateView(@onNull LayoutInflater inflater, final ViewGroup container, Bundle savedInstanceState)51     public View onCreateView(@NonNull LayoutInflater inflater, final ViewGroup container,
52             Bundle savedInstanceState) {
53         View view = inflater.inflate(R.layout.fragment_error, container, false);
54 
55         mErrorMessageView = view.findViewById(R.id.error_message);
56         mErrorButton = view.findViewById(R.id.error_button);
57 
58         Bundle args = getArguments();
59         if (args != null) {
60             mErrorMessageStr = args.getString(ERROR_RESOLUTION_ACTION_MESSAGE);
61             mErrorLabel = args.getString(ERROR_RESOLUTION_ACTION_LABEL);
62             mPendingIntent = args.getParcelable(ERROR_RESOLUTION_ACTION_INTENT);
63         }
64 
65         if (mErrorMessageStr == null) {
66             Log.e(TAG, "ErrorFragment does not have an error message");
67             return view;
68         }
69 
70         mErrorMessageView.setText(mErrorMessageStr);
71 
72         // Only an error message is required. Fragments without a provided message and label
73         // have these elements omitted.
74         if (mErrorLabel != null && mPendingIntent != null) {
75             mErrorButton.setText(mErrorLabel);
76 
77             boolean isDistractionOptimized = CarPackageManagerUtils.getInstance(getActivity())
78                     .isDistractionOptimized(getActivity().getPackageManager(),
79                             mPendingIntent.getIntent());
80             mErrorButton.setUxRestrictions(isDistractionOptimized
81                     ? CarUxRestrictions.UX_RESTRICTIONS_BASELINE
82                     : CarUxRestrictions.UX_RESTRICTIONS_NO_SETUP);
83 
84             mErrorButton.setOnClickListener(v -> {
85                 try {
86                     mPendingIntent.send();
87                 } catch (PendingIntent.CanceledException e) {
88                     if (Log.isLoggable(TAG, Log.ERROR)) {
89                         Log.e(TAG, "Pending intent canceled");
90                     }
91                 }
92             });
93             mErrorButton.setVisibility(View.VISIBLE);
94         } else {
95             mErrorButton.setVisibility(View.GONE);
96         }
97 
98         return view;
99     }
100 }
101