Commit 57f55b3c authored by The Android Open Source Project's avatar The Android Open Source Project
Browse files

Initial Contribution

parents
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := user development
LOCAL_SRC_FILES := $(call all-subdir-java-files)
LOCAL_PACKAGE_NAME := DownloadProvider
LOCAL_CERTIFICATE := media
include $(BUILD_PACKAGE)
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.providers.downloads"
android:sharedUserId="android.media">
<!-- Allows access to the Download Manager -->
<permission android:name="android.permission.ACCESS_DOWNLOAD_MANAGER"
android:label="@string/permlab_downloadManager"
android:description="@string/permdesc_downloadManager"
android:protectionLevel="signatureOrSystem" />
<!-- Allows access to the Download Manager data (for UI purposes) -->
<permission android:name="android.permission.ACCESS_DOWNLOAD_DATA"
android:label="@string/permlab_downloadData"
android:description="@string/permdesc_downloadData"
android:protectionLevel="signature" />
<!-- Allows filesystem access to /cache -->
<permission android:name="android.permission.ACCESS_CACHE_FILESYSTEM"
android:label="@string/permlab_cacheFilesystem"
android:description="@string/permdesc_cacheFilesystem"
android:protectionLevel="signature" />
<!-- Allow to download to /cache/update.install -->
<permission android:name="android.permission.DOWNLOAD_OTA_UPDATE"
android:label="@string/permlab_downloadOtaUpdate"
android:description="@string/permdesc_downloadOtaUpdate"
android:protectionLevel="signature" />
<!-- Allows to send download completed intents -->
<permission android:name="android.permission.SEND_DOWNLOAD_COMPLETED_INTENTS"
android:label="@string/permlab_downloadCompletedIntent"
android:description="@string/permdesc_downloadCompletedIntent"
android:protectionLevel="signature" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.ACCESS_DOWNLOAD_MANAGER" />
<uses-permission android:name="android.permission.ACCESS_DRM" />
<uses-permission android:name="android.permission.ACCESS_CACHE_FILESYSTEM" />
<uses-permission android:name="android.permission.SEND_DOWNLOAD_COMPLETED_INTENTS" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_DOWNLOAD_DATA" />
<application android:process="android.process.media"
android:label="Download Manager">
<provider android:name=".DownloadProvider"
android:authorities="downloads"
android:permission="android.permission.ACCESS_DOWNLOAD_MANAGER" />
<service android:name=".DownloadService"
android:permission="android.permission.ACCESS_DOWNLOAD_MANAGER" />
<receiver android:name=".DownloadReceiver" android:exported="false">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
</intent-filter>
</receiver>
</application>
</manifest>
Copyright (c) 2005-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.
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.
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
<?xml version="1.0" encoding="utf-8"?>
<!--
/*
** Copyright 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.
*/
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
android:background="@android:drawable/status_bar_item_app_background"
>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="horizontal"
>
<LinearLayout android:id="@+id/app"
android:layout_width="40dp"
android:layout_height="fill_parent"
android:orientation="vertical"
android:paddingTop="8dp"
android:focusable="true"
android:clickable="true"
>
<com.android.server.status.AnimatedImageView
android:id="@+id/appIcon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:src="@android:drawable/sym_def_app_icon"
/>
<TextView android:id="@+id/progress_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#ff000000"
android:singleLine="true"
android:textSize="14sp"
android:layout_gravity="center_horizontal"
/>
</LinearLayout>
<RelativeLayout android:id="@+id/app"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
android:focusable="true"
android:clickable="true"
>
<LinearLayout android:id="@+id/notification"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:focusable="true"
android:clickable="true"
android:layout_alignParentTop="true"
android:paddingTop="10dp"
>
<TextView android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:singleLine="true"
android:textSize="18sp"
android:textColor="#ff000000"
android:paddingLeft="2dp"
/>
<TextView android:id="@+id/description"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#ff000000"
android:singleLine="true"
android:textSize="14sp"
android:paddingLeft="5dp"
/>
</LinearLayout>
<ProgressBar android:id="@+id/progress_bar"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:paddingBottom="8dp"
android:paddingRight="25dp"
/>
</RelativeLayout>
</LinearLayout>
<com.android.server.status.AnimatedImageView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:src="@android:drawable/divider_horizontal_bright"
/>
</LinearLayout>
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="download_pending">Herunterladen wird gestartet\u2026</string>
<string name="download_pending_network">Warten auf Netzwerk\u2026</string>
<string name="download_running">Herunterladen läuft </string>
<string name="download_running_paused">Warten auf Netzwerk\u2026 </string>
<string name="download_unknown_title">&lt;ohne Titel&gt;</string>
<string name="notification_download_complete">Herunterladen abgeschlossen</string>
<string name="notification_download_failed">Herunterladen nicht erfolgreich</string>
<string name="notification_filename_extras">" und %d mehr"</string>
<string name="notification_filename_separator">", "</string>
<string name="permdesc_cacheFilesystem">Ermöglicht einer Anwendung
direkt auf den System-Cache-Speicher zuzugreifen und ihn zu ändern und zu löschen. Schädliche
Anwendungen können dies nutzen, um Herunterladen und
andere Anwendungen ernsthaft zu stören und auf private Daten zuzugreifen.</string>
<string name="permdesc_downloadCompletedIntent">Ermöglicht einer Anwendung
Benachrichtigungen über abgeschlossenes Herunterladen zu senden. Schädliche Anwendungen können dies nutzen,
um andere Anwendungen zu stören,
die Dateien herunterladen.</string>
<string name="permdesc_downloadData">Ermöglicht einer Anwendung
auf Informationen über alles Herunterladen im Download-Manager zuzugreifen.
Schädliche Anwendungen können dies nutzen, um Herunterladen ernsthaft zu stören
und auf private Daten zuzugreifen.</string>
<string name="permdesc_downloadManager">Ermöglicht einer Anwendung
auf den Download-Manager zuzugreifen und ihn zum Herunterladen von Dateien zu verwenden.
Schädliche Anwendungen können dies nutzen, um Herunterladen zu stören und auf
private Daten zuzugreifen.</string>
<string name="permdesc_downloadOtaUpdate">Ermöglicht einer Anwendung
festzulegen, dass sie Dateien in den internen
Cache-Speicher mit dem Dateinamen herunterlädt, der für OTA-Updates reserviert ist.
Schädliche Anwendungen können dies nutzen, um das Herunterladen von OTA-Updates
zu verhindern.</string>
<string name="permlab_cacheFilesystem">Systemcache verwenden.</string>
<string name="permlab_downloadCompletedIntent">Herunterladen-Benachrichtigungen
senden.</string>
<string name="permlab_downloadData">Auf heruntergeladene Daten zugreifen.</string>
<string name="permlab_downloadManager">Auf Download-Manager zugreifen.</string>
<string name="permlab_downloadOtaUpdate">OTA-Update herunterladen.</string>
</resources>
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="download_pending">Starting download\u2026</string>
<string name="download_pending_network">Waiting for network\u2026</string>
<string name="download_running">Downloading </string>
<string name="download_running_paused">Waiting for network\u2026 </string>
<string name="download_unknown_title">&lt;Untitled&gt;</string>
<string name="notification_download_complete">Download complete</string>
<string name="notification_download_failed">Download unsuccessful</string>
<string name="notification_filename_extras">" and %d more"</string>
<string name="notification_filename_separator">", "</string>
<string name="permdesc_cacheFilesystem">Allows the application
to directly access, modify and delete the system cache. Malicious
applications can use this to severely disrupt downloads and
other applications, and to access private data.</string>
<string name="permdesc_downloadCompletedIntent">Allows the application
to send notifications about completed downloads. Malicious applications
can use this to confuse other applications that download
files.</string>
<string name="permdesc_downloadData">Allows the application to
access information about all downloads in the download manager.
Malicious applications can use this to severely disrupt downloads
and access private information.</string>
<string name="permdesc_downloadManager">Allows the application to
access the download manager and to use it to download files.
Malicious applications can use this to disrupt downloads and access
private information.</string>
<string name="permdesc_downloadOtaUpdate">Allows the application
to specify that it wants to download files in the internal
cache with the filename that is reserved for OTA updates.
Malicious applications can use this to prevent OTA updates from
getting downloaded.</string>
<string name="permlab_cacheFilesystem">Use system cache.</string>
<string name="permlab_downloadCompletedIntent">Send download
notifications.</string>
<string name="permlab_downloadData">Access download data.</string>
<string name="permlab_downloadManager">Access download manager.</string>
<string name="permlab_downloadOtaUpdate">Download OTA update.</string>
</resources>
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="download_pending">Iniciando descarga\u2026</string>
<string name="download_pending_network">Esperando red\u2026</string>
<string name="download_running">Descargando </string>
<string name="download_running_paused">Esperando red\u2026 </string>
<string name="download_unknown_title">&lt;Sin título&gt;</string>
<string name="notification_download_complete">Descarga completa</string>
<string name="notification_download_failed">Error en la descarga</string>
<string name="notification_filename_extras">" y %d más"</string>
<string name="notification_filename_separator">", "</string>
<string name="permdesc_cacheFilesystem">Permite a la aplicación
acceder directamente, modificar y eliminar la caché del sistema. Las aplicaciones
maliciosas pueden utilizar esta función para dañar las descargas y
otras aplicaciones, o para acceder a datos privados.</string>
<string name="permdesc_downloadCompletedIntent">Permite a la aplicación
enviar notificaciones sobre las descargas realizadas. Las aplicaciones maliciosas
pueden utilizar esta función para confundir a otras aplicaciones que descargan
archivos.</string>
<string name="permdesc_downloadData">Permite a la aplicación
acceder a información sobre todas las descargas en el administrador de descargas.
Las aplicaciones maliciosas pueden utilizar esta función para alterar gravemente las descargas
y acceder a información privada.</string>
<string name="permdesc_downloadManager">Permite a la aplicación
acceder al administrador de descargas y utilizarlo para descargar archivos.
Las aplicaciones maliciosas pueden utilizar esta función para alterar las descargas y acceder
a información privada.</string>
<string name="permdesc_downloadOtaUpdate">Permite a la aplicación
especificar que desea descargar archivos en la caché
interna con el nombre de archivo reservado para las actualizaciones OTA.
Las aplicaciones maliciosas puede utilizar esta función para evitar que las actualizaciones OTA
se descarguen.</string>
<string name="permlab_cacheFilesystem">Uso de la caché del sistema.</string>
<string name="permlab_downloadCompletedIntent">Enviar notificaciones de
descarga.</string>
<string name="permlab_downloadData">Acceso a datos de descarga. </string>
<string name="permlab_downloadManager">Acceso al administrador de descargas. </string>
<string name="permlab_downloadOtaUpdate">Descargar actualización de OTA.</string>
</resources>
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="download_pending">Début du téléchargement\u2026</string>
<string name="download_pending_network">Attente du réseau\u2026</string>
<string name="download_running">Téléchargement en cours </string>
<string name="download_running_paused">Attente du réseau\u2026 </string>
<string name="download_unknown_title">&lt;Sans titre&gt;</string>
<string name="notification_download_complete">Téléchargement terminé</string>
<string name="notification_download_failed">Échec du téléchargement</string>
<string name="notification_filename_extras">" et %d en plus"</string>
<string name="notification_filename_separator">", "</string>
<string name="permdesc_cacheFilesystem">Permet à l\'application
de directement accéder, modifier et supprimer la cache système.
Les applications malicieuses peuvent utiliser cela pour désorganiser
sérieusement les téléchargements et les autres applications, et pour accéder aux données privées.</string>
<string name="permdesc_downloadCompletedIntent">Permet à l\'application
d\'envoyer des notifications sur les téléchargements terminés. Les applications
malicieuses peuvent utiliser cela pour tromper les autres
applications qui téléchargent des fichiers.</string>
<string name="permdesc_downloadData">Permet à l\'application
d\'accéder aux informations de téléchargement dans le gestionnaire de
téléchargements. Les applications malicieuses peuvent utiliser cela
pour désorganiser sérieusement les téléchargements et accéder aux informations privées.</string>
<string name="permdesc_downloadManager">Permet à l\'application
d\'accéder au gestionnaire de téléchargements et de l\'utiliser pour.
télécharger les fichiers. Les applications malicieuses peuvent utiliser cela
pour désorganiser les téléchargements et accéder aux informations privées.</string>
<string name="permdesc_downloadOtaUpdate">Permet à l\'application
de spécifier qu\'elle veut télécharger des fichiers dans la
cache interne avec le nom de fichier réservé aux mises à
jour OTA. Les applications malicieuses peuvent utiliser cela pour
empêcher aux mises à jour OTA d\'être téléchargées.</string>
<string name="permlab_cacheFilesystem">Utilisez la cache système.</string>
<string name="permlab_downloadCompletedIntent">Envoyez les notifications
de téléchargement.</string>
<string name="permlab_downloadData">Accédez aux données de téléchargement.</string>
<string name="permlab_downloadManager">Accédez au gestionnaire de téléchargement.</string>
<string name="permlab_downloadOtaUpdate">Téléchargez la mise à jour OTA.</string>
</resources>
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="download_pending">Avvio del download in corso\u2026</string>
<string name="download_pending_network">In attesa della rete\u2026</string>
<string name="download_running">Download in corso </string>
<string name="download_running_paused">In attesa della rete\u2026 </string>
<string name="download_unknown_title">&lt;Senza titolo&gt;</string>
<string name="notification_download_complete">Download completato</string>
<string name="notification_download_failed">Download non riuscito</string>
<string name="notification_filename_extras">" e ulteriore %d"</string>
<string name="notification_filename_separator">", "</string>
<string name="permdesc_cacheFilesystem">Consente all'applicazione di
accedere direttamente, modificare ed eliminare la cache del sistema. Le applicazioni
dannose possono utilizzare questa autorizzazione per interrompere i download e le altre applicazioni
e accedere ai dati privati.</string>
<string name="permdesc_downloadCompletedIntent">Consente all'applicazione
di inviare le notifiche sui download completati. Le applicazioni nocive
possono utilizzare questa autorizzazione per confondere le applicazioni che scaricano i
file.</string>
<string name="permdesc_downloadData">Consente all'applicazione di
accedere alle informazioni sui download nel gestore download.
Le applicazioni nocive possono utilizzare questa autorizzazione per interrompere i download
e accedere alle informazioni private.</string>
<string name="permdesc_downloadManager">Consente all'applicazione di
accedere al gestore download e utilizzarlo per scaricare i file.
Le applicazioni dannose possono utilizzare questa autorizzazione per interrompere i download e accedere alle
informazioni private.</string>
<string name="permdesc_downloadOtaUpdate">Consente all'applicazione
di specificare che desidera scaricare i file nella cache interna
con il nome file riservato agli aggiornamenti OTA.
Le applicazioni nocive possono utilizzare questa autorizzazione per impedire lo scaricamento di aggiornamenti
OTA.</string>
<string name="permlab_cacheFilesystem">Utilizzare la cache del sistema.</string>
<string name="permlab_downloadCompletedIntent">Inviare le notifiche sul
download.</string>
<string name="permlab_downloadData">Accedere ai dati del download.</string>
<string name="permlab_downloadManager">Accedere al gestore download.</string>
<string name="permlab_downloadOtaUpdate">Scaricare l'aggiornamento OTA.</string>
</resources>
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="download_pending">正在開始下載\u2026</string>
<string name="download_pending_network">正在等待網路\u2026</string>
<string name="download_running">正在下載 </string>
<string name="download_running_paused">正在等待網路\u2026 </string>
<string name="download_unknown_title">&lt;未命名&gt;</string>
<string name="notification_download_complete">下載完成</string>
<string name="notification_download_failed">下載失敗</string>
<string name="notification_filename_extras">" 還有 %d"</string>
<string name="notification_filename_separator">", "</string>
<string name="permdesc_cacheFilesystem">允許應用程式
直接存取、修改及刪除系統快取。惡意的
應用程式可能會利用此方式嚴重干擾下載和
其它應用程式,及存取私人資料。</string>
<string name="permdesc_downloadCompletedIntent">允許應用程式
傳送完成下載的通知。惡意的應用程式
可能會利用此方式混淆下載
檔案的其它應用程式。</string>
<string name="permdesc_downloadData">允許應用程式
存取下載管理員中所有下載的存取資訊。
惡意的應用程式可能會利用此方式嚴重干擾下載,
及存取私人資訊。</string>
<string name="permdesc_downloadManager">允許應用程式
存取下載管理員並使用其下載檔案。
惡意的應用程式可能會利用此方式來干擾下載,及存取
私人資訊。</string>
<string name="permdesc_downloadOtaUpdate">允許應用程式
指定其想要下載內部快取中含有 OTA
更新專用之檔名的檔案。
惡意的應用程式可能會利用此方式來阻止
下載 OTA 更新。</string>
<string name="permlab_cacheFilesystem">使用系統快取。</string>
<string name="permlab_downloadCompletedIntent">傳送下載
通知。</string>
<string name="permlab_downloadData">存取下載資料。</string>
<string name="permlab_downloadManager">存取下載管理員。</string>
<string name="permlab_downloadOtaUpdate">下載 OTA 更新。</string>
</resources>
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2007 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.
-->
<resources>
<!-- Used beneath the progress bar to indicate content downloaded -->
<string name="download_running">Downloading </string>
<!-- Used beneath the progress bar to indicate download about to start -->
<string name="download_pending">Starting download\u2026</string>
<!-- Used beneath the progress bar to indicate download has not started yet and is waiting for network -->
<string name="download_pending_network">Waiting for network\u2026</string>
<!-- Used beneath the progress bar to indicate download has started but is paused and is waiting for network -->
<string name="download_running_paused">Waiting for network\u2026 </string>
<!-- Title to show when the UI doesn't yet know the content that is being downloaded -->
<string name="download_unknown_title">&lt;Untitled&gt;</string>
<string name="permlab_downloadManager">Access download manager.</string>
<string name="permdesc_downloadManager">Allows the application to
access the download manager and to use it to download files.
Malicious applications can use this to disrupt downloads and access
private information.</string>
<string name="permlab_downloadData">Access download data.</string>
<string name="permdesc_downloadData">Allows the application to
access information about all downloads in the download manager.
Malicious applications can use this to severely disrupt downloads
and access private information.</string>
<string name="permlab_cacheFilesystem">Use system cache.</string>
<string name="permdesc_cacheFilesystem">Allows the application
to directly access, modify and delete the system cache. Malicious
applications can use this to severely disrupt downloads and
other applications, and to access private data.</string>
<string name="permlab_downloadOtaUpdate">Download OTA update.</string>
<string name="permdesc_downloadOtaUpdate">Allows the application
to specify that it wants to download files in the internal
cache with the filename that is reserved for OTA updates.
Malicious applications can use this to prevent OTA updates from
getting downloaded.</string>
<string name="permlab_downloadCompletedIntent">Send download
notifications.</string>
<string name="permdesc_downloadCompletedIntent">Allows the application
to send notifications about completed downloads. Malicious applications
can use this to confuse other applications that download
files.</string>
<!-- used to separate filenames in the download notifications -->
<string name="notification_filename_separator">", "</string>
<!-- used to list that there are more than 2 files in a notification -->
<string name="notification_filename_extras">" and %d more"</string>
<!-- information line shown in the notifications for completed downloads -->
<string name="notification_download_complete">Download complete</string>
<!-- information line shown in the notifications for failed downloads -->
<string name="notification_download_failed">Download unsuccessful</string>
</resources>
/*
* 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.providers.downloads;
import android.util.Config;
import android.util.Log;
/**
* Contains the internal constants that are used in the download manager.
* As a general rule, modifying these constants should be done with care.
*/
public class Constants {
/** Tag used for debugging/logging */
public static final String TAG = "DownloadManager";
/** The permission that allows to access data about all downloads */
public static final String UI_PERMISSION = "android.permission.ACCESS_DOWNLOAD_DATA";
/** The permission that allows to download a system image */
public static final String OTA_UPDATE_PERMISSION = "android.permission.DOWNLOAD_OTA_UPDATE";
/** The intent that gets sent when the service must wake up for a retry */
public static final String ACTION_RETRY = "android.intent.action.DOWNLOAD_WAKEUP";
/** the intent that gets sent when clicking a successful download */
public static final String ACTION_OPEN = "android.intent.action.DOWNLOAD_OPEN";
/** the intent that gets sent when clicking an incomplete/failed download */
public static final String ACTION_LIST = "android.intent.action.DOWNLOAD_LIST";
/** the intent that gets sent when deleting the notification of a completed download */
public static final String ACTION_HIDE = "android.intent.action.DOWNLOAD_HIDE";
/** The default base name for downloaded files if we can't get one at the HTTP level */
public static final String DEFAULT_DL_FILENAME = "downloadfile";
/** The default extension for html files if we can't get one at the HTTP level */
public static final String DEFAULT_DL_HTML_EXTENSION = ".html";
/** The default extension for text files if we can't get one at the HTTP level */
public static final String DEFAULT_DL_TEXT_EXTENSION = ".txt";
/** The default extension for binary files if we can't get one at the HTTP level */
public static final String DEFAULT_DL_BINARY_EXTENSION = ".bin";
/**
* When a number has to be appended to the filename, this string is used to separate the
* base filename from the sequence number
*/
public static final String FILENAME_SEQUENCE_SEPARATOR = "-";
/** Where we store downloaded files on the external storage */
public static final String DEFAULT_DL_SUBDIR = "/download";
/** A magic filename that is allowed to exist within the system cache */
public static final String KNOWN_SPURIOUS_FILENAME = "lost+found";
/** A magic filename that is allowed to exist within the system cache */
public static final String RECOVERY_DIRECTORY = "recovery";
/** The magic filename for OTA updates */
public static final String OTA_UPDATE_FILENAME = "update.install";
/** The default user agent used for downloads */
public static final String DEFAULT_USER_AGENT = "AndroidDownloadManager";
/** The MIME type of special DRM files */
public static final String MIMETYPE_DRM_MESSAGE =
android.drm.mobile1.DrmRawContent.DRM_MIMETYPE_MESSAGE_STRING;
/** The MIME type of APKs */
public static final String MIMETYPE_APK = "application/vnd.android.package";
/** The buffer size used to stream the data */
public static final int BUFFER_SIZE = 4096;
/** The minimum amount of progress that has to be done before the progress bar gets updated */
public static final int MIN_PROGRESS_STEP = 4096;
/** The minimum amount of time that has to elapse before the progress bar gets updated, in ms */
public static final long MIN_PROGRESS_TIME = 1500;
/** The maximum number of rows in the database (FIFO) */
public static final int MAX_DOWNLOADS = 1000;
/**
* The number of times that the download manager will retry its network
* operations when no progress is happening before it gives up.
*/
public static final int MAX_RETRIES = 5;
/**
* The time between a failure and the first retry after an IOException.
* Each subsequent retry grows exponentially, doubling each time.
* The time is in seconds.
*/
public static final int RETRY_FIRST_DELAY = 30;
/** Enable verbose logging - use with "setprop log.tag.DownloadManager VERBOSE" */
private static final boolean LOCAL_LOGV = false;
public static final boolean LOGV = Config.LOGV
|| (Config.LOGD && LOCAL_LOGV && Log.isLoggable(TAG, Log.VERBOSE));
/** Enable super-verbose logging */
private static final boolean LOCAL_LOGVV = false;
public static final boolean LOGVV = LOCAL_LOGVV && LOGV;
}
/*
* 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.providers.downloads;
import java.io.FileOutputStream;
/**
* Stores information about the file in which a download gets saved.
*/
public class DownloadFileInfo {
public DownloadFileInfo(String filename, FileOutputStream stream, int status) {
this.filename = filename;
this.stream = stream;
this.status = status;
}
String filename;
FileOutputStream stream;
int status;
}
/*
* 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.providers.downloads;
import android.net.Uri;
import android.content.Context;
import android.content.Intent;
import android.provider.Downloads;
/**
* Stores information about an individual download.
*/
public class DownloadInfo {
public int id;
public String uri;
public int method;
public String entity;
public boolean noIntegrity;
public String hint;
public String filename;
public boolean otaUpdate;
public String mimetype;
public int destination;
public boolean noSystem;
public int visibility;
public int control;
public int status;
public int numFailed;
public long lastMod;
public String pckg;
public String clazz;
public String extras;
public String cookies;
public String userAgent;
public String referer;
public int totalBytes;
public int currentBytes;
public String etag;
public boolean mediaScanned;
public volatile boolean hasActiveThread;
public DownloadInfo(int id, String uri, int method, String entity, boolean noIntegrity,
String hint, String filename, boolean otaUpdate,
String mimetype, int destination, boolean noSystem, int visibility,
int control, int status, int numFailed, long lastMod,
String pckg, String clazz, String extras, String cookies,
String userAgent, String referer, int totalBytes, int currentBytes, String etag,
boolean mediaScanned) {
this.id = id;
this.uri = uri;
this.method = method;
this.entity = entity;
this.noIntegrity = noIntegrity;
this.hint = hint;
this.filename = filename;
this.otaUpdate = otaUpdate;
this.mimetype = mimetype;
this.destination = destination;
this.noSystem = noSystem;
this.visibility = visibility;
this.control = control;
this.status = status;
this.numFailed = numFailed;
this.lastMod = lastMod;
this.pckg = pckg;
this.clazz = clazz;
this.extras = extras;
this.cookies = cookies;
this.userAgent = userAgent;
this.referer = referer;
this.totalBytes = totalBytes;
this.currentBytes = currentBytes;
this.etag = etag;
this.mediaScanned = mediaScanned;
}
public void sendIntentIfRequested(Uri contentUri, Context context) {
if (pckg != null && clazz != null) {
Intent intent = new Intent(Downloads.DOWNLOAD_COMPLETED_ACTION);
intent.setClassName(pckg, clazz);
if (extras != null) {
intent.putExtra(Downloads.NOTIFICATION_EXTRAS, extras);
}
// We only send the content: URI, for security reasons. Otherwise, malicious
// applications would have an easier time spoofing download results by
// sending spoofed intents.
intent.setData(contentUri);
context.sendBroadcast(intent);
}
}
/**
* Returns the time when a download should be restarted. Must only
* be called when numFailed > 0.
*/
public long restartTime() {
return lastMod + Constants.RETRY_FIRST_DELAY * 1000 * (1 << (numFailed - 1));
}
/**
* Returns whether this download should be started at the time when
* it's first inserted in the database.
*/
public boolean isReadyToStart(long now) {
if (status == 0) {
// status hasn't been initialized yet, this is a new download
return true;
}
if (status == Downloads.STATUS_PENDING) {
// download is explicit marked as ready to start
return true;
}
if (status == Downloads.STATUS_RUNNING) {
// download was interrupted (process killed, loss of power) while it was running,
// without a chance to update the database
return true;
}
if (status == Downloads.STATUS_RUNNING_PAUSED) {
if (numFailed == 0) {
// download is waiting for network connectivity to return before it can resume
return true;
}
if (restartTime() < now) {
// download was waiting for a delayed restart, and the delay has expired
return true;
}
}
return false;
}
/**
* Returns whether this download should be restarted at the time when
* it was already known by the download manager
*/
public boolean isReadyToRestart(long now) {
if (status == 0) {
// download hadn't been initialized yet
return true;
}
if (status == Downloads.STATUS_PENDING) {
// download is explicit marked as ready to start
return true;
}
if (status == Downloads.STATUS_RUNNING_PAUSED) {
if (numFailed == 0) {
// download is waiting for network connectivity to return before it can resume
return true;
}
if (restartTime() < now) {
// download was waiting for a delayed restart, and the delay has expired
return true;
}
}
return false;
}
/**
* Returns whether this download has a visible notification after
* completion.
*/
public boolean hasCompletionNotification() {
if (!Downloads.isStatusCompleted(status)) {
return false;
}
if (visibility == Downloads.VISIBILITY_VISIBLE_NOTIFY_COMPLETED) {
return true;
}
return false;
}
}
/*
* 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.providers.downloads;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.provider.Downloads;
import android.widget.RemoteViews;
import java.util.HashMap;
/**
* This class handles the updating of the Notification Manager for the
* cases where there is an ongoing download. Once the download is complete
* (be it successful or unsuccessful) it is no longer the responsibility
* of this component to show the download in the notification manager.
*
*/
class DownloadNotification {
Context mContext;
public NotificationManager mNotificationMgr;
HashMap <String, NotificationItem> mNotifications;
static final String LOGTAG = "DownloadNotification";
static final String WHERE_RUNNING =
"(" + Downloads.STATUS + " >= 100) AND (" +
Downloads.STATUS + " <= 199) AND (" +
Downloads.VISIBILITY + " IS NULL OR " +
Downloads.VISIBILITY + " == " + Downloads.VISIBILITY_VISIBLE + " OR " +
Downloads.VISIBILITY + " == " + Downloads.VISIBILITY_VISIBLE_NOTIFY_COMPLETED + ")";
static final String WHERE_COMPLETED =
Downloads.STATUS + " >= 200 AND " +
Downloads.VISIBILITY + " == " + Downloads.VISIBILITY_VISIBLE_NOTIFY_COMPLETED;
/**
* This inner class is used to collate downloads that are owned by
* the same application. This is so that only one notification line
* item is used for all downloads of a given application.
*
*/
static class NotificationItem {
int id; // This first db _id for the download for the app
int totalCurrent = 0;
int totalTotal = 0;
int titleCount = 0;
String packageName; // App package name
String description;
String[] titles = new String[2]; // download titles.
/*
* Add a second download to this notification item.
*/
void addItem(String title, int currentBytes, int totalBytes) {
totalCurrent += currentBytes;
if (totalBytes <= 0 || totalTotal == -1) {
totalTotal = -1;
} else {
totalTotal += totalBytes;
}
if (titleCount < 2) {
titles[titleCount] = title;
}
titleCount++;
}
}
/**
* Constructor
* @param ctx The context to use to obtain access to the
* Notification Service
*/
DownloadNotification(Context ctx) {
mContext = ctx;
mNotificationMgr = (NotificationManager) mContext
.getSystemService(Context.NOTIFICATION_SERVICE);
mNotifications = new HashMap<String, NotificationItem>();
}
/*
* Update the notification ui.
*/
public void updateNotification() {
updateActiveNotification();
updateCompletedNotification();
}
private void updateActiveNotification() {
// Active downloads
Cursor c = mContext.getContentResolver().query(
Downloads.CONTENT_URI, new String [] {
Downloads._ID, Downloads.TITLE, Downloads.DESCRIPTION,
Downloads.NOTIFICATION_PACKAGE,
Downloads.NOTIFICATION_CLASS,
Downloads.CURRENT_BYTES, Downloads.TOTAL_BYTES,
Downloads.STATUS, Downloads.FILENAME
},
WHERE_RUNNING, null, Downloads._ID);
if (c == null) {
return;
}
// Columns match projection in query above
final int idColumn = 0;
final int titleColumn = 1;
final int descColumn = 2;
final int ownerColumn = 3;
final int classOwnerColumn = 4;
final int currentBytesColumn = 5;
final int totalBytesColumn = 6;
final int statusColumn = 7;
final int filenameColumnId = 8;
// Collate the notifications
mNotifications.clear();
for (c.moveToFirst(); !c.isAfterLast(); c.moveToNext()) {
String packageName = c.getString(ownerColumn);
int max = c.getInt(totalBytesColumn);
int progress = c.getInt(currentBytesColumn);
String title = c.getString(titleColumn);
if (title == null || title.length() == 0) {
title = mContext.getResources().getString(
R.string.download_unknown_title);
}
if (mNotifications.containsKey(packageName)) {
mNotifications.get(packageName).addItem(title, progress, max);
} else {
NotificationItem item = new NotificationItem();
item.id = c.getInt(idColumn);
item.packageName = packageName;
item.description = c.getString(descColumn);
String className = c.getString(classOwnerColumn);
item.addItem(title, progress, max);
mNotifications.put(packageName, item);
}
}
c.close();
// Add the notifications
for (NotificationItem item : mNotifications.values()) {
// Build the notification object
Notification n = new Notification();
n.icon = android.R.drawable.stat_sys_download;
n.flags |= Notification.FLAG_ONGOING_EVENT;
// Build the RemoteView object
RemoteViews expandedView = new RemoteViews(
"com.android.providers.downloads",
R.layout.status_bar_ongoing_event_progress_bar);
StringBuilder title = new StringBuilder(item.titles[0]);
if (item.titleCount > 1) {
title.append(mContext.getString(R.string.notification_filename_separator));
title.append(item.titles[1]);
n.number = item.titleCount;
if (item.titleCount > 2) {
title.append(mContext.getString(R.string.notification_filename_extras,
new Object[] { Integer.valueOf(item.titleCount - 2) }));
}
} else {
expandedView.setTextViewText(R.id.description,
item.description);
}
expandedView.setTextViewText(R.id.title, title);
expandedView.setProgressBar(R.id.progress_bar,
item.totalTotal,
item.totalCurrent,
item.totalTotal == -1);
expandedView.setTextViewText(R.id.progress_text,
getDownloadingText(item.totalTotal, item.totalCurrent));
expandedView.setImageViewResource(R.id.appIcon,
android.R.drawable.stat_sys_download);
n.contentView = expandedView;
Intent intent = new Intent(Constants.ACTION_LIST);
intent.setClassName("com.android.providers.downloads",
DownloadReceiver.class.getName());
intent.setData(Uri.parse(Downloads.CONTENT_URI + "/" + item.id));
intent.putExtra("multiple", item.titleCount > 1);
n.contentIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0);
mNotificationMgr.notify(item.id, n);
}
}
private void updateCompletedNotification() {
// Completed downloads
Cursor c = mContext.getContentResolver().query(
Downloads.CONTENT_URI, new String [] {
Downloads._ID, Downloads.TITLE, Downloads.DESCRIPTION,
Downloads.NOTIFICATION_PACKAGE,
Downloads.NOTIFICATION_CLASS,
Downloads.CURRENT_BYTES, Downloads.TOTAL_BYTES,
Downloads.STATUS, Downloads.FILENAME,
Downloads.LAST_MODIFICATION, Downloads.DESTINATION
},
WHERE_COMPLETED, null, Downloads._ID);
if (c == null) {
return;
}
// Columns match projection in query above
final int idColumn = 0;
final int titleColumn = 1;
final int descColumn = 2;
final int ownerColumn = 3;
final int classOwnerColumn = 4;
final int currentBytesColumn = 5;
final int totalBytesColumn = 6;
final int statusColumn = 7;
final int filenameColumnId = 8;
final int lastModColumnId = 9;
final int destinationColumnId = 10;
for (c.moveToFirst(); !c.isAfterLast(); c.moveToNext()) {
// Add the notifications
Notification n = new Notification();
n.icon = android.R.drawable.stat_sys_download_done;
String title = c.getString(titleColumn);
if (title == null || title.length() == 0) {
title = mContext.getResources().getString(
R.string.download_unknown_title);
}
Uri contentUri = Uri.parse(Downloads.CONTENT_URI + "/" + c.getInt(idColumn));
String caption;
Intent intent;
if (Downloads.isStatusError(c.getInt(statusColumn))) {
caption = mContext.getResources()
.getString(R.string.notification_download_failed);
intent = new Intent(Constants.ACTION_LIST);
} else {
caption = mContext.getResources()
.getString(R.string.notification_download_complete);
if (c.getInt(destinationColumnId) == Downloads.DESTINATION_EXTERNAL) {
intent = new Intent(Constants.ACTION_OPEN);
} else {
intent = new Intent(Constants.ACTION_LIST);
}
}
intent.setClassName("com.android.providers.downloads",
DownloadReceiver.class.getName());
intent.setData(contentUri);
n.setLatestEventInfo(mContext, title, caption,
PendingIntent.getBroadcast(mContext, 0, intent, 0));
intent = new Intent(Constants.ACTION_HIDE);
intent.setClassName("com.android.providers.downloads",
DownloadReceiver.class.getName());
intent.setData(contentUri);
n.deleteIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0);
n.when = c.getLong(lastModColumnId);
mNotificationMgr.notify(c.getInt(idColumn), n);
}
c.close();
}
/*
* Helper function to build the downloading text.
*/
private String getDownloadingText(long totalBytes, long currentBytes) {
if (totalBytes <= 0) {
return "";
}
long progress = currentBytes * 100 / totalBytes;
StringBuilder sb = new StringBuilder();
sb.append(progress);
sb.append('%');
return sb.toString();
}
}
/*
* Copyright (C) 2007 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.providers.downloads;
import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.UriMatcher;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteQueryBuilder;
import android.database.SQLException;
import android.net.Uri;
import android.os.Binder;
import android.os.ParcelFileDescriptor;
import android.os.Process;
import android.provider.BaseColumns;
import android.provider.Downloads;
import android.util.Config;
import android.util.Log;
import java.io.FileNotFoundException;
/**
* Allows application to interact with the download manager.
*/
public final class DownloadProvider extends ContentProvider {
/** Tag used in logging */
private static final String TAG = Constants.TAG;
/** Database filename */
private static final String DB_NAME = "downloads.db";
/** Current database vesion */
private static final int DB_VERSION = 31;
/** Name of table in the database */
private static final String DB_TABLE = "downloads";
/** MIME type for the entire download list */
private static final String DOWNLOAD_LIST_TYPE = "vnd.android.cursor.dir/download";
/** MIME type for an individual download */
private static final String DOWNLOAD_TYPE = "vnd.android.cursor.item/download";
/** URI matcher used to recognize URIs sent by applications */
private static final UriMatcher sURIMatcher = new UriMatcher(UriMatcher.NO_MATCH);
/** URI matcher constant for the URI of the entire download list */
private static final int DOWNLOADS = 1;
/** URI matcher constant for the URI of an individual download */
private static final int DOWNLOADS_ID = 2;
static {
sURIMatcher.addURI("downloads", "download", DOWNLOADS);
sURIMatcher.addURI("downloads", "download/#", DOWNLOADS_ID);
}
/** The database that lies underneath this content provider */
private SQLiteOpenHelper mOpenHelper = null;
/**
* Creates and updated database on demand when opening it.
* Helper class to create database the first time the provider is
* initialized and upgrade it when a new version of the provider needs
* an updated version of the database.
*/
private final class DatabaseHelper extends SQLiteOpenHelper {
public DatabaseHelper(final Context context) {
super(context, DB_NAME, null, DB_VERSION);
}
/**
* Creates database the first time we try to open it.
*/
@Override
public void onCreate(final SQLiteDatabase db) {
if (Constants.LOGVV) {
Log.v(Constants.TAG, "populating new database");
}
createTable(db);
}
/* (not a javadoc comment)
* Checks data integrity when opening the database.
*/
/*
* @Override
* public void onOpen(final SQLiteDatabase db) {
* super.onOpen(db);
* }
*/
/**
* Updates the database format when a content provider is used
* with a database that was created with a different format.
*/
// Note: technically, this could also be a downgrade, so if we want
// to gracefully handle upgrades we should be careful about
// what to do on downgrades.
@Override
public void onUpgrade(final SQLiteDatabase db, final int oldV, final int newV) {
Log.i(TAG, "Upgrading downloads database from version " + oldV + " to " + newV
+ ", which will destroy all old data");
dropTable(db);
createTable(db);
}
}
/**
* Initializes the content provider when it is created.
*/
@Override
public boolean onCreate() {
mOpenHelper = new DatabaseHelper(getContext());
return true;
}
/**
* Returns the content-provider-style MIME types of the various
* types accessible through this content provider.
*/
@Override
public String getType(final Uri uri) {
int match = sURIMatcher.match(uri);
switch (match) {
case DOWNLOADS: {
return DOWNLOAD_LIST_TYPE;
}
case DOWNLOADS_ID: {
return DOWNLOAD_TYPE;
}
default: {
if (Constants.LOGV) {
Log.v(Constants.TAG, "calling getType on an unknown URI: " + uri);
}
throw new IllegalArgumentException("Unknown URI: " + uri);
}
}
}
/**
* Creates the table that'll hold the download information.
*/
private void createTable(SQLiteDatabase db) {
try {
db.execSQL("CREATE TABLE " + DB_TABLE + "(" +
BaseColumns._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," +
Downloads.URI + " TEXT, " +
Downloads.METHOD + " INTEGER, " +
Downloads.ENTITY + " TEXT, " +
Downloads.NO_INTEGRITY + " BOOLEAN, " +
Downloads.FILENAME_HINT + " TEXT, " +
Downloads.OTA_UPDATE + " BOOLEAN, " +
Downloads.FILENAME + " TEXT, " +
Downloads.MIMETYPE + " TEXT, " +
Downloads.DESTINATION + " INTEGER, " +
Downloads.NO_SYSTEM_FILES + " BOOLEAN, " +
Downloads.VISIBILITY + " INTEGER, " +
Downloads.CONTROL + " INTEGER, " +
Downloads.STATUS + " INTEGER, " +
Downloads.FAILED_CONNECTIONS + " INTEGER, " +
Downloads.LAST_MODIFICATION + " BIGINT, " +
Downloads.NOTIFICATION_PACKAGE + " TEXT, " +
Downloads.NOTIFICATION_CLASS + " TEXT, " +
Downloads.NOTIFICATION_EXTRAS + " TEXT, " +
Downloads.COOKIE_DATA + " TEXT, " +
Downloads.USER_AGENT + " TEXT, " +
Downloads.REFERER + " TEXT, " +
Downloads.TOTAL_BYTES + " INTEGER, " +
Downloads.CURRENT_BYTES + " INTEGER, " +
Downloads.ETAG + " TEXT, " +
Downloads.UID + " INTEGER, " +
Downloads.OTHER_UID + " INTEGER, " +
Downloads.TITLE + " TEXT, " +
Downloads.DESCRIPTION + " TEXT, " +
Downloads.MEDIA_SCANNED + " BOOLEAN);");
} catch (SQLException ex) {
Log.e(Constants.TAG, "couldn't create table in downloads database");
throw ex;
}
}
/**
* Deletes the table that holds the download information.
*/
private void dropTable(SQLiteDatabase db) {
try {
db.execSQL("DROP TABLE IF EXISTS " + DB_TABLE);
} catch (SQLException ex) {
Log.e(Constants.TAG, "couldn't drop table in downloads database");
throw ex;
}
}
/**
* Inserts a row in the database
*/
@Override
public Uri insert(final Uri uri, final ContentValues values) {
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
if (sURIMatcher.match(uri) != DOWNLOADS) {
if (Config.LOGD) {
Log.d(Constants.TAG, "calling insert on an unknown/invalid URI: " + uri);
}
throw new IllegalArgumentException("Unknown/Invalid URI " + uri);
}
boolean hasUID = values.containsKey(Downloads.UID);
if (hasUID && Binder.getCallingUid() != 0) {
values.remove(Downloads.UID);
hasUID = false;
}
if (!hasUID) {
values.put(Downloads.UID, Binder.getCallingUid());
}
if (Constants.LOGVV) {
Log.v(TAG, "initiating download with UID " + Binder.getCallingUid());
if (values.containsKey(Downloads.OTHER_UID)) {
Log.v(TAG, "other UID " + values.getAsInteger(Downloads.OTHER_UID));
}
}
if (values.containsKey(Downloads.LAST_MODIFICATION)) {
values.remove(Downloads.LAST_MODIFICATION);
}
values.put(Downloads.LAST_MODIFICATION, System.currentTimeMillis());
if (values.containsKey(Downloads.STATUS)) {
values.remove(Downloads.STATUS);
}
values.put(Downloads.STATUS, Downloads.STATUS_PENDING);
if (values.containsKey(Downloads.OTA_UPDATE)
&& getContext().checkCallingPermission(Constants.OTA_UPDATE_PERMISSION)
!= PackageManager.PERMISSION_GRANTED) {
values.remove(Downloads.OTA_UPDATE);
}
Context context = getContext();
context.startService(new Intent(context, DownloadService.class));
long rowID = db.insert(DB_TABLE, null, values);
Uri ret = null;
if (rowID != -1) {
context.startService(new Intent(context, DownloadService.class));
ret = Uri.parse(Downloads.CONTENT_URI + "/" + rowID);
context.getContentResolver().notifyChange(uri, null);
} else {
if (Config.LOGD) {
Log.d(TAG, "couldn't insert into downloads database");
}
}
return ret;
}
/**
* Starts a database query
*/
@Override
public Cursor query(final Uri uri, final String[] projection,
final String selection, final String[] selectionArgs,
final String sort) {
SQLiteDatabase db = mOpenHelper.getReadableDatabase();
SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
int match = sURIMatcher.match(uri);
boolean emptyWhere = true;
switch (match) {
case DOWNLOADS: {
qb.setTables(DB_TABLE);
break;
}
case DOWNLOADS_ID: {
qb.setTables(DB_TABLE);
qb.appendWhere(BaseColumns._ID + "=");
qb.appendWhere(uri.getPathSegments().get(1));
emptyWhere = false;
break;
}
default: {
if (Constants.LOGV) {
Log.v(TAG, "querying unknown URI: " + uri);
}
throw new IllegalArgumentException("Unknown URI: " + uri);
}
}
if (Binder.getCallingPid() != Process.myPid()
&& Binder.getCallingUid() != 0
&& getContext().checkCallingPermission(Constants.UI_PERMISSION)
!= PackageManager.PERMISSION_GRANTED) {
if (!emptyWhere) {
qb.appendWhere(" AND ");
}
qb.appendWhere("( " + Downloads.UID + "=" + Binder.getCallingUid() + " OR "
+ Downloads.OTHER_UID + "=" + Binder.getCallingUid() + " )");
emptyWhere = false;
}
if (Constants.LOGVV) {
java.lang.StringBuilder sb = new java.lang.StringBuilder();
sb.append("starting query, database is ");
if (db != null) {
sb.append("not ");
}
sb.append("null; ");
if (projection == null) {
sb.append("projection is null; ");
} else if (projection.length == 0) {
sb.append("projection is empty; ");
} else {
for (int i = 0; i < projection.length; ++i) {
sb.append("projection[");
sb.append(i);
sb.append("] is ");
sb.append(projection[i]);
sb.append("; ");
}
}
sb.append("selection is ");
sb.append(selection);
sb.append("; ");
if (selectionArgs == null) {
sb.append("selectionArgs is null; ");
} else if (selectionArgs.length == 0) {
sb.append("selectionArgs is empty; ");
} else {
for (int i = 0; i < selectionArgs.length; ++i) {
sb.append("selectionArgs[");
sb.append(i);
sb.append("] is ");
sb.append(selectionArgs[i]);
sb.append("; ");
}
}
sb.append("sort is ");
sb.append(sort);
sb.append(".");
Log.v(TAG, sb.toString());
}
Cursor ret = qb.query(db, projection, selection, selectionArgs,
null, null, sort);
if (ret != null) {
ret.setNotificationUri(getContext().getContentResolver(), uri);
if (Constants.LOGVV) {
Log.v(Constants.TAG,
"created cursor " + ret + " on behalf of " + Binder.getCallingPid());
}
} else {
if (Constants.LOGV) {
Log.v(TAG, "query failed in downloads database");
}
}
return ret;
}
/**
* Updates a row in the database
*/
@Override
public int update(final Uri uri, final ContentValues values,
final String where, final String[] whereArgs) {
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
int count;
long rowId = 0;
if (values.containsKey(Downloads.UID)) {
values.remove(Downloads.UID);
}
int match = sURIMatcher.match(uri);
switch (match) {
case DOWNLOADS:
case DOWNLOADS_ID: {
String myWhere;
if (where != null) {
if (match == DOWNLOADS) {
myWhere = where;
} else {
myWhere = where + " AND ";
}
} else {
myWhere = "";
}
if (match == DOWNLOADS_ID) {
String segment = uri.getPathSegments().get(1);
rowId = Long.parseLong(segment);
myWhere += Downloads._ID + " = " + rowId;
}
if (Binder.getCallingPid() != Process.myPid()
&& Binder.getCallingUid() != 0
&& getContext().checkCallingPermission(Constants.UI_PERMISSION)
!= PackageManager.PERMISSION_GRANTED) {
myWhere += " AND ( " + Downloads.UID + "=" + Binder.getCallingUid() + " OR "
+ Downloads.OTHER_UID + "=" + Binder.getCallingUid() + " )";
}
count = db.update(DB_TABLE, values, myWhere, whereArgs);
break;
}
default: {
if (Config.LOGD) {
Log.d(TAG, "updating unknown/invalid URI: " + uri);
}
throw new UnsupportedOperationException("Cannot update URI: " + uri);
}
}
getContext().getContentResolver().notifyChange(uri, null);
return count;
}
/**
* Deletes a row in the database
*/
@Override
public int delete(final Uri uri, final String where,
final String[] whereArgs) {
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
int count;
int match = sURIMatcher.match(uri);
switch (match) {
case DOWNLOADS:
case DOWNLOADS_ID: {
String myWhere;
if (where != null) {
if (match == DOWNLOADS) {
myWhere = where;
} else {
myWhere = where + " AND ";
}
} else {
myWhere = "";
}
if (match == DOWNLOADS_ID) {
String segment = uri.getPathSegments().get(1);
long rowId = Long.parseLong(segment);
myWhere += Downloads._ID + " = " + rowId;
}
if (Binder.getCallingPid() != Process.myPid()
&& Binder.getCallingUid() != 0
&& getContext().checkCallingPermission(Constants.UI_PERMISSION)
!= PackageManager.PERMISSION_GRANTED) {
myWhere += " AND ( " + Downloads.UID + "=" + Binder.getCallingUid() + " OR "
+ Downloads.OTHER_UID + "=" + Binder.getCallingUid() + " )";
}
count = db.delete(DB_TABLE, myWhere, whereArgs);
break;
}
default: {
if (Config.LOGD) {
Log.d(TAG, "deleting unknown/invalid URI: " + uri);
}
throw new UnsupportedOperationException("Cannot delete URI: " + uri);
}
}
getContext().getContentResolver().notifyChange(uri, null);
return count;
}
/**
* Remotely opens a file
*/
@Override
public ParcelFileDescriptor openFile(Uri uri, String mode)
throws FileNotFoundException {
if (Constants.LOGVV) {
Log.v(TAG, "openFile uri: " + uri + ", mode: " + mode
+ ", uid: " + Binder.getCallingUid());
Cursor cursor = query(Downloads.CONTENT_URI, new String[] { "_id" }, null, null, "_id");
if (cursor == null) {
Log.v(TAG, "null cursor in openFile");
} else {
if (!cursor.moveToFirst()) {
Log.v(TAG, "empty cursor in openFile");
} else {
do {
Log.v(TAG, "row " + cursor.getInt(0) + " available");
} while(cursor.moveToNext());
}
cursor.close();
}
cursor = query(uri, new String[] { "_data" }, null, null, null);
if (cursor == null) {
Log.v(TAG, "null cursor in openFile");
} else {
if (!cursor.moveToFirst()) {
Log.v(TAG, "empty cursor in openFile");
} else {
String filename = cursor.getString(0);
Log.v(TAG, "filename in openFile: " + filename);
if (new java.io.File(filename).isFile()) {
Log.v(TAG, "file exists in openFile");
}
}
cursor.close();
}
}
ParcelFileDescriptor ret = openFileHelper(uri, mode);
if (ret == null) {
if (Config.LOGD) {
Log.d(TAG, "couldn't open file");
}
} else {
ContentValues values = new ContentValues();
values.put(Downloads.LAST_MODIFICATION, System.currentTimeMillis());
update(uri, values, null, null);
}
return ret;
}
}
/*
* 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.providers.downloads;
import android.app.NotificationManager;
import android.content.ActivityNotFoundException;
import android.content.BroadcastReceiver;
import android.content.ContentUris;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.database.Cursor;
import android.provider.Downloads;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.Uri;
import android.util.Config;
import android.util.Log;
import java.io.File;
import java.util.List;
/**
* Receives system broadcasts (boot, network connectivity)
*/
public class DownloadReceiver extends BroadcastReceiver {
/** Tag used for debugging/logging */
public static final String TAG = Constants.TAG;
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) {
if (Constants.LOGVV) {
Log.v(TAG, "Receiver onBoot");
}
context.startService(new Intent(context, DownloadService.class));
} else if (intent.getAction().equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
if (Constants.LOGVV) {
Log.v(TAG, "Receiver onConnectivity");
}
NetworkInfo info = (NetworkInfo)
intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO);
if (info != null && info.isConnected()) {
context.startService(new Intent(context, DownloadService.class));
}
} else if (intent.getAction().equals(Constants.ACTION_RETRY)) {
if (Constants.LOGVV) {
Log.v(TAG, "Receiver retry");
}
context.startService(new Intent(context, DownloadService.class));
} else if (intent.getAction().equals(Constants.ACTION_OPEN)
|| intent.getAction().equals(Constants.ACTION_LIST)) {
if (Constants.LOGVV) {
if (intent.getAction().equals(Constants.ACTION_OPEN)) {
Log.v(Constants.TAG, "Receiver open for " + intent.getData());
} else {
Log.v(Constants.TAG, "Receiver list for " + intent.getData());
}
}
Cursor cursor = context.getContentResolver().query(
intent.getData(), null, null, null, null);
if (cursor != null) {
boolean mustCommit = false;
if (cursor.moveToFirst()) {
int statusColumn = cursor.getColumnIndexOrThrow(Downloads.STATUS);
int status = cursor.getInt(statusColumn);
int visibilityColumn = cursor.getColumnIndexOrThrow(Downloads.VISIBILITY);
int visibility = cursor.getInt(visibilityColumn);
if (Downloads.isStatusCompleted(status)
&& visibility == Downloads.VISIBILITY_VISIBLE_NOTIFY_COMPLETED) {
cursor.updateInt(visibilityColumn, Downloads.VISIBILITY_VISIBLE);
mustCommit = true;
}
if (intent.getAction().equals(Constants.ACTION_OPEN)) {
int filenameColumn = cursor.getColumnIndexOrThrow(Downloads.FILENAME);
int mimetypeColumn = cursor.getColumnIndexOrThrow(Downloads.MIMETYPE);
String filename = cursor.getString(filenameColumn);
String mimetype = cursor.getString(mimetypeColumn);
Uri path = Uri.parse(filename);
// If there is no scheme, then it must be a file
if (path.getScheme() == null) {
path = Uri.fromFile(new File(filename));
}
Intent activityIntent = new Intent(Intent.ACTION_VIEW);
activityIntent.setDataAndType(path, mimetype);
activityIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
try {
context.startActivity(activityIntent);
} catch (ActivityNotFoundException ex) {
if (Config.LOGD) {
Log.d(Constants.TAG, "no activity for " + mimetype, ex);
}
// nothing anyone can do about this, but we're in a clean state,
// swallow the exception entirely
}
} else {
int packageColumn =
cursor.getColumnIndexOrThrow(Downloads.NOTIFICATION_PACKAGE);
int classColumn =
cursor.getColumnIndexOrThrow(Downloads.NOTIFICATION_CLASS);
String pckg = cursor.getString(packageColumn);
String clazz = cursor.getString(classColumn);
if (pckg != null && clazz != null) {
Intent appIntent = new Intent(Downloads.NOTIFICATION_CLICKED_ACTION);
appIntent.setClassName(pckg, clazz);
if (intent.getBooleanExtra("multiple", true)) {
appIntent.setData(Downloads.CONTENT_URI);
} else {
appIntent.setData(intent.getData());
}
context.sendBroadcast(appIntent);
}
}
}
if (mustCommit) {
if (!cursor.commitUpdates()) {
Log.e(Constants.TAG, "commitUpdate failed in onReceive/OPEN-LIST");
}
}
cursor.close();
}
NotificationManager notMgr = (NotificationManager) context
.getSystemService(Context.NOTIFICATION_SERVICE);
if (notMgr != null) {
notMgr.cancel((int) ContentUris.parseId(intent.getData()));
}
} else if (intent.getAction().equals(Constants.ACTION_HIDE)) {
if (Constants.LOGVV) {
Log.v(Constants.TAG, "Receiver hide for " + intent.getData());
}
Cursor cursor = context.getContentResolver().query(
intent.getData(), null, null, null, null);
if (cursor != null) {
if (cursor.moveToFirst()) {
int statusColumn = cursor.getColumnIndexOrThrow(Downloads.STATUS);
int status = cursor.getInt(statusColumn);
int visibilityColumn = cursor.getColumnIndexOrThrow(Downloads.VISIBILITY);
int visibility = cursor.getInt(visibilityColumn);
if (Downloads.isStatusCompleted(status)
&& visibility == Downloads.VISIBILITY_VISIBLE_NOTIFY_COMPLETED) {
cursor.updateInt(visibilityColumn, Downloads.VISIBILITY_VISIBLE);
if (!cursor.commitUpdates()) {
Log.e(Constants.TAG, "commitUpdate failed in onReceive/HIDE");
}
}
}
cursor.close();
}
}
}
}
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment