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 InternetDialogController mInternetDialogController; 58 private final CoroutineScope mCoroutineScope; 59 @Nullable 60 private List<WifiEntry> mWifiEntries; 61 @VisibleForTesting 62 protected int mWifiEntriesCount; 63 @VisibleForTesting 64 protected int mMaxEntriesCount = InternetDialogController.MAX_WIFI_ENTRY_COUNT; 65 66 protected View mHolderView; 67 protected Context mContext; 68 InternetAdapter(InternetDialogController controller, CoroutineScope coroutineScope)69 public InternetAdapter(InternetDialogController controller, CoroutineScope coroutineScope) { 70 mInternetDialogController = controller; 71 mCoroutineScope = coroutineScope; 72 } 73 74 @Override onCreateViewHolder(@onNull ViewGroup viewGroup, int viewType)75 public InternetViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, 76 int viewType) { 77 mContext = viewGroup.getContext(); 78 mHolderView = LayoutInflater.from(mContext).inflate(R.layout.internet_list_item, 79 viewGroup, false); 80 return new InternetViewHolder(mHolderView, mInternetDialogController, mCoroutineScope); 81 } 82 83 @Override onBindViewHolder(@onNull InternetViewHolder viewHolder, int position)84 public void onBindViewHolder(@NonNull InternetViewHolder viewHolder, int position) { 85 if (mWifiEntries == null || position >= mWifiEntriesCount) { 86 return; 87 } 88 viewHolder.onBind(mWifiEntries.get(position)); 89 } 90 91 /** 92 * Updates the Wi-Fi networks. 93 * 94 * @param wifiEntries the updated Wi-Fi entries. 95 * @param wifiEntriesCount the total number of Wi-Fi entries. 96 */ setWifiEntries(@ullable List<WifiEntry> wifiEntries, int wifiEntriesCount)97 public void setWifiEntries(@Nullable List<WifiEntry> wifiEntries, int wifiEntriesCount) { 98 mWifiEntries = wifiEntries; 99 mWifiEntriesCount = 100 (wifiEntriesCount < mMaxEntriesCount) ? wifiEntriesCount : mMaxEntriesCount; 101 } 102 103 /** 104 * Gets the total number of Wi-Fi networks. 105 * 106 * @return The total number of Wi-Fi entries. 107 */ 108 @Override getItemCount()109 public int getItemCount() { 110 return mWifiEntriesCount; 111 } 112 113 /** 114 * Sets the maximum number of Wi-Fi networks. 115 */ setMaxEntriesCount(int count)116 public void setMaxEntriesCount(int count) { 117 if (count < 0 || mMaxEntriesCount == count) { 118 return; 119 } 120 mMaxEntriesCount = count; 121 if (mWifiEntriesCount > count) { 122 mWifiEntriesCount = count; 123 notifyDataSetChanged(); 124 } 125 } 126 127 /** 128 * ViewHolder for binding Wi-Fi view. 129 */ 130 static class InternetViewHolder extends RecyclerView.ViewHolder { 131 132 final LinearLayout mContainerLayout; 133 final LinearLayout mWifiListLayout; 134 final LinearLayout mWifiNetworkLayout; 135 final ImageView mWifiIcon; 136 final TextView mWifiTitleText; 137 final TextView mWifiSummaryText; 138 final ImageView mWifiEndIcon; 139 final Context mContext; 140 final InternetDialogController mInternetDialogController; 141 final CoroutineScope mCoroutineScope; 142 @Nullable 143 private Job mJob; 144 InternetViewHolder(View view, InternetDialogController internetDialogController, CoroutineScope coroutineScope)145 InternetViewHolder(View view, InternetDialogController internetDialogController, 146 CoroutineScope coroutineScope) { 147 super(view); 148 mContext = view.getContext(); 149 mInternetDialogController = internetDialogController; 150 mCoroutineScope = coroutineScope; 151 mContainerLayout = view.requireViewById(R.id.internet_container); 152 mWifiListLayout = view.requireViewById(R.id.wifi_list); 153 mWifiNetworkLayout = view.requireViewById(R.id.wifi_network_layout); 154 mWifiIcon = view.requireViewById(R.id.wifi_icon); 155 mWifiTitleText = view.requireViewById(R.id.wifi_title); 156 mWifiSummaryText = view.requireViewById(R.id.wifi_summary); 157 mWifiEndIcon = view.requireViewById(R.id.wifi_end_icon); 158 } 159 onBind(@onNull WifiEntry wifiEntry)160 void onBind(@NonNull WifiEntry wifiEntry) { 161 mWifiIcon.setImageDrawable(getWifiDrawable(wifiEntry)); 162 setWifiNetworkLayout(wifiEntry.getTitle(), 163 Html.fromHtml(wifiEntry.getSummary(false), Html.FROM_HTML_MODE_LEGACY)); 164 165 final int connectedState = wifiEntry.getConnectedState(); 166 final int security = wifiEntry.getSecurity(); 167 updateEndIcon(connectedState, security); 168 169 mWifiListLayout.setEnabled(shouldEnabled(wifiEntry)); 170 if (connectedState != WifiEntry.CONNECTED_STATE_DISCONNECTED) { 171 mWifiListLayout.setOnClickListener( 172 v -> mInternetDialogController.launchWifiDetailsSetting( 173 wifiEntry.getKey(), v)); 174 return; 175 } 176 mWifiListLayout.setOnClickListener(v -> onWifiClick(wifiEntry, v)); 177 } 178 shouldEnabled(@onNull WifiEntry wifiEntry)179 boolean shouldEnabled(@NonNull WifiEntry wifiEntry) { 180 if (wifiEntry.canConnect()) { 181 return true; 182 } 183 // If Wi-Fi is connected or saved network, leave it enabled to disconnect or configure. 184 if (wifiEntry.canDisconnect() || wifiEntry.isSaved()) { 185 return true; 186 } 187 return false; 188 } 189 onWifiClick(@onNull WifiEntry wifiEntry, @NonNull View view)190 void onWifiClick(@NonNull WifiEntry wifiEntry, @NonNull View view) { 191 if (Flags.androidVWifiApi() && wifiEntry.getSecurityTypes().contains( 192 WifiEntry.SECURITY_WEP)) { 193 if (mJob == null) { 194 mJob = WifiUtils.checkWepAllowed(mContext, mCoroutineScope, wifiEntry.getSsid(), 195 WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG, intent -> { 196 mInternetDialogController.startActivity(intent, view); 197 return null; 198 }, () -> { 199 wifiConnect(wifiEntry, view); 200 return null; 201 }); 202 } 203 return; 204 } 205 wifiConnect(wifiEntry, view); 206 } 207 wifiConnect(@onNull WifiEntry wifiEntry, @NonNull View view)208 void wifiConnect(@NonNull WifiEntry wifiEntry, @NonNull View view) { 209 if (wifiEntry.shouldEditBeforeConnect()) { 210 final Intent intent = WifiUtils.getWifiDialogIntent(wifiEntry.getKey(), 211 true /* connectForCaller */); 212 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 213 intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT); 214 mContext.startActivity(intent); 215 return; 216 } 217 218 if (wifiEntry.canConnect()) { 219 mInternetDialogController.connect(wifiEntry); 220 return; 221 } 222 223 if (wifiEntry.isSaved()) { 224 Log.w(TAG, "The saved Wi-Fi network does not allow to connect. SSID:" 225 + wifiEntry.getSsid()); 226 mInternetDialogController.launchWifiDetailsSetting(wifiEntry.getKey(), view); 227 } 228 } 229 setWifiNetworkLayout(CharSequence title, CharSequence summary)230 void setWifiNetworkLayout(CharSequence title, CharSequence summary) { 231 mWifiTitleText.setText(title); 232 if (TextUtils.isEmpty(summary)) { 233 mWifiSummaryText.setVisibility(View.GONE); 234 return; 235 } 236 mWifiSummaryText.setVisibility(View.VISIBLE); 237 mWifiSummaryText.setText(summary); 238 } 239 240 @Nullable getWifiDrawable(@onNull WifiEntry wifiEntry)241 Drawable getWifiDrawable(@NonNull WifiEntry wifiEntry) { 242 Drawable drawable = mInternetDialogController.getWifiDrawable(wifiEntry); 243 if (drawable == null) { 244 return null; 245 } 246 drawable.setTint( 247 Utils.getColorAttrDefaultColor(mContext, android.R.attr.textColorTertiary)); 248 final AtomicReference<Drawable> shared = new AtomicReference<>(); 249 shared.set(drawable); 250 return shared.get(); 251 } 252 updateEndIcon(int connectedState, int security)253 void updateEndIcon(int connectedState, int security) { 254 Drawable drawable = null; 255 if (connectedState != WifiEntry.CONNECTED_STATE_DISCONNECTED) { 256 drawable = mContext.getDrawable(R.drawable.ic_settings_24dp); 257 } else if (security != WifiEntry.SECURITY_NONE && security != WifiEntry.SECURITY_OWE) { 258 drawable = mContext.getDrawable(R.drawable.ic_friction_lock_closed); 259 } 260 if (drawable == null) { 261 mWifiEndIcon.setVisibility(View.GONE); 262 return; 263 } 264 mWifiEndIcon.setVisibility(View.VISIBLE); 265 mWifiEndIcon.setImageDrawable(drawable); 266 } 267 } 268 } 269