1 /* 2 * Copyright (C) 2021 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.systemui.qs.tiles.dialog; 18 19 import android.content.Context; 20 import android.content.Intent; 21 import android.graphics.drawable.Drawable; 22 import android.text.Html; 23 import android.text.TextUtils; 24 import android.util.Log; 25 import android.view.LayoutInflater; 26 import android.view.View; 27 import android.view.ViewGroup; 28 import android.view.WindowManager; 29 import android.widget.ImageView; 30 import android.widget.LinearLayout; 31 import android.widget.TextView; 32 33 import androidx.annotation.NonNull; 34 import androidx.annotation.Nullable; 35 import androidx.recyclerview.widget.RecyclerView; 36 37 import com.android.internal.annotations.VisibleForTesting; 38 import com.android.settingslib.Utils; 39 import com.android.settingslib.wifi.WifiUtils; 40 import com.android.systemui.res.R; 41 import com.android.wifi.flags.Flags; 42 import com.android.wifitrackerlib.WifiEntry; 43 44 import kotlinx.coroutines.CoroutineScope; 45 import kotlinx.coroutines.Job; 46 47 import java.util.List; 48 import java.util.concurrent.atomic.AtomicReference; 49 50 /** 51 * Adapter for showing Wi-Fi networks. 52 */ 53 public class InternetAdapter extends RecyclerView.Adapter<InternetAdapter.InternetViewHolder> { 54 55 private static final String TAG = "InternetAdapter"; 56 57 private final InternetDetailsContentController mInternetDetailsContentController; 58 private final CoroutineScope mCoroutineScope; 59 @Nullable 60 private List<WifiEntry> mWifiEntries; 61 @VisibleForTesting 62 protected int mWifiEntriesCount; 63 @VisibleForTesting 64 protected int mMaxEntriesCount = InternetDetailsContentController.MAX_WIFI_ENTRY_COUNT; 65 66 protected View mHolderView; 67 protected Context mContext; 68 InternetAdapter(InternetDetailsContentController controller, CoroutineScope coroutineScope)69 public InternetAdapter(InternetDetailsContentController controller, 70 CoroutineScope coroutineScope) { 71 mInternetDetailsContentController = controller; 72 mCoroutineScope = coroutineScope; 73 } 74 75 @Override onCreateViewHolder(@onNull ViewGroup viewGroup, int viewType)76 public InternetViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, 77 int viewType) { 78 mContext = viewGroup.getContext(); 79 mHolderView = LayoutInflater.from(mContext).inflate(R.layout.internet_list_item, 80 viewGroup, false); 81 return new InternetViewHolder(mHolderView, mInternetDetailsContentController, 82 mCoroutineScope); 83 } 84 85 @Override onBindViewHolder(@onNull InternetViewHolder viewHolder, int position)86 public void onBindViewHolder(@NonNull InternetViewHolder viewHolder, int position) { 87 if (mWifiEntries == null || position >= mWifiEntriesCount) { 88 return; 89 } 90 viewHolder.onBind(mWifiEntries.get(position)); 91 } 92 93 /** 94 * Updates the Wi-Fi networks. 95 * 96 * @param wifiEntries the updated Wi-Fi entries. 97 * @param wifiEntriesCount the total number of Wi-Fi entries. 98 */ setWifiEntries(@ullable List<WifiEntry> wifiEntries, int wifiEntriesCount)99 public void setWifiEntries(@Nullable List<WifiEntry> wifiEntries, int wifiEntriesCount) { 100 mWifiEntries = wifiEntries; 101 mWifiEntriesCount = 102 (wifiEntriesCount < mMaxEntriesCount) ? wifiEntriesCount : mMaxEntriesCount; 103 } 104 105 /** 106 * Gets the total number of Wi-Fi networks. 107 * 108 * @return The total number of Wi-Fi entries. 109 */ 110 @Override getItemCount()111 public int getItemCount() { 112 return mWifiEntriesCount; 113 } 114 115 /** 116 * Sets the maximum number of Wi-Fi networks. 117 */ setMaxEntriesCount(int count)118 public void setMaxEntriesCount(int count) { 119 if (count < 0 || mMaxEntriesCount == count) { 120 return; 121 } 122 mMaxEntriesCount = count; 123 if (mWifiEntriesCount > count) { 124 mWifiEntriesCount = count; 125 notifyDataSetChanged(); 126 } 127 } 128 129 /** 130 * ViewHolder for binding Wi-Fi view. 131 */ 132 static class InternetViewHolder extends RecyclerView.ViewHolder { 133 134 final LinearLayout mContainerLayout; 135 final LinearLayout mWifiListLayout; 136 final LinearLayout mWifiNetworkLayout; 137 final ImageView mWifiIcon; 138 final TextView mWifiTitleText; 139 final TextView mWifiSummaryText; 140 final ImageView mWifiEndIcon; 141 final Context mContext; 142 final InternetDetailsContentController mInternetDetailsContentController; 143 final CoroutineScope mCoroutineScope; 144 @Nullable 145 private Job mJob; 146 InternetViewHolder(View view, InternetDetailsContentController internetDetailsContentController, CoroutineScope coroutineScope)147 InternetViewHolder(View view, 148 InternetDetailsContentController internetDetailsContentController, 149 CoroutineScope coroutineScope) { 150 super(view); 151 mContext = view.getContext(); 152 mInternetDetailsContentController = internetDetailsContentController; 153 mCoroutineScope = coroutineScope; 154 mContainerLayout = view.requireViewById(R.id.internet_container); 155 mWifiListLayout = view.requireViewById(R.id.wifi_list); 156 mWifiNetworkLayout = view.requireViewById(R.id.wifi_network_layout); 157 mWifiIcon = view.requireViewById(R.id.wifi_icon); 158 mWifiTitleText = view.requireViewById(R.id.wifi_title); 159 mWifiSummaryText = view.requireViewById(R.id.wifi_summary); 160 mWifiEndIcon = view.requireViewById(R.id.wifi_end_icon); 161 } 162 onBind(@onNull WifiEntry wifiEntry)163 void onBind(@NonNull WifiEntry wifiEntry) { 164 mWifiIcon.setImageDrawable(getWifiDrawable(wifiEntry)); 165 setWifiNetworkLayout(wifiEntry.getTitle(), 166 Html.fromHtml(wifiEntry.getSummary(false), Html.FROM_HTML_MODE_LEGACY)); 167 168 final int connectedState = wifiEntry.getConnectedState(); 169 final int security = wifiEntry.getSecurity(); 170 updateEndIcon(connectedState, security); 171 172 mWifiListLayout.setEnabled(shouldEnabled(wifiEntry)); 173 if (connectedState != WifiEntry.CONNECTED_STATE_DISCONNECTED) { 174 mWifiListLayout.setOnClickListener( 175 v -> mInternetDetailsContentController.launchWifiDetailsSetting( 176 wifiEntry.getKey(), v)); 177 return; 178 } 179 mWifiListLayout.setOnClickListener(v -> onWifiClick(wifiEntry, v)); 180 } 181 shouldEnabled(@onNull WifiEntry wifiEntry)182 boolean shouldEnabled(@NonNull WifiEntry wifiEntry) { 183 if (wifiEntry.canConnect()) { 184 return true; 185 } 186 // If Wi-Fi is connected or saved network, leave it enabled to disconnect or configure. 187 if (wifiEntry.canDisconnect() || wifiEntry.isSaved()) { 188 return true; 189 } 190 return false; 191 } 192 onWifiClick(@onNull WifiEntry wifiEntry, @NonNull View view)193 void onWifiClick(@NonNull WifiEntry wifiEntry, @NonNull View view) { 194 if (Flags.androidVWifiApi() && wifiEntry.getSecurityTypes().contains( 195 WifiEntry.SECURITY_WEP)) { 196 if (mJob == null) { 197 mJob = WifiUtils.checkWepAllowed(mContext, mCoroutineScope, wifiEntry.getSsid(), 198 WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG, intent -> { 199 mInternetDetailsContentController 200 .startActivityForDialog(intent); 201 return null; 202 }, () -> { 203 wifiConnect(wifiEntry, view); 204 return null; 205 }, intent -> { 206 mInternetDetailsContentController 207 .startActivityForDialogDismissDialogFirst(intent, view); 208 return null; 209 }); 210 } 211 return; 212 } 213 wifiConnect(wifiEntry, view); 214 } 215 wifiConnect(@onNull WifiEntry wifiEntry, @NonNull View view)216 void wifiConnect(@NonNull WifiEntry wifiEntry, @NonNull View view) { 217 if (wifiEntry.shouldEditBeforeConnect()) { 218 final Intent intent = WifiUtils.getWifiDialogIntent(wifiEntry.getKey(), 219 true /* connectForCaller */); 220 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 221 intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT); 222 mInternetDetailsContentController.startActivityForDialog(intent); 223 return; 224 } 225 226 if (wifiEntry.canConnect()) { 227 mInternetDetailsContentController.connect(wifiEntry); 228 return; 229 } 230 231 if (wifiEntry.isSaved()) { 232 Log.w(TAG, "The saved Wi-Fi network does not allow to connect. SSID:" 233 + wifiEntry.getSsid()); 234 mInternetDetailsContentController.launchWifiDetailsSetting(wifiEntry.getKey(), 235 view); 236 } 237 } 238 setWifiNetworkLayout(CharSequence title, CharSequence summary)239 void setWifiNetworkLayout(CharSequence title, CharSequence summary) { 240 mWifiTitleText.setText(title); 241 if (TextUtils.isEmpty(summary)) { 242 mWifiSummaryText.setVisibility(View.GONE); 243 return; 244 } 245 mWifiSummaryText.setVisibility(View.VISIBLE); 246 mWifiSummaryText.setText(summary); 247 } 248 249 @Nullable getWifiDrawable(@onNull WifiEntry wifiEntry)250 Drawable getWifiDrawable(@NonNull WifiEntry wifiEntry) { 251 Drawable drawable = mInternetDetailsContentController.getWifiDrawable(wifiEntry); 252 if (drawable == null) { 253 return null; 254 } 255 drawable.setTint( 256 Utils.getColorAttrDefaultColor(mContext, android.R.attr.textColorTertiary)); 257 final AtomicReference<Drawable> shared = new AtomicReference<>(); 258 shared.set(drawable); 259 return shared.get(); 260 } 261 updateEndIcon(int connectedState, int security)262 void updateEndIcon(int connectedState, int security) { 263 Drawable drawable = null; 264 if (connectedState != WifiEntry.CONNECTED_STATE_DISCONNECTED) { 265 drawable = mContext.getDrawable(R.drawable.ic_settings_24dp); 266 } else if (security != WifiEntry.SECURITY_NONE && security != WifiEntry.SECURITY_OWE) { 267 drawable = mContext.getDrawable(R.drawable.ic_friction_lock_closed); 268 } 269 if (drawable == null) { 270 mWifiEndIcon.setVisibility(View.GONE); 271 return; 272 } 273 mWifiEndIcon.setVisibility(View.VISIBLE); 274 mWifiEndIcon.setImageDrawable(drawable); 275 } 276 } 277 } 278