diff --git a/AndroidManifest.xml b/AndroidManifest.xml index e59e0603dca..ef5e072f952 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -145,6 +145,8 @@ > + + @@ -157,16 +159,6 @@ - - - - - - - - diff --git a/res/values-cs/strings.xml b/res/values-cs/strings.xml index de79429cd40..3c7ad2d8018 100644 --- a/res/values-cs/strings.xml +++ b/res/values-cs/strings.xml @@ -94,7 +94,7 @@ "Odpojeno" "Odpojování..." "Připojování..." - + "Párovat s tímto zařízením" "Párování..." @@ -111,7 +111,7 @@ "Volba časového pásma" "Náhled:" "Velikost písma:" - + "Odeslat broadcast" "Action:" @@ -366,8 +366,16 @@ "Umožňuje vybrat aplikace pro synchronizaci" "Nastavení zobrazení" "Animace" - "Zobrazit animace otevírání a zavírání oken" - "Animuje otevírání a zavírání oken" + + + + + + + + + + "Jas" "Nastavte jas displeje" "Interval vypnutí obrazovky" @@ -456,6 +464,12 @@ "Název AP nemůže být prázdný." "Pole MCC musí obsahovat alespoň 3 číslice." "Pole MNC musí obsahovat 2 nebo 3 číslice." + + + + + + "Obnovení továrních dat" "Umožňuje odstranit všechna data v telefonu" "Tato akce obnoví výchozí tovární nastavení telefonu. Všechna data a stažené aplikace budou smazány." @@ -592,6 +606,8 @@ "Přidat nebo odebrat slova z uživatelského slovníku" "Přidat" "Přidat do slovníku" + + "Upravit" "Smazat" "V uživatelském slovníku nejsou žádná slova. Slovo můžete přidat pomocí nabídky." @@ -612,7 +628,14 @@ "Klávesové zkratky" "Zadávání textu" "Správa možností zadávání textu" - "%s: nastavení" + + + + + + + + "Vývoj" "Umožňuje nastavit možnosti pro vývoj aplikace" "Ladění USB" diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml index 60deacd9218..93a782c77b4 100644 --- a/res/values-de/strings.xml +++ b/res/values-de/strings.xml @@ -94,7 +94,7 @@ "Nicht verbunden" "Verbindung wird getrennt..." "Verbindung wird hergestellt..." - + "Pairing mit diesem Gerät" "Pairing…" @@ -111,7 +111,7 @@ "Zeitzone auswählen" "Vorschau:" "Schriftgröße:" - + "broadcast senden" "Action:" @@ -366,8 +366,16 @@ "Auswählen, welche Anwendungen synchronisiert werden" "Display-Einstellungen" "Animation" - "Animation beim Öffnen/Schließen von Fenstern anzeigen" - "Animation beim Öffnen/Schließen von Fenstern anzeigen" + + + + + + + + + + "Helligkeit" "Helligkeit des Bildschirms anpassen" "Display-Timeout" @@ -456,6 +464,12 @@ "Der APN darf nicht leer sein." "Das MCC-Feld muss 3 Zeichen enthalten." "Das MNC-Feld muss 2 oder 3 Zeichen enthalten." + + + + + + "Auf Werkszustand zurück" "Löscht alle Daten auf dem Telefon" "Durch diese Aktion wird das Telefon auf den Werkszustand zurückgesetzt. Alle Daten und heruntergeladenen Anwendungen werden gelöscht!" @@ -592,6 +606,8 @@ "Hinzufügen & Entfernen von Wörtern im Wörterbuch des Nutzers" "Hinzufügen" "Zum Wörterbuch hinzufügen" + + "Bearbeiten" "Löschen" "Sie haben keine Wörter im Nutzerwörterbuch. Sie können über das Menü ein Wort hinzufügen." @@ -612,7 +628,14 @@ "Tastenkombinationen" "Texteingabe" "Optionen für Texteingabe verwalten" - "%s Einstellungen" + + + + + + + + "Entwicklung" "Optionen zur Anwendungsentwicklung festlegen" "USB-Debugging" diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml index eb4c8b100ee..5cb12cb215f 100644 --- a/res/values-es/strings.xml +++ b/res/values-es/strings.xml @@ -94,7 +94,7 @@ "Desconectada" "Desconectando..." "Estableciendo conexión..." - + "Sincronizar con este dispositivo" "Sincronizando..." @@ -110,7 +110,7 @@ "Seleccionar zona horaria" "Vista previa:" "Tamaño de fuente:" - + "Enviar broadcast" "Action:" @@ -365,8 +365,16 @@ "Seleccionar las aplicaciones que están sincronizadas" "Configuración de pantalla" "Animación" - "Mostrar animación al abrir o cerrar ventanas" - "Mostrar animación al abrir o cerrar ventanas" + + + + + + + + + + "Brillo" "Ajustar el brillo de la pantalla" "Tiempo de espera de pantalla" @@ -455,6 +463,12 @@ "El campo de APN no puede estar vacío." "El campo MMC debe contener 3 dígitos." "El campo MNC debe contener 2 ó 3 dígitos." + + + + + + "Restablecer datos de fábrica" "Borrar todos los datos del teléfono" "Esta acción restablecerá el teléfono a su estado de fábrica inicial y borrará todos los datos y todas las aplicaciones descargadas." @@ -591,6 +605,8 @@ "Añadir y eliminar palabras del diccionario del usuario" "Añadir" "Añadir al usuario" + + "Editar" "Suprimir" "No tienes ninguna palabra en el diccionario del usuario. Puedes añadir una palabra a través del menú." @@ -611,7 +627,14 @@ "Accesos directos" "Introducción de texto" "Administrar opciones de introducción de texto" - "Configuración de %s" + + + + + + + + "Desarrollo" "Establecer opciones de desarrollo de aplicaciones" "Depuración USB" diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml index 3feed965998..388dee9684c 100644 --- a/res/values-fr/strings.xml +++ b/res/values-fr/strings.xml @@ -85,18 +85,18 @@ "Identifiable" "Identifiable pendant %1$s secondes..." "Permettre l\'identification de l\'appareil" - "Périphériques Bluetooth" - "Nom du périphérique" + "Appareils Bluetooth" + "Nom de l\'appareil" "Aucun nom n\'a été défini. Utilisation du nom du compte..." - "Rechercher des périphériques" + "Rechercher d\'appareils" "%1$s va être déconnecté." "Connecté" "Déconnecté" "Déconnexion…" "Connexion…" - + - "Associer à ce périphérique" + "Associer à cet appareil" "Association…" "Associé mais non connecté" "mains libres/casque" @@ -110,7 +110,7 @@ "Choisir fuseau horaire" "Aperçu :" "Taille de police :" - + "Envoyer broadcast" "Action :" @@ -179,7 +179,7 @@ "Paramètres régionaux" "Choisir la langue" "Sélectionner une activité" - "Informations sur le périphérique" + "Informations sur l\'appareil" "Informations sur la batterie" "Historique de la batterie" "Afficher" @@ -215,13 +215,13 @@ "Paramètres Bluetooth" "Gérer les connexions, configurer le nom et l\'identification de l\'appareil" "Demande d\'association Bluetooth" - "Informations sur le périphérique Bluetooth" + "Informations sur l\'appareil Bluetooth" "%1$s"\n\n"Saisissez le code PIN pour associer l\'appareil."\n"(Essayez avec 0000 ou 1234.)" "Attention" "Un problème est survenu lors de l\'association à %1$s." - "Un problème est survenu lors de l\'association à %1$s car le PIN saisi est incorrect." + "Un problème est survenu lors de l\'association à %1$s, car le PIN saisi est incorrect." "Un problème est survenu lors de la connexion à %1$s." - "Rechercher des périphériques" + "Rechercher des appareils" "Se connecter" "Déconnecter" "Associer et connecter" @@ -365,8 +365,16 @@ "Sélectionner les applications à synchroniser" "Afficher les paramètres" "Animation" - "Animation lors de l\'ouverture et la fermeture de fenêtres" - "Animation lors de l\'ouverture et la fermeture de fenêtres" + + + + + + + + + + "Luminosité" "Régler la luminosité de l\'écran" "Mise en veille de l\'écran" @@ -455,6 +463,12 @@ "Le champ Nom de point d\'accès (APN) doit être renseigné." "Le champ MCC doit contenir 3 chiffres." "Le champ MNC doit contenir 2 ou 3 chiffres." + + + + + + "Réinit. valeurs d\'usine" "Effacer toutes les données du téléphone" "Cette action réinitialisera le téléphone à ses valeurs d\'usine et effacera toutes les données et applications téléchargées !" @@ -591,6 +605,8 @@ "Ajouter et retirer des mots du dictionnaire personnel" "Ajouter" "Ajouter au dictionnaire" + + "Modifier" "Supprimer" "Votre dictionnaire personnel ne contient aucun mot. Vous pouvez ajouter un mot via le menu." @@ -611,7 +627,14 @@ "Raccourcis" "Saisie de texte" "Gérer les options de saisie de texte" - "Paramètres %s" + + + + + + + + "Développement" "Définir les options pour le développement de l\'application" "Débogage USB" diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml index 6e10e36d27f..ef452c375f3 100644 --- a/res/values-it/strings.xml +++ b/res/values-it/strings.xml @@ -94,7 +94,7 @@ "Disconnesso" "Disconnessione..." "Connessione..." - + "Accoppia con il dispositivo" "Accoppiamento..." @@ -110,7 +110,7 @@ "Seleziona fuso orario" "Anteprima:" "Dimensioni carattere:" - + "Invia broadcast" "Action:" @@ -365,8 +365,16 @@ "Seleziona le applicazioni da sincronizzare" "Impostazioni display" "Animazione" - "Mostra animazioni durante apertura/chiusura di finestre" - "Mostra animazioni durante apertura/chiusura di finestre" + + + + + + + + + + "Luminosità" "Regola la luminosità dello schermo" "Timeout schermo" @@ -455,6 +463,12 @@ "Il campo APN non può essere vuoto." "Il campo MCC deve contenere 3 cifre." "Il campo MNC deve contenere 2 o 3 cifre." + + + + + + "Ripristino dati di fabbrica" "Cancella tutti i dati sul telefono" "Questa azione consente di ripristinare i valori di fabbrica del telefono, cancellando tutti i dati e le applicazioni scaricate." @@ -481,7 +495,7 @@ "Visualizza la posizione nelle applicazioni (ad esempio Maps) utilizzando le reti wireless" "Posizione determinata dalle reti mobili e/o Wi-Fi" "Attiva satelliti GPS" - "Durante localizzazione, accuratezza a livello stradale (deselezionare per risparmiare batteria)" + "Accuratezza a livello stradale (deseleziona per risparmiare batteria)" "Localizza a livello stradale (richiede più batteria e la vista del cielo)" "Info sul telefono" "Visualizza informazioni legali, stato del telefono, versione del software" @@ -494,7 +508,7 @@ "Errore durante il caricamento delle licenze." "Caricamento..." "Sequenza di sblocco schermo" - "Cambia sequenza di sblocco" + "Cambia sequenza sblocco" "Conferma sequenza salvata" "Riprova:" "Inserisci una sequenza di sblocco" @@ -521,7 +535,7 @@ "Annulla" "Avanti" "Protezione del telefono" - "Proteggi il telefono dall\'uso non autorizzato creando una sequenza di sblocco dello schermo personale. "\n\n"1""  Nella prossima schermata, osserva la creazione di una sequenza di esempio. "\n\n"2""  Quando sei pronto, crea la tua sequenza di sblocco personale. Prova diverse sequenze collegando sempre almeno quattro punti. "\n\n"3""  Inserisci di nuovo la sequenza per confermare. "\n\n"Pronto per iniziare? Seleziona “Avanti”"". "\n\n"Se non desideri proteggere il telefono, seleziona “Annulla”." + "Proteggi il telefono dall\'uso non autorizzato creando una sequenza di sblocco dello schermo personalizzata. "\n\n"1"" Nella prossima schermata, osserva la creazione di una sequenza di esempio. "\n\n"2"" Quando sei pronto, crea la tua sequenza di sblocco personale. Prova diverse sequenze collegando sempre almeno quattro punti. "\n\n"3"" Inserisci di nuovo la sequenza per confermare. "\n\n"Pronto per iniziare? Seleziona “Avanti”"". "\n\n"Se non desideri proteggere il telefono, seleziona “Annulla”." "Sequenza di esempio" "Collega almeno quattro punti."\n" "\n"Seleziona \"Avanti\" quando sei pronto a creare la tua sequenza." "Gestisci applicazioni" @@ -530,7 +544,7 @@ "Gestisci le applicazioni, imposta le scorciatoie di avvio rapido" "Impostazioni applicazione" "Origini sconosciute" - "Consenti l\'installazione di applicazioni non commerciali" + "Consenti l\'installazione di applicazioni non presenti in Market" "Il telefono e i dati personali sono più vulnerabili agli attacchi da parte di applicazioni\n di origini sconosciute. L\'utente accetta di essere il solo responsabile degli eventuali\n danni al telefono o della perdita dei dati che potrebbero derivare dall\'utilizzo di\n queste applicazioni." "Info applicazione" "Archiviazione" @@ -591,6 +605,8 @@ "Aggiungi e rimuovi parole dal dizionario utente" "Aggiungi" "Aggiungi al dizionario" + + "Modifica" "Elimina" "Non sono presenti parole nel dizionario utente. Puoi aggiungere una parola mediante il menu." @@ -611,7 +627,14 @@ "Scorciatoie" "Inserimento testo" "Gestisci opzioni inserimento testo" - "Impostazioni %s" + + + + + + + + "Sviluppo" "Imposta opzioni per lo sviluppo di applicazioni" "Debug USB" diff --git a/res/values-ja/arrays.xml b/res/values-ja/arrays.xml index d73a3d7e700..c10aa860297 100644 --- a/res/values-ja/arrays.xml +++ b/res/values-ja/arrays.xml @@ -30,7 +30,7 @@ "1分" "2分" "10分" - "タイムアウトなし" + "減光しない" "自動" @@ -52,8 +52,8 @@ "画面がOFFになったとき" - "電源接続時はスリープしない" - "スリープしない" + "電源接続時はスリープにしない" + "スリープにしない" diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml index b887234a834..7e358b218d1 100644 --- a/res/values-ja/strings.xml +++ b/res/values-ja/strings.xml @@ -30,7 +30,7 @@ "起動時にデータを無効にする" "使用中" "休止中または使用不可" - "緊急呼のみ" + "緊急通報のみ" "無線通信をオフ" "ローミング" "ローミングなし" @@ -94,7 +94,7 @@ "切断" "切断中..." "接続中..." - + "この端末をペアに設定する" "ペアとして設定中..." @@ -111,7 +111,7 @@ "タイムゾーンの選択" "プレビュー:" "フォントサイズ:" - + "broadcastを送信" "Action:" @@ -211,7 +211,7 @@ "現在地情報、画面ロック、SIMカードロック" "パスワード" "Bluetooth" - "Bluetoothをオン" + "BluetoothをONにする" "Bluetooth設定" "Bluetooth設定" "端末の名前、接続や検出設定" @@ -245,7 +245,7 @@ "携帯電話の音声に使用" "Wi-Fi" "Wi-Fi" - "Wi-Fiをオン" + "Wi-FiをONにする" "Wi-Fi設定" "Wi-Fi設定" "ワイヤレスアクセスポイントの設定" @@ -268,10 +268,10 @@ "WPA2により保護" "IPアドレス" "電波強度" - "オンにしています..." - "オフにしています..." + "ONにしています..." + "OFFにしています..." "エラー" - "Wi-Fiを開始できません" + "Wi-Fiを使用できません" "Wi-Fiを停止できません" "ネットワークをスキャンできません" "ネットワークに接続できません" @@ -283,7 +283,7 @@ "パスワードを表示" "スキャン" "圏外" - "これまでの設定" + "接続履歴あり" "接続できませんでした。選択すると再試行します。" "Wi-Fiネットワーク" "ネットワークSSID" @@ -300,7 +300,7 @@ "保存" "キャンセル" "正しいIPアドレスを入力してください。" - "静的IPを使用" + "静的IPを使用する" "IPアドレス" "DNS 1" "DNS 2" @@ -310,12 +310,12 @@ "ネットワークへの接続を解除" "パスワードを変更" "詳細設定" - "規制領域" - "使用するチャンネルの番号を設定する" - "規制領域の設定で問題が発生しました。" - "チャンネル数%1$d件" - "Wi-Fiスリープポリシー" - "Wi-Fiからモバイルデータに切り替えるタイミングを指定する" + "規制区域" + "使用するチャネル番号を設定する" + "規制区域の設定に問題があります。" + "%1$dチャネル" + "Wi-Fiのスリープ設定" + "Wi-Fiをスリープに切り替えるタイミング" "スリープポリシーの設定で問題が発生しました。" "MACアドレス" "スキャン中..." @@ -338,15 +338,15 @@ "音の設定" "着信音、操作音、画面の明るさなど" "マナーモード" - "メディア(音楽や動画)、アラーム以外は無音にします" + "音楽、動画メディア、アラーム以外は消音" "着信音" - "端末既定の着信音設定" - "着信音の音量" - "着信音と通知音の音量を設定する" + "端末の基本着信音を選択" + "着信音量" + "着信音と通知音の音量" "バイブレーション" - "着信時のバイブレーションON" + "着信時バイブレーションをONにする" "通知音" - "端末既定の通知音設定" + "端末の基本通知音を選択" "着信音量" "通知音量" "通知音にも着信音量を適用" @@ -357,21 +357,29 @@ "ダイヤルパッドの操作音をONにする" "ダイヤルパッドの操作音をONにする" "選択時の操作音" - "メニュー選択時に音を鳴らす" - "メニュー選択時に音を鳴らす" + "メニュー選択時の操作音をONにする" + "メニュー選択時の操作音をONにする" "SDカードの通知" - "SDカードの通知音を無効にする" - "SDカードの通知音を有効にします" + "SDカード通知音をOFFにする" + "SDカード通知音をONにする" "データの同期" - "同期するアプリケーションを選択する" + "同期するアプリケーションの選択" "画面設定" "アニメーション表示" - "ウィンドウの開閉をアニメーションで表示する" - "ウィンドウの開閉をアニメーションで表示する" + + + + + + + + + + "画面の明るさ" - "画面の明るさを調整します" - "画面のタイムアウト" - "画面が自動的にOFFになるまでの時間を調整します" + "画面の明るさを調整する" + "バックライト消灯" + "画面のバックライトを自動消灯するまでの時間" "SIMカードロック設定" "SIMカードロック設定" "SIMカードロック" @@ -406,7 +414,7 @@ "端末の状態" "電話番号、端末識別番号、電波状態など" "SDカード & 端末容量" - "SDカードの取り外し、空き容量の表示など" + "SDカードの取り外し、空き容量の表示" "電話番号" "モバイルネットワークのタイプ" "モバイルネットワークの状態" @@ -456,6 +464,12 @@ "APNを空にできません。" "MCCのフィールドには3桁で指定してください。" "MNCのフィールドには2桁か3桁で指定してください。" + + + + + + "データの初期化" "携帯電話内のすべてのデータを消去" "この操作は携帯電話を出荷時の初期状態にリセットし、データとダウンロードしたアプリケーションをすべて消去します。" @@ -476,16 +490,16 @@ "通話設定" "ボイスメール、電話転送、発信者番号などの設定" "モバイルネットワーク" - "ローミング、ネットワーク、APNの設定" - "現在地情報" + "ローミング、ネットワーク、APN設定" + "位置情報の検出" "ワイヤレスネットワークを使用" - "ワイヤレスネットワークを使用するアプリケーション(地図など)で位置を表示する" + "無線ネットワークを使用するアプリケーション(地図など)で位置を表示する" "Wi-Fi/モバイルネットワークで位置を検出する" - "GPS機能を有効にする" - "高精度測位(電池を節約する場合はOFFを選択)" - "高精度測位(電池消費大、電波が良好な野外使用)" + "GPS機能をONにする" + "高精度測位(電池の消費を節約する場合はOFFにしてください)" + "高精度測位(電池消費増、電波が良好な場所で使用)" "端末情報" - "端末情報、法的情報、バージョン情報など" + "端末情報、規約、バージョン情報" "法的情報" "貢献者/連携パートナー" "著作権" @@ -524,7 +538,7 @@ "携帯電話の保護" "画面ロックの解除パターンを作成して携帯電話の不正使用を防ぐことができます。"\n\n"1""  次の画面でパターン作成の例を参考にしてください。"\n\n"2""  ロック解除パターンを決めたら、そのパターンを指でなぞって描きます。さまざまなパターンを作成できますが、最低4つの点を結んでください。"\n\n"3""  確認のためもう一度そのパターンを入力します。"\n\n"[次へ]を押すと次に進みます""。"\n\n"パターンロックを設定しない場合は[キャンセル]を選択してください。" "パターン例" - "少なくとも4つの点を結んで下さい。"\n" "\n"独自のパターンを決めたら[次へ]を選択します。" + "少なくとも4つの点を結んで下さい。"\n" "\n"パターンを決めたら[次へ]を選択して進みます。" "アプリケーションの管理" "インストール済みアプリケーションを管理/削除します" "アプリケーション" @@ -535,7 +549,7 @@ "提供元不明のアプリケーションから携帯電話や個人情報データが攻撃を受ける可能性が高くなります。このようなアプリケーションの使用により生じうる携帯電話への損害やデータの損失について、お客様がすべての責任を負うことに同意するものとします。" "アプリケーション情報" "メモリ" - "いつも起動" + "いつもこのアプリケーションを選択する操作" "許可" "キャッシュ" "キャッシュをクリア" @@ -547,9 +561,9 @@ "データ" "アンインストール" "データを消去" - "このアプリケーションはある操作で常に起動するように設定されています。" - "端末既定の設定なし" - "既定操作を消去" + "特定の操作で使用する既定アプリケーションとして設定されています。" + "設定されている操作はありません。" + "設定を消去" "不明" "並べ替え" "サイズ順に並べ替え" @@ -573,7 +587,7 @@ "パッケージのサイズを計算できません" "サードパーティ製のアプリケーションはインストールされていません。" "地域/言語 & 文字入力" - "地域と言語、文字入力、自動修正の設定" + "言語と地域、文字入力の設定" "地域/言語設定" "文字入力設定" "地域/言語を選択" @@ -583,15 +597,17 @@ "自動大文字変換" "英語: 先頭文字を大文字に変換する" "ピリオド自動挿入" - "物理キーボードの設定" + "キーボードの設定" "英語: Spaceキー2回でピリオド(.)を挿入" "パスワードを表示" - "入力中のパスワードを表示する" + "入力時にパスワードを表示する" "ユーザー辞書" "ユーザー辞書" "ユーザー辞書への語句の追加と削除" "追加" "辞書に追加" + + "編集" "削除" "ユーザー辞書に何も登録されていません。語句はメニューから登録できます。" @@ -612,7 +628,14 @@ "ショートカット" "文字入力" "テキスト入力オプションを管理" - "%s設定" + + + + + + + + "開発" "アプリケーション開発オプション" "USBデバッグ" diff --git a/res/values-ko/strings.xml b/res/values-ko/strings.xml index f5d680fae4e..e3f1de1608c 100644 --- a/res/values-ko/strings.xml +++ b/res/values-ko/strings.xml @@ -94,7 +94,7 @@ "연결끊김" "연결을 끊는 중..." "연결 중..." - + "이 장치와 페어링" "페어링 중..." @@ -111,7 +111,7 @@ "표준시간대 선택" "미리보기:" "글꼴 크기:" - + "broadcast 보내기" "Action:" @@ -366,8 +366,16 @@ "동기화할 응용프로그램 선택" "디스플레이 설정" "애니메이션" - "창을 열거나 닫을 때 애니메이션 표시" - "창을 열거나 닫을 때 애니메이션 표시" + + + + + + + + + + "밝기" "화면 밝기 조정" "화면 시간제한" @@ -456,6 +464,12 @@ "APN을 비워둘 수 없습니다." "MCC 필드는 3자리 숫자여야 합니다." "MNC 필드는 2~3자리 숫자여야 합니다." + + + + + + "공장 기본값 데이터 재설정" "전화기의 모든 데이터 지우기" "이 작업을 수행하면 전화기의 모든 데이터 및 다운로드한 응용프로그램이 지워지고 출고시 초기 상태로 재설정됩니다" @@ -592,6 +606,8 @@ "사용자 사전에서 단어 추가 및 삭제" "추가" "사전에 추가" + + "편집" "삭제" "사용자 사전에 단어가 없습니다. 메뉴를 통해 단어를 추가할 수 있습니다." @@ -612,7 +628,14 @@ "바로가기" "텍스트 입력" "텍스트 입력 옵션 관리" - "%s 설정" + + + + + + + + "개발" "응용프로그램 개발 옵션 설정" "USB 디버깅" diff --git a/res/values-nb/strings.xml b/res/values-nb/strings.xml index f9f01a613a8..3366c52b6a3 100644 --- a/res/values-nb/strings.xml +++ b/res/values-nb/strings.xml @@ -94,7 +94,7 @@ "Frakoblet" "Kobler fra…" "Kobler til…" - + "Par med denne enheten" "Parer…" @@ -110,7 +110,7 @@ "Velg tidssone" "Forhåndsvisning:" "Skriftstørrelse:" - + "Send broadcast" "Action:" @@ -365,8 +365,16 @@ "Applikasjoner som skal synkroniseres" "Skjerminnstillinger" "Animasjon" - "Vis animasjon når vinduer åpnes/lukkes" - "Vis animasjon når vinduer åpnes/lukkes" + + + + + + + + + + "Lysstyrke" "Juster skjermens lysstyrke" "Skjermsparer" @@ -455,6 +463,12 @@ "APNet kan ikke være tomt." "MCC-feltet må være på tre siffer." "MNC-feltet må være på to eller tre siffer." + + + + + + "Fabrikkinnstillinger" "Fjern alle data fra telefonen" "Dette vil nullstille telefonen til fabrikktilstanden, noe som fjerner alle data og nedlastede applikasjoner!" @@ -591,6 +605,8 @@ "Legg til og fjern ord fra ordlisten" "Legg til" "Legg til ordliste" + + "Rediger" "Slett" "Ordlisten er tom. Du kan legge til ord i menyen." @@ -611,7 +627,14 @@ "Snarveier" "Skriving av tekst" "Innstillinger for skriving av tekst" - "Innstillinger for %s" + + + + + + + + "Utvikling" "Innstillinger for applikasjonsutvikling" "USB-debugging" diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml index 4f1c6f9b0a5..d834db31ece 100644 --- a/res/values-nl/strings.xml +++ b/res/values-nl/strings.xml @@ -94,7 +94,7 @@ "Verbinding verbroken" "Verbinding verbreken..." "Verbinding maken..." - + "Koppelen met dit apparaat" "Koppelen..." @@ -111,7 +111,7 @@ "Tijdzone selecteren" "Voorbeeld:" "Lettergrootte:" - + "broadcast verzenden" "Action:" @@ -366,8 +366,16 @@ "Selecteren welke toepassingen worden gesynchroniseerd" "Instellingen weergeven" "Animatie" - "Animatie weergeven bij het openen/sluiten van vensters" - "Animatie weergeven bij het openen/sluiten van vensters" + + + + + + + + + + "Helderheid" "Helderheid van het scherm aanpassen" "Time-out scherm" @@ -456,6 +464,12 @@ "De APN mag niet leeg zijn." "MCC-veld moet 3 cijfers bevatten." "MNC-veld moet 2 of 3 cijfers bevatten." + + + + + + "Terugzetten op fabrieksinstellingen" "Hiermee worden alle gegevens op de telefoon gewist" "Met deze actie wordt de telefoon teruggezet op de fabrieksinstellingen. Alle gegevens en gedownloade toepassingen worden gewist!" @@ -592,6 +606,8 @@ "Woorden toevoegen aan en verwijderen uit gebruikerswoordenboek" "Toevoegen" "Toevoegen aan woordenboek" + + "Bewerken" "Verwijderen" "U heeft geen woorden in het gebruikerswoordenboek. U kunt een woord toevoegen via het menu." @@ -612,7 +628,14 @@ "Sneltoetsen" "Tekstinvoer" "Opties voor tekstinvoer beheren" - "Instellingen voor %s" + + + + + + + + "Ontwikkeling" "Opties instellen voor toepassingsontwikkeling" "USB-foutopsporing" diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml index c6e7b076a7f..21e0e01054f 100644 --- a/res/values-pl/strings.xml +++ b/res/values-pl/strings.xml @@ -94,7 +94,7 @@ "Rozłączona" "Rozłączanie..." "Łączenie..." - + "Paruj z tym urządzeniem" "Parowanie..." @@ -111,7 +111,7 @@ "Wybierz strefę czasową" "Podgląd:" "Rozmiar czcionki:" - + "Wyślij broadcast" "Action:" @@ -366,8 +366,16 @@ "Wybierz, które aplikacje są synchronizowane" "Ustawienia wyświetlacza" "Animacja" - "Pokazuj animację podczas otwierania i zamykania okien" - "Pokazuj animację podczas otwierania i zamykania okien" + + + + + + + + + + "Jasność ekranu" "Dostosuj jasność ekranu" "Wygaszanie ekranu" @@ -456,6 +464,12 @@ "Pole APN nie może być puste." "Pole MMC musi zawierać 3 cyfry." "Pole MNC musi zawierać 2 lub 3 cyfry." + + + + + + "Ustawienia fabryczne" "Wymazuje wszystkie dane w telefonie" "Ta czynność spowoduje przywrócenie w telefonie ustawień fabrycznych i wymazanie wszystkich danych oraz pobranych aplikacji!" @@ -592,6 +606,8 @@ "Dodaj i usuń słowa w słowniku użytkownika" "Dodaj" "Dodaj do słownika" + + "Edytuj" "Usuń" "Nie masz żadnych słów w słowniku użytkownika. Możesz dodać słowo poprzez menu." @@ -612,7 +628,14 @@ "Skróty" "Wprowadzanie tekstu" "Zarządzaj opcjami wprowadzania tekstu" - "%s – ustawienia" + + + + + + + + "Programowanie" "Ustaw opcje związane z programowaniem aplikacji" "Debugowanie USB" diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml index fa835ab277f..365e64d4cd0 100644 --- a/res/values-ru/strings.xml +++ b/res/values-ru/strings.xml @@ -94,7 +94,7 @@ "Отключено" "Отключение…" "Идет подключение…" - + "Создать пару с этим устройством" "Идет создание пары..." @@ -111,7 +111,7 @@ "Выбрать часовой пояс" "Предварительный просмотр:" "Размер шрифта:" - + "Отправить broadcast" "Action:" @@ -366,8 +366,16 @@ "Выбрать синхронизируемые приложения" "Настройки экрана" "Анимация" - "Показывать анимацию при открытии и закрытии окон" - "Показывать анимацию при открытии и закрытии окон" + + + + + + + + + + "Яркость" "Настроить яркость экрана" "Время до отключения экрана" @@ -456,6 +464,12 @@ "APN не может быть пустым." "Поле MCC должно содержать 3 цифры." "Поле MNC должно содержать 2 или 3 цифры." + + + + + + "Сброс заводских данных" "Удаление всех данных с телефона" "Это действие сбросит телефон до исходного заводского состояния, удалив все данные и загруженные приложения!" @@ -592,6 +606,8 @@ "Добавить или удалить слова из пользовательского словаря" "Добавить" "Добавление в словарь" + + "Изменить" "Удалить" "В пользовательском словаре отсутствуют слова. Добавить слово можно с помощью меню." @@ -612,7 +628,14 @@ "Ярлыки" "Ввод текста" "Управление параметрами ввода текста" - "Настройки %s" + + + + + + + + "Разработка" "Выбрать параметры разработки приложений" "Отладка USB" diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml index 4ad3d9e4c3f..afa5e52148b 100644 --- a/res/values-zh-rCN/strings.xml +++ b/res/values-zh-rCN/strings.xml @@ -94,7 +94,7 @@ "已断开连接" "正在断开连接..." "正在连接..." - + "与此设备配对" "正在配对..." @@ -111,7 +111,7 @@ "选择时区" "预览:" "字体大小:" - + "发送broadcast" "Action:" @@ -366,8 +366,16 @@ "选择同步哪些应用程序" "显示设置" "动画" - "打开/关闭窗口时显示动画" - "打开/关闭窗口时显示动画" + + + + + + + + + + "亮度" "调整屏幕亮度" "屏幕待机" @@ -456,6 +464,12 @@ "APN 不能为空。" "MCC 字段必须为 3 位数。" "MNC 字段必须为 2 位数或 3 位数。" + + + + + + "已重设出厂数据" "清除手机上的所有数据" "此操作会将手机重设为其初始出厂状态,即清除所有数据和下载的应用程序!" @@ -592,6 +606,8 @@ "向用户词典中添加字词以及从用户词典中删除字词" "添加" "添加到词典" + + "编辑" "删除" "用户词典中没有您定义的字词。您可以通过菜单添加字词。" @@ -612,7 +628,14 @@ "快捷键" "文本输入" "管理文本输入选项" - "%s 设置" + + + + + + + + "开发" "设置应用程序开发选项" "USB 调试" diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml index a076eb83828..5ced4cea1ee 100644 --- a/res/values-zh-rTW/strings.xml +++ b/res/values-zh-rTW/strings.xml @@ -94,7 +94,7 @@ "連線中斷" "連線中斷..." "連線中..." - + "與此裝置配對" "配對中..." @@ -111,7 +111,7 @@ "選取時區" "預覽:" "字型大小:" - + "傳送 broadcast" "Action:" @@ -366,8 +366,16 @@ "選取要同步處理的應用程式" "顯示設定" "動畫" - "開啟/關閉視窗時顯示動畫" - "開啟/關閉視窗時顯示動畫" + + + + + + + + + + "亮度" "調整螢幕亮度" "螢幕逾時" @@ -456,6 +464,12 @@ "APN 不能空白。" "MCC 欄位必須為 3 位。" "MNC 欄位至少要 2 或 3 位。" + + + + + + "出廠資料重設" "清除手機上所有資料" "此項操作會將手機回復至出廠設定,清除所有資料與下載的應用程式!" @@ -592,6 +606,8 @@ "在使用者字典中新增及移除字詞" "新增" "新增至字典" + + "編輯" "刪除" "您的使用者字典中沒有任何字詞。您可以透過選單新增字詞。" @@ -612,7 +628,14 @@ "捷徑" "文字輸入法" "管理輸入法選項" - "%s 設定" + + + + + + + + "開發" "設定應用程式開發的選項" "USB 除錯中" diff --git a/res/values/arrays.xml b/res/values/arrays.xml index d9480c2d9f3..6cfa7f0c9bb 100644 --- a/res/values/arrays.xml +++ b/res/values/arrays.xml @@ -47,9 +47,9 @@ dd-MM-yyyy - MMM dd, yyyy + MMM d, yyyy - dd-MMM-yyyy + d-MMM-yyyy yyyy-MM-dd diff --git a/res/values/strings.xml b/res/values/strings.xml index 356dbef6a27..55a153b3ece 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -812,9 +812,9 @@ Animation - Show screen transition animations + Show animation when opening & closing windows - Show screen transition animations + Show animation when opening & closing windows Orientation @@ -1314,6 +1314,13 @@ found in the list of installed applications. Visible passwords Show password as you type + + This input method may be able to collect + all the text you type, including personal data like passwords and credit + card numbers. It comes from the application + %1$s. + Enable this input method? diff --git a/src/com/android/settings/AppWidgetPickActivity.java b/src/com/android/settings/AppWidgetPickActivity.java index 0a6371204b8..acc9382236e 100644 --- a/src/com/android/settings/AppWidgetPickActivity.java +++ b/src/com/android/settings/AppWidgetPickActivity.java @@ -24,6 +24,7 @@ import android.content.Intent; import android.content.pm.PackageManager; import android.graphics.drawable.Drawable; import android.os.Bundle; +import android.os.Parcelable; import android.view.View; import android.widget.ListView; import android.util.Log; @@ -40,6 +41,9 @@ public class AppWidgetPickActivity extends LauncherActivity AppWidgetManager mAppWidgetManager; int mAppWidgetId; + ArrayList mCustomInfo; + ArrayList mCustomExtras; + Drawable mDefaultIcon = null; public AppWidgetPickActivity() { mAppWidgetManager = AppWidgetManager.getInstance(this); @@ -47,12 +51,67 @@ public class AppWidgetPickActivity extends LauncherActivity @Override public void onCreate(Bundle icicle) { - super.onCreate(icicle); - Bundle extras = getIntent().getExtras(); + if (extras == null) { + setResultData(RESULT_CANCELED, null); + finish(); + } + mAppWidgetId = extras.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID); - setResultData(RESULT_CANCELED); + // get and validate the extras they gave us + ArrayList customInfo = null; + ArrayList customExtras = null; + try_custom_items: { + customInfo = extras.getParcelableArrayList(AppWidgetManager.EXTRA_CUSTOM_INFO); + if (customInfo == null || customInfo.size() == 0) { + Log.i(TAG, "EXTRA_CUSTOM_INFO not present."); + break try_custom_items; + } + + int customInfoSize = customInfo.size(); + for (int i=0; i() { Collator mCollator = Collator.getInstance(); public int compare(ListItem lhs, ListItem rhs) { return mCollator.compare(lhs.label, rhs.label); } }); + return result; } - void setResultData(int code) { - Intent result = new Intent(); + void setResultData(int code, Intent intent) { + Intent result = intent != null ? intent : new Intent(); result.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mAppWidgetId); setResult(code, result); } diff --git a/src/com/android/settings/BrightnessPreference.java b/src/com/android/settings/BrightnessPreference.java index a9851cc93a2..9f554632631 100644 --- a/src/com/android/settings/BrightnessPreference.java +++ b/src/com/android/settings/BrightnessPreference.java @@ -93,7 +93,7 @@ public class BrightnessPreference extends SeekBarPreference implements IHardwareService hardware = IHardwareService.Stub.asInterface( ServiceManager.getService("hardware")); if (hardware != null) { - hardware.setScreenBacklight(brightness); + hardware.setBacklights(brightness); } } catch (RemoteException doe) { diff --git a/src/com/android/settings/ChooseLockPattern.java b/src/com/android/settings/ChooseLockPattern.java index 3ddd669a98f..d0c375844ae 100644 --- a/src/com/android/settings/ChooseLockPattern.java +++ b/src/com/android/settings/ChooseLockPattern.java @@ -481,8 +481,15 @@ public class ChooseLockPattern extends Activity implements View.OnClickListener{ } private void saveChosenPatternAndFinish() { + final boolean lockVirgin = !mLockPatternUtils.isPatternEverChosen(); + mLockPatternUtils.saveLockPattern(mChosenPattern); mLockPatternUtils.setLockPatternEnabled(true); + + if (lockVirgin) { + mLockPatternUtils.setVisiblePatternEnabled(true); + mLockPatternUtils.setTactileFeedbackEnabled(false); + } setResult(RESULT_FINISHED); finish(); diff --git a/src/com/android/settings/InputMethodsSettings.java b/src/com/android/settings/InputMethodsSettings.java deleted file mode 100644 index 51b770d0942..00000000000 --- a/src/com/android/settings/InputMethodsSettings.java +++ /dev/null @@ -1,191 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ - -package com.android.settings; - -import java.util.HashSet; -import java.util.List; - -import android.content.Context; -import android.content.Intent; -import android.os.Bundle; -import android.os.RemoteException; -import android.os.SystemProperties; -import android.preference.Preference; -import android.preference.PreferenceActivity; -import android.preference.PreferenceScreen; -import android.preference.CheckBoxPreference; -import android.provider.Settings; -import android.text.TextUtils; -import android.view.inputmethod.InputMethodInfo; -import android.view.inputmethod.InputMethodManager; - -/* - * Displays preferences for input methods. - */ -public class InputMethodsSettings extends PreferenceActivity { - private List mInputMethodProperties; - - final TextUtils.SimpleStringSplitter mStringColonSplitter - = new TextUtils.SimpleStringSplitter(':'); - - private String mLastInputMethodId; - private String mLastTickedInputMethodId; - - static public String getInputMethodIdFromKey(String key) { - return key; - } - - @Override - protected void onCreate(Bundle icicle) { - super.onCreate(icicle); - - addPreferencesFromResource(R.xml.input_methods_prefs); - - InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); - - mInputMethodProperties = imm.getInputMethodList(); - - mLastInputMethodId = Settings.Secure.getString(getContentResolver(), - Settings.Secure.DEFAULT_INPUT_METHOD); - - int N = (mInputMethodProperties == null ? 0 : mInputMethodProperties - .size()); - for (int i = 0; i < N; ++i) { - InputMethodInfo property = mInputMethodProperties.get(i); - String prefKey = property.getId(); - - CharSequence label = property.loadLabel(getPackageManager()); - - // Add a check box. - CheckBoxPreference chkbxPref = new CheckBoxPreference(this); - chkbxPref.setKey(prefKey); - chkbxPref.setTitle(label); - getPreferenceScreen().addPreference(chkbxPref); - - // If setting activity is available, add a setting screen entry. - if (null != property.getSettingsActivity()) { - PreferenceScreen prefScreen = new PreferenceScreen(this, null); - prefScreen.setKey(property.getSettingsActivity()); - prefScreen.setTitle(getResources().getString( - R.string.input_methods_settings_label_format, label)); - getPreferenceScreen().addPreference(prefScreen); - } - } - } - - @Override - protected void onResume() { - super.onResume(); - - final HashSet enabled = new HashSet(); - String enabledStr = Settings.Secure.getString(getContentResolver(), - Settings.Secure.ENABLED_INPUT_METHODS); - if (enabledStr != null) { - final TextUtils.SimpleStringSplitter splitter = mStringColonSplitter; - splitter.setString(enabledStr); - while (splitter.hasNext()) { - enabled.add(splitter.next()); - } - } - - // Update the statuses of the Check Boxes. - int N = mInputMethodProperties.size(); - for (int i = 0; i < N; ++i) { - final String id = mInputMethodProperties.get(i).getId(); - CheckBoxPreference pref = (CheckBoxPreference) findPreference(mInputMethodProperties - .get(i).getId()); - pref.setChecked(enabled.contains(id)); - } - mLastTickedInputMethodId = null; - } - - @Override - protected void onPause() { - super.onPause(); - - StringBuilder builder = new StringBuilder(256); - - boolean haveLastInputMethod = false; - - int firstEnabled = -1; - int N = mInputMethodProperties.size(); - for (int i = 0; i < N; ++i) { - final String id = mInputMethodProperties.get(i).getId(); - CheckBoxPreference pref = (CheckBoxPreference) findPreference(id); - boolean hasIt = id.equals(mLastInputMethodId); - if (pref.isChecked()) { - if (builder.length() > 0) builder.append(':'); - builder.append(id); - if (firstEnabled < 0) { - firstEnabled = i; - } - if (hasIt) haveLastInputMethod = true; - } else if (hasIt) { - mLastInputMethodId = mLastTickedInputMethodId; - } - } - - // If the last input method is unset, set it as the first enabled one. - if (null == mLastInputMethodId || "".equals(mLastInputMethodId)) { - if (firstEnabled >= 0) { - mLastInputMethodId = mInputMethodProperties.get(firstEnabled).getId(); - } else { - mLastInputMethodId = null; - } - } - - Settings.Secure.putString(getContentResolver(), - Settings.Secure.ENABLED_INPUT_METHODS, builder.toString()); - Settings.Secure.putString(getContentResolver(), - Settings.Secure.DEFAULT_INPUT_METHOD, mLastInputMethodId); - } - - @Override - public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, - Preference preference) { - - // Those monkeys kept committing suicide, so we add this property - // to disable this functionality - if (!TextUtils.isEmpty(SystemProperties.get("ro.monkey"))) { - return false; - } - - if (preference instanceof CheckBoxPreference) { - CheckBoxPreference chkPref = (CheckBoxPreference) preference; - String id = getInputMethodIdFromKey(chkPref.getKey()); - if (chkPref.isChecked()) { - mLastTickedInputMethodId = id; - } else if (id.equals(mLastTickedInputMethodId)) { - mLastTickedInputMethodId = null; - } - } else if (preference instanceof PreferenceScreen) { - if (preference.getIntent() == null) { - PreferenceScreen pref = (PreferenceScreen) preference; - String activityName = pref.getKey(); - String packageName = activityName.substring(0, activityName - .lastIndexOf(".")); - if (activityName.length() > 0) { - Intent i = new Intent(Intent.ACTION_MAIN); - i.setClassName(packageName, activityName); - startActivity(i); - } - } - } - - return false; - } -} diff --git a/src/com/android/settings/LanguageSettings.java b/src/com/android/settings/LanguageSettings.java index dd447be2fd6..cbab3901981 100644 --- a/src/com/android/settings/LanguageSettings.java +++ b/src/com/android/settings/LanguageSettings.java @@ -16,8 +16,12 @@ package com.android.settings; +import android.app.AlertDialog; +import android.app.Dialog; import android.content.Context; +import android.content.DialogInterface; import android.content.Intent; +import android.content.pm.ApplicationInfo; import android.content.res.Configuration; import android.os.Bundle; import android.os.Environment; @@ -29,6 +33,7 @@ import android.preference.PreferenceGroup; import android.preference.PreferenceScreen; import android.provider.Settings; import android.text.TextUtils; +import android.view.View.OnClickListener; import android.view.inputmethod.InputMethodInfo; import android.view.inputmethod.InputMethodManager; @@ -74,12 +79,12 @@ public class LanguageSettings extends PreferenceActivity { mHaveHardKeyboard = true; } mCheckboxes = new ArrayList(); - mRootDirectory = Environment.getRootDirectory().getAbsolutePath(); onCreateIMM(); } private boolean isSystemIme(InputMethodInfo property) { - return property.getServiceInfo().applicationInfo.sourceDir.startsWith(mRootDirectory); + return (property.getServiceInfo().applicationInfo.flags + & ApplicationInfo.FLAG_SYSTEM) != 0; } private void onCreateIMM() { @@ -161,8 +166,6 @@ public class LanguageSettings extends PreferenceActivity { StringBuilder builder = new StringBuilder(256); - boolean haveLastInputMethod = false; - int firstEnabled = -1; int N = mInputMethodProperties.size(); for (int i = 0; i < N; ++i) { @@ -178,7 +181,6 @@ public class LanguageSettings extends PreferenceActivity { if (firstEnabled < 0) { firstEnabled = i; } - if (hasIt) haveLastInputMethod = true; } else if (hasIt) { mLastInputMethodId = mLastTickedInputMethodId; } @@ -196,7 +198,8 @@ public class LanguageSettings extends PreferenceActivity { Settings.Secure.putString(getContentResolver(), Settings.Secure.ENABLED_INPUT_METHODS, builder.toString()); Settings.Secure.putString(getContentResolver(), - Settings.Secure.DEFAULT_INPUT_METHOD, mLastInputMethodId); + Settings.Secure.DEFAULT_INPUT_METHOD, + mLastInputMethodId != null ? mLastInputMethodId : ""); } @Override @@ -210,10 +213,49 @@ public class LanguageSettings extends PreferenceActivity { } if (preference instanceof CheckBoxPreference) { - CheckBoxPreference chkPref = (CheckBoxPreference) preference; - String id = getInputMethodIdFromKey(chkPref.getKey()); + final CheckBoxPreference chkPref = (CheckBoxPreference) preference; + final String id = getInputMethodIdFromKey(chkPref.getKey()); if (chkPref.isChecked()) { - mLastTickedInputMethodId = id; + InputMethodInfo selImi = null; + final int N = mInputMethodProperties.size(); + for (int i=0; i newList = getInstalledApps(FILTER_APPS_ALL); if (!mJustCreated) { // Add or delete newly created packages by comparing lists - List newList = getInstalledApps(FILTER_APPS_ALL); - int oldCount = mAppPropCache.size(); - boolean idxArr[] = new boolean[oldCount]; - for ( int i = 0; i < oldCount; i++) { - idxArr[i] = false; - } - - if (newList != null) { - for (ApplicationInfo app : newList) { - AppInfo aInfo = mAppPropCache.get(app.packageName); - if ( aInfo == null) { - // New package. post an ADD_PKG message - if(localLOGV) Log.i(TAG, "Adding pkg: "+app.packageName); - updatePackageList(Intent.ACTION_PACKAGE_ADDED, app.packageName); - } else { - idxArr[aInfo.index] = true; - } - } - Set keyList = mAppPropCache.keySet(); - for (String key : keyList) { - AppInfo aInfo = mAppPropCache.get(key); - int idx = aInfo.index; - if (!idxArr[idx]) { - String pkg = aInfo.pkgName; - if(localLOGV) Log.i(TAG, "Deleting pkg: " + pkg); - updatePackageList(Intent.ACTION_PACKAGE_REMOVED, pkg); - } - } - } + updateAppList(newList); } // Retrieve the package list and init some structures initAppList(mFilterApps); @@ -308,46 +283,11 @@ public class ManageApplications extends ListActivity implements mObserver.invokeGetSizeInfo(mAppInfoAdapter.getApplicationInfo( mComputeIndex), COMPUTE_PKG_SIZE_DONE); - } else { - // check for added/removed packages - Set keys = mAddRemoveMap.keySet(); - Iterator iter = keys.iterator(); - List removeList = new ArrayList(); - boolean added = false; - boolean removed = false; - while (iter.hasNext()) { - String key = iter.next(); - if (mAddRemoveMap.get(key) == Boolean.TRUE) { - // add - try { - info = mPm.getApplicationInfo(key, 0); - mAppInfoAdapter.addApplicationInfo(info); - added = true; - } catch (NameNotFoundException e) { - Log.w(TAG, "Invalid added package:"+key+" Ignoring entry"); - } - } else { - // remove - removeList.add(key); - removed = true; - } - } - // remove uninstalled packages from list - if (removed) { - mAppInfoAdapter.removeFromList(removeList); - } - // handle newly installed packages - if (added) { - mObserver.invokeGetSizeInfo(mAppInfoAdapter.getApplicationInfo( - mComputeIndex), - COMPUTE_PKG_SIZE_DONE); - } else { - // end computation here - mComputeSizes = true; - mFirst = true; - mAppInfoAdapter.sortList(mSortOrder); - mHandler.sendEmptyMessage(NEXT_LOAD_STEP); - } + } else { + // End computation here + mComputeSizes = true; + mFirst = true; + mHandler.sendEmptyMessage(NEXT_LOAD_STEP); } break; case REMOVE_PKG: @@ -381,8 +321,7 @@ public class ManageApplications extends ListActivity implements } else if(menuOption != mFilterApps) { // Option to filter list mFilterApps = menuOption; - boolean ret = mAppInfoAdapter.resetAppList(mFilterApps, - getInstalledApps(mFilterApps)); + boolean ret = mAppInfoAdapter.resetAppList(mFilterApps); if(!ret) { // Reset cache mAppPropCache = null; @@ -398,7 +337,7 @@ public class ManageApplications extends ListActivity implements Log.w(TAG, "Ignoring message:ADD_PKG_START for null pkgName"); break; } - if (!mComputeSizes) { + if (!mComputeSizes || !mLoadLabels) { Boolean currB = mAddRemoveMap.get(pkgName); if (currB == null || (currB.equals(Boolean.FALSE))) { mAddRemoveMap.put(pkgName, Boolean.TRUE); @@ -406,11 +345,11 @@ public class ManageApplications extends ListActivity implements break; } try { - info = mPm.getApplicationInfo(pkgName, 0); - } catch (NameNotFoundException e) { - Log.w(TAG, "Couldnt find application info for:"+pkgName); - break; - } + info = mPm.getApplicationInfo(pkgName, 0); + } catch (NameNotFoundException e) { + Log.w(TAG, "Couldnt find application info for:"+pkgName); + break; + } mObserver.invokeGetSizeInfo(info, ADD_PKG_DONE); break; case ADD_PKG_DONE: @@ -422,19 +361,33 @@ public class ManageApplications extends ListActivity implements ps = data.getParcelable(ATTR_APP_PKG_STATS); mAppInfoAdapter.addToList(pkgName, ps); break; - case REFRESH_ICONS: - Map iconMap = (Map) msg.obj; - if(iconMap == null) { + case REFRESH_APP_RESOURCE: + AppInfo aInfo = (AppInfo) msg.obj; + if(aInfo == null) { Log.w(TAG, "Error loading icons for applications"); } else { - mAppInfoAdapter.updateAppsResourceInfo(iconMap); + mAppInfoAdapter.updateAppsResourceInfo(aInfo); } + break; + case REFRESH_DONE: mLoadLabels = true; mHandler.sendEmptyMessage(NEXT_LOAD_STEP); break; case NEXT_LOAD_STEP: if (mComputeSizes && mLoadLabels) { doneLoadingData(); + // Check for added/removed packages + Set keys = mAddRemoveMap.keySet(); + for (String key : keys) { + if (mAddRemoveMap.get(key) == Boolean.TRUE) { + // Add the package + updatePackageList(Intent.ACTION_PACKAGE_ADDED, key); + } else { + // Remove the package + updatePackageList(Intent.ACTION_PACKAGE_REMOVED, key); + } + } + mAddRemoveMap.clear(); } else if (!mComputeSizes && !mLoadLabels) { // Either load the package labels or initiate get size info if (mSizesFirst) { @@ -446,12 +399,13 @@ public class ManageApplications extends ListActivity implements // Create list view from the adapter here. Wait till the sort order // of list is defined. its either by label or by size. so atleast one of the // first steps should be complete before filling the list + mAppInfoAdapter.sortList(mSortOrder); if (mJustCreated) { // Set the adapter here. mJustCreated = false; mListView.setAdapter(mAppInfoAdapter); dismissLoadingMsg(); - } + } if (!mComputeSizes) { initComputeSizes(); } else if (!mLoadLabels) { @@ -465,7 +419,49 @@ public class ManageApplications extends ListActivity implements } }; - + /* + * This method compares the current cache against a new list of + * installed applications and tries to update the list with add or remove + * messages. + */ + private boolean updateAppList(List newList) { + if ((newList == null) || (mAppPropCache == null)) { + return false; + } + Set existingList = new HashSet(); + boolean ret = false; + // Loop over new list and find out common elements between old and new lists + for (ApplicationInfo info : newList) { + String pkgName = info.packageName; + AppInfo aInfo = mAppPropCache.get(pkgName); + if (aInfo != null) { + existingList.add(pkgName); + } else { + // New package. update info by refreshing + if (localLOGV) Log.i(TAG, "New pkg :"+pkgName+" installed when paused"); + updatePackageList(Intent.ACTION_PACKAGE_ADDED, pkgName); + ret = true; + } + } + // Loop over old list and figure out state entries + List deletedList = null; + Set staleList = mAppPropCache.keySet(); + for (String pkgName : staleList) { + if (!existingList.contains(pkgName)) { + if (localLOGV) Log.i(TAG, "Pkg :"+pkgName+" deleted when paused"); + if (deletedList == null) { + deletedList = new ArrayList(); + deletedList.add(pkgName); + } + ret = true; + } + } + // Delete right away + if (deletedList != null) { + mAppInfoAdapter.removeFromList(deletedList); + } + return ret; + } private void doneLoadingData() { setProgressBarIndeterminateVisibility(false); @@ -524,16 +520,68 @@ public class ManageApplications extends ListActivity implements } } + /* + * Utility method used to figure out list of apps based on filterOption + * If the framework supports an additional flag to indicate running apps + * we can get away with some code here. + */ + List getFilteredApps(List pAppList, int filterOption) { + List retList = new ArrayList(); + if(pAppList == null) { + return retList; + } + if (filterOption == FILTER_APPS_THIRD_PARTY) { + List appList =new ArrayList (); + for (ApplicationInfo appInfo : pAppList) { + boolean flag = false; + if ((appInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0) { + // Updated system app + flag = true; + } else if ((appInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) { + // Non-system app + flag = true; + } + if (flag) { + appList.add(appInfo); + } + } + return appList; + } else if (filterOption == FILTER_APPS_RUNNING) { + List appList =new ArrayList (); + List procList = getRunningAppProcessesList(); + if ((procList == null) || (procList.size() == 0)) { + return appList; + } + // Retrieve running processes from ActivityManager + HashMap runningMap = + new HashMap(); + for (ActivityManager.RunningAppProcessInfo appProcInfo : procList) { + if ((appProcInfo != null) && (appProcInfo.pkgList != null)){ + int size = appProcInfo.pkgList.length; + for (int i = 0; i < size; i++) { + runningMap.put(appProcInfo.pkgList[i], appProcInfo); + } + } + } + // Query list to find running processes in current list + for (ApplicationInfo appInfo : pAppList) { + if (runningMap.get(appInfo.packageName) != null) { + appList.add(appInfo); + } + } + return appList; + } else { + return pAppList; + } + } + private List getRunningAppProcessesList() { ActivityManager am = (ActivityManager)getSystemService(Context.ACTIVITY_SERVICE); return am.getRunningAppProcesses(); } - // some initialization code used when kicking off the size computation private void initAppList(int filterOption) { - // Initialize lists - List appList = getInstalledApps(filterOption); - initAppList(appList, filterOption); + initAppList(null, filterOption); } // some initialization code used when kicking off the size computation @@ -544,7 +592,7 @@ public class ManageApplications extends ListActivity implements mLoadLabels = false; // Initialize lists mAddRemoveMap = new TreeMap(); - mAppInfoAdapter.resetAppList(filterOption, appList); + mAppInfoAdapter.initMapFromList(appList, filterOption); } // Utility method to start a thread to read application labels and icons @@ -552,6 +600,7 @@ public class ManageApplications extends ListActivity implements //load resources now if(mResourceThread.isAlive()) { mResourceThread.interrupt(); + mResourceThread = new ResourceLoaderThread(); } mResourceThread.loadAllResources(mAppInfoAdapter.getAppList()); } @@ -605,13 +654,13 @@ public class ManageApplications extends ListActivity implements for (ApplicationInfo appInfo : mAppList) { CharSequence appName = appInfo.loadLabel(mPm); Drawable appIcon = appInfo.loadIcon(mPm); - iconMap.put(appInfo.packageName, - new AppInfo(appInfo.packageName, appName, appIcon)); + Message msg = mHandler.obtainMessage(REFRESH_APP_RESOURCE); + msg.obj = new AppInfo(appInfo.packageName, appName, appIcon); + mHandler.sendMessage(msg); } } - Message msg = mHandler.obtainMessage(REFRESH_ICONS); - msg.obj = iconMap; - mHandler.sendMessage(msg); + Message doneMsg = mHandler.obtainMessage(REFRESH_DONE); + mHandler.sendMessage(doneMsg); } } @@ -700,6 +749,7 @@ public class ManageApplications extends ListActivity implements */ class AppInfoAdapter extends BaseAdapter { private Map mAppPropMap; + private List mAppList; private List mAppLocalList; ApplicationInfo.DisplayNameComparator mAlphaComparator; AppInfoComparator mSizeComparator; @@ -710,34 +760,51 @@ public class ManageApplications extends ListActivity implements } return mAppPropCache.get(packageName); } - - public AppInfoAdapter(Context c, List appList) { - mAppLocalList = appList; - boolean useCache = false; - int sortOrder = SORT_ORDER_ALPHA; - int imax = mAppLocalList.size(); - if(mAppPropCache != null) { - useCache = true; - // Activity has been resumed. can use the cache to populate values initially - mAppPropMap = mAppPropCache; - sortOrder = mSortOrder; + + // Make sure the cache or map contains entries for all elements + // in appList for a valid sort. + public void initMapFromList(List appList, int filterOption) { + if (appList == null) { + // Just refresh the list + appList = mAppList; + } else { + mAppList = appList; } + mAppLocalList = getFilteredApps(appList, filterOption); + int sortOrder = SORT_ORDER_ALPHA; + if (mAppPropCache != null) { + // Retain previous sort order + sortOrder = mSortOrder; + mAppPropMap = mAppPropCache; + } else { + // Recreate property map + mAppPropMap = new TreeMap(); + } + // Re init the comparators + mAlphaComparator = null; + mSizeComparator = null; + sortAppList(sortOrder); - // Recreate property map - mAppPropMap = new TreeMap(); + int imax = appList.size(); for (int i = 0; i < imax; i++) { - ApplicationInfo info = mAppLocalList.get(i); - AppInfo aInfo = getFromCache(info.packageName); + ApplicationInfo info = appList.get(i); + AppInfo aInfo = mAppPropMap.get(info.packageName); if(aInfo == null){ aInfo = new AppInfo(info.packageName, i, - info.packageName, mDefaultAppIcon, null); + info.packageName, mDefaultAppIcon, null); + if (localLOGV) Log.i(TAG, "Creating entry pkg:"+info.packageName+" to map"); } else { aInfo.index = i; + if (localLOGV) Log.i(TAG, "Adding pkg:"+info.packageName+" to map"); } mAppPropMap.put(info.packageName, aInfo); } } + public AppInfoAdapter(Context c, List appList) { + initMapFromList(appList, mFilterApps); + } + public int getCount() { return mAppLocalList.size(); } @@ -772,14 +839,6 @@ public class ManageApplications extends ListActivity implements } return mAppLocalList.get(position); } - - public void addApplicationInfo(ApplicationInfo info) { - if(info == null) { - Log.w(TAG, "Ignoring null add in List Adapter"); - return; - } - mAppLocalList.add(info); - } public long getItemId(int position) { int imax = mAppLocalList.size(); @@ -843,9 +902,8 @@ public class ManageApplications extends ListActivity implements private void adjustIndex() { int imax = mAppLocalList.size(); - ApplicationInfo info; for (int i = 0; i < imax; i++) { - info = mAppLocalList.get(i); + ApplicationInfo info = mAppLocalList.get(i); mAppPropMap.get(info.packageName).index = i; } } @@ -855,21 +913,28 @@ public class ManageApplications extends ListActivity implements } public void sortList(int sortOrder) { + if (localLOGV) Log.i(TAG, "sortOrder = "+sortOrder); sortAppList(sortOrder); adjustIndex(); notifyDataSetChanged(); } - public boolean resetAppList(int filterOption, List appList) { - // Create application list based on the filter value - mAppLocalList = appList; + /* + * Reset the application list associated with this adapter. + * @param filterOption Sort the list based on this value + * @param appList the actual application list that is used to reset + * @return Return a boolean value to indicate inconsistency + */ + public boolean resetAppList(int filterOption) { + // Change application list based on filter option + mAppLocalList = getFilteredApps(mAppList, filterOption); // Check for all properties in map before sorting. Populate values from cache for(ApplicationInfo applicationInfo : mAppLocalList) { AppInfo appInfo = mAppPropMap.get(applicationInfo.packageName); if(appInfo == null) { AppInfo rInfo = getFromCache(applicationInfo.packageName); if(rInfo == null) { - // Need to load resources again. Inconsistency somewhere + // Need to load resources again. Inconsistency somewhere return false; } mAppPropMap.put(applicationInfo.packageName, rInfo); @@ -912,7 +977,7 @@ public class ManageApplications extends ListActivity implements return true; } boolean changed = false; - for (ApplicationInfo info : mAppLocalList) { + for (ApplicationInfo info : mAppList) { AppInfo pInfo = iconMap.get(info.packageName); if(pInfo != null) { AppInfo aInfo = mAppPropMap.get(info.packageName); @@ -930,27 +995,39 @@ public class ManageApplications extends ListActivity implements return true; } + public boolean updateAppsResourceInfo(AppInfo pInfo) { + if(pInfo == null) { + Log.w(TAG, "Null info when refreshing icon in List Adapter"); + return false; + } + AppInfo aInfo = mAppPropMap.get(pInfo.pkgName); + if (aInfo != null) { + aInfo.refreshIcon(pInfo); + notifyDataSetChanged(); + return true; + } + return false; + } + private boolean shouldBeInList(int filterOption, ApplicationInfo info) { // Match filter here - boolean addToCurrList = false; if (filterOption == FILTER_APPS_RUNNING) { List runningList = getInstalledApps(FILTER_APPS_RUNNING); for (ApplicationInfo running : runningList) { if (running.packageName.equalsIgnoreCase(info.packageName)) { - addToCurrList = true; - break; + return true; } } } else if (filterOption == FILTER_APPS_THIRD_PARTY) { if ((info.flags & ApplicationInfo.FLAG_SYSTEM) == 0) { - addToCurrList = true; + return true; } else if ((info.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0) { - addToCurrList = true; + return true; } } else { return true; } - return addToCurrList; + return false; } /* @@ -961,20 +1038,15 @@ public class ManageApplications extends ListActivity implements * @param ps PackageStats of new package */ public void addToList(String pkgName, PackageStats ps) { - if(pkgName == null) { - Log.w(TAG, "Adding null pkg to List Adapter"); + if((pkgName == null) || (ps == null)) { + if (pkgName == null) { + Log.w(TAG, "Adding null pkg to List Adapter"); + } else { + Log.w(TAG, "Adding pkg : "+pkgName+" with invalid PackageStats"); + } return; } boolean notInList = true; - int newIdx = getIndex(pkgName); - if (newIdx != -1) { - notInList = false; - if (mAppPropMap.get(pkgName) != null) { - // weird. just ignore entry - Log.i(TAG, "Package:"+pkgName+" already added"); - return; - } - } // Get ApplicationInfo ApplicationInfo info = null; try { @@ -988,14 +1060,17 @@ public class ManageApplications extends ListActivity implements Log.i(TAG, "Null ApplicationInfo for package:"+pkgName); return; } - // Add entry to map - mAppPropMap.put(pkgName, new AppInfo(pkgName, newIdx, + // Add entry to local list + mAppList.add(info); + // Add entry to map. Note that the index gets adjusted later on based on + // whether the newly added package is part of displayed list + mAppPropMap.put(pkgName, new AppInfo(pkgName, -1, info.loadLabel(mPm), info.loadIcon(mPm), ps)); // Add to list if (notInList && (shouldBeInList(mFilterApps, info))) { // Binary search returns a negative index (ie -index) of the position where // this might be inserted. - newIdx = Collections.binarySearch(mAppLocalList, info, + int newIdx = Collections.binarySearch(mAppLocalList, info, getAppComparator(mSortOrder)); if(newIdx >= 0) { Log.i(TAG, "Strange. Package:"+pkgName+" is not new"); @@ -1010,11 +1085,30 @@ public class ManageApplications extends ListActivity implements } } + private void removePkgListBase(List pkgNames) { + for (String pkg : pkgNames) { + removePkgBase(pkg); + } + } + + private void removePkgBase(String pkgName) { + int imax = mAppList.size(); + for (int i = 0; i < imax; i++) { + ApplicationInfo app = mAppList.get(i); + if (app.packageName.equalsIgnoreCase(pkgName)) { + if (localLOGV) Log.i(TAG, "Removing pkg: "+pkgName+" from base list"); + mAppList.remove(i); + return; + } + } + } + public void removeFromList(List pkgNames) { if(pkgNames == null) { Log.w(TAG, "Removing null pkg list from List Adapter"); return; } + removePkgListBase(pkgNames); int imax = mAppLocalList.size(); boolean found = false; ApplicationInfo info; @@ -1042,7 +1136,7 @@ public class ManageApplications extends ListActivity implements } // Sort idxArr Arrays.sort(idxArr); - // remove the packages based on decending indices + // remove the packages based on descending indices for (k = kmax-1; k >= 0; k--) { // Check if package has been found in the list of existing apps first if(idxArr[k] == -1) { @@ -1051,13 +1145,13 @@ public class ManageApplications extends ListActivity implements info = mAppLocalList.get(idxArr[k]); mAppLocalList.remove(idxArr[k]); mAppPropMap.remove(info.packageName); - if (localLOGV) Log.i(TAG, "Removed pkg:"+info.packageName+ " list"); + if (localLOGV) Log.i(TAG, "Removed pkg:"+info.packageName+ " from display list"); } if (found) { adjustIndex(); notifyDataSetChanged(); } - } + } public void updateAppSize(String pkgName, PackageStats ps) { if(pkgName == null) { @@ -1213,6 +1307,7 @@ public class ManageApplications extends ListActivity implements requestWindowFeature(Window.FEATURE_PROGRESS); requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS); setContentView(R.layout.compute_sizes); + showLoadingMsg(); mDefaultAppIcon =Resources.getSystem().getDrawable( com.android.internal.R.drawable.sym_def_app_icon); mInvalidSizeStr = getText(R.string.invalid_size_value); @@ -1231,7 +1326,6 @@ public class ManageApplications extends ListActivity implements lv.setItemsCanFocus(true); lv.setOnItemClickListener(this); mListView = lv; - showLoadingMsg(); } @Override @@ -1263,9 +1357,9 @@ public class ManageApplications extends ListActivity implements super.onStart(); // Create a thread to load resources mResourceThread = new ResourceLoaderThread(); - sendMessageToHandler(INIT_PKG_INFO); // register receiver mReceiver.registerReceiver(); + sendMessageToHandler(INIT_PKG_INFO); } @Override diff --git a/src/com/android/settings/bluetooth/BluetoothDiscoverableEnabler.java b/src/com/android/settings/bluetooth/BluetoothDiscoverableEnabler.java index f1a2a1e409d..d458c5fdd0b 100644 --- a/src/com/android/settings/bluetooth/BluetoothDiscoverableEnabler.java +++ b/src/com/android/settings/bluetooth/BluetoothDiscoverableEnabler.java @@ -92,7 +92,6 @@ public class BluetoothDiscoverableEnabler implements Preference.OnPreferenceChan } IntentFilter filter = new IntentFilter(BluetoothIntent.SCAN_MODE_CHANGED_ACTION); - filter.addAction(BluetoothIntent.DISABLED_ACTION); mContext.registerReceiver(mReceiver, filter); mCheckBoxPreference.setOnPreferenceChangeListener(this); diff --git a/src/com/android/settings/bluetooth/BluetoothEnabler.java b/src/com/android/settings/bluetooth/BluetoothEnabler.java index 661700fd3c5..82961b86215 100644 --- a/src/com/android/settings/bluetooth/BluetoothEnabler.java +++ b/src/com/android/settings/bluetooth/BluetoothEnabler.java @@ -17,8 +17,9 @@ package com.android.settings.bluetooth; import com.android.settings.R; -import com.android.settings.bluetooth.LocalBluetoothManager.ExtendedBluetoothState; +import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothIntent; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; @@ -70,15 +71,15 @@ public class BluetoothEnabler implements Preference.OnPreferenceChangeListener { return; } - ExtendedBluetoothState state = mLocalManager.getBluetoothState(); + int state = mLocalManager.getBluetoothState(); // This is the widget enabled state, not the preference toggled state - mCheckBoxPreference.setEnabled(state == ExtendedBluetoothState.ENABLED || - state == ExtendedBluetoothState.DISABLED); + mCheckBoxPreference.setEnabled(state == BluetoothDevice.BLUETOOTH_STATE_ON || + state == BluetoothDevice.BLUETOOTH_STATE_OFF); // BT state is not a sticky broadcast, so set it manually handleStateChanged(state); mContext.registerReceiver(mReceiver, - new IntentFilter(LocalBluetoothManager.EXTENDED_BLUETOOTH_STATE_CHANGED_ACTION)); + new IntentFilter(BluetoothIntent.BLUETOOTH_STATE_CHANGED_ACTION)); mCheckBoxPreference.setOnPreferenceChangeListener(this); } @@ -106,22 +107,24 @@ public class BluetoothEnabler implements Preference.OnPreferenceChangeListener { mLocalManager.setBluetoothEnabled(enable); } - private void handleStateChanged(ExtendedBluetoothState state) { + private void handleStateChanged(int state) { - if (state == ExtendedBluetoothState.DISABLED || state == ExtendedBluetoothState.ENABLED) { - mCheckBoxPreference.setChecked(state == ExtendedBluetoothState.ENABLED); - mCheckBoxPreference - .setSummary(state == ExtendedBluetoothState.DISABLED ? mOriginalSummary : null); + if (state == BluetoothDevice.BLUETOOTH_STATE_OFF || + state == BluetoothDevice.BLUETOOTH_STATE_ON) { + mCheckBoxPreference.setChecked(state == BluetoothDevice.BLUETOOTH_STATE_ON); + mCheckBoxPreference.setSummary(state == BluetoothDevice.BLUETOOTH_STATE_OFF ? + mOriginalSummary : + null); mCheckBoxPreference.setEnabled(isEnabledByDependency()); - } else if (state == ExtendedBluetoothState.ENABLING || - state == ExtendedBluetoothState.DISABLING) { - mCheckBoxPreference.setSummary(state == ExtendedBluetoothState.ENABLING + } else if (state == BluetoothDevice.BLUETOOTH_STATE_TURNING_ON || + state == BluetoothDevice.BLUETOOTH_STATE_TURNING_OFF) { + mCheckBoxPreference.setSummary(state == BluetoothDevice.BLUETOOTH_STATE_TURNING_ON ? R.string.wifi_starting : R.string.wifi_stopping); - } else if (state == ExtendedBluetoothState.UNKNOWN) { + } else { mCheckBoxPreference.setChecked(false); mCheckBoxPreference.setSummary(R.string.wifi_error); mCheckBoxPreference.setEnabled(true); diff --git a/src/com/android/settings/bluetooth/BluetoothEventRedirector.java b/src/com/android/settings/bluetooth/BluetoothEventRedirector.java index 2ad5726ddc7..71b91d33a0a 100644 --- a/src/com/android/settings/bluetooth/BluetoothEventRedirector.java +++ b/src/com/android/settings/bluetooth/BluetoothEventRedirector.java @@ -16,8 +16,6 @@ package com.android.settings.bluetooth; -import com.android.settings.bluetooth.LocalBluetoothManager.ExtendedBluetoothState; - import android.bluetooth.BluetoothA2dp; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothHeadset; @@ -50,12 +48,10 @@ public class BluetoothEventRedirector { String action = intent.getAction(); String address = intent.getStringExtra(BluetoothIntent.ADDRESS); - if (action.equals(BluetoothIntent.ENABLED_ACTION)) { - mManager.setBluetoothStateInt(ExtendedBluetoothState.ENABLED); - - } else if (action.equals(BluetoothIntent.DISABLED_ACTION)) { - mManager.setBluetoothStateInt(ExtendedBluetoothState.DISABLED); - + if (action.equals(BluetoothIntent.BLUETOOTH_STATE_CHANGED_ACTION)) { + int state = intent.getIntExtra(BluetoothIntent.BLUETOOTH_STATE, + BluetoothError.ERROR); + mManager.setBluetoothStateInt(state); } else if (action.equals(BluetoothIntent.DISCOVERY_STARTED_ACTION)) { mManager.onScanningStateChanged(true); @@ -86,25 +82,29 @@ public class BluetoothEventRedirector { } } else if (action.equals(BluetoothIntent.HEADSET_STATE_CHANGED_ACTION)) { - mManager.getLocalDeviceManager().onProfileStateChanged(address); - int newState = intent.getIntExtra(BluetoothIntent.HEADSET_STATE, 0); int oldState = intent.getIntExtra(BluetoothIntent.HEADSET_PREVIOUS_STATE, 0); if (newState == BluetoothHeadset.STATE_DISCONNECTED && oldState == BluetoothHeadset.STATE_CONNECTING) { Log.i(TAG, "Failed to connect BT headset"); } - - } else if (action.equals(BluetoothA2dp.SINK_STATE_CHANGED_ACTION)) { - mManager.getLocalDeviceManager().onProfileStateChanged(address); + boolean transientState = !(newState == BluetoothHeadset.STATE_CONNECTED + || newState == BluetoothHeadset.STATE_DISCONNECTED); + mManager.getLocalDeviceManager().onProfileStateChanged(address,transientState); + + } else if (action.equals(BluetoothA2dp.SINK_STATE_CHANGED_ACTION)) { int newState = intent.getIntExtra(BluetoothA2dp.SINK_STATE, 0); int oldState = intent.getIntExtra(BluetoothA2dp.SINK_PREVIOUS_STATE, 0); if (newState == BluetoothA2dp.STATE_DISCONNECTED && oldState == BluetoothA2dp.STATE_CONNECTING) { Log.i(TAG, "Failed to connect BT A2DP"); } - + + boolean transientState = !(newState == BluetoothA2dp.STATE_CONNECTED + || newState == BluetoothA2dp.STATE_DISCONNECTED); + mManager.getLocalDeviceManager().onProfileStateChanged(address, transientState); + } else if (action.equals(BluetoothIntent.REMOTE_DEVICE_CLASS_UPDATED_ACTION)) { mManager.getLocalDeviceManager().onBtClassChanged(address); @@ -120,8 +120,7 @@ public class BluetoothEventRedirector { IntentFilter filter = new IntentFilter(); // Bluetooth on/off broadcasts - filter.addAction(BluetoothIntent.ENABLED_ACTION); - filter.addAction(BluetoothIntent.DISABLED_ACTION); + filter.addAction(BluetoothIntent.BLUETOOTH_STATE_CHANGED_ACTION); // Discovery broadcasts filter.addAction(BluetoothIntent.DISCOVERY_STARTED_ACTION); diff --git a/src/com/android/settings/bluetooth/BluetoothNamePreference.java b/src/com/android/settings/bluetooth/BluetoothNamePreference.java index 3065b26c5e5..40bab2ccae8 100644 --- a/src/com/android/settings/bluetooth/BluetoothNamePreference.java +++ b/src/com/android/settings/bluetooth/BluetoothNamePreference.java @@ -17,6 +17,7 @@ package com.android.settings.bluetooth; import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothError; import android.bluetooth.BluetoothIntent; import android.content.BroadcastReceiver; import android.content.Context; @@ -39,7 +40,14 @@ public class BluetoothNamePreference extends EditTextPreference { private BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { - setSummaryToName(); + String action = intent.getAction(); + if (action.equals(BluetoothIntent.NAME_CHANGED_ACTION)) { + setSummaryToName(); + } else if (action.equals(BluetoothIntent.BLUETOOTH_STATE_CHANGED_ACTION) && + (intent.getIntExtra(BluetoothIntent.BLUETOOTH_STATE, + BluetoothError.ERROR) == BluetoothDevice.BLUETOOTH_STATE_ON)) { + setSummaryToName(); + } } }; @@ -53,7 +61,7 @@ public class BluetoothNamePreference extends EditTextPreference { public void resume() { IntentFilter filter = new IntentFilter(); - filter.addAction(BluetoothIntent.ENABLED_ACTION); + filter.addAction(BluetoothIntent.BLUETOOTH_STATE_CHANGED_ACTION); filter.addAction(BluetoothIntent.NAME_CHANGED_ACTION); getContext().registerReceiver(mReceiver, filter); } diff --git a/src/com/android/settings/bluetooth/BluetoothSettings.java b/src/com/android/settings/bluetooth/BluetoothSettings.java index 5adada3c424..e6ac5fdb3c8 100644 --- a/src/com/android/settings/bluetooth/BluetoothSettings.java +++ b/src/com/android/settings/bluetooth/BluetoothSettings.java @@ -18,11 +18,12 @@ package com.android.settings.bluetooth; import com.android.settings.ProgressCategory; import com.android.settings.R; -import com.android.settings.bluetooth.LocalBluetoothManager.ExtendedBluetoothState; import java.util.List; import java.util.WeakHashMap; +import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothIntent; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; @@ -117,8 +118,8 @@ public class BluetoothSettings extends PreferenceActivity mLocalManager.startScanning(false); - registerReceiver(mReceiver, - new IntentFilter(LocalBluetoothManager.EXTENDED_BLUETOOTH_STATE_CHANGED_ACTION)); + registerReceiver(mReceiver, + new IntentFilter(BluetoothIntent.BLUETOOTH_STATE_CHANGED_ACTION)); mLocalManager.setForegroundActivity(this); } @@ -248,12 +249,12 @@ public class BluetoothSettings extends PreferenceActivity mDeviceList.setProgress(started); } - private void onBluetoothStateChanged(ExtendedBluetoothState bluetoothState) { + private void onBluetoothStateChanged(int bluetoothState) { // When bluetooth is enabled (and we are in the activity, which we are), // we should start a scan - if (bluetoothState == ExtendedBluetoothState.ENABLED) { + if (bluetoothState == BluetoothDevice.BLUETOOTH_STATE_ON) { mLocalManager.startScanning(false); - } else if (bluetoothState == ExtendedBluetoothState.DISABLED) { + } else if (bluetoothState == BluetoothDevice.BLUETOOTH_STATE_OFF) { mDeviceList.setProgress(false); } } diff --git a/src/com/android/settings/bluetooth/LocalBluetoothDevice.java b/src/com/android/settings/bluetooth/LocalBluetoothDevice.java index a4885401e23..eedae936fb5 100644 --- a/src/com/android/settings/bluetooth/LocalBluetoothDevice.java +++ b/src/com/android/settings/bluetooth/LocalBluetoothDevice.java @@ -20,22 +20,23 @@ import com.android.settings.R; import com.android.settings.bluetooth.LocalBluetoothProfileManager.Profile; import android.app.AlertDialog; -import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothClass; -import android.bluetooth.IBluetoothDeviceCallback; +import android.bluetooth.BluetoothDevice; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.res.Resources; -import android.os.IBinder; -import android.os.RemoteException; import android.text.TextUtils; import android.util.Log; import android.view.ContextMenu; import android.view.Menu; import android.view.MenuItem; +import java.text.DateFormat; import java.util.ArrayList; +import java.util.Date; +import java.util.Iterator; +import java.util.LinkedList; import java.util.List; /** @@ -71,6 +72,173 @@ public class LocalBluetoothDevice implements Comparable { */ private boolean mIsConnectingErrorPossible; + // Max time to hold the work queue if we don't get or missed a response + // from the bt framework. + private static final long MAX_WAIT_TIME_FOR_FRAMEWORK = 25 * 1000; + + private enum BluetoothCommand { + CONNECT, DISCONNECT, + } + + class BluetoothJob { + final BluetoothCommand command; // CONNECT, DISCONNECT + final LocalBluetoothDevice device; + final Profile profile; // HEADSET, A2DP, etc + // 0 means this command was not been sent to the bt framework. + long timeSent; + + public BluetoothJob(BluetoothCommand command, + LocalBluetoothDevice device, Profile profile) { + this.command = command; + this.device = device; + this.profile = profile; + this.timeSent = 0; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append(command.name()); + sb.append(" Address:").append(device.mAddress); + sb.append(" Profile:").append(profile.name()); + sb.append(" TimeSent:"); + if (timeSent == 0) { + sb.append("not yet"); + } else { + sb.append(DateFormat.getTimeInstance().format(new Date(timeSent))); + } + return sb.toString(); + } + } + + /** + * We want to serialize connect and disconnect calls. http://b/170538 + * This are some headsets that may have L2CAP resource limitation. We want + * to limit the bt bandwidth usage. + * + * A queue to keep track of asynchronous calls to the bt framework. The + * first item, if exist, should be in progress i.e. went to the bt framework + * already, waiting for a notification to come back. The second item and + * beyond have not been sent to the bt framework yet. + */ + private static LinkedList workQueue = new LinkedList(); + + private void queueCommand(BluetoothJob job) { + Log.d(TAG, workQueue.toString()); + synchronized (workQueue) { + boolean processNow = false; + long now = System.currentTimeMillis(); + + Iterator it = workQueue.iterator(); + while (it.hasNext()) { + BluetoothJob existingJob = it.next(); + + // Remove any pending CONNECTS when we receive a DISCONNECT + if (job.command == BluetoothCommand.DISCONNECT) { + if (existingJob.timeSent == 0 + && existingJob.command == BluetoothCommand.CONNECT + && existingJob.device.mAddress.equals(job.device.mAddress) + && existingJob.profile == job.profile) { + it.remove(); + continue; + } + } + + // Defensive Code: Remove any job that older than a preset time. + // We never got a call back. It is better to have overlapping + // calls than to get stuck. + Log.d(TAG, "Age:" + (now - existingJob.timeSent)); + if (existingJob.timeSent != 0 + && (now - existingJob.timeSent) >= MAX_WAIT_TIME_FOR_FRAMEWORK) { + Log.w(TAG, "Timeout. Removing Job:" + existingJob.toString()); + it.remove(); + processNow = true; + continue; + } + } + + // Add job to queue + Log.d(TAG, "Adding: " + job.toString()); + workQueue.add(job); + + // if there's nothing pending from before, send the command to bt + // framework immediately. + if (workQueue.size() == 1 || processNow) { + Log.d(TAG, "workQueue.size() == 1 || TimeOut -> process command now"); + // If the failed to process, just drop it from the queue. + // There will be no callback to remove this from the queue. + processCommands(); + } + } + } + + private boolean processCommand(BluetoothJob job) { + boolean successful = false; + if (job.timeSent == 0) { + job.timeSent = System.currentTimeMillis(); + switch (job.command) { + case CONNECT: + successful = connectInt(job.device, job.profile); + break; + case DISCONNECT: + successful = disconnectInt(job.device, job.profile); + break; + } + + if (successful) { + Log.d(TAG, "Command sent successfully:" + job.toString()); + } else { + Log.d(TAG, "Framework rejected command immediately:" + job.toString()); + } + + } else { + Log.d(TAG, "Job already has a sent time. Skip. " + job.toString()); + } + + return successful; + } + + public void onProfileStateChanged() { + // Remove the first item and process the next one + BluetoothJob job = workQueue.poll(); + if (job == null) { + Log.w(TAG, "Yikes, onProfileStateChanged called but job queue is empty"); + } else if (job.device.mAddress != mAddress) { + Log.w(TAG, "Yikes, onProfileStateChanged called but the address differ. this.mAddress=" + + mAddress + " workQueue.head=" + job.toString()); + } else { + Log.d(TAG, "LocalBluetoothDevice.onProfileStateChanged() called. MAC addr matched"); + } + + processCommands(); + } + + /* + * This method is called in 2 places: + * 1) queryCommand() - when someone or something want to connect or + * disconnect + * 2) onProfileStateChanged() - when the framework sends an intent + * notification when it finishes processing a command + */ + private void processCommands() { + Iterator it = workQueue.iterator(); + while (it.hasNext()) { + BluetoothJob job = it.next(); + if (processCommand(job)) { + // Sent to bt framework. Done for now. Will remove this job + // from queue when we get an event + return; + } else { + /* + * If the command failed immediately, there will be no event + * callbacks. So delete the job immediately and move on to the + * next one + */ + it.remove(); + } + } + } + LocalBluetoothDevice(Context context, String address) { mLocalManager = LocalBluetoothManager.getInstance(context); if (mLocalManager == null) { @@ -102,12 +270,19 @@ public class LocalBluetoothDevice implements Comparable { } public void disconnect(Profile profile) { + queueCommand(new BluetoothJob(BluetoothCommand.DISCONNECT, this, profile)); + } + + private boolean disconnectInt(LocalBluetoothDevice device, Profile profile) { LocalBluetoothProfileManager profileManager = LocalBluetoothProfileManager.getProfileManager(mLocalManager, profile); - int status = profileManager.getConnectionStatus(mAddress); + int status = profileManager.getConnectionStatus(device.mAddress); if (SettingsBtStatus.isConnectionStatusConnected(status)) { - profileManager.disconnect(mAddress); + if (profileManager.disconnect(device.mAddress) == BluetoothDevice.RESULT_SUCCESS) { + return true; + } } + return false; } public void askDisconnect() { @@ -153,7 +328,7 @@ public class LocalBluetoothDevice implements Comparable { LocalBluetoothProfileManager.getProfileManager(mLocalManager, profile); if (profileManager.isPreferred(mAddress)) { hasAtLeastOnePreferredProfile = true; - connectInt(profile); + queueCommand(new BluetoothJob(BluetoothCommand.CONNECT, this, profile)); } } @@ -173,27 +348,30 @@ public class LocalBluetoothDevice implements Comparable { LocalBluetoothProfileManager profileManager = LocalBluetoothProfileManager.getProfileManager(mLocalManager, profile); profileManager.setPreferred(mAddress, true); - connectInt(profile); + queueCommand(new BluetoothJob(BluetoothCommand.CONNECT, this, profile)); } } public void connect(Profile profile) { // Reset the only-show-one-error-dialog tracking variable mIsConnectingErrorPossible = true; - connectInt(profile); + queueCommand(new BluetoothJob(BluetoothCommand.CONNECT, this, profile)); } - public void connectInt(Profile profile) { - if (!ensurePaired()) return; + private boolean connectInt(LocalBluetoothDevice device, Profile profile) { + if (!device.ensurePaired()) return false; LocalBluetoothProfileManager profileManager = LocalBluetoothProfileManager.getProfileManager(mLocalManager, profile); - int status = profileManager.getConnectionStatus(mAddress); + int status = profileManager.getConnectionStatus(device.mAddress); if (!SettingsBtStatus.isConnectionStatusConnected(status)) { - if (profileManager.connect(mAddress) != BluetoothDevice.RESULT_SUCCESS) { - Log.i(TAG, "Failed to connect " + profile.toString() + " to " + mName); + if (profileManager.connect(device.mAddress) == BluetoothDevice.RESULT_SUCCESS) { + return true; } + Log.i(TAG, "Failed to connect " + profile.toString() + " to " + device.mName); } + Log.i(TAG, "Not connected"); + return false; } public void showConnectingError() { @@ -228,6 +406,24 @@ public class LocalBluetoothDevice implements Comparable { } public void unpair() { + synchronized (workQueue) { + // Remove any pending commands for this device + boolean processNow = false; + Iterator it = workQueue.iterator(); + while (it.hasNext()) { + BluetoothJob job = it.next(); + if (job.device.mAddress.equals(this.mAddress)) { + it.remove(); + if (job.timeSent != 0) { + processNow = true; + } + } + } + if (processNow) { + processCommands(); + } + } + BluetoothDevice manager = mLocalManager.getBluetoothManager(); switch (getBondState()) { diff --git a/src/com/android/settings/bluetooth/LocalBluetoothDeviceManager.java b/src/com/android/settings/bluetooth/LocalBluetoothDeviceManager.java index 6bb2b4afe16..9527980b5a5 100644 --- a/src/com/android/settings/bluetooth/LocalBluetoothDeviceManager.java +++ b/src/com/android/settings/bluetooth/LocalBluetoothDeviceManager.java @@ -16,11 +16,8 @@ package com.android.settings.bluetooth; -import android.app.AlertDialog; import android.bluetooth.BluetoothDevice; import android.util.Log; -import android.widget.Toast; -import android.content.Context; import com.android.settings.R; import com.android.settings.bluetooth.LocalBluetoothManager.Callback; @@ -190,10 +187,13 @@ public class LocalBluetoothDeviceManager { R.string.bluetooth_pairing_error_message); } - public synchronized void onProfileStateChanged(String address) { + public synchronized void onProfileStateChanged(String address, boolean transientState) { LocalBluetoothDevice device = findDevice(address); if (device == null) return; + if (!transientState) { + device.onProfileStateChanged(); + } device.refresh(); } diff --git a/src/com/android/settings/bluetooth/LocalBluetoothManager.java b/src/com/android/settings/bluetooth/LocalBluetoothManager.java index 4671fac6e8e..1a848b2d066 100644 --- a/src/com/android/settings/bluetooth/LocalBluetoothManager.java +++ b/src/com/android/settings/bluetooth/LocalBluetoothManager.java @@ -25,6 +25,8 @@ import android.app.Activity; import android.app.AlertDialog; import android.bluetooth.BluetoothA2dp; import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothError; +import android.bluetooth.BluetoothIntent; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; @@ -40,8 +42,6 @@ public class LocalBluetoothManager { private static final String TAG = "LocalBluetoothManager"; static final boolean V = true; - public static final String EXTENDED_BLUETOOTH_STATE_CHANGED_ACTION = - "com.android.settings.bluetooth.intent.action.EXTENDED_BLUETOOTH_STATE_CHANGED"; private static final String SHARED_PREFERENCES_NAME = "bluetooth_settings"; private static LocalBluetoothManager INSTANCE; @@ -60,8 +60,7 @@ public class LocalBluetoothManager { private BluetoothEventRedirector mEventRedirector; private BluetoothA2dp mBluetoothA2dp; - public static enum ExtendedBluetoothState { ENABLED, ENABLING, DISABLED, DISABLING, UNKNOWN } - private ExtendedBluetoothState mState = ExtendedBluetoothState.UNKNOWN; + private int mState = BluetoothError.ERROR; private List mCallbacks = new ArrayList(); @@ -182,34 +181,27 @@ public class LocalBluetoothManager { } } - public ExtendedBluetoothState getBluetoothState() { + public int getBluetoothState() { - if (mState == ExtendedBluetoothState.UNKNOWN) { + if (mState == BluetoothError.ERROR) { syncBluetoothState(); } return mState; } - void setBluetoothStateInt(ExtendedBluetoothState state) { + void setBluetoothStateInt(int state) { mState = state; - - /* - * TODO: change to callback method. originally it was broadcast to - * parallel the framework's method, but it just complicates things here. - */ - // If this were a real API, I'd add as an extra - mContext.sendBroadcast(new Intent(EXTENDED_BLUETOOTH_STATE_CHANGED_ACTION)); - - if (state == ExtendedBluetoothState.ENABLED || state == ExtendedBluetoothState.DISABLED) { - mLocalDeviceManager.onBluetoothStateChanged(state == ExtendedBluetoothState.ENABLED); + if (state == BluetoothDevice.BLUETOOTH_STATE_ON || + state == BluetoothDevice.BLUETOOTH_STATE_OFF) { + mLocalDeviceManager.onBluetoothStateChanged(state == BluetoothDevice.BLUETOOTH_STATE_ON); } } private void syncBluetoothState() { setBluetoothStateInt(mManager.isEnabled() - ? ExtendedBluetoothState.ENABLED - : ExtendedBluetoothState.DISABLED); + ? BluetoothDevice.BLUETOOTH_STATE_ON + : BluetoothDevice.BLUETOOTH_STATE_OFF); } public void setBluetoothEnabled(boolean enabled) { @@ -219,8 +211,8 @@ public class LocalBluetoothManager { if (wasSetStateSuccessful) { setBluetoothStateInt(enabled - ? ExtendedBluetoothState.ENABLING - : ExtendedBluetoothState.DISABLING); + ? BluetoothDevice.BLUETOOTH_STATE_TURNING_ON + : BluetoothDevice.BLUETOOTH_STATE_TURNING_OFF); } else { if (V) { Log.v(TAG, diff --git a/src/com/android/settings/bluetooth/LocalBluetoothProfileManager.java b/src/com/android/settings/bluetooth/LocalBluetoothProfileManager.java index 50edf86f4f9..24563a767ef 100644 --- a/src/com/android/settings/bluetooth/LocalBluetoothProfileManager.java +++ b/src/com/android/settings/bluetooth/LocalBluetoothProfileManager.java @@ -72,19 +72,22 @@ public abstract class LocalBluetoothProfileManager { /** * Temporary method to fill profiles based on a device's class. * + * NOTE: This list happens to define the connection order. We should put this logic in a more + * well known place when this method is no longer temporary. + * * @param btClass The class * @param profiles The list of profiles to fill */ public static void fill(int btClass, List profiles) { profiles.clear(); - if (BluetoothA2dp.doesClassMatchSink(btClass)) { - profiles.add(Profile.A2DP); - } - if (BluetoothHeadset.doesClassMatch(btClass)) { profiles.add(Profile.HEADSET); } + + if (BluetoothA2dp.doesClassMatchSink(btClass)) { + profiles.add(Profile.A2DP); + } } protected LocalBluetoothProfileManager(LocalBluetoothManager localManager) { @@ -214,7 +217,7 @@ public abstract class LocalBluetoothProfileManager { */ String address = mService.getHeadsetAddress(); if (TextUtils.isEmpty(address)) return; - mLocalManager.getLocalDeviceManager().onProfileStateChanged(address); + mLocalManager.getLocalDeviceManager().onProfileStateChanged(address, true); } }); }