این وبسایت یک نسخه آزمایشی از سایت developer android می‌باشد که در حال ترجمه می‌باشد.
برای پیوستن به تیم ترجمه و خواندن مستندات اینجا کلیک کنید.
AgendaData / Application / src / com.example.android.wearable.agendadata /

CalendarQueryService.java

1
/*
2
 * Copyright (C) 2014 The Android Open Source Project
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *      http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16
 
17
package com.example.android.wearable.agendadata;
18
 
19
 
20
import static com.example.android.wearable.agendadata.Constants.TAG;
21
import static com.example.android.wearable.agendadata.Constants.CONNECTION_TIME_OUT_MS;
22
import static com.example.android.wearable.agendadata.Constants.CAL_DATA_ITEM_PATH_PREFIX;
23
import static com.example.android.wearable.agendadata.Constants.ALL_DAY;
24
import static com.example.android.wearable.agendadata.Constants.BEGIN;
25
import static com.example.android.wearable.agendadata.Constants.DATA_ITEM_URI;
26
import static com.example.android.wearable.agendadata.Constants.DESCRIPTION;
27
import static com.example.android.wearable.agendadata.Constants.END;
28
import static com.example.android.wearable.agendadata.Constants.EVENT_ID;
29
import static com.example.android.wearable.agendadata.Constants.ID;
30
import static com.example.android.wearable.agendadata.Constants.PROFILE_PIC;
31
import static com.example.android.wearable.agendadata.Constants.TITLE;
32
 
33
import android.app.IntentService;
34
import android.content.ContentResolver;
35
import android.content.ContentUris;
36
import android.content.Context;
37
import android.content.Intent;
38
import android.content.res.Resources;
39
import android.database.Cursor;
40
import android.graphics.Bitmap;
41
import android.graphics.BitmapFactory;
42
import android.net.Uri;
43
import android.os.Bundle;
44
import android.provider.CalendarContract;
45
import android.provider.ContactsContract.CommonDataKinds.Email;
46
import android.provider.ContactsContract.Contacts;
47
import android.provider.ContactsContract.Data;
48
import android.text.format.Time;
49
import android.util.Log;
50
 
51
import com.google.android.gms.common.ConnectionResult;
52
import com.google.android.gms.common.api.GoogleApiClient;
53
import com.google.android.gms.common.api.GoogleApiClient.ConnectionCallbacks;
54
import com.google.android.gms.common.api.GoogleApiClient.OnConnectionFailedListener;
55
import com.google.android.gms.wearable.Asset;
56
import com.google.android.gms.wearable.DataMap;
57
import com.google.android.gms.wearable.PutDataMapRequest;
58
import com.google.android.gms.wearable.Wearable;
59
 
60
import java.io.ByteArrayOutputStream;
61
import java.io.Closeable;
62
import java.io.IOException;
63
import java.io.InputStream;
64
import java.util.ArrayList;
65
import java.util.List;
66
import java.util.concurrent.TimeUnit;
67
 
68
/**
69
 * Queries calendar events using Android Calendar Provider API and creates a data item for each
70
 * event.
71
 */
72
public class CalendarQueryService extends IntentService
73
        implements ConnectionCallbacks, OnConnectionFailedListener {
74
 
75
    private static final String[] INSTANCE_PROJECTION = {
76
            CalendarContract.Instances._ID,
77
            CalendarContract.Instances.EVENT_ID,
78
            CalendarContract.Instances.TITLE,
79
            CalendarContract.Instances.BEGIN,
80
            CalendarContract.Instances.END,
81
            CalendarContract.Instances.ALL_DAY,
82
            CalendarContract.Instances.DESCRIPTION,
83
            CalendarContract.Instances.ORGANIZER
84
    };
85
 
86
    private static final String[] CONTACT_PROJECTION = new String[] { Data._ID, Data.CONTACT_ID };
87
    private static final String CONTACT_SELECTION = Email.ADDRESS + " = ?";
88
 
89
    private GoogleApiClient mGoogleApiClient;
90
 
91
    public CalendarQueryService() {
92
        super(CalendarQueryService.class.getSimpleName());
93
    }
94
 
95
    @Override
96
    public void onCreate() {
97
        super.onCreate();
98
        mGoogleApiClient = new GoogleApiClient.Builder(this)
99
                .addApi(Wearable.API)
100
                .addConnectionCallbacks(this)
101
                .addOnConnectionFailedListener(this)
102
                .build();
103
    }
104
 
105
    @Override
106
    protected void onHandleIntent(Intent intent) {
107
        mGoogleApiClient.blockingConnect(CONNECTION_TIME_OUT_MS, TimeUnit.MILLISECONDS);
108
        // Query calendar events in the next 24 hours.
109
        Time time = new Time();
110
        time.setToNow();
111
        long beginTime = time.toMillis(true);
112
        time.monthDay++;
113
        time.normalize(true);
114
        long endTime = time.normalize(true);
115
 
116
        List<Event> events = queryEvents(this, beginTime, endTime);
117
        for (Event event : events) {
118
            final PutDataMapRequest putDataMapRequest = event.toPutDataMapRequest();
119
            if (mGoogleApiClient.isConnected()) {
120
                Wearable.DataApi.putDataItem(
121
                    mGoogleApiClient, putDataMapRequest.asPutDataRequest()).await();
122
            } else {
123
                Log.e(TAG, "Failed to send data item: " + putDataMapRequest
124
                         + " - Client disconnected from Google Play Services");
125
            }
126
        }
127
        mGoogleApiClient.disconnect();
128
    }
129
 
130
    private static String makeDataItemPath(long eventId, long beginTime) {
131
        return CAL_DATA_ITEM_PATH_PREFIX + eventId + "/" + beginTime;
132
    }
133
 
134
    private static List<Event> queryEvents(Context context, long beginTime, long endTime) {
135
        ContentResolver contentResolver = context.getContentResolver();
136
        Uri.Builder builder = CalendarContract.Instances.CONTENT_URI.buildUpon();
137
        ContentUris.appendId(builder, beginTime);
138
        ContentUris.appendId(builder, endTime);
139
 
140
        Cursor cursor = contentResolver.query(builder.build(), INSTANCE_PROJECTION,
141
                null /* selection */, null /* selectionArgs */, null /* sortOrder */);
142
        try {
143
            int idIdx = cursor.getColumnIndex(CalendarContract.Instances._ID);
144
            int eventIdIdx = cursor.getColumnIndex(CalendarContract.Instances.EVENT_ID);
145
            int titleIdx = cursor.getColumnIndex(CalendarContract.Instances.TITLE);
146
            int beginIdx = cursor.getColumnIndex(CalendarContract.Instances.BEGIN);
147
            int endIdx = cursor.getColumnIndex(CalendarContract.Instances.END);
148
            int allDayIdx = cursor.getColumnIndex(CalendarContract.Instances.ALL_DAY);
149
            int descIdx = cursor.getColumnIndex(CalendarContract.Instances.DESCRIPTION);
150
            int ownerEmailIdx = cursor.getColumnIndex(CalendarContract.Instances.ORGANIZER);
151
 
152
            List<Event> events = new ArrayList<Event>(cursor.getCount());
153
            while (cursor.moveToNext()) {
154
                Event event = new Event();
155
                event.id = cursor.getLong(idIdx);
156
                event.eventId = cursor.getLong(eventIdIdx);
157
                event.title = cursor.getString(titleIdx);
158
                event.begin = cursor.getLong(beginIdx);
159
                event.end = cursor.getLong(endIdx);
160
                event.allDay = cursor.getInt(allDayIdx) != 0;
161
                event.description = cursor.getString(descIdx);
162
                String ownerEmail = cursor.getString(ownerEmailIdx);
163
                Cursor contactCursor = contentResolver.query(Data.CONTENT_URI,
164
                        CONTACT_PROJECTION, CONTACT_SELECTION, new String[] {ownerEmail}, null);
165
                int ownerIdIdx = contactCursor.getColumnIndex(Data.CONTACT_ID);
166
                long ownerId = -1;
167
                if (contactCursor.moveToFirst()) {
168
                    ownerId = contactCursor.getLong(ownerIdIdx);
169
                }
170
                contactCursor.close();
171
                // Use event organizer's profile picture as the notification background.
172
                event.ownerProfilePic = getProfilePicture(contentResolver, context, ownerId);
173
                events.add(event);
174
            }
175
            return events;
176
        } finally {
177
            cursor.close();
178
        }
179
    }
180
 
181
    @Override
182
    public void onConnected(Bundle connectionHint) {
183
    }
184
 
185
    @Override
186
    public void onConnectionSuspended(int cause) {
187
    }
188
 
189
    @Override
190
    public void onConnectionFailed(ConnectionResult result) {
191
    }
192
 
193
    private static Asset getDefaultProfile(Resources res) {
194
        Bitmap bitmap = BitmapFactory.decodeResource(res, R.drawable.nobody);
195
        return Asset.createFromBytes(toByteArray(bitmap));
196
    }
197
 
198
    private static Asset getProfilePicture(ContentResolver contentResolver, Context context,
199
                                           long contactId) {
200
        if (contactId != -1) {
201
            // Try to retrieve the profile picture for the given contact.
202
            Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId);
203
            InputStream inputStream = Contacts.openContactPhotoInputStream(contentResolver,
204
                    contactUri, true /*preferHighres*/);
205
 
206
            if (null != inputStream) {
207
                try {
208
                    Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
209
                    if (bitmap != null) {
210
                        return Asset.createFromBytes(toByteArray(bitmap));
211
                    } else {
212
                        Log.e(TAG, "Cannot decode profile picture for contact " + contactId);
213
                    }
214
                } finally {
215
                    closeQuietly(inputStream);
216
                }
217
            }
218
        }
219
        // Use a default background image if the user has no profile picture or there was an error.
220
        return getDefaultProfile(context.getResources());
221
    }
222
 
223
    private static byte[] toByteArray(Bitmap bitmap) {
224
        ByteArrayOutputStream stream = new ByteArrayOutputStream();
225
        bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream);
226
        byte[] byteArray = stream.toByteArray();
227
        closeQuietly(stream);
228
        return byteArray;
229
    }
230
 
231
    private static void closeQuietly(Closeable closeable) {
232
        try {
233
            closeable.close();
234
        } catch (IOException e) {
235
            Log.e(TAG, "IOException while closing closeable.", e);
236
        }
237
    }
238
 
239
    private static class Event {
240
 
241
        public long id;
242
        public long eventId;
243
        public String title;
244
        public long begin;
245
        public long end;
246
        public boolean allDay;
247
        public String description;
248
        public Asset ownerProfilePic;
249
 
250
        public PutDataMapRequest toPutDataMapRequest(){
251
            final PutDataMapRequest putDataMapRequest = PutDataMapRequest.create(
252
                    makeDataItemPath(eventId, begin));
253
            DataMap data = putDataMapRequest.getDataMap();
254
            data.putString(DATA_ITEM_URI, putDataMapRequest.getUri().toString());
255
            data.putLong(ID, id);
256
            data.putLong(EVENT_ID, eventId);
257
            data.putString(TITLE, title);
258
            data.putLong(BEGIN, begin);
259
            data.putLong(END, end);
260
            data.putBoolean(ALL_DAY, allDay);
261