blob: 047e9b52c2dbdb5a32883b00399e1acf696ce33a [file] [log] [blame]
Alexandre Lisionb8add812013-10-24 11:42:42 -04001/*
2 * Copyright (C) 2010-2012 Regis Montoya (aka r3gis - www.r3gis.fr)
Alexandre Lisionc1024c02014-01-06 11:12:53 -05003 * Copyright (C) 2004-2014 Savoir-Faire Linux Inc.
Alexandre Lisionb8add812013-10-24 11:42:42 -04004 *
Alexandre Lisiona8b78722013-12-13 10:18:33 -05005 * Author: Regis Montoya <r3gis.3R@gmail.com>
6 * Alexandre Lision <alexandre.lision@savoirfairelinux.com>
Alexandre Lisionb8add812013-10-24 11:42:42 -04007 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 *
22 * Additional permission under GNU GPL version 3 section 7:
23 *
24 * If you modify this program, or any covered work, by linking or
25 * combining it with the OpenSSL project's OpenSSL library (or a
26 * modified version of that library), containing parts covered by the
27 * terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc.
28 * grants you additional permission to convey the resulting work.
29 * Corresponding Source for a non-source form of such a combination
30 * shall include the source code for the parts of OpenSSL used as well
31 * as that of the covered work.
32 */
33
34package org.sflphone.utils;
35
36import java.io.File;
37import java.io.FileFilter;
38import java.lang.reflect.Field;
39import java.util.regex.Pattern;
40
41import android.content.Context;
42import android.content.Intent;
43import android.content.pm.ApplicationInfo;
44import android.content.pm.PackageInfo;
45import android.content.pm.PackageManager;
46import android.content.pm.PackageManager.NameNotFoundException;
47import android.content.res.Configuration;
48import android.media.AudioManager;
49import android.media.MediaRecorder.AudioSource;
50import android.net.Uri;
51import android.os.Environment;
52import android.provider.Contacts;
53import android.util.Log;
54
55@SuppressWarnings("deprecation")
56public final class Compatibility {
57
58 private Compatibility() {
59 }
60
61 private static final String THIS_FILE = "Compat";
62
63 public static int getApiLevel() {
64 return android.os.Build.VERSION.SDK_INT;
65 }
66
67 public static boolean isCompatible(int apiLevel) {
68 return android.os.Build.VERSION.SDK_INT >= apiLevel;
69 }
70
71 /**
Alexandre Lision35577132013-12-06 15:21:15 -050072 * Get the stream id for in call track. Can differ on some devices. Current device for which it's different :
Alexandre Lisionb8add812013-10-24 11:42:42 -040073 *
74 * @return
75 */
76 public static int getInCallStream(boolean requestBluetooth) {
77 /* Archos 5IT */
Alexandre Lision35577132013-12-06 15:21:15 -050078 if (android.os.Build.BRAND.equalsIgnoreCase("archos") && android.os.Build.DEVICE.equalsIgnoreCase("g7a")) {
Alexandre Lisionb8add812013-10-24 11:42:42 -040079 // Since archos has no voice call capabilities, voice call stream is
80 // not implemented
81 // So we have to choose the good stream tag, which is by default
82 // falled back to music
83 return AudioManager.STREAM_MUSIC;
84 }
85 if (requestBluetooth) {
86 return 6; /* STREAM_BLUETOOTH_SCO -- Thx @Stefan for the contrib */
87 }
88
89 // return AudioManager.STREAM_MUSIC;
90 return AudioManager.STREAM_VOICE_CALL;
91 }
92
93 public static boolean shouldUseRoutingApi() {
Alexandre Lision35577132013-12-06 15:21:15 -050094 Log.d(THIS_FILE, "Current device " + android.os.Build.BRAND + " - " + android.os.Build.DEVICE);
Alexandre Lisionb8add812013-10-24 11:42:42 -040095
96 // HTC evo 4G
97 if (android.os.Build.PRODUCT.equalsIgnoreCase("htc_supersonic")) {
98 return true;
99 }
100
101 // ZTE joe
102 if (android.os.Build.DEVICE.equalsIgnoreCase("joe")) {
103 return true;
104 }
105
106 // Samsung GT-S5830
107 if (android.os.Build.DEVICE.toUpperCase().startsWith("GT-S")) {
108 return true;
109 }
110
111 if (!isCompatible(4)) {
112 // If android 1.5, force routing api use
113 return true;
114 } else {
115 return false;
116 }
117 }
118
119 public static boolean shouldUseModeApi() {
120
121 // ZTE blade et joe
Alexandre Lision35577132013-12-06 15:21:15 -0500122 if (android.os.Build.DEVICE.equalsIgnoreCase("blade") || android.os.Build.DEVICE.equalsIgnoreCase("joe")) {
Alexandre Lisionb8add812013-10-24 11:42:42 -0400123 return true;
124 }
125 // Samsung GT-S5360 GT-S5830 GT-S6102 ... probably all..
Alexandre Lision35577132013-12-06 15:21:15 -0500126 if (android.os.Build.DEVICE.toUpperCase().startsWith("GT-") || android.os.Build.PRODUCT.toUpperCase().startsWith("GT-")
127 || android.os.Build.DEVICE.toUpperCase().startsWith("YP-")) {
Alexandre Lisionb8add812013-10-24 11:42:42 -0400128 return true;
129 }
130
131 // HTC evo 4G
132 if (android.os.Build.PRODUCT.equalsIgnoreCase("htc_supersonic")) {
133 return true;
134 }
135 // LG P500, Optimus V
136 if (android.os.Build.DEVICE.toLowerCase().startsWith("thunder")) {
137 return true;
138 }
139 // LG-E720(b)
Alexandre Lision35577132013-12-06 15:21:15 -0500140 if (android.os.Build.MODEL.toUpperCase().startsWith("LG-E720") && !Compatibility.isCompatible(9)) {
Alexandre Lisionb8add812013-10-24 11:42:42 -0400141 return true;
142 }
143 // LG-LS840
144 if (android.os.Build.DEVICE.toLowerCase().startsWith("cayman")) {
145 return true;
146 }
147
148 // Huawei
Alexandre Lision35577132013-12-06 15:21:15 -0500149 if (android.os.Build.DEVICE.equalsIgnoreCase("U8150") || android.os.Build.DEVICE.equalsIgnoreCase("U8110")
150 || android.os.Build.DEVICE.equalsIgnoreCase("U8120") || android.os.Build.DEVICE.equalsIgnoreCase("U8100")
151 || android.os.Build.PRODUCT.equalsIgnoreCase("U8655")) {
Alexandre Lisionb8add812013-10-24 11:42:42 -0400152 return true;
153 }
154
155 // Moto defy mini
156 if (android.os.Build.MODEL.equalsIgnoreCase("XT320")) {
157 return true;
158 }
159
160 // Alcatel
161 if (android.os.Build.DEVICE.toUpperCase().startsWith("ONE_TOUCH_993D")) {
162 return true;
163 }
164
165 // N4
166 if (android.os.Build.DEVICE.toUpperCase().startsWith("MAKO")) {
167 return true;
168 }
169
170 return false;
171 }
172
173 public static String guessInCallMode() {
174 // New api for 2.3.3 is not available on galaxy S II :(
175 if (!isCompatible(11) && android.os.Build.DEVICE.toUpperCase().startsWith("GT-I9100")) {
176 return Integer.toString(AudioManager.MODE_NORMAL);
177 }
178
179 if (android.os.Build.BRAND.equalsIgnoreCase("sdg") || isCompatible(10)) {
180 // Note that in APIs this is only available from level 11.
181 return "3";
182 }
183 if (android.os.Build.DEVICE.equalsIgnoreCase("blade")) {
184 return Integer.toString(AudioManager.MODE_IN_CALL);
185 }
186
187 if (!isCompatible(5)) {
188 return Integer.toString(AudioManager.MODE_IN_CALL);
189 }
190
191 return Integer.toString(AudioManager.MODE_NORMAL);
192 }
193
194 public static String getDefaultMicroSource() {
195 // Except for galaxy S II :(
196 if (!isCompatible(11) && android.os.Build.DEVICE.toUpperCase().startsWith("GT-I9100")) {
197 return Integer.toString(AudioSource.MIC);
198 }
199
200 if (isCompatible(10)) {
201 // Note that in APIs this is only available from level 11.
202 // VOICE_COMMUNICATION
203 return Integer.toString(0x7);
204 }
205 /*
Alexandre Lision35577132013-12-06 15:21:15 -0500206 * Too risky in terms of regressions else if (isCompatible(4)) { // VOICE_CALL return 0x4; }
Alexandre Lisionb8add812013-10-24 11:42:42 -0400207 */
208 /*
Alexandre Lision35577132013-12-06 15:21:15 -0500209 * if(android.os.Build.MODEL.equalsIgnoreCase("X10i")) { // VOICE_CALL return Integer.toString(0x4); }
Alexandre Lisionb8add812013-10-24 11:42:42 -0400210 */
211 /*
Alexandre Lision35577132013-12-06 15:21:15 -0500212 * Not relevant anymore, atrix I tested sounds fine with that if(android.os.Build.DEVICE.equalsIgnoreCase("olympus")) { //Motorola atrix bug
213 * // CAMCORDER return Integer.toString(0x5); }
Alexandre Lisionb8add812013-10-24 11:42:42 -0400214 */
215
216 return Integer.toString(AudioSource.DEFAULT);
217 }
218
219 public static String getDefaultFrequency() {
220 if (android.os.Build.DEVICE.equalsIgnoreCase("olympus")) {
221 // Atrix bug
222 return "32000";
223 }
224 if (android.os.Build.DEVICE.toUpperCase().equals("GT-P1010")) {
225 // Galaxy tab see issue 932
226 return "32000";
227 }
228
229 return isCompatible(4) ? "16000" : "8000";
230 }
231
232 public static String getCpuAbi() {
233 if (isCompatible(4)) {
234 Field field;
235 try {
236 field = android.os.Build.class.getField("CPU_ABI");
237 return field.get(null).toString();
238 } catch (Exception e) {
239 Log.w(THIS_FILE, "Announce to be android 1.6 but no CPU ABI field", e);
240 }
241
242 }
243 return "armeabi";
244 }
245
246 public final static int getNumCores() {
247 // Private Class to display only CPU devices in the directory listing
248 class CpuFilter implements FileFilter {
249 @Override
250 public boolean accept(File pathname) {
251 // Check if filename is "cpu", followed by a single digit number
252 if (Pattern.matches("cpu[0-9]", pathname.getName())) {
253 return true;
254 }
255 return false;
256 }
257 }
258 try {
259 // Get directory containing CPU info
260 File dir = new File("/sys/devices/system/cpu/");
261 // Filter to only list the devices we care about
262 File[] files = dir.listFiles(new CpuFilter());
263 // Return the number of cores (virtual CPU devices)
264 return files.length;
265 } catch (Exception e) {
266 return Runtime.getRuntime().availableProcessors();
267 }
268 }
269
270 private static boolean needPspWorkaround() {
271 // New api for 2.3 does not work on Incredible S
272 if (android.os.Build.DEVICE.equalsIgnoreCase("vivo")) {
273 return true;
274 }
275
276 // New API for android 2.3 should be able to manage this but do only for
277 // honeycomb cause seems not correctly supported by all yet
278 if (isCompatible(11)) {
279 return false;
280 }
281
282 // All htc except....
Alexandre Lision35577132013-12-06 15:21:15 -0500283 if (android.os.Build.PRODUCT.toLowerCase().startsWith("htc") || android.os.Build.BRAND.toLowerCase().startsWith("htc")
Alexandre Lisionb8add812013-10-24 11:42:42 -0400284 || android.os.Build.PRODUCT.toLowerCase().equalsIgnoreCase("inc") /*
Alexandre Lision35577132013-12-06 15:21:15 -0500285 * For Incredible
Alexandre Lisionb8add812013-10-24 11:42:42 -0400286 */
287 || android.os.Build.DEVICE.equalsIgnoreCase("passion") /* N1 */) {
288 if (android.os.Build.DEVICE.equalsIgnoreCase("hero") /* HTC HERO */
289 || android.os.Build.DEVICE.equalsIgnoreCase("magic") /*
Alexandre Lision35577132013-12-06 15:21:15 -0500290 * Magic Aka Dev G2
Alexandre Lisionb8add812013-10-24 11:42:42 -0400291 */
292 || android.os.Build.DEVICE.equalsIgnoreCase("tatoo") /* Tatoo */
293 || android.os.Build.DEVICE.equalsIgnoreCase("dream") /*
Alexandre Lision35577132013-12-06 15:21:15 -0500294 * Dream Aka Dev G1
Alexandre Lisionb8add812013-10-24 11:42:42 -0400295 */
296 || android.os.Build.DEVICE.equalsIgnoreCase("legend") /* Legend */
297
298 ) {
299 return false;
300 }
301
302 // Older than 2.3 has no chance to have the new full perf wifi mode
303 // working since does not exists
304 if (!isCompatible(9)) {
305 return true;
306 } else {
307 // N1 is fine with that
308 if (android.os.Build.DEVICE.equalsIgnoreCase("passion")) {
309 return false;
310 }
311 return true;
312 }
313
314 }
315 // Dell streak
Alexandre Lision35577132013-12-06 15:21:15 -0500316 if (android.os.Build.BRAND.toLowerCase().startsWith("dell") && android.os.Build.DEVICE.equalsIgnoreCase("streak")) {
Alexandre Lisionb8add812013-10-24 11:42:42 -0400317 return true;
318 }
319 // Motorola milestone 1 and 2 & motorola droid & defy not under 2.3
Alexandre Lision35577132013-12-06 15:21:15 -0500320 if ((android.os.Build.DEVICE.toLowerCase().contains("milestone2") || android.os.Build.BOARD.toLowerCase().contains("sholes")
321 || android.os.Build.PRODUCT.toLowerCase().contains("sholes") || android.os.Build.DEVICE.equalsIgnoreCase("olympus") || android.os.Build.DEVICE
322 .toLowerCase().contains("umts_jordan")) && !isCompatible(9)) {
Alexandre Lisionb8add812013-10-24 11:42:42 -0400323 return true;
324 }
325 // Moto defy mini
326 if (android.os.Build.MODEL.equalsIgnoreCase("XT320")) {
327 return true;
328 }
329
330 // Alcatel ONE touch
331 if (android.os.Build.DEVICE.startsWith("one_touch_990")) {
332 return true;
333 }
334
335 return false;
336 }
337
338 private static boolean needToneWorkaround() {
Alexandre Lision35577132013-12-06 15:21:15 -0500339 if (android.os.Build.PRODUCT.toLowerCase().startsWith("gt-i5800") || android.os.Build.PRODUCT.toLowerCase().startsWith("gt-i5801")
340 || android.os.Build.PRODUCT.toLowerCase().startsWith("gt-i9003")) {
Alexandre Lisionb8add812013-10-24 11:42:42 -0400341 return true;
342 }
343 return false;
344 }
345
346 private static boolean needSGSWorkaround() {
347 if (isCompatible(9)) {
348 return false;
349 }
Alexandre Lision35577132013-12-06 15:21:15 -0500350 if (android.os.Build.DEVICE.toUpperCase().startsWith("GT-I9000") || android.os.Build.DEVICE.toUpperCase().startsWith("GT-P1000")) {
Alexandre Lisionb8add812013-10-24 11:42:42 -0400351 return true;
352 }
353 return false;
354 }
355
356 private static boolean needWebRTCImplementation() {
357 if (android.os.Build.DEVICE.toLowerCase().contains("droid2")) {
358 return true;
359 }
360 if (android.os.Build.MODEL.toLowerCase().contains("droid bionic")) {
361 return true;
362 }
363 if (android.os.Build.DEVICE.toLowerCase().contains("sunfire")) {
364 return true;
365 }
366 // Huawei Y300
367 if (android.os.Build.DEVICE.equalsIgnoreCase("U8833")) {
368 return true;
369 }
370 return false;
371 }
372
373 public static boolean shouldSetupAudioBeforeInit() {
374 // Setup for GT / GS samsung devices.
Alexandre Lision35577132013-12-06 15:21:15 -0500375 if (android.os.Build.DEVICE.toLowerCase().startsWith("gt-") || android.os.Build.PRODUCT.toLowerCase().startsWith("gt-")) {
Alexandre Lisionb8add812013-10-24 11:42:42 -0400376 return true;
377 }
378 return false;
379 }
380
381 private static boolean shouldFocusAudio() {
382 /* HTC One X */
Alexandre Lision35577132013-12-06 15:21:15 -0500383 if (android.os.Build.DEVICE.toLowerCase().startsWith("endeavoru") || android.os.Build.DEVICE.toLowerCase().startsWith("evita")) {
Alexandre Lisionb8add812013-10-24 11:42:42 -0400384 return false;
385 }
386
387 if (android.os.Build.DEVICE.toUpperCase().startsWith("GT-P7510") && isCompatible(15)) {
388 return false;
389 }
390 return true;
391 }
392
Alexandre Lision35577132013-12-06 15:21:15 -0500393 // private static int getDefaultAudioImplementation() {
394 // // Acer A510
395 // if (android.os.Build.DEVICE.toLowerCase().startsWith("picasso")) {
396 // return SipConfigManager.AUDIO_IMPLEMENTATION_JAVA;
397 // }
398 // if (Compatibility.isCompatible(11)) {
399 // return SipConfigManager.AUDIO_IMPLEMENTATION_OPENSLES;
400 // }
401 // if (android.os.Build.DEVICE.equalsIgnoreCase("ST25i") && Compatibility.isCompatible(10)) {
402 // return SipConfigManager.AUDIO_IMPLEMENTATION_OPENSLES;
403 // }
404 // if (android.os.Build.DEVICE.equalsIgnoreCase("u8510") && Compatibility.isCompatible(10)) {
405 // return SipConfigManager.AUDIO_IMPLEMENTATION_OPENSLES;
406 // }
407 // return SipConfigManager.AUDIO_IMPLEMENTATION_JAVA;
408 // }
Alexandre Lisionb8add812013-10-24 11:42:42 -0400409
410 public static boolean useFlipAnimation() {
Alexandre Lision35577132013-12-06 15:21:15 -0500411 if (android.os.Build.BRAND.equalsIgnoreCase("archos") && android.os.Build.DEVICE.equalsIgnoreCase("g7a")) {
Alexandre Lisionb8add812013-10-24 11:42:42 -0400412 return false;
413 }
414 return true;
415 }
416
Alexandre Lisionb8add812013-10-24 11:42:42 -0400417 public static Intent getContactPhoneIntent() {
418 Intent intent = new Intent(Intent.ACTION_PICK);
419 /*
Alexandre Lision35577132013-12-06 15:21:15 -0500420 * intent.setAction(Intent.ACTION_GET_CONTENT); intent.setType(Contacts.Phones.CONTENT_ITEM_TYPE);
Alexandre Lisionb8add812013-10-24 11:42:42 -0400421 */
422 if (isCompatible(5)) {
423 // Don't use constant to allow backward compat simply
424 intent.setData(Uri.parse("content://com.android.contacts/contacts"));
425 } else {
426 // Fallback for android 4
427 intent.setData(Contacts.People.CONTENT_URI);
428 }
429
430 return intent;
431
432 }
Alexandre Lisionb8add812013-10-24 11:42:42 -0400433
434 public static boolean isTabletScreen(Context ctxt) {
435 boolean isTablet = false;
436 if (!isCompatible(4)) {
437 return false;
438 }
439 Configuration cfg = ctxt.getResources().getConfiguration();
440 int screenLayoutVal = 0;
441 try {
442 Field f = Configuration.class.getDeclaredField("screenLayout");
443 screenLayoutVal = (Integer) f.get(cfg);
444 } catch (Exception e) {
445 return false;
446 }
447 int screenLayout = (screenLayoutVal & 0xF);
448 // 0xF = SCREENLAYOUT_SIZE_MASK but avoid 1.5 incompat doing that
449 if (screenLayout == 0x3 || screenLayout == 0x4) {
450 // 0x3 = SCREENLAYOUT_SIZE_LARGE but avoid 1.5 incompat doing that
451 // 0x4 = SCREENLAYOUT_SIZE_XLARGE but avoid 1.5 incompat doing that
452 isTablet = true;
453 }
454
455 return isTablet;
456 }
457
458 public static int getHomeMenuId() {
459 return 0x0102002c;
460 // return android.R.id.home;
461 }
462
463 public static boolean isInstalledOnSdCard(Context context) {
464 // check for API level 8 and higher
465 if (Compatibility.isCompatible(8)) {
466 PackageManager pm = context.getPackageManager();
467 try {
468 PackageInfo pi = pm.getPackageInfo(context.getPackageName(), 0);
469 ApplicationInfo ai = pi.applicationInfo;
470 return (ai.flags & 0x00040000 /*
Alexandre Lision35577132013-12-06 15:21:15 -0500471 * ApplicationInfo. FLAG_EXTERNAL_STORAGE
Alexandre Lisionb8add812013-10-24 11:42:42 -0400472 */) == 0x00040000 /*
Alexandre Lision35577132013-12-06 15:21:15 -0500473 * ApplicationInfo. FLAG_EXTERNAL_STORAGE
Alexandre Lisionb8add812013-10-24 11:42:42 -0400474 */;
475 } catch (NameNotFoundException e) {
476 // ignore
477 }
478 }
479
480 // check for API level 7 - check files dir
481 try {
482 String filesDir = context.getFilesDir().getAbsolutePath();
483 if (filesDir.startsWith("/data/")) {
484 return false;
485 } else if (filesDir.contains(Environment.getExternalStorageDirectory().getPath())) {
486 return true;
487 }
488 } catch (Throwable e) {
489 // ignore
490 }
491
492 return false;
493 }
494
495}