1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * Copyright (C) 2016 Mopria Alliance, Inc. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 package com.android.bips.ui; 19 20 import android.annotation.SuppressLint; 21 import android.app.AlertDialog; 22 import android.content.Context; 23 import android.os.Bundle; 24 import android.text.Editable; 25 import android.text.TextWatcher; 26 import android.util.Log; 27 import android.view.KeyEvent; 28 import android.view.View; 29 import android.view.Window; 30 import android.view.WindowManager; 31 import android.view.inputmethod.EditorInfo; 32 import android.view.inputmethod.InputMethodManager; 33 import android.widget.Button; 34 import android.widget.ProgressBar; 35 import android.widget.TextView; 36 37 import com.android.bips.R; 38 import com.android.bips.discovery.DiscoveredPrinter; 39 import com.android.bips.discovery.ManualDiscovery; 40 41 import java.util.regex.Matcher; 42 import java.util.regex.Pattern; 43 44 /** 45 * Allows the user to enter printer address manually 46 */ 47 class AddManualPrinterDialog extends AlertDialog implements TextWatcher, 48 TextView.OnEditorActionListener, View.OnKeyListener { 49 private static final String TAG = AddManualPrinterDialog.class.getSimpleName(); 50 private static final boolean DEBUG = false; 51 52 /** 53 * A regex that matches IP addresses and domain names like "192.168.1.101" and 54 * "printer1.company.com" 55 */ 56 private static final String NAME_IP_REGEX = 57 "[a-zA-Z0-9]+(\\-[a-zA-Z0-9]+)*(\\.[a-zA-Z0-9]+(\\-[a-zA-Z0-9]+)*)*"; 58 private static final String HOSTNAME_REGEXP = "^" + NAME_IP_REGEX + "$"; 59 private static final Pattern HOSTNAME_PATTERN = Pattern.compile(HOSTNAME_REGEXP); 60 61 private final ManualDiscovery mDiscovery; 62 private TextView mHostnameView; 63 private Button mAddButton; 64 private ProgressBar mProgressBar; 65 66 AddManualPrinterDialog(Context context, ManualDiscovery discovery) { 67 super(context); 68 mDiscovery = discovery; 69 } 70 71 @SuppressLint("InflateParams") 72 @Override 73 protected void onCreate(Bundle savedInstanceState) { 74 if (DEBUG) Log.d(TAG, "onCreate"); 75 View view = getLayoutInflater().inflate(R.layout.manual_printer_add, null); 76 setView(view); 77 setTitle(R.string.add_manual_printer); 78 setButton(AlertDialog.BUTTON_NEGATIVE, getContext().getString(android.R.string.cancel), 79 (OnClickListener) null); 80 setButton(AlertDialog.BUTTON_POSITIVE, getContext().getString(R.string.add), 81 (OnClickListener) null); 82 83 super.onCreate(savedInstanceState); 84 mAddButton = getButton(AlertDialog.BUTTON_POSITIVE); 85 mHostnameView = (TextView) findViewById(R.id.hostname); 86 mProgressBar = (ProgressBar) findViewById(R.id.progress); 87 88 mAddButton.setOnClickListener(view1 -> addPrinter()); 89 90 // Update add button as contents change 91 mHostnameView.addTextChangedListener(this); 92 mHostnameView.setOnEditorActionListener(this); 93 mHostnameView.setOnKeyListener(this); 94 95 // Force open keyboard if appropriate 96 openKeyboard(mHostnameView); 97 98 updateButtonState(); 99 } 100 101 private void openKeyboard(TextView view) { 102 Window window = getWindow(); 103 if (window != null) { 104 window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE); 105 } 106 107 view.requestFocus(); 108 InputMethodManager imm = (InputMethodManager) getContext() 109 .getSystemService(Context.INPUT_METHOD_SERVICE); 110 imm.showSoftInput(view, InputMethodManager.SHOW_IMPLICIT); 111 } 112 113 private void updateButtonState() { 114 String hostname = mHostnameView.getText().toString(); 115 Matcher hostMatch = HOSTNAME_PATTERN.matcher(hostname); 116 117 mAddButton.setEnabled(hostMatch.matches()); 118 } 119 120 /** Attempt to add the printer based on current data */ 121 private void addPrinter() { 122 // Disable other actions while we are checking 123 mAddButton.setEnabled(false); 124 mHostnameView.setEnabled(false); 125 mProgressBar.setVisibility(View.VISIBLE); 126 127 // Begin an attempt to add the printer 128 mDiscovery.addManualPrinter(mHostnameView.getText().toString(), 129 new ManualDiscovery.PrinterAddCallback() { 130 @Override 131 public void onFound(DiscoveredPrinter printer, boolean supported) { 132 if (supported) { 133 // Success case 134 dismiss(); 135 } else { 136 error(getContext().getString(R.string.printer_not_supported)); 137 } 138 } 139 140 @Override 141 public void onNotFound() { 142 error(getContext().getString(R.string.no_printer_found)); 143 } 144 }); 145 } 146 147 /** Inform user of error and allow them to correct it */ 148 private void error(String message) { 149 mProgressBar.setVisibility(View.GONE); 150 mHostnameView.setError(message); 151 mHostnameView.setEnabled(true); 152 openKeyboard(mHostnameView); 153 } 154 155 @Override 156 public void beforeTextChanged(CharSequence charSequence, int start, int count, int after) { 157 } 158 159 @Override 160 public void onTextChanged(CharSequence charSequence, int start, int before, int count) { 161 } 162 163 @Override 164 public void afterTextChanged(Editable editable) { 165 updateButtonState(); 166 } 167 168 @Override 169 public boolean onEditorAction(TextView textView, int id, KeyEvent keyEvent) { 170 if (id == EditorInfo.IME_ACTION_DONE && mAddButton.isEnabled()) { 171 addPrinter(); 172 return true; 173 } 174 return false; 175 } 176 177 @Override 178 public boolean onKey(View view, int keyCode, KeyEvent keyEvent) { 179 if (keyCode == KeyEvent.KEYCODE_ENTER && mAddButton.isEnabled()) { 180 addPrinter(); 181 return true; 182 } 183 return false; 184 } 185 }